diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index e2bf81f2d..e2a463cac 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -441,7 +441,8 @@ static void load_script(const Content& content, T& def) { def.name, scriptfile, def.scriptFile, - def.rt.funcsset + def.rt.funcsset, + def.rt.eventNames ); } } diff --git a/src/items/ItemDef.hpp b/src/items/ItemDef.hpp index ee37215a6..3f16e04b1 100644 --- a/src/items/ItemDef.hpp +++ b/src/items/ItemDef.hpp @@ -15,6 +15,9 @@ struct ItemFuncsSet { bool on_block_break_by : 1; }; +struct ItemFuncNamesCache { +}; + enum class ItemIconType { NONE, // invisible (core:empty) must not be rendered SPRITE, // textured quad: icon is `atlas_name:texture_name` @@ -75,6 +78,8 @@ struct ItemDef { bool emissive = false; std::set tags; + + ItemFuncNamesCache eventNames; } rt {}; ItemDef(const std::string& name); diff --git a/src/lighting/LightSolver.cpp b/src/lighting/LightSolver.cpp index cda3ccc88..f43b4d487 100644 --- a/src/lighting/LightSolver.cpp +++ b/src/lighting/LightSolver.cpp @@ -1,6 +1,3 @@ -#include -#include - #include "LightSolver.hpp" #include "Lightmap.hpp" #include "content/Content.hpp" @@ -9,6 +6,8 @@ #include "voxels/voxel.hpp" #include "voxels/Block.hpp" +#include + LightSolver::LightSolver(const ContentIndices& contentIds, Chunks& chunks, int channel) : blockDefs(contentIds.blocks.getDefs()), chunks(chunks), @@ -55,7 +54,7 @@ void LightSolver::remove(int x, int y, int z) { lightmap.set(x-chunk->x*CHUNK_W, y, z-chunk->z*CHUNK_D, channel, 0); } -void LightSolver::solve(){ +void LightSolver::solve(Chunk* prevailingChunk) { const int coords[] = { 0, 0, 1, 0, 0,-1, @@ -66,47 +65,54 @@ void LightSolver::solve(){ }; while (!remqueue.empty()){ - const lightentry entry = remqueue.front(); + lightentry entry = std::move(remqueue.front()); remqueue.pop(); for (int i = 0; i < 6; i++) { - int imul3 = i*3; + int imul3 = i * 3; int x = entry.x+coords[imul3]; int y = entry.y+coords[imul3+1]; int z = entry.z+coords[imul3+2]; - Chunk* chunk = chunks.getChunkByVoxel(x,y,z); - if (chunk) { - int lx = x - chunk->x * CHUNK_W; - int lz = z - chunk->z * CHUNK_D; - chunk->flags.modified = true; + Chunk* chunk = prevailingChunk; + if (chunk == nullptr || !chunk->isBlockInside(x, z)) { + chunk = chunks.getChunkByVoxel(x,y,z); + if (chunk == nullptr) { + continue; + } + } else if (y < 0 || y >= CHUNK_H) { + continue; + } - assert(chunk->lightmap != nullptr); - auto& lightmap = *chunk->lightmap; + int lx = x - chunk->x * CHUNK_W; + int lz = z - chunk->z * CHUNK_D; + chunk->flags.modified = true; - ubyte light = lightmap.get(lx,y,lz, channel); - if (light != 0 && light == entry.light-1){ - voxel* vox = chunks.get(x, y, z); - if (vox && vox->id != 0) { - const Block* block = blockDefs[vox->id]; - if (uint8_t emission = block->emission[channel]) { - addqueue.push(lightentry {x, y, z, emission}); - lightmap.set(lx, y, lz, channel, emission); - } - else lightmap.set(lx, y, lz, channel, 0); + assert(chunk->lightmap != nullptr); + auto& lightmap = *chunk->lightmap; + + ubyte light = lightmap.get(lx,y,lz, channel); + if (light != 0 && light == entry.light-1) { + voxel* vox = chunks.get(x, y, z); + if (vox && vox->id != 0) { + const Block* block = blockDefs[vox->id]; + if (uint8_t emission = block->emission[channel]) { + addqueue.push(lightentry {x, y, z, emission}); + lightmap.set(lx, y, lz, channel, emission); } else lightmap.set(lx, y, lz, channel, 0); - remqueue.push(lightentry {x, y, z, light}); - } - else if (light >= entry.light){ - addqueue.push(lightentry {x, y, z, light}); } + else lightmap.set(lx, y, lz, channel, 0); + remqueue.push(lightentry {x, y, z, light}); + } + else if (light >= entry.light) { + addqueue.push(lightentry {x, y, z, light}); } } } while (!addqueue.empty()){ - const lightentry entry = addqueue.front(); + lightentry entry = std::move(addqueue.front()); addqueue.pop(); for (int i = 0; i < 6; i++) { @@ -115,10 +121,16 @@ void LightSolver::solve(){ int y = entry.y+coords[imul3+1]; int z = entry.z+coords[imul3+2]; - Chunk* chunk = chunks.getChunkByVoxel(x,y,z); - if (chunk == nullptr) { + Chunk* chunk = prevailingChunk; + if (chunk == nullptr || !chunk->isBlockInside(x, z)) { + chunk = chunks.getChunkByVoxel(x,y,z); + if (chunk == nullptr) { + continue; + } + } else if (y < 0 || y >= CHUNK_H) { continue; } + assert(chunk->lightmap != nullptr); auto& lightmap = *chunk->lightmap; int lx = x - chunk->x * CHUNK_W; diff --git a/src/lighting/LightSolver.hpp b/src/lighting/LightSolver.hpp index e51863e1e..31c33a804 100644 --- a/src/lighting/LightSolver.hpp +++ b/src/lighting/LightSolver.hpp @@ -1,7 +1,8 @@ #pragma once -#include +#include "util/array_queue.hpp" +class Chunk; class Chunks; class ContentIndices; class Block; @@ -14,8 +15,8 @@ struct lightentry { }; class LightSolver { - std::queue addqueue; - std::queue remqueue; + util::array_queue addqueue; + util::array_queue remqueue; const Block* const* blockDefs; Chunks& chunks; int channel; @@ -25,5 +26,5 @@ public: void add(int x, int y, int z); void add(int x, int y, int z, int emission); void remove(int x, int y, int z); - void solve(); + void solve(Chunk* prevailingChunk = nullptr); }; diff --git a/src/lighting/Lighting.cpp b/src/lighting/Lighting.cpp index 9101c72ac..b17b6f333 100644 --- a/src/lighting/Lighting.cpp +++ b/src/lighting/Lighting.cpp @@ -167,10 +167,10 @@ void Lighting::onChunkLoaded(int cx, int cz, bool expand) { } } } - solverR.solve(); - solverG.solve(); - solverB.solve(); - solverS.solve(); + solverR.solve(chunk); + solverG.solve(chunk); + solverB.solve(chunk); + solverS.solve(chunk); } void Lighting::onBlockSet(int x, int y, int z, blockid_t id){ @@ -180,9 +180,10 @@ void Lighting::onBlockSet(int x, int y, int z, blockid_t id){ solverB->remove(x,y,z); if (id == 0){ - solverR->solve(); - solverG->solve(); - solverB->solve(); + auto chunk = chunks.getChunkByVoxel(glm::ivec3{x, y, z}); + solverR->solve(chunk); + solverG->solve(chunk); + solverB->solve(chunk); if (chunks.getLight(x,y+1,z, 3) == 0xF){ for (int i = y; i >= 0; i--){ voxel* vox = chunks.get(x,i,z); @@ -191,17 +192,30 @@ void Lighting::onBlockSet(int x, int y, int z, blockid_t id){ solverS->add(x,i,z, 0xF); } } - solverR->add(x,y+1,z); solverG->add(x,y+1,z); solverB->add(x,y+1,z); solverS->add(x,y+1,z); - solverR->add(x,y-1,z); solverG->add(x,y-1,z); solverB->add(x,y-1,z); solverS->add(x,y-1,z); - solverR->add(x+1,y,z); solverG->add(x+1,y,z); solverB->add(x+1,y,z); solverS->add(x+1,y,z); - solverR->add(x-1,y,z); solverG->add(x-1,y,z); solverB->add(x-1,y,z); solverS->add(x-1,y,z); - solverR->add(x,y,z+1); solverG->add(x,y,z+1); solverB->add(x,y,z+1); solverS->add(x,y,z+1); - solverR->add(x,y,z-1); solverG->add(x,y,z-1); solverB->add(x,y,z-1); solverS->add(x,y,z-1); - solverR->solve(); - solverG->solve(); - solverB->solve(); - solverS->solve(); + const int coords[] = { + 0, 0, 1, + 0, 0,-1, + 0, 1, 0, + 0,-1, 0, + 1, 0, 0, + -1, 0, 0 + }; + for (int i = 0; i < 6; i++) { + int lx = x + coords[i * 3]; + int ly = y + coords[i * 3 + 1]; + int lz = z + coords[i * 3 + 2]; + + solverR->add(lx, ly, lz); + solverG->add(lx, ly, lz); + solverB->add(lx, ly, lz); + solverS->add(lx, ly, lz); + solverR->solve(chunk); + solverG->solve(chunk); + solverB->solve(chunk); + solverS->solve(chunk); + } } else { + auto chunk = chunks.getChunkByVoxel(glm::ivec3{x, y, z}); if (!block.skyLightPassing){ solverS->remove(x,y,z); for (int i = y-1; i >= 0; i--){ @@ -210,19 +224,19 @@ void Lighting::onBlockSet(int x, int y, int z, blockid_t id){ break; } } - solverS->solve(); + solverS->solve(chunk); } - solverR->solve(); - solverG->solve(); - solverB->solve(); + solverR->solve(chunk); + solverG->solve(chunk); + solverB->solve(chunk); if (block.emission[0] || block.emission[1] || block.emission[2]){ solverR->add(x,y,z,block.emission[0]); solverG->add(x,y,z,block.emission[1]); solverB->add(x,y,z,block.emission[2]); - solverR->solve(); - solverG->solve(); - solverB->solve(); + solverR->solve(chunk); + solverG->solve(chunk); + solverB->solve(chunk); } } } diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index 08e2aae7c..f859a8455 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -1,7 +1,5 @@ #include "BlocksController.hpp" -#include - #include "content/Content.hpp" #include "items/Inventories.hpp" #include "items/Inventory.hpp" @@ -175,12 +173,8 @@ void BlocksController::randomTick( void BlocksController::randomTick(int tickid, int parts, uint padding) { auto indices = level.content.getIndices(); - std::set chunksIterated; - for (const auto& [pid, player] : *level.players) { const auto& chunks = *player->chunks; - int offsetX = chunks.getOffsetX(); - int offsetY = chunks.getOffsetY(); int width = chunks.getWidth(); int height = chunks.getHeight(); int segments = 4; @@ -195,20 +189,15 @@ void BlocksController::randomTick(int tickid, int parts, uint padding) { if (chunk == nullptr || !chunk->flags.lighted) { continue; } - union { - int32_t pos[2]; - uint64_t key; - } posU; - posU.pos[0] = x + offsetX; - posU.pos[1] = z + offsetY; - if (chunksIterated.find(posU.key) != chunksIterated.end()) { + if (chunk->lastRandomTickId == randomTickId) { continue; } - chunksIterated.insert(posU.key); + chunk->lastRandomTickId = randomTickId; randomTick(*chunk, segments, indices); } } } + randomTickId++; } int64_t BlocksController::createBlockInventory(int x, int y, int z) { diff --git a/src/logic/BlocksController.hpp b/src/logic/BlocksController.hpp index f3fa5f67a..8b26e0190 100644 --- a/src/logic/BlocksController.hpp +++ b/src/logic/BlocksController.hpp @@ -33,6 +33,7 @@ class BlocksController { util::Clock worldTickClock; FastRandom random {}; std::vector blockInteractionCallbacks; + uint64_t randomTickId = 0; public: BlocksController(const Level& level, Lighting* lighting); diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 4af1a4287..ca1ab3164 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -1,8 +1,5 @@ #include "scripting.hpp" -#include -#include - #include "scripting_commons.hpp" #include "content/Content.hpp" #include "content/ContentPack.hpp" @@ -28,6 +25,9 @@ #include "world/World.hpp" #include "interfaces/Process.hpp" +#include +#include + using namespace scripting; static debug::Logger logger("scripting"); @@ -391,15 +391,15 @@ void scripting::on_blocks_tick(const Block& block, int tps) { } void scripting::update_block(const Block& block, const glm::ivec3& pos) { - std::string name = block.name + ".update"; - lua::emit_event(lua::get_main_state(), name, [pos](auto L) { + lua::emit_event(lua::get_main_state(), block.rt.eventNames.update, + [pos](auto L) { return lua::pushivec_stack(L, pos); }); } void scripting::random_update_block(const Block& block, const glm::ivec3& pos) { - std::string name = block.name + ".randupdate"; - lua::emit_event(lua::get_main_state(), name, [pos](auto L) { + lua::emit_event(lua::get_main_state(), block.rt.eventNames.randomUpdate, + [pos](auto L) { return lua::pushivec_stack(L, pos); }); } @@ -660,7 +660,8 @@ void scripting::load_content_script( const std::string& prefix, const io::path& file, const std::string& fileName, - BlockFuncsSet& funcsset + BlockFuncsSet& funcsset, + BlockFuncNamesCache& namesCache ) { int env = *senv; lua::pop(lua::get_main_state(), load_script(env, "block", file, fileName)); @@ -686,6 +687,9 @@ void scripting::load_content_script( register_event(env, "on_block_present", prefix + ".blockpresent"); funcsset.onblockremoved = register_event(env, "on_block_removed", prefix + ".blockremoved"); + + namesCache.randomUpdate = prefix + ".update"; + namesCache.randomUpdate = prefix + ".randupdate"; } void scripting::load_content_script( @@ -693,7 +697,8 @@ void scripting::load_content_script( const std::string& prefix, const io::path& file, const std::string& fileName, - ItemFuncsSet& funcsset + ItemFuncsSet& funcsset, + ItemFuncNamesCache& namesCache ) { int env = *senv; lua::pop(lua::get_main_state(), load_script(env, "item", file, fileName)); diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index 298130c99..64fa1a3d1 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -23,7 +23,9 @@ struct ItemDef; class Inventory; class UiDocument; struct BlockFuncsSet; +struct BlockFuncNamesCache; struct ItemFuncsSet; +struct ItemFuncNamesCache; struct WorldFuncsSet; struct UserComponent; struct uidocscript; @@ -168,7 +170,8 @@ namespace scripting { const std::string& prefix, const io::path& file, const std::string& fileName, - BlockFuncsSet& funcsset + BlockFuncsSet& funcsset, + BlockFuncNamesCache& namesCache ); /// @brief Load script associated with an Item @@ -182,7 +185,8 @@ namespace scripting { const std::string& prefix, const io::path& file, const std::string& fileName, - ItemFuncsSet& funcsset + ItemFuncsSet& funcsset, + ItemFuncNamesCache& namesCache ); /// @brief Load component script diff --git a/src/util/array_queue.hpp b/src/util/array_queue.hpp new file mode 100644 index 000000000..649ec2282 --- /dev/null +++ b/src/util/array_queue.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include +#include +#include + +namespace util { + template + class array_queue { + public: + array_queue(size_t initCapacity = 8) + : _capacity(initCapacity), + _size(0), + _front(0), + _back(0), + _data(std::make_unique(_capacity)) { + if (initCapacity == 0 || (initCapacity & (initCapacity - 1)) != 0) { + throw std::invalid_argument("initCapacity must be positive power of 2"); + } + } + + ~array_queue() { + while (!empty()) { + pop(); + } + } + + void push(T&& value) { + if (_back == _front && _size) { + grow(); + } + _data[_back] = std::forward(value); + _back = (_back + 1) & (_capacity - 1); + ++_size; + } + + T& front() { + return _data[_front]; + } + + void pop() { + _data[_front].~T(); + _front = (_front + 1) & (_capacity - 1); + --_size; + } + + bool empty() const { + return _size == 0; + } + + size_t size() const { + return _size; + } + + private: + size_t _capacity; + size_t _size; + size_t _front; + size_t _back; + std::unique_ptr _data; + + void grow() { + size_t newCapacity = _capacity * 2; + auto newData = std::make_unique(newCapacity); + + std::move(_data.get() + _front, _data.get() + _capacity, newData.get()); + std::move(_data.get(), _data.get() + _front, newData.get() + (_capacity - _front)); + + _back = _size; + _front = 0; + + _data.reset(newData.release()); + _capacity = newCapacity; + } + }; +} diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 96620c8f9..99b9dee70 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -54,6 +54,11 @@ struct BlockFuncsSet { bool onblockremoved : 1; }; +struct BlockFuncNamesCache { + std::string update; + std::string randomUpdate; +}; + struct CoordSystem { std::array axes; /// @brief Grid 3d position fix offset (for negative vectors) @@ -296,6 +301,8 @@ public: blockid_t surfaceReplacement = 0; std::set tags; + + BlockFuncNamesCache eventNames; } rt {}; Block(const std::string& name); diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 393f05f8a..5377df020 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -40,6 +40,8 @@ public: bool dirtyHeights : 1; } flags {}; + uint64_t lastRandomTickId = -1; + /// @brief Block inventories map where key is index of block in voxels array ChunkInventoriesMap inventories; /// @brief Blocks metadata heap @@ -81,4 +83,10 @@ public: glm::vec3((x + 1) * CHUNK_W, INFINITY, (z + 1) * CHUNK_D) ); } + + bool isBlockInside(int x, int z) const { + x -= this->x * CHUNK_W; + z -= this->z * CHUNK_D; + return x >= 0 && z >= 0 && x < CHUNK_W && z < CHUNK_D; + } };