Savegame Pro | Unity3D package

Version 1.0, 2019/10/17 support@peterverstappen.com

User documentation for the Unity3D Savegame Pro package by Peter Verstappen.

Table of Contents


Summary

Savegame Pro is an extensible Unity3D package that allows you to quickly implement saving and loading to and from files into your game. Out-of-the-box support for GameObjects, Components, primitive types and many UnityEngine types and structs is provided. Savegame Pro can be extended easily, either with custom surrogates classes or by simply defining the type you need to save with the provided default surrogate.

The Savegame Pro workflow provides easy saving and loading to one or more files. Files are kept small and duplicate data is avoided by not saving recursively. This keeps you in full control on what is saved for an object. Writing to disk happens only when you call the function for it. Reading from disk occurs only when creating the Savegame object or when you call the function.


Code

This section provides code samples for the basic functionalities of the package.

Creating a savegame

Import the package with using SavegamePro.

//Import the package
using SavegamePro;

Savegame needs a SavegameSettings object that contains at least the filename.

//Creating a standard savegame
public void ExampleSavegame() {
    SavegameSettings settings = new SavegameSettings("my-save-game-filename");
    Savegame savegame = new Savegame(settings);
}

SavegameSettings can be set with additional parameters to customize where the file is saved and with what extension.

//Customizing savegame settings
public void ExampleSavegameSettings() {
    //Saved in the persistent data directory with filename "my-save-game.sav"
    SavegameSettings settings = new SavegameSettings("my-save-game");

    //Saved in the given directory relative to executable, with filename "my-save-game.sav"
    SavegameSettings settings = new SavegameSettings("my-save-game", "my-directory");

    //Saved in the given directory, with filename "my-save-game.sav"
    SavegameSettings settings = new SavegameSettings("my-save-game",
    "C:\\my-directory\\sub-directory\\save-directory");

    //Saved in the executable directory, with filename "my-save-game.custom"
    SavegameSettings settings = new SavegameSettings("my-save-game", "", "custom");
}

Saving

All objects are saved with the public void Save(string key, object value) method. The full list of tested saveable types can be found here. Theoretically, all types are supported.

//Saving an object
public void ExampleSave() {
    //Create the savegame
    SavegameSettings settings = new SavegameSettings("my-save-game");
    Savegame savegame = new Savegame(settings);

    //Saving a simple string
    savegame.Save("my-string-key", "My Hero Name");

    //Saving a Vector3
    savegame.Save("my-vector3-key", new Vector3(1, 2, 3));

    //Saving a GameObject
    GameObject go = GameObject.Find("Cube");
    savegame.Save("my-gameobject-key", go);

    //Saving a Component
    Transform transform = go.GetComponent<Transform>();
    savegame.Save("my-transform-key", transform);
}

Loading

There are two load methods. public T Load<T>(string key) is used for loading types that are serializable or have a surrogate defined in the UnitySurrogateSelector class. You can load any primitive type, enum or serializable struct with this method. Also all structs defined here.

//Loading objects without a reference
public void ExampleLoadingWithoutReference() {
    //Create the savegame
    SavegameSettings settings = new SavegameSettings("my-save-game");
    Savegame savegame = new Savegame(settings);

    //Loading a string
    String myString = savegame.Load<String>("my-string-key");

    //Loading a Vector3
    Vector3 myVector3 = savegame.Load<Vector3>("my-vector3-key");
}

The public void Load<T>(string key, ref T obj) method is used to load objects with a reference. GameObjects, Components and complex UnityEngine types and structs can only be loaded with this method because it does not create new instances, rather uses the given reference to load values into it.

//Loading objects with a reference
public void ExampleLoadingWithReference() {
    //Create the savegame
    SavegameSettings settings = new SavegameSettings("my-save-game");
    Savegame savegame = new Savegame(settings);

    //Loading a GameObject
    GameObject go = GameObject.Find("Cube");
    savegame.Load("my-gameobject-key", ref go);

    //Loading a Transform (or any Component)
    Transform transform = GameObject.GetComponent<Transform>();
    savegame.Load("my-transform-key", ref transform);
}

Persisting to disk

The Savegame is only written to disk when you call the WriteToDisk() function.

//Persisting the savegame to disk
public void ExamplePersistance() {
    //Create the savegame
    SavegameSettings settings = new SavegameSettings("my-save-game");
    Savegame savegame = new Savegame(settings);

    //Saving a simple string
    savegame.Save("my-string-key", "My Hero Name");

    //Write to disk
    savegame.WriteToDisk();
}

Deleting from disk

Deleting the Savegame will remove the file from disk and clear all keys.

//Deleting a savegame
public void ExampleDelete() {
    //Create the savegame
    SavegameSettings settings = new SavegameSettings("my-save-game");
    Savegame savegame = new Savegame(settings);

    //Delete from disk and clear savegame
    savegame.DeleteFromDisk();
}

Logging

Savegame is able to provide detailed debug logs by adjusting the Savegame.Logging property. The default value is LogLevel.ReadingWriting and shows when I/O file interactions are happening.

//Loglevels
Savegame.Logging = LogLevel.None;
Savegame.Logging = LogLevel.ReadingWriting;
Savegame.Logging = LogLevel.Keys;
Savegame.Logging = LogLevel.Serialization;
Savegame.Logging = LogLevel.Full;

//Mixing and mashing
Savegame.Logging = LogLevel.ReadingWriting | LogLevel.Serialization;

Additional functions

SavegameController

The SavegameController is a Component that can be added to any GameObject. It provides the basic structure to save and load in-game. This controller can be modified.

Best practices


Supported types

This package has implementations for the types below. All of these types have been tested. This package saves the settable properties of the given type.

Examples:

The structs below are saved in any type, even when nested within another type.

Structs

Struct Unsupported Partially saved Fully saved
Primitive types (string, int, float, etc.)     X
Vector2     X
Vector2Int     X
Vector3     X
Vector3Int     X
Vector4     X
Quaternion     X
Color     X
Color32     X
Bounds     X
BoundsInt     X
Matrix4x4     X
BoneWeight     X
BoneWeight1     X

Components

Components save the structs defined above and all their settable fields and properties. References to other GameObjects, Components or complex UnityEngine types are not saved.

Component Unsupported Partially saved Fully saved
GameObject     X
Transform     X
BoxCollider   X  
AudioSource   X  
MeshFilter X[1]    
MeshRenderer   X  
RigidBody     X[2]
Light   X  

UnityEngine Types

UnityEngine types save the structs defined above and all their settable fields and properties. References to other GameObjects, Components or complex UnityEngine types are not saved.

UnityEngine Type Unsupported Partially saved Fully saved
Mesh     X
Material   X  

What is saved

It is important to note that only settable fields and properties are saved. All types in the structs table are always saved in any type. UnityEngine types that are not in this table are always skipped. You can save them separately.

The table below shows a sample of Components and some of their saved properties. As you can see, only UnityEngine types are skipped when saving. If you need them, save them separately and assign them to the component in code.

Component Saves Does not save
GameObject Name, Tag, HideFlags, Layer, IsStatic Hierarchy, Components
Transform Position, Rotation, Scale, LocalPosition, LocalRotation, LocalScale Parent, Hierarchy
BoxCollider Center, Size, IsTrigger, ContactOffset Material, RigidBody
AudioSource Volume, Pitch, Time, Loop, PlayOnAwake AudioClip, AudioMixer

When loading a GameObject, Component or UnityEngine type, only the values are loaded from disk, no new object is created. This is to prevent leaks for objects such as GameObjects, Meshes and Materials.