diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml
index 75f3e351..1423e335 100644
--- a/.github/workflows/runner.yml
+++ b/.github/workflows/runner.yml
@@ -6,7 +6,7 @@ on:
branches:
- "*"
paths-ignore:
- - "README.md"
+ - "**/*.md"
- "LICENSE"
- "**/*.png"
- ".github/ISSUE_TEMPLATE/*"
@@ -16,7 +16,7 @@ on:
branches:
- "main"
paths-ignore:
- - "**/README.md"
+ - "**/*.md"
- "**/*.png"
- "**/LICENSE"
- ".github/ISSUE_TEMPLATE/*"
diff --git a/config.py b/config.py
index 6b1396d4..4bcd08c0 100644
--- a/config.py
+++ b/config.py
@@ -26,6 +26,7 @@ def get_doc_classes():
"LuaError",
"LuaTuple",
"LuaCallableExtra",
+ "LuaFunctionRef",
"LuaObjectMetatable",
"LuaDefaultObjectMetatable",
]
diff --git a/doc_classes/LuaAPI.xml b/doc_classes/LuaAPI.xml
index 4806a254..3fb84801 100644
--- a/doc_classes/LuaAPI.xml
+++ b/doc_classes/LuaAPI.xml
@@ -7,7 +7,7 @@
This class represents a lua state and allows you to interact with lua at runtime. You can load files and strings code. Push Callable's as lua functions. And push any Variant as a lua variable.
- w
+
@@ -131,6 +131,9 @@
Sets the memory limit for the state in bytes. If the limit is 0, there is no limit.
+
+ When true, Lua functions passed to Godot will use the LuaCallable type. This type is a CallableCustom which has issues currently with GDExtension and C#
+ When false, Lua functions passed to Godot will use the LuaFunctionRef type. This type is a RefCounted which behaves the same as a LuaCallable. But uses Inoke instead of Call.
diff --git a/doc_classes/LuaFunctionRef.xml b/doc_classes/LuaFunctionRef.xml
new file mode 100644
index 00000000..fba58160
--- /dev/null
+++ b/doc_classes/LuaFunctionRef.xml
@@ -0,0 +1,20 @@
+
+
+
+ Lua Function Reference.
+
+
+ Reference to a Lua function. This class is used to pass Lua functions to Godot.
+
+
+
+
+
+
+
+
+ Invoke the Lua function being referenced.
+
+
+
+
diff --git a/register_types.cpp b/register_types.cpp
index c1ece786..8e09f00f 100644
--- a/register_types.cpp
+++ b/register_types.cpp
@@ -3,6 +3,7 @@
#include "src/classes/luaCallableExtra.h"
#include "src/classes/luaCoroutine.h"
#include "src/classes/luaError.h"
+#include "src/classes/luaFunctionRef.h"
#include "src/classes/luaObjectMetatable.h"
#include "src/classes/luaTuple.h"
@@ -19,6 +20,7 @@ void initialize_luaAPI_module(ModuleInitializationLevel p_level) {
ClassDB::register_class();
ClassDB::register_class();
ClassDB::register_class();
+ ClassDB::register_class();
ClassDB::register_class();
ClassDB::register_class();
ClassDB::register_class();
diff --git a/src/classes/luaAPI.cpp b/src/classes/luaAPI.cpp
index aa0d9787..c6b4fdd7 100644
--- a/src/classes/luaAPI.cpp
+++ b/src/classes/luaAPI.cpp
@@ -45,12 +45,16 @@ void LuaAPI::_bind_methods() {
ClassDB::bind_method(D_METHOD("new_coroutine"), &LuaAPI::newCoroutine);
ClassDB::bind_method(D_METHOD("get_running_coroutine"), &LuaAPI::getRunningCoroutine);
+ ClassDB::bind_method(D_METHOD("set_use_callables", "value"), &LuaAPI::setUseCallables);
+ ClassDB::bind_method(D_METHOD("get_use_callables"), &LuaAPI::getUseCallables);
+
ClassDB::bind_method(D_METHOD("set_object_metatable", "value"), &LuaAPI::setObjectMetatable);
ClassDB::bind_method(D_METHOD("get_object_metatable"), &LuaAPI::getObjectMetatable);
ClassDB::bind_method(D_METHOD("set_memory_limit", "limit"), &LuaAPI::setMemoryLimit);
ClassDB::bind_method(D_METHOD("get_memory_limit"), &LuaAPI::getMemoryLimit);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_callables"), "set_use_callables", "get_use_callables");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "object_metatable"), "set_object_metatable", "get_object_metatable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "memory_limit"), "set_memory_limit", "get_memory_limit");
@@ -82,6 +86,14 @@ int LuaAPI::configureGC(int what, int data) {
return lua_gc(lState, what, data);
}
+void LuaAPI::setUseCallables(bool value) {
+ useCallables = value;
+}
+
+bool LuaAPI::getUseCallables() const {
+ return useCallables;
+}
+
void LuaAPI::setObjectMetatable(Ref value) {
objectMetatable = value;
}
diff --git a/src/classes/luaAPI.h b/src/classes/luaAPI.h
index 098385c1..9ef093e6 100644
--- a/src/classes/luaAPI.h
+++ b/src/classes/luaAPI.h
@@ -33,6 +33,9 @@ class LuaAPI : public RefCounted {
void bindLibraries(Array libs);
void setHook(Callable hook, int mask, int count);
+ void setUseCallables(bool value);
+ bool getUseCallables() const;
+
void setObjectMetatable(Ref value);
Ref getObjectMetatable() const;
@@ -82,6 +85,8 @@ class LuaAPI : public RefCounted {
};
private:
+ bool useCallables = true;
+
LuaState state;
lua_State *lState = nullptr;
diff --git a/src/classes/luaFunctionRef.cpp b/src/classes/luaFunctionRef.cpp
new file mode 100644
index 00000000..397dab7d
--- /dev/null
+++ b/src/classes/luaFunctionRef.cpp
@@ -0,0 +1,46 @@
+#include "luaFunctionRef.h"
+
+#include
+
+void LuaFunctionRef::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("invoke", "args"), &LuaFunctionRef::invoke);
+}
+
+LuaFunctionRef::LuaFunctionRef() {
+ L = nullptr;
+ ref = LUA_NOREF;
+}
+
+LuaFunctionRef::~LuaFunctionRef() {
+ luaL_unref(L, LUA_REGISTRYINDEX, ref);
+}
+
+void LuaFunctionRef::setLuaState(lua_State *state) {
+ L = state;
+}
+
+void LuaFunctionRef::setRef(int ref) {
+ this->ref = ref;
+}
+
+Variant LuaFunctionRef::invoke(Array args) {
+ lua_pushcfunction(L, LuaState::luaErrorHandler);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+
+ for (int i = 0; i < args.size(); i++) {
+ Variant arg = args[i];
+ LuaState::pushVariant(L, arg);
+ }
+
+ int err = lua_pcall(L, args.size(), 1, -2 - args.size());
+ Variant ret;
+ if (err) {
+ ret = LuaState::handleError(L, ret);
+ } else {
+ ret = LuaState::getVariant(L, -1);
+ }
+
+ lua_pop(L, 1);
+
+ return ret;
+}
\ No newline at end of file
diff --git a/src/classes/luaFunctionRef.h b/src/classes/luaFunctionRef.h
new file mode 100644
index 00000000..020e8d16
--- /dev/null
+++ b/src/classes/luaFunctionRef.h
@@ -0,0 +1,40 @@
+#ifndef LUAFUNCTIONREF_H
+#define LUAFUNCTIONREF_H
+
+#ifndef LAPI_GDEXTENSION
+#include "core/core_bind.h"
+#include "core/object/ref_counted.h"
+#else
+#include
+#endif
+
+#include
+
+#ifdef LAPI_GDEXTENSION
+using namespace godot;
+#endif
+
+class LuaFunctionRef : public RefCounted {
+ GDCLASS(LuaFunctionRef, RefCounted);
+
+protected:
+ static void _bind_methods();
+
+public:
+ LuaFunctionRef();
+ ~LuaFunctionRef();
+
+ void setLuaState(lua_State *state);
+ void setRef(int ref);
+
+ Variant invoke(Array args);
+
+ inline int getRef() const { return ref; }
+ inline lua_State *getLuaState() const { return L; }
+
+private:
+ lua_State *L;
+ int ref;
+};
+
+#endif
\ No newline at end of file
diff --git a/src/luaState.cpp b/src/luaState.cpp
index 97a02fd3..2aefeccc 100644
--- a/src/luaState.cpp
+++ b/src/luaState.cpp
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#ifndef LAPI_GDXTENSION
@@ -463,6 +464,20 @@ Ref LuaState::pushVariant(lua_State *state, Variant var) {
break;
}
+ // If the type being pushed is a thread, push a LUA_TTHREAD state.
+#ifndef LAPI_GDEXTENSION
+ if (Ref funcRef = Object::cast_to(var.operator Object *()); funcRef.is_valid()) {
+#else
+ // blame this on https://github.com/godotengine/godot-cpp/issues/995
+ if (Ref funcRef = dynamic_cast(var.operator Object *()); funcRef.is_valid()) {
+#endif
+ lua_rawgeti(state, LUA_REGISTRYINDEX, funcRef->getRef());
+ if (funcRef->getLuaState() != state) {
+ lua_xmove(funcRef->getLuaState(), state, 1);
+ }
+ break;
+ }
+
// If the type being pushed is a LuaCallableExtra. use mt_CallableExtra instead
#ifndef LAPI_GDEXTENSION
if (Ref func = Object::cast_to(var.operator Object *()); func.is_valid()) {
@@ -595,16 +610,25 @@ Variant LuaState::getVariant(lua_State *state, int index) {
break;
}
case LUA_TFUNCTION: {
+ Ref api = getAPI(state);
// Put function on the top of the stack and get a ref to it. This will create a copy of the function.
lua_pushvalue(state, index);
+ if (api->getUseCallables()) {
#ifndef LAPI_GDEXTENSION
- LuaCallable *callable = memnew(LuaCallable(Ref(getAPI(state)), luaL_ref(state, LUA_REGISTRYINDEX), state));
- result = Callable(callable);
+ LuaCallable *callable = memnew(LuaCallable(api, luaL_ref(state, LUA_REGISTRYINDEX), state));
+ result = Callable(callable);
#else
- Array binds;
- binds.push_back(luaL_ref(state, LUA_REGISTRYINDEX));
- result = Callable(getAPI(state), "call_function_ref").bindv(binds);
+ Array binds;
+ binds.push_back(luaL_ref(state, LUA_REGISTRYINDEX));
+ result = Callable(getAPI(state), "call_function_ref").bindv(binds);
#endif
+ } else {
+ Ref funcRef;
+ funcRef.instantiate();
+ funcRef->setRef(luaL_ref(state, LUA_REGISTRYINDEX));
+ funcRef->setLuaState(state);
+ result = funcRef;
+ }
break;
}
case LUA_TTHREAD: {