You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Custom setters and getters are not called when a variable is initialized. That includes the value that gets assigned via @onready. docs
That is actually a good thing in my opinion, though I noticed that this is not the case for the value that is assigned via @export.
This causes problems when you want to change values of child nodes in the setter of an exported var, because at the time the value is applied the child is not loaded yet.
If you use a @tool script, you also get an error every time you open that too.
If you set a value for an exported variable, it gets assigned in-game after init, but still before enter_tree, and it calls the custom setter.
This behavior feels weird to me. I tested for hours to get why this is happening.
Semantically the value I set in the editor replaces the initial value, it's just a shortcut to do that not in code. And in my opinion it should be handled the same. At least at the moment it is reapplied on init.
When I use a @tool script, it should call the setter, because then I might want to do something with it in that moment. It might change the value of other nodes, but then it is fine. Those are loaded and the changed values will get saved too. But those values should not call the setter afterwards.
In short, if you change a value yourself actively, the setter should be called.
If the engine applies that value internally if that scene is loaded it should not call the setter.
TLDR:
The moment you change an exported var in the editor, the custom setter should be called.
The moment that stored exported value gets reapplied at init (at game-start or when that scene is loaded again), the setter should not be called
Calling a setter when assigning a variable is a GDScript language feature. It has nothing to do with the core scene/resource (de)serialization system. If a property is stored in a scene/resource file, then during deserialization this property will be assigned, and therefore the setter will be called.
From GDScript point of view, the setter is not called only in a few cases: for an initializing expression and when assigning to a variable within its setter. See When setter/getter is not called for details.
From the core point of view, scenes/resources do not serialize default values (and some other cases), in this case the property is not assigned and therefore the GDScript setter is not called. But in other cases this happens. Core doesn't know anything about GDScript setters, it just calls Object.set(). It makes no difference whether the property is a native one, a GDScript variable, or a user property handled in _set().
Regarding the main problem you mentioned:
This causes problems when you want to change values of child nodes in the setter of an exported var, because at the time the value is applied the child is not loaded yet.
If you use a @tool script, you also get an error every time you open that too.
If you set a value for an exported variable, it gets assigned in-game after init, but still before enter_tree, and it calls the custom setter.
I agree with you that this causes certain inconveniences, but I do not agree with the solution you propose. I think the problem is not that the setter is called, but when the variable is assigned (and hence the setter is called). See also:
Unfortunately, @onready and potential @oninstantiated annotations do not solve this problem because they do not affect when core assigns the property (see the warning in @onready annotation). We probably need to add a new property usage flag that tells core that the exported value should be assigned after all children have been added.
In the meantime, there are two workarounds:
Add child nodes in _init() instead (not very convenient).
Tested versions
4.3.dev6
System information
Windows 10 - Godot 4.3.dev6 - Forward+
Issue description
Custom setters and getters are not called when a variable is initialized. That includes the value that gets assigned via @onready. docs
That is actually a good thing in my opinion, though I noticed that this is not the case for the value that is assigned via @export.
This causes problems when you want to change values of child nodes in the setter of an exported var, because at the time the value is applied the child is not loaded yet.
If you use a @tool script, you also get an error every time you open that too.
If you set a value for an exported variable, it gets assigned in-game after init, but still before enter_tree, and it calls the custom setter.
This behavior feels weird to me. I tested for hours to get why this is happening.
Semantically the value I set in the editor replaces the initial value, it's just a shortcut to do that not in code. And in my opinion it should be handled the same. At least at the moment it is reapplied on init.
When I use a @tool script, it should call the setter, because then I might want to do something with it in that moment. It might change the value of other nodes, but then it is fine. Those are loaded and the changed values will get saved too. But those values should not call the setter afterwards.
In short, if you change a value yourself actively, the setter should be called.
If the engine applies that value internally if that scene is loaded it should not call the setter.
TLDR:
Steps to reproduce
Minimal reproduction project (MRP)
getters-and-setters.zip
Did some testing to get a grip of how it actually works.
The main problem can be seen in
test_access_children.tscn
.The text was updated successfully, but these errors were encountered: