Why is my exported typed Dictionary saving changes made at runtime between level reloads?

Godot Version

4.4

Question

I have a var action_map: Dictionary[StringName, NodePath] and I want it to be set in the inspector but without it being saved like @export does defaultly with PROPERTY_USAGE_STORAGE.

I have tried
@export_custom(PROPERTY_HINT_DICTIONARY_TYPE, “StringName; NodePath”, PROPERTY_USAGE_EDITOR) var action_map: Dictionary[StringName, NodePath]
and

@tool
extends Node

var action_map: Dictionary[StringName, NodePath]

func _validate_property(property: Dictionary):
    if property.name == “action_map”:
        property.usage = PROPERTY_USAGE_EDITOR
        property.type = TYPE_DICTIONARY
        property.hint = PROPERTY_HINT_DICTIONARY_TYPE
        property.hint_string = “StringName;NodePath”

Both fail in the same way. They show the variable in the inspector but the dictionary loses its typing, and if I select the proper type for the key and action_map does not get set to the values I gave in the inspector.

I suspect my hint_string is wrong but its hard to tell since I can’t find much on the details for how this is supposed to work or what the expected formatting is. I just need my variable to behave as it normally would if it were exported, but without PROPERTY_USAGE_STORAGE.

The reason I am trying to do this is that I want this variable set in the inspector but changes to it during game play seem to carry over between level reloads when using just @export.

The variable is held in a node in a character scene. The level spawns in the character using preload and instantiate. Then the player gets control. When they hit backspace the level is reloaded with get_tree().reload_current_scene(). The script with action_mapholds paths to nodes in the character, and removes the paths if the nodes level the tree. Reloading the level causes the nodes to leave, which removes them from action_mapand this removal carries over when the level reloads.

So the problem you’re having has nothing to do with an @export variable. It has to do with the way Dictionary objects work in GDScript. Specifically, a Dictionary is passed by reference. From the docs:

Note: Dictionaries are always passed by reference. To get a copy of a dictionary which can be modified independently of the original dictionary, use duplicate().

So instead of jumping through all those hoops, if you want to re-use a Dictionary, use the duplicate() function for your local copy, and they do it again when you restart your level. At the end of your level, if you want to keep the changes, copy them over to the original Dictionary.

I don’t want the changes, I want the variable to be set to what was set in the inspector when the level gets reloaded.

Not sure why but bringing the project to v4.5 and just having the variable exported as normal @export var action_map: Dictionary[StringName, NodePath]fixed the issue. I assume some bug in 4.4.

I didn’t see you were on 4.4. I think it’s actually just a new feature in 4.5 not a bug in 4.4. But glad that solved the problem.

1 Like