Vault Save System

ScriptableObjects & MonoBehaviours

ScriptableObjects

Scans all [Save]-marked fields and persists them in one call. The key is a namespace prefix - fields are stored as "key.TypeName.fieldName".

static void Save(string key, ScriptableObject so) static void Load(string key, ScriptableObject so) static Task SaveAsync(string key, ScriptableObject so)
[CreateAssetMenu]
public class GameSettings : ScriptableObject
{
    [Save] public bool  musicEnabled = true;
    [Save] public float masterVolume = 0.8f;
}

Vault.SetDrawer("settings");
Vault.Save("settings", myGameSettings);
Vault.Load("settings", myGameSettings);

await Vault.SaveAsync("settings", myGameSettings);  // async variant

MonoBehaviours

The builder overload saves all [Save]-marked fields on the MonoBehaviour automatically, plus any Unity components you add with .With<T>(). Only what you list is included - nothing is saved implicitly.

static void Save(string key, MonoBehaviour mb, Action<VaultBuilder> build) static void Load(string key, MonoBehaviour mb, Action<VaultBuilder> build)
// [Save] fields on the MonoBehaviour are included automatically.
// .With<T>() adds Unity components (Transform, Rigidbody, Camera, etc.)
Vault.Save("player", this, b => b.With<Transform>().With<Rigidbody>());
Vault.Load("player", this, b => b.With<Transform>().With<Rigidbody>());

Keys are stored as "player.YourComponent" per component and "player.YourMonoBehaviour" for the root script's [Save] fields.

Multiple components of the same type

The builder saves one component per type. .With<T>() stores types, not instances (and dedupes them), then resolves each with GetComponent - which returns only the first component of that type - under a type-named key like "player.BoxCollider", with no index. So for stackable types (multiple Colliders or AudioSources, or several instances of your own MonoBehaviour) only the first is saved; the rest are silently ignored, and would collide on the same key anyway. Types Unity only allows one of - Transform, Rigidbody, Camera, Light, MeshFilter, ... - are completely safe.

To save more than one component of the same type, give each instance its own key with the direct component overload:

// Save - a distinct key per instance
Vault.Save("player.hitbox",  hitboxCollider);
Vault.Save("player.trigger", triggerCollider);

// Load - applied back in-place to the specific instances
Vault.Load("player.hitbox",  hitboxCollider);
Vault.Load("player.trigger", triggerCollider);