Skip to content

Commit 0478360

Browse files
committed
Merge branch 'main' into feature/fill-classes-singletons
2 parents 14f9ff9 + 8e4d581 commit 0478360

File tree

21 files changed

+367
-165
lines changed

21 files changed

+367
-165
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,4 +273,6 @@ jobs:
273273
path: |
274274
LICENSE
275275
addons/lua-gdextension/**
276+
addons/lua-gdextension/build/.gdignore
277+
include-hidden-files: true
276278

CHANGELOG.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
2-
## [Unreleased](https://github.com/gilzoide/lua-gdextension/compare/0.5.0...HEAD)
2+
## [Unreleased](https://github.com/gilzoide/lua-gdextension/compare/0.6.0...HEAD)
3+
### Changed
4+
- Opening `GODOT_CLASSES` now registers all classes at once instead of setting up a lazy getter in `_G`'s metatable
5+
- Opening `GODOT_SINGLETONS` now registers all singletons at once instead of setting up a lazy getter in `_G`'s metatable
6+
7+
8+
9+
## [0.6.0](https://github.com/gilzoide/lua-gdextension/releases/tag/0.6.0)
310
### Added
411
- Support for constructing typed arrays in Lua using the idiom `Array[some_type]()`
512
- Support for constructing typed dictionaries in Lua using the idiom `Dictionary[key_type][value_type]()`
@@ -27,8 +34,13 @@
2734
+ In "Always Evaluate" behavior, Lua code will always be evaluated
2835
+ In "Don't Load" behavior, Lua code will not be loaded nor evaluated at all
2936
+ Note that only evaluated scripts can be attached to Godot Objects.
30-
- Opening `GODOT_CLASSES` now registers all classes at once instead of setting up a lazy getter in `_G`'s metatable
31-
- Opening `GODOT_SINGLETONS` now registers all singletons at once instead of setting up a lazy getter in `_G`'s metatable
37+
- Variant and `LuaScriptInstance` methods are now converted to Callable, so they can be more easily passed to Godot APIs such as `Signal.connect`
38+
```lua
39+
-- Before this change, we had to manually instantiate Callable
40+
some_signal:connect(Callable(self, "method_name"))
41+
-- Now we can pass the method directly
42+
some_signal:connect(self.method_name)
43+
```
3244

3345
### Fixed
3446
- Fixed cyclic references from `LuaScriptInstance` <-> `LuaState`, avoiding leaks of `LuaScript`s
@@ -40,6 +52,11 @@
4052
- Convert null Object Variants (`<Object#null>`) to `nil` when passing them to Lua
4153
- Convert freed Object Variants (`<Freed Object>`) to `nil` when passing them to Lua
4254
- Fixed `LuaJIT core/library version mismatch` errors in LuaJIT builds
55+
- `LuaScriptResourceFormatLoader::_load` now respects the cache mode, fixing "Another resource is loaded from path 'res://...' (possible cyclic resource inclusion)." errors
56+
- Error messages from Lua code using the wrong stack index
57+
- Crashes when passing Lua primitives to `typeof`, `Variant.is`, `Variant.get_type`, `Variant.booleanize`, `Variant.duplicate`, `Variant.get_type_name`, `Variant.hash`, `Variant.recursive_hash` and `Variant.hash_compare`
58+
- The `addons/lua-gdextension/build/.gdignore` file was added to the distributed build.
59+
This fixes import errors when opening the Godot editor with the LuaJIT build.
4360

4461

4562
## [0.5.0](https://github.com/gilzoide/lua-gdextension/releases/tag/0.5.0)

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Lua GDExtension
2-
[![Godot Asset Library page](https://img.shields.io/static/v1?logo=godotengine&label=asset%20library%20%28Lua%205.4%29&color=478CBF&message=0.5.0)](https://godotengine.org/asset-library/asset/2330)
3-
[![Godot Asset Library page](https://img.shields.io/static/v1?logo=godotengine&label=asset%20library%20%28LuaJIT%29&color=478CBF&message=0.5.0)](https://godotengine.org/asset-library/asset/2330)
2+
[![Godot Asset Library page](https://img.shields.io/static/v1?logo=godotengine&label=asset%20library%20%28Lua%205.4%29&color=478CBF&message=0.6.0)](https://godotengine.org/asset-library/asset/2330)
3+
[![Godot Asset Library page](https://img.shields.io/static/v1?logo=godotengine&label=asset%20library%20%28LuaJIT%29&color=478CBF&message=0.6.0)](https://godotengine.org/asset-library/asset/2330)
44
[![Build and Test workflow](https://github.com/gilzoide/lua-gdextension/actions/workflows/build.yml/badge.svg)](https://github.com/gilzoide/lua-gdextension/actions/workflows/build.yml)
55

66
<img src="addons/lua-gdextension/icon.png" alt="Lua GDExtension icon" width="150" height="150"/>
@@ -67,6 +67,9 @@ local LuaBouncingLogo = {
6767
function LuaBouncingLogo:_ready()
6868
self.position = self:get_viewport():get_size() / 2
6969
self.movement = Vector2(self.linear_velocity, 0):rotated(deg_to_rad(self.initial_angle))
70+
71+
-- To connect a signal in Lua, you can use the method name just like in GDScript
72+
self.bounced:connect(self._on_bounced)
7073
end
7174

7275
-- Called every frame. 'delta' is the elapsed time since the previous frame.
@@ -80,6 +83,10 @@ function LuaBouncingLogo:_process(delta)
8083
self.position = self.position + self.movement * delta
8184
end
8285

86+
function LuaBouncingLogo:_on_bounced()
87+
print("Bounced =D")
88+
end
89+
8390
-- Return the metadata table for the script to be usable by Godot objects
8491
return LuaBouncingLogo
8592
```

addons/lua-gdextension/plugin.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
name="Lua GDExtension"
44
description="Tools for Lua GDExtension: REPL tab"
55
author="gilzoide"
6-
version="0.5.0"
6+
version="0.6.0"
77
script="plugin.gd"

doc_classes/LuaFunction.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
[codeblocks]
2727
[gdscript]
2828
var lua_state = LuaState.new()
29-
var add_function = lua_state.load_string("return function(a, b) return a + b end")
29+
var add_function = lua_state.do_string("return function(a, b) return a + b end")
3030
# Call function using invoke
3131
var result = add_function.invoke(1, 2)
3232
print(result) # Prints 3
@@ -45,7 +45,7 @@
4545
[codeblocks]
4646
[gdscript]
4747
var lua_state = LuaState.new()
48-
var add_function = lua_state.load_string("return function(a, b) return a + b end")
48+
var add_function = lua_state.do_string("return function(a, b) return a + b end")
4949
# Call function using invokev
5050
var result = add_function.invokev([1, 2])
5151
print(result) # Prints 3

src/LuaError.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ String LuaError::extract_message(const sol::load_result& load_result) {
7575
}
7676

7777
String LuaError::extract_message(const sol::protected_function_result& function_result) {
78-
return luaL_tolstring(function_result.lua_state(), function_result.stack_index(), NULL);
78+
return luaL_tolstring(function_result.lua_state(), function_result.stack_index() + function_result.return_count() - 1, NULL);
7979
}
8080

8181
}

src/luaopen/variant.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,10 @@
3131
#include "../utils/IndexedIterator.hpp"
3232
#include "../utils/ObjectIterator.hpp"
3333
#include "../utils/VariantType.hpp"
34-
#include "../utils/MethodBindByName.hpp"
3534
#include "../utils/convert_godot_lua.hpp"
3635
#include "../utils/convert_godot_std.hpp"
36+
#include "../utils/function_wrapper.hpp"
37+
#include "../utils/method_bind_impl.hpp"
3738
#include "../utils/string_names.hpp"
3839

3940
using namespace godot;
@@ -87,7 +88,7 @@ sol::object variant__index(sol::this_state state, const Variant& variant, const
8788
return to_lua(state, variant.get_named(string_name, is_valid));
8889
}
8990
else if (variant.has_method(string_name)) {
90-
return sol::make_object(state, MethodBindByName(string_name));
91+
return sol::make_object(state, VariantMethodBind(variant, string_name));
9192
}
9293
}
9394

@@ -132,11 +133,12 @@ std::tuple<sol::object, sol::object> variant__pairs(sol::this_state state, const
132133
return ObjectIterator::object_pairs(state, variant);
133134
}
134135

135-
VariantType variant_get_type(const Variant& variant) {
136-
return VariantType(variant.get_type());
136+
VariantType variant_get_type(const sol::stack_object& self) {
137+
return VariantType(to_variant(self).get_type());
137138
}
138139

139-
bool variant_is(const Variant& variant, const sol::stack_object& type) {
140+
bool variant_is(const sol::stack_object& self, const sol::stack_object& type) {
141+
Variant variant = to_variant(self);
140142
if (type.get_type() == sol::type::nil) {
141143
return variant.get_type() == Variant::NIL;
142144
}
@@ -186,15 +188,15 @@ extern "C" int luaopen_godot_variant(lua_State *L) {
186188
Variant(double v),
187189
Variant(const char *v)
188190
>(),
189-
"booleanize", &Variant::booleanize,
190-
"duplicate", &Variant::duplicate,
191+
"booleanize", wrap_function(L, +[](const Variant& v) { return v.booleanize(); }),
192+
"duplicate", wrap_function(L, +[](const Variant& self) { return self.duplicate(); }),
191193
"call", &variant_call,
192194
"pcall", &variant_pcall,
193195
"get_type", &variant_get_type,
194-
"get_type_name", &get_type_name,
195-
"hash", &Variant::hash,
196-
"recursive_hash", &Variant::recursive_hash,
197-
"hash_compare", &Variant::hash_compare,
196+
"get_type_name", wrap_function(L, &get_type_name),
197+
"hash", wrap_function(L, +[](const Variant& self) { return self.hash(); }),
198+
"recursive_hash", wrap_function(L, +[](const Variant& self, int recursion_count) { return self.recursive_hash(recursion_count); }),
199+
"hash_compare", wrap_function(L, +[](const Variant& self, const Variant& other) { return self.hash_compare(other); }),
198200
"is", &variant_is,
199201
// comparison
200202
sol::meta_function::equal_to, &evaluate_binary_operator<Variant::OP_EQUAL>,
@@ -224,7 +226,7 @@ extern "C" int luaopen_godot_variant(lua_State *L) {
224226
sol::meta_function::to_string, &Variant::stringify
225227
);
226228

227-
MethodBindByName::register_usertype(state);
229+
VariantMethodBind::register_usertype(state);
228230
VariantType::register_usertype(state);
229231

230232
state.set("typeof", &variant_get_type);

src/script-language/LuaScriptInstance.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
#include "../LuaError.hpp"
3232
#include "../LuaFunction.hpp"
3333
#include "../LuaTable.hpp"
34-
#include "../utils/MethodBindByName.hpp"
3534
#include "../utils/VariantArguments.hpp"
3635
#include "../utils/convert_godot_lua.hpp"
3736
#include "../utils/function_wrapper.hpp"
37+
#include "../utils/method_bind_impl.hpp"
3838
#include "../utils/string_names.hpp"
3939

4040
namespace luagdextension {
@@ -328,7 +328,7 @@ static int lua_index(lua_State *L) {
328328
if (LuaScriptInstance *instance = LuaScriptInstance::find_instance(self)) {
329329
StringName key_name = key.as<StringName>();
330330
if (instance->owner->has_method(key_name)) {
331-
sol::stack::push(L, MethodBindByName(key_name));
331+
sol::stack::push(L, LuaScriptInstanceMethodBind(instance, key_name));
332332
}
333333
else {
334334
Variant value = instance->owner->get(key_name);
@@ -368,14 +368,16 @@ static int lua_to_string(lua_State *L) {
368368
}
369369

370370
void LuaScriptInstance::register_lua(lua_State *L) {
371-
metatable = sol::state_view(L).create_table_with(
371+
sol::state_view state(L);
372+
metatable = state.create_table_with(
372373
"__index", lua_index,
373374
"__newindex", lua_newindex,
374375
"__tostring", lua_to_string,
375376
"__metatable", "LuaScriptInstance"
376377
);
377378
rawget = wrap_function(L, _rawget);
378379
rawset = wrap_function(L, _rawset);
380+
LuaScriptInstanceMethodBind::register_usertype(state);
379381
}
380382

381383
void LuaScriptInstance::unregister_lua(lua_State *L) {

src/script-language/LuaScriptResourceFormatLoader.cpp

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include "LuaScript.hpp"
2727
#include "LuaScriptLanguage.hpp"
2828
#include "LuaScriptResourceFormatLoader.hpp"
29-
#include "../LuaTable.hpp"
3029

3130
namespace luagdextension {
3231

@@ -54,8 +53,31 @@ bool LuaScriptResourceFormatLoader::_exists(const String &p_path) const {
5453
}
5554

5655
Variant LuaScriptResourceFormatLoader::_load(const String &p_path, const String &p_original_path, bool p_use_sub_threads, int32_t p_cache_mode) const {
57-
Ref<LuaScript> script(LuaScriptLanguage::get_singleton()->_create_script());
58-
script->set_path(p_original_path);
56+
Ref<LuaScript> script;
57+
script.instantiate();
58+
59+
switch (p_cache_mode) {
60+
case ResourceFormatLoader::CACHE_MODE_IGNORE:
61+
case ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP:
62+
break;
63+
64+
case ResourceFormatLoader::CACHE_MODE_REUSE: {
65+
Ref<LuaScript> existing_script = ResourceLoader::get_singleton()->get_cached_ref(p_path);
66+
if (existing_script.is_null()) {
67+
script->set_path(p_original_path);
68+
}
69+
else {
70+
script = existing_script;
71+
}
72+
break;
73+
}
74+
75+
case ResourceFormatLoader::CACHE_MODE_REPLACE:
76+
case ResourceFormatLoader::CACHE_MODE_REPLACE_DEEP:
77+
script->take_over_path(p_original_path);
78+
break;
79+
}
80+
5981
script->set_source_code(FileAccess::get_file_as_string(p_path));
6082
Error status = script->reload();
6183
if (status == OK) {

src/utils/Class.cpp

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
*/
2222
#include "Class.hpp"
2323

