diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index bfca17328..c27f31293 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -123,10 +123,10 @@ void lua::init_state(State* L, StateType stateType) { setglobal(L, env_name(0)); createtable(L, 0, 0); - setglobal(L, LAMBDAS_TABLE); + setregistry(L, LAMBDAS_TABLE); createtable(L, 0, 0); - setglobal(L, CHUNKS_TABLE); + setregistry(L, CHUNKS_TABLE); initialize_libs_extends(L); diff --git a/src/logic/scripting/lua/lua_util.cpp b/src/logic/scripting/lua/lua_util.cpp index 6fdbe91ea..a563239a7 100644 --- a/src/logic/scripting/lua/lua_util.cpp +++ b/src/logic/scripting/lua/lua_util.cpp @@ -220,7 +220,7 @@ void lua::dump_stack(State* L) { static std::shared_ptr create_lambda_handler(State* L) { auto ptr = reinterpret_cast(topointer(L, -1)); auto name = util::mangleid(ptr); - requireglobal(L, LAMBDAS_TABLE); + reguireregistry(L, LAMBDAS_TABLE); pushvalue(L, -2); setfield(L, name); pop(L, 2); @@ -229,7 +229,7 @@ static std::shared_ptr create_lambda_handler(State* L) { new std::string(name), [=](std::string* name) { auto L = lua::get_main_state(); - requireglobal(L, LAMBDAS_TABLE); + reguireregistry(L, LAMBDAS_TABLE); pushnil(L); setfield(L, *name); pop(L); @@ -242,8 +242,9 @@ runnable lua::create_runnable(State* L) { auto funcptr = create_lambda_handler(L); return [=]() { auto L = lua::get_main_state(); - if (!get_from(L, LAMBDAS_TABLE, *funcptr, false)) + if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) { return; + } call_nothrow(L, 0, 0); pop(L); }; @@ -252,8 +253,9 @@ runnable lua::create_runnable(State* L) { KeyCallback lua::create_simple_handler(State* L) { auto funcptr = create_lambda_handler(L); return [=]() -> bool { - if (!get_from(L, LAMBDAS_TABLE, *funcptr, false)) + if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) { return false; + } int top = gettop(L) - 1; if (call_nothrow(L, 0)) { int nres = gettop(L) - top; @@ -271,8 +273,9 @@ KeyCallback lua::create_simple_handler(State* L) { scripting::common_func lua::create_lambda(State* L) { auto funcptr = create_lambda_handler(L); return [=](const std::vector& args) -> dv::value { - if (!get_from(L, LAMBDAS_TABLE, *funcptr, false)) + if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) { return nullptr; + } int top = gettop(L) - 1; for (const auto& arg : args) { pushvalue(L, arg); @@ -294,8 +297,9 @@ scripting::common_func lua::create_lambda(State* L) { scripting::common_func lua::create_lambda_nothrow(State* L) { auto funcptr = create_lambda_handler(L); return [=](const std::vector& args) -> dv::value { - if (!get_from(L, LAMBDAS_TABLE, *funcptr, false)) + if (!get_from_registry(L, LAMBDAS_TABLE, *funcptr, false)) { return nullptr; + } int top = gettop(L) - 1; for (const auto& arg : args) { pushvalue(L, arg); diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index f87853256..c7fa60cca 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -20,15 +20,27 @@ namespace lua { std::string env_name(int env); void dump_stack(lua::State*); - inline bool getglobal(lua::State* L, const std::string& name) { - lua_getglobal(L, name.c_str()); - if (isnil(L, -1)) { + inline bool isnoneornil(lua::State* L, int idx) { + return lua_isnoneornil(L, idx); + } + + inline bool getfield(lua::State* L, const std::string& name, int idx = -1) { + lua_getfield(L, idx, name.c_str()); + if (isnoneornil(L, -1)) { pop(L); return false; } return true; } + inline bool getglobal(lua::State* L, const std::string& name) { + return getfield(L, name, LUA_GLOBALSINDEX); + } + + inline bool getregistry(lua::State* L, const std::string& name) { + return getfield(L, name, LUA_REGISTRYINDEX); + } + inline int requireglobal(lua::State* L, const std::string& name) { if (getglobal(L, name)) { return 1; @@ -37,6 +49,14 @@ namespace lua { } } + inline int reguireregistry(lua::State* L, const std::string& name) { + if (getregistry(L, name)) { + return 1; + } else { + throw std::runtime_error("registry entry " + name + " not found"); + } + } + inline bool hasglobal(lua::State* L, const std::string& name) { lua_getglobal(L, name.c_str()); if (isnil(L, -1)) { @@ -203,9 +223,6 @@ namespace lua { inline int pushglobals(lua::State* L) { return pushvalue(L, LUA_GLOBALSINDEX); } - inline bool isnoneornil(lua::State* L, int idx) { - return lua_isnoneornil(L, idx); - } inline bool isboolean(lua::State* L, int idx) { return lua_isboolean(L, idx); } @@ -267,6 +284,9 @@ namespace lua { inline void setglobal(lua::State* L, const std::string& name) { lua_setglobal(L, name.c_str()); } + inline void setregistry(lua::State* L, const std::string& key) { + lua_setfield(L, LUA_REGISTRYINDEX, key.c_str()); + } template inline T* touserdata(lua::State* L, int idx) { if (void* rawptr = lua_touserdata(L, idx)) { @@ -461,15 +481,6 @@ namespace lua { [[nodiscard]] dv::value tovalue(lua::State*, int idx); - inline bool getfield(lua::State* L, const std::string& name, int idx = -1) { - lua_getfield(L, idx, name.c_str()); - if (isnoneornil(L, -1)) { - pop(L); - return false; - } - return true; - } - inline int requirefield( lua::State* L, const std::string& name, int idx = -1 ) { @@ -551,7 +562,46 @@ namespace lua { setfield(L, name); pop(L, 2); } else { - throw std::runtime_error("table " + tableName + " not found"); + throw std::runtime_error("global table " + tableName + " not found"); + } + } + + inline void store_in_registry( + lua::State* L, const std::string& tableName, const std::string& name + ) { + if (getregistry(L, tableName)) { + pushvalue(L, -2); + setfield(L, name); + pop(L, 2); + } else { + throw std::runtime_error("table " + tableName + " not found in registry"); + } + } + + inline int get_from( + lua::State* L, + const std::string& tableName, + const std::string& name, + bool required, + int idx, + std::string_view context + ) { + if (getfield(L, tableName, idx)) { + if (getfield(L, name)) { + return 1; + } else if (required) { + pop(L); + throw std::runtime_error( + std::string(context) + " table " + tableName + + " has no member " + name + ); + } + pop(L); + return 0; + } else { + throw std::runtime_error( + std::string(context) + " table " + tableName + " not found" + ); } } @@ -561,20 +611,20 @@ namespace lua { const std::string& name, bool required = false ) { - if (getglobal(L, tableName)) { - if (getfield(L, name)) { - return 1; - } else if (required) { - pop(L); - throw std::runtime_error( - "table " + tableName + " has no member " + name - ); - } - pop(L); - return 0; - } else { - throw std::runtime_error("table " + tableName + " not found"); - } + return get_from( + L, tableName, name, required, LUA_GLOBALSINDEX, "global" + ); + } + + inline int get_from_registry( + lua::State* L, + const std::string& tableName, + const std::string& name, + bool required = false + ) { + return get_from( + L, tableName, name, required, LUA_REGISTRYINDEX, "registry" + ); } int call(lua::State*, int argc, int nresults = -1); diff --git a/src/logic/scripting/scripting.cpp b/src/logic/scripting/scripting.cpp index 341470c17..bf9227390 100644 --- a/src/logic/scripting/scripting.cpp +++ b/src/logic/scripting/scripting.cpp @@ -742,7 +742,7 @@ void scripting::load_entity_component( std::string src = io::read_string(file); logger.info() << "script (component) " << file.string(); lua::loadbuffer(L, *env, src, fileName); - lua::store_in(L, lua::CHUNKS_TABLE, name); + lua::store_in_registry(L, lua::CHUNKS_TABLE, name); } void scripting::load_world_script( diff --git a/src/logic/scripting/scripting_entities.cpp b/src/logic/scripting/scripting_entities.cpp index 656cbbba6..375b382a9 100644 --- a/src/logic/scripting/scripting_entities.cpp +++ b/src/logic/scripting/scripting_entities.cpp @@ -94,7 +94,7 @@ static void create_component( auto compenv = create_component_environment( std::move(parentEnv), -1, component.name ); - lua::get_from(L, lua::CHUNKS_TABLE, component.name, true); + lua::get_from_registry(L, lua::CHUNKS_TABLE, component.name, true); lua::pushenv(L, *compenv); if (args != nullptr) {