diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index a0f05ae..187823a 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -52,6 +52,7 @@ public: void receive_player_logout(const LogoutRsp& rsp); int rendering_distance() const; void rendering_distance(int rendering_distance); + int get_chunk_task_id() const; void start_client_thread(std::string_view uuid); void stop_client_thread(); @@ -108,6 +109,7 @@ private: std::atomic m_day_tick{6000}; std::atomic m_requesting_chunk{false}; std::atomic m_is_rebuilding{false}; + std::atomic m_chunk_task_id{0}; std::shared_ptr m_client; ChunkLoadStyle m_chunk_load_style{ChunkLoadStyle::CENTER}; diff --git a/include/Cubed/gameplay/server_player.hpp b/include/Cubed/gameplay/server_player.hpp index 0d89b60..c809bff 100644 --- a/include/Cubed/gameplay/server_player.hpp +++ b/include/Cubed/gameplay/server_player.hpp @@ -22,6 +22,8 @@ public: void update_pos(float x, float y, float z); void update_sync_gametick(TickType gametick); bool is_disconnect(TickType current_gametick) const; + int task_id() const; + void task_id(int id); private: static constexpr TickType TIMEOUT = 200; @@ -32,5 +34,6 @@ private: ChunkPos m_last_chunk_pos{0, 0}; std::shared_ptr m_session; std::atomic m_last_gametick{0}; + std::atomic m_chunk_task_id{0}; }; } // namespace Cubed diff --git a/include/Cubed/gameplay/server_world.hpp b/include/Cubed/gameplay/server_world.hpp index b561fa0..7330759 100644 --- a/include/Cubed/gameplay/server_world.hpp +++ b/include/Cubed/gameplay/server_world.hpp @@ -72,7 +72,7 @@ public: std::shared_ptr session); glm::vec3 get_player_pos(const std::string& uuid) const; - void handle_chunk_req(const std::string& uuid, ChunkPos pos); + void handle_chunk_req(int task_id, const std::string& uuid, ChunkPos pos); void handle_block_change(const BlockChangeReq& req); template void register_timer(std::string_view id, TickType threshold, Fn&& f) { diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index 05ad83f..7a97ac7 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -573,6 +573,7 @@ void DevPanel::show_client_world_table_bar() { if (ImGui::Button("Spawn Point")) { m_player->set_player_pos({0.0f, 255.0f, 0.0f}); } + ImGui::Text("Chunk Task Id %d", m_app.client_world().get_chunk_task_id()); } void DevPanel::show_player_tab_item() { diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index 2f3d74c..65143e8 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -416,8 +416,10 @@ void ClientWorld::request_chunk() { } auto uuid = m_player.get_uuid(); Arena arena; + ++m_chunk_task_id; auto* req = Arena::Create(&arena); for (const auto& pos : need_send_pos) { + req->set_task_id(m_chunk_task_id.load()); req->set_uuid(uuid); auto* p = req->mutable_pos(); p->set_x(pos.x); @@ -429,6 +431,9 @@ void ClientWorld::request_chunk() { } void ClientWorld::receive_chunk(ChunkDataRsp data) { + if (data.task_id() < m_chunk_task_id) { + return; + } { std::lock_guard lock(m_chunks_mutex); @@ -573,6 +578,9 @@ void ClientWorld::rendering_distance(int rendering_distance) { m_rendering_distance.load()); request_chunk(); } + +int ClientWorld::get_chunk_task_id() const { return m_chunk_task_id.load(); } + const std::vector& ClientWorld::render_snapshots() const { return m_render_snapshots; }; diff --git a/src/gameplay/server_player.cpp b/src/gameplay/server_player.cpp index ff0c0e6..164cce7 100644 --- a/src/gameplay/server_player.cpp +++ b/src/gameplay/server_player.cpp @@ -31,4 +31,7 @@ bool ServerPlayer::is_disconnect(TickType current_gametick) const { return false; } +int ServerPlayer::task_id() const { return m_chunk_task_id.load(); } +void ServerPlayer::task_id(int id) { m_chunk_task_id = id; } + } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/server_world.cpp b/src/gameplay/server_world.cpp index 37f6c59..3aebf44 100644 --- a/src/gameplay/server_world.cpp +++ b/src/gameplay/server_world.cpp @@ -524,10 +524,32 @@ glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const { return it->second.get_pos(); } -void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) { - +void ServerWorld::handle_chunk_req(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 (it->second.task_id() < task_id) { + // task_id is an atomic variable, can be operated on directly + it->second.task_id(task_id); + } + } auto pool = m_gen_thread_pool.load(); - pool->enqueue([uuid, pos, this]() { + 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(); @@ -578,7 +600,7 @@ void ServerWorld::handle_chunk_req(const std::string& uuid, ChunkPos pos) { Logger::error("Player {} session not exist", uuid); return; } - + rsp->set_task_id(task_id); s->send(make_packet(*rsp)); }); } diff --git a/src/gameplay/session.cpp b/src/gameplay/session.cpp index aef3db9..be9a043 100644 --- a/src/gameplay/session.cpp +++ b/src/gameplay/session.cpp @@ -77,7 +77,8 @@ asio::awaitable Session::read_loop() { // Logger::info("Session: Receive Chunk Data req"); if (decode_packet(*req, body_data, header)) { m_server_world.handle_chunk_req( - req->uuid(), ChunkPos(req->pos().x(), req->pos().z())); + req->task_id(), req->uuid(), + ChunkPos(req->pos().x(), req->pos().z())); } } if (cmd_id == to_num(PacketEnum::BLOCK_CHANGE_REQ)) { diff --git a/src/proto/world/chunk_data.proto b/src/proto/world/chunk_data.proto index f247ded..8b29e73 100644 --- a/src/proto/world/chunk_data.proto +++ b/src/proto/world/chunk_data.proto @@ -3,19 +3,21 @@ syntax = "proto3"; import "common/chunk_pos.proto"; message ChunkDataReq { - string uuid = 1; - ChunkPosNet pos = 2; + int32 task_id = 1; + string uuid = 2; + ChunkPosNet pos = 3; } message ChunkDataRsp { - ChunkPosNet pos = 1; - uint32 chunk_seed = 2; - int32 biome_type = 3; - repeated uint32 chunk_blocks = 4 [packed=true]; - repeated uint32 neighbor_blocks_1 = 5 [packed=true]; - repeated uint32 neighbor_blocks_2 = 6 [packed=true]; - repeated uint32 neighbor_blocks_3 = 7 [packed=true]; - repeated uint32 neighbor_blocks_4 = 8 [packed=true]; + int32 task_id = 1; + ChunkPosNet pos = 2; + uint32 chunk_seed = 3; + int32 biome_type = 4; + repeated uint32 chunk_blocks = 5 [packed=true]; + repeated uint32 neighbor_blocks_1 = 6 [packed=true]; + repeated uint32 neighbor_blocks_2 = 7 [packed=true]; + repeated uint32 neighbor_blocks_3 = 8 [packed=true]; + repeated uint32 neighbor_blocks_4 = 9 [packed=true]; } message S2C_ClearAllChunks {