mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
feat(gameplay): add block change sync and coordinate utils
This commit is contained in:
@@ -37,7 +37,15 @@ public:
|
|||||||
|
|
||||||
static int index(int x, int y, int z);
|
static int index(int x, int y, int z);
|
||||||
static int index(const glm::vec3& pos);
|
static int index(const glm::vec3& pos);
|
||||||
|
static std::tuple<int, int, int> world_to_block(int world_x, int world_y,
|
||||||
|
int world_z, int chunk_x,
|
||||||
|
int chunk_z);
|
||||||
|
static std::tuple<int, int, int> world_to_block(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos);
|
||||||
|
static std::tuple<int, int, int> block_to_world(int x, int y, int z,
|
||||||
|
int chunk_x, int chunk_z);
|
||||||
|
static std::tuple<int, int, int> block_to_world(const glm::ivec3& block_pos,
|
||||||
|
ChunkPos chunk_pos);
|
||||||
BiomeType get_biome() const;
|
BiomeType get_biome() const;
|
||||||
ChunkPos get_chunk_pos() const;
|
ChunkPos get_chunk_pos() const;
|
||||||
const std::vector<BlockType>& get_chunk_blocks() const;
|
const std::vector<BlockType>& get_chunk_blocks() const;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Cubed/AABB.hpp"
|
|
||||||
#include "Cubed/gameplay/block.hpp"
|
#include "Cubed/gameplay/block.hpp"
|
||||||
#include "Cubed/gameplay/chunk_pos.hpp"
|
#include "Cubed/gameplay/chunk_pos.hpp"
|
||||||
#include "Cubed/gameplay/client_chunk.hpp"
|
#include "Cubed/gameplay/client_chunk.hpp"
|
||||||
@@ -18,7 +17,6 @@ public:
|
|||||||
~ClientWorld();
|
~ClientWorld();
|
||||||
void init();
|
void init();
|
||||||
void update(float delta_time);
|
void update(float delta_time);
|
||||||
bool can_move(const AABB& player_box) const;
|
|
||||||
const std::optional<LookBlock>&
|
const std::optional<LookBlock>&
|
||||||
get_look_block_pos(const std::string& name) const;
|
get_look_block_pos(const std::string& name) const;
|
||||||
ClientPlayer& get_player();
|
ClientPlayer& get_player();
|
||||||
@@ -26,13 +24,14 @@ public:
|
|||||||
bool is_solid(const glm::ivec3& block_pos) const;
|
bool is_solid(const glm::ivec3& block_pos) const;
|
||||||
bool can_pass_block(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;
|
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_vbo(GLuint vbo);
|
||||||
void push_delete_vao(GLuint vao);
|
void push_delete_vao(GLuint vao);
|
||||||
void hot_reload();
|
// void hot_reload();
|
||||||
|
|
||||||
void rebuild_world();
|
|
||||||
|
|
||||||
|
// 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;
|
int rendering_distance() const;
|
||||||
void rendering_distance(int rendering_distance);
|
void rendering_distance(int rendering_distance);
|
||||||
void start_client_thread(std::string_view uuid);
|
void start_client_thread(std::string_view uuid);
|
||||||
@@ -78,5 +77,6 @@ private:
|
|||||||
void report_player_pos();
|
void report_player_pos();
|
||||||
|
|
||||||
void request_chunk();
|
void request_chunk();
|
||||||
|
void set_block(const glm::ivec3& pos, unsigned id);
|
||||||
};
|
};
|
||||||
} // namespace Cubed
|
} // namespace Cubed
|
||||||
|
|||||||
@@ -137,7 +137,34 @@ int ClientChunk::index(int x, int y, int z) {
|
|||||||
int ClientChunk::index(const glm::vec3& pos) {
|
int ClientChunk::index(const glm::vec3& pos) {
|
||||||
return ClientChunk::index(pos.x, pos.y, pos.z);
|
return ClientChunk::index(pos.x, pos.y, pos.z);
|
||||||
}
|
}
|
||||||
|
std::tuple<int, int, int> 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<int, int, int>
|
||||||
|
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<int, int, int>
|
||||||
|
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<int, int, int>
|
||||||
|
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(); }
|
BiomeType ClientChunk::get_biome() const { return m_biome.load(); }
|
||||||
|
|
||||||
ChunkPos ClientChunk::get_chunk_pos() const { return m_chunk_pos; }
|
ChunkPos ClientChunk::get_chunk_pos() const { return m_chunk_pos; }
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ void ClientPlayer::update_lookup_block() {
|
|||||||
if (m_look_block != std::nullopt) {
|
if (m_look_block != std::nullopt) {
|
||||||
if (Input::get_input_state().mouse_state.left) {
|
if (Input::get_input_state().mouse_state.left) {
|
||||||
if (m_world.is_solid(m_look_block->pos)) {
|
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;
|
Input::get_input_state().mouse_state.left = false;
|
||||||
}
|
}
|
||||||
@@ -296,7 +296,7 @@ void ClientPlayer::update_lookup_block() {
|
|||||||
static_cast<float>(z + 1)}};
|
static_cast<float>(z + 1)}};
|
||||||
AABB player_box = get_aabb();
|
AABB player_box = get_aabb();
|
||||||
if (!player_box.intersects(block_box)) {
|
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;
|
Input::get_input_state().mouse_state.right = false;
|
||||||
|
|||||||
@@ -49,6 +49,143 @@ ClientWorld::get_look_block_pos(const std::string& name) const {
|
|||||||
|
|
||||||
ClientPlayer& ClientWorld::get_player() { return m_player; }
|
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() {
|
void ClientWorld::init() {
|
||||||
m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4);
|
m_chunks.reserve(MAX_DISTANCE * MAX_DISTANCE * 4);
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,12 @@ asio::awaitable<void> NetworkClient::read_loop() {
|
|||||||
m_world.receive_chunk(rsp);
|
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) {
|
} catch (const asio::system_error& e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user