When setting a default value for an exported variable with `CustomResource.new()` the script exporting the variable needs to be a `@tool` script
Godot version
4.0 rc2
System information
MacOS 13.1 M1 Pro
Issue description
If you try to export a variable which default value is a new Custom Resource. The CustomResource won't be created and the inspector will have an empty Object instead.
https://user-images.githubusercontent.com/66184050/220940521-ea101fc2-3e65-4357-a6bf-3c59aba6321e.mp4
Steps to reproduce
- create a custom Resource
- try to instantiate it through new() in a non tool script
- check the inspector the variable won't be instantiated
Minimal reproduction project
N/A
This is probably the case with all resources, since I have the same behavior with Curve2D.
I believe this is expected behavior, only @tool scripts run in the editor, and the script would need to run to execute the new() operator.
To change this, I can think of two options:
- Make
@exportauto-initialize object types. This might be possible by settingPROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECTon the property. - Add a new
@default_initializeannotation or similar, which would trigger this behavior explicitly.
yeah it seems it is expected I don't know why I thought it was working with built-in resources.
I'm not sure how PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT would work what i thought of would be to fully initialize an instance of the object by running all code for default value and maybe also the _init() function. After initialization the instance would be registered (just as they are in .res or .tscn) and used as default values for all instances. But as this might way more and really near tool, I think having to be explicitly enabled through an annotation that would go instead of @tool would be better.
If PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT only resolves the problem of "Resource.new()" not being run then I think it soul be enabled by default (and if people complain we could add an editor setting to remove it for thos that don't want it)
Is it related to:
- https://github.com/godotengine/godot/issues/68427 (exported custom resource, but no mention of
@tool) - https://github.com/godotengine/godot/issues/80864 (non-exported variable, not specifically resource, but mentions
@tooland[Tool]for C#) ?
There is no sample code and the repro steps are a bit imprecise (they don't mention @export but the rest of the description suggests you need it to repro, or nothing will show in the inspector), so I'm not sure to what extent it's similar.
EDIT: ok I see a difference in this issue: it's about the resource field being completely empty or initialized to some default, as opposed to using _init to initialize it to a specific default value. I can confirm that only @tool creates some instance. ~~Then I have a second bug that doesn't initialize to the values I passed to my custom _init, which is better described in the other mentioned issues.~~ When _init is correctly defined, .new() also works fine even when inlined directly in the @export declaration.
EDIT 2: Ah, re-reading #68427 makes it obvious it's dealing with exported vars inside the custom resource and that those are not ready in the Resource's own _init, which is completely different. Sorry for the confusion. While #80864 is also about exported vars inside the Resource, but about setting it. So this issue is really the one I'm having in my project.
Since I have the same issue, I thought I may as well post my own example (not exactly MWE but still simplified):
Custom resource
class_name AttributeModifier
extends Resource
## Attribute name
@export var attribute_name: StringName
## Attribute multiplier
@export var multiplier: float = 1.0
func _init(p_attribute_name: StringName = &"", p_multiplier: float = 1.0):
attribute_name = p_attribute_name
multiplier = p_multiplier
Usage
#@tool # Resource initialization fails as long as this is commented out
extends Node
@export var attribute_modifier: AttributeModifier = AttributeModifier.new("a", 5.0)