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.

FunctionReturnsDescription
GetFragmentName()FStringRequired. Unique fragment file name within the slot. Must be unique across all registered systems.
GetSaveScope() / GetProfileId()FStringWorld (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)voidOptional. Called after SaveGame properties are deserialized. Fragment is const and never null.
OnPreSave() / OnPostSave()voidBefore GatherSaveData / after all fragments are written.
OnPreRestore() / OnPostRestore()voidBefore / after RestoreFromSaveData.

ICrimsonSaveableActor - implement on a level actor to persist it. Note actors use an FInstancedStruct payload, whereas systems use a UCrimsonSaveGameFragmentBase.

FunctionReturnsDescription
GatherActorSaveData()FInstancedStructOptional custom payload beyond auto-captured state. Empty (default) = auto-capture only.
RestoreFromSaveData(ActorData)voidReceives the FInstancedStruct. Transform, SaveGame fields, and component state are already restored.
OnPreRestoreState() / OnPostRestoreState()voidLifecycle hooks around restoration.
ShouldRespawnAfterDestroyed()boolDefault 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).

FunctionDescription
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

Server / Standalone Only
All save operations are authority-guarded; calls on NM_Client are rejected. See Concept: Multiplayer & Save Scopes.
FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

FunctionDescription
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

DelegateSignatureWhen fired
OnLoadCompletebool bSuccessAfter 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.
OnSaveCompletebool bSuccessA 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.
OnSaveErrorFString SlotName, FString FragmentNamePer fragment that fails to save; the operation continues.
OnLoadErrorFString SlotName, FString FragmentNamePer fragment that fails to load; other fragments continue.

World Manager Subsystem

UCrimsonSaveWorldManagerSubsystem (UWorldSubsystem). Discovers ICrimsonSaveableActor actors, manages per-level slabs, handles streaming. Server-authoritative.

FunctionDescription
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.

FunctionDescription
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.

FunctionReturnsDescription
InitializeStorage()boolCalled 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()voidCalled when the owning manager is torn down.
WriteBlob(BlobId, Data)boolRequired. Write Data under BlobId, overwriting. May run on a background thread.
ReadBlob(BlobId, OutData)boolRequired. Read BlobId. false if absent or unreadable. May run on a background thread.
DeleteBlob(BlobId)boolRequired. Remove BlobId. Returning true for a blob that did not exist is correct.
BlobExists(BlobId)boolRequired. Whether BlobId currently exists.
EnumerateBlobs(SlotId, OutBlobs)boolRequired. 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)boolAppend 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)boolDelete every blob for a slot. Default enumerates and deletes one by one; override for an atomic drop.
WriteBlobAsync(BlobId, Data, Callback)voidDefault runs WriteBlob on a background thread and fires Callback on the game thread. Override only for a native async backend.
ReadBlobAsync(BlobId, Callback)voidDefault runs ReadBlob on a background thread and fires Callback on the game thread.
Threading contract
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:

TypeDescription
UCrimsonPlatformSaveStorageProviderDefault. 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.
UCrimsonFileSaveStorageProviderWrites plain files under CustomSaveDirectory, with {SavedDir} / {UserDir} / {Project} token expansion (ResolveDirectoryTokens is a public static). GetRootDirectory() returns the resolved path. Bypasses ISaveGameSystem; PC-oriented.
TypeKindDescription
FCrimsonSaveBlobIdUSTRUCTAddresses 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.
FCrimsonSaveSlotIdUSTRUCTA slot as Kind + Number - the decoded form of the public int32 slot index. FCrimsonSaveSlotId::Global() addresses non-slot data. Convert with UCrimsonSaveGameManagerSubsystem::MakeSlotId / SlotIdToIndex.
ECrimsonSaveSlotKindUENUMManual, AutoSave, QuickSave, Global.
ECrimsonSaveBlobKindUENUMHeader, Fragment, WorldSlab, UserSettings.

Data types

