Built-InsReady-made managers, storage backends, security and helpers.

Local managers

PrototypePersistenceManager

PM

"Prototype". Zero-config local save, desktop/mobile/WebGL. No settings. Not consoles: those gate saving behind their own SDK, so they need a PersistenceManager subclass of your own.

FilePersistenceManager

PM

"Local File". The manager to ship with: you name the file and the folder, and turn compression, encryption and the backup copy on.

string FileNameThe save file's name, subfolders included.
string HeaderTextAn optional '#' comment line written at the top of the file. Players can edit or delete it; empty writes none.
string SaveFolderAbsolute folder this manager saves in, or a path starting with the folder token {Documents}, {UserProfile}, {AppData} or {LocalAppData}, which the machine running replaces with a folder of its own. Empty means the folder the platform hands the game. The SaveLocation subfolders are created under it as they are under the default. Desktop players and the editor only: elsewhere it refuses every operation, and a build for such a target fails while it is set. It applies in the editor too, so a manager using it shares its saves with an installed build of the game.
string FileExtensionExtension (no dot) this manager's files take. Empty means save. Part of the file name, so it decides which files a load finds.
Compression Compression / Encryption Encryption / SaveAnchor AnchorSaveToStorage protection; all three default to None.
bool DoBackupKeep a second copy against crashes mid-save. On by default.
static string RuntimeSecret { get; set; }Secret supplied at runtime for the RuntimeSecret anchor, forwarding to CheatProtectionUtility.RuntimeSecret: the two are one session-wide value. The setter throws ArgumentException when set to null/empty, and InvalidOperationException when set a second time with a different value.
static event Action<Object> OnTamperedLoadedRaised after a load completed with tampered data now on the target (passed to the handler): the file failed its AppendHash integrity check, or carried the sticky mark of a previous detection.
static bool IsTampered(Object target)Whether the data currently loaded on the target descends from a tampered save. The mark is sticky: it is rewritten into every save of the lineage (slot copies and Slots.SaveTo snapshots included), so it survives sessions; it resets on a clear, or when a load finds pristine data again. Throws ArgumentNullException for a null target.
static void MarkTampered(Object target)Brand the current save lineage as tampered from your own cheat detection: the same sticky, authenticated mark an automatic detection writes, which a player cannot edit back out of a readable save. There is no way to unmark it, and OnTamperedLoaded is not raised. Throws ArgumentNullException for a null target, InvalidOperationException when no active file manager is in charge of it or its Encryption is not AppendHash.

PlayerPrefsPersistenceManager

PM

"Player Prefs". Saves through PlayerPrefs; synchronous; good for small data. The automatic load retry is off: a Player Prefs read never fails transiently. It reports no errors either, since Unity's own API has no channel for them: a save always comes back successful, and a write that did not survive reads later as a first run. A binary serializer is base64 encoded to fit, costing about a third more space: the one manager where a binary save is larger than a text one.

Remote managers

RemotePersistenceManager

PMabstractextending

Base for remote managers. ReadExecutionMode is always AsyncOnly and WriteExecutionMode is PreferAsync only while a cache is on, otherwise AsyncOnly: a remote load is never synchronous. Implement the async FetchRemote / StoreRemote / DeleteRemote primitives (each reports an Answer); inherit async, cache and push. Worked example: A custom remote manager.

