Different references to objects apparently create different objects

Godot Version

v4.7.2.stable.official

Question

I have a list of characters stored in two places. One, inside a state file which can be saved and loaded at will. Two, inside a temporary list of characters for use in a camping scene. I thought that these two different arrays should both be storing references to they same character objects in memory. However, through testing, I have determined that the objects are somehow being duplicated instead of referenced.

I hope it’s not necessary to post my full code. I think the problem relates to the way I’m setting up and storing the separate date, not the way I’m changing the data. By using print() statements, I’ve determined that modifications to characters in the campCalendar do not affect the same characters in the State. I am not using a .duplicate() function anywhere. So, what am I doing wrong? And how do I fix it?

SAVE STATE

class_name State extends Resource

@export var characters: Array[Character]

DATA MANAGER

extends Node
@onready var state := State.new()
var campTasks : Array[ CampTask ]
var campCalendar : Array[ Array ]

func setupCampCalendar():
	for character in state.characters:
		campCalendar.append( [character, campTasks[0] ] )

There isn’t enough information.

  • What’s a Character? a Resource or a Node?
  • You are creating a new State object in your data manager. Are you loading the characters later? How?
  • How are you checking that the objects are different?

A character is a resource:

class_name Character extends Resource

@export var stats:Stats
@export var identity:Identity
@export var profession:Profession
@export var experience:Experience

func _init(  ):
	stats = Stats.new()
	identity = Identity.new()
	profession = Profession.new()
	experience = Experience.new()
func setup( fName:String, pName:String ):
	identity.familyName = fName
	identity.personalName = pName
	stats.initializeMeters()

The State is being created at the start of the program. There are save/load functions, but they aren’t being used right now.

The differences between characters are being checked with this function, after characters have been modified via functions using campCalendar:

	var character = DataManager.state.characters[0]
	print( "%s : %d" % [character.identity.familyName, character.stats.stamina.x])
	character = DataManager.campCalendar[0][0]
	print( "%s : %d" % [character.identity.familyName, character.stats.stamina.x])
	

I originally noticed this problem because the UI is only showing the original states of the characters and not detecting any changes to them made via campCalendar. (The UI only takes information from the State.)

How are you filling the State.characters array and when?
When are you calling DataManager.setupCampCalendar()? Is it before or after you fill the State.characters array?
What’s the output of those prints?

The function that sets up the state looks like this. (For simplicity, I have deleted some repetitive parts.)

func newGame():
	state = State.new()
	
	var grandma = Character.new( )
	grandma.stats.endurance = 127
	grandma.setup( "Kinoti", "Arrow" )
	grandma.profession.title = "Elder"
	state.characters.append( grandma )
	var grandma2 = Character.new( )
...
	var protag = Character.new()
...
	state.characters.append( protag )
	
	campTasks.clear()
	var task1 = CampTask.new()
	task1.staminaCost = 5
	task1.knowledges.append( "nature" )
	task1.experience.append( 5 )
	task1.title = "Gather"
	var task2 = CampTask.new()
...
	var task3 = CampTask.new()
...
	campTasks.append( task3 )
	campTasks.append( task1 )
	campTasks.append( task2 )
	
	

newGame() and setupCalendar() are being called by _ready() in DataManager, which currently just looks like this:

func _ready() -> void:
	newGame()
	setupCampCalendar()
	

So the prints, assuming something has been done to change the stats of a character, will look like this:

Kinoti : 127
Kinoti : 112

What’s that something? How it’s done and when?

Provide the full context, also try to make a contained minimal example that demonstrates the problem.

Okay, I found the problem. Looks like a newGame() function was being called elsewhere to reinitialize the state without updating the campCalendar.

I think the issue might be happening somewhere else in your code rather than during object creation. Since you’re using Character.new() for each character, they should be separate instances.

I’d suggest checking where stats.endurance is being modified and whether newGame() or any setup function is being called more than once.

Also, try printing get_instance_id() for both references to confirm they’re pointing to the same object or different ones.

The key is to find where the value changes from 127 to 112. That should help identify the actual cause.