Unable to refer to object after saving

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

I followed the tutorial for saving in Godot 3, and implemented it in my game with only minor changes (the official Godot saving docs tutorial had some errors) but otherwise I implemented it with no changes. I set a door to be a persistent object, and I save a handful of variables including the rotation of the door. However, when I load the door I am unable to refer to the door via get_node or via signals. The door otherwise behaves as expected, and my signals work if I do not load the game.

Interestingly, when I save the game with the door and then delete the door before running the game, it works perfectly - loading only one copy of the door, from the save. To check my theory, I print(name) in the ready of the door and it prints two names - Door, and @Door@6 - I assume this is the name it is was given after loading, but I am not sure why.

I have attached the appropriate code, hopefully someone can indicate what the problem is and how I should resolve it.

Thanks a pile.

Loading code:

func load_game():
	var save_game = File.new()
	if not save_game.file_exists("res://savegame.save"):
		return # Error! We don't have a save to load.

    # We need to revert the game state so we're not cloning objects during loading. This will vary wildly depending on the needs of a project, so take care with this step.
    # For our example, we will accomplish this by deleting savable objects.
	var save_nodes = get_tree().get_nodes_in_group("Persist")
	for i in save_nodes:
		i.queue_free()

    # Load the file line by line and process that dictionary to restore the object it represents
	save_game.open("res://savegame.save", File.READ)
	var current_line = parse_json(save_game.get_as_text())
        # First we need to create the object and add it to the tree and set its position.
	var new_object = load(current_line["filename"]).instance()
	get_node(current_line["parent"]).add_child(new_object)
	new_object.position = Vector2(current_line["pos_x"], current_line["pos_y"])
        # Now we set the remaining variables.
	for i in current_line.keys():
		if i == "filename" or i == "parent" or i == "pos_x" or i == "pos_y":
			continue
		new_object.set(i, current_line[i])
	save_game.close()

Saving Code:

func save_game():
	var save_game = File.new()
	save_game.open("res://savegame.save", File.WRITE)
	var save_nodes = get_tree().get_nodes_in_group("Persist")
	for i in save_nodes:
		var node_data = i.save();
		save_game.store_line(to_json(node_data))
	save_game.close()

Save file contents: {“door_stop”:false,“filename”:“res://Maps/Door.tscn”,“name”:“Door”,“parent”:“/root/TestMap”,“pos_x”:24.874701,“pos_y”:233.261993,“rotation”:0}

:bust_in_silhouette: Reply From: eons

To see if you are saving and referencing it correctly, check the remote tree when running, and look at the debugger, add breakpoints, etc.

You may need to reconnect some signals too when loaded.


About saving, do not save on res:// because it won’t work on export, that is the game’s virtual filesystem, save it on user:// which is the game’s data folder.

And please report any error or inconsistency you do see in the docs at the documentation repository (check first on “latest” docs to see if it is not already fixed for the next version).

Thanks for the note on :res// will change that.

I actually had no idea that the remote tree existed! Super useful debug tool. Anyhow, I checked out the remote tree during runtime and saw that the node “Door” did not exist (My loader queue_free’s that, so not surprising) but that in it’s place was “@Door@7”

In another part of my code, I call

connect("room_clear", get_parent().get_node("Door"), "perma_open")

I imagine it isn’t working because “Door” no longer exists and has become “@Door@7” I replaced “Door” with “@Door@7” in the connect and it worked, however I do not understand why it was being switched to something other than simply “Door” when I load it - should it not queue_free the door and replace it with an identically named scene?

Hailrig | 2018-11-15 22:24

I looked into it further, and it seems to be an issue when I instance the object, it gets instanced with a name of @nodename@7. I am passing the correct node name.

EDIT: The problem line is specifically

get_node(current_line["parent"]).add_child(new_object)

Hailrig | 2018-11-16 21:47

Try to not depend on names on dynamic objects, because the tree will rename them if these are repeated, try instead to store a reference when creating and use it for restoring connections with other nodes.

eons | 2018-11-17 00:47

I currently connect the code by calling

connect("room_entered", get_parent().get_node("Fog"), "_reveal")

How should I reference the code if not by name? How do I go about storing a reference to it when I create it?

Hailrig | 2018-11-17 20:16