Save Manager

4 min read

Updated on November 21, 2025

Introduction

This Manager class handles saving the data from this asset, which includes the Resource Node, Item Container and Crafter components.

All of these components self register themselves with this manager to make sure they are saved if they still exist.

It uses the ISaveable interface, alongside the SaveableObject component. The former must be implemented on any class to be saved, and the SaveableObject must also be component on the same gameobject as the 3 main components mentioned above. This will also add a UniqueID component, which is essential for saving and loading. You should not need to do anything with either of these classes. You can assign a new or copy an ID if you wish but should not need to.

Save data is located in the Application.persistentDataPath with the scene name as .json file.

Note – It does not save anything apart from what is specified. It is meant to be used alongside other saving and loading systems if building the main components into the scene at runtime. This system has no building functionality, so if this functionality is present in your game, you will need to custom load this data back onto the objects.

Setting up

There is a prefab Save Manager located in /prefabs/Managers or the main prefab for the ResourceAndProductionManager also contains this manager.

Setting up otherwise is as simple as adding the component to a gameobject.

Settings

Save On Exit
If enabled, runs the SaveGame method OnApplicationQuit.

Load On Play
If enabled, runs the LodGame method OnStart.

Auto Save Interval Minutes
Loops Auto saving after a certain number of minutes have passed. Suggested values of above 5 minutes are recommended for performance.

Combining Loading and Saving with your own (easy)

If you are not placing any new assets at runtime from this asset, then the normal SaveGame and LoadGame functions should serve just fine.

1. Get the UniqueID of the component and save it alongside the rest of your system data. You can get this via the UniqueID component itself or via the SaveableObject component.

2. Use your custom loading logic to completly load your game.

3. Ones fully loaded back in to the scene (instantiated), assign the ID string back onto the UniqueID using AssignNewID.

4. Use LoadGame() in the SaveManager to load all data back onto the instantiated gameobjects.

Combining Loading and Saving with your own (Advanced)

If you are not placing any new assets at runtime from this asset, then the normal SaveGame and LoadGame functions should serve just fine.

There are several important functions available to you if you wanted to custom load this assets components.

If you are placing/removing these components at runtime, its crucial to make sure you gather the data you need and follow the next steps.

1. Get the UniqueID of the component and save it alongside the rest of your system data. You can get this via the UniqueID component itself or via the SaveableObject component.

2. Use that UniqueID to get the asset data back from the saved .json file using one of the following methods

//This is per ID
public void LoadObject 
{
    //ResourceNodeSaveData resourceSaveData = GetSavedData<ResourceNodeSaveData>("182f2134-9037-4dda-b3ed-4f8c54410161");
    //Debug.Log(resourceSaveData.currentHp);
}

//This is the whole save file
public void LoadObjects
{
    var data = SaveManager.Instance.TryGetSaveData();

    if (data == null)
    {
        Debug.Log("No save file found for this scene.");
        return;
    }

    //Use your saved ID here 
    string savedID = "182f2134-9037-4dda-b3ed-4f8c54410161";

    if (data != null && data.TryGetValue(savedID, out object objectData))
    {
        //This is the object you are loading, just get the ISaveable interface from it
        ISaveable target = loadedGameobject.GetComponent<ISaveable>();
 
        if (target != null && objectData != null)
        {
            target.RestoreState(objectData);

            //Reassign your ID back on for future saving
            target.GetComponent<UniqueID>().AssignNewId(savedID);
        }
    }
}

//This is the whole save file
//Should run on Start
//Similar for getting the save data above, but you can automatically run it when the game is saved
public void Start() 
{
    SaveManager.Instance.OnGameSaved += (data) =>
            {
                foreach (var kvp in data)
                {
                    //You could store your keys here
                    Debug.Log($"Saved Key: {kvp.Key}, Value: {kvp.Value}");
                }
            };
}

//This is the whole save file
//Should run on Awake, not Start so we hook into the event before the game is loaded on Start
//Similar for getting the save data above, but you can automatically run it when the game is loaded
public void Awake() 
{
    SaveManager.Instance.OnGameLoaded += (data) =>
            {
                foreach (var kvp in data)
                {
                    Debug.Log($"Saved Key: {kvp.Key}, Value: {kvp.Value}");
                }
            };
}

After you have loaded the object, make sure to also reassign the ID back to UniqueID using AssignNewID.

To summarise –

1. Store the ID in your own saving logic

2. During your own loading phase when you are loading gameobjects back into the scene, use the stored ID to get the saved data using the above methods.

3. Get the ISaveable interface from the gameobject that is now placed in the scene. Call the saveableObject.RestoreState(data) function with the data returned from the Dictionary.

Scripting

There are a few public methods to assist with saving and loading

/// <summary>
/// Register an ISaveable to save with the SaveManager
/// </summary>
/// <param name="saveable">The ISaveable to be saved</param>
public void RegisterSaveable(ISaveable saveable)

/// <summary>
/// Removes the ISaveable to be saved
/// </summary>
/// <param name="saveable"></param>
public void UnregisterSaveable(ISaveable saveable)

/// <summary>
/// Saves the current Resource and Production assets using the ISaveables list
/// </summary>
/// <param name="filename"></param>
public void SaveGame(string filename = "savegame.json")

/// <summary>
/// Loads the current save and reapplies the current
/// </summary>
/// <param name="filename"></param>
public void LoadGame(string filename = "savegame.json")

/// <summary>
/// Tries to get the save data from the current scene
/// </summary>
/// <param name="filename">Optional override if you saved the game with a custom file name</param>
/// <returns>A Dictionary<string, object> of saveable objects</returns>
public Dictionary<string, object> TryGetSaveData(string filename = "savegame.json")

/// <summary>
/// Loads and returns the saved data for a specific UniqueID directly from the save file.
/// Does not require LoadGame() to have been called.
/// Returns null if no entry or type mismatch is found.
/// </summary>
public T GetSavedData<T>(string uniqueId, string filename = "savegame.json") where T : class