mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
Compare commits
3 Commits
322fb2fea0
...
b2187bf0ad
| Author | SHA1 | Date | |
|---|---|---|---|
| b2187bf0ad | |||
| 2aa9d07e43 | |||
| 8ff789c576 |
@@ -50,6 +50,8 @@ public:
|
||||
void generate_cave();
|
||||
void generate_river();
|
||||
|
||||
void spawn_creature();
|
||||
|
||||
private:
|
||||
static inline std::atomic<bool> is_init{false};
|
||||
static inline unsigned m_generator_seed{0};
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
ClientWorld(AudioEngine& auido, Config& config, WorldScene& scene);
|
||||
~ClientWorld();
|
||||
void init(std::string_view player_name,
|
||||
std::shared_ptr<NetworkClient> client);
|
||||
std::shared_ptr<NetworkClient> client, RunMode mode);
|
||||
void update(float dt);
|
||||
bool handle_event(const Event& e);
|
||||
const std::optional<LookBlock>& get_look_block_pos() const;
|
||||
@@ -132,6 +132,7 @@ private:
|
||||
|
||||
static constexpr int WORLD_EXIT_TIMEOUT = 200;
|
||||
static constexpr int MAX_UPLOAD_CHUNK_SUM = 16;
|
||||
std::atomic<RunMode> m_runmode = RunMode::HYBRID;
|
||||
ClientEntityManager m_entity_manager;
|
||||
ClientPlayerManager m_player_manager;
|
||||
ChunkHashMap m_chunks;
|
||||
|
||||
20
include/Cubed/gameplay/creatures/spawn.hpp
Normal file
20
include/Cubed/gameplay/creatures/spawn.hpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/biome.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
namespace Cubed {
|
||||
struct SpawnConfig {
|
||||
std::string_view name; // factory key, e.g. "cubed:pig"
|
||||
std::span<const BiomeType> biomes; // allowed biomes
|
||||
float probability = 0.0f; // per chunk spawn probability
|
||||
unsigned max_spawn_count = 0; // per chunk_max_spawn_sum
|
||||
};
|
||||
|
||||
namespace SpawnDefaults {
|
||||
constexpr std::array<BiomeType, 2> PIG_BIOMES{BiomeType::PLAIN,
|
||||
BiomeType::FOREST};
|
||||
constexpr SpawnConfig PIG{"cubed:pig", PIG_BIOMES, 0.02f, 3};
|
||||
} // namespace SpawnDefaults
|
||||
} // namespace Cubed
|
||||
@@ -14,8 +14,7 @@ public:
|
||||
void stop();
|
||||
|
||||
// Run in another thread after initialization is complete
|
||||
void start_server(int port);
|
||||
void start_server();
|
||||
void start_server(int port, RunMode mode);
|
||||
int port() const;
|
||||
ServerWorld& server_world();
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <entt/entt.hpp>
|
||||
#include <tbb/concurrent_hash_map.h>
|
||||
#include <tbb/concurrent_queue.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
namespace Cubed {
|
||||
class ServerWorld;
|
||||
class Session;
|
||||
@@ -15,7 +16,7 @@ public:
|
||||
void init();
|
||||
void update();
|
||||
// not thread safe
|
||||
void add_entity(std::string_view name, const glm::vec3& pos);
|
||||
void add_entity(std::string_view name, const glm::vec3& world_pos);
|
||||
void destory(EntityID id);
|
||||
void handle_player_login(std::shared_ptr<Session> session);
|
||||
|
||||
@@ -46,8 +47,9 @@ private:
|
||||
void send_all_entities(std::shared_ptr<Session>& session);
|
||||
void update_ai(entt::entity e);
|
||||
void update_move(entt::entity e);
|
||||
void update_send(entt::entity e,
|
||||
std::span<std::shared_ptr<Session>> sessions);
|
||||
void
|
||||
update_send(entt::entity e,
|
||||
tbb::concurrent_vector<std::shared_ptr<Session>>& sessions);
|
||||
template <typename... Args>
|
||||
EntityID create_entity_in_factory(Args&&... args) {
|
||||
auto entity = m_registry.create();
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <tbb/concurrent_hash_map.h>
|
||||
#include <tbb/concurrent_queue.h>
|
||||
#include <tbb/concurrent_unordered_map.h>
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -34,7 +35,7 @@ public:
|
||||
~ServerWorld();
|
||||
void stop();
|
||||
void handle_player_exit(const std::string& uuid);
|
||||
void init_world();
|
||||
void init_world(RunMode mode);
|
||||
void need_gen(std::string uuid);
|
||||
void update();
|
||||
void hot_reload();
|
||||
@@ -92,10 +93,11 @@ public:
|
||||
|
||||
int chunk_size() const;
|
||||
|
||||
std::vector<std::shared_ptr<Session>> get_all_session() const;
|
||||
tbb::concurrent_vector<std::shared_ptr<Session>> get_all_session() const;
|
||||
|
||||
uint32_t get_chunk_ref_count(const glm::vec3& pos) const;
|
||||
|
||||
ServerEntityManager& entity_manager();
|
||||
std::shared_ptr<ThreadPool> get_compute_pool();
|
||||
int get_block(const glm::ivec3& block_pos) const override;
|
||||
bool is_solid(const glm::ivec3& block_pos) const override;
|
||||
bool can_pass_block(const glm::ivec3& block_pos) const override;
|
||||
@@ -113,7 +115,27 @@ private:
|
||||
struct ChunkEntity {
|
||||
ChunkState state;
|
||||
std::shared_ptr<ServerChunk> chunk;
|
||||
uint32_t ref_count = 0;
|
||||
std::atomic<uint32_t> ref_count = 0;
|
||||
ChunkEntity() = default;
|
||||
ChunkEntity(ChunkState s, std::shared_ptr<ServerChunk> c = {})
|
||||
: state(s), chunk(std::move(c)) {}
|
||||
|
||||
ChunkEntity& operator=(ChunkEntity&& o) noexcept {
|
||||
if (this == &o) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
state = std::exchange(o.state, ServerWorld::ChunkState::NONE);
|
||||
chunk = std::move(o.chunk);
|
||||
ref_count = o.ref_count.exchange(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ChunkEntity(ChunkEntity&& o) noexcept
|
||||
: state(std::exchange(o.state, ServerWorld::ChunkState::NONE)),
|
||||
chunk(std::move(o.chunk)), ref_count(o.ref_count.exchange(0)) {}
|
||||
ChunkEntity(const ChunkEntity&) = delete;
|
||||
ChunkEntity& operator=(const ChunkEntity&) = delete;
|
||||
};
|
||||
|
||||
enum class ChunkLoadStyle { RANDOM, CENTER };
|
||||
@@ -141,6 +163,7 @@ private:
|
||||
using uuid_cacc = PlayerUUIDMap::const_accessor;
|
||||
|
||||
Config& m_config;
|
||||
std::atomic<RunMode> m_runmode{RunMode::HYBRID};
|
||||
ServerEntityManager m_entity_manager;
|
||||
// key = uuid
|
||||
PlayerHashMap m_players;
|
||||
@@ -162,8 +185,9 @@ private:
|
||||
std::atomic<bool> m_init{false};
|
||||
std::atomic<bool> m_stopped{false};
|
||||
std::atomic<int> m_rendering_distance{24};
|
||||
std::atomic<int> m_gen_pool_threads{0};
|
||||
std::atomic<int> m_net_pool_threads{0};
|
||||
std::atomic<int> m_gen_threads{0};
|
||||
std::atomic<int> m_net_threads{0};
|
||||
std::atomic<int> m_compute_threads{0};
|
||||
std::atomic<int> m_max_threads{1};
|
||||
std::atomic<size_t> m_player_sum{0};
|
||||
std::atomic<TickType> m_game_ticks{0};
|
||||
@@ -179,6 +203,7 @@ private:
|
||||
|
||||
std::atomic<std::shared_ptr<PriorityThreadPool>> m_gen_thread_pool;
|
||||
std::atomic<std::shared_ptr<ThreadPool>> m_net_thread_pool;
|
||||
std::atomic<std::shared_ptr<ThreadPool>> m_compute_thread_pool;
|
||||
|
||||
std::atomic<ChunkLoadStyle> m_chunk_load_style{ChunkLoadStyle::CENTER};
|
||||
|
||||
|
||||
@@ -26,4 +26,7 @@ public:
|
||||
glm::vec3{0.5f, 0.5f, 0.5f}};
|
||||
}
|
||||
};
|
||||
|
||||
enum class RunMode { CLIENT_ONLY, SERVER_ONLY, HYBRID };
|
||||
|
||||
} // namespace Cubed
|
||||
130
include/Cubed/tools/threas_utils.hpp
Normal file
130
include/Cubed/tools/threas_utils.hpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#pragma once
|
||||
#include "Cubed/gameplay/world.hpp"
|
||||
#include "Cubed/tools/cubed_assert.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
namespace Cubed {
|
||||
namespace Tools {
|
||||
|
||||
constexpr size_t SERVER_RESERVED_THREADS = 3; // tick + netio + gen scheduler
|
||||
constexpr size_t CLIENT_RESERVED_THREADS =
|
||||
3; // main/render + netio + system reserved
|
||||
|
||||
constexpr size_t safe_sub(size_t a, size_t b) { return a > b ? a - b : 0; }
|
||||
|
||||
inline size_t get_hardware_threads() {
|
||||
auto hc = std::thread::hardware_concurrency();
|
||||
return hc == 0 ? 4 : static_cast<size_t>(hc);
|
||||
}
|
||||
|
||||
inline size_t get_server_available_threads() {
|
||||
return std::max<size_t>(
|
||||
1, safe_sub(get_hardware_threads(), SERVER_RESERVED_THREADS));
|
||||
}
|
||||
|
||||
inline size_t get_client_available_threads() {
|
||||
return std::max<size_t>(
|
||||
1, safe_sub(get_hardware_threads(), CLIENT_RESERVED_THREADS));
|
||||
}
|
||||
|
||||
inline size_t get_client_threads(RunMode mode) {
|
||||
switch (mode) {
|
||||
case RunMode::SERVER_ONLY:
|
||||
ASSERT_MSG(false, "Server Only don't need client pool");
|
||||
return 1;
|
||||
case RunMode::CLIENT_ONLY: {
|
||||
auto available = get_client_available_threads();
|
||||
return std::clamp<size_t>(available, 1, 16);
|
||||
}
|
||||
|
||||
case RunMode::HYBRID: {
|
||||
auto available = get_client_available_threads();
|
||||
return std::clamp<size_t>(available / 2, 1, 4);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline size_t get_server_net_pool_threads(RunMode mode) {
|
||||
switch (mode) {
|
||||
|
||||
case RunMode::SERVER_ONLY: {
|
||||
auto available = get_server_available_threads();
|
||||
return std::clamp<size_t>(available / 4, 1,
|
||||
std::min<size_t>(4, available));
|
||||
}
|
||||
|
||||
case RunMode::CLIENT_ONLY:
|
||||
ASSERT_MSG(false, "Client Only don't need net pool");
|
||||
return 1;
|
||||
case RunMode::HYBRID: {
|
||||
auto available = get_server_available_threads();
|
||||
return std::clamp<size_t>(available / 8, 1,
|
||||
std::min<size_t>(4, available));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline size_t get_server_compute_treads(RunMode mode) {
|
||||
switch (mode) {
|
||||
case RunMode::HYBRID:
|
||||
case RunMode::SERVER_ONLY: {
|
||||
auto available = get_server_available_threads();
|
||||
|
||||
return std::clamp<size_t>(available / 4, 1,
|
||||
std::min<size_t>(4, available));
|
||||
}
|
||||
case RunMode::CLIENT_ONLY:
|
||||
ASSERT_MSG(false, "Client Only don't need update pool");
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
inline size_t get_server_gen_threads(RunMode mode) {
|
||||
switch (mode) {
|
||||
case RunMode::SERVER_ONLY: {
|
||||
auto available = get_server_available_threads();
|
||||
|
||||
auto net_pool = get_server_net_pool_threads(mode);
|
||||
|
||||
auto update_pool = get_server_compute_treads(mode);
|
||||
|
||||
size_t remain = available;
|
||||
|
||||
remain -= std::min(remain, net_pool);
|
||||
|
||||
remain -= std::min(remain, update_pool);
|
||||
|
||||
return std::max<size_t>(1, remain);
|
||||
}
|
||||
case RunMode::CLIENT_ONLY:
|
||||
ASSERT_MSG(false, "Client Only don't need gen pool");
|
||||
return 1;
|
||||
case RunMode::HYBRID: {
|
||||
auto available = get_server_available_threads();
|
||||
|
||||
auto net_pool = get_server_net_pool_threads(mode);
|
||||
|
||||
auto update_pool = get_server_compute_treads(mode);
|
||||
|
||||
auto client_pool = get_client_threads(mode);
|
||||
|
||||
size_t remain = available;
|
||||
|
||||
remain -= std::min(remain, net_pool);
|
||||
|
||||
remain -= std::min(remain, update_pool);
|
||||
|
||||
remain -= std::min(remain, client_pool);
|
||||
|
||||
return std::max<size_t>(1, remain);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
} // namespace Tools
|
||||
} // namespace Cubed
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Cubed/gameplay/builders/river_builder.hpp"
|
||||
#include "Cubed/gameplay/builders/snowy_plain_builder.hpp"
|
||||
#include "Cubed/gameplay/cave_path.hpp"
|
||||
#include "Cubed/gameplay/creatures/spawn.hpp"
|
||||
#include "Cubed/gameplay/river.path.hpp"
|
||||
#include "Cubed/gameplay/server_chunk.hpp"
|
||||
#include "Cubed/gameplay/server_world.hpp"
|
||||
@@ -17,6 +18,8 @@
|
||||
#include "Cubed/tools/cubed_hash.hpp"
|
||||
#include "Cubed/tools/math_tools.hpp"
|
||||
#include "Cubed/tools/perlin_noise.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
namespace Cubed {
|
||||
|
||||
namespace {
|
||||
@@ -805,6 +808,35 @@ void ChunkGenerator::generate_river() {
|
||||
}
|
||||
}
|
||||
|
||||
void ChunkGenerator::spawn_creature() {
|
||||
auto biome = m_chunk.biome();
|
||||
const auto& blocks = m_chunk.blocks();
|
||||
const auto& heightmap = m_chunk.heightmap();
|
||||
const auto& chunk_pos = m_chunk.chunk_pos();
|
||||
if (std::ranges::contains(SpawnDefaults::PIG.biomes, biome)) {
|
||||
|
||||
if (m_random.random_bool(SpawnDefaults::PIG.probability)) {
|
||||
int want =
|
||||
m_random.random_int(0, SpawnDefaults::PIG.max_spawn_count);
|
||||
for (int i = 0; i < want; ++i) {
|
||||
int x = m_random.random_int(0, CHUNK_SIZE - 1);
|
||||
int z = m_random.random_int(0, CHUNK_SIZE - 1);
|
||||
int y = static_cast<int>(heightmap[x][z]);
|
||||
glm::vec3 pos(x, y + 1, z);
|
||||
auto type = blocks[Chunk::index(pos)];
|
||||
if (type != 0) {
|
||||
continue;
|
||||
}
|
||||
auto [world_x, world_y, world_z] = Chunk::block_to_world(
|
||||
x, y + 1, z, chunk_pos.x, chunk_pos.z);
|
||||
m_chunk.world().entity_manager().add_entity(
|
||||
SpawnDefaults::PIG.name,
|
||||
glm::vec3{world_x, world_y, world_z});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ServerChunk& ChunkGenerator::chunk() { return m_chunk; }
|
||||
|
||||
Random& ChunkGenerator::random() { return m_random; }
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "Cubed/gameplay/game_time.hpp"
|
||||
#include "Cubed/gameplay/packet.hpp"
|
||||
#include "Cubed/scene/world_scene.hpp"
|
||||
#include "Cubed/tools/threas_utils.hpp"
|
||||
#include "Cubed/tools/time_tools.hpp"
|
||||
|
||||
#include <absl/container/inlined_vector.h>
|
||||
@@ -363,7 +364,8 @@ void ClientWorld::send_player_water_sound(bool underwater,
|
||||
}
|
||||
|
||||
void ClientWorld::init(std::string_view player_name,
|
||||
std::shared_ptr<NetworkClient> client) {
|
||||
std::shared_ptr<NetworkClient> client, RunMode mode) {
|
||||
m_runmode = mode;
|
||||
m_entity_manager.init();
|
||||
m_player_manager.init(player_name);
|
||||
m_client = client;
|
||||
@@ -480,8 +482,8 @@ void ClientWorld::stop_client_thread() {
|
||||
m_game_running = false;
|
||||
}
|
||||
void ClientWorld::start_thread_pool() {
|
||||
int max_threads = std::thread::hardware_concurrency();
|
||||
int threads = std::min<size_t>(max_threads, 4);
|
||||
auto threads = Tools::get_client_threads(m_runmode);
|
||||
Logger::info("Client pool threads {}", threads);
|
||||
change_pool_threads(threads);
|
||||
}
|
||||
void ClientWorld::stop_thread_pool() {
|
||||
@@ -500,7 +502,6 @@ void ClientWorld::change_pool_threads(int threads) {
|
||||
m_max_threads = 1;
|
||||
}
|
||||
int used_thread = std::clamp(threads, 1, m_max_threads);
|
||||
Logger::info("Create New Thread Pool Use {} Threads", used_thread);
|
||||
m_thread_pool.store(std::make_shared<PriorityThreadPool>(used_thread));
|
||||
}
|
||||
|
||||
|
||||
@@ -92,14 +92,10 @@ void NetworkServer::net_run() {
|
||||
Logger::info("Server Started!");
|
||||
}
|
||||
|
||||
void NetworkServer::start_server(int port) {
|
||||
void NetworkServer::start_server(int port, RunMode mode) {
|
||||
m_port = port;
|
||||
m_config.set("port", m_port);
|
||||
start_server();
|
||||
}
|
||||
|
||||
void NetworkServer::start_server() {
|
||||
m_world.init_world();
|
||||
m_world.init_world(mode);
|
||||
net_run();
|
||||
m_started = true;
|
||||
}
|
||||
|
||||
@@ -141,6 +141,7 @@ void ServerChunk::gen_phase_five() {
|
||||
m_generator->generate_cave();
|
||||
|
||||
m_generator->generate_vegetation();
|
||||
m_generator->spawn_creature();
|
||||
m_generator = nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +33,31 @@ void ServerEntityManager::update() {
|
||||
handle_task();
|
||||
|
||||
auto view = m_registry.view<BaseServerCreature>();
|
||||
auto sessions = m_world.get_all_session();
|
||||
for (auto e : view) {
|
||||
const auto& c = view.get<BaseServerCreature>(e);
|
||||
if (!m_world.get_chunk_ref_count(c.transform.position.value)) {
|
||||
continue;
|
||||
}
|
||||
update_ai(e);
|
||||
update_move(e);
|
||||
update_send(e, sessions);
|
||||
|
||||
auto pool = m_world.get_compute_pool();
|
||||
if (!pool) {
|
||||
return;
|
||||
}
|
||||
auto sessions = m_world.get_all_session();
|
||||
std::vector<entt::entity> entities;
|
||||
for (auto e : view) {
|
||||
entities.push_back(e);
|
||||
}
|
||||
// parallel block touches disjoint entities only;
|
||||
// structural registry changes stay on the server thread via m_tasks.
|
||||
parallel_do(
|
||||
*pool, entities.begin(), entities.end(), pool->thread_sum(),
|
||||
[this, &sessions](entt::entity e) {
|
||||
const auto& c = m_registry.get<BaseServerCreature>(e);
|
||||
if (!m_world.get_chunk_ref_count(c.transform.position.value)) {
|
||||
const auto& entity = m_registry.get<Entity>(e);
|
||||
destory(entity.id);
|
||||
return;
|
||||
}
|
||||
update_ai(e);
|
||||
update_move(e);
|
||||
update_send(e, sessions);
|
||||
});
|
||||
}
|
||||
|
||||
void ServerEntityManager::update_ai(entt::entity e) {
|
||||
@@ -57,7 +72,8 @@ void ServerEntityManager::update_move(entt::entity e) {
|
||||
}
|
||||
|
||||
void ServerEntityManager::update_send(
|
||||
entt::entity e, std::span<std::shared_ptr<Session>> sessions) {
|
||||
entt::entity e,
|
||||
tbb::concurrent_vector<std::shared_ptr<Session>>& sessions) {
|
||||
|
||||
if (!m_registry.all_of<Entity, BaseServerCreature>(e)) {
|
||||
return;
|
||||
@@ -102,9 +118,9 @@ void ServerEntityManager::handle_task() {
|
||||
}
|
||||
|
||||
void ServerEntityManager::add_entity(std::string_view name,
|
||||
const glm::vec3& pos) {
|
||||
const glm::vec3& world_pos) {
|
||||
m_tasks.emplace(Command::CREATE,
|
||||
EntityCreateElement{std::string(name), pos});
|
||||
EntityCreateElement{std::string(name), world_pos});
|
||||
}
|
||||
|
||||
void ServerEntityManager::destory(EntityID id) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Cubed/tools/log.hpp"
|
||||
#include "Cubed/tools/math_tools.hpp"
|
||||
#include "Cubed/tools/net_utils.hpp"
|
||||
#include "Cubed/tools/threas_utils.hpp"
|
||||
#include "Cubed/tools/uuid.hpp"
|
||||
|
||||
#include <ranges>
|
||||
@@ -178,10 +179,9 @@ void ServerWorld::send_chunk(int task_id, const std::string& uuid,
|
||||
s->send(make_packet(*rsp));
|
||||
}
|
||||
|
||||
void ServerWorld::init_world() {
|
||||
|
||||
void ServerWorld::init_world(RunMode mode) {
|
||||
m_runmode = mode;
|
||||
m_entity_manager.init();
|
||||
m_entity_manager.add_entity("cubed:pig", {0, 225, 0});
|
||||
register_timer("player disconnect", 5, [this]() {
|
||||
std::vector<std::string> disconnect;
|
||||
{
|
||||
@@ -318,7 +318,7 @@ void ServerWorld::sync_and_collect_missing_chunks(
|
||||
chunk_acc acc;
|
||||
if (m_chunks.insert(acc, pos)) {
|
||||
need_gen_chunks_pos.push_back(pos);
|
||||
acc->second = ChunkEntity{ChunkState::GENERATING, nullptr, 0};
|
||||
acc->second = ChunkEntity{ChunkState::GENERATING};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -361,7 +361,7 @@ void ServerWorld::submit_new_chunks(const std::string& uuid,
|
||||
return dist2(a.first) < dist2(b.first);
|
||||
});
|
||||
|
||||
const int CHUNKS_PER_PRIORITY = m_gen_pool_threads;
|
||||
const int CHUNKS_PER_PRIORITY = m_gen_threads;
|
||||
|
||||
for (size_t i = 0; i < tasks.size(); ++i) {
|
||||
int priority = 10 + static_cast<int>(i / CHUNKS_PER_PRIORITY);
|
||||
@@ -411,20 +411,30 @@ void ServerWorld::start_server_thread() {
|
||||
}
|
||||
|
||||
void ServerWorld::start_thread_pool() {
|
||||
int max_thread = std::thread::hardware_concurrency();
|
||||
if (m_gen_pool_threads == 0) {
|
||||
m_gen_pool_threads = change_pool_threads(m_gen_thread_pool,
|
||||
max_thread - RESERVED_THREADS);
|
||||
if (m_gen_threads == 0) {
|
||||
auto gen_threads = Tools::get_server_gen_threads(m_runmode);
|
||||
Logger::info("Server Gen pool threads {}", gen_threads);
|
||||
m_gen_threads = change_pool_threads(m_gen_thread_pool, gen_threads);
|
||||
} else {
|
||||
m_gen_pool_threads =
|
||||
change_pool_threads(m_gen_thread_pool, m_gen_pool_threads);
|
||||
m_gen_threads = change_pool_threads(m_gen_thread_pool, m_gen_threads);
|
||||
}
|
||||
|
||||
if (m_net_pool_threads == 0) {
|
||||
m_net_pool_threads = change_pool_threads(m_net_thread_pool, 4);
|
||||
if (m_net_threads == 0) {
|
||||
auto net_threads = Tools::get_server_net_pool_threads(m_runmode);
|
||||
Logger::info("Server Net pool threads {}", net_threads);
|
||||
m_net_threads = change_pool_threads(m_net_thread_pool, net_threads);
|
||||
} else {
|
||||
m_net_pool_threads =
|
||||
change_pool_threads(m_net_thread_pool, m_net_pool_threads);
|
||||
m_net_threads = change_pool_threads(m_net_thread_pool, m_net_threads);
|
||||
}
|
||||
|
||||
if (m_compute_threads == 0) {
|
||||
auto compute_threads = Tools::get_server_compute_treads(m_runmode);
|
||||
Logger::info("Server compute pool threads {}", compute_threads);
|
||||
m_compute_threads =
|
||||
change_pool_threads(m_compute_thread_pool, compute_threads);
|
||||
} else {
|
||||
m_compute_threads =
|
||||
change_pool_threads(m_compute_thread_pool, m_compute_threads);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,6 +469,13 @@ void ServerWorld::stop_thread_pool() {
|
||||
}
|
||||
m_net_thread_pool.store(nullptr);
|
||||
Logger::info("Net Thread Pool Stopped");
|
||||
|
||||
auto c = m_compute_thread_pool.load();
|
||||
if (c) {
|
||||
c->stop();
|
||||
}
|
||||
m_compute_thread_pool.store(nullptr);
|
||||
Logger::info("Compute Thread Pool Stopped");
|
||||
}
|
||||
|
||||
void ServerWorld::serever_run(std::stop_token stoken) {
|
||||
@@ -910,16 +927,16 @@ void ServerWorld::per_tick_time(int ms) { m_per_tick_time = ms; }
|
||||
|
||||
bool ServerWorld::is_tick_running() const { return m_tick_running.load(); }
|
||||
void ServerWorld::tick_running(bool run) { m_tick_running = run; }
|
||||
int ServerWorld::gen_pool_threads() const { return m_gen_pool_threads.load(); }
|
||||
int ServerWorld::gen_pool_threads() const { return m_gen_threads.load(); }
|
||||
int ServerWorld::max_threads() const { return m_max_threads.load(); }
|
||||
|
||||
void ServerWorld::change_pool_threads(ThreadPoolKind kind, int threads) {
|
||||
switch (kind) {
|
||||
case ThreadPoolKind::NET:
|
||||
m_net_pool_threads = change_pool_threads(m_net_thread_pool, threads);
|
||||
m_net_threads = change_pool_threads(m_net_thread_pool, threads);
|
||||
break;
|
||||
case ThreadPoolKind::GEN:
|
||||
m_gen_pool_threads = change_pool_threads(m_gen_thread_pool, threads);
|
||||
m_gen_threads = change_pool_threads(m_gen_thread_pool, threads);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -946,7 +963,6 @@ int ServerWorld::change_pool_threads(
|
||||
m_max_threads = 1;
|
||||
}
|
||||
int used_thread = std::clamp(threads, 1, m_max_threads.load());
|
||||
Logger::info("Create New Thread Pool Use {} Threads", used_thread);
|
||||
thread_pool.store(std::make_shared<PriorityThreadPool>(used_thread));
|
||||
return used_thread;
|
||||
}
|
||||
@@ -1011,9 +1027,10 @@ void ServerWorld::set_chunk_load_style(int id) {
|
||||
|
||||
int ServerWorld::chunk_size() const { return m_chunks.size(); }
|
||||
|
||||
std::vector<std::shared_ptr<Session>> ServerWorld::get_all_session() const {
|
||||
tbb::concurrent_vector<std::shared_ptr<Session>>
|
||||
ServerWorld::get_all_session() const {
|
||||
std::shared_lock lock(m_players_mutex);
|
||||
std::vector<std::shared_ptr<Session>> sessions;
|
||||
tbb::concurrent_vector<std::shared_ptr<Session>> sessions;
|
||||
for (const auto& [_, player] : m_players) {
|
||||
sessions.emplace_back(player.get_session());
|
||||
}
|
||||
@@ -1114,5 +1131,8 @@ BlockType ServerWorld::get_block_tpye(const glm::ivec3& block_pos) const {
|
||||
}
|
||||
|
||||
int ServerWorld::get_per_tick_time() const { return m_per_tick_time; }
|
||||
|
||||
ServerEntityManager& ServerWorld::entity_manager() { return m_entity_manager; }
|
||||
std::shared_ptr<ThreadPool> ServerWorld::get_compute_pool() {
|
||||
return m_compute_thread_pool.load();
|
||||
}
|
||||
} // namespace Cubed
|
||||
@@ -129,10 +129,21 @@ void WorldScene::on_enter() {
|
||||
load_config();
|
||||
m_error_ui.init();
|
||||
m_client = std::make_shared<NetworkClient>(m_client_world);
|
||||
RunMode mode = RunMode::HYBRID;
|
||||
if (m_argument.direct_enter) {
|
||||
if (m_argument.ip) {
|
||||
mode = RunMode::CLIENT_ONLY;
|
||||
}
|
||||
} else {
|
||||
if (!m_scene_manager.world_scene_param().host_game) {
|
||||
mode = RunMode::CLIENT_ONLY;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_argument.direct_enter) {
|
||||
if (!m_argument.ip) {
|
||||
ChunkGenerator::init();
|
||||
m_server.start_server(*m_argument.port);
|
||||
m_server.start_server(*m_argument.port, mode);
|
||||
m_client->start("127.0.0.1", *m_argument.port);
|
||||
} else {
|
||||
m_client->start(*m_argument.ip, *m_argument.port);
|
||||
@@ -148,7 +159,7 @@ void WorldScene::on_enter() {
|
||||
} else {
|
||||
ChunkGenerator::init();
|
||||
}
|
||||
m_server.start_server(param.port);
|
||||
m_server.start_server(param.port, mode);
|
||||
}
|
||||
|
||||
m_client->start(param.ip, param.port);
|
||||
@@ -157,7 +168,8 @@ void WorldScene::on_enter() {
|
||||
// init will send packet
|
||||
try {
|
||||
|
||||
m_client_world.init(m_argument.player.value_or("Unknown"), m_client);
|
||||
m_client_world.init(m_argument.player.value_or("Unknown"), m_client,
|
||||
mode);
|
||||
|
||||
Logger::info("World Init Success");
|
||||
m_camera.camera_init(&m_client_world.get_player());
|
||||
|
||||
Reference in New Issue
Block a user