Saving game data to file

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By antonis74
:warning: Old Version Published before Godot 3 was released.

Hi,
I have a class (base type is Node) in my project with a number of properties. In the game, a number of its instances are stored into an array.
First, I saved the array using the “store_var” method. The loading procedure (“get_var”) returned an empty object.
Then, I tried with the “to_json method”. In that case, the load process returned a node object (in the form Node:XXXX) but trying to access its properties (i.e. each item’s properties), I received errors in the form: “Invalid get index ‘RSF’ (on base: ‘String’)”, where RSF is the name of the first property.
I tried all the above with a dictionary instead of an array with the same results.

Any help will be greatly appreciated!

When using the store_var on an array or dictionary, am I supposed to loop through each item or it works with the whole thing? For example: Array[a, b, c], where a, b and c are classes with properties. Using store_var(Array) and later get_var(Array) is valid (because this is what I did) or I must iterate through each item of Array and store it individually?

antonis74 | 2017-04-20 16:35

:bust_in_silhouette: Reply From: Zylann

When you use store_xxx, Godot will append the binary form of the variable to the file. In order to read them back, you have to read them in the same order. I suppose if you store an array it might work, but I never tested it.

However, storing an array of nodes won’t work because nodes are not “storable” types, they are objects (classes also aren’t storable currently). So you will end up with some kind of ID instead which won’t be of much use once you read them back. You can store their type and properties manually though.

When using to_json, you will get a string that can be stored in a file using store_string. You can read it back as a string too, but it won’t directly be accessible because it’s just text, so that’s why you get "Invalid get index 'RSF' (on base: 'String')".

To read back the JSON dictionary from a string, you need to parse it back, as explained here http://docs.godotengine.org/en/stable/tutorials/engine/saving_games.html#serializing :

var dict = {}
dict.parse_json(json_text)

Hi Zylann and thanks for the quick answer!

I understand the first part (for the store_XXXX, get_XXXX) but searching for the subject, I found a few guys telling it is doable (however I couldn’t find any example). I also cannot understand how storing a simple variable works the same as storing an entire array (it would be the best solution, nonetheless)!

As for the second method, I know that I have to “translate” the json dictionary. My code at that point looks like:

		var currentline = {}
		while (!save_file.eof_reached()):
			currentline.clear()
			currentline.parse_json(save_file.get_line())
			for i in currentline.keys():
				Goods[i] = currentline[i]

where the Goods is the dictionary I want to fill and the result looks like: [[Node:822], [Node:710]] where both items are the values (the keys are not shown but are returned correctly). Now, these are the correct classes that I saved but the problem is they are not usable (or at least, I do not know how to read their properties properly).

antonis74 | 2017-04-20 17:34

I forgot to add that I made all variable of the class as “exportable” because I understand that this is the way to make them “saveable”. However, if, as you say, classes are not “saveable” then I should probably write a separate saving function into the class for each of its properties.

antonis74 | 2017-04-20 17:39

Also, there is a function “instance_from_id” in the manual, which instantiates an object from its ID. I tried it with no success. I am not sure if [Node:XXXX] is just a string or a strange form of the saved class that needs manipulation.

antonis74 | 2017-04-20 17:50

The “Node:822” things are actually a runtime representation of the class you tried to save (that is, the thing you obtain when you print() them). They are not saveable out of the box, and adding exports won’t make it work automatically either. It may work to load them back with some trickery but you won’t get back their properties, and because it’s a runtime ID they will be wrong as soon as you restart the game.
Long story short: don’t save classes directly, serialize them manually. I know it sounds stupid but I went through this too and that’s the only easy thing that worked for me.
In the future, methods using _get_property_list() can help make it automatic, eventually.
I also tried inst2dict and dict2inst but they didn’t worked well for me.

Zylann | 2017-04-20 19:52

I think you are right. I did a manually save of each property of each object and it worked! However, it can be very complicated especially if you have a great number of properties. I also realized that some “strange” properties (like a textureimage) cannot be saved and I had to save its path instead!
I sure hope that version 3 will bring some user friendliness to that subject because this engine is really good!

antonis74 | 2017-04-20 20:09

TextureImage is also a class, so it has the same limitations.

Zylann | 2017-04-20 20:12