diff --git a/res/layouts/inventory.xml b/res/layouts/inventory.xml index b5ea903c..afe61bbd 100644 --- a/res/layouts/inventory.xml +++ b/res/layouts/inventory.xml @@ -1,3 +1,4 @@ - + + diff --git a/res/scripts/world.lua b/res/scripts/world.lua index e69de29b..964100e7 100644 --- a/res/scripts/world.lua +++ b/res/scripts/world.lua @@ -0,0 +1,3 @@ +-- use for engine development tests +-- must be empty in release +-- must not be modified by content-packs diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 177f2e9e..35babebc 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -66,6 +66,8 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, bool world) { loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/sun.png", "misc/sun"); for (fs::path& file : loader.getPaths()->listdir(LAYOUTS_FOLDER)) { + if (file.extension().u8string() != ".xml") + continue; std::string packName = file.parent_path().parent_path().filename(); if (packName == "res") { packName = "core"; diff --git a/src/frontend/UiDocument.cpp b/src/frontend/UiDocument.cpp index 88702084..3d2f774a 100644 --- a/src/frontend/UiDocument.cpp +++ b/src/frontend/UiDocument.cpp @@ -10,8 +10,9 @@ UiDocument::UiDocument( std::string namesp, uidocscript script, - std::shared_ptr root -) : namesp(namesp), script(script), root(root) { + std::shared_ptr root, + int env +) : namesp(namesp), script(script), root(root), env(env) { collect(map, root); } @@ -53,7 +54,7 @@ std::unique_ptr UiDocument::read(std::string namesp, fs::path file) uidocscript script {}; auto scriptFile = fs::path(file.u8string()+".lua"); if (fs::is_regular_file(scriptFile)) { - scripting::load_layout_script(scriptFile, script); + scripting::load_layout_script(env->getId(), scriptFile, script); } - return std::make_unique(namesp, script, view); + return std::make_unique(namesp, script, view, env.release()->getId()); } diff --git a/src/frontend/UiDocument.h b/src/frontend/UiDocument.h index a987ecf3..45484b01 100644 --- a/src/frontend/UiDocument.h +++ b/src/frontend/UiDocument.h @@ -25,8 +25,13 @@ class UiDocument { uidocscript script; uinodes_map map; std::shared_ptr root; + int env; public: - UiDocument(std::string namesp, uidocscript script, std::shared_ptr root); + UiDocument( + std::string namesp, + uidocscript script, + std::shared_ptr root, + int env); const uinodes_map& getMap() const; const std::string& getNamespace() const; diff --git a/src/frontend/gui/gui_xml.cpp b/src/frontend/gui/gui_xml.cpp index 67e65e5f..9df72ed6 100644 --- a/src/frontend/gui/gui_xml.cpp +++ b/src/frontend/gui/gui_xml.cpp @@ -117,7 +117,11 @@ static std::shared_ptr readButton(UiXmlReader& reader, xml::xmlelement e _readPanel(reader, element, *button); if (element->has("onclick")) { - auto callback = scripting::create_runnable("", element->attr("onclick").getText(), reader.getEnvironment()); + auto callback = scripting::create_runnable( + reader.getEnvironment().getId(), + "", + element->attr("onclick").getText() + ); button->listenAction([callback](GUI*) { callback(); }); @@ -137,6 +141,7 @@ static std::shared_ptr readTextBox(UiXmlReader& reader, xml::xmlelement if (element->has("consumer")) { auto consumer = scripting::create_wstring_consumer( + reader.getEnvironment().getId(), element->attr("consumer").getText(), reader.getFilename() ); diff --git a/src/logic/scripting/LuaState.cpp b/src/logic/scripting/LuaState.cpp index 5e4b6983..8d3836c0 100644 --- a/src/logic/scripting/LuaState.cpp +++ b/src/logic/scripting/LuaState.cpp @@ -25,8 +25,12 @@ lua::LuaState::LuaState() { createFuncs(); - lua_getglobal(L, "_G"); - lua_setglobal(L, ":G"); + lua_pushvalue(L, LUA_GLOBALSINDEX); + setglobal(envName(0)); +} + +const std::string lua::LuaState::envName(int env) const { + return "_ENV"+util::mangleid(env); } lua::LuaState::~LuaState() { @@ -109,10 +113,13 @@ void lua::LuaState::createFuncs() { addfunc("set_block_user_bits", l_set_block_user_bits); } -void lua::LuaState::loadbuffer(const std::string& src, const std::string& file) { +void lua::LuaState::loadbuffer(int env, const std::string& src, const std::string& file) { if (luaL_loadbuffer(L, src.c_str(), src.length(), file.c_str())) { throw lua::luaerror(lua_tostring(L, -1)); } + if (env && getglobal(envName(env))) { + lua_setfenv(L, -2); + } } int lua::LuaState::call(int argc) { @@ -130,14 +137,14 @@ int lua::LuaState::callNoThrow(int argc) { return 1; } -int lua::LuaState::eval(const std::string& src, const std::string& file) { +int lua::LuaState::eval(int env, const std::string& src, const std::string& file) { auto srcText = "return ("+src+")"; - loadbuffer(srcText, file); + loadbuffer(env, srcText, file); return call(0); } -int lua::LuaState::execute(const std::string& src, const std::string& file) { - loadbuffer(src, file); +int lua::LuaState::execute(int env, const std::string& src, const std::string& file) { + loadbuffer(env, src, file); return callNoThrow(0); } @@ -186,49 +193,24 @@ const std::string lua::LuaState::storeAnonymous() { return funcName; } -void lua::LuaState::initEnvironment() { - lua_getglobal(L, "_G"); - lua_setfield(L, -1, ":G"); -} - int lua::LuaState::createEnvironment() { int id = nextEnvironment++; + // globals table + lua_createtable(L, 0, 1); + + // metatable + lua_createtable(L, 0, 1); - if (currentEnvironment != 0) { - setEnvironment(0); - } + lua_pushvalue(L, LUA_GLOBALSINDEX); + lua_setfield(L, -2, "__index"); + lua_setmetatable(L, -2); - lua_createtable(L, 0, 0); - initEnvironment(); - setglobal("_N"+util::mangleid(id)); - - setEnvironment(id); + setglobal(envName(id)); return id; } + void lua::LuaState::removeEnvironment(int id) { - if (currentEnvironment == id) { - setEnvironment(0); - } lua_pushnil(L); - setglobal("_N"+util::mangleid(id)); -} - -int lua::LuaState::getEnvironment() const { - return currentEnvironment; -} - -void lua::LuaState::setEnvironment(int id) { - if (id == 0) { - getglobal(":G"); - lua_setfenv(L, -1); - } else { - getglobal(":G"); - lua_getfield(L, -1, ("_N"+util::mangleid(id)).c_str()); - if (lua_isnil(L, -1)) { - lua_pop(L, -1); - throw luaerror("environment "+std::to_string(id)+" was not found"); - } - lua_setfenv(L, -1); - } + setglobal(envName(id)); } diff --git a/src/logic/scripting/LuaState.h b/src/logic/scripting/LuaState.h index d2f64da7..71a231cd 100644 --- a/src/logic/scripting/LuaState.h +++ b/src/logic/scripting/LuaState.h @@ -17,7 +17,6 @@ namespace lua { class LuaState { lua_State* L; int nextEnvironment = 1; - int currentEnvironment = 0; void logError(const std::string& text); void initEnvironment(); @@ -25,7 +24,8 @@ namespace lua { LuaState(); ~LuaState(); - void loadbuffer(const std::string& src, const std::string& file); + const std::string envName(int env) const; + void loadbuffer(int env, const std::string& src, const std::string& file); int gettop() const; int pushivec3(luaint x, luaint y, luaint z); int pushinteger(luaint x); @@ -35,8 +35,8 @@ namespace lua { luaint tointeger(int index); int call(int argc); int callNoThrow(int argc); - int execute(const std::string& src, const std::string& file=""); - int eval(const std::string& src, const std::string& file=""); + int execute(int env, const std::string& src, const std::string& file=""); + int eval(int env, const std::string& src, const std::string& file=""); void openlib(const std::string& name, const luaL_Reg* libfuncs, int nup); void addfunc(const std::string& name, lua_CFunction func); bool getglobal(const std::string& name); @@ -47,9 +47,6 @@ namespace lua { void createFuncs(); int createEnvironment(); void removeEnvironment(int id); - int getEnvironment() const; - void setEnvironment(int id); - const std::string storeAnonymous(); }; } diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 985fd173..de2056e5 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -47,7 +47,7 @@ void load_script(fs::path name) { fs::path file = paths->getResources()/fs::path("scripts")/name; std::string src = files::read_string(file); - state->execute(src, file.u8string()); + state->execute(0, src, file.u8string()); } void scripting::initialize(Engine* engine) { @@ -58,35 +58,23 @@ void scripting::initialize(Engine* engine) { load_script(fs::path("stdlib.lua")); } -// todo: luaL state check runnable scripting::create_runnable( + int env, const std::string& file, const std::string& src ) { return [=](){ - state->execute(src, file); - }; -} - -runnable scripting::create_runnable( - const std::string& file, - const std::string& src, - const Environment& env -) { - return [=](){ - int previous = state->getEnvironment(); - state->setEnvironment(env.getId()); - state->execute(src, file); - state->setEnvironment(previous); + state->execute(env, src, file); }; } wstringconsumer scripting::create_wstring_consumer( + int env, const std::string& src, const std::string& file ) { try { - if (state->eval(src, file) == 0) + if (state->eval(env, src, file) == 0) return [](const std::wstring& _) {}; } catch (const lua::luaerror& err) { std::cerr << err.what() << std::endl; @@ -220,7 +208,7 @@ bool scripting::on_item_break_block(Player* player, const ItemDef* item, int x, void scripting::load_block_script(std::string prefix, fs::path file, block_funcs_set& funcsset) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; - state->execute(src, file.u8string()); + state->execute(0, src, file.u8string()); funcsset.init=state->rename("init", prefix+".init"); funcsset.update=state->rename("on_update", prefix+".update"); @@ -234,7 +222,7 @@ void scripting::load_block_script(std::string prefix, fs::path file, block_funcs void scripting::load_item_script(std::string prefix, fs::path file, item_funcs_set& funcsset) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; - state->execute(src, file.u8string()); + state->execute(0, src, file.u8string()); funcsset.init=state->rename("init", prefix+".init"); funcsset.on_use_on_block=state->rename("on_use_on_block", prefix+".useon"); funcsset.on_block_break_by=state->rename("on_block_break_by", prefix+".blockbreakby"); @@ -244,7 +232,7 @@ void scripting::load_world_script(std::string prefix, fs::path file) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; - state->loadbuffer(src, file.u8string()); + state->loadbuffer(0, src, file.u8string()); state->callNoThrow(0); state->rename("init", prefix+".init"); @@ -253,12 +241,12 @@ void scripting::load_world_script(std::string prefix, fs::path file) { state->rename("on_world_quit", prefix+".worldquit"); } -void scripting::load_layout_script(fs::path file, uidocscript& script) { +void scripting::load_layout_script(int env, fs::path file, uidocscript& script) { std::string src = files::read_string(file); std::cout << "loading script " << file.u8string() << std::endl; - script.environment = state->createEnvironment(); - state->loadbuffer(src, file.u8string()); + script.environment = env; + state->loadbuffer(env, src, file.u8string()); state->callNoThrow(0); script.onopen = state->hasglobal("on_open"); script.onclose = state->hasglobal("on_close"); diff --git a/src/logic/scripting/scripting.h b/src/logic/scripting/scripting.h index b8fe6f55..64bbc452 100644 --- a/src/logic/scripting/scripting.h +++ b/src/logic/scripting/scripting.h @@ -38,17 +38,13 @@ namespace scripting { void initialize(Engine* engine); runnable create_runnable( + int env, const std::string& filename, const std::string& source ); - - runnable create_runnable( - const std::string& filename, - const std::string& source, - const Environment& env - ); wstringconsumer create_wstring_consumer( + int env, const std::string& src, const std::string& file="" ); @@ -69,6 +65,6 @@ namespace scripting { void load_block_script(std::string prefix, fs::path file, block_funcs_set& funcsset); void load_item_script(std::string prefix, fs::path file, item_funcs_set& funcsset); void load_world_script(std::string prefix, fs::path file); - void load_layout_script(fs::path file, uidocscript& script); + void load_layout_script(int env, fs::path file, uidocscript& script); void close(); }