Documentation index for AI agents (llms.txt) A Markdown version of every page is available: request the page's source under /docs/, follow the "alternate" link in this page's head, or start from /llms.txt.
Visual Script logo Scripting API

Saving your own components#

ISaveLoad is the interface implemented by every save-system participant. Implement it on your own component or ScriptableObject when the type should save itself without a Remember component.

The interface#

This manager subscribes for its lifetime and saves one integer in a dedicated data class:

using System;
using UnityEngine;
using VisualScript.Runtime;

public class MyManager : MonoBehaviour, ISaveLoad
{
    [SerializeField] private SaveOptions m_SaveOptions = new SaveOptions();
    [SerializeField] private int m_Score;

    [Serializable]
    public class Data
    {
        [SerializeField] public int score;
    }

    private void Awake() => SaveLoadManager.Subscribe(this);
    private void OnDestroy() => SaveLoadManager.Unsubscribe(this);

    IdString ISaveLoad.Id => this.m_SaveOptions.Id;
    Type ISaveLoad.Type => typeof(Data);

    bool ISaveLoad.IsShared => false;
    bool ISaveLoad.IsPersistent => true;

    void ISaveLoad.OnReset() => this.m_Score = 0;

    object ISaveLoad.OnSave() => new Data { score = this.m_Score };

    Awaitable ISaveLoad.OnLoad(object value)
    {
        if (value is Data data) this.m_Score = data.score;
        return AwaitableUtils.DontAwait;
    }
}

SaveOptions supplies the stable ID, while Data defines the serialized contract. Awake and OnDestroy keep the manager registered only while it exists.

The properties#

These properties define which saved data belongs to the object and when the manager restores it:

Property Means
Id Unique identity. Two objects with the same ID are treated as the same object.
Type The type of the data returned by OnSave.
Priority Restore order, higher first. Defaults to 0.
CanSave Whether to write at all. Defaults to true.
IsShared true for data common to every profile, false for per-profile data.
IsPersistent true if the object survives scene loads, false if it's scene-bound.

IsPersistent controls restore timing#

Choose IsPersistent based on whether your object survives the scene load:

Value Restored Suits
true Before scenes load Managers, singletons, assets
false As its scene loads Components on scene objects

Marking a scene-bound object as persistent restores it before the scene load. The load then destroys the object and silently discards the restored state.

Id must be stable#

The manager uses the ID to match stored data to the object that receives it.

Never change an ID after shipping

Existing saves reference the old ID. Changing it makes the data unreachable, so the object returns with default state and no migration error.

The built-in SaveOptions field provides the same identity UI as the Remember component, including designer-set and generated IDs. Prefer it to a separate ID implementation.

Subscribing#

Subscribe when the object initializes and unsubscribe when its lifetime ends:

Kind Subscribe in Unsubscribe in
MonoBehaviour Awake OnDestroy
ScriptableObject Initialization Never — assets outlive the session

Forgetting to unsubscribe keeps a destroyed component in the subscriber list. The next save calls OnSave on that component.

OnSave and OnLoad#

OnSave returns any serializable object. Use a dedicated, flat data class to make the stored format explicit and keep component changes separate from save compatibility.

OnLoad receives it back as object. Always type-check rather than casting, because a save written by an older version may hold something different:

if (value is not Data data) return AwaitableUtils.DontAwait;

The type check returns immediately when the loaded value isn't Data. When the value is valid, OnLoad can await any required initialization before restoring it.

OnReset#

The save system calls OnReset when the game returns to a new-game state. Restore the component's authored defaults there.

Without this reset, state from the previous profile leaks into the new game.

Versioning#

Players may load saves written by an earlier version of your game. Two habits help preserve compatibility:

  • Add fields; do not repurpose them. A new field receives its default in old saves, while a changed meaning corrupts the interpretation of existing data.
  • Include a version number in the data class from the first release. It provides the branch needed for a later migration.

Where to go next#

Visual Script logoVisual Script © Catsoft Works 2026. All rights reserved.