mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(gameplay): add task ID to chunk requests to discard stale responses
This commit is contained in:
@@ -52,6 +52,7 @@ public:
|
|||||||
void receive_player_logout(const LogoutRsp& rsp);
|
void receive_player_logout(const LogoutRsp& rsp);
|
||||||
int rendering_distance() const;
|
int rendering_distance() const;
|
||||||
void rendering_distance(int rendering_distance);
|
void rendering_distance(int rendering_distance);
|
||||||
|
int get_chunk_task_id() const;
|
||||||
void start_client_thread(std::string_view uuid);
|
void start_client_thread(std::string_view uuid);
|
||||||
void stop_client_thread();
|
void stop_client_thread();
|
||||||
|
|
||||||
@@ -108,6 +109,7 @@ private:
|
|||||||
std::atomic<TickType> m_day_tick{6000};
|
std::atomic<TickType> m_day_tick{6000};
|
||||||
std::atomic<bool> m_requesting_chunk{false};
|
std::atomic<bool> m_requesting_chunk{false};
|
||||||
std::atomic<bool> m_is_rebuilding{false};
|
std::atomic<bool> m_is_rebuilding{false};
|
||||||
|
std::atomic<int> m_chunk_task_id{0};
|
||||||
std::shared_ptr<NetworkClient> m_client;
|
std::shared_ptr<NetworkClient> m_client;
|
||||||
ChunkLoadStyle m_chunk_load_style{ChunkLoadStyle::CENTER};
|
ChunkLoadStyle m_chunk_load_style{ChunkLoadStyle::CENTER};
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ public:
|
|||||||
void update_pos(float x, float y, float z);
|
void update_pos(float x, float y, float z);
|
||||||
void update_sync_gametick(TickType gametick);
|
void update_sync_gametick(TickType gametick);
|
||||||
bool is_disconnect(TickType current_gametick) const;
|
bool is_disconnect(TickType current_gametick) const;
|
||||||
|
int task_id() const;
|
||||||
|
void task_id(int id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr TickType TIMEOUT = 200;
|
static constexpr TickType TIMEOUT = 200;
|
||||||
@@ -32,5 +34,6 @@ private:
|
|||||||
ChunkPos m_last_chunk_pos{0, 0};
|
ChunkPos m_last_chunk_pos{0, 0};
|
||||||
std::shared_ptr<Session> m_session;
|
std::shared_ptr<Session> m_session;
|
||||||
std::atomic<TickType> m_last_gametick{0};
|
std::atomic<TickType> m_last_gametick{0};
|
||||||
|
std::atomic<int> m_chunk_task_id{0};
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public:
|
|||||||
std::shared_ptr<Session> session);
|
std::shared_ptr<Session> session);
|
||||||
glm::vec3 get_player_pos(const std::string& uuid) const;
|
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);
|
void handle_block_change(const BlockChangeReq& req);
|
||||||
template <typename Fn>
|
template <typename Fn>
|
||||||
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
void register_timer(std::string_view id, TickType threshold, Fn&& f) {
|
||||||
|
|||||||
@@ -573,6 +573,7 @@ void DevPanel::show_client_world_table_bar() {
|
|||||||
if (ImGui::Button("Spawn Point")) {
|
if (ImGui::Button("Spawn Point")) {
|
||||||
m_player->set_player_pos({0.0f, 255.0f, 0.0f});
|
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() {
|
void DevPanel::show_player_tab_item() {
|
||||||
|
|||||||
@@ -416,8 +416,10 @@ void ClientWorld::request_chunk() {
|
|||||||
}
|
}
|
||||||
auto uuid = m_player.get_uuid();
|
auto uuid = m_player.get_uuid();
|
||||||
Arena arena;
|
Arena arena;
|
||||||
|
++m_chunk_task_id;
|
||||||
auto* req = Arena::Create<ChunkDataReq>(&arena);
|
auto* req = Arena::Create<ChunkDataReq>(&arena);
|
||||||
for (const auto& pos : need_send_pos) {
|
for (const auto& pos : need_send_pos) {
|
||||||
|
req->set_task_id(m_chunk_task_id.load());
|
||||||
req->set_uuid(uuid);
|
req->set_uuid(uuid);
|
||||||
auto* p = req->mutable_pos();
|
auto* p = req->mutable_pos();
|
||||||
p->set_x(pos.x);
|
p->set_x(pos.x);
|
||||||
@@ -429,6 +431,9 @@ void ClientWorld::request_chunk() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ClientWorld::receive_chunk(ChunkDataRsp data) {
|
void ClientWorld::receive_chunk(ChunkDataRsp data) {
|
||||||
|
if (data.task_id() < m_chunk_task_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard lock(m_chunks_mutex);
|
std::lock_guard lock(m_chunks_mutex);
|
||||||
@@ -573,6 +578,9 @@ void ClientWorld::rendering_distance(int rendering_distance) {
|
|||||||
m_rendering_distance.load());
|
m_rendering_distance.load());
|
||||||
request_chunk();
|
request_chunk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ClientWorld::get_chunk_task_id() const { return m_chunk_task_id.load(); }
|
||||||
|
|
||||||
const std::vector<ChunkRenderSnapshot>& ClientWorld::render_snapshots() const {
|
const std::vector<ChunkRenderSnapshot>& ClientWorld::render_snapshots() const {
|
||||||
return m_render_snapshots;
|
return m_render_snapshots;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,4 +31,7 @@ bool ServerPlayer::is_disconnect(TickType current_gametick) const {
|
|||||||
return false;
|
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
|
} // namespace Cubed
|
||||||
@@ -524,10 +524,32 @@ glm::vec3 ServerWorld::get_player_pos(const std::string& uuid) const {
|
|||||||
return it->second.get_pos();
|
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();
|
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;
|
Arena arean;
|
||||||
ChunkDataRsp* rsp = Arena::Create<ChunkDataRsp>(&arean);
|
ChunkDataRsp* rsp = Arena::Create<ChunkDataRsp>(&arean);
|
||||||
auto* rsq_pos = rsp->mutable_pos();
|
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);
|
Logger::error("Player {} session not exist", uuid);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rsp->set_task_id(task_id);
|
||||||
s->send(make_packet(*rsp));
|
s->send(make_packet(*rsp));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ asio::awaitable<void> Session::read_loop() {
|
|||||||
// Logger::info("Session: Receive Chunk Data req");
|
// Logger::info("Session: Receive Chunk Data req");
|
||||||
if (decode_packet(*req, body_data, header)) {
|
if (decode_packet(*req, body_data, header)) {
|
||||||
m_server_world.handle_chunk_req(
|
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)) {
|
if (cmd_id == to_num(PacketEnum::BLOCK_CHANGE_REQ)) {
|
||||||
|
|||||||
@@ -3,19 +3,21 @@ syntax = "proto3";
|
|||||||
import "common/chunk_pos.proto";
|
import "common/chunk_pos.proto";
|
||||||
|
|
||||||
message ChunkDataReq {
|
message ChunkDataReq {
|
||||||
string uuid = 1;
|
int32 task_id = 1;
|
||||||
ChunkPosNet pos = 2;
|
string uuid = 2;
|
||||||
|
ChunkPosNet pos = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
message ChunkDataRsp {
|
message ChunkDataRsp {
|
||||||
ChunkPosNet pos = 1;
|
int32 task_id = 1;
|
||||||
uint32 chunk_seed = 2;
|
ChunkPosNet pos = 2;
|
||||||
int32 biome_type = 3;
|
uint32 chunk_seed = 3;
|
||||||
repeated uint32 chunk_blocks = 4 [packed=true];
|
int32 biome_type = 4;
|
||||||
repeated uint32 neighbor_blocks_1 = 5 [packed=true];
|
repeated uint32 chunk_blocks = 5 [packed=true];
|
||||||
repeated uint32 neighbor_blocks_2 = 6 [packed=true];
|
repeated uint32 neighbor_blocks_1 = 6 [packed=true];
|
||||||
repeated uint32 neighbor_blocks_3 = 7 [packed=true];
|
repeated uint32 neighbor_blocks_2 = 7 [packed=true];
|
||||||
repeated uint32 neighbor_blocks_4 = 8 [packed=true];
|
repeated uint32 neighbor_blocks_3 = 8 [packed=true];
|
||||||
|
repeated uint32 neighbor_blocks_4 = 9 [packed=true];
|
||||||
}
|
}
|
||||||
|
|
||||||
message S2C_ClearAllChunks {
|
message S2C_ClearAllChunks {
|
||||||
|
|||||||
Reference in New Issue
Block a user