Help duplicating custom node: both point to same resource instance

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Bernard Cloutier

I have a custom node which holds a resource. When I duplicate the node in the scene tab, I would like the cloned node to hold a copy of that resource, not a reference to the same resource.

Is there a simple way to achieve this? Here is what my custom node look like:

tool
extends Node

# I am avoiding using export so that it doesn't
# show in the inspector, hence the _get, _set
# and _get_property_list methods below
var my_resource: MyCustomResourceType


func _ready():
	if not self.my_resource:
		self.my_resource = MyCustomResourceType.new()


func _set(property, value):
	match property:
		"custom_resource":
			my_resource = value
			return true
	return false


func _get(property):
	match property:
		"custom_resource":
			return my_resource
	return null


func _get_property_list() -> Array:
	return [
		{
			"name": "custom_resource",
			"type": TYPE_OBJECT,
			"hint": PROPERTY_HINT_RESOURCE_TYPE,
			"hint_string": "MyCustomResourceType",
			"usage": PROPERTY_USAGE_NOEDITOR
		}
	]

Thanks a bunch!

Have you already tried using the duplicate() method on the resource?

Ertain | 2020-10-18 17:33

No I haven’t, but how would I go about it? I would need to somehow react to the “duplicate” function in the scene tree. How do I know when my node is being copied?

Bernard Cloutier | 2020-10-18 17:45

I tried replacing my_resource = value with my_resource = value.duplicate(true), but I get the error Trying to assign value of type '' to a variable of type 'my_custom_resource_type.gd'

I tried casting: my_resource = value.duplicate(true) as MyCustomResourceType, but then my_resource ends up null. It kinda looks like an engine issue. I know support for custom resources is a bit lacking.

Doing my_resource = value works fine, I don’t really understand why my_resource = value.duplicate() wouldn’t.

Bernard Cloutier | 2020-10-18 19:11

Maybe first try checking the value of value in the _set() function? If it’s null, then try creating a duplicate resource? Set it up to check for a null value, and return false on such a value? Maybe also check for the intended datatype?

func _set(property, value):
    if not value:
        return false
    match property:
        "custom_resource":
            if value is Resource:
                 my_resource = value
                 return true
    return false

I’m also wondering about your datatype, MyCustomResourceType. Aren’t custom datatypes usually defined in a class?

Ertain | 2020-10-19 22:49

The value is not null. Thanks for the help, I’ll try some more debugging tomorrow and I’ll get back if I make any advance.

I’m also wondering about your datatype, MyCustomResourceType. Aren’t custom datatypes usually defined in a class?

I have a need for custom resources, like the one shown in this tutotial: Resources — Godot Engine (stable) documentation in English

Bernard Cloutier | 2020-10-20 02:50

Thanks for trying to help, but unfortunately this seems to be a known issue: [3.x] Add PROPERTY_USAGE_ALWAYS_SHARE_ON_DUPLICATE flag by jkb0o · Pull Request #41924 · godotengine/godot · GitHub

My resource does contain custom scripts, and those seem to cause problemes when using duplicate.

Bernard Cloutier | 2020-10-20 14:17