From 7b6c11e904f1afee9590b68e07beafd96a51af0b Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Sat, 27 Jun 2026 11:20:51 +0800 Subject: [PATCH] feat(gameplay): add packet to clear all chunks on server rebuild Add new packet S2C_ClearAllChunks (ID 3005) to notify clients when the server rebuilds its world. Clients respond by clearing their chunk cache and requesting fresh chunks. Shift UPDATE_TIME packet ID to 3006 to accommodate. --- include/Cubed/gameplay/client_world.hpp | 3 +++ include/Cubed/gameplay/packet.hpp | 6 +++++- src/gameplay/client_world.cpp | 19 +++++++++++++++++++ src/gameplay/network_client.cpp | 13 +++++++++++-- src/gameplay/server_world.cpp | 10 ++++++++++ src/proto/world/chunk_data.proto | 6 +++++- 6 files changed, 53 insertions(+), 4 deletions(-) diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 677c228..a0f05ae 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -37,6 +37,8 @@ public: bool can_pass_block(const glm::ivec3& block_pos) const; BlockType get_block_tpye(const glm::ivec3& block_pos) const; + void rebuild_world(); + void push_delete_vbo(GLuint vbo); void push_delete_vao(GLuint vao); // void hot_reload(); @@ -105,6 +107,7 @@ private: std::atomic m_game_ticks{0}; std::atomic m_day_tick{6000}; std::atomic m_requesting_chunk{false}; + std::atomic m_is_rebuilding{false}; std::shared_ptr m_client; ChunkLoadStyle m_chunk_load_style{ChunkLoadStyle::CENTER}; diff --git a/include/Cubed/gameplay/packet.hpp b/include/Cubed/gameplay/packet.hpp index 5ebcff5..b13f995 100644 --- a/include/Cubed/gameplay/packet.hpp +++ b/include/Cubed/gameplay/packet.hpp @@ -52,7 +52,8 @@ enum class PacketEnum : uint16_t { CHUNK_DATA_RSP = 3002, BLOCK_CHANGE_REQ = 3003, BLOCK_CHANGE_RSP = 3004, - UPDATE_TIME = 3005, + S2C_CLEAR_ALL_CHUNKS = 3005, + UPDATE_TIME = 3006, PING = 9001, PONG = 9002 @@ -98,6 +99,9 @@ template <> constexpr uint16_t get_packet_id() { template <> constexpr uint16_t get_packet_id() { return std::to_underlying(PacketEnum::BLOCK_CHANGE_RSP); } +template <> constexpr uint16_t get_packet_id() { + return std::to_underlying(PacketEnum::S2C_CLEAR_ALL_CHUNKS); +} template <> constexpr uint16_t get_packet_id() { return std::to_underlying(PacketEnum::UPDATE_TIME); } diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index 8785af3..98ce7dd 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -104,6 +104,25 @@ bool ClientWorld::can_pass_block(const glm::ivec3& block_pos) const { auto id = chunk_blocks[ClientChunk::index(x, y, z)]; return BlockManager::is_passable(id); } + +void ClientWorld::rebuild_world() { + if (m_is_rebuilding.exchange(true)) { + return; + } + stop_thread_pool(); + { + std::lock_guard lk(m_chunks_mutex); + m_chunks.clear(); + } + { + std::lock_guard lock(m_pending_upload_queue_mutex); + m_pending_upload_queue.clear(); + } + start_thread_pool(); + request_chunk(); + m_is_rebuilding = false; +} + BlockType ClientWorld::get_block_tpye(const glm::ivec3& block_pos) const { auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z); std::shared_lock lk(m_chunks_mutex); diff --git a/src/gameplay/network_client.cpp b/src/gameplay/network_client.cpp index a17e57c..08772b6 100644 --- a/src/gameplay/network_client.cpp +++ b/src/gameplay/network_client.cpp @@ -78,8 +78,8 @@ asio::awaitable NetworkClient::read_loop() { } break; case to_num(PacketEnum::CHUNK_DATA_RSP): { ChunkDataRsp rsp; - Logger::info("Client: Receive Chunk Data rsp, size {}mb", - body_data.size() / 1024.0f / 1024); + // Logger::info("Client: Receive Chunk Data rsp, size {}mb", + // body_data.size() / 1024.0f / 1024); if (decode_packet(rsp, body_data, header)) { m_world.receive_chunk(std::move(rsp)); } @@ -109,6 +109,15 @@ asio::awaitable NetworkClient::read_loop() { m_world.receive_player_logout(*rsp); } } break; + case to_num(PacketEnum::S2C_CLEAR_ALL_CHUNKS): { + auto* rsp = Arena::Create(&arena); + if (decode_packet(*rsp, body_data, header)) { + if (rsp->clear()) { + Logger::info("Client Clear All Chunk"); + m_world.rebuild_world(); + } + } + } break; } } } catch (const asio::system_error& e) { diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index 394a595..3da56ed 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -392,6 +392,16 @@ void ServerWorld::rebuild_world() { start_thread_pool(); start_gen_thread(); need_gen(std::nullopt); + Arena arena; + auto* rsp = Arena::Create(&arena); + rsp->set_clear(true); + { + std::lock_guard lock(m_player_mutex); + for (auto& [uuid, player] : m_players) { + player.get_session()->send(make_packet(*rsp)); + } + } + m_is_rebuilding = false; } diff --git a/src/proto/world/chunk_data.proto b/src/proto/world/chunk_data.proto index 4c070b2..f247ded 100644 --- a/src/proto/world/chunk_data.proto +++ b/src/proto/world/chunk_data.proto @@ -16,4 +16,8 @@ message ChunkDataRsp { repeated uint32 neighbor_blocks_2 = 6 [packed=true]; repeated uint32 neighbor_blocks_3 = 7 [packed=true]; repeated uint32 neighbor_blocks_4 = 8 [packed=true]; -} \ No newline at end of file +} + +message S2C_ClearAllChunks { + bool clear = 1; +}