diff --git a/res/scripts/internal_events.lua b/res/scripts/internal_events.lua index 4f72e1b1..ec8e8dd6 100644 --- a/res/scripts/internal_events.lua +++ b/res/scripts/internal_events.lua @@ -1,8 +1,9 @@ local updating_blocks = {} local present_queues = {} -local TYPE_REGISTER = 1 -local TYPE_UPDATING = 2 -local TYPE_PRESENT = 4 +local REGISTER_BIT = 0x1 +local UPDATING_BIT = 0x2 +local PRESENT_BIT = 0x4 +local REMOVED_BIT = 0x8 block.__perform_ticks = function(delta) for id, entry in pairs(updating_blocks) do @@ -25,7 +26,7 @@ block.__perform_ticks = function(delta) end for id, queue in pairs(present_queues) do queue.timer = queue.timer + delta - local steps = math.floor(queue.timer / queue.delta * #queue / 4) + local steps = math.floor(queue.timer / queue.delta * #queue / 3) if steps == 0 then goto continue end @@ -33,16 +34,15 @@ block.__perform_ticks = function(delta) local event = queue.event local update_list = updating_blocks[id] for i=1, steps do - local index = #queue - 3 + local index = #queue - 2 if index <= 0 then break end - local is_register = queue[index] - local x = queue[index + 1] - local y = queue[index + 2] - local z = queue[index + 3] + local x = queue[index] + local y = queue[index + 1] + local z = queue[index + 2] - for j=1,4 do + for j=1,3 do table.remove(queue, index) end events.emit(event, x, y, z) @@ -65,6 +65,10 @@ block.__process_register_events = function() if not register_events then return end + + local emit_event = events.emit + local removed_events = {} + for i=1, #register_events, 4 do local header = register_events[i] local event_bits = bit.band(header, 0xFFFF) @@ -73,11 +77,21 @@ block.__process_register_events = function() local y = register_events[i + 2] local z = register_events[i + 3] - local is_register = bit.band(event_bits, TYPE_REGISTER) ~= 0 - local is_updating = bit.band(event_bits, TYPE_UPDATING) ~= 0 - local is_present = bit.band(event_bits, TYPE_PRESENT) ~= 0 + local is_register = bit.band(event_bits, REGISTER_BIT) ~= 0 + local is_updating = bit.band(event_bits, UPDATING_BIT) ~= 0 + local is_present = bit.band(event_bits, PRESENT_BIT) ~= 0 + local is_removed = bit.band(event_bits, REMOVED_BIT) ~= 0 local list = updating_blocks[id] + if not is_register and is_removed then + local rm_event = removed_events[id] + if not rm_event then + rm_event = block.name(id) .. ".blockremoved" + removed_events[id] = rm_event + end + emit_event(rm_event, x, y, z) + end + if not list and is_register and is_updating then list = {} list.event = block.name(id) .. ".blocktick" @@ -100,7 +114,6 @@ block.__process_register_events = function() present_queue.updating = is_updating present_queues[id] = present_queue end - table.insert(present_queue, is_register) table.insert(present_queue, x) table.insert(present_queue, y) table.insert(present_queue, z) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index a9199132..8624a844 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -357,6 +357,10 @@ function __vc_on_world_tick(tps) time.schedules.world:tick(1.0 / tps) end +function __vc_process_before_quit() + block.__process_register_events() +end + function __vc_on_world_save() local rule_values = {} for name, rule in pairs(rules.rules) do diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index eab517da..10348734 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -109,6 +109,7 @@ LevelScreen::~LevelScreen() { scripting::on_frontend_close(); // unblock all bindings input.getBindings().enableAll(); + playerController->getPlayer()->chunks->saveAndClear(); controller->onWorldQuit(); engine.getPaths().setCurrentWorldFolder(""); } @@ -278,5 +279,6 @@ void LevelScreen::onEngineShutdown() { if (hud->isInventoryOpen()) { hud->closeInventory(); } + controller->processBeforeQuit(); controller->saveWorld(); } diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index d6820fa1..db956e15 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -366,7 +366,9 @@ void EngineController::reconfigPacks( ); } } else { - auto world = controller->getLevel()->getWorld(); + auto level = controller->getLevel(); + auto world = level->getWorld(); + controller->processBeforeQuit(); controller->saveWorld(); auto names = PacksManager::getNames(world->getPacks()); diff --git a/src/logic/LevelController.cpp b/src/logic/LevelController.cpp index 95d91014..11717d9a 100644 --- a/src/logic/LevelController.cpp +++ b/src/logic/LevelController.cpp @@ -27,7 +27,8 @@ LevelController::LevelController( : settings(engine->getSettings()), level(std::move(levelPtr)), chunks(std::make_unique(*level)), - playerTickClock(20, 3) { + playerTickClock(20, 3), + localPlayer(clientPlayer) { level->events->listen(LevelEventType::CHUNK_PRESENT, [](auto, Chunk* chunk) { scripting::on_chunk_present(*chunk, chunk->flags.loaded); @@ -121,6 +122,13 @@ void LevelController::update(float delta, bool pause) { level->entities->clean(); } +void LevelController::processBeforeQuit() { + if (localPlayer) { + localPlayer->chunks->saveAndClear(); + } + scripting::process_before_quit(); +} + void LevelController::saveWorld() { auto world = level->getWorld(); if (world->isNameless()) { diff --git a/src/logic/LevelController.hpp b/src/logic/LevelController.hpp index 7ae0fc5b..c7b98623 100644 --- a/src/logic/LevelController.hpp +++ b/src/logic/LevelController.hpp @@ -20,6 +20,7 @@ class LevelController { std::unique_ptr chunks; util::Clock playerTickClock; + Player* localPlayer; public: LevelController(Engine* engine, std::unique_ptr level, Player* clientPlayer); @@ -27,6 +28,7 @@ public: /// @param pause is world and player simulation paused void update(float delta, bool pause); + void processBeforeQuit(); void saveWorld(); void onWorldQuit(); diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 8f8a7bc8..8454e5c3 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -119,6 +119,7 @@ static int l_close_world(lua::State* L) { if (controller == nullptr) { throw std::runtime_error("no world open"); } + controller->processBeforeQuit(); bool save_world = lua::toboolean(L, 1); if (save_world) { controller->saveWorld(); diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index fb2e997b..3a68917d 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -341,6 +341,13 @@ void scripting::on_world_save() { } } +void scripting::process_before_quit() { + auto L = lua::get_main_state(); + if (lua::getglobal(L, "__vc_process_before_quit")) { + lua::call_nothrow(L, 0, 0); + } +} + void scripting::on_world_quit() { auto L = lua::get_main_state(); for (auto& pack : content_control->getAllContentPacks()) { @@ -677,6 +684,8 @@ void scripting::load_content_script( register_event(env, "on_blocks_tick", prefix + ".blockstick"); funcsset.onblockpresent = register_event(env, "on_block_present", prefix + ".blockpresent"); + funcsset.onblockremoved = + register_event(env, "on_block_removed", prefix + ".blockremoved"); } void scripting::load_content_script( diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index a096e9cc..966450c6 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -81,6 +81,7 @@ namespace scripting { void on_world_load(LevelController* controller); void on_world_tick(int tps); void on_world_save(); + void process_before_quit(); void on_world_quit(); void cleanup(const std::vector& nonReset); void on_blocks_tick(const Block& block, int tps); diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 9d091893..29eda249 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -51,6 +51,7 @@ struct BlockFuncsSet { bool onblocktick : 1; bool onblockstick : 1; bool onblockpresent : 1; + bool onblockremoved : 1; }; struct CoordSystem { diff --git a/src/voxels/blocks_agent.cpp b/src/voxels/blocks_agent.cpp index 338c3cb8..7041f67a 100644 --- a/src/voxels/blocks_agent.cpp +++ b/src/voxels/blocks_agent.cpp @@ -19,6 +19,7 @@ static uint8_t get_events_bits(const Block& def) { auto funcsset = def.rt.funcsset; bits |= BlockRegisterEvent::UPDATING_BIT * funcsset.onblocktick; bits |= BlockRegisterEvent::PRESENT_EVENT_BIT * funcsset.onblockpresent; + bits |= BlockRegisterEvent::REMOVED_EVENT_BIT * funcsset.onblockremoved; return bits; } diff --git a/src/voxels/blocks_agent.hpp b/src/voxels/blocks_agent.hpp index 93a3c1ad..7c0223cb 100644 --- a/src/voxels/blocks_agent.hpp +++ b/src/voxels/blocks_agent.hpp @@ -28,6 +28,7 @@ struct BlockRegisterEvent { static inline constexpr uint8_t REGISTER_BIT = 0x1; static inline constexpr uint8_t UPDATING_BIT = 0x2; static inline constexpr uint8_t PRESENT_EVENT_BIT = 0x4; + static inline constexpr uint8_t REMOVED_EVENT_BIT = 0x8; uint8_t bits; blockid_t id; glm::ivec3 coord;