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.
This commit is contained in:
2026-07-01 15:28:26 +08:00
parent 647f980c66
commit 298fe68552
4 changed files with 40 additions and 37 deletions

View File

@@ -23,7 +23,7 @@ public:
const ChunkPosSet& get_chunk_pos_set() const; const ChunkPosSet& get_chunk_pos_set() const;
ChunkPosSet& get_chunk_pos_set(); 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 glm::vec3& get_front() const;
const Gait& get_gait() const; const Gait& get_gait() const;
const std::optional<LookBlock>& get_look_block_pos() const; const std::optional<LookBlock>& get_look_block_pos() const;
@@ -97,7 +97,7 @@ private:
glm::vec3 m_front{0, 0, -1}; glm::vec3 m_front{0, 0, -1};
glm::vec3 m_right{0, 0, 0}; 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; Gait m_gait = Gait::WALK;
MoveState m_move_state{}; MoveState m_move_state{};

View File

@@ -71,6 +71,7 @@ public:
void request_exit(); void request_exit();
bool is_receive_exit(); bool is_receive_exit();
int chunk_size() const; int chunk_size() const;
static AABB get_block_aabb(const glm::ivec3& pos);
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) {
m_timers.emplace(std::piecewise_construct, m_timers.emplace(std::piecewise_construct,
@@ -99,7 +100,7 @@ private:
std::mutex m_delete_vbo_mutex; std::mutex m_delete_vbo_mutex;
std::mutex m_delete_vao_mutex; std::mutex m_delete_vao_mutex;
std::mutex m_other_players_mutex; mutable std::shared_mutex m_other_players_mutex;
tbb::concurrent_queue<std::unique_ptr<ClientChunk>> m_pending_upload_queue; tbb::concurrent_queue<std::unique_ptr<ClientChunk>> m_pending_upload_queue;
tbb::concurrent_queue<ChunkPos> m_dirty_chunk_queue; tbb::concurrent_queue<ChunkPos> m_dirty_chunk_queue;

View File

@@ -8,13 +8,13 @@ namespace Cubed {
ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {} ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {}
ClientPlayer::~ClientPlayer() {} ClientPlayer::~ClientPlayer() {}
AABB ClientPlayer::get_aabb(const glm::vec3& pos) const { AABB ClientPlayer::get_aabb(const glm::vec3& pos) {
float half_width = m_size.x / 2.0f; float half_width = M_SIZE.x / 2.0f;
float half_depth = m_size.z / 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 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}; return AABB{min, max};
} }
@@ -282,15 +282,7 @@ void ClientPlayer::update_lookup_block() {
if (Input::get_input_state().mouse_state.right) { if (Input::get_input_state().mouse_state.right) {
glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal;
if (!m_world.is_solid(near_pos)) { if (!m_world.is_solid(near_pos)) {
auto x = near_pos.x; AABB block_box = ClientWorld::get_block_aabb(near_pos);
auto y = near_pos.y;
auto z = near_pos.z;
AABB block_box = {glm::vec3{static_cast<float>(x),
static_cast<float>(y),
static_cast<float>(z)},
glm::vec3{static_cast<float>(x + 1),
static_cast<float>(y + 1),
static_cast<float>(z + 1)}};
AABB player_box = get_aabb(get_player_pos()); AABB player_box = get_aabb(get_player_pos());
if (!player_box.intersects(block_box)) { if (!player_box.intersects(block_box)) {
m_world.report_block_change(near_pos, m_place_block); 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 x = minx; x <= maxx; ++x) {
for (int y = miny; y <= maxy; ++y) { for (int y = miny; y <= maxy; ++y) {
for (int z = minz; z <= maxz; ++z) { for (int z = minz; z <= maxz; ++z) {
if (!m_world.can_pass_block(glm::ivec3{x, y, z})) { glm::ivec3 block_pos{x, y, z};
AABB block_box = {glm::vec3{static_cast<float>(x), if (!m_world.can_pass_block(block_pos)) {
static_cast<float>(y), AABB block_box = ClientWorld::get_block_aabb(block_pos);
static_cast<float>(z)},
glm::vec3{static_cast<float>(x + 1),
static_cast<float>(y + 1),
static_cast<float>(z + 1)}};
if (player_box.intersects(block_box)) { if (player_box.intersects(block_box)) {
m_gait = Gait::WALK; m_gait = Gait::WALK;
player_pos.x -= move_distance.x; 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 x = minx; x <= maxx; ++x) {
for (int y = miny; y <= maxy; ++y) { for (int y = miny; y <= maxy; ++y) {
for (int z = minz; z <= maxz; ++z) { for (int z = minz; z <= maxz; ++z) {
if (!m_world.can_pass_block(glm::ivec3{x, y, z})) { glm::ivec3 block_pos{x, y, z};
AABB block_box = {glm::vec3{static_cast<float>(x), if (!m_world.can_pass_block(block_pos)) {
static_cast<float>(y), AABB block_box = ClientWorld::get_block_aabb(block_pos);
static_cast<float>(z)},
glm::vec3{static_cast<float>(x + 1),
static_cast<float>(y + 1),
static_cast<float>(z + 1)}};
if (player_box.intersects(block_box)) { if (player_box.intersects(block_box)) {
player_pos.y -= move_distance.y; player_pos.y -= move_distance.y;
m_y_speed = 0.0f; 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 x = minx; x <= maxx; ++x) {
for (int y = miny; y <= maxy; ++y) { for (int y = miny; y <= maxy; ++y) {
for (int z = minz; z <= maxz; ++z) { for (int z = minz; z <= maxz; ++z) {
if (!m_world.can_pass_block(glm::ivec3{x, y, z})) { glm::ivec3 block_pos{x, y, z};
AABB block_box = {glm::vec3{static_cast<float>(x), if (!m_world.can_pass_block(block_pos)) {
static_cast<float>(y), AABB block_box = ClientWorld::get_block_aabb(block_pos);
static_cast<float>(z)},
glm::vec3{static_cast<float>(x + 1),
static_cast<float>(y + 1),
static_cast<float>(z + 1)}};
if (player_box.intersects(block_box)) { if (player_box.intersects(block_box)) {
m_gait = Gait::WALK; m_gait = Gait::WALK;
player_pos.z -= move_distance.z; player_pos.z -= move_distance.z;

View File

@@ -262,6 +262,18 @@ void ClientWorld::push_delete_vao(GLuint vao) {
void ClientWorld::report_block_change(const glm::ivec3& pos, void ClientWorld::report_block_change(const glm::ivec3& pos,
unsigned id) const { 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; Arena arena;
auto* req = Arena::Create<BlockChangeReq>(&arena); auto* req = Arena::Create<BlockChangeReq>(&arena);
req->set_uuid(m_player.get_uuid()); 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(); } 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<float>(x), static_cast<float>(y),
static_cast<float>(z)},
glm::vec3{static_cast<float>(x + 1), static_cast<float>(y + 1),
static_cast<float>(z + 1)}};
}
void ClientWorld::request_exit() { void ClientWorld::request_exit() {
if (m_receive_exit) { if (m_receive_exit) {
return; return;