diff --git a/include/Cubed/gameplay/client_chunk.hpp b/include/Cubed/gameplay/client_chunk.hpp index 17cf169..619631c 100644 --- a/include/Cubed/gameplay/client_chunk.hpp +++ b/include/Cubed/gameplay/client_chunk.hpp @@ -37,7 +37,15 @@ public: static int index(int x, int y, int z); static int index(const glm::vec3& pos); - + static std::tuple world_to_block(int world_x, int world_y, + int world_z, int chunk_x, + int chunk_z); + static std::tuple world_to_block(const glm::ivec3& block_pos, + ChunkPos chunk_pos); + static std::tuple block_to_world(int x, int y, int z, + int chunk_x, int chunk_z); + static std::tuple block_to_world(const glm::ivec3& block_pos, + ChunkPos chunk_pos); BiomeType get_biome() const; ChunkPos get_chunk_pos() const; const std::vector& get_chunk_blocks() const; diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index addb1dc..735e479 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -1,5 +1,4 @@ #pragma once -#include "Cubed/AABB.hpp" #include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/chunk_pos.hpp" #include "Cubed/gameplay/client_chunk.hpp" @@ -18,7 +17,6 @@ public: ~ClientWorld(); void init(); void update(float delta_time); - bool can_move(const AABB& player_box) const; const std::optional& get_look_block_pos(const std::string& name) const; ClientPlayer& get_player(); @@ -26,13 +24,14 @@ public: bool is_solid(const glm::ivec3& block_pos) const; bool can_pass_block(const glm::ivec3& block_pos) const; BlockType get_block_tpye(const glm::ivec3& block_pos) const; - void set_block(const glm::ivec3& pos, unsigned id); + void push_delete_vbo(GLuint vbo); void push_delete_vao(GLuint vao); - void hot_reload(); - - void rebuild_world(); + // void hot_reload(); + // void rebuild_world(); + void report_block_change(const glm::ivec3& pos, unsigned id) const; + void receive_block_change(const BlockChangeRsp& rsp); int rendering_distance() const; void rendering_distance(int rendering_distance); void start_client_thread(std::string_view uuid); @@ -78,5 +77,6 @@ private: void report_player_pos(); void request_chunk(); + void set_block(const glm::ivec3& pos, unsigned id); }; } // namespace Cubed diff --git a/src/gameplay/client_chunk.cpp b/src/gameplay/client_chunk.cpp index 050d37b..44465cb 100644 --- a/src/gameplay/client_chunk.cpp +++ b/src/gameplay/client_chunk.cpp @@ -137,7 +137,34 @@ int ClientChunk::index(int x, int y, int z) { int ClientChunk::index(const glm::vec3& pos) { return ClientChunk::index(pos.x, pos.y, pos.z); } +std::tuple ClientChunk::world_to_block(int world_x, int world_y, + int world_z, int chunk_x, + int chunk_z) { + int x, y, z; + y = world_y; + x = world_x - chunk_x * CHUNK_SIZE; + z = world_z - chunk_z * CHUNK_SIZE; + return {x, y, z}; +} +std::tuple +ClientChunk::world_to_block(const glm::ivec3& block_pos, ChunkPos chunk_pos) { + return world_to_block(block_pos.x, block_pos.y, block_pos.z, chunk_pos.x, + chunk_pos.z); +} + +std::tuple +ClientChunk::block_to_world(int x, int y, int z, int chunk_x, int chunk_z) { + int world_x = x + chunk_x * CHUNK_SIZE; + int world_z = z + chunk_z * CHUNK_SIZE; + int world_y = y; + return {world_x, world_y, world_z}; +} +std::tuple +ClientChunk::block_to_world(const glm::ivec3& block_pos, ChunkPos chunk_pos) { + return block_to_world(block_pos.x, block_pos.y, block_pos.z, chunk_pos.x, + chunk_pos.z); +} BiomeType ClientChunk::get_biome() const { return m_biome.load(); } ChunkPos ClientChunk::get_chunk_pos() const { return m_chunk_pos; } diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index b3dcd1c..205770d 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -278,7 +278,7 @@ void ClientPlayer::update_lookup_block() { if (m_look_block != std::nullopt) { if (Input::get_input_state().mouse_state.left) { if (m_world.is_solid(m_look_block->pos)) { - m_world.set_block(m_look_block->pos, 0); + m_world.report_block_change(m_look_block->pos, 0); } Input::get_input_state().mouse_state.left = false; } @@ -296,7 +296,7 @@ void ClientPlayer::update_lookup_block() { static_cast(z + 1)}}; AABB player_box = get_aabb(); if (!player_box.intersects(block_box)) { - m_world.set_block(near_pos, m_place_block); + m_world.report_block_change(near_pos, m_place_block); } } Input::get_input_state().mouse_state.right = false; diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index 014f0c0..0b99cf4 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -49,6 +49,143 @@ ClientWorld::get_look_block_pos(const std::string& name) const { ClientPlayer& ClientWorld::get_player() { return m_player; } +int ClientWorld::get_block(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); + auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); + + if (it == m_chunks.end()) { + return 0; + } + + const auto& chunk_blocks = it->second.get_chunk_blocks(); + auto [x, y, z] = ClientChunk::world_to_block(block_pos, {chunk_x, chunk_z}); + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { + return 0; + } + return chunk_blocks[ClientChunk::index(x, y, z)]; +} +bool ClientWorld::is_solid(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); + auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); + + if (it == m_chunks.end()) { + return false; + } + const auto& chunk_blocks = it->second.get_chunk_blocks(); + auto [x, y, z] = ClientChunk::world_to_block(block_pos, {chunk_x, chunk_z}); + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { + return false; + } + auto id = chunk_blocks[ClientChunk::index(x, y, z)]; + if (BlockManager::is_gas(id) || BlockManager::is_liquid(id)) { + return false; + } else { + return true; + } +} +bool ClientWorld::can_pass_block(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); + auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); + + if (it == m_chunks.end()) { + return true; + } + const auto& chunk_blocks = it->second.get_chunk_blocks(); + auto [x, y, z] = ClientChunk::world_to_block(block_pos, {chunk_x, chunk_z}); + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { + return true; + } + auto id = chunk_blocks[ClientChunk::index(x, y, z)]; + return BlockManager::is_passable(id); +} +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); + auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); + + if (it == m_chunks.end()) { + // Logger::error("Can't Find Block {} {} {}", block_pos.x, block_pos.y, + // block_pos.z); + return 0; + } + const auto& chunk_blocks = it->second.get_chunk_blocks(); + auto [x, y, z] = ClientChunk::world_to_block(block_pos, {chunk_x, chunk_z}); + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { + // Logger::error("Can't Find Block {} {} {}", block_pos.x, block_pos.y, + // block_pos.z); + return 0; + } + return chunk_blocks[ClientChunk::index(x, y, z)]; +} +void ClientWorld::set_block(const glm::ivec3& block_pos, unsigned id) { + int world_x, world_y, world_z; + world_x = block_pos.x; + world_y = block_pos.y; + world_z = block_pos.z; + + auto [chunk_x, chunk_z] = get_chunk_pos(world_x, world_z); + std::lock_guard lk(m_chunks_mutex); + auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); + + if (it == m_chunks.end()) { + return; + } + + auto [x, y, z] = ClientChunk::world_to_block(world_x, world_y, world_z, + chunk_x, chunk_z); + if (x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y || + z >= CHUNK_SIZE) { + return; + } + + it->second.set_chunk_block(ClientChunk::index(x, y, z), id); + + static const glm::ivec3 NEIGHBOR_DIRS[] = { + {1, 0, 0}, {-1, 0, 0}, {0, 0, -1}, {0, 0, 1}}; + + for (const auto& dir : NEIGHBOR_DIRS) { + glm::ivec3 neighbor = block_pos + dir; + + auto [cx, cz] = get_chunk_pos(neighbor.x, neighbor.z); + auto it = m_chunks.find({cx, cz}); + if (it != m_chunks.end()) { + it->second.mark_dirty(); + } + } +} +void ClientWorld::push_delete_vbo(GLuint vbo) { + std::lock_guard lk(m_delete_vbo_mutex); + m_pending_delete_vbo.push_back(vbo); +} +void ClientWorld::push_delete_vao(GLuint vao) { + std::lock_guard lk(m_delete_vao_mutex); + m_pending_delete_vao.push_back(vao); +} + +void ClientWorld::report_block_change(const glm::ivec3& pos, + unsigned id) const { + BlockChangeReq req; + req.set_uuid(m_player.get_uuid()); + req.set_block(id); + auto* p = req.mutable_pos(); + p->set_x(pos.x); + p->set_y(pos.y); + p->set_z(pos.z); + m_client->send(make_packet(req)); +} + +void ClientWorld::receive_block_change(const BlockChangeRsp& rsp) { + glm::vec3 pos{rsp.pos().x(), rsp.pos().y(), rsp.pos().z()}; + set_block(pos, rsp.block()); +} + void ClientWorld::init() { m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4); diff --git a/src/gameplay/network_client.cpp b/src/gameplay/network_client.cpp index 7e18474..3ba74cd 100644 --- a/src/gameplay/network_client.cpp +++ b/src/gameplay/network_client.cpp @@ -74,6 +74,12 @@ asio::awaitable NetworkClient::read_loop() { m_world.receive_chunk(rsp); } } + case to_num(PacketEnum::BLOCK_CHANGE_RSP): { + BlockChangeRsp rsp; + if (rsp.ParseFromArray(body_data.data(), body_data.size())) { + m_world.receive_block_change(rsp); + } + } } } } catch (const asio::system_error& e) {