From 05de043154d3c4a59af9d14b67b094782852e31c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 18:23:10 +0300 Subject: [PATCH 01/14] add 'project:content' content source --- src/content/ContentControl.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/content/ContentControl.cpp b/src/content/ContentControl.cpp index 9c99135b..543931d3 100644 --- a/src/content/ContentControl.cpp +++ b/src/content/ContentControl.cpp @@ -30,6 +30,7 @@ ContentControl::ContentControl( manager->setSources({ "world:content", "user:content", + "project:content", "res:content", }); } From 87ff77a73fd0640d478827f8a3e73f06eda48e7c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 18:26:36 +0300 Subject: [PATCH 02/14] add project start application script --- src/devtools/Project.hpp | 2 ++ src/engine/Engine.cpp | 28 ++++++++++++++++++++++++---- src/engine/Engine.hpp | 1 + src/engine/Mainloop.cpp | 1 + src/engine/ServerMainloop.cpp | 1 + src/frontend/screens/MenuScreen.cpp | 8 +++++--- 6 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/devtools/Project.hpp b/src/devtools/Project.hpp index be9d88a3..68093ada 100644 --- a/src/devtools/Project.hpp +++ b/src/devtools/Project.hpp @@ -4,6 +4,7 @@ #include #include +#include "interfaces/Process.hpp" #include "interfaces/Serializable.hpp" namespace scripting { @@ -15,6 +16,7 @@ struct Project : Serializable { std::string title; std::vector basePacks; std::unique_ptr clientScript; + std::unique_ptr setupCoroutine; ~Project(); diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 3053b613..1b8cd440 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -62,13 +62,24 @@ static std::unique_ptr load_icon() { return nullptr; } -static std::unique_ptr load_client_project_script() { +static std::unique_ptr load_project_client_script() { io::path scriptFile = "project:project_client.lua"; if (io::exists(scriptFile)) { - logger.info() << "starting project script"; + logger.info() << "starting project client script"; return scripting::load_client_project_script(scriptFile); } else { - logger.warning() << "project script does not exists"; + logger.warning() << "project client script does not exists"; + } + return nullptr; +} + +static std::unique_ptr load_project_start_script() { + io::path scriptFile = "project:start.lua"; + if (io::exists(scriptFile)) { + logger.info() << "starting project start script"; + return scripting::start_app_script(scriptFile); + } else { + logger.warning() << "project start script does not exists"; } return nullptr; } @@ -226,7 +237,10 @@ void Engine::initialize(CoreParameters coreParameters) { langs::setup(lang, paths.resPaths.collectRoots()); }, true)); - project->clientScript = load_client_project_script(); + project->setupCoroutine = load_project_start_script(); + if (!params.headless) { + project->clientScript = load_project_client_script(); + } } void Engine::loadSettings() { @@ -301,6 +315,12 @@ void Engine::detachDebugger() { debuggingServer.reset(); } +void Engine::applicationTick() { + if (project->setupCoroutine && project->setupCoroutine->isActive()) { + project->setupCoroutine->update(); + } +} + void Engine::updateFrontend() { double delta = time.getDelta(); updateHotkeys(); diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 98a2c3ef..468563d0 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -105,6 +105,7 @@ public: void postUpdate(); + void applicationTick(); void updateFrontend(); void renderFrame(); void nextFrame(); diff --git a/src/engine/Mainloop.cpp b/src/engine/Mainloop.cpp index a14c5464..5435e983 100644 --- a/src/engine/Mainloop.cpp +++ b/src/engine/Mainloop.cpp @@ -38,6 +38,7 @@ void Mainloop::run() { logger.info() << "main loop started"; while (!window.isShouldClose()){ time.update(window.time()); + engine.applicationTick(); engine.updateFrontend(); if (!window.isIconified()) { diff --git a/src/engine/ServerMainloop.cpp b/src/engine/ServerMainloop.cpp index ab35ffbd..7fb8ffed 100644 --- a/src/engine/ServerMainloop.cpp +++ b/src/engine/ServerMainloop.cpp @@ -60,6 +60,7 @@ void ServerMainloop::run() { controller->getLevel()->getWorld()->updateTimers(delta); controller->update(glm::min(delta, 0.2), false); } + engine.applicationTick(); engine.postUpdate(); if (!coreParams.testMode) { diff --git a/src/frontend/screens/MenuScreen.cpp b/src/frontend/screens/MenuScreen.cpp index c1339494..e1015e8c 100644 --- a/src/frontend/screens/MenuScreen.cpp +++ b/src/frontend/screens/MenuScreen.cpp @@ -12,9 +12,11 @@ #include "window/Camera.hpp" #include "engine/Engine.hpp" -MenuScreen::MenuScreen(Engine& engine) : Screen(engine) { - uicamera = - std::make_unique(glm::vec3(), engine.getWindow().getSize().y); +MenuScreen::MenuScreen(Engine& engine) + : Screen(engine), + uicamera( + std::make_unique(glm::vec3(), engine.getWindow().getSize().y) + ) { uicamera->perspective = false; uicamera->near = -1.0f; uicamera->far = 1.0f; From 4bafad708e60bf111d124843c22b338cc896b466 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 19:09:35 +0300 Subject: [PATCH 03/14] move window-related code from Engine.cpp to WindowControl --- src/engine/Engine.cpp | 63 ++++------------------------ src/engine/Engine.hpp | 4 +- src/engine/WindowControl.cpp | 81 ++++++++++++++++++++++++++++++++++++ src/engine/WindowControl.hpp | 24 +++++++++++ src/io/engine_paths.cpp | 2 +- src/io/engine_paths.hpp | 2 +- 6 files changed, 116 insertions(+), 60 deletions(-) create mode 100644 src/engine/WindowControl.cpp create mode 100644 src/engine/WindowControl.hpp diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 1b8cd440..7f920833 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -8,8 +8,6 @@ #include "assets/AssetsLoader.hpp" #include "audio/audio.hpp" #include "coders/GLSLExtension.hpp" -#include "coders/imageio.hpp" -#include "coders/json.hpp" #include "coders/toml.hpp" #include "coders/commons.hpp" #include "devtools/Editor.hpp" @@ -23,23 +21,21 @@ #include "frontend/screens/Screen.hpp" #include "graphics/render/ModelsGenerator.hpp" #include "graphics/core/DrawContext.hpp" -#include "graphics/core/ImageData.hpp" #include "graphics/core/Shader.hpp" #include "graphics/ui/GUI.hpp" #include "graphics/ui/elements/Menu.hpp" -#include "objects/rigging.hpp" #include "logic/EngineController.hpp" #include "logic/CommandsInterpreter.hpp" #include "logic/scripting/scripting.hpp" #include "logic/scripting/scripting_hud.hpp" #include "network/Network.hpp" #include "util/platform.hpp" -#include "window/Camera.hpp" #include "window/input.hpp" #include "window/Window.hpp" #include "world/Level.hpp" #include "Mainloop.hpp" #include "ServerMainloop.hpp" +#include "WindowControl.hpp" #include #include @@ -50,18 +46,6 @@ static debug::Logger logger("engine"); -static std::unique_ptr load_icon() { - try { - auto file = "res:textures/misc/icon.png"; - if (io::exists(file)) { - return imageio::read(file); - } - } catch (const std::exception& err) { - logger.error() << "could not load window icon: " << err.what(); - } - return nullptr; -} - static std::unique_ptr load_project_client_script() { io::path scriptFile = "project:project_client.lua"; if (io::exists(scriptFile)) { @@ -119,29 +103,9 @@ void Engine::onContentLoad() { } void Engine::initializeClient() { - std::string title = project->title; - if (title.empty()) { - title = "VoxelCore v" + - std::to_string(ENGINE_VERSION_MAJOR) + "." + - std::to_string(ENGINE_VERSION_MINOR); - } - if (ENGINE_DEBUG_BUILD) { - title += " [debug]"; - } - if (debuggingServer) { - title = "[debugging] " + title; - } - auto [window, input] = Window::initialize(&settings.display, title); - if (!window || !input){ - throw initialize_error("could not initialize window"); - } - window->setFramerate(settings.display.framerate.get()); + windowControl = std::make_unique(*this); + auto [window, input] = windowControl->initialize(); - time.set(window->time()); - if (auto icon = load_icon()) { - icon->flipY(); - window->setIcon(icon.get()); - } this->window = std::move(window); this->input = std::move(input); @@ -270,7 +234,7 @@ void Engine::loadControls() { void Engine::updateHotkeys() { if (input->jpressed(Keycode::F2)) { - saveScreenshot(); + windowControl->saveScreenshot(); } if (input->pressed(Keycode::LEFT_CONTROL) && input->pressed(Keycode::F3) && input->jpressed(Keycode::U)) { @@ -285,14 +249,6 @@ void Engine::updateHotkeys() { } } -void Engine::saveScreenshot() { - auto image = window->takeScreenshot(); - image->flipY(); - io::path filename = paths.getNewScreenshotFile("png"); - imageio::write(filename.string(), image.get()); - logger.info() << "saved screenshot as " << filename.string(); -} - void Engine::run() { if (params.headless) { ServerMainloop(*this).run(); @@ -331,13 +287,7 @@ void Engine::updateFrontend() { } void Engine::nextFrame() { - window->setFramerate( - window->isIconified() && settings.display.limitFpsIconified.get() - ? 20 - : settings.display.framerate.get() - ); - window->swapBuffers(); - input->pollEvents(); + windowControl->nextFrame(); } void Engine::startPauseLoop() { @@ -437,7 +387,8 @@ void Engine::loadAssets() { // no need // correct log messages order is more useful - bool threading = false; // look at two upper lines + // 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(); diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 468563d0..2049258f 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -14,6 +14,7 @@ #include class Window; +class WindowControl; class Assets; class Level; class Screen; @@ -75,6 +76,7 @@ class Engine : public util::ObjectsKeeper { std::unique_ptr gui; std::unique_ptr editor; std::unique_ptr debuggingServer; + std::unique_ptr windowControl; PostRunnables postRunnables; Time time; OnWorldOpen levelConsumer; @@ -144,8 +146,6 @@ public: postRunnables.postRunnable(callback); } - void saveScreenshot(); - EngineController* getController(); void setLevelConsumer(OnWorldOpen levelConsumer); diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp new file mode 100644 index 00000000..edf0a6e7 --- /dev/null +++ b/src/engine/WindowControl.cpp @@ -0,0 +1,81 @@ +#include "WindowControl.hpp" + +#include "Engine.hpp" +#include "devtools/Project.hpp" +#include "coders/imageio.hpp" +#include "window/Window.hpp" +#include "window/input.hpp" +#include "debug/Logger.hpp" +#include "graphics/core/ImageData.hpp" + +static debug::Logger logger("window-control"); + +namespace { + static std::unique_ptr load_icon() { + try { + auto file = "res:textures/misc/icon.png"; + if (io::exists(file)) { + return imageio::read(file); + } + } catch (const std::exception& err) { + logger.error() << "could not load window icon: " << err.what(); + } + return nullptr; + } +} + +WindowControl::WindowControl(Engine& engine) : engine(engine) {} + +WindowControl::Result WindowControl::initialize() { + const auto& project = engine.getProject(); + auto& settings = engine.getSettings(); + + std::string title = project.title; + if (title.empty()) { + title = "VoxelCore v" + + std::to_string(ENGINE_VERSION_MAJOR) + "." + + std::to_string(ENGINE_VERSION_MINOR); + } + if (ENGINE_DEBUG_BUILD) { + title += " [debug]"; + } + if (engine.getDebuggingServer()) { + title = "[debugging] " + title; + } + + auto [window, input] = Window::initialize(&settings.display, title); + if (!window || !input){ + throw initialize_error("could not initialize window"); + } + window->setFramerate(settings.display.framerate.get()); + if (auto icon = load_icon()) { + icon->flipY(); + window->setIcon(icon.get()); + } + + return Result {std::move(window), std::move(input)}; +} + +void WindowControl::saveScreenshot() { + auto& window = engine.getWindow(); + const auto& paths = engine.getPaths(); + + auto image = window.takeScreenshot(); + image->flipY(); + io::path filename = paths.getNewScreenshotFile("png"); + imageio::write(filename.string(), image.get()); + logger.info() << "saved screenshot as " << filename.string(); +} + +void WindowControl::nextFrame() { + const auto& settings = engine.getSettings(); + auto& window = engine.getWindow(); + auto& input = engine.getInput(); + window.setFramerate( + window.isIconified() && settings.display.limitFpsIconified.get() + ? 20 + : settings.display.framerate.get() + ); + window.swapBuffers(); + input.pollEvents(); +} diff --git a/src/engine/WindowControl.hpp b/src/engine/WindowControl.hpp new file mode 100644 index 00000000..807d9758 --- /dev/null +++ b/src/engine/WindowControl.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +class Window; +class Input; +class Engine; + +class WindowControl { +public: + struct Result { + std::unique_ptr window; + std::unique_ptr input; + }; + WindowControl(Engine& engine); + + Result initialize(); + + void nextFrame(); + + void saveScreenshot(); +private: + Engine& engine; +}; diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index 98363d9b..ef102621 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -67,7 +67,7 @@ const std::filesystem::path& EnginePaths::getResourcesFolder() const { return resourcesFolder; } -io::path EnginePaths::getNewScreenshotFile(const std::string& ext) { +io::path EnginePaths::getNewScreenshotFile(const std::string& ext) const { auto folder = SCREENSHOTS_FOLDER; if (!io::is_directory(folder)) { io::create_directories(folder); diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 8b9b7f8e..0fa58874 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -63,7 +63,7 @@ public: void setCurrentWorldFolder(io::path folder); io::path getCurrentWorldFolder(); - io::path getNewScreenshotFile(const std::string& ext); + io::path getNewScreenshotFile(const std::string& ext) const; std::string mount(const io::path& file); void unmount(const std::string& name); From 01bf474a2b36201164bcae7e7052526441172e53 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 19:37:40 +0300 Subject: [PATCH 04/14] cleanup Engine.cpp a bit --- src/devtools/Project.cpp | 25 ++++++++++++++++++++++ src/devtools/Project.hpp | 3 +++ src/engine/Engine.cpp | 41 ++++++------------------------------ src/engine/WindowControl.cpp | 10 +++++++++ src/engine/WindowControl.hpp | 2 ++ 5 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/devtools/Project.cpp b/src/devtools/Project.cpp index 881f6cc7..61e99c6a 100644 --- a/src/devtools/Project.cpp +++ b/src/devtools/Project.cpp @@ -1,8 +1,13 @@ #include "Project.hpp" #include "data/dv_util.hpp" +#include "debug/Logger.hpp" +#include "io/io.hpp" +#include "io/path.hpp" #include "logic/scripting/scripting.hpp" +static debug::Logger logger("project"); + Project::~Project() = default; dv::value Project::serialize() const { @@ -18,3 +23,23 @@ void Project::deserialize(const dv::value& src) { src.at("title").get(title); dv::get(src, "base_packs", basePacks); } + +void Project::loadProjectClientScript() { + io::path scriptFile = "project:project_client.lua"; + if (io::exists(scriptFile)) { + logger.info() << "starting project client script"; + clientScript = scripting::load_client_project_script(scriptFile); + } else { + logger.warning() << "project client script does not exists"; + } +} + +void Project::loadProjectStartScript() { + io::path scriptFile = "project:start.lua"; + if (io::exists(scriptFile)) { + logger.info() << "starting project start script"; + setupCoroutine = scripting::start_app_script(scriptFile); + } else { + logger.warning() << "project start script does not exists"; + } +} diff --git a/src/devtools/Project.hpp b/src/devtools/Project.hpp index 68093ada..f0851b30 100644 --- a/src/devtools/Project.hpp +++ b/src/devtools/Project.hpp @@ -22,4 +22,7 @@ struct Project : Serializable { dv::value serialize() const override; void deserialize(const dv::value& src) override; + + void loadProjectClientScript(); + void loadProjectStartScript(); }; diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 7f920833..150b8b02 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -46,28 +46,6 @@ static debug::Logger logger("engine"); -static std::unique_ptr load_project_client_script() { - io::path scriptFile = "project:project_client.lua"; - if (io::exists(scriptFile)) { - logger.info() << "starting project client script"; - return scripting::load_client_project_script(scriptFile); - } else { - logger.warning() << "project client script does not exists"; - } - return nullptr; -} - -static std::unique_ptr load_project_start_script() { - io::path scriptFile = "project:start.lua"; - if (io::exists(scriptFile)) { - logger.info() << "starting project start script"; - return scripting::start_app_script(scriptFile); - } else { - logger.warning() << "project start script does not exists"; - } - return nullptr; -} - Engine::Engine() = default; Engine::~Engine() = default; @@ -146,7 +124,7 @@ void Engine::initialize(CoreParameters coreParameters) { logger.info() << "engine version: " << ENGINE_VERSION_STRING; if (params.headless) { - logger.info() << "headless mode is enabled"; + logger.info() << "engine runs in headless mode"; } if (params.projectFolder.empty()) { params.projectFolder = params.resFolder; @@ -154,6 +132,9 @@ void Engine::initialize(CoreParameters coreParameters) { paths.setResourcesFolder(params.resFolder); paths.setUserFilesFolder(params.userFolder); paths.setProjectFolder(params.projectFolder); + if (!params.scriptFile.empty()) { + paths.setScriptFolder(params.scriptFile.parent_path()); + } paths.prepare(); loadProject(); @@ -172,10 +153,6 @@ void Engine::initialize(CoreParameters coreParameters) { ); } } - - if (!params.scriptFile.empty()) { - paths.setScriptFolder(params.scriptFile.parent_path()); - } loadSettings(); controller = std::make_unique(*this); @@ -201,9 +178,9 @@ void Engine::initialize(CoreParameters coreParameters) { langs::setup(lang, paths.resPaths.collectRoots()); }, true)); - project->setupCoroutine = load_project_start_script(); + project->loadProjectStartScript(); if (!params.headless) { - project->clientScript = load_project_client_script(); + project->loadProjectClientScript(); } } @@ -241,11 +218,7 @@ void Engine::updateHotkeys() { gui->toggleDebug(); } if (input->jpressed(Keycode::F11)) { - if (settings.display.windowMode.get() != static_cast(WindowMode::FULLSCREEN)) { - settings.display.windowMode.set(static_cast(WindowMode::FULLSCREEN)); - } else { - settings.display.windowMode.set(static_cast(WindowMode::WINDOWED)); - } + windowControl->toggleFullscreen(); } } diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp index edf0a6e7..8557c5be 100644 --- a/src/engine/WindowControl.cpp +++ b/src/engine/WindowControl.cpp @@ -67,6 +67,16 @@ void WindowControl::saveScreenshot() { logger.info() << "saved screenshot as " << filename.string(); } +void WindowControl::toggleFullscreen() { + auto& settings = engine.getSettings(); + auto& windowMode = settings.display.windowMode; + if (windowMode.get() != static_cast(WindowMode::FULLSCREEN)) { + windowMode.set(static_cast(WindowMode::FULLSCREEN)); + } else { + windowMode.set(static_cast(WindowMode::WINDOWED)); + } +} + void WindowControl::nextFrame() { const auto& settings = engine.getSettings(); auto& window = engine.getWindow(); diff --git a/src/engine/WindowControl.hpp b/src/engine/WindowControl.hpp index 807d9758..f3b7c8bc 100644 --- a/src/engine/WindowControl.hpp +++ b/src/engine/WindowControl.hpp @@ -19,6 +19,8 @@ public: void nextFrame(); void saveScreenshot(); + + void toggleFullscreen(); private: Engine& engine; }; From 3b583d4dd6995279c47409193e8c2c7c2f63f755 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 19:56:46 +0300 Subject: [PATCH 05/14] refactor: Engine, EnginePaths, move CoreParameters to new header --- src/engine/CoreParameters.hpp | 15 +++++++ src/engine/Engine.cpp | 9 +--- src/engine/Engine.hpp | 33 +++++--------- src/io/engine_paths.cpp | 82 ++++++++++++++++------------------- src/io/engine_paths.hpp | 17 +++----- 5 files changed, 71 insertions(+), 85 deletions(-) create mode 100644 src/engine/CoreParameters.hpp diff --git a/src/engine/CoreParameters.hpp b/src/engine/CoreParameters.hpp new file mode 100644 index 00000000..c937bf3a --- /dev/null +++ b/src/engine/CoreParameters.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +struct CoreParameters { + bool headless = false; + bool testMode = false; + std::filesystem::path resFolder = "res"; + std::filesystem::path userFolder = "."; + std::filesystem::path scriptFile; + std::filesystem::path projectFolder; + std::string debugServerString; + int tps = 20; +}; diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 150b8b02..ca8edc89 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -16,6 +16,7 @@ #include "content/ContentControl.hpp" #include "core_defs.hpp" #include "io/io.hpp" +#include "io/settings_io.hpp" #include "frontend/locale.hpp" #include "frontend/menu.hpp" #include "frontend/screens/Screen.hpp" @@ -129,13 +130,7 @@ void Engine::initialize(CoreParameters coreParameters) { if (params.projectFolder.empty()) { params.projectFolder = params.resFolder; } - paths.setResourcesFolder(params.resFolder); - paths.setUserFilesFolder(params.userFolder); - paths.setProjectFolder(params.projectFolder); - if (!params.scriptFile.empty()) { - paths.setScriptFolder(params.scriptFile.parent_path()); - } - paths.prepare(); + paths.prepare(params); loadProject(); editor = std::make_unique(*this); diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 2049258f..5087ab50 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -1,26 +1,26 @@ #pragma once -#include "delegates.hpp" -#include "typedefs.hpp" -#include "settings.hpp" - -#include "io/engine_paths.hpp" -#include "io/settings_io.hpp" -#include "util/ObjectsKeeper.hpp" +#include "CoreParameters.hpp" #include "PostRunnables.hpp" #include "Time.hpp" +#include "delegates.hpp" +#include "io/engine_paths.hpp" +#include "settings.hpp" +#include "typedefs.hpp" +#include "util/ObjectsKeeper.hpp" #include #include -class Window; -class WindowControl; class Assets; -class Level; -class Screen; class ContentControl; class EngineController; class Input; +class Level; +class Screen; +class SettingsHandler; +class Window; +class WindowControl; struct Project; namespace gui { @@ -45,17 +45,6 @@ public: initialize_error(const std::string& message) : std::runtime_error(message) {} }; -struct CoreParameters { - bool headless = false; - bool testMode = false; - std::filesystem::path resFolder = "res"; - std::filesystem::path userFolder = "."; - std::filesystem::path scriptFile; - std::filesystem::path projectFolder; - std::string debugServerString; - int tps = 20; -}; - using OnWorldOpen = std::function, int64_t)>; class Engine : public util::ObjectsKeeper { diff --git a/src/io/engine_paths.cpp b/src/io/engine_paths.cpp index ef102621..506230ad 100644 --- a/src/io/engine_paths.cpp +++ b/src/io/engine_paths.cpp @@ -1,44 +1,56 @@ #include "engine_paths.hpp" +#include "debug/Logger.hpp" +#include "io/devices/StdfsDevice.hpp" +#include "io/devices/ZipFileDevice.hpp" +#include "maths/util.hpp" +#include "typedefs.hpp" +#include "util/platform.hpp" +#include "util/random.hpp" +#include "util/stringutil.hpp" +#include "world/files/WorldFiles.hpp" + #include #include +#include #include #include -#include "typedefs.hpp" -#include "util/stringutil.hpp" -#include "util/platform.hpp" +#include #include -#include "io/devices/StdfsDevice.hpp" -#include "io/devices/ZipFileDevice.hpp" -#include "world/files/WorldFiles.hpp" -#include "debug/Logger.hpp" - -#include -#include "maths/util.hpp" - -template -static std::string generate_random_base64() { - auto now = std::chrono::high_resolution_clock::now(); - auto seed = now.time_since_epoch().count(); - - util::PseudoRandom random(seed); // fixme: replace with safe random - ubyte bytes[n]; - random.rand(bytes, n); - return util::base64_urlsafe_encode(bytes, n); -} - namespace fs = std::filesystem; -static debug::Logger logger("engine-paths"); +static std::random_device random_device; static inline io::path SCREENSHOTS_FOLDER = "user:screenshots"; static inline io::path CONTENT_FOLDER = "user:content"; static inline io::path WORLDS_FOLDER = "user:worlds"; -void EnginePaths::prepare() { +static debug::Logger logger("engine-paths"); + +template +static std::string generate_random_base64() { + auto randomEngine = util::seeded_random_engine(random_device); + static std::uniform_int_distribution dist(0, 0xFF); + ubyte bytes[n]; + for (size_t i = 0; i < n; i++) { + bytes[i] = dist(randomEngine); + } + return util::base64_urlsafe_encode(bytes, n); +} + +void EnginePaths::prepare(CoreParameters& params) { + resourcesFolder = params.resFolder; + userFilesFolder = params.userFolder; + projectFolder = params.projectFolder; + if (!params.scriptFile.empty()) { + scriptFolder = params.scriptFile.parent_path(); + io::set_device("script", std::make_shared(*scriptFolder)); + } + io::set_device("res", std::make_shared(resourcesFolder, false)); io::set_device("user", std::make_shared(userFilesFolder)); + io::set_device("project", std::make_shared(projectFolder)); if (!io::is_directory("res:")) { throw std::runtime_error( @@ -59,11 +71,11 @@ void EnginePaths::prepare() { io::create_subdevice("config", "user", "config"); } -const std::filesystem::path& EnginePaths::getUserFilesFolder() const { +const fs::path& EnginePaths::getUserFilesFolder() const { return userFilesFolder; } -const std::filesystem::path& EnginePaths::getResourcesFolder() const { +const fs::path& EnginePaths::getResourcesFolder() const { return resourcesFolder; } @@ -132,24 +144,6 @@ std::vector EnginePaths::scanForWorlds() const { return folders; } -void EnginePaths::setUserFilesFolder(std::filesystem::path folder) { - this->userFilesFolder = std::move(folder); -} - -void EnginePaths::setResourcesFolder(std::filesystem::path folder) { - this->resourcesFolder = std::move(folder); -} - -void EnginePaths::setScriptFolder(std::filesystem::path folder) { - io::set_device("script", std::make_shared(folder)); - this->scriptFolder = std::move(folder); -} - -void EnginePaths::setProjectFolder(std::filesystem::path folder) { - io::set_device("project", std::make_shared(folder)); - this->projectFolder = std::move(folder); -} - void EnginePaths::setCurrentWorldFolder(io::path folder) { if (folder.empty()) { io::remove_device("world"); diff --git a/src/io/engine_paths.hpp b/src/io/engine_paths.hpp index 0fa58874..fd411db7 100644 --- a/src/io/engine_paths.hpp +++ b/src/io/engine_paths.hpp @@ -1,15 +1,15 @@ #pragma once +#include "io.hpp" +#include "data/dv.hpp" +#include "engine/CoreParameters.hpp" + #include -#include #include #include #include #include -#include "io.hpp" -#include "data/dv.hpp" - struct PathsRoot { std::string name; io::path path; @@ -46,18 +46,11 @@ class EnginePaths { public: ResPaths resPaths; - void prepare(); + void prepare(CoreParameters& params); - void setUserFilesFolder(std::filesystem::path folder); const std::filesystem::path& getUserFilesFolder() const; - - void setResourcesFolder(std::filesystem::path folder); const std::filesystem::path& getResourcesFolder() const; - void setScriptFolder(std::filesystem::path folder); - - void setProjectFolder(std::filesystem::path folder); - io::path getWorldFolderByName(const std::string& name); io::path getWorldsFolder() const; From 17ffa73ce75671d69ffe1e6b479a28249907006b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 20:13:59 +0300 Subject: [PATCH 06/14] refactor: move and rename EnginePaths --- src/assets/AssetsLoader.cpp | 2 +- src/assets/assetload_funcs.cpp | 2 +- src/coders/GLSLExtension.cpp | 2 +- src/content/ContentControl.cpp | 2 +- src/content/ContentLoader.cpp | 2 +- src/content/ContentPack.cpp | 2 +- src/content/loading/GeneratorLoader.cpp | 2 +- src/core_defs.cpp | 2 +- src/devtools/Editor.cpp | 2 +- src/engine/Engine.cpp | 17 +++++++------- src/engine/Engine.hpp | 6 ++--- .../EnginePaths.cpp} | 22 +++++-------------- .../EnginePaths.hpp} | 16 +++++--------- src/engine/ServerMainloop.cpp | 1 + src/engine/WindowControl.cpp | 1 + src/frontend/menu.cpp | 2 +- src/frontend/screens/LevelScreen.cpp | 1 + src/graphics/render/Decorator.cpp | 1 + src/logic/EngineController.cpp | 17 +++++++------- src/logic/scripting/lua/libs/libaudio.cpp | 1 + src/logic/scripting/lua/libs/libcore.cpp | 2 +- src/logic/scripting/lua/libs/libentity.cpp | 1 + src/logic/scripting/lua/libs/libfile.cpp | 2 +- .../scripting/lua/libs/libgeneration.cpp | 1 + src/logic/scripting/lua/libs/libpack.cpp | 2 +- src/logic/scripting/lua/libs/libworld.cpp | 2 +- src/logic/scripting/lua/lua_engine.cpp | 2 +- .../lua/usertypes/lua_type_heightmap.cpp | 1 + src/logic/scripting/scripting.cpp | 2 +- src/util/command_line.cpp | 2 +- 30 files changed, 57 insertions(+), 63 deletions(-) rename src/{io/engine_paths.cpp => engine/EnginePaths.cpp} (92%) rename src/{io/engine_paths.hpp => engine/EnginePaths.hpp} (81%) diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 8dc7c31c..0fde22fc 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -9,7 +9,7 @@ #include "content/Content.hpp" #include "content/ContentPack.hpp" #include "debug/Logger.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "graphics/core/Texture.hpp" #include "logic/scripting/scripting.hpp" diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 4fda3b0d..a1c04dfc 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -15,7 +15,7 @@ #include "coders/vec3.hpp" #include "constants.hpp" #include "debug/Logger.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "frontend/UiDocument.hpp" #include "graphics/core/Atlas.hpp" diff --git a/src/coders/GLSLExtension.cpp b/src/coders/GLSLExtension.cpp index 5d53cb35..fa1335f3 100644 --- a/src/coders/GLSLExtension.cpp +++ b/src/coders/GLSLExtension.cpp @@ -6,7 +6,7 @@ #include #include "debug/Logger.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "typedefs.hpp" #include "util/stringutil.hpp" #include "coders/json.hpp" diff --git a/src/content/ContentControl.cpp b/src/content/ContentControl.cpp index 543931d3..6140c3d2 100644 --- a/src/content/ContentControl.cpp +++ b/src/content/ContentControl.cpp @@ -1,7 +1,7 @@ #include "ContentControl.hpp" #include "io/io.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "Content.hpp" #include "ContentPack.hpp" #include "ContentBuilder.hpp" diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index ea29e27c..a88146be 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -13,7 +13,7 @@ #include "objects/rigging.hpp" #include "util/listutil.hpp" #include "util/stringutil.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" static debug::Logger logger("content-loader"); diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 021f083e..d2ffdc9e 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -8,7 +8,7 @@ #include "coders/json.hpp" #include "constants.hpp" #include "data/dv.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "coders/commons.hpp" #include "debug/Logger.hpp" diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index 2f8f40d5..668425e0 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -6,7 +6,7 @@ #include "../ContentPack.hpp" #include "io/io.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "logic/scripting/scripting.hpp" #include "util/stringutil.hpp" #include "world/generator/GeneratorDef.hpp" diff --git a/src/core_defs.cpp b/src/core_defs.cpp index 79551cd4..a72d6eef 100644 --- a/src/core_defs.cpp +++ b/src/core_defs.cpp @@ -4,7 +4,7 @@ #include "content/Content.hpp" #include "content/ContentBuilder.hpp" #include "io/io.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "window/input.hpp" #include "voxels/Block.hpp" #include "coders/toml.hpp" diff --git a/src/devtools/Editor.cpp b/src/devtools/Editor.cpp index 82475ee4..0bd0af7d 100644 --- a/src/devtools/Editor.cpp +++ b/src/devtools/Editor.cpp @@ -1,7 +1,7 @@ #include "Editor.hpp" #include "engine/Engine.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "coders/syntax_parser.hpp" #include "SyntaxProcessor.hpp" diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index ca8edc89..b892908c 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -37,6 +37,7 @@ #include "Mainloop.hpp" #include "ServerMainloop.hpp" #include "WindowControl.hpp" +#include "EnginePaths.hpp" #include #include @@ -61,7 +62,7 @@ Engine& Engine::getInstance() { void Engine::onContentLoad() { editor->loadTools(); - langs::setup(langs::get_current(), paths.resPaths.collectRoots()); + langs::setup(langs::get_current(), paths->resPaths.collectRoots()); if (isHeadless()) { return; @@ -130,7 +131,7 @@ void Engine::initialize(CoreParameters coreParameters) { if (params.projectFolder.empty()) { params.projectFolder = params.resFolder; } - paths.prepare(params); + paths = std::make_unique(params); loadProject(); editor = std::make_unique(*this); @@ -161,7 +162,7 @@ void Engine::initialize(CoreParameters coreParameters) { langs::locale_by_envlocale(platform::detect_locale()) ); } - content = std::make_unique(*project, paths, *input, [this]() { + content = std::make_unique(*project, *paths, *input, [this]() { onContentLoad(); }); scripting::initialize(this); @@ -170,7 +171,7 @@ void Engine::initialize(CoreParameters coreParameters) { gui->setPageLoader(scripting::create_page_loader()); } keepAlive(settings.ui.language.observe([this](auto lang) { - langs::setup(lang, paths.resPaths.collectRoots()); + langs::setup(lang, paths->resPaths.collectRoots()); }, true)); project->loadProjectStartScript(); @@ -345,12 +346,12 @@ void Engine::setLevelConsumer(OnWorldOpen levelConsumer) { void Engine::loadAssets() { logger.info() << "loading assets"; - Shader::preprocessor->setPaths(&paths.resPaths); + Shader::preprocessor->setPaths(&paths->resPaths); auto content = this->content->get(); auto new_assets = std::make_unique(); - AssetsLoader loader(*this, *new_assets, paths.resPaths); + AssetsLoader loader(*this, *new_assets, paths->resPaths); AssetsLoader::addDefaults(loader, content); // no need @@ -426,11 +427,11 @@ Assets* Engine::getAssets() { } EnginePaths& Engine::getPaths() { - return paths; + return *paths; } ResPaths& Engine::getResPaths() { - return paths.resPaths; + return paths->resPaths; } std::shared_ptr Engine::getScreen() { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 5087ab50..58a79f95 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -4,7 +4,6 @@ #include "PostRunnables.hpp" #include "Time.hpp" #include "delegates.hpp" -#include "io/engine_paths.hpp" #include "settings.hpp" #include "typedefs.hpp" #include "util/ObjectsKeeper.hpp" @@ -15,8 +14,10 @@ class Assets; class ContentControl; class EngineController; +class EnginePaths; class Input; class Level; +class ResPaths; class Screen; class SettingsHandler; class Window; @@ -50,8 +51,7 @@ using OnWorldOpen = std::function, int64_t)>; class Engine : public util::ObjectsKeeper { CoreParameters params; EngineSettings settings; - EnginePaths paths; - + std::unique_ptr paths; std::unique_ptr project; std::unique_ptr settingsHandler; std::unique_ptr assets; diff --git a/src/io/engine_paths.cpp b/src/engine/EnginePaths.cpp similarity index 92% rename from src/io/engine_paths.cpp rename to src/engine/EnginePaths.cpp index 506230ad..8a786140 100644 --- a/src/io/engine_paths.cpp +++ b/src/engine/EnginePaths.cpp @@ -1,4 +1,4 @@ -#include "engine_paths.hpp" +#include "EnginePaths.hpp" #include "debug/Logger.hpp" #include "io/devices/StdfsDevice.hpp" @@ -39,10 +39,10 @@ static std::string generate_random_base64() { return util::base64_urlsafe_encode(bytes, n); } -void EnginePaths::prepare(CoreParameters& params) { - resourcesFolder = params.resFolder; - userFilesFolder = params.userFolder; - projectFolder = params.projectFolder; +EnginePaths::EnginePaths(CoreParameters& params) + : resourcesFolder(params.resFolder), + userFilesFolder(params.userFolder), + projectFolder(params.projectFolder) { if (!params.scriptFile.empty()) { scriptFolder = params.scriptFile.parent_path(); io::set_device("script", std::make_shared(*scriptFolder)); @@ -71,14 +71,6 @@ void EnginePaths::prepare(CoreParameters& params) { io::create_subdevice("config", "user", "config"); } -const fs::path& EnginePaths::getUserFilesFolder() const { - return userFilesFolder; -} - -const fs::path& EnginePaths::getResourcesFolder() const { - return resourcesFolder; -} - io::path EnginePaths::getNewScreenshotFile(const std::string& ext) const { auto folder = SCREENSHOTS_FOLDER; if (!io::is_directory(folder)) { @@ -107,10 +99,6 @@ io::path EnginePaths::getWorldsFolder() const { return WORLDS_FOLDER; } -io::path EnginePaths::getCurrentWorldFolder() { - return currentWorldFolder; -} - io::path EnginePaths::getWorldFolderByName(const std::string& name) { return getWorldsFolder() / name; } diff --git a/src/io/engine_paths.hpp b/src/engine/EnginePaths.hpp similarity index 81% rename from src/io/engine_paths.hpp rename to src/engine/EnginePaths.hpp index fd411db7..41d02236 100644 --- a/src/io/engine_paths.hpp +++ b/src/engine/EnginePaths.hpp @@ -1,8 +1,8 @@ #pragma once -#include "io.hpp" +#include "io/io.hpp" #include "data/dv.hpp" -#include "engine/CoreParameters.hpp" +#include "CoreParameters.hpp" #include #include @@ -46,16 +46,12 @@ class EnginePaths { public: ResPaths resPaths; - void prepare(CoreParameters& params); - - const std::filesystem::path& getUserFilesFolder() const; - const std::filesystem::path& getResourcesFolder() const; + EnginePaths(CoreParameters& params); io::path getWorldFolderByName(const std::string& name); io::path getWorldsFolder() const; void setCurrentWorldFolder(io::path folder); - io::path getCurrentWorldFolder(); io::path getNewScreenshotFile(const std::string& ext) const; std::string mount(const io::path& file); @@ -73,9 +69,9 @@ public: static inline io::path CONTROLS_FILE = "user:controls.toml"; static inline io::path SETTINGS_FILE = "user:settings.toml"; private: - std::filesystem::path userFilesFolder {"."}; - std::filesystem::path resourcesFolder {"res"}; - std::filesystem::path projectFolder = resourcesFolder; + std::filesystem::path resourcesFolder; + std::filesystem::path userFilesFolder; + std::filesystem::path projectFolder; io::path currentWorldFolder; std::optional scriptFolder; std::vector entryPoints; diff --git a/src/engine/ServerMainloop.cpp b/src/engine/ServerMainloop.cpp index 7fb8ffed..41887aee 100644 --- a/src/engine/ServerMainloop.cpp +++ b/src/engine/ServerMainloop.cpp @@ -1,6 +1,7 @@ #include "ServerMainloop.hpp" #include "Engine.hpp" +#include "EnginePaths.hpp" #include "logic/scripting/scripting.hpp" #include "logic/LevelController.hpp" #include "interfaces/Process.hpp" diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp index 8557c5be..0dabd009 100644 --- a/src/engine/WindowControl.cpp +++ b/src/engine/WindowControl.cpp @@ -1,6 +1,7 @@ #include "WindowControl.hpp" #include "Engine.hpp" +#include "engine/EnginePaths.hpp" #include "devtools/Project.hpp" #include "coders/imageio.hpp" #include "window/Window.hpp" diff --git a/src/frontend/menu.cpp b/src/frontend/menu.cpp index e46888df..372264a5 100644 --- a/src/frontend/menu.cpp +++ b/src/frontend/menu.cpp @@ -11,7 +11,7 @@ #include "graphics/ui/elements/Menu.hpp" #include "graphics/ui/gui_util.hpp" #include "interfaces/Task.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "locale.hpp" #include "logic/scripting/scripting.hpp" #include "screens/MenuScreen.hpp" diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index d398b3cc..f3694d85 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -6,6 +6,7 @@ #include "core_defs.hpp" #include "debug/Logger.hpp" #include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "assets/Assets.hpp" #include "frontend/ContentGfxCache.hpp" #include "frontend/LevelFrontend.hpp" diff --git a/src/graphics/render/Decorator.cpp b/src/graphics/render/Decorator.cpp index 94b8ee13..8bbb2c9d 100644 --- a/src/graphics/render/Decorator.cpp +++ b/src/graphics/render/Decorator.cpp @@ -19,6 +19,7 @@ #include "logic/LevelController.hpp" #include "util/stringutil.hpp" #include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "audio/audio.hpp" #include "maths/util.hpp" diff --git a/src/logic/EngineController.cpp b/src/logic/EngineController.cpp index 0d0a5a60..d6820fa1 100644 --- a/src/logic/EngineController.cpp +++ b/src/logic/EngineController.cpp @@ -4,28 +4,29 @@ #include #include -#include "engine/Engine.hpp" #include "coders/commons.hpp" -#include "debug/Logger.hpp" #include "coders/json.hpp" -#include "content/ContentReport.hpp" #include "content/ContentControl.hpp" +#include "content/ContentReport.hpp" #include "content/PacksManager.hpp" -#include "world/files/WorldConverter.hpp" -#include "world/files/WorldFiles.hpp" +#include "debug/Logger.hpp" +#include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "frontend/locale.hpp" #include "frontend/menu.hpp" #include "frontend/screens/LevelScreen.hpp" #include "frontend/screens/MenuScreen.hpp" -#include "graphics/ui/GUI.hpp" #include "graphics/ui/elements/Menu.hpp" #include "graphics/ui/gui_util.hpp" -#include "objects/Players.hpp" +#include "graphics/ui/GUI.hpp" #include "interfaces/Task.hpp" +#include "LevelController.hpp" +#include "objects/Players.hpp" #include "util/stringutil.hpp" +#include "world/files/WorldConverter.hpp" +#include "world/files/WorldFiles.hpp" #include "world/Level.hpp" #include "world/World.hpp" -#include "LevelController.hpp" static debug::Logger logger("engine-control"); diff --git a/src/logic/scripting/lua/libs/libaudio.cpp b/src/logic/scripting/lua/libs/libaudio.cpp index db868c57..606c4351 100644 --- a/src/logic/scripting/lua/libs/libaudio.cpp +++ b/src/logic/scripting/lua/libs/libaudio.cpp @@ -1,6 +1,7 @@ #include "audio/audio.hpp" #include "assets/Assets.hpp" #include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "api_lua.hpp" inline const char* DEFAULT_CHANNEL = "regular"; diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 9f14e2a0..34c33d6d 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -8,7 +8,7 @@ #include "content/Content.hpp" #include "content/ContentControl.hpp" #include "engine/Engine.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "io/settings_io.hpp" #include "frontend/menu.hpp" diff --git a/src/logic/scripting/lua/libs/libentity.cpp b/src/logic/scripting/lua/libs/libentity.cpp index 26d3ea61..3b9730c2 100644 --- a/src/logic/scripting/lua/libs/libentity.cpp +++ b/src/logic/scripting/lua/libs/libentity.cpp @@ -2,6 +2,7 @@ #include "content/Content.hpp" #include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "objects/Entities.hpp" #include "objects/EntityDef.hpp" #include "objects/Entity.hpp" diff --git a/src/logic/scripting/lua/libs/libfile.cpp b/src/logic/scripting/lua/libs/libfile.cpp index 28ed5a6e..c3ee4bdb 100644 --- a/src/logic/scripting/lua/libs/libfile.cpp +++ b/src/logic/scripting/lua/libs/libfile.cpp @@ -3,7 +3,7 @@ #include "coders/gzip.hpp" #include "engine/Engine.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "io/devices/ZipFileDevice.hpp" #include "util/stringutil.hpp" diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index 5c060382..49407022 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -9,6 +9,7 @@ #include "content/Content.hpp" #include "content/ContentControl.hpp" #include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "../lua_custom_types.hpp" using namespace scripting; diff --git a/src/logic/scripting/lua/libs/libpack.cpp b/src/logic/scripting/lua/libs/libpack.cpp index f23e96b3..b7162b4d 100644 --- a/src/logic/scripting/lua/libs/libpack.cpp +++ b/src/logic/scripting/lua/libs/libpack.cpp @@ -10,7 +10,7 @@ #include "graphics/ui/elements/Menu.hpp" #include "frontend/locale.hpp" #include "world/files/WorldFiles.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "world/Level.hpp" #include "world/World.hpp" #include "api_lua.hpp" diff --git a/src/logic/scripting/lua/libs/libworld.cpp b/src/logic/scripting/lua/libs/libworld.cpp index 41778204..eb966f50 100644 --- a/src/logic/scripting/lua/libs/libworld.cpp +++ b/src/logic/scripting/lua/libs/libworld.cpp @@ -10,7 +10,7 @@ #include "content/ContentControl.hpp" #include "engine/Engine.hpp" #include "world/files/WorldFiles.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "lighting/Lighting.hpp" #include "voxels/Chunk.hpp" diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index 08d2eb85..324b3d3b 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -4,7 +4,7 @@ #include #include "io/io.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "debug/Logger.hpp" #include "util/stringutil.hpp" #include "libs/api_lua.hpp" diff --git a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp index 3e015b72..2800035a 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_heightmap.cpp @@ -13,6 +13,7 @@ #include "graphics/core/ImageData.hpp" #include "maths/Heightmap.hpp" #include "engine/Engine.hpp" +#include "engine/EnginePaths.hpp" #include "../lua_util.hpp" using namespace lua; diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 586feeb8..b9efda4b 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -9,7 +9,7 @@ #include "content/ContentControl.hpp" #include "debug/Logger.hpp" #include "engine/Engine.hpp" -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "io/io.hpp" #include "frontend/UiDocument.hpp" #include "items/Inventory.hpp" diff --git a/src/util/command_line.cpp b/src/util/command_line.cpp index 3691b77b..7cb3614e 100644 --- a/src/util/command_line.cpp +++ b/src/util/command_line.cpp @@ -6,7 +6,7 @@ #include #include -#include "io/engine_paths.hpp" +#include "engine/EnginePaths.hpp" #include "util/ArgsReader.hpp" #include "engine/Engine.hpp" From 7fc3703ad2f72e31e27dce95404a2f58a59f098f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 22:22:24 +0300 Subject: [PATCH 07/14] feat: refresh on demand in menu (adaptive framerate) --- src/engine/Engine.cpp | 6 +++--- src/engine/Engine.hpp | 2 +- src/engine/Mainloop.cpp | 4 +++- src/engine/WindowControl.cpp | 19 ++++++++++++------- src/engine/WindowControl.hpp | 2 +- src/window/Window.hpp | 5 +++++ src/window/detail/GLFWWindow.cpp | 32 ++++++++++++++++++++++++++++++-- src/window/input.hpp | 2 +- 8 files changed, 56 insertions(+), 16 deletions(-) diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index b892908c..4cd7a316 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -255,8 +255,8 @@ void Engine::updateFrontend() { gui->postAct(); } -void Engine::nextFrame() { - windowControl->nextFrame(); +void Engine::nextFrame(bool waitForRefresh) { + windowControl->nextFrame(waitForRefresh); } void Engine::startPauseLoop() { @@ -275,7 +275,7 @@ void Engine::startPauseLoop() { if (isHeadless()) { platform::sleep(1.0 / params.tps * 1000); } else { - nextFrame(); + nextFrame(false); } } if (initialCursorLocked) { diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 58a79f95..6b09b2ca 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -99,7 +99,7 @@ public: void applicationTick(); void updateFrontend(); void renderFrame(); - void nextFrame(); + void nextFrame(bool waitForRefresh); void startPauseLoop(); /// @brief Set screen (scene). diff --git a/src/engine/Mainloop.cpp b/src/engine/Mainloop.cpp index 5435e983..e87bc7d9 100644 --- a/src/engine/Mainloop.cpp +++ b/src/engine/Mainloop.cpp @@ -45,7 +45,9 @@ void Mainloop::run() { engine.renderFrame(); } engine.postUpdate(); - engine.nextFrame(); + engine.nextFrame( + dynamic_cast(engine.getScreen().get()) != nullptr + ); } logger.info() << "main loop stopped"; } diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp index 0dabd009..637f4899 100644 --- a/src/engine/WindowControl.cpp +++ b/src/engine/WindowControl.cpp @@ -8,6 +8,7 @@ #include "window/input.hpp" #include "debug/Logger.hpp" #include "graphics/core/ImageData.hpp" +#include "util/platform.hpp" static debug::Logger logger("window-control"); @@ -78,15 +79,19 @@ void WindowControl::toggleFullscreen() { } } -void WindowControl::nextFrame() { +void WindowControl::nextFrame(bool waitForRefresh) { const auto& settings = engine.getSettings(); auto& window = engine.getWindow(); auto& input = engine.getInput(); - window.setFramerate( - window.isIconified() && settings.display.limitFpsIconified.get() - ? 20 - : settings.display.framerate.get() - ); + if (waitForRefresh) { + window.setFramerate(Window::FPS_UNLIMITED); + } else { + window.setFramerate( + window.isIconified() && settings.display.limitFpsIconified.get() + ? 20 + : settings.display.framerate.get() + ); + } window.swapBuffers(); - input.pollEvents(); + input.pollEvents(waitForRefresh); } diff --git a/src/engine/WindowControl.hpp b/src/engine/WindowControl.hpp index f3b7c8bc..2bea138e 100644 --- a/src/engine/WindowControl.hpp +++ b/src/engine/WindowControl.hpp @@ -16,7 +16,7 @@ public: Result initialize(); - void nextFrame(); + void nextFrame(bool waitForRefresh); void saveScreenshot(); diff --git a/src/window/Window.hpp b/src/window/Window.hpp index 135e4f7d..71004470 100644 --- a/src/window/Window.hpp +++ b/src/window/Window.hpp @@ -18,6 +18,8 @@ enum class WindowMode { class Window { public: + static inline constexpr int FPS_UNLIMITED = 0; + Window(glm::ivec2 size) : size(std::move(size)) {} virtual ~Window() = default; @@ -40,6 +42,9 @@ public: virtual void popScissor() = 0; virtual void resetScissor() = 0; + virtual void setShouldRefresh() = 0; + virtual bool checkShouldRefresh() = 0; + virtual double time() = 0; virtual void setFramerate(int framerate) = 0; diff --git a/src/window/detail/GLFWWindow.cpp b/src/window/detail/GLFWWindow.cpp index 27f56d3c..a80c10e0 100644 --- a/src/window/detail/GLFWWindow.cpp +++ b/src/window/detail/GLFWWindow.cpp @@ -180,14 +180,18 @@ public: : window(window) { } - void pollEvents() override { + void pollEvents(bool waitForRefresh) override { delta.x = 0.0f; delta.y = 0.0f; scroll = 0; currentFrame++; codepoints.clear(); pressedKeys.clear(); - glfwPollEvents(); + if (waitForRefresh) { + glfwWaitEvents(); + } else { + glfwPollEvents(); + } for (auto& [_, binding] : bindings.getAll()) { if (!binding.enabled) { @@ -377,6 +381,18 @@ public: prevSwap = time(); } + void setShouldRefresh() override { + shouldRefresh = true; + } + + bool checkShouldRefresh() override { + if (shouldRefresh) { + shouldRefresh = false; + return true; + } + return false; + } + bool isMaximized() const override { return glfwGetWindowAttrib(window, GLFW_MAXIMIZED); } @@ -557,12 +573,14 @@ private: double prevSwap = 0.0; int posX = 0; int posY = 0; + bool shouldRefresh = true; }; static_assert(!std::is_abstract()); static void mouse_button_callback(GLFWwindow* window, int button, int action, int) { auto handler = static_cast(glfwGetWindowUserPointer(window)); handler->input.onMouseCallback(button, action == GLFW_PRESS); + handler->setShouldRefresh(); } static void character_callback(GLFWwindow* window, unsigned int codepoint) { @@ -574,6 +592,8 @@ static void key_callback( GLFWwindow* window, int key, int /*scancode*/, int action, int /*mode*/ ) { auto handler = static_cast(glfwGetWindowUserPointer(window)); + handler->setShouldRefresh(); + auto& input = handler->input; if (key == GLFW_KEY_UNKNOWN) { return; @@ -599,11 +619,13 @@ static void window_size_callback(GLFWwindow* window, int width, int height) { static void scroll_callback(GLFWwindow* window, double, double yoffset) { auto handler = static_cast(glfwGetWindowUserPointer(window)); handler->input.scroll += yoffset; + handler->setShouldRefresh(); } static void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos) { auto handler = static_cast(glfwGetWindowUserPointer(window)); handler->input.setCursorPosition(xpos, ypos); + handler->setShouldRefresh(); } static void iconify_callback(GLFWwindow* window, int iconified) { @@ -629,6 +651,11 @@ static void create_standard_cursors() { } } +static void refresh_callback(GLFWwindow* window) { + auto handler = static_cast(glfwGetWindowUserPointer(window)); + handler->setShouldRefresh(); +} + static void setup_callbacks(GLFWwindow* window) { glfwSetKeyCallback(window, key_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); @@ -637,6 +664,7 @@ static void setup_callbacks(GLFWwindow* window) { glfwSetCharCallback(window, character_callback); glfwSetScrollCallback(window, scroll_callback); glfwSetWindowIconifyCallback(window, iconify_callback); + glfwSetWindowRefreshCallback(window, refresh_callback); } std::tuple< diff --git a/src/window/input.hpp b/src/window/input.hpp index 2edfe4c7..84c12040 100644 --- a/src/window/input.hpp +++ b/src/window/input.hpp @@ -261,7 +261,7 @@ class Input { public: virtual ~Input() = default; - virtual void pollEvents() = 0; + virtual void pollEvents(bool waitForRefresh) = 0; virtual const char* getClipboardText() const = 0; virtual void setClipboardText(const char* str) = 0; From 50d520e747e346d940bcd47674baab23d9cf139c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 22:27:37 +0300 Subject: [PATCH 08/14] fix: container:setInterval in menu screen --- src/graphics/ui/elements/Container.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index b930d76a..77ed5dd3 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -2,6 +2,8 @@ #include "graphics/core/DrawContext.hpp" #include "graphics/core/Batch2D.hpp" +#include "window/Window.hpp" +#include "../GUI.hpp" #include #include @@ -87,9 +89,12 @@ void Container::act(float delta) { } } } + GUI& gui = this->gui; intervalEvents.erase(std::remove_if( intervalEvents.begin(), intervalEvents.end(), - [](const IntervalEvent& event) { + [&gui](const IntervalEvent& event) { + // TODO: make it interval-based + gui.getWindow().setShouldRefresh(); return event.repeat == 0; } ), intervalEvents.end()); From 0e6fb878bf0b20149c56d165eeb6c4ec1d6bf3a4 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 9 Nov 2025 23:04:50 +0300 Subject: [PATCH 09/14] add app.reset_content 'non_reset_packs' optional argument --- res/scripts/stdmin.lua | 23 ++++++++++++++++++++++- src/content/ContentControl.cpp | 6 ++---- src/content/ContentControl.hpp | 2 +- src/engine/Engine.cpp | 1 + src/frontend/screens/MenuScreen.cpp | 2 +- src/logic/scripting/lua/libs/libcore.cpp | 11 ++++++++++- src/logic/scripting/scripting.cpp | 12 ++++++++++-- src/logic/scripting/scripting.hpp | 2 +- src/window/detail/GLFWWindow.cpp | 6 +++--- 9 files changed, 51 insertions(+), 14 deletions(-) diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index df5c7ce2..362e9a41 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -742,15 +742,36 @@ function require(path) return __load_script(prefix .. ":modules/" .. file .. ".lua", nil, env) end -function __scripts_cleanup() +-- TODO: move to string +local function join(t, sep) + local s = "" + for i, v in ipairs(t) do + s = s..tostring(v) + if i < #t then + s = s..sep + end + end + return s +end + +function __scripts_cleanup(non_reset_packs) debug.log("cleaning scripts cache") + if #non_reset_packs == 0 then + debug.log("no non-reset packs") + else + debug.log("non-reset packs: "..join(non_reset_packs, ", ")) + end for k, v in pairs(__cached_scripts) do local packname, _ = parse_path(k) + if table.has(non_reset_packs, packname) then + goto continue + end if packname ~= "core" then debug.log("unloaded "..k) __cached_scripts[k] = nil package.loaded[k] = nil end + ::continue:: end end diff --git a/src/content/ContentControl.cpp b/src/content/ContentControl.cpp index 6140c3d2..c887baa6 100644 --- a/src/content/ContentControl.cpp +++ b/src/content/ContentControl.cpp @@ -49,10 +49,10 @@ std::vector& ContentControl::getBasePacks() { return basePacks; } -void ContentControl::resetContent() { +void ContentControl::resetContent(const std::vector& nonReset) { paths.setCurrentWorldFolder(""); - scripting::cleanup(); + scripting::cleanup(nonReset); std::vector resRoots; { auto pack = ContentPack::createCore(); @@ -79,8 +79,6 @@ void ContentControl::loadContent(const std::vector& names) { } void ContentControl::loadContent() { - scripting::cleanup(); - std::vector names; for (auto& pack : contentPacks) { names.push_back(pack.id); diff --git a/src/content/ContentControl.hpp b/src/content/ContentControl.hpp index ef45a04a..f066601e 100644 --- a/src/content/ContentControl.hpp +++ b/src/content/ContentControl.hpp @@ -34,7 +34,7 @@ public: std::vector& getBasePacks(); /// @brief Reset content to base packs list - void resetContent(); + void resetContent(const std::vector& nonReset); void loadContent(const std::vector& names); diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 4cd7a316..6598562f 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -394,6 +394,7 @@ void Engine::setScreen(std::shared_ptr screen) { } if (project->clientScript && this->screen) { project->clientScript->onScreenChange(this->screen->getName(), true); + window->setShouldRefresh(); } } diff --git a/src/frontend/screens/MenuScreen.cpp b/src/frontend/screens/MenuScreen.cpp index e1015e8c..6472578d 100644 --- a/src/frontend/screens/MenuScreen.cpp +++ b/src/frontend/screens/MenuScreen.cpp @@ -26,7 +26,7 @@ MenuScreen::MenuScreen(Engine& engine) MenuScreen::~MenuScreen() = default; void MenuScreen::onOpen() { - engine.getContentControl().resetContent(); + engine.getContentControl().resetContent({}); auto menu = engine.getGUI().getMenu(); menu->reset(); diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 34c33d6d..8f8a7bc8 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -43,7 +43,16 @@ static int l_reset_content(lua::State* L) { if (level != nullptr) { throw std::runtime_error("world must be closed before"); } - content_control->resetContent(); + std::vector nonResetPacks; + if (lua::istable(L, 1)) { + int len = lua::objlen(L, 1); + for (int i = 0; i < len; i++) { + lua::rawgeti(L, i + 1, 1); + nonResetPacks.emplace_back(lua::require_lstring(L, -1)); + lua::pop(L); + } + } + content_control->resetContent(std::move(nonResetPacks)); return 0; } diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index b9efda4b..f3135c1c 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -348,10 +348,13 @@ void scripting::on_world_quit() { scripting::controller = nullptr; } -void scripting::cleanup() { +void scripting::cleanup(const std::vector& nonReset) { auto L = lua::get_main_state(); lua::requireglobal(L, "pack"); for (auto& pack : content_control->getAllContentPacks()) { + if (std::find(nonReset.begin(), nonReset.end(), pack.id) != nonReset.end()) { + continue; + } lua::requirefield(L, "unload"); lua::pushstring(L, pack.id); lua::call_nothrow(L, 1); @@ -359,7 +362,12 @@ void scripting::cleanup() { lua::pop(L); if (lua::getglobal(L, "__scripts_cleanup")) { - lua::call_nothrow(L, 0); + lua::createtable(L, nonReset.size(), 0); + for (size_t i = 0; i < nonReset.size(); i++) { + lua::pushstring(L, nonReset[i]); + lua::rawseti(L, i + 1); + } + lua::call_nothrow(L, 1); } } diff --git a/src/logic/scripting/scripting.hpp b/src/logic/scripting/scripting.hpp index d9c7e614..a096e9cc 100644 --- a/src/logic/scripting/scripting.hpp +++ b/src/logic/scripting/scripting.hpp @@ -82,7 +82,7 @@ namespace scripting { void on_world_tick(int tps); void on_world_save(); void on_world_quit(); - void cleanup(); + void cleanup(const std::vector& nonReset); void on_blocks_tick(const Block& block, int tps); void update_block(const Block& block, const glm::ivec3& pos); void random_update_block(const Block& block, const glm::ivec3& pos); diff --git a/src/window/detail/GLFWWindow.cpp b/src/window/detail/GLFWWindow.cpp index a80c10e0..5fa8865f 100644 --- a/src/window/detail/GLFWWindow.cpp +++ b/src/window/detail/GLFWWindow.cpp @@ -382,11 +382,11 @@ public: } void setShouldRefresh() override { - shouldRefresh = true; + shouldRefresh = 2; } bool checkShouldRefresh() override { - if (shouldRefresh) { + if ((--shouldRefresh) == 0) { shouldRefresh = false; return true; } @@ -573,7 +573,7 @@ private: double prevSwap = 0.0; int posX = 0; int posY = 0; - bool shouldRefresh = true; + int shouldRefresh = 1; }; static_assert(!std::is_abstract()); From be5a9077ca1e7ea9029096bfb956fda4b22de1f9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 10 Nov 2025 00:16:06 +0300 Subject: [PATCH 10/14] fix --- src/engine/WindowControl.cpp | 2 +- src/window/detail/GLFWWindow.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp index 637f4899..a44a410d 100644 --- a/src/engine/WindowControl.cpp +++ b/src/engine/WindowControl.cpp @@ -93,5 +93,5 @@ void WindowControl::nextFrame(bool waitForRefresh) { ); } window.swapBuffers(); - input.pollEvents(waitForRefresh); + input.pollEvents(waitForRefresh && !window.checkShouldRefresh()); } diff --git a/src/window/detail/GLFWWindow.cpp b/src/window/detail/GLFWWindow.cpp index 5fa8865f..a80c10e0 100644 --- a/src/window/detail/GLFWWindow.cpp +++ b/src/window/detail/GLFWWindow.cpp @@ -382,11 +382,11 @@ public: } void setShouldRefresh() override { - shouldRefresh = 2; + shouldRefresh = true; } bool checkShouldRefresh() override { - if ((--shouldRefresh) == 0) { + if (shouldRefresh) { shouldRefresh = false; return true; } @@ -573,7 +573,7 @@ private: double prevSwap = 0.0; int posX = 0; int posY = 0; - int shouldRefresh = 1; + bool shouldRefresh = true; }; static_assert(!std::is_abstract()); From 7a4eb87195accc4c24d1680854388e24fe9e2734 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 10 Nov 2025 00:20:32 +0300 Subject: [PATCH 11/14] fix --- src/graphics/ui/elements/Container.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index 77ed5dd3..8d45c2a1 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -79,6 +79,10 @@ void Container::act(float delta) { node->act(delta); } } + if (!intervalEvents.empty()) { + // TODO: make it interval-based + gui.getWindow().setShouldRefresh(); + } for (IntervalEvent& event : intervalEvents) { event.timer += delta; if (event.timer > event.interval) { @@ -93,8 +97,6 @@ void Container::act(float delta) { intervalEvents.erase(std::remove_if( intervalEvents.begin(), intervalEvents.end(), [&gui](const IntervalEvent& event) { - // TODO: make it interval-based - gui.getWindow().setShouldRefresh(); return event.repeat == 0; } ), intervalEvents.end()); From 630e75c7d9090f454ef69fbe79a75fc852648218 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 10 Nov 2025 00:25:38 +0300 Subject: [PATCH 12/14] make adaptive menu fps optional ('display.adaptive-menu-fps' flag) --- src/engine/Mainloop.cpp | 2 ++ src/io/settings_io.cpp | 1 + src/settings.hpp | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/engine/Mainloop.cpp b/src/engine/Mainloop.cpp index e87bc7d9..d6ca17cb 100644 --- a/src/engine/Mainloop.cpp +++ b/src/engine/Mainloop.cpp @@ -18,6 +18,7 @@ Mainloop::Mainloop(Engine& engine) : engine(engine) { void Mainloop::run() { auto& time = engine.getTime(); auto& window = engine.getWindow(); + auto& settings = engine.getSettings(); engine.setLevelConsumer([this](auto level, int64_t localPlayer) { if (level == nullptr) { @@ -46,6 +47,7 @@ void Mainloop::run() { } engine.postUpdate(); engine.nextFrame( + settings.display.adaptiveFpsInMenu.get() && dynamic_cast(engine.getScreen().get()) != nullptr ); } diff --git a/src/io/settings_io.cpp b/src/io/settings_io.cpp index 5e1c8327..f4e89338 100644 --- a/src/io/settings_io.cpp +++ b/src/io/settings_io.cpp @@ -51,6 +51,7 @@ SettingsHandler::SettingsHandler(EngineSettings& settings) { builder.add("framerate", &settings.display.framerate); builder.add("limit-fps-iconified", &settings.display.limitFpsIconified); builder.add("window-mode", &settings.display.windowMode); + builder.add("adaptive-menu-fps", &settings.display.adaptiveFpsInMenu); builder.section("camera"); builder.add("sensitivity", &settings.camera.sensitivity); diff --git a/src/settings.hpp b/src/settings.hpp index f97fb513..ee35d5a4 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -31,6 +31,8 @@ struct DisplaySettings { IntegerSetting framerate {-1, -1, 120}; /// @brief Limit framerate when window is iconified FlagSetting limitFpsIconified {false}; + /// @brief Adaptive framerate in menu (experimental) + FlagSetting adaptiveFpsInMenu {false}; }; struct ChunksSettings { From b0d662f84555c6984bb590b97e32ea293c859040 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 10 Nov 2025 00:34:01 +0300 Subject: [PATCH 13/14] limit adaptive fps to display.framerate setting --- src/engine/WindowControl.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/engine/WindowControl.cpp b/src/engine/WindowControl.cpp index a44a410d..5ae96965 100644 --- a/src/engine/WindowControl.cpp +++ b/src/engine/WindowControl.cpp @@ -83,15 +83,11 @@ void WindowControl::nextFrame(bool waitForRefresh) { const auto& settings = engine.getSettings(); auto& window = engine.getWindow(); auto& input = engine.getInput(); - if (waitForRefresh) { - window.setFramerate(Window::FPS_UNLIMITED); - } else { - window.setFramerate( - window.isIconified() && settings.display.limitFpsIconified.get() - ? 20 - : settings.display.framerate.get() - ); - } + window.setFramerate( + window.isIconified() && settings.display.limitFpsIconified.get() + ? 20 + : settings.display.framerate.get() + ); window.swapBuffers(); input.pollEvents(waitForRefresh && !window.checkShouldRefresh()); } From a4461a7dc3a678fe8954772bcd57dee0f4b41822 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 10 Nov 2025 12:23:35 +0300 Subject: [PATCH 14/14] update non-reset-packs semantics --- res/scripts/stdlib.lua | 1 - res/scripts/stdmin.lua | 1 + src/logic/scripting/lua/lua_util.cpp | 16 ++++++++++++++++ src/logic/scripting/lua/lua_util.hpp | 1 + src/logic/scripting/scripting.cpp | 13 +++++++++---- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 7d551a4a..eedc9d43 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -186,7 +186,6 @@ events = require "core:internal/events" function pack.unload(prefix) events.remove_by_prefix(prefix) - __vc__pack_envs[prefix] = nil end function __vc_start_app_script(path) diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 362e9a41..ea425748 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -771,6 +771,7 @@ function __scripts_cleanup(non_reset_packs) __cached_scripts[k] = nil package.loaded[k] = nil end + __vc__pack_envs[packname] = nil ::continue:: end end diff --git a/src/logic/scripting/lua/lua_util.cpp b/src/logic/scripting/lua/lua_util.cpp index 401255c7..1f0bfd99 100644 --- a/src/logic/scripting/lua/lua_util.cpp +++ b/src/logic/scripting/lua/lua_util.cpp @@ -336,6 +336,22 @@ int lua::create_environment(State* L, int parent) { return id; } +int lua::restore_pack_environment(lua::State* L, const std::string& packid) { + if(!lua::getglobal(L, "__vc__pack_envs")) { + return -1; + } + int id = nextEnvironment++; + + if (lua::getfield(L, packid)) { + // envname = env + setglobal(L, env_name(id)); + lua::pop(L); + return id; + } + lua::pop(L); + return -1; +} + void lua::remove_environment(State* L, int id) { if (id == 0) { return; diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index a8fb246e..9e543a0a 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -614,6 +614,7 @@ namespace lua { return 0; } int create_environment(lua::State*, int parent); + int restore_pack_environment(lua::State*, const std::string& packid); void remove_environment(lua::State*, int id); inline void close(lua::State* L) { diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index f3135c1c..8fe88d39 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -173,7 +173,15 @@ std::unique_ptr scripting::start_app_script(const io::path& script) { const ContentPack& pack ) { auto L = lua::get_main_state(); - int id = lua::create_environment(L, 0); + int id = lua::restore_pack_environment(L, pack.id); + if (id != -1) { + return std::shared_ptr(new int(id), [=](int* id) { //-V508 + lua::remove_environment(L, *id); + delete id; + }); + } + id = lua::create_environment(L, 0); + lua::pushenv(L, id); lua::pushvalue(L, -1); lua::setfield(L, "PACK_ENV"); @@ -352,9 +360,6 @@ void scripting::cleanup(const std::vector& nonReset) { auto L = lua::get_main_state(); lua::requireglobal(L, "pack"); for (auto& pack : content_control->getAllContentPacks()) { - if (std::find(nonReset.begin(), nonReset.end(), pack.id) != nonReset.end()) { - continue; - } lua::requirefield(L, "unload"); lua::pushstring(L, pack.id); lua::call_nothrow(L, 1);