24-
#include "MethodBindByName.hpp"
2524
#include "convert_godot_lua.hpp"
25+
#include "method_bind_impl.hpp"
2626
#include "string_names.hpp"
2727

2828
#include <godot_cpp/classes/class_db_singleton.hpp>
@@ -50,16 +50,6 @@ sol::optional<int64_t> Class::get_constant(const StringName& name) const {
5050
}
5151
}
5252

53-
sol::optional<MethodBindByName> Class::get_method(const StringName& name) const {
54-
ClassDBSingleton *class_db = ClassDBSingleton::get_singleton();
55-
if (class_db->class_has_method(class_name, name)) {
56-
return MethodBindByName(name);
57-
}
58-
else {
59-
return sol::nullopt;
60-
}
61-
}
62-
6353
Variant Class::construct(sol::this_state state, const sol::variadic_args& args) const {
6454
auto class_db = ClassDBSingleton::get_singleton();
6555
if (!class_db->can_instantiate(class_name)) {
@@ -87,8 +77,8 @@ static sol::object __index(sol::this_state state, const Class& cls, sol::stack_o
8777
if (auto constant = cls.get_constant(name)) {
8878
return sol::make_object(state, *constant);
8979
}
90-
else if (auto static_method = cls.get_method(name)) {
91-
return sol::make_object(state, *static_method);
80+
else if (ClassDBSingleton::get_singleton()->class_has_method(cls.get_name(), name)) {
81+
return sol::make_object(state, ClassMethodBind(cls, name));
9282
}
9383
}
9484
return sol::nil;
@@ -100,6 +90,7 @@ void Class::register_usertype(sol::state_view& state) {
10090
sol::meta_function::index, &__index,
10191
sol::meta_function::to_string, &Class::get_name
10292
);
93+
ClassMethodBind::register_usertype(state);
10394
}
10495

10596
}

0 commit comments

Comments
 (0)