From 298fe68552f0549f728a713dd277b705f69e7668 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Wed, 1 Jul 2026 15:28:26 +0800 Subject: [PATCH] refactor(client): extract AABB creation and add collision check on block place Make ClientPlayer::get_aabb and ClientWorld::get_block_aabb static. Change player size to static constexpr M_SIZE. Use shared_mutex for concurrent reads of other players. Check for collision with other players before placing a block. --- include/Cubed/gameplay/client_player.hpp | 4 +- include/Cubed/gameplay/client_world.hpp | 3 +- src/gameplay/client_player.cpp | 48 +++++++----------------- src/gameplay/client_world.cpp | 22 +++++++++++ 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/include/Cubed/gameplay/client_player.hpp b/include/Cubed/gameplay/client_player.hpp index d8ce50a..371505a 100644 --- a/include/Cubed/gameplay/client_player.hpp +++ b/include/Cubed/gameplay/client_player.hpp @@ -23,7 +23,7 @@ public: const ChunkPosSet& get_chunk_pos_set() const; ChunkPosSet& get_chunk_pos_set(); - AABB get_aabb(const glm::vec3& pos) const; + static AABB get_aabb(const glm::vec3& pos); const glm::vec3& get_front() const; const Gait& get_gait() const; const std::optional& get_look_block_pos() const; @@ -97,7 +97,7 @@ private: glm::vec3 m_front{0, 0, -1}; glm::vec3 m_right{0, 0, 0}; - glm::vec3 m_size{0.6f, 1.8f, 0.6f}; + static constexpr glm::vec3 M_SIZE{0.6f, 1.8f, 0.6f}; Gait m_gait = Gait::WALK; MoveState m_move_state{}; diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index f5b96f5..e236a70 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -71,6 +71,7 @@ public: void request_exit(); bool is_receive_exit(); int chunk_size() const; + static AABB get_block_aabb(const glm::ivec3& pos); template void register_timer(std::string_view id, TickType threshold, Fn&& f) { m_timers.emplace(std::piecewise_construct, @@ -99,7 +100,7 @@ private: std::mutex m_delete_vbo_mutex; std::mutex m_delete_vao_mutex; - std::mutex m_other_players_mutex; + mutable std::shared_mutex m_other_players_mutex; tbb::concurrent_queue> m_pending_upload_queue; tbb::concurrent_queue m_dirty_chunk_queue; diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index 3ad6e6e..595e44e 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -8,13 +8,13 @@ namespace Cubed { ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {} ClientPlayer::~ClientPlayer() {} -AABB ClientPlayer::get_aabb(const glm::vec3& pos) const { - float half_width = m_size.x / 2.0f; - float half_depth = m_size.z / 2.0f; +AABB ClientPlayer::get_aabb(const glm::vec3& pos) { + float half_width = M_SIZE.x / 2.0f; + float half_depth = M_SIZE.z / 2.0f; glm::vec3 min{pos.x - half_width, pos.y, pos.z - half_depth}; - glm::vec3 max{pos.x + half_width, pos.y + m_size.y, pos.z + half_depth}; + glm::vec3 max{pos.x + half_width, pos.y + M_SIZE.y, pos.z + half_depth}; return AABB{min, max}; } @@ -282,15 +282,7 @@ void ClientPlayer::update_lookup_block() { if (Input::get_input_state().mouse_state.right) { glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; if (!m_world.is_solid(near_pos)) { - auto x = near_pos.x; - auto y = near_pos.y; - auto z = near_pos.z; - AABB block_box = {glm::vec3{static_cast(x), - static_cast(y), - static_cast(z)}, - glm::vec3{static_cast(x + 1), - static_cast(y + 1), - static_cast(z + 1)}}; + AABB block_box = ClientWorld::get_block_aabb(near_pos); AABB player_box = get_aabb(get_player_pos()); if (!player_box.intersects(block_box)) { m_world.report_block_change(near_pos, m_place_block); @@ -409,13 +401,9 @@ void ClientPlayer::update_x_move(glm::vec3& player_pos) { for (int x = minx; x <= maxx; ++x) { for (int y = miny; y <= maxy; ++y) { for (int z = minz; z <= maxz; ++z) { - if (!m_world.can_pass_block(glm::ivec3{x, y, z})) { - AABB block_box = {glm::vec3{static_cast(x), - static_cast(y), - static_cast(z)}, - glm::vec3{static_cast(x + 1), - static_cast(y + 1), - static_cast(z + 1)}}; + glm::ivec3 block_pos{x, y, z}; + if (!m_world.can_pass_block(block_pos)) { + AABB block_box = ClientWorld::get_block_aabb(block_pos); if (player_box.intersects(block_box)) { m_gait = Gait::WALK; player_pos.x -= move_distance.x; @@ -443,13 +431,9 @@ void ClientPlayer::update_y_move(glm::vec3& player_pos) { for (int x = minx; x <= maxx; ++x) { for (int y = miny; y <= maxy; ++y) { for (int z = minz; z <= maxz; ++z) { - if (!m_world.can_pass_block(glm::ivec3{x, y, z})) { - AABB block_box = {glm::vec3{static_cast(x), - static_cast(y), - static_cast(z)}, - glm::vec3{static_cast(x + 1), - static_cast(y + 1), - static_cast(z + 1)}}; + glm::ivec3 block_pos{x, y, z}; + if (!m_world.can_pass_block(block_pos)) { + AABB block_box = ClientWorld::get_block_aabb(block_pos); if (player_box.intersects(block_box)) { player_pos.y -= move_distance.y; m_y_speed = 0.0f; @@ -481,13 +465,9 @@ void ClientPlayer::update_z_move(glm::vec3& player_pos) { for (int x = minx; x <= maxx; ++x) { for (int y = miny; y <= maxy; ++y) { for (int z = minz; z <= maxz; ++z) { - if (!m_world.can_pass_block(glm::ivec3{x, y, z})) { - AABB block_box = {glm::vec3{static_cast(x), - static_cast(y), - static_cast(z)}, - glm::vec3{static_cast(x + 1), - static_cast(y + 1), - static_cast(z + 1)}}; + glm::ivec3 block_pos{x, y, z}; + if (!m_world.can_pass_block(block_pos)) { + AABB block_box = ClientWorld::get_block_aabb(block_pos); if (player_box.intersects(block_box)) { m_gait = Gait::WALK; player_pos.z -= move_distance.z; diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index 987a049..f000cd1 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -262,6 +262,18 @@ void ClientWorld::push_delete_vao(GLuint vao) { void ClientWorld::report_block_change(const glm::ivec3& pos, unsigned id) const { + { + AABB block_box = get_block_aabb(pos); + std::shared_lock lock(m_other_players_mutex); + + for (auto& [uuid, player] : m_other_players) { + AABB box = ClientPlayer::get_aabb(player.target_pos); + if (box.intersects(block_box)) { + return; + } + } + } + Arena arena; auto* req = Arena::Create(&arena); req->set_uuid(m_player.get_uuid()); @@ -572,6 +584,16 @@ bool ClientWorld::is_receive_exit() { return m_receive_exit; } int ClientWorld::chunk_size() const { return m_chunks.size(); } +AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) { + auto x = pos.x; + auto y = pos.y; + auto z = pos.z; + return {glm::vec3{static_cast(x), static_cast(y), + static_cast(z)}, + glm::vec3{static_cast(x + 1), static_cast(y + 1), + static_cast(z + 1)}}; +} + void ClientWorld::request_exit() { if (m_receive_exit) { return;