Public
ConflictPolicy ConflictPolicy (virtual)Only used while CacheMode enables a cache. What to do when a load finds this device and another one both saved the object: PreferNewest (default, keeps the most recent of the two and relies on the devices' clocks) or Ask, which raises Conflicts.OnAny and leaves the load undecided until Conflicts.Resolve answers. Not consulted for an IMergeable target. An inspector field on Server (HTTP) and Cloud Save (UGS); a custom remote manager opts in by overriding it with a serialized auto-property. See when two devices disagree.
static string RuntimeSecret { get; set; }Secret supplied at runtime for the SaveAnchor.RuntimeSecret anchor, on the payload or on the cache. Forwards to CheatProtectionUtility.RuntimeSecret: that value, the file manager's and this one are one session-wide secret, reachable from whichever manager you are working in. The setter throws ArgumentException when set to null/empty, and InvalidOperationException when set a second time with a different value.
Compression Compression (virtual)Defaults to None, and is breaking: saves written with the previous setting stop loading. Gzip is applied to the payload before Encryption and before the backend sees it, so a backend never compresses anything itself and the offline cache stores the compressed payload too. Opt in by overriding with a serialized auto-property, like the protection settings below. On the asynchronous write path the gzip and the encryption run on a background thread (the main thread on WebGL, which has none).
Encryption Encryption / SaveAnchor AnchorSaveTo (virtual)Protection of the payload handed to the backend and read back from it, applied between the serializer and the primitives. Opt in by overriding with a serialized auto-property; a backend that does not override it shows no field and keeps the default. Encryption.AppendHash and SaveAnchor.TargetMachine are refused and the manager then refuses every operation. See Secure a remote save.
Encryption CacheEncryption / SaveAnchor CacheAnchorSaveTo (virtual)Protection of the copy the offline cache keeps on the player's disk, independent of the pair above, so a payload readable to your backend can still be opaque locally. Both default to None, and they are used only while CacheMode enables a cache. SaveAnchor.TargetMachine is allowed here and is the strictest anchor available (the cache never leaves the device); Encryption.AppendHash is refused, as above. Changing either makes existing cache entries unreadable: one the server already holds is dropped and refetched, one holding unpushed work fails loudly instead of being discarded.
RemoteStatus Status { get; } / event Action<RemoteStatus> OnStatusChangedWhether the offline cache is fully pushed (UpToDate), still holds changes to push (PendingChanges), or holds a change another device is blocking until a load settles it (Conflicted). Always UpToDate with no cache.
Task<RemoteStatus> PushPendingChangesAsync(CancellationToken = default)Flush the cache to the server now. Never throws: a push that is cancelled or whose primitive fails reports through the status it returns.
enum AnswerHow the remote responded, which the cache reasons about, so map yours exactly. Success: it landed, and a fetch returns the body byte for byte. NoSave: reachable, but nothing saved at this address. Corrupt: unreadable, a retry will not fix it. Error: the remote answered but the operation did not land, and a retry may help. Unreachable: the remote could not be contacted at all, the only answer an offline cache treats as offline.
WritePayloadSync / ClearPayloadSync / ReadPayloadAsync / WritePayloadAsync / ClearPayloadAsync (sealed)Sealed by this base: a backend implements the asynchronous read, write and clear, and the cache drives the synchronous side.
bool SelfBoundsAsyncOperations (sealed)Sealed on: with a cache on, the engine races the remote against the operation timeout and falls back to the cache, so it bounds itself.
static void ClearLocalCache(string managerName, string folder)Delete one manager type's offline cache (backs a [ClearLocalData] editor cleaner).
For implementers (protected)
Task<(Answer answer, byte[] body, string message)> FetchRemote(string slot, CancellationToken) (protected abstract)Read the slot's payload from the server (the body is null unless the answer is Success).
Task<(Answer answer, string message)> StoreRemote(string slot, byte[] body, CancellationToken) (protected abstract)Write the slot's payload to the server, encoded as your transport requires.
Task<(Answer answer, string message)> DeleteRemote(string slot, CancellationToken) (protected abstract)Delete the slot's payload on the server.
RemoteCacheMode CacheMode { get; protected set; } / OfflineColdStart OfflineColdStart { get; protected set; } (virtual)Offline-cache behavior; override to opt in (e.g. with [field: SerializeField]).
string SetupError (protected virtual)A permanent fault message, such as a missing URL, which refuses every operation until it is fixed. null when there is none.
string LocalCacheFolder (protected virtual)Name of the subfolder the offline cache is kept in. The type name by default.

HttpPersistenceManager

PM

"Server (HTTP)". Saves to your own server, or to a backend service, with a GET, a PUT and a DELETE at url/slot/id.

Public
string ReleaseUrl / DevelopmentUrl / IdEndpoint, dev override, and save id.
string LoadUrlTemplate / SaveUrlTemplate / ClearUrlTemplatePer-operation address, replacing url/slot/id. Supports {url}, {slot}, {id} and {token} (written back as its placeholder wherever an address is logged, so a failing request never carries a credential into a console); empty keeps the built-in scheme.
HttpVerb LoadVerb / SaveVerb / ClearVerbPer-operation HTTP method (Get / Put / Delete by default).
string SaveBodyTemplateJSON envelope a save is wrapped in, with {payload} (escaped for you; base64 when it has no text form, meaning compressed or from a binary serializer), plus {slot} and {id} for a service that wants the record named in the body too. Empty sends the payload verbatim.
string LoadBodyTemplate / ClearBodyTemplateJSON body a load or a clear is sent with, for a service whose read or delete is an RPC rather than a plain GET or DELETE, with {slot} and {id} where it wants the record named. Empty sends no body, which is what a REST backend and a server of your own want. {payload} means nothing here: neither operation carries a save.
string ResponsePayloadPathDotted path the payload is read back from, for example data.Data.save.Value; a numeric step indexes an array, and a step takes {slot} and {id}, filled one step at a time so a slot holding a . names one member rather than splitting the path.
HttpNotFound NotFoundMeansWhat a 404 to a load means, NoSave by default: NoSave (the address holds nothing, so the target starts on its defaults and a cached save for that slot is dropped) or Error (the load retries and a cached save is kept). Use Error only with a backend that signals an absent save some other way, since one that 404s for that too can then never finish a first load.
HttpEmptyAnswer EmptyAnswerMeansWhat an answer that arrived cleanly but holds nothing at ResponsePayloadPath means, Corrupt by default: Corrupt reports it, so a path that does not fit the service is found rather than mistaken for a new player, and a cached save is kept and played from; NoSave reads it as a first launch, which is what the services answering 200 with an empty result need, at the cost of a mistyped path reading the same way and a cached entry for that slot being dropped. Only used while a payload path is set.
HttpHeader[] ExtraHeadersExtra request headers; each value supports {token}, filled from Authorization.
string Authorization / Action<UnityWebRequest> ConfigureRequestRuntime auth and per-request hook, this manager's own. Unset (null), each reads its Default below, so clearing Authorization on sign-out leaves the project-wide token going out: assign an empty string for "send none".
static string DefaultAuthorization / static Action<UnityWebRequest> DefaultConfigureRequestWhat every HTTP manager that sets none of its own sends. Two managers pointed at different services each need their own, or the second signs its requests with the first one's credentials. Both are cleared when play mode ends, so a token never carries into the next session.
For implementers (protected)
string GenerateAddress(string slot) (protected internal) / Task Send(UnityWebRequest, CancellationToken) (protected) / string ErrorText(UnityWebRequest) (protected) / string ErrorText(UnityWebRequest, string token) (protected)Subclassing helpers to adapt the server contract. ErrorText writes the token back as {token} so a failing request never logs a credential, which is why it is an instance member rather than a static one. The one-argument form redacts against this manager's Authorization as it reads now; pass the token you built the address from where a refresh could land mid-request, or the older credential reaches the log in full. Send throws OperationCanceledException when the token is cancelled.

CloudSavePersistenceManager

PM

"Cloud Save (UGS)". Per signed-in player. Requires UGS init + sign-in. RegularSaveDelay defaults to 60 seconds, as on the HTTP manager.

string KeyCloud Save key (accepts the <slot> placeholder; only letters, digits, - and _ are valid, any other character is reported as invalid).

Remote enums

enum
RemoteCacheModeNo Cache: every load and save reaches the server, and fails while it is unreachable. Server + Cache: loads go to the server when it answers, to the cache when it does not. Local Cache (Server Backup): the local save wins, and the server is a write-only backup read only when nothing is cached.
OfflineColdStartWait For Server (default) retries until it answers; Start Fresh starts on defaults.
RemoteStatusUpToDate, PendingChanges, Conflicted.
ConflictPolicyPreferNewest, Ask.

RemoteSettings

static

The project-wide settings of the remote managers, as set under Project Settings > Persistent Asset > Remote. Read here already clamped.

float PushRetryDelay { get; }Seconds between attempts to push pending offline-cache data to the server (clamped to ≥ 5). Defaults to 30.
int RequestTimeout { get; }Seconds before a single remote request is forced to time out: a safety net against a server that accepts the connection and never answers, so it usually only bites when a manager's own Load / Save / Clear Timeout is higher or unbounded (whichever bound is reached first ends it). 0 disables it. Defaults to 120.
const float MinimumPushRetryDelay = 5Lower bound for PushRetryDelay.

SteamCloudPersistenceManager

PM2.0

"Steam Cloud". Saves through Steam Remote Storage, synchronously; the Steam client syncs the files. Needs Steamworks.NET, and your game to call SteamAPI.Init. Windows, macOS and Linux only. A plain PersistenceManager, not a RemotePersistenceManager: no offline cache, no payload encryption, and the Steam client does the syncing.

string FileNameThe cloud file a save is stored under, without extension (defaults to the unique id). The slot is part of it on a slotted manager.
const string FileExtension = ".sav"The extension every cloud file it writes carries, leading dot included, unlike SaveFileUtility.FileExtension.
bool IsSteamReadyWhether the Steam API is initialized, so this manager can operate. While false every operation fails with one message.
bool IsCloudEnabledForAccount / IsCloudEnabledForAppWhether Steam Cloud is on. With it off, saves succeed but stay on the machine.
bool TryGetQuota(out ulong totalBytes, out ulong availableBytes)false while Steam is not initialized or the quota cannot be read. The player's cloud quota for this application. A write that would exceed it fails loudly.

HttpVerb / HttpNotFound / HttpEmptyAnswer / HttpHeader

enumstruct2.0

What the Server (HTTP) manager's Backend Service fields are made of.

enum HttpVerbGet, Post, Put, Delete, Patch.
enum HttpNotFoundNoSave, Error: what a 404 to a load is taken to mean.
enum HttpEmptyAnswerCorrupt, NoSave: what an answer holding nothing at the payload path is taken to mean.
struct HttpHeaderName and Value (a template supporting {token}), plus a constructor taking both.

Other managers

PlatformPersistenceManager

PM2.0

"Platform (Routing)". Saves through a different manager depending on where the game runs: it stores nothing itself and hands every operation to the route it resolved. Routes are authored in its inspector, each claiming platforms (and optionally a distribution) and owning the manager that stores there; the first route claiming the current platform wins, and one with no platform is the fallback. It keeps the serializer, the slot settings and the automatic load and save for the whole setup, and takes the execution modes, the timeouts and the storage from the route. With no matching route, persistence is disabled for the target and the reason is reported. See Save per platform.

PersistenceManager ActiveManager { get; }The manager this platform routes to, or null when nothing matches.

SessionPersistenceManager

PM

"Session (Memory)". Keeps the data in memory for the session and writes nothing to disk. Automatic load and save are forced on, whatever a target's policy asks for, and the load retry and the regular save are off.

TestPersistenceManager

PM

"Test". A fake in-memory manager for seeing how the game behaves when saving misbehaves: force any operation to any outcome, and add a delay to it to try out loading screens, timeouts and cancellation. Assigning it always keeps an import copy of the setup it replaces, restored in one click from its inspector, and it never ships: a release build fails while one exists in the project, and a development build logs a warning. Worked example: Write a test manager.

Inspector: Load Outcome / Save Outcome / Clear OutcomeWhat each operation does instead of reaching storage: Default runs it for real against the in-memory store, and the rest force the result.
Inspector: Load Delay / Save Delay / Clear DelaySeconds each operation takes before it answers, for rehearsing a slow server against a real loading screen.
enum ForcedLoadOutcomeDefault (run for real), Success, Invalid, Failure, Exception, Cancelled, Corrupt (an Invalid that also sets IsCorrupt). Declared in that order, and stored by number, so an existing asset keeps the outcome it was set to.
enum ForcedOutcomeDefault, Success, Failure, Exception, Cancelled (save/clear; no Invalid).

Serializers

UnityJsonSerializer

class

"Unity JSON", the default serializer: serializes fields by Unity's own rules into readable JSON, and supports save versioning. Its inspector Format option is PrettyPrint, OneLine, or Obfuscated (compact base64 so players cannot casually read or edit it, obfuscation, not encryption).

enum FormatPrettyPrint, OneLine, Obfuscated.
Format WriteFormat { get; }The Format set on the asset.

NewtonsoftJsonSerializer

class

"Newtonsoft JSON". Serializes the union of what Unity serializes and what Newtonsoft serializes (dictionaries, properties, nullables, plain C# objects), and supports save versioning. Present only when the com.unity.nuget.newtonsoft-json package is installed. See What can be saved.

enum FormatPrettyPrint, OneLine, Obfuscated.
Format WriteFormat { get; }The Format set on the asset.
bool SharedReferences { get; }Keeps an object referenced from several places as one object (and lets data refer back to itself), adding $id / $ref members. Turns SupportsNode off while it is on, so save upgrades and the conflict prompt's preview fields stop working: a repeat written as a placeholder would have an upgrade read bookkeeping where the values are.
bool PolymorphicTypeNames { get; }Writes the concrete type of values in interface, abstract or base class fields. The type name becomes part of the save format, and a modified save can then name any type in your game.
IList<JsonConverter> Converters (static)Converters your game adds for what this serializer cannot write by itself, an object created at runtime above all. One registered for a type wins over the package's own asset-reference handling of it. Register at start-up: which converter handles a type is decided the first time it is written.

OdinDataSerializer

class

"Odin". Serializes through Odin Serializer, with shared references and polymorphic types handled by Odin itself. Present only when Odin is in the project, either the serializer bundled with Odin Inspector or the free standalone Odin Serializer, which the package detects on its own. See What can be saved.

enum FormatJson (readable, and the only one save upgrades can read old values from), Binary (smaller and faster, raw bytes).
Format WriteFormat { get; }The Format set on the asset.

MemoryPackDataSerializer

class2.0

"MemoryPack". Raw bytes, with the readers and writers generated at compile time: no reflection at run time and no AOT step for an IL2CPP build, at the cost of marking every persistent type [MemoryPackable] partial and every asset member [MemoryPackAllowSerialize]. It also writes only public fields and settable public properties: a private [SerializeField] field the other serializers persist is left out with no error unless it carries [MemoryPackInclude]. A MemoryPack save is raw bytes, so save upgrades and field resets cannot read old values out of it. Present only when MemoryPack is in the project. See What can be saved.

It has no settings of its own.

MemoryPackScriptableObject

abstract2.0

Derive from this instead of PersistentScriptableObject for a type serialized by MemoryPackDataSerializer. Deriving straight from the base class does not compile: MemoryPack needs every inherited member marked, and the base holds a PersistenceManager member inside the package that you cannot mark yourself. This class marks it for you and changes nothing else. Explained in What can be saved.

PersistenceManager PersistenceManager { get; }The base class member, re-declared only to carry [MemoryPackIgnore] so the generator leaves it out of the save. Same value.

AssetFormatter<T>

sealed2.0

Lets MemoryPack save a field pointing at a project asset: it writes the asset's registry id and looks the asset back up on load. The package ships one for Sprite, Texture2D, AudioClip, Material, Mesh, GameObject and ScriptableObject. Register your own for any other asset type, before the first load: MemoryPackFormatterProvider.Register(new AssetFormatter<AnimatorController>()). It has to match the field's declared type. An asset the registry no longer knows reads back as null.

Security

Encryption

enum

Explained in Secure saves.

NoneNo encryption.
AppendHashReadable, with a secured hash: a modified save still loads but is permanently marked as tampered (see FilePersistenceManager.IsTampered).
EncryptFully encrypted; a modified save cannot be loaded at all.

Compression

enum

Explained in Secure saves.

None / Fast / OptimalNo compression, fast, or best (slower) gzip.

SaveAnchor

enum [Flags]

An anchor decides what fails the integrity check; Encryption decides the cost: Encrypt leaves the save unreadable, AppendHash loads it marked as tampered. Explained in Secure saves.

NoneReadable by any copy of the project.
TargetMachineFails its check on another machine.
FileLocationFails its check if moved, renamed or swapped.
RuntimeSecretFails its check without the runtime secret.
EverythingAll locks.

Utilities

SaveFileUtility

staticextending

Low-level file IO shared by the file-backed managers and the offline cache. You only need it to build your own file-based manager. Explained in Extend the package.

const string FileExtension = "save"Extension (no dot) every save file it reads and writes takes, unless one is passed for it.
bool SupportsCustomFolderWhether this platform can read and write saves outside the folder it hands the game, which only the desktop players and the editor can.
string GetRootFolderPath(string root = null) / EnsureRootFolderExists(string root = null)Root folder under which every save location lives (the second creates it). Pass a root to use that absolute folder instead of the platform one; null or empty is the platform one.
string GetSaveFolderPath(SaveLocation location, string root = null) / GetSaveFilePath(SaveLocation, string relativeFilePath, string root = null, string extension = null)Resolve a location's folder, or a file path within it (GetSaveFilePath appends the extension, so pass relativeFilePath without one). Throws ArgumentOutOfRangeException for an undefined location.
byte[] Read(SaveLocation, string relativeFilePath, string root = null, string extension = null) / byte[] ReadHeader(SaveLocation, string, int maxBytes, string root = null, string extension = null)Read a save file, or just its first bytes; null when it does not exist. Throw IOException when the file exists but cannot be read, and UnauthorizedAccessException without permission; ReadHeader throws ArgumentOutOfRangeException for a negative maxBytes.
void Write(SaveLocation, string relativeFilePath, string uniqueId, byte[] data, string root = null, string extension = null) / WriteAtomic(string path, string tempPath, byte[] data)Throw IOException when the file cannot be written (disk full, destination held open) and UnauthorizedAccessException when it is read-only or unpermitted. Write a save file atomically (stage then swap, crash-safe). WebGL cannot swap: the data goes straight to the destination, so an interrupted write can leave it truncated. On a destination that refuses the swap (some network shares, some removable media) the previous save is staged aside by hand, under GetAsidePath.
byte[] ReadAside(SaveLocation, string relativeFilePath, string root = null, string extension = null, int maxBytes = 0)Read the copy WriteAtomic parked aside, for the file at relativeFilePath. An interrupted by-hand swap leaves the save missing and this copy holding the previous one: a manager keeping a second copy of its own reads that instead, one keeping none reads this before reporting a first run. null when there is no such copy. Throws IOException and UnauthorizedAccessException as Read does.
string GetAsidePath(string path)Where WriteAtomic parks the previous save while it stages the new one by hand. Nothing reads it, and a completed write removes it. A manager writing through WriteAtomic rather than Write deletes this alongside its own file when it clears storage, or a save it cleared stays readable beside it.
string GetStagedPath(string path, string uniqueId)Where a write stages before it is swapped in. A manager staging its own writes deletes this alongside its file when it clears storage: an interrupted write leaves it holding the whole payload.
bool IsReservedFileName(string fileName)Whether a name ends in one of the two above, which a save must not take: another manager writing the file it is named after would overwrite or delete it as a leftover of its own.
void Delete(SaveLocation, string relativeFilePath, string root = null, string extension = null, string uniqueId = null)Throws IOException when the file is in use by another process, and UnauthorizedAccessException when it is read-only or unpermitted. Delete a save file (silent if absent), with the copies a write can leave beside it: pass the writing manager's uniqueId so the staged copy of an interrupted write goes too.

CheatProtectionUtility

staticextending

Encrypt or hash save data with a key derived from the project secret (Project Settings > Persistent Asset > Security). Backs the FilePersistenceManager protection options, and the remote managers' payload and offline-cache protection. Explained in Extend the package.

static string RuntimeSecret { get; set; }Runtime secret mixed into the key for a SaveAnchor.RuntimeSecret anchor. The setter throws ArgumentException when set to null/empty, and InvalidOperationException when set a second time with a different value.
bool UsesRuntimeSecret(SaveAnchor anchorTo)Whether the anchor effectively requires the runtime secret (the editor can opt out).
byte[] Encrypt(byte[] data, SaveAnchor anchorTo, string location) / byte[] Decrypt(byte[], SaveAnchor, string)Encrypt/decrypt with an embedded integrity hash. Decrypt returns null when the integrity check fails (data modified, moved, or from another machine or project). Throws ArgumentNullException for null data, InvalidOperationException when the anchor needs an unset RuntimeSecret.
byte[] AppendSecuredHash(byte[], SaveAnchor, string, bool tampered = false) / bool CheckSecuredHash(byte[] dataWithHash, SaveAnchor, string, out byte[] originalData, out bool tampered)Append/verify a tamper-evident hash (data stays readable). tampered writes/reads the tampered-lineage mark, covered by the hash itself so editing it in or out reads as freshly tampered; originalData is extracted even when the check fails, so a caller can carry a tampered payload onward. A CheckSecuredHash overload without the out tampered also exists. Same throws as Encrypt / Decrypt.

GzipUtility

staticextending

Gzip compress and decompress byte data. Empty data compresses to empty and decompresses back to empty; anything else must be one whole gzip stream, so a truncated one is refused instead of inflating in part. Explained in Extend the package.

byte[] Compress(byte[] data, Compression compression) / Decompress(byte[] data, Compression compression)Compress/decompress per a Compression level (None passes through). Throws ArgumentNullException for null data; Decompress throws IOException on a corrupt or truncated gzip stream (Unity's Mono runtime, not InvalidDataException) and InvalidDataException past the size ceiling.
byte[] Compress(byte[] data, CompressionLevel compressionLevel = Optimal) / Decompress(byte[] data)Compress/decompress with a raw System.IO.Compression level. Throws ArgumentNullException for null data; Decompress throws IOException on a corrupt or truncated gzip stream (Unity's Mono runtime, not InvalidDataException) and InvalidDataException past the size ceiling.

TaskUtility

staticextending

Helpers for asynchronous manager code: thread hopping and cancellation. Explained in Extend the package.

ThreadType CurrentThreadType { get; }Whether the caller is on the main or a background thread.
Task SwitchToMainThread()Await to continue on the main thread.
Task StartNew(ThreadType, Action, CancellationToken = default, Action<AggregateException> = null) / Task<TResult> StartNew<TResult>(ThreadType, Func<TResult>, ...)Run work on the chosen thread as a task.
Task<T> WithCancellation<T>(Task<T>, CancellationToken) / Task WithCancellation(Task, CancellationToken)Make any task cancellable even when it ignores the token. Surfaces OperationCanceledException on cancel.
void Observe(Task task)Observe an abandoned task's eventual fault (avoids UnobservedTaskException).

SlotFormatUtility

staticextending

The "<slot>" placeholder handling and the reversible file-path slot codec the file-backed managers share. Explained in Extend the package.

const string Placeholder = "<slot>"The token a manager replaces with the current slot in a user path, key or address.
string GenerateName(string customValue, string slot, string defaultName, params char[] separators)Resolve a storage name: default under the slot, or the custom value with the slot placed/prepended.
bool Replace(ref string value, string replacement, params char[] separators)Replace every placeholder, returning whether any was found.
string EncodeForFilePath(string slot) / DecodeForFilePath(string encoded)Encode a slot into one safe, injective, reversible path segment (and back).
bool IsValidFilePath(string value, out string reason)Whether a relative file path is valid on every platform.

WebGLFileSync

staticextending

Flush the in-memory file system to IndexedDB on WebGL; call after writing or deleting save files. A no-op off WebGL. Explained in Extend the package.

void RequestSync()Flush pending file writes to persistent browser storage.

SaveNodeJson

staticextending

Reads JSON text into a SaveNode tree, to implement Serializer.ParseToNode in a JSON serializer (what lets save upgrades and field resets recover old values). Explained in Extend the package.

SaveNode Parse(string json)Parse JSON text into a tree, or null when it cannot be read (malformed, truncated, or nested past a safe depth). Never throws.

FieldSnapshot

staticextending

Copies every data field of an object and puts it back. Capture before deserializing into a target and restore if that fails, so a failed load leaves the target exactly as it was, as Serializer's deserialize half requires. The copy is shallow. Explained in Extend the package.

object[] Capture(object target)Capture the current value of every data field of the target. A field the runtime refuses to read is logged and left out, and Restore then leaves it as it finds it rather than writing a null over it. Never throws.
void Restore(object target, object[] values)Put back the values a Capture of the same object returned. Never throws.

ThreadType

enum
Main / BackgroundThe main thread (full Unity API) or a background thread (faster, most Unity API unavailable).

SaveLocation

enum
Default / Backup / LocalCacheSubfolders of the save root (Application.persistentDataPath in a build, the project's UserSettings/Persistent Asset folder in the editor, or the folder a call names): the save folder, the backup copy, and the remote managers' offline cache.