Search code examples
serializationsavegodotgdscript

Godot/Gdscript serialization of instances


If I want to serialize an array in Godot, I can do this:

var a1 = [1 ,2 ,3]

# save
var file = File.new()
file.open("a.sav", File.WRITE)
file.store_var(a1, true)
file.close()

# load
file.open("a.sav", File.READ)
var a2 = file.get_var(true)
file.close()

print(a1)
print(a2)

output (it works as expected):

[1, 2, 3]
[1, 2, 3]

But if I want to serialize an object, like this class in A.gd:

class_name A
var v = 0

Same test, with an instance of A:

# instance
var a1 = A.new()
a1.v = 10

# save
var file = File.new()
file.open("a.sav", File.WRITE)
file.store_var(a1, true)
file.close()

# load
file.open("a.sav", File.READ)
var a2 = file.get_var(true)
file.close()
print(a1.v)
print(a2.v)

output:

10

error (on line print(a2.v)):

Invalid get index 'v' (on base: 'previously freed instance').

From the online docs:

void store_var(value: Variant, full_objects: bool = false)

    Stores any Variant value in the file. If full_objects is true, encoding objects is allowed (and can potentially include code).

Variant get_var(allow_objects: bool = false) const

    Returns the next Variant value from the file. If allow_objects is true, decoding objects is allowed.

    Warning: Deserialized objects can contain code which gets executed. Do not use this option if the serialized object comes from untrusted sources to avoid potential security threats such as remote code execution.

Isn't it supposed to work with full_objects=true? Otherwise, what's the purpose of this parameter?

My classes contains many arrays of arrays and other stuff. I guess Godot handle this kind of basic serialization functionality (of course, devs will often have to save complex data at one point), so, maybe I'm just not doing what I'm supposed to do.

Any idea?


Solution

  • For full_objects to work, your custom type must extend from Object (if you don't specify what your class extends, it extends Reference). And then, the serialization will be based on exported variables (or whatever you say in _get_property_list). By the way, this can, and in your case it likely is, serializing the whole script of your custom type. You can verify by looking at the saved file.

    Thus, full_objects is not useful to serialize a type that extends Resource (which does not extend Object). Instead Resource serialization works with ResourceSaver, and ResourceLoader. Also with load and preload. And yes, this is how you would store or load scenes, and scripts (and textures, and meshes, and so on…).


    I believe the simpler solution for your code is to use the functions str2var and var2str. These will save you a lot of headache:

        # save
        var file = File.new()
        file.open("a.sav", File.WRITE)
        file.store_pascal_string(var2str(a1))
        file.close()
    
        # load
        file.open("a.sav", File.READ)
        var a2 = str2var(file.get_pascal_string())
        file.close()
        print(a1.v)
        print(a2.v)
    

    That solution will work regardless of what is it you are storing.