godotengine / godotengine/godot

Setter not called during duplicate for an exported property referencing an instance of a custom class

Open
#98,644 1 comment 0 reactions 0 assignees View on GitHub
discussion topic:core
Dominant language
C++
Stars
117k
Forks
26.8k
PR merge metrics
PR metrics pending

Description

### Tested versions

v4.3.stable.official [77dcf97d8]

### System information

Godot v4.3.stable - Windows 11 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce GTX 1660 Ti (NVIDIA; 32.0.15.6094) - Intel(R) Core(TM) i7-9700F CPU @ 3.00GHz (8 Threads)

### Issue description

If a node includes an exported property that references a child defined as a custom class, the setter is called as expected when the node is created (first time, or when reading a scene). However, when duplicating a node, either through the editor gui, or in gdscript, the setter is not called (for such a child defined as a custom class).

### Steps to reproduce

### Create a custom class,CustomClass, by extending a built-in class, for example:
```
@tool
extends Path3D
class_name CustomClass
```
### Create a second script to apply to a Path3D node
```
@tool
extends Path3D
```
### Create a 3D scene, add a Node3D.
Add a CustomClass as child node, also add a further child node based on the built-in class (Path3D in this case) and attach the Path3D script. Add the following script to the Node3D to display values of properties:
```
@tool
extends Node3D

@export var path3d:Path3D
@export var custom_class:CustomClass

@export var path3d_set:Path3D:
set(value):
path3d_set = value
print( "Set path3d_set ",path3d_set,"\n")

@export var custom_class_set:CustomClass:
set(value):
custom_class_set = value
print( "Set custom_class_set ",custom_class_set,"\n")

func _init() -> void:
print( "Init .............","\n",
"Path3D ",path3d,"\n",
"CustomClass ",custom_class,"\n",
"Path3D_set ",path3d_set,"\n",
"CustomClass_set ",custom_class_set,"\n")

func _ready() -> void:
print( "Ready .............","\n",
"Path3D ",path3d,"\n",
"CustomClass ",custom_class,"\n",
"Path3D_set ",path3d_set,"\n",
"CustomClass_set ",custom_class_set,"\n")
```
### Assign the CustomClass and Path3D nodes to the respective properties in the editor.
Then reload the scene, this gives the following output, note that the exported property, is defined as expected.

> Init .............
> Path3D \
> CustomClass \
> Path3D_set \
> CustomClass_set \
>
> Set path3d_set Path3D:
>
> Set custom_class_set CustomClass:
>
> Ready .............
> Path3D Path3D:
> CustomClass CustomClass:
> Path3D_set Path3D:
> CustomClass_set CustomClass:

### Duplicate the above node
Either in the GUI, or by attaching the script below to the root node of the scene, saving and running the project
```
@tool
extends Node3D

func _ready() -> void:
var new_node = $Node3D.duplicate()
add_child(new_node)
new_node.set_owner(get_tree().get_edited_scene_root())
```
### The output will be as below

> Init .............
> Path3D \
> CustomClass \
> Path3D_set \
> CustomClass_set \
>
> Set path3d_set Path3D:
>
> Ready .............
> Path3D Path3D:
> CustomClass \
> Path3D_set Path3D:
> CustomClass_set \

### As is demonstrated, the CustomClass setter is not called during the duplicate process
The value of the property remains even though defined in the original node, yet the exported property referencing a built-in class is duplicated correctly

### Minimal reproduction project (MRP)

[CustomClassExportDuplicate.zip](https://github.com/user-attachments/files/17559367/CustomClassExportDuplicate.zip)

Contributor guide

Open the contributing guide

Research direction

Start with the attached CustomClassExportDuplicate.zip and reproduce the behavior using the shown Node3D.duplicate() call. Compare duplication of the exported Path3D and CustomClass properties, then trace the engine path used by duplicate(). Done means the custom-class property receives its duplicated value and its setter is called consistently with the built-in class case.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.