From 6cdd6b833cd8e0d9e2dbdfdfb486d261c2705d62 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 6 Jan 2026 23:13:17 +0300 Subject: [PATCH 01/16] feat: debugging server does not require network permission now --- src/engine/Engine.cpp | 3 ++- src/logic/scripting/lua/libs/libapp.cpp | 6 ++++++ src/logic/scripting/lua/libs/libnetwork.cpp | 8 +++++--- src/util/platform.cpp | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 5cb0e7ca6..5223a6c38 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -139,7 +139,8 @@ void Engine::initialize(CoreParameters coreParameters) { editor = std::make_unique(*this); cmd = std::make_unique(); - if (project->permissions.has(Permissions::NETWORK)) { + if (project->permissions.has(Permissions::NETWORK) || + !params.debugServerString.empty()) { network = network::Network::create(settings.network); } diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index d23f96cb0..c40aa63bd 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -29,6 +29,7 @@ static int l_start_debug_instance(lua::State* L) { throw std::runtime_error("could not find free port"); } } + auto projectPath = lua::isstring(L, 2) ? lua::require_lstring(L, 2) : ""; const auto& paths = engine->getPaths(); std::vector args { @@ -36,6 +37,11 @@ static int l_start_debug_instance(lua::State* L) { "--dir", paths.getUserFilesFolder().u8string(), "--dbg-server", "tcp:" + std::to_string(port), }; + if (!projectPath.empty()) { + args.emplace_back("--project"); + args.emplace_back(io::resolve(std::string(projectPath)).string()); + } + platform::new_engine_instance(std::move(args)); return lua::pushinteger(L, port); } diff --git a/src/logic/scripting/lua/libs/libnetwork.cpp b/src/logic/scripting/lua/libs/libnetwork.cpp index 390845207..7fbf6df8d 100644 --- a/src/logic/scripting/lua/libs/libnetwork.cpp +++ b/src/logic/scripting/lua/libs/libnetwork.cpp @@ -2,6 +2,7 @@ #include "coders/json.hpp" #include "engine/Engine.hpp" #include "network/Network.hpp" +#include "devtools/Project.hpp" #include #include @@ -439,7 +440,7 @@ static int l_is_nodelay(lua::State* L, network::Network& network) { return lua::pushboolean(L, false); } -static int l_pull_events(lua::State* L, network::Network& network) { +static int l_pull_events(lua::State* L) { std::vector local_queue; { std::lock_guard lock(events_queue_mutex); @@ -528,7 +529,8 @@ int wrap(lua_State* L) { int result = 0; try { auto network = engine->getNetwork(); - if (network == nullptr) { + const auto& permissions = engine->getProject().permissions; + if (network == nullptr || !permissions.has(Permissions::NETWORK)) { throw std::runtime_error( "network subsystem is not available in the project" ); @@ -554,7 +556,7 @@ const luaL_Reg networklib[] = { {"get_total_download", wrap}, {"find_free_port", wrap}, {"is_available", lua::wrap}, - {"__pull_events", wrap}, + {"__pull_events", lua::wrap}, {"__open_tcp", wrap}, {"__open_udp", wrap}, {"__closeserver", wrap}, diff --git a/src/util/platform.cpp b/src/util/platform.cpp index dce6f89b7..a7ba041db 100644 --- a/src/util/platform.cpp +++ b/src/util/platform.cpp @@ -281,6 +281,7 @@ void platform::new_engine_instance(const std::vector& args) { ss << " >/dev/null &"; auto command = ss.str(); + logger.info() << command; if (int res = system(command.c_str())) { throw std::runtime_error( "starting an engine instance failed with code: " + From 9f39f8dbadf0506d4f8f374376a2c7d6ede90e23 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 6 Jan 2026 23:59:12 +0300 Subject: [PATCH 02/16] feat: disable app.load_content out of app script coroutine --- res/scripts/stdlib.lua | 141 ++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 64 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 1a8954172..7aabc20c7 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -30,6 +30,10 @@ function core.set_setting(name, value, ...) events.emit("core:setting."..name..".set", value) end +local __vc__app_script_coroutine +local __core_load_content = core.load_content +core.load_content = nil + local function complete_app_lib(app) app.sleep = sleep app.script = __VC_SCRIPT_NAME @@ -45,11 +49,16 @@ local function complete_app_lib(app) app.tick = function() coroutine.yield() end + + local __app_tick = app.tick app.get_version = core.get_version app.get_setting_info = core.get_setting_info app.load_content = function() - core.load_content() - app.tick() + if coroutine.running() ~= __vc__app_script_coroutine then + error("content must be reload in application script coroutine") + end + __core_load_content() + __app_tick() end app.reset_content = core.reset_content app.is_content_loaded = core.is_content_loaded @@ -123,6 +132,66 @@ function pack.unload(prefix) events.remove_by_prefix(prefix) end +local __vc_coroutines = {} +local __vc_named_coroutines = {} +local __vc_next_coroutine = 1 + +function __vc_start_coroutine(chunk) + local co = coroutine.create(chunk) + local id = __vc_next_coroutine + __vc_next_coroutine = __vc_next_coroutine + 1 + __vc_coroutines[id] = co + return id +end + +function __vc_resume_coroutine(id) + local co = __vc_coroutines[id] + if co then + local success, err = coroutine.resume(co) + if not success then + debug.error(err) + error(err) + end + return coroutine.status(co) ~= "dead" + end + return false +end + +function __vc_stop_coroutine(id) + local co = __vc_coroutines[id] + if co then + if coroutine.close then + coroutine.close(co) + end + __vc_coroutines[id] = nil + end +end + +function start_coroutine(chunk, name) + local co = coroutine.create(function() + local status, error = xpcall(chunk, function(err) + local fullmsg = "error: "..string.match(err, ": (.+)").."\n"..debug.traceback() + + if hud then + gui.alert(fullmsg, function() + if world.is_open() then + __vc_app.close_world() + else + __vc_app.reset_content() + menu:reset() + menu.page = "main" + end + end) + end + return fullmsg + end) + if not status then + debug.error(error) + end + end) + __vc_named_coroutines[name] = co +end + function __vc_start_app_script(path, name) debug.log("starting application script "..path) @@ -134,9 +203,13 @@ function __vc_start_app_script(path, name) local script_env = setmetatable({app = app or __vc_app}, {__index=_G}) chunk = setfenv(chunk, script_env) if name then - return start_coroutine(chunk, name) + start_coroutine(chunk, name) + __vc__app_script_coroutine = __vc_named_coroutines[name] + return else - return __vc_start_coroutine(chunk) + local id = __vc_start_coroutine(chunk) + __vc__app_script_coroutine = __vc_coroutines[id] + return id end end @@ -435,66 +508,6 @@ function __vc_on_world_quit() file.__close_all_descriptors() end -local __vc_coroutines = {} -local __vc_named_coroutines = {} -local __vc_next_coroutine = 1 - -function __vc_start_coroutine(chunk) - local co = coroutine.create(chunk) - local id = __vc_next_coroutine - __vc_next_coroutine = __vc_next_coroutine + 1 - __vc_coroutines[id] = co - return id -end - -function __vc_resume_coroutine(id) - local co = __vc_coroutines[id] - if co then - local success, err = coroutine.resume(co) - if not success then - debug.error(err) - error(err) - end - return coroutine.status(co) ~= "dead" - end - return false -end - -function __vc_stop_coroutine(id) - local co = __vc_coroutines[id] - if co then - if coroutine.close then - coroutine.close(co) - end - __vc_coroutines[id] = nil - end -end - -function start_coroutine(chunk, name) - local co = coroutine.create(function() - local status, error = xpcall(chunk, function(err) - local fullmsg = "error: "..string.match(err, ": (.+)").."\n"..debug.traceback() - - if hud then - gui.alert(fullmsg, function() - if world.is_open() then - __vc_app.close_world() - else - __vc_app.reset_content() - menu:reset() - menu.page = "main" - end - end) - end - return fullmsg - end) - if not status then - debug.error(error) - end - end) - __vc_named_coroutines[name] = co -end - local __post_runnables = {} local fn_audio_reset_fetch_buffer = audio.__reset_fetch_buffer From 9d4a48096e6c4003c4f0a88a4cb23df812c2b26b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 00:07:17 +0300 Subject: [PATCH 03/16] feat: disable app.reset_content out of app script coroutine --- res/scripts/stdlib.lua | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 7aabc20c7..ac073df25 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -31,10 +31,14 @@ function core.set_setting(name, value, ...) end local __vc__app_script_coroutine -local __core_load_content = core.load_content -core.load_content = nil local function complete_app_lib(app) + local __core_load_content = core.load_content + local __core_reset_content = core.reset_content + local __app_tick = coroutine.yield + core.load_content = nil + core.reset_content = nil + app.sleep = sleep app.script = __VC_SCRIPT_NAME app.new_world = core.new_world @@ -46,21 +50,27 @@ local function complete_app_lib(app) app.reconfig_packs = core.reconfig_packs app.get_setting = core.get_setting app.set_setting = core.set_setting - app.tick = function() - coroutine.yield() - end - - local __app_tick = app.tick + app.tick = __app_tick app.get_version = core.get_version app.get_setting_info = core.get_setting_info - app.load_content = function() + + local function require_app_script_co() if coroutine.running() ~= __vc__app_script_coroutine then error("content must be reload in application script coroutine") end + end + + app.load_content = function() + require_app_script_co() __core_load_content() __app_tick() end - app.reset_content = core.reset_content + app.reset_content = function() + require_app_script_co() + __core_reset_content() + __app_tick() + end + app.is_content_loaded = core.is_content_loaded app.set_title = core.set_title From 43fa181398c6064fd165cd6244ed4847933cef4c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 00:19:34 +0300 Subject: [PATCH 04/16] remove core.set_title & fix app.reset_content args & update app.reconfig_packs --- res/scripts/stdlib.lua | 26 ++++++++++++------------ src/logic/scripting/lua/libs/libapp.cpp | 7 +++++++ src/logic/scripting/lua/libs/libcore.cpp | 7 ------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index ac073df25..155d95c0c 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -35,6 +35,7 @@ local __vc__app_script_coroutine local function complete_app_lib(app) local __core_load_content = core.load_content local __core_reset_content = core.reset_content + local __core_reconfig_packs = core.reconfig_packs local __app_tick = coroutine.yield core.load_content = nil core.reset_content = nil @@ -47,37 +48,36 @@ local function complete_app_lib(app) app.close_world = core.close_world app.reopen_world = core.reopen_world app.delete_world = core.delete_world - app.reconfig_packs = core.reconfig_packs app.get_setting = core.get_setting app.set_setting = core.set_setting app.tick = __app_tick app.get_version = core.get_version app.get_setting_info = core.get_setting_info - local function require_app_script_co() + local function call_in_app_script_co(func, ...) if coroutine.running() ~= __vc__app_script_coroutine then error("content must be reload in application script coroutine") end + func(...) + __app_tick() end - app.load_content = function() - require_app_script_co() - __core_load_content() - __app_tick() + app.reconfig_packs = function(...) + call_in_app_script_co(__core_reconfig_packs, ...) end - app.reset_content = function() - require_app_script_co() - __core_reset_content() - __app_tick() + app.load_content = function(...) + call_in_app_script_co(__core_load_content, ...) + end + app.reset_content = function(...) + call_in_app_script_co(__core_reset_content, ...) end app.is_content_loaded = core.is_content_loaded - app.set_title = core.set_title - + function app.config_packs(packs_list) -- Check if packs are valid and add dependencies to the configuration packs_list = pack.assemble(packs_list) - + local installed = pack.get_installed() local toremove = {} for _, packid in ipairs(installed) do diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index c40aa63bd..6d975af31 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -96,6 +96,12 @@ static int l_reset_content_sources(lua::State* L) { return 0; } +static int l_set_title(lua::State* L) { + auto title = lua::require_string(L, 1); + engine->getWindow().setTitle(title); + return 0; +} + const luaL_Reg applib[] = { {"start_debug_instance", lua::wrap}, {"focus", lua::wrap}, @@ -103,6 +109,7 @@ const luaL_Reg applib[] = { {"get_content_sources", lua::wrap}, {"set_content_sources", lua::wrap}, {"reset_content_sources", lua::wrap}, + {"set_title", lua::wrap}, // for other functions see libcore.cpp and stdlib.lua {nullptr, nullptr} }; diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index e4d5474c7..a3e0f5687 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -300,12 +300,6 @@ static int l_capture_output(lua::State* L) { return 1; } -static int l_set_title(lua::State* L) { - auto title = lua::require_string(L, 1); - engine->getWindow().setTitle(title); - return 0; -} - const luaL_Reg corelib[] = { {"blank", lua::wrap}, {"get_version", lua::wrap}, @@ -327,6 +321,5 @@ const luaL_Reg corelib[] = { {"open_url", lua::wrap}, {"quit", lua::wrap}, {"capture_output", lua::wrap}, - {"set_title", lua::wrap}, {nullptr, nullptr} }; From 1644751b1a32a3ecc2b4604e4a5a1cb00c7692bd Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 00:39:02 +0300 Subject: [PATCH 05/16] fix gui.show_input_dialog key:escape reaction --- res/modules/internal/gui_util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/modules/internal/gui_util.lua b/res/modules/internal/gui_util.lua index f9b29c193..894ca1bcc 100644 --- a/res/modules/internal/gui_util.lua +++ b/res/modules/internal/gui_util.lua @@ -161,7 +161,7 @@ function gui.show_input_dialog(text, actual_callback, validator, confirm_text) callback=callback, validator=validator or function() return #text > 0 end }) - input.add_callback("key:escape", callback, gui.root[id]) + input.add_callback("key:escape", function() gui.root[id]:destruct() end, gui.root[id]) input.add_callback("key:enter", callback, gui.root[id]) gui.root[id.."_input"].focused = true end From 37350a10bef43a462dda39a18fc56334306aadc2 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 01:36:41 +0300 Subject: [PATCH 06/16] remove pages loader from GUI class --- src/engine/Engine.cpp | 2 +- src/graphics/ui/GUI.cpp | 9 --------- src/graphics/ui/GUI.hpp | 8 -------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 5223a6c38..5a63991bb 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -178,7 +178,7 @@ void Engine::initialize(CoreParameters coreParameters) { scripting::initialize(this); if (!isHeadless()) { - gui->setPageLoader(scripting::create_page_loader()); + gui->getMenu()->setPageLoader(scripting::create_page_loader()); } keepAlive(settings.ui.language.observe([this](auto lang) { langs::setup(lang, paths->resPaths.collectRoots()); diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index dc6dd6ac5..e69c20e3b 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -67,15 +67,6 @@ GUI::GUI(Engine& engine) GUI::~GUI() = default; -void GUI::setPageLoader(PageLoaderFunc pageLoader) { - this->pagesLoader = std::move(pageLoader); - menu->setPageLoader(this->pagesLoader); -} - -PageLoaderFunc GUI::getPagesLoader() { - return pagesLoader; -} - std::shared_ptr GUI::getMenu() { return menu; } diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index 5d6140c27..a27872d76 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -62,8 +62,6 @@ namespace gui { class Container; class Menu; - using PageLoaderFunc = std::function(const std::string&)>; - /// @brief The main UI controller class GUI { Engine& engine; @@ -83,8 +81,6 @@ namespace gui { std::queue postRunnables; std::vector> mouseOver; - PageLoaderFunc pagesLoader; - float tooltipTimer = 0.0f; float doubleClickTimer = 0.0f; float doubleClickDelay = 0.5f; @@ -101,10 +97,6 @@ namespace gui { GUI(Engine& engine); ~GUI(); - void setPageLoader(PageLoaderFunc pageLoader); - - PageLoaderFunc getPagesLoader(); - /// @brief Get the main menu (Menu) node std::shared_ptr getMenu(); From d6b6c6903ae5bce82e84deba41ee2557a1ccc863 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 01:37:43 +0300 Subject: [PATCH 07/16] update Element.new --- res/modules/internal/gui_util.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/res/modules/internal/gui_util.lua b/res/modules/internal/gui_util.lua index 894ca1bcc..6d24a93a9 100644 --- a/res/modules/internal/gui_util.lua +++ b/res/modules/internal/gui_util.lua @@ -52,19 +52,21 @@ end -- class designed for simple UI-nodes access via properties syntax local Element = {} +local __gui_getattr = gui.getattr +local __gui_setattr = gui.setattr function Element.new(docname, name) return setmetatable({docname=docname, name=name}, { __index=function(self, k) - return gui.getattr(self.docname, self.name, k) + return __gui_getattr(self.docname, self.name, k) end, __newindex=function(self, k, v) - gui.setattr(self.docname, self.name, k, v) + __gui_setattr(self.docname, self.name, k, v) end, __ipairs=function(self) local i = 0 return function() i = i + 1 - local elem = gui.getattr(self.docname, self.name, i) + local elem = __gui_getattr(self.docname, self.name, i) if elem == nil then return end @@ -102,8 +104,8 @@ function RadioGroup:set(key) end function RadioGroup:__call(elements, onset, default) local group = setmetatable({ - elements=elements, - callback=onset, + elements=elements, + callback=onset, current=nil }, {__index=self}) group:set(default) From e794aa864d2ddeb3e101abfe7dae41ee1c0aaca5 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 01:54:47 +0300 Subject: [PATCH 08/16] add gui.load_document namespace extension table argument & pass app library from standard pages loader --- res/modules/internal/gui_util.lua | 2 +- src/logic/scripting/lua/libs/libgui.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/res/modules/internal/gui_util.lua b/res/modules/internal/gui_util.lua index 6d24a93a9..3309e94a0 100644 --- a/res/modules/internal/gui_util.lua +++ b/res/modules/internal/gui_util.lua @@ -34,7 +34,7 @@ function gui_util.load_page(query) local filename = file.find(string.format("layouts/pages/%s.xml", name)) if filename then name = file.prefix(filename)..":pages/"..name - gui.load_document(filename, name, args) + gui.load_document(filename, name, args, { app = __vc_app }) return name end end diff --git a/src/logic/scripting/lua/libs/libgui.cpp b/src/logic/scripting/lua/libs/libgui.cpp index 4d1506e23..cb98de7d7 100644 --- a/src/logic/scripting/lua/libs/libgui.cpp +++ b/src/logic/scripting/lua/libs/libgui.cpp @@ -1111,6 +1111,16 @@ static int l_gui_load_document(lua::State* L) { ); auto document = documentPtr.get(); engine->getAssets()->store(std::move(documentPtr), alias); + + // namespace extension + if (lua::istable(L, 4)) { + if (lua::get_from(L, "table", "merge")) { + lua::pushenv(L, *document->getEnvironment()); + lua::pushvalue(L, 4); + lua::call(L, 2, 0); + lua::pop(L); + } + } scripting::on_ui_open(document, {args}); return 0; } From 13d13e89cf3075381f6dfd5cd2cf432301113531 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 02:03:33 +0300 Subject: [PATCH 09/16] move open_folder, open_url from core to app --- res/layouts/pages/content.xml | 4 ++-- res/layouts/pages/content_menu.xml | 2 +- res/layouts/pages/settings.xml | 2 +- res/layouts/pages/worlds.xml | 2 +- src/logic/scripting/lua/libs/libapp.cpp | 30 ++++++++++++++++++++++++ src/logic/scripting/lua/libs/libcore.cpp | 30 ------------------------ 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/res/layouts/pages/content.xml b/res/layouts/pages/content.xml index dfa7b6546..63474effd 100644 --- a/res/layouts/pages/content.xml +++ b/res/layouts/pages/content.xml @@ -15,7 +15,7 @@ - @@ -38,4 +38,4 @@ - \ No newline at end of file + diff --git a/res/layouts/pages/content_menu.xml b/res/layouts/pages/content_menu.xml index 85dd54d0d..6718a3028 100644 --- a/res/layouts/pages/content_menu.xml +++ b/res/layouts/pages/content_menu.xml @@ -9,7 +9,7 @@ - diff --git a/res/layouts/pages/settings.xml b/res/layouts/pages/settings.xml index 00437e68b..68a71aa04 100644 --- a/res/layouts/pages/settings.xml +++ b/res/layouts/pages/settings.xml @@ -10,7 +10,7 @@ - + diff --git a/res/layouts/pages/worlds.xml b/res/layouts/pages/worlds.xml index a8a536a21..34fe3400c 100644 --- a/res/layouts/pages/worlds.xml +++ b/res/layouts/pages/worlds.xml @@ -3,6 +3,6 @@ - + diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index 6d975af31..1f0a45610 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -9,7 +9,12 @@ #include "devtools/Project.hpp" #include "network/Network.hpp" #include "util/platform.hpp" +#include "util/stringutil.hpp" #include "window/Window.hpp" +#include "frontend/locale.hpp" +#include "graphics/ui/GUI.hpp" +#include "graphics/ui/gui_util.hpp" +#include "graphics/ui/elements/Menu.hpp" using namespace scripting; @@ -102,6 +107,29 @@ static int l_set_title(lua::State* L) { return 0; } +static int l_open_folder(lua::State* L) { + platform::open_folder(io::resolve(lua::require_string(L, 1))); + return 0; +} + +static int l_open_url(lua::State* L) { + auto url = lua::require_string(L, 1); + + std::wstring msg = langs::get(L"Are you sure you want to open the link:") + + L"\n" + util::str2wstr_utf8(url) + + std::wstring(L"?"); + + auto menu = engine->getGUI().getMenu(); + + guiutil::confirm(*engine, msg, [url, menu]() { + platform::open_url(url); + if (!menu->back()) { + menu->reset(); + } + }); + return 0; +} + const luaL_Reg applib[] = { {"start_debug_instance", lua::wrap}, {"focus", lua::wrap}, @@ -110,6 +138,8 @@ const luaL_Reg applib[] = { {"set_content_sources", lua::wrap}, {"reset_content_sources", lua::wrap}, {"set_title", lua::wrap}, + {"open_folder", lua::wrap}, + {"open_url", lua::wrap}, // for other functions see libcore.cpp and stdlib.lua {nullptr, nullptr} }; diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index a3e0f5687..922298a58 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -20,11 +20,6 @@ #include "util/platform.hpp" #include "world/Level.hpp" #include "world/generator/WorldGenerator.hpp" -#include "util/platform.hpp" -#include "frontend/locale.hpp" -#include "graphics/ui/gui_util.hpp" -#include "graphics/ui/GUI.hpp" -#include "graphics/ui/elements/Menu.hpp" #include "window/Window.hpp" using namespace scripting; @@ -240,29 +235,6 @@ static int l_get_setting_info(lua::State* L) { throw std::runtime_error("unsupported setting type"); } -static int l_open_folder(lua::State* L) { - platform::open_folder(io::resolve(lua::require_string(L, 1))); - return 0; -} - -static int l_open_url(lua::State* L) { - auto url = lua::require_string(L, 1); - - std::wstring msg = langs::get(L"Are you sure you want to open the link:") + - L"\n" + util::str2wstr_utf8(url) + - std::wstring(L"?"); - - auto menu = engine->getGUI().getMenu(); - - guiutil::confirm(*engine, msg, [url, menu]() { - platform::open_url(url); - if (!menu->back()) { - menu->reset(); - } - }); - return 0; -} - /// @brief Quit the game static int l_quit(lua::State*) { engine->quit(); @@ -317,8 +289,6 @@ const luaL_Reg corelib[] = { {"set_setting", lua::wrap}, {"str_setting", lua::wrap}, {"get_setting_info", lua::wrap}, - {"open_folder", lua::wrap}, - {"open_url", lua::wrap}, {"quit", lua::wrap}, {"capture_output", lua::wrap}, {nullptr, nullptr} From 52600621814592357058fd50894e58d83b6d2491 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 02:10:08 +0300 Subject: [PATCH 10/16] remove core.get_version --- res/scripts/stdlib.lua | 3 ++- src/logic/scripting/lua/libs/libapp.cpp | 7 +++++++ src/logic/scripting/lua/libs/libcore.cpp | 7 ------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 155d95c0c..2ba6f73b2 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -51,7 +51,6 @@ local function complete_app_lib(app) app.get_setting = core.get_setting app.set_setting = core.set_setting app.tick = __app_tick - app.get_version = core.get_version app.get_setting_info = core.get_setting_info local function call_in_app_script_co(func, ...) @@ -585,3 +584,5 @@ require "core:internal/deprecated" ffi = nil __vc_lock_internal_modules() + +debug.print(core) diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index 1f0a45610..4cc2c302d 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -18,6 +18,12 @@ using namespace scripting; +static int l_get_version(lua::State* L) { + return lua::pushvec_stack( + L, glm::vec2(ENGINE_VERSION_MAJOR, ENGINE_VERSION_MINOR) + ); +} + static int l_start_debug_instance(lua::State* L) { if (!engine->getProject().permissions.has(Permissions::DEBUGGING)) { throw std::runtime_error("project has no debugging permission"); @@ -131,6 +137,7 @@ static int l_open_url(lua::State* L) { } const luaL_Reg applib[] = { + {"get_version", lua::wrap}, {"start_debug_instance", lua::wrap}, {"focus", lua::wrap}, {"create_memory_device", lua::wrap}, diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 922298a58..6f3056ea4 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -24,12 +24,6 @@ using namespace scripting; -static int l_get_version(lua::State* L) { - return lua::pushvec_stack( - L, glm::vec2(ENGINE_VERSION_MAJOR, ENGINE_VERSION_MINOR) - ); -} - static int l_load_content(lua::State* L) { content_control->loadContent(); return 0; @@ -274,7 +268,6 @@ static int l_capture_output(lua::State* L) { const luaL_Reg corelib[] = { {"blank", lua::wrap}, - {"get_version", lua::wrap}, {"load_content", lua::wrap}, {"reset_content", lua::wrap}, {"is_content_loaded", lua::wrap}, From a6301c88373b2ab88bb6b887e2ed185eba79234c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 02:39:29 +0300 Subject: [PATCH 11/16] remove settings-related functions from core --- res/layouts/pages/settings.xml.lua | 2 +- res/layouts/pages/settings_audio.xml.lua | 12 ++-- res/layouts/pages/settings_controls.xml.lua | 6 +- res/layouts/pages/settings_display.xml.lua | 22 +++--- res/layouts/pages/settings_graphics.xml.lua | 16 ++--- res/layouts/pages/settings_reset.xml.lua | 2 +- res/layouts/pages/worlds.xml.lua | 2 +- res/layouts/templates/language.xml | 2 +- res/layouts/templates/track_setting.xml | 2 +- res/scripts/hud.lua | 2 +- res/scripts/stdlib.lua | 17 ++--- src/logic/scripting/lua/libs/libapp.cpp | 72 +++++++++++++++++++ src/logic/scripting/lua/libs/libcore.cpp | 80 ++------------------- src/logic/scripting/lua/lua_engine.cpp | 2 + 14 files changed, 119 insertions(+), 120 deletions(-) diff --git a/res/layouts/pages/settings.xml.lua b/res/layouts/pages/settings.xml.lua index 8b41491a5..453583518 100644 --- a/res/layouts/pages/settings.xml.lua +++ b/res/layouts/pages/settings.xml.lua @@ -1,7 +1,7 @@ function on_open() document.langs_btn.text = string.format( "%s: %s", gui.str("Language", "settings"), - gui.get_locales_info()[core.get_setting("ui.language")].name + gui.get_locales_info()[app.get_setting("ui.language")].name ) sections = RadioGroup({ audio=document.s_aud, diff --git a/res/layouts/pages/settings_audio.xml.lua b/res/layouts/pages/settings_audio.xml.lua index f8a23baa9..c9b4be4b6 100644 --- a/res/layouts/pages/settings_audio.xml.lua +++ b/res/layouts/pages/settings_audio.xml.lua @@ -1,25 +1,25 @@ function create_setting(id, name, step, postfix) - local info = core.get_setting_info(id) + local info = app.get_setting_info(id) postfix = postfix or "" document.root:add(gui.template("track_setting", { id=id, name=gui.str(name, "settings"), - value=core.get_setting(id), + value=app.get_setting(id), min=info.min, max=info.max, step=step, postfix=postfix })) - update_setting(core.get_setting(id), id, name, postfix) + update_setting(app.get_setting(id), id, name, postfix) end function update_setting(x, id, name, postfix) - core.set_setting(id, x) + app.set_setting(id, x) -- updating label document[id..".L"].text = string.format( "%s: %s%s", gui.str(name, "settings"), - core.str_setting(id), + app.str_setting(id), postfix ) end @@ -54,7 +54,7 @@ function on_open() create_setting("audio.volume-music", "Music", 0.01) document.root:add("") document.root:add("".. + "", core.get_setting("display.window-mode")) + "", app.get_setting("display.window-mode")) ) create_checkbox("camera.shaking", "Camera Shaking") diff --git a/res/layouts/pages/settings_graphics.xml.lua b/res/layouts/pages/settings_graphics.xml.lua index d61057799..3b7f7b13a 100644 --- a/res/layouts/pages/settings_graphics.xml.lua +++ b/res/layouts/pages/settings_graphics.xml.lua @@ -1,12 +1,12 @@ function create_setting(id, name, step, postfix, tooltip, changeonrelease) - local info = core.get_setting_info(id) + local info = app.get_setting_info(id) postfix = postfix or "" tooltip = tooltip or "" changeonrelease = changeonrelease or "" document.root:add(gui.template("track_setting", { id=id, name=gui.str(name, "settings"), - value=core.get_setting(id), + value=app.get_setting(id), min=info.min, max=info.max, step=step, @@ -14,15 +14,15 @@ function create_setting(id, name, step, postfix, tooltip, changeonrelease) tooltip=tooltip, changeonrelease=changeonrelease })) - update_setting(core.get_setting(id), id, name, postfix) + update_setting(app.get_setting(id), id, name, postfix) end function update_setting(x, id, name, postfix) -- updating label document[id..".L"].text = string.format( - "%s: %s%s", - gui.str(name, "settings"), - core.str_setting(id), + "%s: %s%s", + gui.str(name, "settings"), + app.str_setting(id), postfix ) end @@ -30,8 +30,8 @@ end function create_checkbox(id, name, tooltip) tooltip = tooltip or '' document.root:add(string.format( - "%s", - id, core.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings") + "%s", + id, app.str_setting(id), gui.str(tooltip, "settings"), gui.str(name, "settings") )) end diff --git a/res/layouts/pages/settings_reset.xml.lua b/res/layouts/pages/settings_reset.xml.lua index a8ca2a9fc..59583eefa 100644 --- a/res/layouts/pages/settings_reset.xml.lua +++ b/res/layouts/pages/settings_reset.xml.lua @@ -11,7 +11,7 @@ function reset(category) end function reset_setting(name) - core.set_setting(name, core.get_setting_info(name).def) + app.set_setting(name, app.get_setting_info(name).def) end function reset_audio() diff --git a/res/layouts/pages/worlds.xml.lua b/res/layouts/pages/worlds.xml.lua index 1cbcd53db..748bdfb0b 100644 --- a/res/layouts/pages/worlds.xml.lua +++ b/res/layouts/pages/worlds.xml.lua @@ -1,7 +1,7 @@ function on_open() local worlds = world.get_list() for _, info in ipairs(worlds) do - local major, minor = core.get_version() + local major, minor = app.get_version() if info.version[1] > major or info.version[2] > minor then info.versionColor = "#A02010" else diff --git a/res/layouts/templates/language.xml b/res/layouts/templates/language.xml index fea34b313..692744c96 100644 --- a/res/layouts/templates/language.xml +++ b/res/layouts/templates/language.xml @@ -1,4 +1,4 @@ diff --git a/res/layouts/templates/track_setting.xml b/res/layouts/templates/track_setting.xml index 519ba334b..f01b8f842 100644 --- a/res/layouts/templates/track_setting.xml +++ b/res/layouts/templates/track_setting.xml @@ -2,6 +2,6 @@ diff --git a/res/scripts/hud.lua b/res/scripts/hud.lua index 59d8de36a..322f03db5 100644 --- a/res/scripts/hud.lua +++ b/res/scripts/hud.lua @@ -29,7 +29,7 @@ local function configure_SSAO() end events.on("core:setting.graphics.ssao.set", update_ssao_quality) - update_ssao_quality(core.get_setting("graphics.ssao")) + update_ssao_quality(__vc_app.get_setting("graphics.ssao")) end local function update_hand() diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 2ba6f73b2..d7ee98b97 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -1,4 +1,4 @@ -local enable_experimental = core.get_setting("debug.enable-experimental") +local enable_experimental = __vc_app.get_setting("debug.enable-experimental") ------------------------------------------------ ------ Extended kit of standard functions ------ @@ -24,12 +24,6 @@ function tb_frame_tostring(frame) return s end -local core_set_setting = core.set_setting -function core.set_setting(name, value, ...) - core_set_setting(name, value, ...) - events.emit("core:setting."..name..".set", value) -end - local __vc__app_script_coroutine local function complete_app_lib(app) @@ -37,6 +31,7 @@ local function complete_app_lib(app) local __core_reset_content = core.reset_content local __core_reconfig_packs = core.reconfig_packs local __app_tick = coroutine.yield + local __app_set_setting = app.set_setting core.load_content = nil core.reset_content = nil @@ -48,10 +43,12 @@ local function complete_app_lib(app) app.close_world = core.close_world app.reopen_world = core.reopen_world app.delete_world = core.delete_world - app.get_setting = core.get_setting - app.set_setting = core.set_setting + + app.set_setting = function(name, value, ...) + __app_set_setting(name, value, ...) + events.emit("core:setting."..name..".set", value) + end app.tick = __app_tick - app.get_setting_info = core.get_setting_info local function call_in_app_script_co(func, ...) if coroutine.running() ~= __vc__app_script_coroutine then diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index 4cc2c302d..b330e8a90 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -1,6 +1,7 @@ #include "api_lua.hpp" #include "io/io.hpp" +#include "io/settings_io.hpp" #include "io/devices/MemoryDevice.hpp" #include "logic/scripting/scripting.hpp" #include "content/ContentControl.hpp" @@ -113,6 +114,73 @@ static int l_set_title(lua::State* L) { return 0; } +/// @brief Get a setting value +/// @param name The name of the setting +/// @return The value of the setting +static int l_get_setting(lua::State* L) { + auto name = lua::require_string(L, 1); + const auto value = engine->getSettingsHandler().getValue(name); + return lua::pushvalue(L, value); +} + +/// @brief Set a setting value +/// @param name The name of the setting +/// @param value The new value for the setting +static int l_set_setting(lua::State* L) { + auto name = lua::require_string(L, 1); + const auto value = lua::tovalue(L, 2); + engine->getSettingsHandler().setValue(name, value); + return 0; +} + +/// @brief Convert a setting value to a string +/// @param name The name of the setting +/// @return The string representation of the setting value +static int l_str_setting(lua::State* L) { + auto name = lua::require_string(L, 1); + const auto string = engine->getSettingsHandler().toString(name); + return lua::pushstring(L, string); +} + +/// @brief Get information about a setting +/// @param name The name of the setting +/// @return A table with information about the setting +static int l_get_setting_info(lua::State* L) { + auto name = lua::require_string(L, 1); + auto setting = engine->getSettingsHandler().getSetting(name); + lua::createtable(L, 0, 1); + if (auto number = dynamic_cast(setting)) { + lua::pushnumber(L, number->getMin()); + lua::setfield(L, "min"); + lua::pushnumber(L, number->getMax()); + lua::setfield(L, "max"); + lua::pushnumber(L, number->getDefault()); + lua::setfield(L, "def"); + return 1; + } + if (auto integer = dynamic_cast(setting)) { + lua::pushinteger(L, integer->getMin()); + lua::setfield(L, "min"); + lua::pushinteger(L, integer->getMax()); + lua::setfield(L, "max"); + lua::pushinteger(L, integer->getDefault()); + lua::setfield(L, "def"); + return 1; + } + if (auto boolean = dynamic_cast(setting)) { + lua::pushboolean(L, boolean->getDefault()); + lua::setfield(L, "def"); + return 1; + } + if (auto string = dynamic_cast(setting)) { + lua::pushstring(L, string->getDefault()); + lua::setfield(L, "def"); + return 1; + } + lua::pop(L); + throw std::runtime_error("unsupported setting type"); +} + static int l_open_folder(lua::State* L) { platform::open_folder(io::resolve(lua::require_string(L, 1))); return 0; @@ -147,6 +215,10 @@ const luaL_Reg applib[] = { {"set_title", lua::wrap}, {"open_folder", lua::wrap}, {"open_url", lua::wrap}, + {"get_setting", lua::wrap}, + {"set_setting", lua::wrap}, + {"str_setting", lua::wrap}, + {"get_setting_info", lua::wrap}, // for other functions see libcore.cpp and stdlib.lua {nullptr, nullptr} }; diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 6f3056ea4..be7ee614e 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -1,7 +1,3 @@ -#include -#include -#include - #include "api_lua.hpp" #include "constants.hpp" #include "assets/Assets.hpp" @@ -10,7 +6,6 @@ #include "engine/Engine.hpp" #include "engine/EnginePaths.hpp" #include "io/io.hpp" -#include "io/settings_io.hpp" #include "frontend/menu.hpp" #include "frontend/screens/MenuScreen.hpp" #include "graphics/core/Texture.hpp" @@ -22,6 +17,10 @@ #include "world/generator/WorldGenerator.hpp" #include "window/Window.hpp" +#include +#include +#include + using namespace scripting; static int l_load_content(lua::State* L) { @@ -162,73 +161,6 @@ static int l_reconfig_packs(lua::State* L) { return 0; } -/// @brief Get a setting value -/// @param name The name of the setting -/// @return The value of the setting -static int l_get_setting(lua::State* L) { - auto name = lua::require_string(L, 1); - const auto value = engine->getSettingsHandler().getValue(name); - return lua::pushvalue(L, value); -} - -/// @brief Set a setting value -/// @param name The name of the setting -/// @param value The new value for the setting -static int l_set_setting(lua::State* L) { - auto name = lua::require_string(L, 1); - const auto value = lua::tovalue(L, 2); - engine->getSettingsHandler().setValue(name, value); - return 0; -} - -/// @brief Convert a setting value to a string -/// @param name The name of the setting -/// @return The string representation of the setting value -static int l_str_setting(lua::State* L) { - auto name = lua::require_string(L, 1); - const auto string = engine->getSettingsHandler().toString(name); - return lua::pushstring(L, string); -} - -/// @brief Get information about a setting -/// @param name The name of the setting -/// @return A table with information about the setting -static int l_get_setting_info(lua::State* L) { - auto name = lua::require_string(L, 1); - auto setting = engine->getSettingsHandler().getSetting(name); - lua::createtable(L, 0, 1); - if (auto number = dynamic_cast(setting)) { - lua::pushnumber(L, number->getMin()); - lua::setfield(L, "min"); - lua::pushnumber(L, number->getMax()); - lua::setfield(L, "max"); - lua::pushnumber(L, number->getDefault()); - lua::setfield(L, "def"); - return 1; - } - if (auto integer = dynamic_cast(setting)) { - lua::pushinteger(L, integer->getMin()); - lua::setfield(L, "min"); - lua::pushinteger(L, integer->getMax()); - lua::setfield(L, "max"); - lua::pushinteger(L, integer->getDefault()); - lua::setfield(L, "def"); - return 1; - } - if (auto boolean = dynamic_cast(setting)) { - lua::pushboolean(L, boolean->getDefault()); - lua::setfield(L, "def"); - return 1; - } - if (auto string = dynamic_cast(setting)) { - lua::pushstring(L, string->getDefault()); - lua::setfield(L, "def"); - return 1; - } - lua::pop(L); - throw std::runtime_error("unsupported setting type"); -} - /// @brief Quit the game static int l_quit(lua::State*) { engine->quit(); @@ -278,10 +210,6 @@ const luaL_Reg corelib[] = { {"close_world", lua::wrap}, {"delete_world", lua::wrap}, {"reconfig_packs", lua::wrap}, - {"get_setting", lua::wrap}, - {"set_setting", lua::wrap}, - {"str_setting", lua::wrap}, - {"get_setting_info", lua::wrap}, {"quit", lua::wrap}, {"capture_output", lua::wrap}, {nullptr, nullptr} diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index eef391b54..2a9eb59cb 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -66,6 +66,8 @@ static void create_libs(State* L, StateType stateType) { if (stateType == StateType::SCRIPT) { openlib(L, "app", applib); + lua::getglobal(L, "app"); + lua::setglobal(L, "__vc_app"); } else if (stateType == StateType::BASE) { openlib(L, "__vc_app", applib); } From 24f867dbacd4db39ffb296d4821e0df08c2b54fe Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 02:43:22 +0300 Subject: [PATCH 12/16] remove core.is_content_loaded --- res/scripts/stdlib.lua | 4 ---- src/logic/scripting/lua/libs/libapp.cpp | 5 +++++ src/logic/scripting/lua/libs/libcore.cpp | 5 ----- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index d7ee98b97..83e75322f 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -68,8 +68,6 @@ local function complete_app_lib(app) call_in_app_script_co(__core_reset_content, ...) end - app.is_content_loaded = core.is_content_loaded - function app.config_packs(packs_list) -- Check if packs are valid and add dependencies to the configuration packs_list = pack.assemble(packs_list) @@ -581,5 +579,3 @@ require "core:internal/deprecated" ffi = nil __vc_lock_internal_modules() - -debug.print(core) diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index b330e8a90..4e8c6d9c4 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -25,6 +25,10 @@ static int l_get_version(lua::State* L) { ); } +static int l_is_content_loaded(lua::State* L) { + return lua::pushboolean(L, content != nullptr); +} + static int l_start_debug_instance(lua::State* L) { if (!engine->getProject().permissions.has(Permissions::DEBUGGING)) { throw std::runtime_error("project has no debugging permission"); @@ -206,6 +210,7 @@ static int l_open_url(lua::State* L) { const luaL_Reg applib[] = { {"get_version", lua::wrap}, + {"is_content_loaded", lua::wrap}, {"start_debug_instance", lua::wrap}, {"focus", lua::wrap}, {"create_memory_device", lua::wrap}, diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index be7ee614e..bef6f52a5 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -45,10 +45,6 @@ static int l_reset_content(lua::State* L) { return 0; } -static int l_is_content_loaded(lua::State* L) { - return lua::pushboolean(L, content != nullptr); -} - /// @brief Creating new world /// @param name Name world /// @param seed Seed world @@ -202,7 +198,6 @@ const luaL_Reg corelib[] = { {"blank", lua::wrap}, {"load_content", lua::wrap}, {"reset_content", lua::wrap}, - {"is_content_loaded", lua::wrap}, {"new_world", lua::wrap}, {"open_world", lua::wrap}, {"reopen_world", lua::wrap}, From 9af675611f5a8c9fc8bfdebb69bc03ce9d35969f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 19:37:57 +0300 Subject: [PATCH 13/16] remove core.quit add 'silent' argument to app.quit --- res/layouts/pages/main.xml | 2 +- res/scripts/stdlib.lua | 21 ++++++++++++--------- src/logic/scripting/lua/libs/libapp.cpp | 7 +++++++ src/logic/scripting/lua/libs/libcore.cpp | 7 ------- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/res/layouts/pages/main.xml b/res/layouts/pages/main.xml index b1fab2c9e..b05ac7158 100644 --- a/res/layouts/pages/main.xml +++ b/res/layouts/pages/main.xml @@ -3,5 +3,5 @@ - + diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 83e75322f..06ba4f6e8 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -32,6 +32,7 @@ local function complete_app_lib(app) local __core_reconfig_packs = core.reconfig_packs local __app_tick = coroutine.yield local __app_set_setting = app.set_setting + local __app_quit = app.quit core.load_content = nil core.reset_content = nil @@ -51,7 +52,8 @@ local function complete_app_lib(app) app.tick = __app_tick local function call_in_app_script_co(func, ...) - if coroutine.running() ~= __vc__app_script_coroutine then + local running = coroutine.running() + if not running or running ~= __vc__app_script_coroutine then error("content must be reload in application script coroutine") end func(...) @@ -88,15 +90,16 @@ local function complete_app_lib(app) app.reconfig_packs(toadd, toremove) end - function app.quit() - local tb = debug.get_traceback(1) - local s = "app.quit() traceback:" - for i, frame in ipairs(tb) do - s = s .. "\n\t"..tb_frame_tostring(frame) + function app.quit(silent) + if not silent then + local tb = debug.get_traceback(1) + local s = "app.quit() traceback:" + for i, frame in ipairs(tb) do + s = s .. "\n\t"..tb_frame_tostring(frame) + end + debug.log(s) end - debug.log(s) - core.quit() - coroutine.yield() + __app_quit() end function app.sleep_until(predicate, max_ticks, max_time) diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index 4e8c6d9c4..b949adf72 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -208,6 +208,12 @@ static int l_open_url(lua::State* L) { return 0; } +/// @brief Quit the game +static int l_quit(lua::State*) { + engine->quit(); + return 0; +} + const luaL_Reg applib[] = { {"get_version", lua::wrap}, {"is_content_loaded", lua::wrap}, @@ -224,6 +230,7 @@ const luaL_Reg applib[] = { {"set_setting", lua::wrap}, {"str_setting", lua::wrap}, {"get_setting_info", lua::wrap}, + {"quit", lua::wrap}, // for other functions see libcore.cpp and stdlib.lua {nullptr, nullptr} }; diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index bef6f52a5..71a38d192 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -157,12 +157,6 @@ static int l_reconfig_packs(lua::State* L) { return 0; } -/// @brief Quit the game -static int l_quit(lua::State*) { - engine->quit(); - return 0; -} - static int l_blank(lua::State*) { return 0; } @@ -205,7 +199,6 @@ const luaL_Reg corelib[] = { {"close_world", lua::wrap}, {"delete_world", lua::wrap}, {"reconfig_packs", lua::wrap}, - {"quit", lua::wrap}, {"capture_output", lua::wrap}, {nullptr, nullptr} }; From 126a8485a1250cb8bf7412a8e1b9032cd7fa326d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 20:03:34 +0300 Subject: [PATCH 14/16] remove content-related functions from core library --- res/scripts/stdlib.lua | 14 +++--- src/logic/scripting/lua/libs/libapp.cpp | 61 ++++++++++++++++++++++++ src/logic/scripting/lua/libs/libcore.cpp | 60 ----------------------- 3 files changed, 67 insertions(+), 68 deletions(-) diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index 06ba4f6e8..cc0131fa7 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -27,14 +27,12 @@ end local __vc__app_script_coroutine local function complete_app_lib(app) - local __core_load_content = core.load_content - local __core_reset_content = core.reset_content - local __core_reconfig_packs = core.reconfig_packs + local __app_load_content = app.load_content + local __app_reset_content = app.reset_content + local __app_reconfig_packs = app.reconfig_packs local __app_tick = coroutine.yield local __app_set_setting = app.set_setting local __app_quit = app.quit - core.load_content = nil - core.reset_content = nil app.sleep = sleep app.script = __VC_SCRIPT_NAME @@ -61,13 +59,13 @@ local function complete_app_lib(app) end app.reconfig_packs = function(...) - call_in_app_script_co(__core_reconfig_packs, ...) + call_in_app_script_co(__app_reconfig_packs, ...) end app.load_content = function(...) - call_in_app_script_co(__core_load_content, ...) + call_in_app_script_co(__app_load_content, ...) end app.reset_content = function(...) - call_in_app_script_co(__core_reset_content, ...) + call_in_app_script_co(__app_reset_content, ...) end function app.config_packs(packs_list) diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index b949adf72..9412baa36 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -4,6 +4,7 @@ #include "io/settings_io.hpp" #include "io/devices/MemoryDevice.hpp" #include "logic/scripting/scripting.hpp" +#include "logic/EngineController.hpp" #include "content/ContentControl.hpp" #include "engine/Engine.hpp" #include "engine/EnginePaths.hpp" @@ -29,6 +30,63 @@ static int l_is_content_loaded(lua::State* L) { return lua::pushboolean(L, content != nullptr); } +static int l_load_content(lua::State* L) { + content_control->loadContent(); + return 0; +} + +static int l_reset_content(lua::State* L) { + if (level != nullptr) { + throw std::runtime_error("world must be closed before"); + } + 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; +} + +/// @brief Reconfigure packs +/// @param addPacks An array of packs to add +/// @param remPacks An array of packs to remove +static int l_reconfig_packs(lua::State* L) { + if (!lua::istable(L, 1)) { + throw std::runtime_error("strings array expected as the first argument"); + } + if (!lua::istable(L, 2)) { + throw std::runtime_error("strings array expected as the second argument"); + } + std::vector addPacks; + int addLen = lua::objlen(L, 1); + for (int i = 0; i < addLen; i++) { + lua::rawgeti(L, i + 1, 1); + addPacks.emplace_back(lua::require_lstring(L, -1)); + lua::pop(L); + } + std::vector remPacks; + int remLen = lua::objlen(L, 2); + for (int i = 0; i < remLen; i++) { + lua::rawgeti(L, i + 1, 2); + remPacks.emplace_back(lua::require_lstring(L, -1)); + lua::pop(L); + } + auto engineController = engine->getController(); + try { + engineController->reconfigPacks(controller, addPacks, remPacks); + } catch (const contentpack_error& err) { + throw std::runtime_error( + std::string(err.what()) + " [" + err.getPackId() + " ]" + ); + } + return 0; +} + static int l_start_debug_instance(lua::State* L) { if (!engine->getProject().permissions.has(Permissions::DEBUGGING)) { throw std::runtime_error("project has no debugging permission"); @@ -217,6 +275,9 @@ static int l_quit(lua::State*) { const luaL_Reg applib[] = { {"get_version", lua::wrap}, {"is_content_loaded", lua::wrap}, + {"load_content", lua::wrap}, + {"reset_content", lua::wrap}, + {"reconfig_packs", lua::wrap}, {"start_debug_instance", lua::wrap}, {"focus", lua::wrap}, {"create_memory_device", lua::wrap}, diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index 71a38d192..b9648ad35 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -23,28 +23,6 @@ using namespace scripting; -static int l_load_content(lua::State* L) { - content_control->loadContent(); - return 0; -} - -static int l_reset_content(lua::State* L) { - if (level != nullptr) { - throw std::runtime_error("world must be closed before"); - } - 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; -} - /// @brief Creating new world /// @param name Name world /// @param seed Seed world @@ -122,41 +100,6 @@ static int l_delete_world(lua::State* L) { return 0; } -/// @brief Reconfigure packs -/// @param addPacks An array of packs to add -/// @param remPacks An array of packs to remove -static int l_reconfig_packs(lua::State* L) { - if (!lua::istable(L, 1)) { - throw std::runtime_error("strings array expected as the first argument"); - } - if (!lua::istable(L, 2)) { - throw std::runtime_error("strings array expected as the second argument"); - } - std::vector addPacks; - int addLen = lua::objlen(L, 1); - for (int i = 0; i < addLen; i++) { - lua::rawgeti(L, i + 1, 1); - addPacks.emplace_back(lua::require_lstring(L, -1)); - lua::pop(L); - } - std::vector remPacks; - int remLen = lua::objlen(L, 2); - for (int i = 0; i < remLen; i++) { - lua::rawgeti(L, i + 1, 2); - remPacks.emplace_back(lua::require_lstring(L, -1)); - lua::pop(L); - } - auto engineController = engine->getController(); - try { - engineController->reconfigPacks(controller, addPacks, remPacks); - } catch (const contentpack_error& err) { - throw std::runtime_error( - std::string(err.what()) + " [" + err.getPackId() + " ]" - ); - } - return 0; -} - static int l_blank(lua::State*) { return 0; } @@ -190,15 +133,12 @@ static int l_capture_output(lua::State* L) { const luaL_Reg corelib[] = { {"blank", lua::wrap}, - {"load_content", lua::wrap}, - {"reset_content", lua::wrap}, {"new_world", lua::wrap}, {"open_world", lua::wrap}, {"reopen_world", lua::wrap}, {"save_world", lua::wrap}, {"close_world", lua::wrap}, {"delete_world", lua::wrap}, - {"reconfig_packs", lua::wrap}, {"capture_output", lua::wrap}, {nullptr, nullptr} }; From c57fe211202b564557c180e10e81e4cbe303749c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 20:12:06 +0300 Subject: [PATCH 15/16] move world-related functions from core library --- res/layouts/pages/new_world.xml.lua | 2 +- res/layouts/pages/pause.xml | 2 +- res/layouts/templates/world.xml | 4 +- res/scripts/stdlib.lua | 6 -- src/logic/scripting/lua/libs/libapp.cpp | 106 ++++++++++++++++++++--- src/logic/scripting/lua/libs/libcore.cpp | 102 ---------------------- 6 files changed, 100 insertions(+), 122 deletions(-) diff --git a/res/layouts/pages/new_world.xml.lua b/res/layouts/pages/new_world.xml.lua index 694ca9565..ad95aad0d 100644 --- a/res/layouts/pages/new_world.xml.lua +++ b/res/layouts/pages/new_world.xml.lua @@ -21,7 +21,7 @@ function create_world() local seed = document.seed_box.text local generator = settings.generator session.reset_entry('new_world') - core.new_world(name, seed, generator) + app.new_world(name, seed, generator) end function world_name_placeholder() diff --git a/res/layouts/pages/pause.xml b/res/layouts/pages/pause.xml index 63d827e10..3e4427cae 100644 --- a/res/layouts/pages/pause.xml +++ b/res/layouts/pages/pause.xml @@ -2,7 +2,7 @@ - diff --git a/res/layouts/templates/world.xml b/res/layouts/templates/world.xml index a258604b4..4ae936b6e 100644 --- a/res/layouts/templates/world.xml +++ b/res/layouts/templates/world.xml @@ -2,7 +2,7 @@ size='380,66' color='#0F1E2DB2' hover-color='#162B3399' - onclick='core.open_world("%{name}")' + onclick='app.open_world("%{name}")' > @@ -11,7 +11,7 @@ color='#00000000' hover-color='#FFFFFF2B' padding='0' - onclick='core.delete_world("%{name}")'> + onclick='app.delete_world("%{name}")'> diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index cc0131fa7..4eb6dd17e 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -36,12 +36,6 @@ local function complete_app_lib(app) app.sleep = sleep app.script = __VC_SCRIPT_NAME - app.new_world = core.new_world - app.open_world = core.open_world - app.save_world = core.save_world - app.close_world = core.close_world - app.reopen_world = core.reopen_world - app.delete_world = core.delete_world app.set_setting = function(name, value, ...) __app_set_setting(name, value, ...) diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index 9412baa36..736fc8624 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -1,22 +1,24 @@ #include "api_lua.hpp" -#include "io/io.hpp" -#include "io/settings_io.hpp" -#include "io/devices/MemoryDevice.hpp" -#include "logic/scripting/scripting.hpp" -#include "logic/EngineController.hpp" #include "content/ContentControl.hpp" +#include "devtools/Project.hpp" #include "engine/Engine.hpp" #include "engine/EnginePaths.hpp" -#include "devtools/Project.hpp" +#include "frontend/locale.hpp" +#include "graphics/ui/elements/Menu.hpp" +#include "graphics/ui/gui_util.hpp" +#include "graphics/ui/GUI.hpp" +#include "io/devices/MemoryDevice.hpp" +#include "io/io.hpp" +#include "io/settings_io.hpp" +#include "logic/EngineController.hpp" +#include "logic/LevelController.hpp" +#include "logic/scripting/scripting.hpp" #include "network/Network.hpp" #include "util/platform.hpp" #include "util/stringutil.hpp" #include "window/Window.hpp" -#include "frontend/locale.hpp" -#include "graphics/ui/GUI.hpp" -#include "graphics/ui/gui_util.hpp" -#include "graphics/ui/elements/Menu.hpp" +#include "world/Level.hpp" using namespace scripting; @@ -266,6 +268,84 @@ static int l_open_url(lua::State* L) { return 0; } +/// @brief Creating new world +/// @param name Name world +/// @param seed Seed world +/// @param generator Type of generation +static int l_new_world(lua::State* L) { + auto name = lua::require_string(L, 1); + auto seed = lua::require_string(L, 2); + auto generator = lua::require_string(L, 3); + int64_t localPlayer = 0; + if (lua::gettop(L) >= 4) { + localPlayer = lua::tointeger(L, 4); + } + if (level != nullptr) { + throw std::runtime_error("world must be closed before"); + } + auto controller = engine->getController(); + controller->setLocalPlayer(localPlayer); + controller->createWorld(name, seed, generator); + return 0; +} + +/// @brief Open world +/// @param name Name world +static int l_open_world(lua::State* L) { + auto name = lua::require_string(L, 1); + if (level != nullptr) { + throw std::runtime_error("world must be closed before"); + } + auto controller = engine->getController(); + controller->setLocalPlayer(0); + controller->openWorld(name, false); + return 0; +} + +/// @brief Reopen world +static int l_reopen_world(lua::State*) { + auto controller = engine->getController(); + if (level == nullptr) { + throw std::runtime_error("no world open"); + } + controller->reopenWorld(level->getWorld()); + return 0; +} + +/// @brief Save world +static int l_save_world(lua::State* L) { + if (controller == nullptr) { + throw std::runtime_error("no world open"); + } + controller->saveWorld(); + return 0; +} + +/// @brief Close world +/// @param flag Save world (bool) +static int l_close_world(lua::State* L) { + if (controller == nullptr) { + throw std::runtime_error("no world open"); + } + controller->processBeforeQuit(); + bool save_world = lua::toboolean(L, 1); + if (save_world) { + controller->saveWorld(); + } + engine->onWorldClosed(); + return 0; +} + +/// @brief Delete world +/// @param name Name world +static int l_delete_world(lua::State* L) { + auto name = lua::require_string(L, 1); + auto controller = engine->getController(); + controller->deleteWorld(name); + return 0; +} + + /// @brief Quit the game static int l_quit(lua::State*) { engine->quit(); @@ -291,6 +371,12 @@ const luaL_Reg applib[] = { {"set_setting", lua::wrap}, {"str_setting", lua::wrap}, {"get_setting_info", lua::wrap}, + {"new_world", lua::wrap}, + {"open_world", lua::wrap}, + {"reopen_world", lua::wrap}, + {"save_world", lua::wrap}, + {"close_world", lua::wrap}, + {"delete_world", lua::wrap}, {"quit", lua::wrap}, // for other functions see libcore.cpp and stdlib.lua {nullptr, nullptr} diff --git a/src/logic/scripting/lua/libs/libcore.cpp b/src/logic/scripting/lua/libs/libcore.cpp index b9648ad35..324cd5471 100644 --- a/src/logic/scripting/lua/libs/libcore.cpp +++ b/src/logic/scripting/lua/libs/libcore.cpp @@ -1,105 +1,9 @@ #include "api_lua.hpp" -#include "constants.hpp" -#include "assets/Assets.hpp" -#include "content/Content.hpp" -#include "content/ContentControl.hpp" -#include "engine/Engine.hpp" -#include "engine/EnginePaths.hpp" -#include "io/io.hpp" -#include "frontend/menu.hpp" -#include "frontend/screens/MenuScreen.hpp" -#include "graphics/core/Texture.hpp" -#include "logic/EngineController.hpp" -#include "logic/LevelController.hpp" -#include "util/listutil.hpp" -#include "util/platform.hpp" -#include "world/Level.hpp" -#include "world/generator/WorldGenerator.hpp" -#include "window/Window.hpp" -#include -#include #include using namespace scripting; -/// @brief Creating new world -/// @param name Name world -/// @param seed Seed world -/// @param generator Type of generation -static int l_new_world(lua::State* L) { - auto name = lua::require_string(L, 1); - auto seed = lua::require_string(L, 2); - auto generator = lua::require_string(L, 3); - int64_t localPlayer = 0; - if (lua::gettop(L) >= 4) { - localPlayer = lua::tointeger(L, 4); - } - if (level != nullptr) { - throw std::runtime_error("world must be closed before"); - } - auto controller = engine->getController(); - controller->setLocalPlayer(localPlayer); - controller->createWorld(name, seed, generator); - return 0; -} - -/// @brief Open world -/// @param name Name world -static int l_open_world(lua::State* L) { - auto name = lua::require_string(L, 1); - if (level != nullptr) { - throw std::runtime_error("world must be closed before"); - } - auto controller = engine->getController(); - controller->setLocalPlayer(0); - controller->openWorld(name, false); - return 0; -} - -/// @brief Reopen world -static int l_reopen_world(lua::State*) { - auto controller = engine->getController(); - if (level == nullptr) { - throw std::runtime_error("no world open"); - } - controller->reopenWorld(level->getWorld()); - return 0; -} - -/// @brief Save world -static int l_save_world(lua::State* L) { - if (controller == nullptr) { - throw std::runtime_error("no world open"); - } - controller->saveWorld(); - return 0; -} - -/// @brief Close world -/// @param flag Save world (bool) -static int l_close_world(lua::State* L) { - if (controller == nullptr) { - throw std::runtime_error("no world open"); - } - controller->processBeforeQuit(); - bool save_world = lua::toboolean(L, 1); - if (save_world) { - controller->saveWorld(); - } - engine->onWorldClosed(); - return 0; -} - -/// @brief Delete world -/// @param name Name world -static int l_delete_world(lua::State* L) { - auto name = lua::require_string(L, 1); - auto controller = engine->getController(); - controller->deleteWorld(name); - return 0; -} - static int l_blank(lua::State*) { return 0; } @@ -133,12 +37,6 @@ static int l_capture_output(lua::State* L) { const luaL_Reg corelib[] = { {"blank", lua::wrap}, - {"new_world", lua::wrap}, - {"open_world", lua::wrap}, - {"reopen_world", lua::wrap}, - {"save_world", lua::wrap}, - {"close_world", lua::wrap}, - {"delete_world", lua::wrap}, {"capture_output", lua::wrap}, {nullptr, nullptr} }; From 7f51377db399c5531c5cfe940dc7713fb0bd8404 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 7 Jan 2026 21:06:22 +0300 Subject: [PATCH 16/16] cleanup a bit --- src/logic/scripting/lua/libs/libapp.cpp | 173 +++++++++++++----------- 1 file changed, 96 insertions(+), 77 deletions(-) diff --git a/src/logic/scripting/lua/libs/libapp.cpp b/src/logic/scripting/lua/libs/libapp.cpp index 736fc8624..09ea33ce3 100644 --- a/src/logic/scripting/lua/libs/libapp.cpp +++ b/src/logic/scripting/lua/libs/libapp.cpp @@ -22,21 +22,18 @@ using namespace scripting; -static int l_get_version(lua::State* L) { - return lua::pushvec_stack( - L, glm::vec2(ENGINE_VERSION_MAJOR, ENGINE_VERSION_MINOR) - ); -} - +/// @brief Check if content is loaded static int l_is_content_loaded(lua::State* L) { return lua::pushboolean(L, content != nullptr); } +/// @brief Load content static int l_load_content(lua::State* L) { content_control->loadContent(); return 0; } +/// @brief Reset content, excluding specified packs modules static int l_reset_content(lua::State* L) { if (level != nullptr) { throw std::runtime_error("world must be closed before"); @@ -89,59 +86,7 @@ static int l_reconfig_packs(lua::State* L) { return 0; } -static int l_start_debug_instance(lua::State* L) { - if (!engine->getProject().permissions.has(Permissions::DEBUGGING)) { - throw std::runtime_error("project has no debugging permission"); - } - - int port = lua::tointeger(L, 1); - if (port == 0) { - auto network = engine->getNetwork(); - if (network == nullptr) { - throw std::runtime_error("project has no network permission"); - } - port = network->findFreePort(); - if (port == -1) { - throw std::runtime_error("could not find free port"); - } - } - auto projectPath = lua::isstring(L, 2) ? lua::require_lstring(L, 2) : ""; - const auto& paths = engine->getPaths(); - - std::vector args { - "--res", paths.getResourcesFolder().u8string(), - "--dir", paths.getUserFilesFolder().u8string(), - "--dbg-server", "tcp:" + std::to_string(port), - }; - if (!projectPath.empty()) { - args.emplace_back("--project"); - args.emplace_back(io::resolve(std::string(projectPath)).string()); - } - - platform::new_engine_instance(std::move(args)); - return lua::pushinteger(L, port); -} - -static int l_focus(lua::State* L) { - engine->getWindow().focus(); - return 0; -} - -static int l_create_memory_device(lua::State* L) { - std::string name = lua::require_string(L, 1); - if (io::get_device(name)) { - throw std::runtime_error( - "entry-point '" + name + "' is already used" - ); - } - if (name.find(':') != std::string::npos) { - throw std::runtime_error("invalid entry point name"); - } - - io::set_device(name, std::make_unique()); - return 0; -} - +/// @brief Get content sources list static int l_get_content_sources(lua::State* L) { const auto& sources = engine->getContentControl().getContentSources(); lua::createtable(L, static_cast(sources.size()), 0); @@ -152,6 +97,7 @@ static int l_get_content_sources(lua::State* L) { return 1; } +/// @brief Set content sources list static int l_set_content_sources(lua::State* L) { if (!lua::istable(L, 1)) { throw std::runtime_error("table expected as argument 1"); @@ -167,17 +113,12 @@ static int l_set_content_sources(lua::State* L) { return 0; } +/// @brief Reset content sources to defaults static int l_reset_content_sources(lua::State* L) { engine->getContentControl().resetContentSources(); return 0; } -static int l_set_title(lua::State* L) { - auto title = lua::require_string(L, 1); - engine->getWindow().setTitle(title); - return 0; -} - /// @brief Get a setting value /// @param name The name of the setting /// @return The value of the setting @@ -245,11 +186,13 @@ static int l_get_setting_info(lua::State* L) { throw std::runtime_error("unsupported setting type"); } +/// @brief Open folder in file explorer static int l_open_folder(lua::State* L) { platform::open_folder(io::resolve(lua::require_string(L, 1))); return 0; } +/// @brief Open URL in default browser with confirmation dialog static int l_open_url(lua::State* L) { auto url = lua::require_string(L, 1); @@ -268,6 +211,26 @@ static int l_open_url(lua::State* L) { return 0; } + +/// @brief Bring application window to focus +static int l_focus(lua::State* L) { + engine->getWindow().focus(); + return 0; +} + +/// @brief Set window title +static int l_set_title(lua::State* L) { + auto title = lua::require_string(L, 1); + engine->getWindow().setTitle(title); + return 0; +} + +/// @brief Quit the game +static int l_quit(lua::State*) { + engine->quit(); + return 0; +} + /// @brief Creating new world /// @param name Name world /// @param seed Seed world @@ -345,39 +308,95 @@ static int l_delete_world(lua::State* L) { return 0; } +/// @brief Get engine version +/// @return major, minor +static int l_get_version(lua::State* L) { + return lua::pushvec_stack( + L, glm::vec2(ENGINE_VERSION_MAJOR, ENGINE_VERSION_MINOR) + ); +} -/// @brief Quit the game -static int l_quit(lua::State*) { - engine->quit(); +/// @brief Create in-memory named IO device +static int l_create_memory_device(lua::State* L) { + std::string name = lua::require_string(L, 1); + if (io::get_device(name)) { + throw std::runtime_error( + "entry-point '" + name + "' is already used" + ); + } + if (name.find(':') != std::string::npos) { + throw std::runtime_error("invalid entry point name"); + } + + io::set_device(name, std::make_unique()); return 0; } +/// @brief Start a new engine instance with debugging server +static int l_start_debug_instance(lua::State* L) { + if (!engine->getProject().permissions.has(Permissions::DEBUGGING)) { + throw std::runtime_error("project has no debugging permission"); + } + + int port = lua::tointeger(L, 1); + if (port == 0) { + auto network = engine->getNetwork(); + if (network == nullptr) { + throw std::runtime_error("project has no network permission"); + } + port = network->findFreePort(); + if (port == -1) { + throw std::runtime_error("could not find free port"); + } + } + auto projectPath = lua::isstring(L, 2) ? lua::require_lstring(L, 2) : ""; + const auto& paths = engine->getPaths(); + + std::vector args { + "--res", paths.getResourcesFolder().u8string(), + "--dir", paths.getUserFilesFolder().u8string(), + "--dbg-server", "tcp:" + std::to_string(port), + }; + if (!projectPath.empty()) { + args.emplace_back("--project"); + args.emplace_back(io::resolve(std::string(projectPath)).string()); + } + + platform::new_engine_instance(std::move(args)); + return lua::pushinteger(L, port); +} + const luaL_Reg applib[] = { - {"get_version", lua::wrap}, + /// content {"is_content_loaded", lua::wrap}, {"load_content", lua::wrap}, {"reset_content", lua::wrap}, {"reconfig_packs", lua::wrap}, - {"start_debug_instance", lua::wrap}, - {"focus", lua::wrap}, - {"create_memory_device", lua::wrap}, {"get_content_sources", lua::wrap}, {"set_content_sources", lua::wrap}, {"reset_content_sources", lua::wrap}, - {"set_title", lua::wrap}, - {"open_folder", lua::wrap}, - {"open_url", lua::wrap}, + /// settings {"get_setting", lua::wrap}, {"set_setting", lua::wrap}, {"str_setting", lua::wrap}, {"get_setting_info", lua::wrap}, + /// system applications + {"open_folder", lua::wrap}, + {"open_url", lua::wrap}, + /// window + {"focus", lua::wrap}, + {"set_title", lua::wrap}, + {"quit", lua::wrap}, + /// world {"new_world", lua::wrap}, {"open_world", lua::wrap}, {"reopen_world", lua::wrap}, {"save_world", lua::wrap}, {"close_world", lua::wrap}, {"delete_world", lua::wrap}, - {"quit", lua::wrap}, - // for other functions see libcore.cpp and stdlib.lua + /// other + {"get_version", lua::wrap}, + {"create_memory_device", lua::wrap}, + {"start_debug_instance", lua::wrap}, {nullptr, nullptr} };