diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml index 95d65138..df3d3355 100644 --- a/.github/workflows/android-build.yml +++ b/.github/workflows/android-build.yml @@ -17,7 +17,7 @@ env: BASE_BRANCH: main SCONSFLAGS: "production=yes extra_suffix=luaAPI" SCONS_CACHE_LIMIT: 7168 - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} jobs: android-builds: diff --git a/.github/workflows/gdextension-unit-tests.yml b/.github/workflows/gdextension-unit-tests.yml index 409311e5..64f3125f 100644 --- a/.github/workflows/gdextension-unit-tests.yml +++ b/.github/workflows/gdextension-unit-tests.yml @@ -18,7 +18,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Download godot ${{ inputs.godot_version }} - run: wget -O godot.zip https://downloads.tuxfamily.org/godotengine/${{ inputs.godot_version }}/Godot_v${{ inputs.godot_version }}-stable_linux.x86_64.zip + run: wget -O godot.zip https://github.com/godotengine/godot-builds/releases/download/4.2-beta2/Godot_v4.2-beta2_linux.x86_64.zip - name: Extract godot run: | 7z x godot.zip @@ -48,7 +48,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Download godot ${{ inputs.godot_version }} - run: wget -O godot.zip https://downloads.tuxfamily.org/godotengine/${{ inputs.godot_version }}/Godot_v${{ inputs.godot_version }}-stable_linux.x86_64.zip + run: wget -O godot.zip https://github.com/godotengine/godot-builds/releases/download/4.2-beta2/Godot_v4.2-beta2_linux.x86_64.zip - name: Extract godot run: | 7z x godot.zip diff --git a/.github/workflows/gdextension.yml b/.github/workflows/gdextension.yml index f87e3410..f2a7579c 100644 --- a/.github/workflows/gdextension.yml +++ b/.github/workflows/gdextension.yml @@ -15,7 +15,7 @@ on: env: BASE_BRANCH: main - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} jobs: gdextension: diff --git a/.github/workflows/ios-build.yml b/.github/workflows/ios-build.yml index 6c1908d4..54c53bc3 100644 --- a/.github/workflows/ios-build.yml +++ b/.github/workflows/ios-build.yml @@ -17,7 +17,7 @@ env: BASE_BRANCH: main SCONSFLAGS: "production=yes extra_suffix=luaAPI" SCONS_CACHE_LIMIT: 7168 - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} jobs: ios-builds: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 948c48b1..82319107 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -17,7 +17,7 @@ env: BASE_BRANCH: main SCONSFLAGS: "production=yes extra_suffix=luaAPI" SCONS_CACHE_LIMIT: 7168 - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} jobs: linux-builds: diff --git a/.github/workflows/macos-build.yml b/.github/workflows/macos-build.yml index a34c27fa..4f5525a5 100644 --- a/.github/workflows/macos-build.yml +++ b/.github/workflows/macos-build.yml @@ -17,7 +17,7 @@ env: BASE_BRANCH: main SCONSFLAGS: "production=yes extra_suffix=luaAPI" SCONS_CACHE_LIMIT: 7168 - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} jobs: macos-builds: diff --git a/.github/workflows/macos-package.yml b/.github/workflows/macos-package.yml index 2c13bb26..9a3afee5 100644 --- a/.github/workflows/macos-package.yml +++ b/.github/workflows/macos-package.yml @@ -64,7 +64,7 @@ jobs: uses: actions/checkout@v3 with: repository: godotengine/godot - ref: ${{ inputs.godot_version }}-stable + ref: ${{ inputs.godot_version }} path: scripts/godot - name: Download Artifact diff --git a/.github/workflows/runner.yml b/.github/workflows/runner.yml index 1423e335..df97ed2d 100644 --- a/.github/workflows/runner.yml +++ b/.github/workflows/runner.yml @@ -24,7 +24,7 @@ on: - "project/demo/*" env: - GODOT_VERSION: 4.1.2 + GODOT_VERSION: master jobs: static-checks: @@ -37,7 +37,7 @@ jobs: uses: ./.github/workflows/linux.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master macos-build: name: 🍎 macOS @@ -45,7 +45,7 @@ jobs: uses: ./.github/workflows/macos-build.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master macos-package: name: 🍎 macOS Package @@ -53,7 +53,7 @@ jobs: uses: ./.github/workflows/macos-package.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master android-build: name: 🤖 Android @@ -61,7 +61,7 @@ jobs: uses: ./.github/workflows/android-build.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master android-package: name: 🤖 Android Package @@ -75,7 +75,7 @@ jobs: uses: ./.github/workflows/ios-build.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master ios-package: name: 🍎 IOS Package @@ -89,7 +89,7 @@ jobs: uses: ./.github/workflows/web.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master windows-build: name: 🎨 Windows @@ -97,7 +97,7 @@ jobs: uses: ./.github/workflows/windows.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master gdextension-build: name: ⚙️ GDExtension @@ -105,7 +105,7 @@ jobs: uses: ./.github/workflows/gdextension.yml with: fullbuild: ${{ github.event_name == 'workflow_dispatch' }} - godot_version: 4.1.2 + godot_version: master module-unit-tests: name: ⚙️ Module Unit Tests @@ -117,7 +117,7 @@ jobs: needs: gdextension-build uses: ./.github/workflows/gdextension-unit-tests.yml with: - godot_version: 4.1.2 + godot_version: master template-version-file: name: 📝 Create template version file diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml index 8dc3b368..a4129862 100644 --- a/.github/workflows/web.yml +++ b/.github/workflows/web.yml @@ -17,7 +17,7 @@ env: BASE_BRANCH: main SCONSFLAGS: "production=yes extra_suffix=luaAPI optimize=size" SCONS_CACHE_LIMIT: 7168 - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} EM_VERSION: 3.1.18 EM_CACHE_FOLDER: "emsdk-cache" diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index afcccec7..cea56bad 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -16,7 +16,7 @@ env: BASE_BRANCH: main SCONSFLAGS: "production=yes extra_suffix=luaAPI" SCONS_CACHE_LIMIT: 7168 - GODOT_VERSION: ${{ inputs.godot_version }}-stable + GODOT_VERSION: ${{ inputs.godot_version }} jobs: windows-builds: diff --git a/doc_classes/LuaAPI.xml b/doc_classes/LuaAPI.xml index 379309b8..29ac2fc0 100644 --- a/doc_classes/LuaAPI.xml +++ b/doc_classes/LuaAPI.xml @@ -61,15 +61,6 @@ Calls a function inside current Lua state. This can be either a exposed function or a function defined with with Lua. You may want to check if the function actually exists with [code]function_exists(LuaFunctionName)[/code]. This function supports 1 return value from lua. It will be returned as a variant and if Lua returns no value it will be null. If an error occurs while calling this function, a LuaError object will be returned. - - - - - - This method is used to create a Callable when pulling a lua function from the stack. It is not intended to be called directly. - When returning a Callable, the function ref is bound to the Callable. You must only supply the arguments. - - diff --git a/external/godot-cpp b/external/godot-cpp index c297228f..b733a165 160000 --- a/external/godot-cpp +++ b/external/godot-cpp @@ -1 +1 @@ -Subproject commit c297228fb02cc35afd5b2b259549cbdc64fd7f66 +Subproject commit b733a165db881c0b188332941703f94931cc4544 diff --git a/project/addons/luaAPI/luaAPI.gdextension b/project/addons/luaAPI/luaAPI.gdextension index af4c6801..d0d4d596 100644 --- a/project/addons/luaAPI/luaAPI.gdextension +++ b/project/addons/luaAPI/luaAPI.gdextension @@ -1,6 +1,6 @@ [configuration] entry_symbol = "luaAPI_library_init" -compatibility_minimum = 4.1 +compatibility_minimum = 4.2 [libraries] linux.x86_64.debug = "bin/libluaapi.linux.template_debug.x86_64.so" diff --git a/project/project.godot b/project/project.godot index f9afaa40..2b230f55 100644 --- a/project/project.godot +++ b/project/project.godot @@ -12,7 +12,7 @@ config_version=5 config/name="LuaAPI Test Project" run/main_scene="res://testing/run_tests.tscn" -config/features=PackedStringArray("4.1", "Mobile") +config/features=PackedStringArray("4.2", "Mobile") [autoload] diff --git a/project/testing/tests/LuaAPI.call_function.gd b/project/testing/tests/LuaAPI.call_function.gd index e2243a87..70020c99 100644 --- a/project/testing/tests/LuaAPI.call_function.gd +++ b/project/testing/tests/LuaAPI.call_function.gd @@ -54,7 +54,7 @@ func _process(delta): errors.append(LuaError.new_error("testCallable is not Callable but is '%d'" % typeof(testCallable), LuaError.ERR_TYPE)) return fail() - var cret = testCallable.call([5]) + var cret = testCallable.call(5) if cret is LuaError: errors.append(cret) return fail() diff --git a/src/classes/luaAPI.cpp b/src/classes/luaAPI.cpp index b8ed1cb8..e95db409 100644 --- a/src/classes/luaAPI.cpp +++ b/src/classes/luaAPI.cpp @@ -37,9 +37,6 @@ void LuaAPI::_bind_methods() { 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); -#ifdef LAPI_GDEXTENSION - ClassDB::bind_method(D_METHOD("call_function_ref", "Args", "LuaFunctionRef"), &LuaAPI::callFunctionRef); -#endif ClassDB::bind_method(D_METHOD("function_exists", "LuaFunctionName"), &LuaAPI::luaFunctionExists); ClassDB::bind_method(D_METHOD("new_coroutine"), &LuaAPI::newCoroutine); @@ -137,33 +134,6 @@ Variant LuaAPI::callFunction(String functionName, Array args) { return state.callFunction(functionName, args); } -#ifdef LAPI_GDEXTENSION -// Invokes the passed lua reference -Variant LuaAPI::callFunctionRef(Array args, int funcRef) { - lua_pushcfunction(lState, LuaState::luaErrorHandler); - - // Getting the lua function via the reference stored in funcRef - lua_rawgeti(lState, LUA_REGISTRYINDEX, funcRef); - - // Push all the argument on to the stack - for (int i = 0; i < args.size(); i++) { - LuaState::pushVariant(lState, args[i]); - } - - Variant toReturn; - // execute the function using a protected call. - int ret = lua_pcall(lState, args.size(), 1, -2 - args.size()); - if (ret != LUA_OK) { - toReturn = LuaState::handleError(lState, ret); - } else { - toReturn = LuaState::getVariant(lState, -1); - } - - lua_pop(lState, 1); - return toReturn; -} -#endif - // Calls LuaState::pushGlobalVariant() Ref LuaAPI::pushGlobalVariant(String name, Variant var) { return state.pushGlobalVariant(name, var); diff --git a/src/classes/luaAPI.h b/src/classes/luaAPI.h index ec948b39..8914a306 100644 --- a/src/classes/luaAPI.h +++ b/src/classes/luaAPI.h @@ -48,9 +48,6 @@ class LuaAPI : public RefCounted { Variant pullVariant(String name); Variant callFunction(String functionName, Array args); -#ifdef LAPI_GDEXTENSION - Variant callFunctionRef(Array args, int funcRef); -#endif Variant getRegistryValue(String name); diff --git a/src/classes/luaCallable.cpp b/src/classes/luaCallable.cpp index 1f620076..698185e5 100644 --- a/src/classes/luaCallable.cpp +++ b/src/classes/luaCallable.cpp @@ -1,13 +1,17 @@ -#ifndef LAPI_GDEXTENSION - #include "luaCallable.h" #include "luaAPI.h" +#ifndef LAPI_GDEXTENSION #include "core/templates/hashfuncs.h" +#else +#include +#include +#endif // I used "GDScriptLambdaCallable" as a template for this LuaCallable::LuaCallable(Ref p_obj, int ref, lua_State *p_state) { obj = p_obj; + objectID = obj->get_instance_id(); funcRef = ref; state = p_state; h = (uint32_t)hash_djb2_one_64((uint64_t)this); @@ -17,12 +21,12 @@ LuaCallable::~LuaCallable() { luaL_unref(state, LUA_REGISTRYINDEX, funcRef); } -bool LuaCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { +LAPI_BOOL LuaCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) { // Lua callables are only compared by reference. return p_a == p_b; } -bool LuaCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { +LAPI_BOOL LuaCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) { // Lua callables are only compared by reference. return p_a < p_b; } @@ -35,9 +39,15 @@ CallableCustom::CompareLessFunc LuaCallable::get_compare_less_func() const { return compare_less; } +#ifndef LAPI_GDEXTENSION ObjectID LuaCallable::get_object() const { - return obj->get_instance_id(); + return objectID; } +#else +Object *LuaCallable::get_object() const { + return Object::cast_to(obj.ptr()); +} +#endif String LuaCallable::get_as_text() const { // I dont know of a way to get a useful name from the function @@ -53,31 +63,20 @@ uint32_t LuaCallable::hash() const { return h; } -void LuaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const { +bool LuaCallable::is_valid() const { + return ObjectDB::get_instance(objectID); +} + +void LuaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, LAPI_CALL_ERROR &r_call_error) const { lua_pushcfunction(state, LuaState::luaErrorHandler); // Getting the lua function via the reference stored in funcRef lua_rawgeti(state, LUA_REGISTRYINDEX, funcRef); - // ------------------ - // This is a hack to match the API with the GDExtension Callable workaround - if (p_argcount != 1 || p_arguments[0]->get_type() != Variant::Type::ARRAY) { - r_return_value = LuaError::newError("LuaCallable arguments must be supplied with a Godot Array", LuaError::ERR_TYPE); - return; - } - - Array args = p_arguments[0]->operator Array(); - for (int i = 0; i < args.size(); i++) { - LuaState::pushVariant(state, args[i]); - } - - p_argcount = args.size(); - // ------------------ - // Push all the argument on to the stack - // for (int i = 0; i < p_argcount; i++) { - // LuaState::pushVariant(state, *p_arguments[i]); - // } + for (int i = 0; i < p_argcount; i++) { + LuaState::pushVariant(state, *p_arguments[i]); + } // execute the function using a protected call. int ret = lua_pcall(state, p_argcount, 1, -2 - p_argcount); @@ -88,9 +87,14 @@ void LuaCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_r } lua_pop(state, 1); +// TODO: Tie the error handling systems together? +#ifndef LAPI_GDEXTENSION + r_call_error.error = LAPI_CALL_ERROR::CALL_OK; +#else + r_call_error.error = GDExtensionCallErrorType::GDEXTENSION_CALL_OK; +#endif } int LuaCallable::getFuncRef() { return funcRef; -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/classes/luaCallable.h b/src/classes/luaCallable.h index 175d5f0c..f81a1048 100644 --- a/src/classes/luaCallable.h +++ b/src/classes/luaCallable.h @@ -1,10 +1,13 @@ -#ifndef LAPI_GDEXTENSION - #ifndef LUACALLABLE_H #define LUACALLABLE_H +#ifndef LAPI_GDEXTENSION #include "core/object/ref_counted.h" #include "core/variant/callable.h" +#else +#include +#include +#endif #include @@ -12,32 +15,44 @@ #ifdef LAPI_GDEXTENSION using namespace godot; +#define LAPI_BOOL GDExtensionBool +#define LAPI_CALL_ERROR GDExtensionCallError +#else +#define LAPI_BOOL bool +#define LAPI_CALL_ERROR Callable::CallError #endif class LuaCallable : public CallableCustom { - static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); - static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b); + static LAPI_BOOL compare_equal(const CallableCustom *p_a, const CallableCustom *p_b); + static LAPI_BOOL compare_less(const CallableCustom *p_a, const CallableCustom *p_b); uint32_t h; public: - uint32_t hash() const override; - String get_as_text() const override; - CompareEqualFunc get_compare_equal_func() const override; - CompareLessFunc get_compare_less_func() const override; - ObjectID get_object() const override; - lua_State *getLuaState() const; - void call(const Variant **p_argument, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override; + LuaCallable(Ref obj, int ref, lua_State *p_state); + virtual ~LuaCallable() override; - int getFuncRef(); + virtual uint32_t hash() const override; + virtual String get_as_text() const override; + virtual CompareEqualFunc get_compare_equal_func() const override; + virtual CompareLessFunc get_compare_less_func() const override; - LuaCallable(Ref obj, int ref, lua_State *p_state); - ~LuaCallable() override; +#ifndef LAPI_GDEXTENSION + virtual ObjectID get_object() const override; +#else + virtual Object *get_object() const override; +#endif + + virtual void call(const Variant **p_argument, int p_argcount, Variant &r_return_value, LAPI_CALL_ERROR &r_call_error) const override; + virtual bool is_valid() const override; + + int getFuncRef(); + lua_State *getLuaState() const; private: int funcRef; + ObjectID objectID; Ref obj; lua_State *state = nullptr; }; -#endif #endif \ No newline at end of file diff --git a/src/luaState.cpp b/src/luaState.cpp index 3806dc9f..4cb95c3f 100644 --- a/src/luaState.cpp +++ b/src/luaState.cpp @@ -2,6 +2,7 @@ #include "lua/lua.h" #include +#include #include #include #include @@ -9,10 +10,6 @@ #include -#ifndef LAPI_GDXTENSION -#include -#endif - #include void LuaState::setState(lua_State *state, LuaAPI *api, bool bindAPI) { @@ -427,10 +424,8 @@ Ref LuaState::pushVariant(lua_State *state, Variant var) { break; } - if (callable.is_custom()) { - // If the type being pushed is a lua function ref, push the ref instead. #ifndef LAPI_GDEXTENSION - Ref callObj = Object::cast_to(callable.get_object()); + if (callable.is_custom()) { CallableCustom *custom = callable.get_custom(); LuaCallable *luaCallable = dynamic_cast(custom); if (luaCallable != nullptr) { @@ -440,20 +435,6 @@ Ref LuaState::pushVariant(lua_State *state, Variant var) { } break; } -#else - Ref callObj = dynamic_cast(callable.get_object()); - if (callObj.is_valid() && (String)callable.get_method() == "call_function_ref") { - Array argBinds = callable.get_bound_arguments(); - if (argBinds.size() == 1) { - lua_State *refState = callObj->getState(); - lua_rawgeti(refState, LUA_REGISTRYINDEX, (int)argBinds[0]); - if (refState != state) { - lua_xmove(refState, state, 1); - } - break; - } - } -#endif // A work around to preserve ref count of CallableCustoms Ref callableCustom; @@ -462,6 +443,7 @@ Ref LuaState::pushVariant(lua_State *state, Variant var) { LuaState::pushVariant(state, callableCustom); break; } +#endif Variant *userdata = (Variant *)lua_newuserdata(state, sizeof(Variant)); memnew_placement(userdata, Variant(var)); @@ -537,14 +519,8 @@ Variant LuaState::getVariant(lua_State *state, int index) { // 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(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); -#endif } else { Ref funcRef; funcRef.instantiate();