Refactoring @export variables in Godot without losing data
In Godot, you can use @export variables to edit their values inside the Godot editor. This is especially useful for resources, which are a great way to store your game data. You can think of them like JSON files, but in a way they're more powerful since they can store any Godot resource in them.
I'm starting to use them to save information about dialogues. For example, I'm using an @export_multiline var dialogue: String to save the text that will be displayed.
But as I develop my dialogue system, refactors inevitably happens. This shouldn't be a problem with a code-only approach. But Godot, although is a great tool, comes with its little annoyances. You'll learn to love it with its defects too, that's how true love works, and that's probably why I always keep returning to it. 💙
Anyway, let's get into the problem:
- What if you rename that
dialoguevariable to something else? - What if you change its type to
Array[String]because now you want to represent a dialogue through multiple strings?
It will happen that all the values you entered for the dialogue variable through the editor in all of your resources inheriting your resource script, will vanish as easily as a message you draw on the crystal of a humid window. 🌬️
There are two solutions to this problem:
Using an external editor
Using an external editor, you basically change the name of the variable dialogue both in the script of your resource and in all you resource (.tres) files that inherit that script. Simple... Until you need to change its type too.
Tool script workaround
If you also need to change the type of the variable but you want to retain the data you had in the String value, you can follow this strategy that I found in this subreddit:
In your resource script, create the new variable with the name and the type you're going to use.
Add
@toolat the top of your script, this will make it a script tool.Make a getter and a setter for the new variable. The getter will need to map the data from the old variable to the structure of the type of the new variable, so the information will be shown as you desire in the Godot inspector. The setter simply populates the new variable. In our example, it would look like this:
getter:
return [dialogue]
set(value):
dialogue_new = value
Open all your resource instances (
.tresfiles) in the Godot editor so they will populate the new variable. This is the key step, because the getter will get and map the value from the old variable, and the setter will populate the value of the new variable.Now you can remove the setters and getters of the new variable, the old variable, and the
@toolannotation.