From 28b66ee275c15b90847599371829ae0a0d8dc2c9 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sun, 28 Jun 2026 14:27:30 +0800 Subject: [PATCH] refactor(world): rework chunk state machine and player chunk tracking Introduce ChunkState enum and ChunkEntity struct to manage chunk lifecycle. Store chunks as shared_ptr to avoid move operations during generation. Add clear_unused_chunks to remove chunks not referenced by any player. Implement deferred chunk request queue for safe processing after generation completes. Update player chunk set during required chunk computation. Improve thread safety with mutexes on chunk and player maps. Fix m_gening flag not reset after generation and add assertions for correctness. Change need_gen to require a player UUID, removing std::optional. Add chunk_size query method for debugging. --- CMakeLists.txt | 3 + include/Cubed/gameplay/server_chunk.hpp | 1 + include/Cubed/gameplay/server_player.hpp | 14 + include/Cubed/gameplay/server_world.hpp | 39 ++- src/dev_panel.cpp | 3 +- src/gameplay/server_chunk.cpp | 9 +- src/gameplay/server_player.cpp | 10 + src/gameplay/server_world.cpp | 314 +++++++++++++++-------- 8 files changed, 280 insertions(+), 113 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0b9e45b..756c4f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,9 @@ target_link_libraries(${PROJECT_NAME} protobuf::libprotobuf absl::log absl::check + absl::base + absl::strings + absl::flat_hash_map zstd::zstd $<$:ws2_32> diff --git a/include/Cubed/gameplay/server_chunk.hpp b/include/Cubed/gameplay/server_chunk.hpp index eb5be60..8fa7075 100644 --- a/include/Cubed/gameplay/server_chunk.hpp +++ b/include/Cubed/gameplay/server_chunk.hpp @@ -93,4 +93,5 @@ private: // Generate biome-specific vegetation/structures void gen_phase_five(); }; + } // namespace Cubed diff --git a/include/Cubed/gameplay/server_player.hpp b/include/Cubed/gameplay/server_player.hpp index c809bff..99c9631 100644 --- a/include/Cubed/gameplay/server_player.hpp +++ b/include/Cubed/gameplay/server_player.hpp @@ -5,16 +5,26 @@ #include #include #include +#include #include #include +#include namespace Cubed { class ServerWorld; class Session; class ServerPlayer { + using ChunkPosSet = std::unordered_set; + public: + ServerPlayer(const ServerPlayer&) = delete; + ServerPlayer(ServerPlayer&&) = delete; + ServerPlayer& operator=(const ServerPlayer&) = delete; + ServerPlayer& operator=(ServerPlayer&&) = delete; ServerPlayer(std::string_view name, std::string_view uuid, ServerWorld& m_world, std::shared_ptr session, TickType gametick); + using PlayerChunkPosSet = std::unordered_set; + const glm::vec3& get_pos() const; const std::string& get_name() const; const std::string& get_uuid() const; @@ -24,6 +34,8 @@ public: bool is_disconnect(TickType current_gametick) const; int task_id() const; void task_id(int id); + bool has_player(ChunkPos pos) const; + void update_chunk_set(const ChunkPosSet& set); private: static constexpr TickType TIMEOUT = 200; @@ -35,5 +47,7 @@ private: std::shared_ptr m_session; std::atomic m_last_gametick{0}; std::atomic m_chunk_task_id{0}; + mutable std::shared_mutex m_chunk_pos_mutex; + PlayerChunkPosSet m_player_chunk_pos_set; }; } // namespace Cubed diff --git a/include/Cubed/gameplay/server_world.hpp b/include/Cubed/gameplay/server_world.hpp index 7330759..e1eb18b 100644 --- a/include/Cubed/gameplay/server_world.hpp +++ b/include/Cubed/gameplay/server_world.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,9 @@ class ServerWorld { public: ServerWorld(); ~ServerWorld(); - void player_join(std::string_view name, std::string_view uuid); void handle_player_exit(const std::string& uuid); void init_world(); - void need_gen(std::optional uuid); + void need_gen(std::string uuid); void update(); void hot_reload(); @@ -74,6 +74,9 @@ public: void handle_chunk_req(int task_id, const std::string& uuid, ChunkPos pos); void handle_block_change(const BlockChangeReq& req); + + int chunk_size() const; + template void register_timer(std::string_view id, TickType threshold, Fn&& f) { m_timers.emplace(std::piecewise_construct, @@ -82,25 +85,42 @@ public: } private: + enum class ChunkState { NONE, GENERATING, READY, PENDING_DELETE }; + struct ChunkEntity { + ChunkState state; + std::shared_ptr chunk; + }; + enum class ChunkLoadStyle { RANDOM, CENTER }; + struct PendingRequest { + std::string uuid; + int task_id; + ChunkPos pos; + }; struct PendingChunk { ServerChunk chunk; std::future future; }; + struct FinishedChunk { + ChunkPos pos; + std::shared_ptr chunk; + }; + using ChunkHashMap = - tbb::concurrent_unordered_map; + std::unordered_map; using PlayerHashMap = std::unordered_map; using PendingChunkHashMap = std::unordered_map; using ChunkPosSet = std::unordered_set; using PlayerUUIDMap = tbb::concurrent_hash_map; + using uuid_acc = PlayerUUIDMap::accessor; using uuid_cacc = PlayerUUIDMap::const_accessor; // key = uuid PlayerHashMap m_players; ChunkHashMap m_chunks; PendingChunkHashMap m_new_chunks; - std::vector> m_new_finished_chunk; + std::vector m_new_finished_chunk; CaveCarver m_cave_carcer; RiverWorm m_river_worm; @@ -136,19 +156,26 @@ private: std::atomic m_chunk_load_style{ChunkLoadStyle::CENTER}; PlayerUUIDMap m_uuid_to_name; + tbb::concurrent_unordered_map m_timers; + tbb::concurrent_queue m_waiting_chunk_requests; + void init_chunks(); - void gen_chunks_internal(std::optional uuid); + void gen_chunks_internal(const std::string& uuid); void compute_required_chunks(ChunkPosSet& required_chunks, const std::optional& uuid); void sync_and_collect_missing_chunks(std::vector&, const ChunkPosSet&); - void submit_new_chunks(const std::optional& uuid); + void submit_new_chunks(const std::string& uuid); void poll_finished_chunks(); void wait_all_chunk_tasks(); + void clear_unused_chunks(); + void send_time(); + + void send_chunk(int task_id, const std::string& uuid, ChunkPos pos); }; } // namespace Cubed diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index f871b91..2aeecd4 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -530,7 +530,7 @@ void DevPanel::show_server_world_table_bar() { ImGui::SameLine(); if (ImGui::Button("Request Chunk Build")) { Logger::warn("This Request Chunk Build button is not finish"); - m_app.server_world().need_gen(std::nullopt); + m_app.server_world().need_gen(m_player->get_uuid()); } ImGui::SameLine(); if (ImGui::Checkbox("Gen Thread", &m_gen_thread_running)) { @@ -540,6 +540,7 @@ void DevPanel::show_server_world_table_bar() { m_app.server_world().stop_gen_thread(); } } + ImGui::Text("Server Chunk Size %d", m_app.server_world().chunk_size()); if (ImGui::BeginTabBar("World Settings")) { if (ImGui::BeginTabItem("Time")) { diff --git a/src/gameplay/server_chunk.cpp b/src/gameplay/server_chunk.cpp index 619f880..ee7f711 100644 --- a/src/gameplay/server_chunk.cpp +++ b/src/gameplay/server_chunk.cpp @@ -13,7 +13,9 @@ ServerChunk::ServerChunk(ServerChunk&& other) noexcept m_world(other.m_world), m_heightmap(std::move(other.m_heightmap)), m_blocks(std::move(other.m_blocks)), m_neightbor_blocks(std::move(other.m_neightbor_blocks)), - m_seed(other.m_seed), m_conditions(other.m_conditions) {} + m_seed(other.m_seed), m_conditions(other.m_conditions) { + ASSERT_MSG(!other.m_gening, "Other is Gening Can't Move"); +} ServerChunk& ServerChunk::operator=(ServerChunk&& other) noexcept { // Logger::info("other Chunk pos {} {} in Chunk& Chunk::operator=(Chunk&& @@ -22,6 +24,7 @@ ServerChunk& ServerChunk::operator=(ServerChunk&& other) noexcept { if (this == &other) { return *this; } + ASSERT_MSG(!other.m_gening, "Other is Gening Can't Move"); m_chunk_pos = std::move(other.m_chunk_pos); m_heightmap = std::move(other.m_heightmap); m_blocks = std::move(other.m_blocks); @@ -145,10 +148,13 @@ void ServerChunk::gen_chunk() { if (m_gening.exchange(true)) return; m_gening = true; + ASSERT_MSG(m_blocks.empty(), + "Blocks isn't Empty, chunk already generated!"); if (m_blocks.size() != 0) { Logger::warn( "Request Generator Chunk {} {} ,but the Blocks size is Not 0", m_chunk_pos.x, m_chunk_pos.z); + return; } std::vector neighbor; for (int i = 0; i < 4; i++) { @@ -169,6 +175,7 @@ void ServerChunk::gen_chunk() { } gen_phase_four(m_neightbor_blocks); gen_phase_five(); + m_gening = false; } // Logger::info("Cross Sum {}", m_cross_vertices_sum.load()); diff --git a/src/gameplay/server_player.cpp b/src/gameplay/server_player.cpp index 164cce7..e7fc820 100644 --- a/src/gameplay/server_player.cpp +++ b/src/gameplay/server_player.cpp @@ -34,4 +34,14 @@ bool ServerPlayer::is_disconnect(TickType current_gametick) const { int ServerPlayer::task_id() const { return m_chunk_task_id.load(); } void ServerPlayer::task_id(int id) { m_chunk_task_id = id; } +bool ServerPlayer::has_player(ChunkPos pos) const { + std::shared_lock lock(m_chunk_pos_mutex); + return m_player_chunk_pos_set.find(pos) != m_player_chunk_pos_set.end(); +} +void ServerPlayer::update_chunk_set(const ChunkPosSet& set) { + std::lock_guard lock(m_chunk_pos_mutex); + m_player_chunk_pos_set.clear(); + m_player_chunk_pos_set.insert(set.begin(), set.end()); +} + } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index 3aebf44..2b95c76 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -7,6 +7,7 @@ #include "Cubed/tools/log.hpp" #include "Cubed/tools/uuid.hpp" +#include #include using namespace std::chrono; using namespace std::chrono_literals; @@ -32,10 +33,37 @@ ServerWorld::~ServerWorld() { void ServerWorld::wait_all_chunk_tasks() { std::lock_guard lock(m_new_chunk_mutex); for (auto& [pos, task] : m_new_chunks) { - task.future.get(); + if (task.future.valid()) { + try { + task.future.get(); + } catch (const std::exception& e) { + Logger::error("Chunk generation failed: {}", e.what()); + continue; + } + } else { + Logger::error("Chunk {} {} not started gen task", pos.x, pos.z); + } } } +void ServerWorld::clear_unused_chunks() { + + std::scoped_lock lock(m_chunks_mutex, m_player_mutex); + Logger::info("before {}", m_chunks.size()); + + size_t removed = std::erase_if(m_chunks, [this](const auto& item) { + const auto& [pos, chunk] = item; + for (const auto& [uuid, player] : m_players) { + if (player.has_player(pos)) { + return false; + } + } + return true; + }); + Logger::info("removed: {}", removed); + Logger::info("after {}", m_chunks.size()); +} + void ServerWorld::send_time() { Arena arena; auto* rsp = Arena::Create(&arena); @@ -48,6 +76,84 @@ void ServerWorld::send_time() { } } +void ServerWorld::send_chunk(int task_id, const std::string& uuid, + ChunkPos pos) { + + { + std::shared_lock lock(m_player_mutex); + auto it = m_players.find(uuid); + if (it == m_players.end()) { + return; + } + if (task_id < it->second.task_id()) { + // Old chunk requests are simply discarded + return; + } + } + + Arena arean; + ChunkDataRsp* rsp = Arena::Create(&arean); + auto* rsq_pos = rsp->mutable_pos(); + rsq_pos->set_x(pos.x); + rsq_pos->set_z(pos.z); + { + std::shared_lock lock(m_chunks_mutex); + auto it = m_chunks.find(pos); + if (it == m_chunks.end()) { + // No chunk found and not generating + Logger::error("Chunk {} {} neither pending nor ready", pos.x, + pos.z); + return; + } + + if (it->second.state == ChunkState::GENERATING) { + + m_waiting_chunk_requests.emplace(uuid, task_id, pos); + return; + } + + rsp->set_chunk_seed(it->second.chunk->seed()); + rsp->set_biome_type(std::to_underlying(it->second.chunk->biome())); + auto* blocks = rsp->mutable_chunk_blocks(); + auto& chunk_blocks = it->second.chunk->get_chunk_blocks(); + blocks->Assign(chunk_blocks.begin(), chunk_blocks.end()); + auto& neighbor_blocks = it->second.chunk->get_neightbor_blocks(); + auto assign = [](auto* nb, + const std::optional>& blocks) { + if (!blocks) { + return; + } + if (!nb) { + return; + } + nb->Assign(blocks->begin(), blocks->end()); + }; + auto* nb1 = rsp->mutable_neighbor_blocks_1(); + auto* nb2 = rsp->mutable_neighbor_blocks_2(); + auto* nb3 = rsp->mutable_neighbor_blocks_3(); + auto* nb4 = rsp->mutable_neighbor_blocks_4(); + assign(nb1, neighbor_blocks[0]); + assign(nb2, neighbor_blocks[1]); + assign(nb3, neighbor_blocks[2]); + assign(nb4, neighbor_blocks[3]); + } + std::shared_ptr s; + { + std::shared_lock lock(m_player_mutex); + auto it = m_players.find(uuid); + if (it != m_players.end()) { + s = it->second.get_session(); + it->second.update_sync_gametick(m_game_ticks); + } + } + if (!s) { + Logger::error("Player {} session not exist", uuid); + return; + } + rsp->set_task_id(task_id); + s->send(make_packet(*rsp)); +} + void ServerWorld::init_world() { register_timer("player disconnect", 5, [this]() { @@ -64,6 +170,13 @@ void ServerWorld::init_world() { handle_player_exit(uuid); } }); + // Periodically process pending players + register_timer("player chunk send", 1, [this]() { + PendingRequest request; + if (m_waiting_chunk_requests.try_pop(request)) { + handle_chunk_req(request.task_id, request.uuid, request.pos); + } + }); m_cave_carcer.init(ChunkGenerator::seed()); m_river_worm.init(ChunkGenerator::seed()); @@ -84,27 +197,35 @@ void ServerWorld::init_world() { void ServerWorld::init_chunks() { hot_reload(); } -void ServerWorld::gen_chunks_internal(std::optional uuid) { +void ServerWorld::gen_chunks_internal(const std::string& uuid) { // Logger::info("gen_chunks_internal"); m_chunk_gen_finished = false; ChunkPosSet required_chunks; compute_required_chunks(required_chunks, uuid); - - ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!"); - std::vector need_gen_chunks_pos; sync_and_collect_missing_chunks(need_gen_chunks_pos, required_chunks); + { + std::lock_guard lock(m_player_mutex); + auto it = m_players.find(uuid); + if (it == m_players.end()) { + return; + } + it->second.update_chunk_set(required_chunks); + } + ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!"); + clear_unused_chunks(); Logger::info("New Gen Chunks Sum: {}", need_gen_chunks_pos.size()); - if (need_gen_chunks_pos.empty()) { + if (need_gen_chunks_pos.empty() && m_new_chunks.empty()) { m_could_gen = true; return; } { + // Create new chunk std::lock_guard lock(m_new_chunk_mutex); for (auto& pos : need_gen_chunks_pos) { m_new_chunks.emplace(pos, ServerChunk(*this, pos)); @@ -138,26 +259,24 @@ void ServerWorld::compute_required_chunks( } } } + void ServerWorld::sync_and_collect_missing_chunks( std::vector& need_gen_chunks_pos, const ChunkPosSet& required_chunks) { - std::lock_guard lk(m_chunks_mutex); - for (auto it = m_chunks.begin(); it != m_chunks.end();) { - if (required_chunks.find(it->first) == required_chunks.end()) { - it = m_chunks.unsafe_erase(it); - } else { - ++it; - } - } - - for (auto pos : required_chunks) { - auto it = m_chunks.find(pos); - if (it == m_chunks.end()) { - need_gen_chunks_pos.push_back(pos); + { + std::lock_guard lock(m_chunks_mutex); + for (auto pos : required_chunks) { + auto it = m_chunks.find(pos); + if (it == m_chunks.end()) { + need_gen_chunks_pos.push_back(pos); + m_chunks.emplace(pos, + ChunkEntity{ChunkState::GENERATING, nullptr}); + } } } } -void ServerWorld::submit_new_chunks(const std::optional& uuid) { + +void ServerWorld::submit_new_chunks(const std::string& uuid) { using enum ChunkLoadStyle; std::lock_guard lock(m_new_chunk_mutex); auto pool_ptr = m_gen_thread_pool.load(); @@ -166,6 +285,7 @@ void ServerWorld::submit_new_chunks(const std::optional& uuid) { } switch (m_chunk_load_style) { case RANDOM: + // Enqueue directly in random order for (auto& [pos, task] : m_new_chunks) { if (!task.future.valid()) { task.future = @@ -180,12 +300,8 @@ void ServerWorld::submit_new_chunks(const std::optional& uuid) { tasks.emplace_back(pos, &task); } } - glm::vec3 player_pos; - if (uuid == std::nullopt) { - player_pos = glm::vec3{0.0f}; - } else { - player_pos = get_player_pos(uuid.value()); - } + glm::vec3 player_pos = get_player_pos(uuid); + auto dist2 = [player_pos](ChunkPos chunk_pos) { ChunkPos player_chunk_pos = get_chunk_pos(player_pos.x, player_pos.z); @@ -220,10 +336,17 @@ void ServerWorld::poll_finished_chunks() { if (pending.future.wait_for(0ms) != std::future_status::ready) { return false; } - pending.future.get(); + try { + pending.future.get(); + } catch (const std::exception& e) { + Logger::error("Chunk generation failed: {}", e.what()); + return true; + } + // Spawn complete, move away + m_new_finished_chunk.emplace_back( + pair.first, + std::make_shared(std::move(pending.chunk))); - m_new_finished_chunk.emplace_back(pair.first, - std::move(pending.chunk)); return true; }); } @@ -246,7 +369,7 @@ void ServerWorld::start_gen_thread() { break; } m_need_gen_chunk = false; - std::optional uuid{std::nullopt}; + std::string uuid; if (!m_need_gen_queue.empty()) { uuid = m_need_gen_queue.front(); m_need_gen_queue.pop(); @@ -316,7 +439,7 @@ void ServerWorld::serever_run(std::stop_token stoken) { Logger::info("Server Thread Stopped!"); } -void ServerWorld::need_gen(std::optional uuid) { +void ServerWorld::need_gen(std::string uuid) { // if (!m_could_gen) { // Logger::warn("It is generating or consuming new chunks"); @@ -325,9 +448,9 @@ void ServerWorld::need_gen(std::optional uuid) { m_could_gen = false; - if (uuid) { + { std::lock_guard lock(m_need_gen_queue_mutex); - m_need_gen_queue.enqueue(*uuid); + m_need_gen_queue.enqueue(std::move(uuid)); } // m_gen_player_pos = get_player("TestPlayer").get_player_pos(); @@ -359,7 +482,7 @@ bool ServerWorld::set_block(const glm::ivec3& block_pos, unsigned id) { return false; } - it->second.set_chunk_block(ServerChunk::index(x, y, z), id); + it->second.chunk->set_chunk_block(ServerChunk::index(x, y, z), id); return true; } @@ -367,7 +490,6 @@ void ServerWorld::hot_reload() { auto& config = Config::get(); int dist = config.get("world.rendering_distance"); m_rendering_distance = dist <= MAX_DISTANCE ? dist : MAX_DISTANCE; - need_gen(std::nullopt); } void ServerWorld::rebuild_world() { @@ -391,7 +513,6 @@ void ServerWorld::rebuild_world() { ChunkGenerator::reload(); start_thread_pool(); start_gen_thread(); - need_gen(std::nullopt); Arena arena; auto* rsp = Arena::Create(&arena); rsp->set_clear(true); @@ -410,15 +531,27 @@ void ServerWorld::update() { { std::lock_guard lk(m_chunks_mutex); bool consumed = false; - + auto size = m_new_finished_chunk.size(); + if (size != 0) { + Logger::info("New generated {} chunks", size); + } for (auto& x : m_new_finished_chunk) { - m_chunks.emplace(x.first, std::move(x.second)); + auto it = m_chunks.find(x.pos); + if (it == m_chunks.end()) { + Logger::error( + "New Chunk {} {} not Find, don't move to m_chunks", x.pos.x, + x.pos.z); + continue; + } + it->second.chunk = std::move(x.chunk); + it->second.state = ChunkState::READY; consumed = true; } if (consumed) { m_could_gen = true; } } + send_time(); for (auto& [id, timer] : m_timers) { timer.update(); @@ -469,14 +602,43 @@ void ServerWorld::handle_player_login(const std::string& name, std::shared_ptr session) { std::string uuid = generate_uuid(); Logger::info("Player {} (uuid {}) join the world", name, uuid); + bool sucess = true; { std::lock_guard lock(m_player_mutex); - m_players.emplace( + auto [_, inserted] = m_players.emplace( std::piecewise_construct, std::forward_as_tuple(std::string(uuid)), std::forward_as_tuple(name, uuid, *this, session, m_game_ticks)); + if (!inserted) { + Logger::error("Player insert Fail"); + } + sucess = inserted; } - m_uuid_to_name.emplace(uuid, name); + Arena arena; + if (!sucess) { + auto* rsp = Arena::Create(&arena); + rsp->set_success(false); + session->send(make_packet(*rsp)); + return; + } + + m_uuid_to_name.emplace(uuid, name); + // Pre-insert into new_chunks to ensure correct addition to waiting_player + /*ChunkPosSet required_chunks; + compute_required_chunks(required_chunks, uuid); + std::vector need_gen_chunks_pos; + + sync_and_collect_missing_chunks(need_gen_chunks_pos, required_chunks); + + { + std::lock_guard lock(m_new_chunk_mutex); + for (auto& pos : need_gen_chunks_pos) { + m_new_chunks.emplace(pos, ServerChunk(*this, pos)); + } + } + */ + need_gen(uuid); + auto* rsp = Arena::Create(&arena); rsp->set_success(true); rsp->set_uuid(uuid); @@ -538,71 +700,8 @@ void ServerWorld::handle_chunk_req(int task_id, const std::string& uuid, } } auto pool = m_gen_thread_pool.load(); - pool->enqueue([task_id, uuid, pos, this]() { - { - std::shared_lock lock(m_player_mutex); - auto it = m_players.find(uuid); - if (it == m_players.end()) { - return; - } - if (task_id < it->second.task_id()) { - // Old chunk requests are simply discarded - return; - } - } - Arena arean; - ChunkDataRsp* rsp = Arena::Create(&arean); - auto* rsq_pos = rsp->mutable_pos(); - rsq_pos->set_x(pos.x); - rsq_pos->set_z(pos.z); - { - std::shared_lock lock(m_chunks_mutex); - auto it = m_chunks.find(pos); - if (it == m_chunks.end()) { - return; - } - rsp->set_chunk_seed(it->second.seed()); - rsp->set_biome_type(std::to_underlying(it->second.biome())); - auto* blocks = rsp->mutable_chunk_blocks(); - auto& chunk_blocks = it->second.get_chunk_blocks(); - blocks->Assign(chunk_blocks.begin(), chunk_blocks.end()); - auto& neighbor_blocks = it->second.get_neightbor_blocks(); - auto assign = - [](auto* nb, - const std::optional>& blocks) { - if (!blocks) { - return; - } - if (!nb) { - return; - } - nb->Assign(blocks->begin(), blocks->end()); - }; - auto* nb1 = rsp->mutable_neighbor_blocks_1(); - auto* nb2 = rsp->mutable_neighbor_blocks_2(); - auto* nb3 = rsp->mutable_neighbor_blocks_3(); - auto* nb4 = rsp->mutable_neighbor_blocks_4(); - assign(nb1, neighbor_blocks[0]); - assign(nb2, neighbor_blocks[1]); - assign(nb3, neighbor_blocks[2]); - assign(nb4, neighbor_blocks[3]); - } - std::shared_ptr s; - { - std::shared_lock lock(m_player_mutex); - auto it = m_players.find(uuid); - if (it != m_players.end()) { - s = it->second.get_session(); - it->second.update_sync_gametick(m_game_ticks); - } - } - if (!s) { - Logger::error("Player {} session not exist", uuid); - return; - } - rsp->set_task_id(task_id); - s->send(make_packet(*rsp)); - }); + pool->enqueue( + [task_id, uuid, pos, this]() { send_chunk(task_id, uuid, pos); }); } void ServerWorld::handle_block_change(const BlockChangeReq& req) { @@ -683,4 +782,9 @@ void ServerWorld::set_chunk_load_style(int id) { Logger::error("Can,t Find Chunk Load Style Id {}, Nothing Will Do", id); } +int ServerWorld::chunk_size() const { + std::shared_lock lock(m_chunks_mutex); + return m_chunks.size(); +} + } // namespace Cubed \ No newline at end of file