TypeKindDescription
UCrimsonSaveGameFragmentBaseUSaveGame (Blueprintable)Base for custom save data. Holds FragmentVersion and the auto-serialized properties blob. Overridable: GetCurrentVersion, UpgradeFromVersion.
UCrimsonSaveGameHeaderUSaveGame (BlueprintType)Per-slot metadata: DisplayName, SlotType, SaveDateTime, PlayTime, ThumbnailData. Overridable OnHeaderUpdate. Subclass via SaveGameHeaderClass.
FCrimsonSaveWorldActorDataUSTRUCT (BlueprintType)Per-actor slab entry: transform, actor / component SaveGame blobs, object refs, non-property state, custom FInstancedStruct, destroyed / runtime flags.
UCrimsonSaveWorldDataUSaveGameOne per-level slab. TMap<FGuid, FCrimsonSaveWorldActorData>. Managed internally.
UCrimsonSaveProfileIdentityUBlueprintFunctionLibraryResolveProfileId(PC) - the player's stable profile GUID, or an invalid GUID when it is not yet known.
ECrimsonSaveSlotTypeUENUM (BlueprintType)Manual / AutoSave / QuickSave.
ECrimsonSaveSessionModeUENUM (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.

TypeKindDescription
UCrimsonSaveProfileIdentityUBlueprintFunctionLibraryResolveProfileId(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".
UCrimsonSaveProfileIdentityComponentUActorComponentLives 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_AddSaveProfileIdentityUCrimsonSaveSystemGameFeatureAction_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

TypeKindDescription
UCrimsonPersistentIdComponentUActorComponentBakes 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.

FunctionDescription
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.
FCrimsonSaveCleanupReportLiveRows, 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.

MemberTypeDefaultDescription
UCrimsonSaveSystemEditorSettings::bEnableSaveGameDeleterbooltrueProject 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.
ClassFunctionDescription
FCrimsonSaveGameDeleteUtilityHasPlayWorld() / HasNoPlayWorld()PIE-session checks used to gate the Delete Save Game button.
FCrimsonSaveGameDeleteUtilityGetSaveFilesDropdown()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.
FCrimsonSaveGameDeleteUtilityDeleteSaveFileAbsolute_Clicked(AbsolutePath)Deletes a single .sav file by absolute path, after a confirmation dialog.
FCrimsonSaveGameDeleteUtilityDeleteFileGroup_Clicked(GroupDisplayName, AbsolutePaths)Deletes every file in one group, such as all blobs belonging to a save slot.
FCrimsonSaveGameDeleteUtilityDeleteDirectoryAbsolute_Clicked(AbsolutePath)Deletes a whole save directory by absolute path.
ICrimsonFileGroupProviderGetDomain() / 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.
FCrimsonFileGroupRegistryGet() / 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.
FCrimsonFileGroupDisplayName, FilePathsOne 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

SettingDefaultDescription
DefaultPIESaveSlot0Slot index automatically activated when playing in the editor.
DefaultPIECharacterNameEditorCharacterCharacter name used when creating a new PIE debug save.
bResetPIESaveSlotOnStartfalseDelete 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

SettingDefaultDescription
SessionModeAutoDetectAutoDetect reads GetNetMode() at runtime. Override only when your topology doesn't match UE's net mode.
DedicatedServerDefaultSlot0Slot the dedicated server loads on startup. Override with -CrimsonSaveSlot=N.

Multiplayer automation

SettingDefaultDescription
bAutoLoadOnPostLogintrueNotifyPlayerLoggedIn auto-calls LoadFragmentsForProfile. Disable for manual timing.
bAutoSaveOnLogouttrueNotifyPlayerLoggedOut synchronously flushes the player's fragments. Disable for manual timing.
bAutoSaveOnExittrueYour game mode synchronously saves the active slot on shutdown, so "change then quit" persists. Honor it via SaveGameToActiveSlotSynchronous() in EndPlay.

Rotating saves

SettingDefaultDescription
MaxAutoSaves3Rotating auto-save slots (10000-10009). Oldest overwritten at the limit.
MaxQuickSaves3Rotating quick-save slots (10100-10109). Oldest overwritten at the limit.

World state

SettingDefaultDescription
bAutoCaptureActorsOnSavetrueEvery save (and streaming-level unload) scans loaded levels for ICrimsonSaveableActor and captures them. This is what makes implementing the interface enough.
bIncludeWorldStateInMainSavetrueRequestSaveProgress / auto / quick / new-game saves also flush world actor state - one call saves everything.
bAutoLoadWorldStatetrueApply world slabs automatically when a load completes. False = call LoadWorldState() yourself.
WorldStateFlushIntervalSeconds0 (off)Seconds between automatic flushes of changed world actors. Writes one blob per changed actor and never scans the world. Server-authority only.
bResolveCrossObjectReferencestrueStore SaveGame actor-pointer properties as GUIDs and re-resolve them after load.

Storage

SettingDefaultDescription
StorageProviderClassUCrimsonPlatformSaveStorageProviderDecides 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

SettingDefaultDescription
SaveGameHeaderClass(empty = UCrimsonSaveGameHeader)Subclass to add custom slot metadata (chapter, portrait, difficulty). Set your subclass here.
bVerboseLoggingfalseLogs 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.

TypeKindDescription
ACrimsonPersistentActorAActor (Blueprintable)Ready-made base that implements ICrimsonSaveableActor. Derive, mark properties SaveGame, done.
ACrimsonPlayerStateAPlayerStateImplements ICrimsonSaveableSystem; saves stat tags + squad id as a player-scoped fragment. Extend via GatherPlayerSaveData / RestorePlayerSaveData.
UCrimsonPlayerStateSaveFragmentUCrimsonSaveGameFragmentBaseThe player-state fragment payload. Subclass to persist additional per-player data.
ACrimsonGameModeAGameModeBaseForwards login / logout and saves on exit automatically.