-
-
Notifications
You must be signed in to change notification settings - Fork 191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issues exporting resources from Rust custom types #440
Comments
Happy to take a stab at the second issue. I think the first one is more up to opinion so probably needs more discussion. |
The second issue is probably just a mistake someone made yeah. For the first one we should probably try to mirror whatever GDScript does if GDScript's defaults here aren't too weird. |
Godot uses the class_name to construct an instance of the right type in a few places, in particular for the PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT flag. Partial fix for godot-rust#440
Similar issue in #283 wrt nulls in Godot causing problems with |
Did some experiments with GDScript and it looks like it handles non-null default values just fine. If you put an initializer on a field it gets set in some step before _init even runs. If you set another value in the editor, it shows up in init with the default set in GDScript, then gets set afterward. extends Node
class_name ObjNullDefault
@export
var no_default: Resource :
set(value):
print("set, old value, no_default: ", no_default)
print("set, new value, no_default: ", value)
no_default = value
get:
print("get, no_default: ", no_default)
return no_default
@export
var with_default: Resource = Resource.new() :
set(value):
print("set, old value, with_default: ", with_default)
print("set, new value, with_default: ", value)
with_default = value
get:
print("get, with_default: ", with_default)
return with_default
func _init():
print("_init")
print("_init, no_default: ", no_default)
print("_init, with_default: ", with_default) Leaving the field alone in the editor and running:
Setting a value in the editor and running;
Digging through the Godot code I came across Part of the GDExtensionBindings that defines them: So with those implemented it might be fine to have a non-null default, though there's a lot of places in the Godot codebase that use the cached instance default so it's probably a "try it and see" situation plus maybe an upstream patch. Also not clear how you would generate that implementation without requiring the generated init. |
Additionally, trying to use I'm not sure if this is a separate issue or simply a result of the ones mentioned in this thread - does anyone know? |
…exporting resources. see: godot-rust/gdext#440
…exporting resources. see: godot-rust/gdext#440
Is this problem still present on latest |
TL;DR:
#[export] Gd<Foo>
with non-null default causes bugs in the Godot editor, the fix usingPROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
is using the wrong type to initialize the field.Using a non-null resource reference causes a bug with defaults in the Godot editor
Gives this warning sporadically while an instance of the custom class is in the tree:
Which points to this issue in Godot where this caused issues with using the 'reset' button on internal types in the editor: godotengine/godot#36372
The same bug from that issue happens with the example custom type above.
Warning message from: https://github.com/godotengine/godot/blob/bfd78bb917887cfc1fd842ba23570394cad8bedb/core/object/class_db.cpp#L1723
Leads to
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
implemented here: https://github.com/godotengine/godot/blob/bfd78bb917887cfc1fd842ba23570394cad8bedb/editor/editor_data.cpp#L588Core issue is that Godot seems to use the value of a newly instantiated object's field as the default value for that field, meaning Object fields that default to an instance will have that specific instance used as a default for resetting the field. So resetting the field may reset to a dirty object and have strange behavior. This is sort of similar to the footgun in Python with default parameters (e.g.
def foo(x=[]):
uses the same list for every call that uses the default value for the parameter).For an extreme opinion: non-nullable exported
Gd<Foo>
fields seem like a bug and should be a compile-time warning/error. The specific combo seems to be all of:Object*
, e.g.Gd<Foo>
orOption<Gd<Foo>>
PROPERTY_USAGE_EDITOR
on the usage flags (one of the defaults)Gd::new_default()
or anything other thanNone
on anOption<Gd<Foo>>
. (Specifically, I think Godot needs to get a null whenever it makes a new instance to check for the default values so a custom getter that always returns non-null can trigger this too)Preferred way to default to something other than null should be:
The field can still be set to null, but will at least start non-null when created in the editor.
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
is broken for custom Rust typesEnabling
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
leads to weird Rust panics when creating custom nodes with custom types in the editor:Gives this error:
Note that it's trying to set the ExampleResource field to an ExampleNode. Looking at where the
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
logic is done, it uses theclass_name
field of aPropertyInfo
struct.Looking at the constructor for that it uses the
hint_string
for resource types on one constructor, but there's a separate one for GdExtension below which does not and just copies theclass_name
over: https://github.com/godotengine/godot/blob/bfd78bb917887cfc1fd842ba23570394cad8bedb/core/object/object.h#L174Looking at the Rust gdext macro implementation, the
hint_string
is set to the name of the resource class:gdext/godot-core/src/obj/gd.rs
Lines 763 to 767 in 88a7934
But I think that
class_name
field is set here:gdext/godot-macros/src/class/data_models/property.rs
Line 182 in 88a7934
Which comes from the class name of the object that contains the property not the type of the property itself. I believe that should be set to the class name of the property's type instead, and doing that should fix the behavior with
PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT
and make it possible forOption<Gd<Foo>>
fields to 'default' to something other thanNone
.The text was updated successfully, but these errors were encountered: