From c11b2d0d709225d04f7244190b45239c9add5485 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 13 Dec 2025 17:13:07 +0300 Subject: [PATCH 01/10] temporary fix menu panel sizing --- src/graphics/ui/GUI.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 05c20604a..0923b0998 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -270,6 +270,7 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) { auto& page = menu->getCurrent(); if (page.panel) { menu->setSize(page.panel->getSize()); + page.panel->refresh(); if (auto panel = std::dynamic_pointer_cast(page.panel)) { panel->cropToContent(); } From ea8e1301eadcc1298668bcc5d7c6d9893f916e1d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 13 Dec 2025 17:16:00 +0300 Subject: [PATCH 02/10] fix shadeless blocks with soft lights disabled --- src/graphics/render/BlocksRenderer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index f2788df38..b6a45ffba 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -404,22 +404,22 @@ void BlocksRenderer::blockCube( } } else { if (isOpen(coord + Z, block, variant)) { - face(coord, X, Y, Z, texfaces[5], pickLight(coord + Z), lights); + face(coord, X, Y, Z, texfaces[5], lights ? pickLight(coord + Z) : glm::vec4(1,1,1,0), lights); } if (isOpen(coord - Z, block, variant)) { - face(coord, -X, Y, -Z, texfaces[4], pickLight(coord - Z), lights); + face(coord, -X, Y, -Z, texfaces[4], lights ? pickLight(coord - Z) : glm::vec4(1,1,1,0), lights); } if (isOpen(coord + Y, block, variant)) { - face(coord, X, -Z, Y, texfaces[3], pickLight(coord + Y), lights); + face(coord, X, -Z, Y, texfaces[3], lights ? pickLight(coord + Y) : glm::vec4(1,1,1,0), lights); } if (isOpen(coord - Y, block, variant)) { - face(coord, X, Z, -Y, texfaces[2], pickLight(coord - Y), lights); + face(coord, X, Z, -Y, texfaces[2], lights ? pickLight(coord - Y) : glm::vec4(1,1,1,0), lights); } if (isOpen(coord + X, block, variant)) { - face(coord, -Z, Y, X, texfaces[1], pickLight(coord + X), lights); + face(coord, -Z, Y, X, texfaces[1], lights ? pickLight(coord + X) : glm::vec4(1,1,1,0), lights); } if (isOpen(coord - X, block, variant)) { - face(coord, Z, Y, -X, texfaces[0], pickLight(coord - X), lights); + face(coord, Z, Y, -X, texfaces[0], lights ? pickLight(coord - X) : glm::vec4(1,1,1,0), lights); } } } From 55e4e6de02e606b756dba57cefe2fdb3574c389d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 15 Dec 2025 21:43:04 +0300 Subject: [PATCH 03/10] fix hover elements lifetime --- src/graphics/ui/GUI.cpp | 25 +++++++++++++++++-------- src/graphics/ui/GUI.hpp | 2 +- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 0923b0998..dc6dd6ac5 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -146,11 +146,18 @@ void GUI::actMouse(float delta, const CursorState& cursor) { } this->hover = hover; auto node = hover; + while (node) { - if (mouseOver.find(hover) != mouseOver.end()) { - break; + if (std::find_if( + mouseOver.begin(), + mouseOver.end(), + [&hover](const std::weak_ptr& weak) { + auto locked = weak.lock(); + return locked && locked == hover; + }) != mouseOver.end()) { + break; } - mouseOver.insert(node); + mouseOver.push_back(node); node->setMouseOver(true); auto parent = node->getParent(); if (parent) { @@ -159,12 +166,14 @@ void GUI::actMouse(float delta, const CursorState& cursor) { } for (auto it = mouseOver.begin(); it != mouseOver.end(); ) { - auto node = *it; - if (node->isInside(cursor.pos)) { - ++it; - continue; + auto node = it->lock(); + if (node) { + if (node->isInside(cursor.pos)) { + ++it; + continue; + } + node->setMouseOver(false); } - node->setMouseOver(false); it = mouseOver.erase(it); } diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index 8a12c3cd4..5d6140c27 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -81,7 +81,7 @@ namespace gui { std::unique_ptr uicamera; std::shared_ptr menu; std::queue postRunnables; - std::set> mouseOver; + std::vector> mouseOver; PageLoaderFunc pagesLoader; From c3c343ffdb323ccb716b3471740ef6aa7932d8ed Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 15 Dec 2025 22:05:27 +0300 Subject: [PATCH 04/10] update ContentUnitIndices --- src/content/Content.cpp | 6 +++--- src/content/Content.hpp | 35 +++++++++++++++++++------------ src/content/ContentReport.cpp | 4 ++-- src/content/ContentReport.hpp | 2 +- src/logic/scripting/scripting.cpp | 4 ++-- src/typedefs.hpp | 1 + src/voxels/GlobalChunks.cpp | 2 +- src/voxels/Pathfinding.hpp | 6 ++++-- src/world/files/WorldFiles.cpp | 4 ++-- 9 files changed, 38 insertions(+), 26 deletions(-) diff --git a/src/content/Content.cpp b/src/content/Content.cpp index c00934916..0c697fd1d 100644 --- a/src/content/Content.cpp +++ b/src/content/Content.cpp @@ -15,9 +15,9 @@ #include "ContentPack.hpp" ContentIndices::ContentIndices( - ContentUnitIndices blocks, - ContentUnitIndices items, - ContentUnitIndices entities + ContentUnitIndices blocks, + ContentUnitIndices items, + ContentUnitIndices entities ) : blocks(std::move(blocks)), items(std::move(items)), diff --git a/src/content/Content.hpp b/src/content/Content.hpp index 599d50fec..12dc77d2f 100644 --- a/src/content/Content.hpp +++ b/src/content/Content.hpp @@ -36,48 +36,57 @@ public: } }; -template +template class ContentUnitIndices { std::vector defs; public: ContentUnitIndices(std::vector defs) : defs(std::move(defs)) { } - inline const T* get(blockid_t id) const { + const T* get(IdType id) const { if (id >= defs.size()) { return nullptr; } return defs[id]; } - inline const T& require(blockid_t id) const { - return *defs.at(id); + const T& require(IdType id) const { + if (id >= defs.size()) { + invalidId(id); + } + return *defs[id]; } - inline size_t count() const { + size_t count() const { return defs.size(); } - inline const auto& getIterable() const { + const auto& getIterable() const { return defs; } - inline const T* const* getDefs() const { + const T* const* getDefs() const { return defs.data(); } +private: + void invalidId(IdType id) const { + throw std::runtime_error( + "invalid content unit id: " + std::to_string(id) + ); + } }; /// @brief Runtime defs cache: indices class ContentIndices { public: - ContentUnitIndices blocks; - ContentUnitIndices items; - ContentUnitIndices entities; + ContentUnitIndices blocks; + ContentUnitIndices items; + ContentUnitIndices entities; ContentIndices( - ContentUnitIndices blocks, - ContentUnitIndices items, - ContentUnitIndices entities + ContentUnitIndices blocks, + ContentUnitIndices items, + ContentUnitIndices entities ); }; diff --git a/src/content/ContentReport.cpp b/src/content/ContentReport.cpp index a8ecad402..2b04bbf37 100644 --- a/src/content/ContentReport.cpp +++ b/src/content/ContentReport.cpp @@ -22,9 +22,9 @@ ContentReport::ContentReport( regionsVersion(regionsVersion) { } -template +template static constexpr size_t get_entries_count( - const ContentUnitIndices& indices, const dv::value& list + const ContentUnitIndices& indices, const dv::value& list ) { return list != nullptr ? std::max(list.size(), indices.count()) : indices.count(); diff --git a/src/content/ContentReport.hpp b/src/content/ContentReport.hpp index 325e5f29e..9f9e4ac78 100644 --- a/src/content/ContentReport.hpp +++ b/src/content/ContentReport.hpp @@ -51,7 +51,7 @@ class ContentUnitLUT { public: ContentUnitLUT( size_t count, - const ContentUnitIndices& unitIndices, + const ContentUnitIndices& unitIndices, T missingValue, ContentType type ) diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 15c4e85e7..4af1a4287 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -253,9 +253,9 @@ void scripting::process_post_runnables() { } } -template +template static int push_properties_tables( - lua::State* L, const ContentUnitIndices& indices + lua::State* L, const ContentUnitIndices& indices ) { const auto units = indices.getDefs(); size_t size = indices.count(); diff --git a/src/typedefs.hpp b/src/typedefs.hpp index f075e9984..6984a943f 100644 --- a/src/typedefs.hpp +++ b/src/typedefs.hpp @@ -21,6 +21,7 @@ using ubyte = uint8_t; // content indices using itemid_t = uint32_t; using blockid_t = uint16_t; +using entitydefid_t = uint16_t; using entityid_t = uint64_t; using itemcount_t = uint32_t; diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 5e692ad69..032ae17e2 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -70,7 +70,7 @@ void GlobalChunks::erase(int x, int z) { static inline auto load_inventories( WorldRegions& regions, const Chunk& chunk, - const ContentUnitIndices& defs + const ContentUnitIndices& defs ) { auto invs = regions.fetchInventories(chunk.x, chunk.z); auto iterator = invs.begin(); diff --git a/src/voxels/Pathfinding.hpp b/src/voxels/Pathfinding.hpp index 9c172c7df..2e079076e 100644 --- a/src/voxels/Pathfinding.hpp +++ b/src/voxels/Pathfinding.hpp @@ -11,11 +11,13 @@ #include #include +#include "typedefs.hpp" + class Block; class Level; class GlobalChunks; -template +template class ContentUnitIndices; namespace voxels { @@ -82,7 +84,7 @@ namespace voxels { private: const Level& level; const GlobalChunks& chunks; - const ContentUnitIndices& blockDefs; + const ContentUnitIndices& blockDefs; std::unordered_map agents; int nextAgent = 1; diff --git a/src/world/files/WorldFiles.cpp b/src/world/files/WorldFiles.cpp index e4137f034..8e471772a 100644 --- a/src/world/files/WorldFiles.cpp +++ b/src/world/files/WorldFiles.cpp @@ -104,9 +104,9 @@ void WorldFiles::writePacks(const std::vector& packs) { io::write_string(packsFile, ss.str()); } -template +template static void write_indices( - const ContentUnitIndices& indices, dv::value& list + const ContentUnitIndices& indices, dv::value& list ) { for (auto unit : indices.getIterable()) { list.add(unit->name); From 4d53eb97c359b7453209af91eedfe56b03042a6e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 15 Dec 2025 23:54:45 +0300 Subject: [PATCH 05/10] fix on_block_tick triggered while paused --- res/scripts/stdlib.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index dcca0f281..a40a3e4db 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -523,8 +523,10 @@ function __process_post_runnables() fn_audio_reset_fetch_buffer() debug.pull_events() network.__process_events() - block.__process_register_events() - block.__perform_ticks(time.delta()) + if not hud or not hud.is_paused() then + block.__process_register_events() + block.__perform_ticks(time.delta()) + end end function time.post_runnable(runnable) From 77b4382577dc9cc3a21317190290e9019355ec9b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 15 Dec 2025 23:54:59 +0300 Subject: [PATCH 06/10] fix on_block_tick timer --- res/scripts/internal_events.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/scripts/internal_events.lua b/res/scripts/internal_events.lua index 7aee5450f..c71df5d61 100644 --- a/res/scripts/internal_events.lua +++ b/res/scripts/internal_events.lua @@ -9,6 +9,7 @@ block.__perform_ticks = function(delta) for id, entry in pairs(updating_blocks) do entry.timer = entry.timer + delta local steps = math.floor(entry.timer / entry.delta * #entry / 3) + steps = math.min(steps, #entry / 3) if steps == 0 then goto continue end @@ -28,6 +29,7 @@ block.__perform_ticks = function(delta) for id, queue in pairs(present_queues) do queue.timer = queue.timer + delta local steps = math.floor(queue.timer / queue.delta * #queue / 3) + steps = math.min(steps, #queue / 3) if steps == 0 then goto continue end From 180dd5051b5a7358200ae705fd20b632b0d96f72 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Dec 2025 00:17:51 +0300 Subject: [PATCH 07/10] fix fatal error on invalid item id in inventory --- src/items/Inventory.cpp | 19 +++++++++++++++++++ src/items/Inventory.hpp | 1 + src/objects/Players.cpp | 8 ++++++-- src/voxels/GlobalChunks.cpp | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/items/Inventory.cpp b/src/items/Inventory.cpp index 5978f2834..2946d20ab 100644 --- a/src/items/Inventory.cpp +++ b/src/items/Inventory.cpp @@ -1,6 +1,9 @@ #include "Inventory.hpp" #include "content/ContentReport.hpp" +#include "debug/Logger.hpp" + +static debug::Logger logger("inventory"); Inventory::Inventory(int64_t id, size_t size) : id(id), slots(size) { } @@ -104,6 +107,22 @@ dv::value Inventory::serialize() const { return map; } +void Inventory::check(const ContentIndices& indices) { + for (size_t i = 0; i < slots.size(); i++) { + auto& slot = slots[i]; + if (indices.items.get(slot.getItemId()) == nullptr) { +#ifdef NDEBUG + logger.error() << "invalid item id " << slot.getItemId() + << " found in inventory #" << id << " slot #" << i + << "; will reset"; + slot.clear(); +#else + abort(); +#endif + } + } +} + void Inventory::convert(const ContentReport* report) { for (auto& slot : slots) { itemid_t id = slot.getItemId(); diff --git a/src/items/Inventory.hpp b/src/items/Inventory.hpp index 1c66fdece..80fbfecfb 100644 --- a/src/items/Inventory.hpp +++ b/src/items/Inventory.hpp @@ -39,6 +39,7 @@ public: dv::value serialize() const override; + void check(const ContentIndices& indices); void convert(const ContentReport* report); static void convert(dv::value& data, const ContentReport* report); diff --git a/src/objects/Players.cpp b/src/objects/Players.cpp index 5fc59f409..6bce34abd 100644 --- a/src/objects/Players.cpp +++ b/src/objects/Players.cpp @@ -4,6 +4,7 @@ #include #include "Player.hpp" +#include "content/Content.hpp" #include "items/Inventories.hpp" #include "world/Level.hpp" #include "world/World.hpp" @@ -87,7 +88,9 @@ Player* Players::create(int64_t id) { auto player = playerPtr.get(); add(std::move(playerPtr)); - level.inventories->store(player->getInventory()); + auto inventory = player->getInventory(); + inventory->check(*level.content.getIndices()); + level.inventories->store(std::move(inventory)); return player; } @@ -147,6 +150,7 @@ void Players::deserialize(const dv::value& src) { if (inventory->getId() == 0) { inventory->setId(level.getWorld()->getNextInventoryId()); } - level.inventories->store(player->getInventory()); + inventory->check(*level.content.getIndices()); + level.inventories->store(inventory); } } diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 032ae17e2..75aa380ff 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -128,6 +128,7 @@ std::shared_ptr GlobalChunks::create(int x, int z, bool lighting) { chunk->flags.loaded = true; for (auto& entry : chunk->inventories) { + entry.second->check(indices); level.inventories->store(entry.second); } } From c394df4e07641b9c18dc8a4ee1bcd1c519a82f66 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Dec 2025 00:36:09 +0300 Subject: [PATCH 08/10] fix inventory.set --- src/logic/scripting/lua/libs/libinventory.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/logic/scripting/lua/libs/libinventory.cpp b/src/logic/scripting/lua/libs/libinventory.cpp index fda9d4f02..7f43ae88b 100644 --- a/src/logic/scripting/lua/libs/libinventory.cpp +++ b/src/logic/scripting/lua/libs/libinventory.cpp @@ -73,6 +73,7 @@ static int l_set(lua::State* L, ItemStack& item) { if (!data.isObject() && data != nullptr) { throw std::runtime_error("invalid data argument type (table expected)"); } + validate_itemid(itemid); item.set(ItemStack(itemid, count, std::move(data))); return 0; } From 923ca2b89e0fa1db0dc130bc83af3fed1327fa0a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Dec 2025 00:39:30 +0300 Subject: [PATCH 09/10] format Inventories.hpp --- src/items/Inventories.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/items/Inventories.hpp b/src/items/Inventories.hpp index 1af4ec8af..98e956839 100644 --- a/src/items/Inventories.hpp +++ b/src/items/Inventories.hpp @@ -11,7 +11,7 @@ class Level; using inventories_map = std::unordered_map>; -/* Inventories runtime storage */ +/// @brief Inventories runtime storage class Inventories { Level& level; inventories_map map; @@ -20,21 +20,22 @@ public: Inventories(Level& level); ~Inventories(); - /* Create new inventory with new id */ + /// @brief Create new inventory with new id std::shared_ptr create(size_t size); - /* Create runtime-only inventory (has negative id) */ + /// @brief Create runtime-only inventory (has negative id) std::shared_ptr createVirtual(size_t size); - /* Store inventory */ + /// @brief Store inventory void store(const std::shared_ptr& inv); - /* Remove inventory from map */ + /// @brief Remove inventory from map void remove(int64_t id); - /* Get inventory by id (works with both real and virtual)*/ + /// @brief Get inventory by id (works with both real and virtual) std::shared_ptr get(int64_t id); + /// @brief Create inventory non-virtual copy std::shared_ptr clone(int64_t id); const inventories_map& getMap() const; From d708e8d21c41361ea41a71febee4fe8961217cae Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 16 Dec 2025 00:45:15 +0300 Subject: [PATCH 10/10] cleanup --- src/items/Inventories.cpp | 10 ++++++---- src/items/Inventories.hpp | 2 +- src/objects/Players.cpp | 5 +---- src/voxels/GlobalChunks.cpp | 1 - 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/items/Inventories.cpp b/src/items/Inventories.cpp index 4d2baa36d..249f5d66d 100644 --- a/src/items/Inventories.cpp +++ b/src/items/Inventories.cpp @@ -1,9 +1,10 @@ #include "Inventories.hpp" -#include - #include "world/Level.hpp" #include "world/World.hpp" +#include "content/Content.hpp" + +#include Inventories::Inventories(Level& level) : level(level) { } @@ -32,8 +33,9 @@ std::shared_ptr Inventories::createVirtual(size_t size) { }); } -void Inventories::store(const std::shared_ptr& inv) { - map[inv->getId()] = inv; +void Inventories::store(const std::shared_ptr& inventory) { + inventory->check(*level.content.getIndices()); + map[inventory->getId()] = inventory; } void Inventories::remove(int64_t id) { diff --git a/src/items/Inventories.hpp b/src/items/Inventories.hpp index 98e956839..6ce500256 100644 --- a/src/items/Inventories.hpp +++ b/src/items/Inventories.hpp @@ -26,7 +26,7 @@ public: /// @brief Create runtime-only inventory (has negative id) std::shared_ptr createVirtual(size_t size); - /// @brief Store inventory + /// @brief Check and add inventory to the storage void store(const std::shared_ptr& inv); /// @brief Remove inventory from map diff --git a/src/objects/Players.cpp b/src/objects/Players.cpp index 6bce34abd..a90d6d07d 100644 --- a/src/objects/Players.cpp +++ b/src/objects/Players.cpp @@ -88,9 +88,7 @@ Player* Players::create(int64_t id) { auto player = playerPtr.get(); add(std::move(playerPtr)); - auto inventory = player->getInventory(); - inventory->check(*level.content.getIndices()); - level.inventories->store(std::move(inventory)); + level.inventories->store(player->getInventory()); return player; } @@ -150,7 +148,6 @@ void Players::deserialize(const dv::value& src) { if (inventory->getId() == 0) { inventory->setId(level.getWorld()->getNextInventoryId()); } - inventory->check(*level.content.getIndices()); level.inventories->store(inventory); } } diff --git a/src/voxels/GlobalChunks.cpp b/src/voxels/GlobalChunks.cpp index 75aa380ff..032ae17e2 100644 --- a/src/voxels/GlobalChunks.cpp +++ b/src/voxels/GlobalChunks.cpp @@ -128,7 +128,6 @@ std::shared_ptr GlobalChunks::create(int x, int z, bool lighting) { chunk->flags.loaded = true; for (auto& entry : chunk->inventories) { - entry.second->check(indices); level.inventories->store(entry.second); } }