beasty-save-system / reference / api-beastysave.md
BeastySave API
BeastySave is the static facade and the only entry point of the save system. Every method takes a
BeastySaveSettings and returns a typed result. Nothing on this page throws, except the three
registration methods, which throw on developer error.
Namespaces
using Beasty_SaveSystem; // BeastySave, BeastySaveable, BeastySaveManager
using Beasty_SaveSystemCore; // BeastySaveSettings, SaveResult, LoadResult, BeastySaveError,
// IBeastyConverter, ConverterUtil, BeastySaveLog
using Beasty_SaveSystemCore.Json; // JsonNode — needed only for migrations and custom converters
Slot names
Every method that takes a slot validates it. A slot is a bare file name. It is rejected with
InvalidArgument when it is empty or whitespace, contains / or \, contains .., is a rooted path,
contains characters that are invalid in a file name, or is a Windows reserved device name (CON, PRN,
AUX, NUL, COM1-COM9, LPT1-LPT9). The device names are rejected on every platform, so a save
folder written on Linux stays usable on Windows.
Saving
public static SaveResult Save(object data, string slot, BeastySaveSettings settings,
IDictionary<string, string> meta = null)
Serializes data, wraps it in an envelope and writes it to the slot atomically. meta is an optional
string dictionary stored in plain text next to the payload; see
Save file format. Returns SaveResult.Ok() or a failure.
Errors: InvalidArgument (null data, null settings, bad slot name), SerializationFailed (the object
cannot be turned into JSON: a reference cycle, a NaN/Infinity float, an unsupported dictionary key, a
ulong above long.MaxValue, a UnityEngine.Object reference on a plain C# class), IoError (the folder
cannot be created, the disk is full, the file is locked).
public static Task<SaveResult> SaveAsync(object data, string slot, BeastySaveSettings settings,
IDictionary<string, string> meta = null)
Same contract, with the file write done asynchronously. Serialization and encryption still run on the calling thread. Same error codes. See Async saving.
Loading
public static LoadResult<T> Load<T>(string slot, BeastySaveSettings settings)
Reads the slot and maps the payload into a new T. On success, Value holds the object. The envelope’s
type must match typeof(T).FullName.
Errors: InvalidArgument, FileNotFound, IoError, ParseError, Corrupt, VersionTooNew,
DecryptFailed, TypeMismatch, MigrationFailed, FieldMapFailed.
public static Task<LoadResult<T>> LoadAsync<T>(string slot, BeastySaveSettings settings)
Same contract, reading the file asynchronously. Same error codes.
public static LoadResult LoadInto(object target, string slot, BeastySaveSettings settings)
Loads the slot onto an object that already exists, instead of creating one. This is the only way to load a
MonoBehaviour or any other UnityEngine.Object: they are never constructed from file data. The
envelope’s type must match target.GetType().FullName.
Errors: the same as Load<T>, plus InvalidArgument when target is null.
public static Task<LoadResult> LoadIntoAsync(object target, string slot, BeastySaveSettings settings)
Same contract, reading the file asynchronously. Same error codes.
Note
BeastySaveSettings.Strictdecides what a bad field does: strict fails the whole load and applies nothing, tolerant skips the field and reports it inLoadResult.Warnings. See Strict vs tolerant loading.
Slots
public static bool Exists(string slot, BeastySaveSettings settings)
True when the slot file is on disk. False for a null settings or an invalid slot name. Does not open or
validate the file.
public static bool Delete(string slot, BeastySaveSettings settings)
Deletes the slot file and its .bak. Returns true when the slot file itself was deleted. Best effort: a
locked file is skipped silently, never thrown.
public static string[] ListSlots(BeastySaveSettings settings)
Slot names in the save folder, sorted in ordinal order. Backups (.bak) and in-flight temp files (.tmp)
are excluded. Returns an empty array when the folder does not exist.
public static LoadResult<Dictionary<string, string>> ReadMeta(string slot, BeastySaveSettings settings)
Reads only the envelope’s meta dictionary. It does not verify the checksum, does not decrypt and never
touches the payload, so it works on an encrypted save without the key. This is what a save-slot screen
should call. See Slots and metadata.
Errors: InvalidArgument, FileNotFound, IoError, ParseError, Corrupt (the envelope shape is
invalid).
public static SaveResult RestoreBackup(string slot, BeastySaveSettings settings)
Copies <slot>.<ext>.bak over the slot file, atomically. The .bak is left in place, so restoring twice
is safe. See Backups and corruption.
Errors: InvalidArgument, FileNotFound (there is no backup for that slot), IoError.
Extension points
public static void RegisterMigration(int fromVersion, int toVersion, Func<JsonNode, JsonNode> migrate)
Registers one step of the migration chain, applied to the raw JsonNode at load time when the file’s
dataVersion is older than BeastySaveSettings.DataVersion. Steps chain: 1 to 2, 2 to 3, and so on.
Throws ArgumentNullException when migrate is null and ArgumentException when toVersion is not
greater than fromVersion — these are developer mistakes, not file input. See
Versioning and migrations.
public static void RegisterConverter(IBeastyConverter converter)
Registers a converter in the dev layer, which has the highest priority and therefore overrides both
module converters and the built-in core ones. The most recent registration wins. Throws
ArgumentNullException on a null converter.
public static void RegisterModule(string moduleId, IEnumerable<IBeastyConverter> converters)
Registers a named group of converters. Idempotent by id: registering the same id again replaces the group.
The id is written into every component entry of a scene save. Throws ArgumentException on an empty id and
ArgumentNullException on a null sequence. See Custom converters.
public static bool TryDescribeConverter(Type type, out string source)
True when some registered converter handles the type. source is "dev", a module id (for example
"physics2d") or "core". This is what the editor uses to warn about components with no converter.
Warning Entering Play Mode resets the statics. Converters registered with
RegisterConverter, and every migration, are lost on every Play. Register them from a[RuntimeInitializeOnLoadMethod]. Modules registered withRegisterModulesurvive the reset.
Paths
public static string GetFolderPath(BeastySaveSettings settings)
The absolute folder holding the save files: {DataPath or Application.persistentDataPath}/{Folder}. The
folder is created if it does not exist.
public static string GetSlotPath(string slot, BeastySaveSettings settings)
The absolute path of one slot’s file: {folder}/{slot}.{Extension}. Does not create anything and does not
validate the slot name.