22. Save and load
In short: the whole game state (party, inventory, story, quests, world, time and more) is saved in slots, from save points in the world, from a consumable save item that works almost anywhere, and by autosave at save points and zone changes. Saving is never allowed in battle, dialog or cutscenes. Every system saves itself as a named section, so adding your own state is one registration line.
22.1 Basics
22.1.1 What the player gets
- Save points in the world: interact, the slot screen opens, pick a slot.
- A consumable save item: use it from the party menu to save anywhere, except in battle, dialog, cutscenes and zones you mark as no-save (for example before a boss).
- Autosave at every save point and when arriving on another map, in rotating autosave slots that manual saves can never overwrite.
- Continue and Load in the main menu, with a slot screen that shows a thumbnail, zone, party with levels, play time, money and date.
- Damaged saves are recovered from a backup automatically.
There is no saving or suspending during a battle: the state of a fight is never serialized.
22.1.2 Your first save point
- In your level, place a Save Point actor (Place Actors → search "Save Point", class
ARSESavePoint). - Give it a unique Save Point Id (for example
Inn_Hearth). Move its Player Spawn where the player should stand when loading from it. - Optionally set its Mesh and Interact Radius.
- Play, walk up and interact. The save screen opens.
Save screens, Continue and Load in the main menu need nothing else: they are built in.
22.1.3 A no-save zone
- Place a No Save Volume actor (class
ARSENoSaveVolume) around the area, for example the corridor before a boss. - While the player is inside, the consumable item is blocked and the save screen says why. Save points still work (the block's scope is Consumable Item Only).
For an area name shown on the slot screen, place an Area Volume actor (class ARSEAreaVolume; the higher priority wins where volumes overlap).
22.1.4 A save item
Create the item as a Save Item data asset (URSESaveItemData, a consumable without a use ability that is never usable in battle). Give it to the player like any item. Using it opens the slot screen; the item leaves the inventory only after a successful save.
22.2 How it works
22.2.1 The principle
The save system knows no gameplay system. Each system that keeps state registers a participant and writes its own section: an id, a version and bytes. The save file is a header (Info: slot, timestamp, play time, request source, location, party summary, money, a JPEG thumbnail) plus a list of opaque sections. Only fields marked UPROPERTY(SaveGame) are saved, with tagged properties, so a field added after a save loads with its default and a removed field is ignored. References to content are written as text and stay stable between versions.
The sections the plugin saves include:
| Section | What it holds |
|---|---|
Party | members (recruitment, departures, guests), inventory with key items and documents, equipment, vitals (HP, MP and any persistent resource, KO), progression, formation |
Narrative | story flags and variables, solved puzzles, unlocked zones, seen events and scenes, one-shot interactions, discoveries |
Rules | the active rules profile id |
Quests, Cards, Dialog, Difficulty | quest status and steps, card collection, read lines and seen dialogs, adaptive intelligence per mode and recent battles |
World | encounter triggers, random areas, visible enemy spawners, locks, chests, traps, interactables, data layers, interior visits (keyed by stable State Keys) |
Audio, Tutorials, Bestiary, Time, NPCs, Seeds, PartyControl, Map | story music override, seen tutorials, met enemies, clock and weather, story changes of NPC days, random seeds, who controls whom in the field, fog of war and pins |
Intentionally not saved: a battle in progress, the dialog runner, a scene in progress, save blocks, travel in progress, zone music, the current zone banner, character looks and animation state (rebuilt from data), and the player's options (volume, language, text speed, UI style, controls), which belong to the user in GameUserSettings.ini. Session-only sections (such as session rules and stealth state) replicate in co-op but never go in files.
22.2.2 Save rules
Blocking is a registry of reasons, counted so overlapping zones stack. The built-in reasons are Battle, Dialog, Cutscene (all scope) and NoSaveZone (consumable only). Check with Can Save Now, which also returns the reasons. A save is refused with Blocked when a reason applies.
Autosave: Autosave Slot Count slots rotate (Autosave, Autosave1...): the first empty one, else the oldest (a damaged slot is replaced first). Autosave runs at every save point and on arrival at a map through travel, after Zone Autosave Delay, never in no-save zones (unless Autosave In No Save Zones) and not within Min Seconds Between Autosaves. A load never autosaves.
22.2.3 Files and recovery
With the default File backend a slot is Saved/SaveGames/<Slot>.sav: a small container (magic, version, size, CRC32) around the save bytes. Writes are atomic: the new file is written to .tmp, the current good file becomes .bak, then the temp file is renamed over the slot. A damaged file never replaces a good backup. When loading, a damaged or missing slot falls back to the complete temp file, then to the backup; the slot screen marks a slot that came from backup. A save written by a newer game version is refused before anything is applied, so a half-loaded state never exists.
22.2.4 Save backends
Project Settings → Save → Backend: File (default, with free-space check), Save Game System (the platform's ISaveGameSystem, the storage consoles implement, with our container around the bytes) or Custom (a C++ class implementing IRSESaveBackend). Saves are per platform user (FRSESaveUser). Failures report Corrupt, NoSpace, UserSignedOut or Failed through On Save Failed.
22.2.5 Loading
Load Game applies every section to its system immediately (in the game instance, so state survives the map change), then opens the saved map and places the party at the saved save point, marker or transform. Each section is read into a fresh value and assigned only if it succeeds, so a corrupt section cannot spoil the current state. New game resets every saved system (Start New Game).
22.2.6 Versions and migration
The file has a version and each participant has its own. ReadSaveSection receives the saved version so a participant can convert old data. A missing section (a system added after the save) calls OnSaveSectionMissing (default: that system's new-game state). A section with no participant (a removed system) is ignored with a warning. A section newer than its participant is refused.
References to deleted content are dropped on load with a warning per reference, instead of failing the load: the stack of a deleted item, a deleted member, a deleted equipment slot entry.
22.3 Key classes and assets
| Class / asset | Module | Role |
|---|---|---|
URSESaveSubsystem | RSECore | Game instance subsystem: slots, save, load, blocks, autosave, participants |
IRSESaveParticipant, TRSEStructSaveParticipant<T> | RSECore | A system's section writer and reader |
URSESaveGame, FRSESaveSlotInfo, FRSESaveLocation, FRSESaveRequest | RSECore | The file, its header, where the party was, why it was saved |
URSESaveSettings | RSECore | Project Settings → Save |
URSESaveInteropLibrary | RSECore | Export and import sections to your own save system |
IRSESaveBackend | RSECore | Custom storage |
URSESaveSessionPolicy | RSECore | Co-op rules for who may save and load |
URSESaveFlowSubsystem | RSE | Opens the save screen, opens the saved map and places the party, consumes the save item |
ARSESavePoint, ARSENoSaveVolume, ARSEAreaVolume | RSE | Save point, no-save zone, zone name |
URSESaveItemData | RSE | The consumable save item |
URSESaveUISettings | RSE | Project Settings → Save UI |
URSEBlueprintLibrary_Save | RSE | The Blueprint nodes for everything above |
22.4 Settings
Project Settings → RPG Saga Engine → Save. Full list: Appendix B.
| Setting | Default | Meaning |
|---|---|---|
| Slot Count | 3 | Manual slots |
| Slot Name Prefix | Slot | Slot0, Slot1... |
| Autosave Slot Name | Autosave | Empty means no autosave |
| Autosave Slot Count | 1 | Rotating autosave slots |
| Autosave On Zone Transition | on | Autosave when arriving on a map |
| Autosave In No Save Zones | off | Allow it inside no-save zones |
| Zone Autosave Delay | 0.5 s | Wait after arrival |
| Min Seconds Between Autosaves | 30 s | Rate limit |
| Backend | File | File, Save Game System or Custom |
| Suspend Flush Timeout | 2 s | How long a pause waits for pending writes |
| Keep Backup | on | Keep the previous good save |
| Min Free Disk Space MB | 1 | Refuse to save below this |
Save UI (Project Settings → Save UI) holds the slot screen: autosave at save points, thumbnail size and capture, lock after save, and the texts for corrupt, backup and unavailable slots. Game Flow holds Show Continue and the menu keys.
22.5 Blueprint usage
Category RPG Saga | Save (the RPG Saga Blueprint Library Save nodes):
- Save Game (Slot Name, Save Point Id), Load Game (Slot Name; also opens the saved map), Open Save Screen (Save Point Id), Can Save Now (Source, returns the reasons), Has Any Save, Get Continue Slot, Get Save Slots, Delete Save Slot, Start New Game, Block Saving (Reason, Scope) and Allow Saving (Reason), Get Play Time Seconds, Get Slot Name (index).
- On Get Save Subsystem: Request Save, Autosave, Save To Slot Async, Load From Slot Async, Is Busy, Get Last Save Result, events On Saved, On Loaded, On Load Failed, On Save Requested, On Save Failed.
Example, a minigame that blocks saving:
- Event: minigame starts → Block Saving (Reason =
Minigame, Scope = All). - Event: minigame ends (and in Event EndPlay) → Allow Saving (Reason =
Minigame).
Example, a custom "Continue" button:
- Button On Clicked → Get Continue Slot → Branch on the return value.
- True → Load Game (Slot Name = the slot).
- False → show a "no saves" message (or use Has Any Save to disable the button).
Keeping our state inside your own SaveGame: the RPG Saga | Save | Interop nodes read and write live state of any section without using our slots: Get Save Section Ids, Export Section To Bytes, Import Section From Bytes, Export Sections To Bytes / Import Sections From Bytes (an empty list means every section), and the JSON forms (Export Sections To JSON, Import Sections From JSON, Export Section To JSON, Import Section From JSON). In your save function call Export Sections To Bytes with an empty list and keep the array in a Byte Array variable of your SaveGame; after you load your map, call Import Sections From Bytes. Import replaces the state of those sections and does not open the map: load it yourself. A section the project does not have is skipped, not an error.
22.6 C++ usage
Register a section for your own system, in the Initialize of a subsystem whose state is a struct of SaveGame fields:
USTRUCT()
struct FMyQuestBoardState
{
GENERATED_BODY()
UPROPERTY(SaveGame) TArray<FName> CompletedBoards;
UPROPERTY(SaveGame) int32 ReputationPoints = 0;
};
void UMyBoardSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
Collection.InitializeDependency<URSESaveSubsystem>()
->RegisterStruct<FMyQuestBoardState>(TEXT("MyBoard"), /*Version=*/1, this, [this] { return &State; });
}
Rules: the section id never changes after saves exist; the participant lives as long as its owner; use the returned participant's PostLoad(SavedVersion) to convert old data, OnMissing for a system added after the save, and OnNewGame for new-game state. Load order is registration order (the party is first). Do not save things that can be rebuilt (positions of schedule-driven NPCs, animation state).
Block saving from your own code: Save->PushSaveBlock(TEXT("MyCinematic")) and Save->PopSaveBlock(TEXT("MyCinematic")) (reasons are counted; always pop in EndPlay).
State held by actors (triggers, locks, interactables) lives in the exploration state subsystem under a State Key (the Save Key property, assigned by the editor); the actor reads it in BeginPlay and writes on change. See 16-world-building.md.
22.7 Advanced
- Custom backend. Implement
IRSESaveBackendand set Backend to Custom with your class: write the bytes to your cloud or platform service. Metadata (location, party, time, thumbnail as bytes) is in the save, so it works on any backend. - Async save and load.
SaveToSlotAsynccaptures the state immediately and writes on a worker thread;LoadFromSlotAsyncreads on a worker and applies on the game thread. CheckIs Busyand listen toOn SavedandOn Loaded. - State scope. A participant's
GetStateScopeis Shared, PerPlayer or HostOnly, andIsSavedToFilefalse makes it session-only. In co-op, saves belong to the host: a guest's save and load calls returnHostOnly, with the message ofURSESaveSessionPolicy. See 22-networking.md. - Thumbnails. The slot screen captures the viewport without UI. Headless runs and servers skip it. Turn it off in Save UI settings.
- Missing content. Participants may opt out of dropping missing references with
bRemoveMissingContent. - Testing.
RSE.Save.FullRoundTripcompares the registered participants with the audit list, fills every section, writes it to a temp slot, resets, loads and checks byte for byte. A new system with a section fails it until you add it to the list. - Console commands (development).
RSE.Save.Slots,RSE.Save.To <slot index | slot name>,RSE.Save.Load [slot index | auto | slot name],RSE.Save.UseItem [item path] [give], andRSE.Save.SimulateFault NoSpace|Corrupt|SignedOut|Failed. See Appendix C.
22.8 Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| The save item says it cannot be used | A block applies: battle, dialog, cutscene or no-save zone | Check Can Save Now for the reasons; a block you pushed yourself needs its pop |
| Saving is blocked forever after a minigame | A Push without a Pop | Pop in every exit path and in EndPlay; the log warns on a pop without a push |
| A manual save fails with Protected Slot | It targeted an autosave slot | Use Get Slot Name for manual slots |
| Autosave does not run on arrival | Rate limit, no-save zone or the setting is off | Check Autosave On Zone Transition, Min Seconds Between Autosaves, Autosave In No Save Zones |
| After loading, a chest is closed again | The actor's state key changed (renamed actor, copied instance) | Run Fix State Keys and keep the Save Key values |
| Load says Incompatible | The save was written by a newer version | Update the game; nothing was applied |
| My system's data is gone after loading | No participant, or no SaveGame flag on the fields | Register the section and mark fields UPROPERTY(SaveGame) |
| A load puts the party at the wrong place | The save point id is not unique | Give each save point its own Save Point Id |
| A guest cannot save | Co-op: only the host saves | Expected; see the session policy |
| Slot shows as damaged | A corrupt file with no readable backup | Delete the slot, or load another; saves rewrite damaged slots |
22.9 See also
- 02-core-concepts.md for serializable state and IDs.
- 14-narrative.md for story flags and effects that gate saving.
- 15-exploration.md for save points in zones and travel.
- 16-world-building.md for State Keys on World Partition maps.
- 22-networking.md for co-op saving.
- 20-ui.md for the slot screen and replacing it.
- Design note:
docs/design/save-system.md. Product page:docs/product/modularity.md(Save Interop).