diff --git a/src/logic/BlocksController.cpp b/src/logic/BlocksController.cpp index 9ddf12b82..27ab240a1 100644 --- a/src/logic/BlocksController.cpp +++ b/src/logic/BlocksController.cpp @@ -118,6 +118,37 @@ void BlocksController::onBlocksTick(int tickid, int parts) { scripting::on_blocks_tick(def, tickRate / interval); } } + static int gtick = 0; + if (tickid == 0) { + gtick++; + } + const int w = chunks->w; + const int d = chunks->d; + for (uint z = padding; z < d-padding; z++){ + for (uint x = padding; x < w-padding; x++){ + int index = z * w + x; + if ((index + tickid) % parts != 0) + continue; + auto& chunk = chunks->chunks[index]; + if (chunk == nullptr || !chunk->flags.lighted) + continue; + auto updatingBlocks = chunk->updatingBlocks; + for (uint block_index : updatingBlocks) { + auto def = indices->getBlockDef(chunk->voxels[block_index].id); + if (((gtick + tickid) / parts) % def->tickInterval != 0) + continue; + int lx = block_index % CHUNK_W; + int lz = (block_index/CHUNK_W) % CHUNK_D; + int ly = block_index/CHUNK_W/CHUNK_D; + scripting::on_block_tick( + def, + lx + chunk->x * CHUNK_W, + ly, + lz + chunk->z * CHUNK_D + ); + } + } + } } void BlocksController::randomTick(int tickid, int parts) { diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 8005f7ce9..f479e3af1 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -158,6 +158,14 @@ void scripting::on_blocks_tick(const Block* block, int tps) { }); } +void scripting::on_block_tick(const Block* block, int x, int y, int z) { + std::string name = block->name + ".blocktick"; + state->emit_event(name, [x, y, z] (lua::LuaState* state) { + state->pushivec3(x, y, z); + return 3; + }); +} + void scripting::update_block(const Block* block, int x, int y, int z) { std::string name = block->name + ".update"; state->emit_event(name, [x, y, z] (lua::LuaState* state) { @@ -290,6 +298,7 @@ void scripting::load_block_script(scriptenv senv, std::string prefix, fs::path f funcsset.onbroken = register_event(env, "on_broken", prefix+".broken"); funcsset.onplaced = register_event(env, "on_placed", prefix+".placed"); funcsset.oninteract = register_event(env, "on_interact", prefix+".interact"); + funcsset.onblocktick = register_event(env, "on_block_tick", prefix+".blocktick"); funcsset.onblockstick = register_event(env, "on_blocks_tick", prefix+".blockstick"); } diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index d3c37f839..9a9016c7d 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -54,6 +54,7 @@ namespace scripting { void on_world_save(); void on_world_quit(); void on_blocks_tick(const Block* block, int tps); + void on_block_tick(const Block* block, int x, int y, int z); void update_block(const Block* block, int x, int y, int z); void random_update_block(const Block* block, int x, int y, int z); void on_block_placed(Player* player, const Block* block, int x, int y, int z); diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 4628dd0e7..ea87c9b30 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -31,6 +31,7 @@ struct block_funcs_set { bool onbroken: 1; bool oninteract: 1; bool randupdate: 1; + bool onblocktick: 1; bool onblockstick: 1; }; diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index 18dabec28..0cdad515a 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -1,6 +1,7 @@ #include "Chunk.hpp" #include "voxel.hpp" +#include "Block.hpp" #include "../items/Inventory.hpp" #include "../content/ContentLUT.hpp" @@ -117,6 +118,16 @@ bool Chunk::decode(const ubyte* data) { return true; } +void Chunk::onLoad(const Content* content) { + auto contentIds = content->getIndices(); + for (uint i = 0; i < CHUNK_VOL; i++) { + auto def = contentIds->getBlockDef(voxels[i].id); + if (def->rt.funcsset.onblocktick) { + updatingBlocks.push_front(i); + } + } +} + void Chunk::convert(ubyte* data, const ContentLUT* lut) { for (uint i = 0; i < CHUNK_VOL; i++) { // see encode method to understand what the hell is going on here diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 535b61258..dce2974aa 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include "../constants.hpp" @@ -14,6 +15,7 @@ inline constexpr int CHUNK_DATA_LEN = CHUNK_VOL*4; class Lightmap; class ContentLUT; class Inventory; +class Content; using chunk_inventories_map = std::unordered_map>; @@ -31,9 +33,10 @@ public: bool unsaved: 1; bool loadedLights: 1; } flags {}; - - /* Block inventories map where key is index of block in voxels array */ + /// @brief Block inventories map where key is index of block in voxels array chunk_inventories_map inventories; + /// @brief Interval-updating blocks list + std::forward_list updatingBlocks; Chunk(int x, int z); @@ -44,14 +47,14 @@ public: // unused std::unique_ptr clone() const; - /* Creates new block inventory given size - @return inventory id or 0 if block does not exists */ + /// @brief Creates new block inventory given size + /// @return inventory id or 0 if block does not exists void addBlockInventory(std::shared_ptr inventory, uint x, uint y, uint z); void removeBlockInventory(uint x, uint y, uint z); void setBlockInventories(chunk_inventories_map map); - /* @return inventory bound to the given block or nullptr */ + /// @return inventory bound to the given block or nullptr std::shared_ptr getBlockInventory(uint x, uint y, uint z) const; inline void setModifiedAndUnsaved() { @@ -61,12 +64,12 @@ public: std::unique_ptr encode() const; - /** - * @return true if all is fine - **/ + /// @return true if all is fine bool decode(const ubyte* data); + void onLoad(const Content* content); + static void convert(ubyte* data, const ContentLUT* lut); }; -#endif /* VOXELS_CHUNK_HPP_ */ +#endif // VOXELS_CHUNK_HPP_ diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index b9a63e9e5..8d1114411 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -119,25 +119,6 @@ ubyte Chunks::getLight(int32_t x, int32_t y, int32_t z, int channel){ return chunk->lightmap.get(lx, ly, lz, channel); } -light_t Chunks::getLight(int32_t x, int32_t y, int32_t z){ - x -= ox * CHUNK_W; - z -= oz * CHUNK_D; - int cx = floordiv(x, CHUNK_W); - int cy = floordiv(y, CHUNK_H); - int cz = floordiv(z, CHUNK_D); - if (cx < 0 || cy < 0 || cz < 0 || cx >= int(w) || cy >= 1 || cz >= int(d)) { - return 0; - } - const auto& chunk = chunks[(cy * d + cz) * w + cx]; - if (chunk == nullptr) { - return 0; - } - int lx = x - cx * CHUNK_W; - int ly = y - cy * CHUNK_H; - int lz = z - cz * CHUNK_D; - return chunk->lightmap.get(lx,ly,lz); -} - Chunk* Chunks::getChunkByVoxel(int32_t x, int32_t y, int32_t z) { if (y < 0 || y >= CHUNK_H) return nullptr; @@ -159,28 +140,45 @@ Chunk* Chunks::getChunk(int x, int z){ } void Chunks::set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state) { - if (y < 0 || y >= CHUNK_H) + if (y < 0 || y >= CHUNK_H) { return; + } x -= ox * CHUNK_W; z -= oz * CHUNK_D; int cx = floordiv(x, CHUNK_W); int cz = floordiv(z, CHUNK_D); - if (cx < 0 || cz < 0 || cx >= int(w) || cz >= int(d)) + if (cx < 0 || cz < 0 || cx >= int(w) || cz >= int(d)) { return; + } Chunk* chunk = chunks[cz * w + cx].get(); if (chunk == nullptr) return; int lx = x - cx * CHUNK_W; int lz = z - cz * CHUNK_D; + int index = vox_index(lx, y, lz); - voxel& vox = chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx]; + voxel& vox = chunk->voxels[index]; + + // finalizing previous block auto def = contentIds->getBlockDef(vox.id); - if (def->inventorySize == 0) + if (def->inventorySize == 0) { chunk->removeBlockInventory(lx, y, lz); + } + if (def->rt.funcsset.onblocktick) { + chunk->updatingBlocks.remove(index); + } + + // initializing new block vox.id = id; vox.state = state; chunk->setModifiedAndUnsaved(); + auto new_def = contentIds->getBlockDef(id); + if (new_def->rt.funcsset.onblocktick) { + chunk->updatingBlocks.push_front(index); + } + + // updating chunks if (y < chunk->bottom) chunk->bottom = y; else if (y + 1 > chunk->top) chunk->top = y + 1; else if (id == 0) chunk->updateHeights(); @@ -475,11 +473,6 @@ void Chunks::resize(uint32_t newW, uint32_t newD) { chunksSecond = std::move(newChunksSecond); } -void Chunks::_setOffset(int32_t x, int32_t z) { - ox = x; - oz = z; -} - bool Chunks::putChunk(std::shared_ptr chunk) { int x = chunk->x; int z = chunk->z; diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index 7dd4312dc..dda3060c3 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -41,7 +41,6 @@ public: Chunk* getChunk(int32_t x, int32_t z); Chunk* getChunkByVoxel(int32_t x, int32_t y, int32_t z); voxel* get(int32_t x, int32_t y, int32_t z); - light_t getLight(int32_t x, int32_t y, int32_t z); ubyte getLight(int32_t x, int32_t y, int32_t z, int channel); void set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state); @@ -61,9 +60,6 @@ public: bool isReplaceableBlock(int32_t x, int32_t y, int32_t z); bool isObstacleBlock(int32_t x, int32_t y, int32_t z); - // does not move chunks inside - void _setOffset(int32_t x, int32_t z); - void setCenter(int32_t x, int32_t z); void translate(int32_t x, int32_t z); void resize(uint32_t newW, uint32_t newD); diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index 8a9c97b44..d131089a2 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -59,6 +59,7 @@ std::shared_ptr ChunksStorage::create(int x, int z) { auto data = regions.getChunk(chunk->x, chunk->z); if (data) { chunk->decode(data.get()); + chunk->onLoad(level->content); auto invs = regions.fetchInventories(chunk->x, chunk->z); chunk->setBlockInventories(std::move(invs)); chunk->flags.loaded = true;