Concept: The Fragment Model
A save slot is not one file - it is a directory of fragments. Each registered system owns one fragment; the world subsystem owns per-level slabs; a header holds the slot's metadata. Nothing reads another system's fragment, which is what keeps plugins decoupled.
Glossary
| Concept | Description |
|---|---|
| Fragment | One .sav file per system per save slot. Written and read independently from all other systems. |
| Auto-serialization | Any UPROPERTY(SaveGame) field on the registered object is captured automatically via the engine's proxy archive - no custom fragment subclass needed. |
| Custom fragment | A UCrimsonSaveGameFragmentBase subclass for data auto-serialization can't hold (UObject references, GAS state, computed values). Runs alongside auto-serialization. |
| Global vs player-scoped | Global fragments are shared across all players (world state, game progress). Player-scoped fragments are keyed per-player and stored as FragmentName__PlayerKey.sav. |
| Save slot | A directory under Saved/SaveGames/<Slot>/ containing all fragment files, world slabs, and a header. One slot = one playthrough. |
| Header | A metadata .sav per slot for the save-menu UI - display name, date, play time, slot type, optional thumbnail. |
How a save runs
- Register - each system calls
RegisterSaveableSystemon startup and returns a uniqueGetFragmentName. - Gather - on save the manager captures every
SaveGameproperty into a blob and callsGatherSaveDatafor an optional custom fragment. Both run for every system. - Write - the manager writes the header, one
.savper fragment, and (withbIncludeWorldStateInMainSave) the world slabs. - Match - on load each fragment file is matched to its registered system by name.
- Restore - the manager deserializes the
SaveGameblob, then callsRestoreFromSaveDatafor anything the custom fragment holds.
GatherSaveData returning nullptr just means "nothing beyond my SaveGame fields." Start with SaveGame properties; add a custom fragment only for what they can't hold. See How-To: Custom Fragments & Versioning.Saves and loads are asynchronous
Loads complete through delegates, not synchronously. Gate "loaded" UI and screen transitions on OnLoadComplete, and rebuild slot lists on OnSaveSlotListChanged. The one synchronous entry point is SaveGameToActiveSlotSynchronous, used for save-on-exit. See How-To: Handle Save/Load Errors.
On-disk layout
Everything for a slot lives under Saved/SaveGames/<Slot>/: a header file, one FragmentName.sav per global fragment, FragmentName__PlayerKey.sav per player-scoped fragment, and WorldSlab_<Level>.sav per level touched.
| Slot kind | Index range | Notes |
|---|---|---|
| Manual | 0 and up | Named playthroughs; the only slots GetAllSaveSlotHeaders returns. |
| Auto-save | 10000-10009 | Rotating; oldest overwritten past MaxAutoSaves. |
| Quick-save | 10100-10109 | Rotating; oldest overwritten past MaxQuickSaves. |
bIncludeWorldStateInMainSave (default), a single RequestSaveProgress persists both registered systems (fragments) and world actors (slabs), and loading a slot restores both. See Concept: World State & Identity.