diff --git a/src/logic/scripting/lua/libs/libblock.cpp b/src/logic/scripting/lua/libs/libblock.cpp index 5d681e5f..e454903c 100644 --- a/src/logic/scripting/lua/libs/libblock.cpp +++ b/src/logic/scripting/lua/libs/libblock.cpp @@ -98,7 +98,7 @@ static int l_set(lua::State* L) { if (!level->chunks->get(x, y, z)) { return 0; } - level->chunks->set(x, y, z, id, int2blockstate(state)); + blocks_agent::set(*level->chunksStorage, x, y, z, id, int2blockstate(state)); level->lighting->onBlockSet(x, y, z, id); if (!noupdate) { blocks->updateSides(x, y, z); @@ -269,7 +269,9 @@ static int l_is_replaceable_at(lua::State* L) { auto x = lua::tointeger(L, 1); auto y = lua::tointeger(L, 2); auto z = lua::tointeger(L, 3); - return lua::pushboolean(L, level->chunks->isReplaceableBlock(x, y, z)); + return lua::pushboolean( + L, blocks_agent::is_replaceable_at(*level->chunksStorage, x, y, z) + ); } static int l_caption(lua::State* L) { diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 8bfe6166..50812d07 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -89,9 +89,7 @@ bool Chunks::isSolidBlock(int32_t x, int32_t y, int32_t z) { } bool Chunks::isReplaceableBlock(int32_t x, int32_t y, int32_t z) { - voxel* v = get(x, y, z); - if (v == nullptr) return false; - return indices->blocks.require(v->id).replaceable; + return blocks_agent::is_replaceable_at(*this, x, y, z); } bool Chunks::isObstacleBlock(int32_t x, int32_t y, int32_t z) { @@ -184,50 +182,13 @@ glm::ivec3 Chunks::seekOrigin( void Chunks::eraseSegments( const Block& def, blockstate state, int x, int y, int z ) { - const auto& rotation = def.rotations.variants[state.rotation]; - for (int sy = 0; sy < def.size.y; sy++) { - for (int sz = 0; sz < def.size.z; sz++) { - for (int sx = 0; sx < def.size.x; sx++) { - if ((sx | sy | sz) == 0) { - continue; - } - glm::ivec3 pos(x, y, z); - pos += rotation.axisX * sx; - pos += rotation.axisY * sy; - pos += rotation.axisZ * sz; - set(pos.x, pos.y, pos.z, 0, {}); - } - } - } -} - -static constexpr uint8_t segment_to_int(int sx, int sy, int sz) { - return ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2)); + blocks_agent::erase_segments(*this, def, state, x, y, z); } void Chunks::repairSegments( const Block& def, blockstate state, int x, int y, int z ) { - const auto& rotation = def.rotations.variants[state.rotation]; - const auto id = def.rt.id; - const auto size = def.size; - for (int sy = 0; sy < size.y; sy++) { - for (int sz = 0; sz < size.z; sz++) { - for (int sx = 0; sx < size.x; sx++) { - if ((sx | sy | sz) == 0) { - continue; - } - blockstate segState = state; - segState.segment = segment_to_int(sx, sy, sz); - - glm::ivec3 pos(x, y, z); - pos += rotation.axisX * sx; - pos += rotation.axisY * sy; - pos += rotation.axisZ * sz; - set(pos.x, pos.y, pos.z, id, segState); - } - } - } + blocks_agent::repair_segments(*this, def, state, x, y, z); } bool Chunks::checkReplaceability( @@ -283,7 +244,7 @@ void Chunks::setRotationExtended( pos += rotation.axisZ * sz; blockstate segState = newstate; - segState.segment = segment_to_int(sx, sy, sz); + segState.segment = blocks_agent::segment_to_int(sx, sy, sz); auto vox = get(pos); // checked for nullptr by checkReplaceability @@ -344,68 +305,7 @@ void Chunks::setRotation(int32_t x, int32_t y, int32_t z, uint8_t index) { void Chunks::set( int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state ) { - if (y < 0 || y >= CHUNK_H) { - return; - } - int cx = floordiv(x); - int cz = floordiv(z); - auto ptr = areaMap.getIf(cx, cz); - if (ptr == nullptr) { - return; - } - Chunk* chunk = ptr->get(); - if (chunk == nullptr) { - return; - } - int lx = x - cx * CHUNK_W; - int lz = z - cz * CHUNK_D; - size_t index = vox_index(lx, y, lz); - - // block finalization - voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx]; - const auto& prevdef = indices->blocks.require(vox.id); - if (prevdef.inventorySize != 0) { - chunk->removeBlockInventory(lx, y, lz); - } - if (prevdef.rt.extended && !vox.state.segment) { - eraseSegments(prevdef, vox.state, x, y, z); - } - if (prevdef.dataStruct) { - if (auto found = chunk->blocksMetadata.find(index)) { - chunk->blocksMetadata.free(found); - chunk->flags.unsaved = true; - chunk->flags.blocksData = true; - } - } - - // block initialization - const auto& newdef = indices->blocks.require(id); - vox.id = id; - vox.state = state; - chunk->setModifiedAndUnsaved(); - if (!state.segment && newdef.rt.extended) { - repairSegments(newdef, state, x, y, z); - } - - if (y < chunk->bottom) - chunk->bottom = y; - else if (y + 1 > chunk->top) - chunk->top = y + 1; - else if (id == 0) - chunk->updateHeights(); - - if (lx == 0 && (chunk = getChunk(cx - 1, cz))) { - chunk->flags.modified = true; - } - if (lz == 0 && (chunk = getChunk(cx, cz - 1))) { - chunk->flags.modified = true; - } - if (lx == CHUNK_W - 1 && (chunk = getChunk(cx + 1, cz))) { - chunk->flags.modified = true; - } - if (lz == CHUNK_D - 1 && (chunk = getChunk(cx, cz + 1))) { - chunk->flags.modified = true; - } + blocks_agent::set(*this, x, y, z, id, state); } voxel* Chunks::rayCast( @@ -652,6 +552,7 @@ void Chunks::resize(uint32_t newW, uint32_t newD) { bool Chunks::putChunk(const std::shared_ptr& chunk) { if (areaMap.set(chunk->x, chunk->z, chunk)) { + if (level) level->events->trigger(LevelEventType::EVT_CHUNK_SHOWN, chunk.get()); return true; } diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 38843398..98a2d40a 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -16,16 +16,6 @@ #include "Block.hpp" #include "Chunk.hpp" -inline uint64_t keyfrom(int32_t x, int32_t z) { - union { - int32_t pos[2]; - uint64_t key; - } ekey; - ekey.pos[0] = x; - ekey.pos[1] = z; - return ekey.key; -} - static debug::Logger logger("chunks-storage"); GlobalChunks::GlobalChunks(Level* level) @@ -208,11 +198,3 @@ void GlobalChunks::saveAll() { void GlobalChunks::putChunk(std::shared_ptr chunk) { chunksMap[keyfrom(chunk->x, chunk->z)] = std::move(chunk); } - -Chunk* GlobalChunks::getChunk(int cx, int cz) const { - const auto& found = chunksMap.find(keyfrom(cx, cz)); - if (found == chunksMap.end()) { - return nullptr; - } - return found->second.get(); -} diff --git a/src/voxels/GlobalChunks.hpp b/src/voxels/GlobalChunks.hpp index f7ce0e92..afbdf67c 100644 --- a/src/voxels/GlobalChunks.hpp +++ b/src/voxels/GlobalChunks.hpp @@ -14,6 +14,16 @@ class Level; class ContentIndices; class GlobalChunks { + static inline uint64_t keyfrom(int32_t x, int32_t z) { + union { + int32_t pos[2]; + uint64_t key; + } ekey; + ekey.pos[0] = x; + ekey.pos[1] = z; + return ekey.key; + } + Level* level; const ContentIndices* indices; std::unordered_map> chunksMap; @@ -41,7 +51,13 @@ public: void putChunk(std::shared_ptr chunk); - Chunk* getChunk(int cx, int cz) const; + inline Chunk* getChunk(int cx, int cz) const { + const auto& found = chunksMap.find(keyfrom(cx, cz)); + if (found == chunksMap.end()) { + return nullptr; + } + return found->second.get(); + } const ContentIndices& getContentIndices() const { return *indices; diff --git a/src/voxels/blocks_agent.cpp b/src/voxels/blocks_agent.cpp new file mode 100644 index 00000000..53cef38d --- /dev/null +++ b/src/voxels/blocks_agent.cpp @@ -0,0 +1,95 @@ +#include "blocks_agent.hpp" + +using namespace blocks_agent; + +template +static inline void set_block( + Storage& chunks, + int32_t x, + int32_t y, + int32_t z, + uint32_t id, + blockstate state +) { + if (y < 0 || y >= CHUNK_H) { + return; + } + const auto& indices = chunks.getContentIndices(); + int cx = floordiv(x); + int cz = floordiv(z); + Chunk* chunk = get_chunk(chunks, cx, cz); + if (chunk == nullptr) { + return; + } + int lx = x - cx * CHUNK_W; + int lz = z - cz * CHUNK_D; + size_t index = vox_index(lx, y, lz); + + // block finalization + voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx]; + const auto& prevdef = indices.blocks.require(vox.id); + if (prevdef.inventorySize != 0) { + chunk->removeBlockInventory(lx, y, lz); + } + if (prevdef.rt.extended && !vox.state.segment) { + erase_segments(chunks, prevdef, vox.state, x, y, z); + } + if (prevdef.dataStruct) { + if (auto found = chunk->blocksMetadata.find(index)) { + chunk->blocksMetadata.free(found); + chunk->flags.unsaved = true; + chunk->flags.blocksData = true; + } + } + + // block initialization + const auto& newdef = indices.blocks.require(id); + vox.id = id; + vox.state = state; + chunk->setModifiedAndUnsaved(); + if (!state.segment && newdef.rt.extended) { + repair_segments(chunks, newdef, state, x, y, z); + } + + if (y < chunk->bottom) + chunk->bottom = y; + else if (y + 1 > chunk->top) + chunk->top = y + 1; + else if (id == 0) + chunk->updateHeights(); + + if (lx == 0 && (chunk = get_chunk(chunks, cx - 1, cz))) { + chunk->flags.modified = true; + } + if (lz == 0 && (chunk = get_chunk(chunks, cx, cz - 1))) { + chunk->flags.modified = true; + } + if (lx == CHUNK_W - 1 && (chunk = get_chunk(chunks, cx + 1, cz))) { + chunk->flags.modified = true; + } + if (lz == CHUNK_D - 1 && (chunk = get_chunk(chunks, cx, cz + 1))) { + chunk->flags.modified = true; + } +} + +void blocks_agent::set( + Chunks& chunks, + int32_t x, + int32_t y, + int32_t z, + uint32_t id, + blockstate state +) { + set_block(chunks, x, y, z, id, state); +} + +void blocks_agent::set( + GlobalChunks& chunks, + int32_t x, + int32_t y, + int32_t z, + uint32_t id, + blockstate state +) { + set_block(chunks, x, y, z, id, state); +} diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index 31ae79c5..22850f40 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -1,12 +1,16 @@ #pragma once #include "voxel.hpp" +#include "Block.hpp" +#include "Chunk.hpp" +#include "Chunks.hpp" +#include "GlobalChunks.hpp" +#include "constants.hpp" #include "typedefs.hpp" +#include "content/Content.hpp" #include "maths/voxmaths.hpp" -class Chunk; -class Chunks; -class GlobalChunks; +#include /// Using templates to minimize OOP overhead @@ -55,4 +59,81 @@ inline bool is_solid_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) return false; } +template +inline bool is_replaceable_at(const Storage& chunks, int32_t x, int32_t y, int32_t z) { + if (auto vox = get(chunks, x, y, z)) { + return get_block_def(chunks, vox->id).replaceable; + } + return false; +} + +void set( + Chunks& chunks, + int32_t x, + int32_t y, + int32_t z, + uint32_t id, + blockstate state +); + +void set( + GlobalChunks& chunks, + int32_t x, + int32_t y, + int32_t z, + uint32_t id, + blockstate state +); + +template +inline void erase_segments( + Storage& chunks, const Block& def, blockstate state, int x, int y, int z +) { + const auto& rotation = def.rotations.variants[state.rotation]; + for (int sy = 0; sy < def.size.y; sy++) { + for (int sz = 0; sz < def.size.z; sz++) { + for (int sx = 0; sx < def.size.x; sx++) { + if ((sx | sy | sz) == 0) { + continue; + } + glm::ivec3 pos(x, y, z); + pos += rotation.axisX * sx; + pos += rotation.axisY * sy; + pos += rotation.axisZ * sz; + set(chunks, pos.x, pos.y, pos.z, 0, {}); + } + } + } +} + +static constexpr uint8_t segment_to_int(int sx, int sy, int sz) { + return ((sx > 0) | ((sy > 0) << 1) | ((sz > 0) << 2)); +} + +template +inline void repair_segments( + Storage& chunks, const Block& def, blockstate state, int x, int y, int z +) { + const auto& rotation = def.rotations.variants[state.rotation]; + const auto id = def.rt.id; + const auto size = def.size; + for (int sy = 0; sy < size.y; sy++) { + for (int sz = 0; sz < size.z; sz++) { + for (int sx = 0; sx < size.x; sx++) { + if ((sx | sy | sz) == 0) { + continue; + } + blockstate segState = state; + segState.segment = segment_to_int(sx, sy, sz); + + glm::ivec3 pos(x, y, z); + pos += rotation.axisX * sx; + pos += rotation.axisY * sy; + pos += rotation.axisZ * sz; + set(chunks, pos.x, pos.y, pos.z, id, segState); + } + } + } +} + } // blocks_agent diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index bc851a07..281ac411 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -189,10 +189,10 @@ void WorldGenerator::placeLine(const LinePlacement& line, int priority) { aabb.fix(); aabb.a -= line.radius; aabb.b += line.radius; - int cxa = floordiv(aabb.a.x, CHUNK_W); - int cza = floordiv(aabb.a.z, CHUNK_D); - int cxb = floordiv(aabb.b.x, CHUNK_W); - int czb = floordiv(aabb.b.z, CHUNK_D); + int cxa = floordiv(aabb.a.x); + int cza = floordiv(aabb.a.z); + int cxb = floordiv(aabb.b.x); + int czb = floordiv(aabb.b.z); for (int cz = cza; cz <= czb; cz++) { for (int cx = cxa; cx <= cxb; cx++) { const auto& found = prototypes.find({cx, cz});