API Reference
The complete lookup surface. All interface methods are BlueprintNativeEvent (overridable in C++ via _Implementation and in Blueprint) unless noted. Subsystem functions are BlueprintCallable unless marked C++-only.
Interfaces
ICrimsonSaveableSystem - implement on any UObject (subsystem, component, or plain object) to make it a saveable system; register with the manager.
| Function | Returns | Description |
|---|
GetFragmentName() | FString | Required. Unique fragment file name within the slot. Must be unique across all registered systems. |
GetSaveScope() / GetProfileId() | FString | World (default), Player, or Profile. For the latter two, return UCrimsonSaveProfileIdentity::ResolveProfileId(PC) from GetProfileId(). An invalid GUID means "not known yet" and delivery waits - it never falls back to a shared fragment. |
GatherSaveData() | UCrimsonSaveGameFragmentBase* | Optional. Return a custom fragment, or nullptr to rely on SaveGame auto-serialization. Both run together. |
RestoreFromSaveData(Fragment) | void | Optional. Called after SaveGame properties are deserialized. Fragment is const and never null. |
OnPreSave() / OnPostSave() | void | Before GatherSaveData / after all fragments are written. |
OnPreRestore() / OnPostRestore() | void | Before / after RestoreFromSaveData. |
ICrimsonSaveableActor - implement on a level actor to persist it. Note actors use an FInstancedStruct payload, whereas systems use a UCrimsonSaveGameFragmentBase.
| Function | Returns | Description |
|---|
GatherActorSaveData() | FInstancedStruct | Optional custom payload beyond auto-captured state. Empty (default) = auto-capture only. |
RestoreFromSaveData(ActorData) | void | Receives the FInstancedStruct. Transform, SaveGame fields, and component state are already restored. |
OnPreRestoreState() / OnPostRestoreState() | void | Lifecycle hooks around restoration. |
ShouldRespawnAfterDestroyed() | bool | Default false. Return true so a destroyed placed actor respawns from the level. Runtime actors ignore it. |
Save Manager Subsystem - Registration
UCrimsonSaveGameManagerSubsystem (UGameInstanceSubsystem). Access via UCrimsonSaveGameManagerSubsystem::Get(WorldContextObject).
| Function | Description |
|---|
RegisterSaveableSystem(System) | Registers a saveable system. Call from BeginPlay or Initialize. If a matching fragment is already cached (loaded before the system started), it is delivered immediately. |
UnregisterSaveableSystem(System) | Call from EndPlay or Deinitialize. Safe at any time. |
GetStorageProvider() | The active UCrimsonSaveStorageProvider. Never null after Initialize - falls back to the platform provider if the configured class is unset or fails. See Concept: Where Saves Are Stored. |
Save Manager Subsystem - Save operations
All save operations are authority-guarded; calls on NM_Client are rejected. See Concept: Multiplayer & Save Scopes.
| Function | Description |
|---|
RequestNewGameSave(SlotIndex, CharacterName, OutError) | Creates a new slot directory, writes the header, and saves all registered fragments. Returns false if the slot exists or the name is empty. |
RequestSaveProgress() | Saves all registered fragments to the active slot. No-op if no slot is active. |
RequestAutoSave(DisplayName) | Saves to a rotating auto-save slot (10000-10009). Oldest overwritten past MaxAutoSaves. |
RequestQuickSave(DisplayName) | Saves to a rotating quick-save slot (10100-10109). Oldest overwritten past MaxQuickSaves. |
RequestSaveSpecificFragment(System) | Saves a single system's fragment without requiring an active slot. Useful for user preferences that save independently of game progress. |
SaveGameToActiveSlotSynchronous() | Synchronous save of systems + world actors, safe during shutdown / PIE-end. Used by the save-on-exit path. |
Save Manager Subsystem - Load operations
| Function | Description |
|---|
RequestLoadFromSlot(SlotIndex) | Loads the header and all fragment files from the slot. Each fragment is matched to its registered system and RestoreFromSaveData is called. Fires OnLoadComplete. |
LoadFragmentsForProfile(ProfileId) | Loads only fragments matching PlayerSaveKey from the active slot. Call from PostLogin for players joining a running session. |
RequestSaveProfileFragments(ProfileId) | Synchronously flushes all fragments belonging to PlayerSaveKey. Call from Logout before the player's objects are destroyed. |
Save Manager Subsystem - Slots
| Function | Description |
|---|
RequestDeleteSlot(SlotIndex) | Deletes all files in the slot directory. Irreversible. |
GetActiveSaveHeader() | The UCrimsonSaveGameHeader for the active slot, or nullptr. |
GetAllSaveSlotHeaders() | Headers for all manual (non-auto/quick) slots. Populate a slot-selection UI with this. |
GetRotatingSaveSlotIndices(SlotType) | Slot indices of the auto-save or quick-save range that hold a save (Manual returns the manual slots). Pass each to GetSaveSlotHeader or RequestLoadFromSlot. |
GetSlotNameByIndex(SlotIndex) | The on-disk directory name for a slot index. |
SetActiveSaveSlot(SlotIndex) / GetActiveSaveSlot() | Set / get the current gameplay slot index. GetActiveSaveSlot returns -1 if none. |
Save Manager Subsystem - Session hooks
| Function | Description |
|---|
NotifyPlayerLoggedIn(PlayerController) | Call from PostLogin. Resolves the player's save key; if bAutoLoadOnPostLogin, loads their player-scoped fragments. |
NotifyPlayerLoggedOut(PlayerController) | Call from Logout before Super::Logout. If bAutoSaveOnLogout, synchronously flushes the player's fragments. |
Save Manager Subsystem - Playtime & user prefs
| Function | Description |
|---|
StartNewPlaytimeSession() | Reset the playtime clock; call after creating a new slot. |
LoadPlaytimeFromHeader(PlayTime) | Seed the clock from a loaded header's accumulated play time. |
GetCurrentTotalPlayTime() | Current total play time; flushed to the header on save. |
GetLastSelectedSaveSlot() / SetLastSelectedSaveSlot(Index) | Per-user preference persisted outside any gameplay slot. |
ShouldAutoLoadLastSave() / SetShouldAutoLoadLastSave(bool) | Per-user "continue" preference. |
HasLoadedFragment(CacheKey) | True if a fragment for CacheKey is already in the load cache. |
IsSaveOrLoadInProgress() | True between any save/load start and its matching complete. Complements the OnSaveStarted/OnLoadStarted events for polling (e.g. gating a Quit button). |
Save Manager Subsystem - Delegates
| Delegate | Signature | When fired |
|---|
OnLoadComplete | bool bSuccess | After a full load. bSuccess is false if any critical file was missing. |
OnLoadStarted | (none) | A load begins, before any fragment is read. Pairs with OnLoadComplete. |
OnSaveStarted | (none) | A save begins, before any fragment is written. |
OnSaveComplete | bool bSuccess | A save finishes. bSuccess is false if any fragment failed. |
OnSaveSlotListChanged | (none) | After a slot is created or deleted - rebind slot-list UI here. |
ClearActiveSaveData | (none) | On return to main menu / new game - clear in-memory state. |
OnSaveError | FString SlotName, FString FragmentName | Per fragment that fails to save; the operation continues. |
OnLoadError | FString SlotName, FString FragmentName | Per fragment that fails to load; other fragments continue. |
World Manager Subsystem
UCrimsonSaveWorldManagerSubsystem (UWorldSubsystem). Discovers ICrimsonSaveableActor actors, manages per-level slabs, handles streaming. Server-authoritative.
| Function | Description |
|---|
SaveWorldState() | Captures every saveable actor in every loaded level, then writes them all out. The thorough call; use FlushDirtyWorldState() when you only need what changed. |
LoadWorldState() | Apply slabs, re-spawn runtime actors, resolve cross-object references. |
OnActorStateChanged(Actor) | Records one actor's state into its level and marks it dirty. Does not write to disk - follow with FlushDirtyWorldState() for a checkpoint. Optional: the capture-on-save path already covers every saveable actor. |
OnActorDestroyed(Actor) | Optional manual destruction hook. Destruction is auto-detected on the server. |
FlushDirtyWorldState() | Writes only the actors that changed since the last flush, one blob each, and clears the marks. Does not scan the world - the cost follows what changed, not what exists. Use for checkpoints; WorldStateFlushIntervalSeconds calls it on a timer. Server-authority only. |
MakeStableActorPath(Actor) | The actor's authored object path, normalized so a World Partition cell name never appears in it. The identity fallback for an actor with no persistent id, and what save-data tooling uses to derive the same key the subsystem writes. |
Save Facade (Blueprint helper)
UCrimsonSaveFacade (UBlueprintFunctionLibrary) - a one-call surface over the save manager for save-menu UI. Every call resolves the manager from the world context.
| Function | Description |
|---|
StartNewGame(Slot, CharacterName) | Create a fresh save and make it the active slot. |
SaveGame() | Save systems + world actors to the active slot. Returns false (and logs) if no slot is active. |
QuickSave(DisplayName) / AutoSave(DisplayName) | Write a rotating quick / auto snapshot without changing the active slot. |
LoadGame(Slot) | Load a slot; world state restores automatically. |
GetSaveSlots() | Headers for every manual slot - populate a load / continue menu. |
DeleteSlot(Slot) | Delete all files for a slot. Irreversible. |
HasActiveSaveSlot() | True if a game has been started or loaded. |
Storage providers
UCrimsonSaveStorageProvider (UObject, abstract) decides where save bytes physically live. Select the class in Project Settings -> Crimson -> Crimson Save Game Manager -> Storage Provider Class; reach the live instance with UCrimsonSaveGameManagerSubsystem::GetStorageProvider(). C++ only - see How-To: Change Where Saves Are Stored for why, and Concept: Where Saves Are Stored for the model.
| Function | Returns | Description |
|---|
InitializeStorage() | bool | Called once on the game thread before any blob access. Return false to reject the provider; the manager falls back to the platform provider. Default returns true. |
ShutdownStorage() | void | Called when the owning manager is torn down. |
WriteBlob(BlobId, Data) | bool | Required. Write Data under BlobId, overwriting. May run on a background thread. |
ReadBlob(BlobId, OutData) | bool | Required. Read BlobId. false if absent or unreadable. May run on a background thread. |
DeleteBlob(BlobId) | bool | Required. Remove BlobId. Returning true for a blob that did not exist is correct. |
BlobExists(BlobId) | bool | Required. Whether BlobId currently exists. |
EnumerateBlobs(SlotId, OutBlobs) | bool | Required. Append every blob stored for SlotId, fully populated so Name, Scope and ProfileId all round-trip. This is how the manager discovers a slot's contents. |
EnumerateSlots(Kind, OutSlotNumbers) | bool | Append the number of every slot of Kind holding data. Default probes each slot for a header up to MaxSlotsToProbe (64); override to answer from one listing. |
DeleteSlot(SlotId) | bool | Delete every blob for a slot. Default enumerates and deletes one by one; override for an atomic drop. |
WriteBlobAsync(BlobId, Data, Callback) | void | Default runs WriteBlob on a background thread and fires Callback on the game thread. Override only for a native async backend. |
ReadBlobAsync(BlobId, Callback) | void | Default runs ReadBlob on a background thread and fires Callback on the game thread. |
The synchronous functions may be called from a background thread. Do not touch UObjects, the world, or any non-thread-safe engine subsystem inside them. Any override of the async functions must fire its delegate on the game thread.
Shipped implementations:
| Type | Description |
|---|
UCrimsonPlatformSaveStorageProvider | Default. Routes through the engine's ISaveGameSystem - the platform's own save system, correct on PC and console. Uses the platform's native async path where implemented. SetUserIndex(int32) / GetUserIndex() select which local user's storage to use (default 0). BlobIdToStorageName / StorageNameToBlobId / CollectSlotNumbers are public statics you can reuse. |
UCrimsonFileSaveStorageProvider | Writes plain files under CustomSaveDirectory, with {SavedDir} / {UserDir} / {Project} token expansion (ResolveDirectoryTokens is a public static). GetRootDirectory() returns the resolved path. Bypasses ISaveGameSystem; PC-oriented. |
| Type | Kind | Description |
|---|
FCrimsonSaveBlobId | USTRUCT | Addresses one stored blob: Slot, BlobKind, Scope, Name, ProfileId. Builders: MakeHeader, MakeWorldFragment, MakePlayerFragment, MakeProfileFragment, MakeWorldSlab, MakeUserSettings, MakeLocalProfiles. Helpers: IsValid(), IsProfileScoped(), ToCacheKey(), ToString(). Build these with the factories - they are what makes an unaddressable combination impossible to express by accident. |
FCrimsonSaveSlotId | USTRUCT | A slot as Kind + Number - the decoded form of the public int32 slot index. FCrimsonSaveSlotId::Global() addresses non-slot data. Convert with UCrimsonSaveGameManagerSubsystem::MakeSlotId / SlotIdToIndex. |
ECrimsonSaveSlotKind | UENUM | Manual, AutoSave, QuickSave, Global. |
ECrimsonSaveBlobKind | UENUM | Header, Fragment, WorldSlab, UserSettings. |
Data types
| Type | Kind | Description |
|---|
UCrimsonSaveGameFragmentBase | USaveGame (Blueprintable) | Base for custom save data. Holds FragmentVersion and the auto-serialized properties blob. Overridable: GetCurrentVersion, UpgradeFromVersion. |
UCrimsonSaveGameHeader | USaveGame (BlueprintType) | Per-slot metadata: DisplayName, SlotType, SaveDateTime, PlayTime, ThumbnailData. Overridable OnHeaderUpdate. Subclass via SaveGameHeaderClass. |
FCrimsonSaveWorldActorData | USTRUCT (BlueprintType) | Per-actor slab entry: transform, actor / component SaveGame blobs, object refs, non-property state, custom FInstancedStruct, destroyed / runtime flags. |
UCrimsonSaveWorldData | USaveGame | One per-level slab. TMap<FGuid, FCrimsonSaveWorldActorData>. Managed internally. |
UCrimsonSaveProfileIdentity | UBlueprintFunctionLibrary | ResolveProfileId(PC) - the player's stable profile GUID, or an invalid GUID when it is not yet known. |
ECrimsonSaveSlotType | UENUM (BlueprintType) | Manual / AutoSave / QuickSave. |
ECrimsonSaveSessionMode | UENUM (BlueprintType) | AutoDetect / SinglePlayer / ListenServer / DedicatedServer - controls save-authority logic. |
Player identity
How the system decides which save a given player's fragments belong to. Only the owning client can answer that, so the answer is reported to the server rather than derived there - see Multiplayer & Save Scopes.
| Type | Kind | Description |
|---|
UCrimsonSaveProfileIdentity | UBlueprintFunctionLibrary | ResolveProfileId(PC) is the one way to ask who a controller belongs to: what the owning client reported, else local resolution for a local controller, else an invalid GUID. An invalid GUID means "ask later", never "use the shared copy". |
UCrimsonSaveProfileIdentityComponent | UActorComponent | Lives on a player controller. The owning client resolves its own profile id and reports it to the server once. Find(PC) returns the most-derived one on that controller; a less specific duplicate logs a warning and stands down rather than reporting a second answer. Subclass and override ResolveIdToReport() to narrow identity further (per character, say). |
UCrimsonGameFeatureAction_AddSaveProfileIdentity | UCrimsonSaveSystemGameFeatureAction_WorldActionBase | "Add Crimson Save Profile Identity" - the supported way to attach that component. One IdentityList entry (FCrimsonSaveProfileIdentityEntry) per controller class: ActorClass (any APlayerController subclass) and IdentityComponentClass (the base for one save per account, a subclass to narrow it). Controllers that are ModularGameplay component receivers get the component through a UGameFrameworkComponentManager request on client and server; any other controller gets it from the server at PostLogin (and at activation for players already connected), replicated to the owning client. A controller that already carries the component is skipped. Prefer this over a native subobject so the choice stays per experience. |
Actor identity
| Type | Kind | Description |
|---|
UCrimsonPersistentIdComponent | UActorComponent | Bakes the actor's engine-assigned ActorGuid into the level so it survives the cook - the engine's own copy is editor-only. Add it to any saveable actor; ACrimsonPersistentActor has one already. GetPersistentId() reads it, FindPersistentId(Actor) is the static lookup. The id fills in when the level is saved in the editor, and is cleared and refilled on duplication so a copy is its own actor. |
Save data maintenance (editor)
UCrimsonSaveCleanupStatics removes stored actor state whose actor no longer exists. Editor-only by necessity: at runtime, "no actor matches this row" nearly always means the level or cell simply is not streamed in, so a runtime sweep would erase the state of everything the player is not standing next to.
| Function | Description |
|---|
CleanOrphanedWorldRows(SlotIndex, bDeleteOrphans) | Scans a slot's stored actor state against the actors its levels actually contain. Defaults to a dry run - pass true only after reading the report. For a partitioned world it enumerates actor descriptors, so it sees every actor without streaming a cell. A level missing from the project is reported, never auto-deleted. |
FCrimsonSaveCleanupReport | LiveRows, OrphanedRows, DeletedRows, ActorsWithoutBakedId (saveable actors relying on the path fallback), UnresolvedLevels, and a Details line per finding. |
Editor tools (CrimsonSaveSystemEditor)
C++-only editor helpers in the CrimsonSaveSystemEditor module. They are static, driven by the Level Editor play toolbar, and not Blueprint-exposed. See How-To: Delete Save Files in the Editor.
| Member | Type | Default | Description |
|---|
UCrimsonSaveSystemEditorSettings::bEnableSaveGameDeleter | bool | true | Project Settings -> Crimson -> Crimson Save System Editor -> Utilities. Registers the Delete Save Game toolbar button. Read when the toolbar is built, so a change needs an editor restart. Stored in Config/DefaultEditor.ini. |
| Class | Function | Description |
|---|
FCrimsonSaveGameDeleteUtility | HasPlayWorld() / HasNoPlayWorld() | PIE-session checks used to gate the Delete Save Game button. |
FCrimsonSaveGameDeleteUtility | GetSaveFilesDropdown() | Builds the hierarchical toolbar dropdown: slot groups with their blobs when a file-group provider is registered for the SaveGames domain, plus the raw save directories. |
FCrimsonSaveGameDeleteUtility | DeleteSaveFileAbsolute_Clicked(AbsolutePath) | Deletes a single .sav file by absolute path, after a confirmation dialog. |
FCrimsonSaveGameDeleteUtility | DeleteFileGroup_Clicked(GroupDisplayName, AbsolutePaths) | Deletes every file in one group, such as all blobs belonging to a save slot. |
FCrimsonSaveGameDeleteUtility | DeleteDirectoryAbsolute_Clicked(AbsolutePath) | Deletes a whole save directory by absolute path. |
ICrimsonFileGroupProvider | GetDomain() / GetRootDirectories(OutDirectories) / GroupFiles(AbsoluteFilePaths, OutGroups) | Teaches an editor browse tool where a domain's files live and how they group. GroupFiles must place every input path in some group, or return false to fall back to the tool's default behavior. |
FCrimsonFileGroupRegistry | Get() / Register(Provider) / Unregister(Domain) / FindProvider(Domain) | Singleton registry of providers, one per domain; registering a second provider for a domain replaces the first. The editor module registers this plugin's own provider under SaveGames, which groups blobs by slot and reads the directory the configured storage provider writes to. |
FCrimsonFileGroup | DisplayName, FilePaths | One display group: the section header (e.g. Slot 0) and the absolute paths in it. |
Developer Settings
Project Settings -> Crimson -> Crimson Save Game Manager (UCrimsonSaveGameManagerDeveloperSettings, stored in Config/DefaultGame.ini).
PIE
| Setting | Default | Description |
|---|
DefaultPIESaveSlot | 0 | Slot index automatically activated when playing in the editor. |
DefaultPIECharacterName | EditorCharacter | Character name used when creating a new PIE debug save. |
bResetPIESaveSlotOnStart | false | Delete and recreate the PIE slot on every PIE start - clean state each play. |
MainMenuMap | (empty) | A map that starts PIE without forcing a save load - lets the main menu work in PIE. |
Session mode
| Setting | Default | Description |
|---|
SessionMode | AutoDetect | AutoDetect reads GetNetMode() at runtime. Override only when your topology doesn't match UE's net mode. |
DedicatedServerDefaultSlot | 0 | Slot the dedicated server loads on startup. Override with -CrimsonSaveSlot=N. |
Multiplayer automation
| Setting | Default | Description |
|---|
bAutoLoadOnPostLogin | true | NotifyPlayerLoggedIn auto-calls LoadFragmentsForProfile. Disable for manual timing. |
bAutoSaveOnLogout | true | NotifyPlayerLoggedOut synchronously flushes the player's fragments. Disable for manual timing. |
bAutoSaveOnExit | true | Your game mode synchronously saves the active slot on shutdown, so "change then quit" persists. Honor it via SaveGameToActiveSlotSynchronous() in EndPlay. |
Rotating saves
| Setting | Default | Description |
|---|
MaxAutoSaves | 3 | Rotating auto-save slots (10000-10009). Oldest overwritten at the limit. |
MaxQuickSaves | 3 | Rotating quick-save slots (10100-10109). Oldest overwritten at the limit. |
World state
| Setting | Default | Description |
|---|
bAutoCaptureActorsOnSave | true | Every save (and streaming-level unload) scans loaded levels for ICrimsonSaveableActor and captures them. This is what makes implementing the interface enough. |
bIncludeWorldStateInMainSave | true | RequestSaveProgress / auto / quick / new-game saves also flush world actor state - one call saves everything. |
bAutoLoadWorldState | true | Apply world slabs automatically when a load completes. False = call LoadWorldState() yourself. |
WorldStateFlushIntervalSeconds | 0 (off) | Seconds between automatic flushes of changed world actors. Writes one blob per changed actor and never scans the world. Server-authority only. |
bResolveCrossObjectReferences | true | Store SaveGame actor-pointer properties as GUIDs and re-resolve them after load. |
Storage
| Setting | Default | Description |
|---|
StorageProviderClass | UCrimsonPlatformSaveStorageProvider | Decides where save bytes physically go. The default routes through the engine's ISaveGameSystem and is correct on PC and console. See How-To: Change Where Saves Are Stored. |
CustomSaveDirectory | (empty) | Directory used by UCrimsonFileSaveStorageProvider; ignored by every other provider. Absolute path, expands {SavedDir} / {UserDir} / {Project}. Empty means {SavedDir}SaveGames. |
Header & logging
| Setting | Default | Description |
|---|
SaveGameHeaderClass | (empty = UCrimsonSaveGameHeader) | Subclass to add custom slot metadata (chapter, portrait, difficulty). Set your subclass here. |
bVerboseLogging | false | Logs per-fragment save/load, registration, slab paging, cache delivery. Enable during integration. |
CrimsonCore integration types
Listed for orientation only - these ship in the CrimsonCore plugin, not in CrimsonSaveSystem. (CrimsonCore - requires all Crimson plugins.) CrimsonCore is free to download, but compiles only with all Crimson plugins installed, so you cannot reference these types from a project that owns CrimsonSaveSystem alone. The self-built equivalents are in Quick Start: Saveable Systems, How-To: Persist a Level Actor, and How-To: Build a Save/Load Menu.
| Type | Kind | Description |
|---|
ACrimsonPersistentActor | AActor (Blueprintable) | Ready-made base that implements ICrimsonSaveableActor. Derive, mark properties SaveGame, done. |
ACrimsonPlayerState | APlayerState | Implements ICrimsonSaveableSystem; saves stat tags + squad id as a player-scoped fragment. Extend via GatherPlayerSaveData / RestorePlayerSaveData. |
UCrimsonPlayerStateSaveFragment | UCrimsonSaveGameFragmentBase | The player-state fragment payload. Subclass to persist additional per-player data. |
ACrimsonGameMode | AGameModeBase | Forwards login / logout and saves on exit automatically. |