godot icon indicating copy to clipboard operation
godot copied to clipboard

When setting a default value for an exported variable with `CustomResource.new()` the script exporting the variable needs to be a `@tool` script

Open ajreckof opened this issue 3 years ago • 3 comments

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

ajreckof avatar Feb 23 '23 14:02 ajreckof

This is probably the case with all resources, since I have the same behavior with Curve2D.

nathanfranke avatar Mar 08 '23 01:03 nathanfranke

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 @export auto-initialize object types. This might be possible by setting PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT on the property.
  • Add a new @default_initialize annotation or similar, which would trigger this behavior explicitly.

akien-mga avatar Mar 08 '23 08:03 akien-mga

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)

ajreckof avatar Mar 08 '23 16:03 ajreckof

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 @tool and [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.

hsandt avatar Jun 22 '24 19:06 hsandt

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)

hsandt avatar Jun 22 '24 20:06 hsandt