From 89485dc592f138cd244d61ac6871d745c3e82e9d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Thu, 22 Jan 2026 22:27:30 +0300 Subject: [PATCH 01/20] fix extra faces when dense mode is off --- src/graphics/render/BlocksRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 36f12a196..b96890edb 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -750,7 +750,7 @@ void BlocksRenderer::build(const Chunk* chunk, const VoxelsVolume& volume) { size_t endIndex = indexCount; denseRender = true; - densePass = true; + densePass = settings.graphics.denseRender.get(); render(voxels, beginEnds); denseIndexCount = indexCount; From d5f8fed63315d64327ea1bb5e83b4dca4cf9f5d5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 23 Jan 2026 12:48:54 +0300 Subject: [PATCH 02/20] add AssetsManagement --- src/engine/AssetsManagement.cpp | 53 +++++++++++++++++++++++++++++++++ src/engine/AssetsManagement.hpp | 22 ++++++++++++++ src/engine/Engine.cpp | 34 ++++----------------- src/engine/Engine.hpp | 3 +- 4 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 src/engine/AssetsManagement.cpp create mode 100644 src/engine/AssetsManagement.hpp diff --git a/src/engine/AssetsManagement.cpp b/src/engine/AssetsManagement.cpp new file mode 100644 index 000000000..2135f568f --- /dev/null +++ b/src/engine/AssetsManagement.cpp @@ -0,0 +1,53 @@ +#include "AssetsManagement.hpp" + +#include "assets/Assets.hpp" +#include "assets/AssetsLoader.hpp" +#include "engine/Engine.hpp" +#include "debug/Logger.hpp" +#include "content/Content.hpp" +#include "graphics/core/Shader.hpp" +#include "EnginePaths.hpp" +#include "coders/GLSLExtension.hpp" +#include "graphics/render/ModelsGenerator.hpp" +#include "graphics/ui/GUI.hpp" + +static debug::Logger logger("assets-management"); + +AssetsManagement::AssetsManagement(Engine& engine) : engine(engine) {} + +const Assets* AssetsManagement::getStorage() const { + return assets.get(); +} + +Assets* AssetsManagement::getStorage() { + return assets.get(); +} + +void AssetsManagement::loadAssets(Content* content) { + const auto& paths = engine.getPaths(); + logger.info() << "loading assets"; + Shader::preprocessor->setPaths(&paths.resPaths); + + auto new_assets = std::make_unique(); + AssetsLoader loader(engine, *new_assets, paths.resPaths); + AssetsLoader::addDefaults(loader, content); + + // no need + // correct log messages order is more useful + // todo: before setting to true, check if GLSLExtension thread safe + bool threading = false; // look at three upper lines + if (threading) { + auto task = loader.startTask([=](){}); + task->waitForEnd(); + } else { + while (loader.hasNext()) { + loader.loadNext(); + } + } + assets = std::move(new_assets); + if (content) { + ModelsGenerator::prepare(*content, *assets); + } + assets->setup(); + engine.getGUI().onAssetsLoad(assets.get()); +} diff --git a/src/engine/AssetsManagement.hpp b/src/engine/AssetsManagement.hpp new file mode 100644 index 000000000..5b06e6d8c --- /dev/null +++ b/src/engine/AssetsManagement.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +class Assets; +class AssetsLoader; +class Engine; +class Content; + +class AssetsManagement { +public: + AssetsManagement(Engine& engine); + + void loadAssets(Content* content); + + Assets* getStorage(); + const Assets* getStorage() const; +private: + Engine& engine; + std::unique_ptr assets; + std::unique_ptr backgroundLoader; +}; diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 5a63991bb..6cc976799 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -34,6 +34,7 @@ #include "window/input.hpp" #include "window/Window.hpp" #include "world/Level.hpp" +#include "AssetsManagement.hpp" #include "Mainloop.hpp" #include "ServerMainloop.hpp" #include "WindowControl.hpp" @@ -84,6 +85,7 @@ void Engine::onContentLoad() { } void Engine::initializeClient() { + assets = std::make_unique(*this); windowControl = std::make_unique(*this); auto [window, input] = windowControl->initialize(); @@ -305,7 +307,7 @@ void Engine::renderFrame() { screen->draw(time.getDelta()); DrawContext ctx(nullptr, *window, nullptr); - gui->draw(ctx, *assets); + gui->draw(ctx, *assets->getStorage()); } void Engine::saveSettings() { @@ -363,33 +365,7 @@ void Engine::setLevelConsumer(OnWorldOpen levelConsumer) { } void Engine::loadAssets() { - logger.info() << "loading assets"; - Shader::preprocessor->setPaths(&paths->resPaths); - - auto content = this->content->get(); - - auto new_assets = std::make_unique(); - AssetsLoader loader(*this, *new_assets, paths->resPaths); - AssetsLoader::addDefaults(loader, content); - - // no need - // correct log messages order is more useful - // todo: before setting to true, check if GLSLExtension thread safe - bool threading = false; // look at three upper lines - if (threading) { - auto task = loader.startTask([=](){}); - task->waitForEnd(); - } else { - while (loader.hasNext()) { - loader.loadNext(); - } - } - assets = std::move(new_assets); - if (content) { - ModelsGenerator::prepare(*content, *assets); - } - assets->setup(); - gui->onAssetsLoad(assets.get()); + assets->loadAssets(content->get()); } void Engine::loadProject() { @@ -442,7 +418,7 @@ EngineSettings& Engine::getSettings() { } Assets* Engine::getAssets() { - return assets.get(); + return assets->getStorage(); } EnginePaths& Engine::getPaths() { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 06246f8c6..7ecff05c6 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -10,6 +10,7 @@ #include class Assets; +class AssetsManagement; class ContentControl; class EngineController; class EnginePaths; @@ -52,7 +53,7 @@ class Engine : public util::ObjectsKeeper { std::unique_ptr paths; std::unique_ptr project; std::unique_ptr settingsHandler; - std::unique_ptr assets; + std::unique_ptr assets; std::shared_ptr screen; std::unique_ptr content; std::unique_ptr controller; From 245e040a1c068ad1673d56b4256823cfb5dcd0ed Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 23 Jan 2026 22:39:20 +0300 Subject: [PATCH 03/20] add jobsSource to ThreadPool --- src/util/ThreadPool.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/util/ThreadPool.hpp b/src/util/ThreadPool.hpp index 98ebcce5b..e1f7f24d7 100644 --- a/src/util/ThreadPool.hpp +++ b/src/util/ThreadPool.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ namespace util { std::atomic busyWorkers = 0; std::atomic jobsDone = 0; std::atomic working = true; + supplier> jobsSource = nullptr; bool failed = false; bool standaloneResults = true; bool stopOnFail = true; @@ -151,6 +153,10 @@ namespace util { return working; } + void setJobsSource(supplier>&& source) { + jobsSource = std::move(source); + } + void terminate() override { if (!working) { return; @@ -221,6 +227,22 @@ namespace util { } } } + if (jobsSource) { + bool jobsAdded = false; + std::lock_guard jobsLock(jobsMutex); + while (true) { + auto job = jobsSource(); + if (job.has_value()) { + jobs.push(std::move(job.value())); + jobsAdded = true; + } else { + break; + } + } + if (jobsAdded) { + jobsMutexCondition.notify_one(); + } + } if (failed) { throw std::runtime_error("some job failed"); } From 0cf7d9b1ed6d02e2e7a3ec8c035eb055ebb2b77c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 23 Jan 2026 22:40:57 +0300 Subject: [PATCH 04/20] add background assets loader --- src/assets/AssetsLoader.cpp | 30 +++++++++------ src/assets/AssetsLoader.hpp | 3 +- src/engine/AssetsManagement.cpp | 47 +++++++++++++++++++---- src/engine/AssetsManagement.hpp | 13 ++++++- src/engine/Engine.cpp | 40 ++++++++++--------- src/engine/Engine.hpp | 3 ++ src/engine/EnginePaths.cpp | 3 ++ src/logic/scripting/lua/libs/libpack.cpp | 4 +- src/logic/scripting/lua/libs/libworld.cpp | 7 ++-- 9 files changed, 104 insertions(+), 46 deletions(-) diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index cf64a9c8e..ca9ee93df 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -319,28 +319,27 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { } bool AssetsLoader::loadExternalTexture( - Assets* assets, + AssetsLoader& loader, const std::string& name, const std::vector& alternatives ) { - if (assets->get(name) != nullptr) { + if (loader.getAssets().get(name) != nullptr) { return true; } for (auto& path : alternatives) { - if (io::exists(path)) { - try { - auto image = imageio::read(path); - assets->store(Texture::from(image.get()), name); - return true; - } catch (const std::exception& err) { - logger.error() << "error while loading external " - << path.string() << ": " << err.what(); - } + logger.info() << (path.string() + ".png"); + if (io::exists(path.string() + ".png")) { + loader.add(AssetType::TEXTURE, path.string(), name, nullptr); + return true; // TODO: fallbacks support } } return false; } +Assets& AssetsLoader::getAssets() { + return assets; +} + Engine& AssetsLoader::getEngine() { return engine; } @@ -376,6 +375,15 @@ std::shared_ptr AssetsLoader::startTask(runnable onDone) { [this](const assetload::postfunc& func) { func(&assets); } ); pool->setOnComplete(std::move(onDone)); + pool->setJobsSource([this]() -> std::optional { + if (entries.empty()) { + return std::nullopt; + } + aloader_entry entry = std::move(entries.front()); + entries.pop(); + return entry; + }); + while (!entries.empty()) { aloader_entry entry = std::move(entries.front()); entries.pop(); diff --git a/src/assets/AssetsLoader.hpp b/src/assets/AssetsLoader.hpp index 78152b6ac..c34eb822d 100644 --- a/src/assets/AssetsLoader.hpp +++ b/src/assets/AssetsLoader.hpp @@ -124,10 +124,11 @@ public: static void addDefaults(AssetsLoader& loader, const Content* content); static bool loadExternalTexture( - Assets* assets, + AssetsLoader& loader, const std::string& name, const std::vector& alternatives ); + Assets& getAssets(); Engine& getEngine(); }; diff --git a/src/engine/AssetsManagement.cpp b/src/engine/AssetsManagement.cpp index 2135f568f..55bfb9401 100644 --- a/src/engine/AssetsManagement.cpp +++ b/src/engine/AssetsManagement.cpp @@ -1,13 +1,12 @@ #include "AssetsManagement.hpp" -#include "assets/Assets.hpp" #include "assets/AssetsLoader.hpp" -#include "engine/Engine.hpp" -#include "debug/Logger.hpp" -#include "content/Content.hpp" -#include "graphics/core/Shader.hpp" -#include "EnginePaths.hpp" #include "coders/GLSLExtension.hpp" +#include "content/Content.hpp" +#include "debug/Logger.hpp" +#include "engine/Engine.hpp" +#include "EnginePaths.hpp" +#include "graphics/core/Shader.hpp" #include "graphics/render/ModelsGenerator.hpp" #include "graphics/ui/GUI.hpp" @@ -15,6 +14,10 @@ static debug::Logger logger("assets-management"); AssetsManagement::AssetsManagement(Engine& engine) : engine(engine) {} +AssetsManagement::~AssetsManagement() { + finishBackgroundLoader(); +} + const Assets* AssetsManagement::getStorage() const { return assets.get(); } @@ -23,7 +26,23 @@ Assets* AssetsManagement::getStorage() { return assets.get(); } +AssetsLoader& AssetsManagement::acquireBackgroundLoader() { + if (backgroundLoader) { + return *backgroundLoader; + } + if (assets == nullptr) { + throw std::runtime_error("no assets storage available"); + } + backgroundLoader = std::make_unique( + engine, *assets, engine.getResPaths() + ); + backgroundLoaderTask = backgroundLoader->startTask(nullptr); + return *backgroundLoader; +} + void AssetsManagement::loadAssets(Content* content) { + finishBackgroundLoader(); + const auto& paths = engine.getPaths(); logger.info() << "loading assets"; Shader::preprocessor->setPaths(&paths.resPaths); @@ -34,7 +53,7 @@ void AssetsManagement::loadAssets(Content* content) { // no need // correct log messages order is more useful - // todo: before setting to true, check if GLSLExtension thread safe + // todo: before setting to true, check if GLSLExtension thread safe bool threading = false; // look at three upper lines if (threading) { auto task = loader.startTask([=](){}); @@ -51,3 +70,17 @@ void AssetsManagement::loadAssets(Content* content) { assets->setup(); engine.getGUI().onAssetsLoad(assets.get()); } + +void AssetsManagement::update() { + if (backgroundLoaderTask) { + backgroundLoaderTask->update(); + } +} + +void AssetsManagement::finishBackgroundLoader() { + if (backgroundLoaderTask == nullptr) { + return; + } + backgroundLoaderTask.reset(); + backgroundLoader.reset(); +} diff --git a/src/engine/AssetsManagement.hpp b/src/engine/AssetsManagement.hpp index 5b06e6d8c..f88bc281a 100644 --- a/src/engine/AssetsManagement.hpp +++ b/src/engine/AssetsManagement.hpp @@ -1,22 +1,31 @@ #pragma once +#include "assets/Assets.hpp" + #include -class Assets; class AssetsLoader; class Engine; class Content; +class Task; -class AssetsManagement { +class AssetsManagement final { public: AssetsManagement(Engine& engine); + ~AssetsManagement(); void loadAssets(Content* content); + void update(); Assets* getStorage(); const Assets* getStorage() const; + + AssetsLoader& acquireBackgroundLoader(); private: + void finishBackgroundLoader(); + Engine& engine; std::unique_ptr assets; std::unique_ptr backgroundLoader; + std::shared_ptr backgroundLoaderTask; }; diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 6cc976799..9afe0824a 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -4,48 +4,45 @@ #define GLEW_STATIC #endif -#include "debug/Logger.hpp" -#include "assets/AssetsLoader.hpp" +#include "AssetsManagement.hpp" #include "audio/audio.hpp" +#include "coders/commons.hpp" #include "coders/GLSLExtension.hpp" #include "coders/toml.hpp" -#include "coders/commons.hpp" -#include "devtools/Editor.hpp" -#include "devtools/Project.hpp" -#include "devtools/DebuggingServer.hpp" #include "content/ContentControl.hpp" #include "core_defs.hpp" -#include "io/io.hpp" -#include "io/settings_io.hpp" +#include "debug/Logger.hpp" +#include "devtools/DebuggingServer.hpp" +#include "devtools/Editor.hpp" +#include "devtools/Project.hpp" +#include "EnginePaths.hpp" #include "frontend/locale.hpp" #include "frontend/menu.hpp" #include "frontend/screens/Screen.hpp" -#include "graphics/render/ModelsGenerator.hpp" #include "graphics/core/DrawContext.hpp" #include "graphics/core/Shader.hpp" -#include "graphics/ui/GUI.hpp" #include "graphics/ui/elements/Menu.hpp" -#include "logic/EngineController.hpp" +#include "graphics/ui/GUI.hpp" +#include "io/io.hpp" +#include "io/settings_io.hpp" #include "logic/CommandsInterpreter.hpp" -#include "logic/scripting/scripting.hpp" +#include "logic/EngineController.hpp" #include "logic/scripting/scripting_hud.hpp" +#include "logic/scripting/scripting.hpp" +#include "Mainloop.hpp" #include "network/Network.hpp" +#include "ServerMainloop.hpp" #include "util/platform.hpp" +#include "util/stringutil.hpp" #include "window/input.hpp" #include "window/Window.hpp" -#include "world/Level.hpp" -#include "AssetsManagement.hpp" -#include "Mainloop.hpp" -#include "ServerMainloop.hpp" #include "WindowControl.hpp" -#include "EnginePaths.hpp" +#include "world/Level.hpp" -#include #include #include #include #include -#include static debug::Logger logger("engine"); @@ -266,6 +263,7 @@ void Engine::applicationTick() { void Engine::updateFrontend() { double delta = time.getDelta(); + assets->update(); updateHotkeys(); audio::update(delta); gui->act(delta, window->getSize()); @@ -421,6 +419,10 @@ Assets* Engine::getAssets() { return assets->getStorage(); } +AssetsLoader& Engine::acquireBackgroundLoader() { + return assets->acquireBackgroundLoader(); +} + EnginePaths& Engine::getPaths() { return *paths; } diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 7ecff05c6..4f4e68280 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -10,6 +10,7 @@ #include class Assets; +class AssetsLoader; class AssetsManagement; class ContentControl; class EngineController; @@ -110,6 +111,8 @@ public: /// @brief Get active assets storage instance Assets* getAssets(); + AssetsLoader& acquireBackgroundLoader(); + /// @brief Get writeable engine settings structure instance EngineSettings& getSettings(); diff --git a/src/engine/EnginePaths.cpp b/src/engine/EnginePaths.cpp index 7cb71079c..c61d27f89 100644 --- a/src/engine/EnginePaths.cpp +++ b/src/engine/EnginePaths.cpp @@ -274,6 +274,9 @@ ResPaths::ResPaths(std::vector roots) } io::path ResPaths::find(const std::string& filename) const { + if (filename.find(':') != std::string::npos) { + return filename; + } for (int i = roots.size() - 1; i >= 0; i--) { auto& root = roots[i]; auto file = root.path / filename; diff --git a/src/logic/scripting/lua/libs/libpack.cpp b/src/logic/scripting/lua/libs/libpack.cpp index b7162b4d0..66fa86426 100644 --- a/src/logic/scripting/lua/libs/libpack.cpp +++ b/src/logic/scripting/lua/libs/libpack.cpp @@ -87,10 +87,10 @@ static int l_pack_get_info( lua::setfield(L, "path"); if (!engine->isHeadless()) { - auto assets = engine->getAssets(); + auto& assetsLoader = engine->acquireBackgroundLoader(); std::string icon = pack.id + ".icon"; if (!AssetsLoader::loadExternalTexture( - assets, icon, {pack.folder / "icon.png"} + assetsLoader, icon, {pack.folder / "icon"} )) { icon = "gui/no_icon"; } diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 9b28c719f..a9567ea97 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -56,13 +56,12 @@ static int l_get_list(lua::State* L) { lua::pushstring(L, name); lua::setfield(L, "name"); - auto assets = engine->getAssets(); std::string icon = "world#" + name + ".icon"; if (!engine->isHeadless() && !AssetsLoader::loadExternalTexture( - assets, + engine->acquireBackgroundLoader(), icon, - {worlds[i] / "icon.png", - worlds[i] / "preview.png"} + {worlds[i] / "icon", + worlds[i] / "preview"} )) { icon = "gui/no_world_icon"; } From 5a742b8a0f68ee7d44442435425c4580d988651a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 24 Jan 2026 14:21:38 +0300 Subject: [PATCH 05/20] feat: post-runnables context now allowing to use content-related app.* functions --- res/layouts/pages/content.xml.lua | 4 +++- res/scripts/stdlib.lua | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/res/layouts/pages/content.xml.lua b/res/layouts/pages/content.xml.lua index 89c230ed0..e77141cc4 100644 --- a/res/layouts/pages/content.xml.lua +++ b/res/layouts/pages/content.xml.lua @@ -28,7 +28,9 @@ local function include(id, is_include) end function apply() - core.reconfig_packs(add_packs, rem_packs) + time.post_runnable(function () + app.reconfig_packs(add_packs, rem_packs) + end) if mode ~= "world" then menu:back() end diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 4eb6dd17e..683f27e8a 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -25,6 +25,7 @@ function tb_frame_tostring(frame) end local __vc__app_script_coroutine +local __vc__is_post_runnable = false local function complete_app_lib(app) local __app_load_content = app.load_content @@ -44,6 +45,10 @@ local function complete_app_lib(app) app.tick = __app_tick local function call_in_app_script_co(func, ...) + if __vc__is_post_runnable then + func(...) + return + end local running = coroutine.running() if not running or running ~= __vc__app_script_coroutine then error("content must be reload in application script coroutine") @@ -513,7 +518,7 @@ local fn_audio_reset_fetch_buffer = audio.__reset_fetch_buffer audio.__reset_fetch_buffer = nil core.get_core_token = audio.input.__get_core_token -function __process_post_runnables() +local function __vc__process_post_runnables() if #__post_runnables then for _, func in ipairs(__post_runnables) do local status, result = xpcall(func, __vc__error) @@ -547,6 +552,15 @@ function __process_post_runnables() end end +function __process_post_runnables() + __vc__is_post_runnable = true + local success, err = pcall(__vc__process_post_runnables) + if not success then + debug.error("an error ocurred while processing post-runnables: ".. err) + end + __vc__is_post_runnable = false +end + function time.post_runnable(runnable) table.insert(__post_runnables, runnable) end From 3f5fc5376d8fb4c5f18ef76c93a31c1e2afe8733 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 24 Jan 2026 14:33:38 +0300 Subject: [PATCH 06/20] elevate minimum ore generation height by 6 before blocks generation priority added --- res/content/base/modules/generation/ores.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/content/base/modules/generation/ores.lua b/res/content/base/modules/generation/ores.lua index 3b2c2f915..64b0c2a64 100644 --- a/res/content/base/modules/generation/ores.lua +++ b/res/content/base/modules/generation/ores.lua @@ -18,7 +18,7 @@ function ores.place(placements, x, z, w, d, seed, hmap, chunk_height) for i=1,count do local sx = math.random() * w local sz = math.random() * d - local sy = math.random() * (chunk_height * 0.5) + local sy = math.random() * (chunk_height * 0.5) + 6 if sy < hmap:at(sx, sz) * chunk_height - 6 then table.insert(placements, {ore.struct, {sx, sy, sz}, math.random()*4, -1}) end From 279299274a2e868912fb99e92e342eb3f4d13e03 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 26 Jan 2026 21:52:49 +0300 Subject: [PATCH 07/20] feat: pre-set `world:` entry-point on world creation --- src/logic/EngineController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index db956e150..4e653beb5 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -276,8 +276,8 @@ void EngineController::createWorld( auto folder = paths.getWorldsFolder() / name; call(engine, [this, &paths, folder]() { - engine.getContentControl().loadContent(); paths.setCurrentWorldFolder(folder); + engine.getContentControl().loadContent(); }); auto& contentControl = engine.getContentControl(); From 18e7fb55a64aa3a35261ddcf37032ed28fa38001 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 27 Jan 2026 23:04:30 +0300 Subject: [PATCH 08/20] cleanup Image element & add fallback --- src/graphics/ui/elements/Image.cpp | 51 ++++++++++++++---------------- src/graphics/ui/elements/Image.hpp | 22 +++++++++---- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/graphics/ui/elements/Image.cpp b/src/graphics/ui/elements/Image.cpp index f321ddf8a..49eb3d874 100644 --- a/src/graphics/ui/elements/Image.cpp +++ b/src/graphics/ui/elements/Image.cpp @@ -3,6 +3,7 @@ #include #include "assets/Assets.hpp" +#include "assets/assets_util.hpp" #include "graphics/core/Atlas.hpp" #include "graphics/core/Batch2D.hpp" #include "graphics/core/DrawContext.hpp" @@ -16,37 +17,25 @@ Image::Image(GUI& gui, std::string texture, glm::vec2 size) setInteractive(false); } +util::TextureRegion Image::refreshTexture(const Assets& assets) { + auto region = util::get_texture_region(assets, texture, fallback); + if (region.texture && autoresize) { + setSize(glm::vec2( + region.texture->getWidth() * region.region.getWidth(), + region.texture->getHeight() * region.region.getHeight() + )); + } + return region; +} + void Image::draw(const DrawContext& pctx, const Assets& assets) { glm::vec2 pos = calcPos(); auto batch = pctx.getBatch2D(); - Texture* texture = nullptr; - auto separator = this->texture.find(':'); - if (separator == std::string::npos) { - texture = assets.get(this->texture); - batch->texture(texture); - if (texture && autoresize) { - setSize(glm::vec2(texture->getWidth(), texture->getHeight())); - } - } else { - auto atlasName = this->texture.substr(0, separator); - if (auto atlas = assets.get(atlasName)) { - if (auto region = - atlas->getIf(this->texture.substr(separator + 1))) { - texture = atlas->getTexture(); - batch->texture(atlas->getTexture()); - batch->setRegion(*region); - if (autoresize) { - setSize(glm::vec2( - texture->getWidth() * region->getWidth(), - texture->getHeight() * region->getHeight() - )); - } - } else { - batch->texture(nullptr); - } - } - } + auto textureRegion = refreshTexture(assets); + + batch->setRegion(textureRegion.region); + batch->texture(textureRegion.texture); batch->rect( pos.x, pos.y, @@ -73,10 +62,18 @@ const std::string& Image::getTexture() const { return texture; } +const std::string& Image::getFallback() const { + return fallback; +} + void Image::setTexture(const std::string& name) { texture = name; } +void Image::setFallback(const std::string& name) { + fallback = name; +} + void Image::setRegion(const UVRegion& region) { this->region = region; } diff --git a/src/graphics/ui/elements/Image.hpp b/src/graphics/ui/elements/Image.hpp index 40765a4c0..194619f7d 100644 --- a/src/graphics/ui/elements/Image.hpp +++ b/src/graphics/ui/elements/Image.hpp @@ -3,21 +3,31 @@ #include "UINode.hpp" #include "maths/UVRegion.hpp" +namespace util { + struct TextureRegion; +} + namespace gui { - class Image : public UINode { + class Image final : public UINode { protected: std::string texture; + std::string fallback; UVRegion region {}; bool autoresize = false; + bool isFallback = false; + + util::TextureRegion refreshTexture(const Assets& assets); public: Image(GUI& gui, std::string texture, glm::vec2 size=glm::vec2(32,32)); - virtual void draw(const DrawContext& pctx, const Assets& assets) override; + void draw(const DrawContext& pctx, const Assets& assets) override; - virtual void setAutoResize(bool flag); - virtual bool isAutoResize() const; - virtual const std::string& getTexture() const; - virtual void setTexture(const std::string& name); + void setAutoResize(bool flag); + bool isAutoResize() const; + const std::string& getTexture() const; + const std::string& getFallback() const; + void setTexture(const std::string& name); + void setFallback(const std::string& name); void setRegion(const UVRegion& region); const UVRegion& getRegion() const; }; From 6aac90094eb721d8d9cc7169cbc808ae34bace62 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 27 Jan 2026 23:10:08 +0300 Subject: [PATCH 09/20] add 'fallback' property to xml and scripting --- res/layouts/templates/pack.xml | 2 +- res/layouts/templates/world.xml | 2 +- src/graphics/ui/elements/Image.hpp | 1 - src/graphics/ui/gui_xml.cpp | 4 +++- src/logic/scripting/lua/libs/libgui.cpp | 14 ++++++++++++++ 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/res/layouts/templates/pack.xml b/res/layouts/templates/pack.xml index 3b24aa960..56bd50e50 100644 --- a/res/layouts/templates/pack.xml +++ b/res/layouts/templates/pack.xml @@ -11,5 +11,5 @@ - + diff --git a/res/layouts/templates/world.xml b/res/layouts/templates/world.xml index 4ae936b6e..d20f78407 100644 --- a/res/layouts/templates/world.xml +++ b/res/layouts/templates/world.xml @@ -4,7 +4,7 @@ hover-color='#162B3399' onclick='app.open_world("%{name}")' > - +