refactor(gameplay): add base classes Chunk and World for shared logic

This commit is contained in:
2026-07-25 15:47:46 +08:00
parent df3ac5b5db
commit f9bf2f4b89
11 changed files with 202 additions and 67 deletions

View File

@@ -95,4 +95,5 @@ target_sources(${PROJECT_NAME}
tools/model_loader.cpp
render/model_manager.cpp
render/model_renderer.cpp
gameplay/chunk.cpp
)

49
src/gameplay/chunk.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "Cubed/gameplay/chunk.hpp"
#include "Cubed/tools/cubed_assert.hpp"
namespace Cubed {
int Chunk::index(int x, int y, int z) {
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
z >= CHUNK_SIZE));
if ((x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z < 0 ||
(x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z >=
CHUNK_SIZE * CHUNK_SIZE * WORLD_SIZE_Y) {
Logger::error("block pos x {} y {} z {} range error", x, y, z);
ASSERT(0);
}
return (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z;
}
int Chunk::index(const glm::vec3& pos) {
return Chunk::index(pos.x, pos.y, pos.z);
}
std::tuple<int, int, int> Chunk::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> Chunk::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> Chunk::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> Chunk::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);
}
} // namespace Cubed

View File

@@ -1,7 +1,5 @@
#include "Cubed/gameplay/client_chunk.hpp"
#include "Cubed/tools/cubed_assert.hpp"
namespace Cubed {
using OptionalBlockVectorArray =
std::array<std::optional<std::vector<BlockType>>, 4>;
@@ -128,49 +126,6 @@ ClientChunk& ClientChunk::operator=(ClientChunk&& other) noexcept {
return *this;
}
int ClientChunk::index(int x, int y, int z) {
ASSERT(!(x < 0 || y < 0 || z < 0 || x >= CHUNK_SIZE || y >= WORLD_SIZE_Y ||
z >= CHUNK_SIZE));
if ((x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z < 0 ||
(x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z >=
CHUNK_SIZE * CHUNK_SIZE * WORLD_SIZE_Y) {
Logger::error("block pos x {} y {} z {} range error", x, y, z);
ASSERT(0);
}
return (x * WORLD_SIZE_Y + y) * CHUNK_SIZE + z;
}
int ClientChunk::index(const glm::vec3& pos) {
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(); }
ChunkPos ClientChunk::get_chunk_pos() const { return m_chunk_pos; }

View File

@@ -136,7 +136,6 @@ void ClientWorld::rebuild_world() {
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);
chunk_cacc cacc;
;
if (!m_chunks.find(cacc, ChunkPos{chunk_x, chunk_z})) {
// Logger::error("Can't Find Block {} {} {}", block_pos.x, block_pos.y,
@@ -737,6 +736,7 @@ AABB ClientWorld::get_block_aabb(const glm::ivec3& pos) {
static_cast<float>(pos.z) + 0.5f},
glm::vec3{0.5f, 0.5f, 0.5f}};
}
AudioEngine& ClientWorld::get_audio() { return m_audio; }
const AudioEngine& ClientWorld::get_audio() const { return m_audio; }
Config& ClientWorld::get_config() { return m_config; }

View File

@@ -113,7 +113,7 @@ void ServerWorld::send_chunk(int task_id, const std::string& uuid,
rsq_pos->set_x(pos.x);
rsq_pos->set_z(pos.z);
{
chunk_caac cacc;
chunk_cacc cacc;
if (!m_chunks.find(cacc, pos)) {
// No chunk found and not generating
Logger::error("Chunk {} {} neither pending nor ready", pos.x,
@@ -990,4 +990,88 @@ void ServerWorld::set_chunk_load_style(int id) {
int ServerWorld::chunk_size() const { return m_chunks.size(); }
int ServerWorld::get_block(const glm::ivec3& block_pos) const {
auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z);
chunk_cacc cacc;
if (!m_chunks.find(cacc, ChunkPos{chunk_x, chunk_z})) {
return 0;
}
if (cacc->second.state != ChunkState::READY) {
return 0;
}
const auto& chunk_blocks = cacc->second.chunk->get_chunk_blocks();
auto [x, y, z] = Chunk::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[Chunk::index(x, y, z)];
}
bool ServerWorld::is_solid(const glm::ivec3& block_pos) const {
auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z);
chunk_cacc cacc;
if (!m_chunks.find(cacc, ChunkPos{chunk_x, chunk_z})) {
return false;
}
if (cacc->second.state != ChunkState::READY) {
return 0;
}
const auto& chunk_blocks = cacc->second.chunk->get_chunk_blocks();
auto [x, y, z] = Chunk::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[Chunk::index(x, y, z)];
if (BlockManager::is_gas(id) || BlockManager::is_liquid(id)) {
return false;
} else {
return true;
}
}
bool ServerWorld::can_pass_block(const glm::ivec3& block_pos) const {
auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z);
chunk_cacc cacc;
if (!m_chunks.find(cacc, ChunkPos{chunk_x, chunk_z})) {
return true;
}
if (cacc->second.state != ChunkState::READY) {
return 0;
}
const auto& chunk_blocks = cacc->second.chunk->get_chunk_blocks();
auto [x, y, z] = Chunk::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[Chunk::index(x, y, z)];
return BlockManager::is_passable(id);
}
BlockType ServerWorld::get_block_tpye(const glm::ivec3& block_pos) const {
auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z);
chunk_cacc cacc;
if (!m_chunks.find(cacc, ChunkPos{chunk_x, chunk_z})) {
// Logger::error("Can't Find Block {} {} {}", block_pos.x, block_pos.y,
// block_pos.z);
return 0;
}
if (cacc->second.state != ChunkState::READY) {
return 0;
}
const auto& chunk_blocks = cacc->second.chunk->get_chunk_blocks();
auto [x, y, z] = Chunk::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[Chunk::index(x, y, z)];
}
} // namespace Cubed