diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4fa48de..6134475 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -191,23 +191,23 @@ jobs: include: - name: Linux runner-os: ubuntu-latest - godot-release: 4.4-stable/Godot_v4.4-stable_linux.x86_64.zip - godot-bin: ./Godot_v4.4-stable_linux.x86_64 + godot-release: 4.4.1-stable/Godot_v4.4.1-stable_linux.x86_64.zip + godot-bin: ./Godot_v4.4.1-stable_linux.x86_64 - name: Linux (arm64) runner-os: ubuntu-24.04-arm - godot-release: 4.4-stable/Godot_v4.4-stable_linux.arm64.zip - godot-bin: ./Godot_v4.4-stable_linux.arm64 + godot-release: 4.4.1-stable/Godot_v4.4.1-stable_linux.arm64.zip + godot-bin: ./Godot_v4.4.1-stable_linux.arm64 - name: Windows runner-os: windows-latest - godot-release: 4.4-stable/Godot_v4.4-stable_win64.exe.zip - godot-bin: ./Godot_v4.4-stable_win64.exe + godot-release: 4.4.1-stable/Godot_v4.4.1-stable_win64.exe.zip + godot-bin: ./Godot_v4.4.1-stable_win64.exe - name: Windows (arm64) runner-os: windows-11-arm - godot-release: 4.4-stable/Godot_v4.4-stable_windows_arm64.exe.zip - godot-bin: ./Godot_v4.4-stable_windows_arm64.exe + godot-release: 4.4.1-stable/Godot_v4.4.1-stable_windows_arm64.exe.zip + godot-bin: ./Godot_v4.4.1-stable_windows_arm64.exe - name: macOS runner-os: macos-latest - godot-release: 4.4-stable/Godot_v4.4-stable_macos.universal.zip + godot-release: 4.4.1-stable/Godot_v4.4.1-stable_macos.universal.zip godot-bin: ./Godot.app/Contents/MacOS/Godot env: GODOT_BIN: ${{ matrix.godot-bin }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b04656..40cfe06 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog ## [Unreleased](https://github.com/gilzoide/lua-gdextension/compare/0.6.0...HEAD) +### Changed +- Opening `GODOT_CLASSES` now registers all classes at once instead of setting up a lazy getter in `_G`'s metatable +- Opening `GODOT_SINGLETONS` now registers all singletons at once instead of setting up a lazy getter in `_G`'s metatable + ## [0.6.0](https://github.com/gilzoide/lua-gdextension/releases/tag/0.6.0) diff --git a/doc_classes/LuaState.xml b/doc_classes/LuaState.xml index bd8e1b6..506e152 100644 --- a/doc_classes/LuaState.xml +++ b/doc_classes/LuaState.xml @@ -285,7 +285,7 @@ [b]Note: This may override some Lua functions like [code]print[/code].[/b] - Godot singletons library. + Godot singletons library. Adds global singletons like [Engine] and [ResourceLoader] to _G. Godot classes library. Adds Godot classes like [Node] to _G. @@ -293,7 +293,7 @@ [gdscript] var lua_state = LuaState.new() lua_state.open_libraries(LuaState.Library.LUA_BASE | LuaState.Library.GODOT_CLASSES) - var vec3 = lua_state.do_string(""" + var node = lua_state.do_string(""" -- Create a Node in Lua local node = Node:new() return node diff --git a/src/LuaState.cpp b/src/LuaState.cpp index 1295fb7..a307217 100644 --- a/src/LuaState.cpp +++ b/src/LuaState.cpp @@ -25,7 +25,6 @@ #include "LuaTable.hpp" #include "LuaThread.hpp" #include "luaopen/godot.hpp" -#include "utils/_G_metatable.hpp" #include "utils/convert_godot_lua.hpp" #include "utils/module_names.hpp" @@ -75,7 +74,6 @@ LuaState::LuaState() : lua_state(lua_panic_handler, lua_alloc) #endif { - setup_G_metatable(lua_state); #ifdef HAVE_LUA_WARN lua_setwarnf(lua_state, lua_warn_handler, this); #endif @@ -153,12 +151,12 @@ void LuaState::open_libraries(BitField libraries) { if (libraries.has_flag(GODOT_UTILITY_FUNCTIONS)) { lua_state.require(module_names::utility_functions, &luaopen_godot_utility_functions, false); } - if (libraries.has_flag(GODOT_SINGLETONS)) { - lua_state.require(module_names::singleton_access, &luaopen_godot_singleton_access, false); - } if (libraries.has_flag(GODOT_CLASSES)) { lua_state.require(module_names::classes, &luaopen_godot_classes, false); } + if (libraries.has_flag(GODOT_SINGLETONS)) { + lua_state.require(module_names::singleton_access, &luaopen_godot_singleton_access, false); + } if (libraries.has_flag(GODOT_ENUMS)) { lua_state.require(module_names::enums, &luaopen_godot_enums, false); } diff --git a/src/luaopen/classes.cpp b/src/luaopen/classes.cpp index 2512d74..0f93bac 100644 --- a/src/luaopen/classes.cpp +++ b/src/luaopen/classes.cpp @@ -19,19 +19,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ - #include "../utils/Class.hpp" -#include "../utils/module_names.hpp" -#include +#include using namespace luagdextension; extern "C" int luaopen_godot_classes(lua_State *L) { sol::state_view state = L; - state.registry()[module_names::classes] = true; Class::register_usertype(state); + ClassDBSingleton *classdb = ClassDBSingleton::get_singleton(); + for (auto&& class_name : classdb->get_class_list()) { + state.set(class_name.ascii().get_data(), Class(class_name)); + } return 0; } diff --git a/src/luaopen/godot.cpp b/src/luaopen/godot.cpp index 47a78cd..6cca070 100644 --- a/src/luaopen/godot.cpp +++ b/src/luaopen/godot.cpp @@ -33,8 +33,8 @@ extern "C" int luaopen_godot(lua_State *L) { state.require(module_names::variant, &luaopen_godot_variant, false); state.require(module_names::utility_functions, &luaopen_godot_utility_functions, false); - state.require(module_names::singleton_access, &luaopen_godot_singleton_access, false); state.require(module_names::classes, &luaopen_godot_classes, false); + state.require(module_names::singleton_access, &luaopen_godot_singleton_access, false); state.require(module_names::enums, &luaopen_godot_enums, false); state.require(module_names::local_paths, &luaopen_godot_local_paths, false); diff --git a/src/luaopen/singleton_access.cpp b/src/luaopen/singleton_access.cpp index 41963c2..9da4d2d 100644 --- a/src/luaopen/singleton_access.cpp +++ b/src/luaopen/singleton_access.cpp @@ -19,17 +19,17 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include "../utils/custom_sol.hpp" -#include "../utils/module_names.hpp" +#include -#include - -using namespace luagdextension; +using namespace godot; extern "C" int luaopen_godot_singleton_access(lua_State *L) { - sol::state_view state = L; - - state.registry()[module_names::singleton_access] = true; - + sol::state_view state(L); + Engine *engine = Engine::get_singleton(); + for (auto&& singleton_name : engine->get_singleton_list()) { + state.set(singleton_name.ascii().get_data(), engine->get_singleton(singleton_name)); + } return 0; } diff --git a/src/utils/_G_metatable.cpp b/src/utils/_G_metatable.cpp deleted file mode 100644 index 6b7eae8..0000000 --- a/src/utils/_G_metatable.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Copyright (C) 2025 Gil Barbosa Reis. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the “Software”), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include "_G_metatable.hpp" - -#include "Class.hpp" -#include "convert_godot_lua.hpp" -#include "module_names.hpp" - -#include -#include - -using namespace godot; - -namespace luagdextension { - -sol::object __index(sol::this_state state, sol::global_table _G, sol::stack_object key) { - static Engine *engine = Engine::get_singleton(); - - if (key.get_type() != sol::type::string) { - return sol::nil; - } - - auto registry = sol::state_view(state).registry(); - if (registry.get_or(module_names::singleton_access, false)) { - auto class_name = key.as(); - if (engine->has_singleton(class_name)) { - Variant singleton = engine->get_singleton(class_name); - return _G[key] = to_lua(state, singleton); - } - } - if (registry.get_or(module_names::classes, false)) { - StringName class_name = key.as(); - if (ClassDB::class_exists(class_name)) { - Class cls(class_name); - return _G[key] = sol::make_object(state, cls); - } - } - return sol::nil; -} - -void setup_G_metatable(sol::state_view& state) { - state.globals()[sol::metatable_key] = state.create_table_with( - sol::meta_function::index, &__index - ); -} - -} - diff --git a/src/utils/_G_metatable.hpp b/src/utils/_G_metatable.hpp deleted file mode 100644 index 64659bd..0000000 --- a/src/utils/_G_metatable.hpp +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright (C) 2025 Gil Barbosa Reis. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the “Software”), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef __UTILS_G_METATABLE_HPP__ -#define __UTILS_G_METATABLE_HPP__ - -#include - -namespace luagdextension { - -void setup_G_metatable(sol::state_view& state); - -} - -#endif // __UTILS_G_METATABLE_HPP__ diff --git a/test/test_entrypoint.gd b/test/test_entrypoint.gd index 2588e08..d5db46f 100644 --- a/test/test_entrypoint.gd +++ b/test/test_entrypoint.gd @@ -4,7 +4,7 @@ const LUA_TEST_DIR = "res://lua_tests" const GDSCRIPT_TEST_DIR = "res://gdscript_tests" func _initialize(): - var all_success = true + var error_count = 0 print("Starting Lua GDExtension tests (runtime: ", LuaState.get_lua_runtime(), ")") for lua_script in DirAccess.get_files_at(LUA_TEST_DIR): @@ -16,7 +16,7 @@ func _initialize(): var file_name = str(LUA_TEST_DIR, "/", lua_script) var result = lua_state.do_file(file_name) if result is LuaError: - all_success = false + error_count += 1 print("! ", lua_script) push_error(result.message) else: @@ -38,11 +38,12 @@ func _initialize(): obj._setup() # actual test if not obj.call(method_name): - all_success = false + error_count += 1 printerr(" ! ", method_name) else: print(" ✓ ", method_name) if obj is Node: obj.queue_free() - quit(0 if all_success else -1) + print("\nFailed tests: ", error_count) + quit(0 if error_count == 0 else -1)