diff --git a/doc_classes/LuaAPI.xml b/doc_classes/LuaAPI.xml
index c5813a62..573b05c1 100644
--- a/doc_classes/LuaAPI.xml
+++ b/doc_classes/LuaAPI.xml
@@ -45,7 +45,7 @@
- Returns [code]true[/code] only if [code]LuaFunctionName[/code] is defined in current Lua's state as a function.
+ Returns [code]true[/code] only if [code]LuaFunctionName[/code] is defined in the global environment table as a function.
@@ -80,6 +80,21 @@
Will push a copy of a Variant to lua as a global. Returns a error if the type is not supported.
+
+
+
+
+ Will pull a copy of a Variant from lua's registry table.
+
+
+
+
+
+
+
+ Will push a copy of a Variant to lua's registry table. Returns a error if the type is not supported.
+
+
diff --git a/doc_classes/LuaCoroutine.xml b/doc_classes/LuaCoroutine.xml
index 7d27b899..af93680a 100644
--- a/doc_classes/LuaCoroutine.xml
+++ b/doc_classes/LuaCoroutine.xml
@@ -87,6 +87,21 @@
Will push a copy of a Variant to lua as a global. Returns a error if the type is not supported.
+
+
+
+
+ Will pull a copy of a Variant from lua's registry table.
+
+
+
+
+
+
+
+ Will push a copy of a Variant to lua's registry table. Returns a error if the type is not supported.
+
+
diff --git a/src/classes/luaAPI.cpp b/src/classes/luaAPI.cpp
index cbbdfb26..a2c69f1f 100644
--- a/src/classes/luaAPI.cpp
+++ b/src/classes/luaAPI.cpp
@@ -34,6 +34,8 @@ void LuaAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_memory_usage"), &LuaAPI::getMemoryUsage);
ClassDB::bind_method(D_METHOD("push_variant", "Name", "var"), &LuaAPI::pushGlobalVariant);
ClassDB::bind_method(D_METHOD("pull_variant", "Name"), &LuaAPI::pullVariant);
+ ClassDB::bind_method(D_METHOD("get_registry_value", "Name"), &LuaAPI::getRegistryValue);
+ ClassDB::bind_method(D_METHOD("set_registry_value", "Name", "var"), &LuaAPI::setRegistryValue);
ClassDB::bind_method(D_METHOD("call_function", "LuaFunctionName", "Args"), &LuaAPI::callFunction);
ClassDB::bind_method(D_METHOD("call_function_ref", "Args", "LuaFunctionRef"), &LuaAPI::callFunctionRef);
ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaAPI::luaFunctionExists);
@@ -94,6 +96,14 @@ uint64_t LuaAPI::getMemoryLimit() const {
return luaAllocData.memoryLimit;
}
+Variant LuaAPI::getRegistryValue(String name) {
+ return state.getRegistryValue(name);
+}
+
+Ref LuaAPI::setRegistryValue(String name, Variant var) {
+ return state.setRegistryValue(name, var);
+}
+
uint64_t LuaAPI::getMemoryUsage() const {
return luaAllocData.memoryUsed;
}
@@ -259,4 +269,4 @@ void *LuaAPI::luaAlloc(void *ud, void *ptr, size_t osize, size_t nsize) {
data->memoryUsed -= (uint64_t)osize;
data->memoryUsed += (uint64_t)nsize;
return memrealloc(ptr, nsize);
-}
\ No newline at end of file
+}
diff --git a/src/classes/luaAPI.h b/src/classes/luaAPI.h
index 92f04492..510eda10 100644
--- a/src/classes/luaAPI.h
+++ b/src/classes/luaAPI.h
@@ -48,6 +48,9 @@ class LuaAPI : public RefCounted {
Variant callFunction(String functionName, Array args);
Variant callFunctionRef(Array args, int funcRef);
+ Variant getRegistryValue(String name);
+ Ref setRegistryValue(String name, Variant var);
+
Ref doFile(String fileName);
Ref doString(String code);
Ref pushGlobalVariant(String name, Variant var);
diff --git a/src/classes/luaCoroutine.cpp b/src/classes/luaCoroutine.cpp
index c30b4fbd..c9bf7a60 100644
--- a/src/classes/luaCoroutine.cpp
+++ b/src/classes/luaCoroutine.cpp
@@ -23,6 +23,8 @@ void LuaCoroutine::_bind_methods() {
ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaCoroutine::luaFunctionExists);
ClassDB::bind_method(D_METHOD("push_variant", "Name", "var"), &LuaCoroutine::pushGlobalVariant);
ClassDB::bind_method(D_METHOD("pull_variant", "Name"), &LuaCoroutine::pullVariant);
+ ClassDB::bind_method(D_METHOD("get_registry_value", "Name"), &LuaCoroutine::getRegistryValue);
+ ClassDB::bind_method(D_METHOD("set_registry_value", "Name", "var"), &LuaCoroutine::setRegistryValue);
// This signal is only meant to be used by await when yield_await is called.
ADD_SIGNAL(MethodInfo("coroutine_resume"));
@@ -85,6 +87,16 @@ Variant LuaCoroutine::callFunction(String functionName, Array args) {
return state.callFunction(functionName, args);
}
+// Calls LuaState::getRegistryValue()
+Variant LuaCoroutine::getRegistryValue(String name) {
+ return state.getRegistryValue(name);
+}
+
+// Calls LuaState::setRegistryValue()
+Ref LuaCoroutine::setRegistryValue(String name, Variant var) {
+ return state.setRegistryValue(name, var);
+}
+
// loads a string into the threads state
Ref LuaCoroutine::loadString(String code) {
done = false;
diff --git a/src/classes/luaCoroutine.h b/src/classes/luaCoroutine.h
index e3f2616b..02f50a1a 100644
--- a/src/classes/luaCoroutine.h
+++ b/src/classes/luaCoroutine.h
@@ -34,6 +34,9 @@ class LuaCoroutine : public RefCounted {
bool luaFunctionExists(String functionName);
+ Variant getRegistryValue(String name);
+ Ref setRegistryValue(String name, Variant var);
+
Ref loadString(String code);
Ref loadFile(String fileName);
Ref pushGlobalVariant(String name, Variant var);
diff --git a/src/luaState.cpp b/src/luaState.cpp
index 72d7c49d..aaa0cacc 100644
--- a/src/luaState.cpp
+++ b/src/luaState.cpp
@@ -43,7 +43,7 @@ lua_State *LuaState::getState() const {
#ifndef LAPI_LUAJIT
-// Binds lua librares with the lua state
+// Binds lua libraries with the lua state
void LuaState::bindLibraries(Array libs) {
for (int i = 0; i < libs.size(); i++) {
String lib = ((String)libs[i]).to_lower();
@@ -85,7 +85,7 @@ void LuaState::bindLibraries(Array libs) {
#else
-// Binds lua librares with the lua state
+// Binds lua libraries with the lua state
void LuaState::bindLibraries(Array libs) {
for (int i = 0; i < libs.size(); i++) {
String lib = ((String)libs[i]).to_lower();
@@ -141,10 +141,52 @@ void LuaState::setHook(Callable hook, int mask, int count) {
lua_sethook(L, luaHook, mask, count);
}
+void LuaState::indexForReading(String name) {
+#ifndef LAPI_GDEXTENSION
+ Vector strs = name.split(".");
+#else
+ PackedStringArray strs = name.split(".");
+#endif
+ for (String str : strs) {
+ if (lua_type(L, -1) != LUA_TTABLE) {
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ break;
+ }
+ lua_getfield(L, -1, str.ascii().get_data());
+ lua_remove(L, -2);
+ }
+}
+
+String LuaState::indexForWriting(String name) {
+#ifndef LAPI_GDEXTENSION
+ Vector strs = name.split(".");
+#else
+ PackedStringArray strs = name.split(".");
+#endif
+ String last = strs[strs.size() - 1];
+ strs.remove_at(strs.size() - 1);
+ for (String str : strs) {
+ if (lua_type(L, -1) != LUA_TTABLE) {
+ lua_pop(L, 1);
+ lua_pushnil(L);
+ break;
+ }
+ lua_getfield(L, -1, str.ascii().get_data());
+ lua_remove(L, -2);
+ }
+ return last;
+}
+
// Returns true if a lua function exists with the given name
bool LuaState::luaFunctionExists(String functionName) {
+#ifndef LAPI_LUAJIT
+ lua_pushglobaltable(L);
+#else
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+#endif
+ indexForReading(functionName);
// LuaJIT does not return a type here
- lua_getglobal(L, functionName.ascii().get_data());
int type = lua_type(L, -1);
lua_pop(L, 1);
return type == LUA_TFUNCTION;
@@ -157,20 +199,52 @@ Variant LuaState::getVar(int index) const {
// Pull a global variant from Lua to GDScript
Variant LuaState::pullVariant(String name) {
- lua_getglobal(L, name.ascii().get_data());
+#ifndef LAPI_LUAJIT
+ lua_pushglobaltable(L);
+#else
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+#endif
+ indexForReading(name);
+ Variant val = getVar(-1);
+ lua_pop(L, 1);
+ return val;
+}
+Variant LuaState::getRegistryValue(String name) {
+ lua_pushvalue(L, LUA_REGISTRYINDEX);
+ indexForReading(name);
Variant val = getVar(-1);
lua_pop(L, 1);
return val;
}
+Ref LuaState::setRegistryValue(String name, Variant var) {
+ lua_pushvalue(L, LUA_REGISTRYINDEX);
+ String field = indexForWriting(name);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ return LuaError::newError("cannot index nil with string", LuaError::ERR_RUNTIME); // Make it look natural.
+ }
+ Ref err = pushVariant(var);
+ if (err.is_null()) {
+ lua_setfield(L, -2, field.ascii().get_data());
+ lua_pop(L, 1);
+ return nullptr;
+ }
+ lua_pop(L, 1);
+ return err;
+}
+
// call a Lua function from GDScript
Variant LuaState::callFunction(String functionName, Array args) {
// push the error handler on to the stack
lua_pushcfunction(L, luaErrorHandler);
- // put global function name on stack
- lua_getglobal(L, functionName.ascii().get_data());
-
+#ifndef LAPI_LUAJIT
+ lua_pushglobaltable(L);
+#else
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+#endif
+ indexForReading(functionName);
// push args
for (int i = 0; i < args.size(); ++i) {
pushVariant(args[i]);
@@ -193,11 +267,23 @@ Ref LuaState::pushVariant(Variant var) const {
// Call pushVariant() and set it to a global name
Ref LuaState::pushGlobalVariant(String name, Variant var) {
+#ifndef LAPI_LUAJIT
+ lua_pushglobaltable(L);
+#else
+ lua_pushvalue(L, LUA_GLOBALSINDEX);
+#endif
+ String field = indexForWriting(name);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ return LuaError::newError("cannot index nil with string", LuaError::ERR_RUNTIME); // Make it look natural.
+ }
Ref err = pushVariant(var);
if (err.is_null()) {
- lua_setglobal(L, name.ascii().get_data());
+ lua_setfield(L, -2, field.ascii().get_data());
+ lua_pop(L, 1);
return nullptr;
}
+ lua_pop(L, 1);
return err;
}
@@ -332,7 +418,7 @@ Ref LuaState::pushVariant(lua_State *state, Variant var) {
break;
}
- // If the type being pushed is a lua error, Raise a error
+ // If the type being pushed is a lua error, Raise an error
#ifndef LAPI_GDEXTENSION
if (Ref err = Object::cast_to(var.operator Object *()); !err.is_null()) {
#else
diff --git a/src/luaState.h b/src/luaState.h
index b298f970..6c797ff4 100644
--- a/src/luaState.h
+++ b/src/luaState.h
@@ -29,6 +29,9 @@ class LuaState {
Variant pullVariant(String name);
Variant callFunction(String functionName, Array args);
+ Variant getRegistryValue(String name);
+ Ref setRegistryValue(String name, Variant var);
+
Ref pushVariant(Variant var) const;
Ref pushGlobalVariant(String name, Variant var);
Ref handleError(int lua_error) const;
@@ -55,6 +58,10 @@ class LuaState {
private:
lua_State *L = nullptr;
+ // Helper functions for recursive indexing
+ void indexForReading(String name); // Puts the object on the stack
+ String indexForWriting(String name); // Puts the table on the stack and gives the last name. (Please make sure the table is not nil.)
+
void exposeConstructors();
void createVector2Metatable();
void createVector3Metatable();