Duplication's making me pull my hairs out

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

I’ve tried every thing I’ve seen on google related to the issue I’m having, but there’s either a version difference, magic gnomes in my computer, or I’m making some stupid mistake.

This is how my code looks like:

var weaponTest = weaponList[2].duplicate()
weaponList[2].description = "test" <- this line is just to check if I'm not by some getting a reference by some magical way

weaponList is just some list which has empty nodes with scripts attached to it, each having some variables about the weapon. When trying to dupe the node into some other variable, the result is that the node has the script attached, but no variables get copied over (just null gets returned).

I’ve no idea why this doesn’t work, as this reddit thread shows it working beautifully.

:bust_in_silhouette: Reply From: Error7Studios

3 things:
First, you’re changing a value in the original node, weaponList[2]and expecting that change to be reflected in the duplicated node, weaponTest. That doesn’t work. They’re separate nodes, not linked. Changes to the original will not affect the duplicate.

Second, when a node is duplicated, all its properties will be assigned its default values, not the current values of the original node.

Third, in the thread you linked to, in the first answer by willnationsdev, no values are copied to the duplicate. The duplicated node just assigns its default values when created.

To do what you want (actually copy values to the duplicated node), you can create a function for that.

I have a scene called Obj.tscn, with an Obj.gd script:

# Obj.gd
extends Node

class_name Obj

var health = 0
var energy = 0
var offense = 0
var defense = 0

I also have a Main.tscn with a Main.gd script:

# Main.gd
extends Node

const PACKED_OBJ := preload("res://Scenes/Obj/Obj.tscn")

func get_copy(source_node: Node) -> Node: # will copy script var values
	var duplicate_node = source_node.duplicate()

	var script_property_dict := get_script_property_dict(source_node)
	var var_names := script_property_dict.keys()
	var var_values := script_property_dict.values()
	for i in var_names.size():
		var var_name: String = var_names[i]
		var var_value = var_values[i]
		duplicate_node.set(var_name, var_value)

	return duplicate_node

func get_script_property_dict(node: Node) -> Dictionary:
	var node_script: Script = node.get_script()
	var script_property_dict := {}
	var script_property_list: Array = node_script.get_script_property_list()

	for i in script_property_list.size():
		var property_dict: Dictionary = script_property_list[i]
		var property_name: String = property_dict["name"]
		var property_value = node.get(property_name)
		script_property_dict[property_name] = property_value

	return script_property_dict

func print_script_vars(node: Node) -> void:
	var script_property_dict := get_script_property_dict(node)
	var keys := script_property_dict.keys()
	var values := script_property_dict.values()
	for i in script_property_dict.size():
		print(keys[i], ": ", values[i])

func _ready():
	var obj: Obj = PACKED_OBJ.instance()

	obj.health = 100
	obj.energy = 50
	obj.offense = 10
	obj.defense = 7

	var obj_copy: Obj = get_copy(obj)

	print(" ----- source node -----")
	print(" ----- duplicate node -----")

When running the Main scene, you’ll get this output:

 ----- source node -----
health: 100
energy: 50
offense: 10
defense: 7
 ----- duplicate node -----
health: 100
energy: 50
offense: 10
defense: 7

Yeah, that’s what I eventually figured out I had to do. It’s unfortunate there isn’t some way to just copy the current variables, because the copy function I had to write had ~120 lines just because of the number of variables. I remember there being something like this in Unity, disappointing it isn’t a thing in Godot.

Xyseer764 | 2021-02-22 08:52