# Use Rolly Save from C++

> Add the plugin's modules to your code, save and load through the subsystem, read and write save files and records yourself, keep saves in storage of your own,...

Product: Rolly Save 1.0.0 | Sheet: guide | Updated: 2026-10-31 | HTML: https://rolly-docs.pages.dev/save/guides/use-from-cpp/

## Add the modules

| Module | Loads in | What it holds |
|---|---|---|
| `RollySave` | Games, servers and the editor | The subsystem and its Blueprint nodes, actors, Save Rules, handlers, level tools, the save file format, storage, migration |
| `RollySavePCG` | Games, servers and the editor | Saving PCG components and their output |
| `RollySaveStateTree` | Games, servers and the editor | The StateTree handler |
| `RollySaveGAS` | Games, servers and the editor | The Gameplay Abilities handler |
| `RollySaveUI` | Games and the editor, never a dedicated server | The slot screen, the profiles panel, the saving indicator, notices and the loading overlay |
| `RollySaveEditor` | The editor | The rule editor, Pick Properties, the outliner column, markers, checks, the setup panel, Play from Slot, the Save Inspector and the automated tests |
| `RollySaveCore` | Games, servers and the editor | The shared foundation: setup reports, validation, the input device tracker |
| `RollySaveCoreUI` | Games and the editor, never a dedicated server | The Rolly UI design system the screens are built from |
| `RollySaveCoreEditor` | The editor | The Message Log listing, the theme editor, the core's tests |

The last three are the shared Rolly foundation, carried inside this plugin under this product's name, so several Rolly products in one project never clash.

```csharp
PrivateDependencyModuleNames.AddRange(new string[]
{
	"RollySave",   // the subsystem, files, records, rules, handlers
	"RollySaveUI", // the slot screen and the other screens
});
```

Headers sit in feature folders and are included by path from the module's `Public` folder (`Game/RollySaveSubsystem.h`); [ARCHITECTURE.md](https://rolly-docs.pages.dev/save/architecture/) lists the folders and the extension points, and the [class reference](https://rolly-docs.pages.dev/save/reference/classes/) gives every class's header.

## Save and load through the subsystem

`URollySaveSubsystem` (`Game/RollySaveSubsystem.h`), one per game instance, saves and loads the game on the server or in a standalone game: the variables flagged `SaveGame` of the game instance, its subsystems, the Game Mode, the Game State, the world's subsystems and the map's Level Blueprint, each by its role in the game, the objects registered under a name, and the world's actors and components that save (`URollySaveWorldSubsystem::ResolveActorSettings` gives what one keeps; `URollySaveRule` data assets set it for the actors they match and save engine properties by path, `RollySaveRuleExplain::Explain` tells why; `URollySaveComponent` overrides it and fires `OnPreSave`, `OnSaved` and `OnLoaded`) and the local players. `ForgetLevel` and `ForgetAllLevels` reset the levels it keeps across travel. Project Settings > Plugins > Rolly Save > What Saves turns each kind off, and Game Data Version is written into every save.

```cpp
#include "Game/RollySaveSubsystem.h"

URollySaveSubsystem* Save = URollySaveSubsystem::Get(this); // any object of the running game
Save->RegisterObject(QuestLog, TEXT("QuestLog"));           // an object that does not save on its own
Save->Save(TEXT("Slot 1"), [](const FRollySaveResult& Result)
{
	// On a later tick. Succeeded, or Result.Status says why and the slot keeps its previous save.
});

// Opens the map the save was made in; every saved value is set before its Begin Play.
Save->Load(TEXT("Slot 1"), ERollySaveLoadMap::OpenSavedMap, [](const FRollySaveResult& Result)
{
	// After the loaded map's Begin Play, where this object still exists, such as in the Game Instance.
});
```

```cpp
Save->ListSlots([](const FRollySaveResult& Result, const TArray<FRollySaveSlotInfo>& Slots)
{
	// Newest first, from the slot index: SlotName, SaveTime (UTC), GameDataVersion, SizeBytes and the save's metadata.
});
Save->Copy(TEXT("Slot 1"), TEXT("Slot 2")); // Slot 2 keeps what it held before as its backup
Save->Delete(TEXT("Slot 2"));               // both copies; succeeds when the slot held no save
```

A load's callback reaches only an object that lives through the map change. Elsewhere, bind `OnLoadFinished` in Begin Play, or call `GetLastLoadResult` there: the values are set by then. An object registered under a name after the load, such as an actor that registers in its Begin Play, takes its saved values inside that `RegisterObject` call. Until a load's values are set, and during seamless travel, saves and loads return `Busy`; spread After Begin Play values are the exception: a save or load asked for while they are set sets the rest first. The next save writes back what the last load or save held for objects that are not there, such as another map's Level Blueprint; call `ClearLoadedGame` when the player starts a new game.

`Load` also takes an `FRollySaveLoadRequest`: a slot from storage or memory (`bFromMemory`), the whole game or the parts of a `Scope`, into the saved map, the current one or `GivenMap`. `SavePart` saves the parts of an `FRollySaveScope` and keeps the rest of the slot, `SaveToMemory`, `SaveRewindPoint` and `Rewind` keep whole-game snapshots for the session, and `AddSaveBlock` and `RemoveSaveBlock` refuse saves while a block is on.

## Fill what slot lists show

`SetSlotLocation`, `SetSlotGameFields` and `GetPlayTime` fill and read the metadata `ListSlots` gives, `SetSlotTitle`, `SetNextSaveTitle` and `SaveToNewSlot` give saves titles, and `SetCurrentSlot` names the current slot (see [Show saves in a slot list](https://rolly-docs.pages.dev/save/guides/list-slots/)). `CaptureThumbnail`, `SetNextThumbnail` and `ClearThumbnail` choose the next save's picture, `CaptureThumbnailHold`, `UseThumbnailHold` and `ReleaseThumbnailHold` keep one per menu for split screen, and `LoadSlotThumbnail` gives a slot's picture as a texture (see [Show save thumbnails](https://rolly-docs.pages.dev/save/guides/thumbnails/)).

## Follow saves, loads and the world

`OnSaveStarted` (with who started the save; a player's menu saves inside `FPlayerSaveScope`), `OnLoadStarted` and `OnLoadProgress` report saves and loads as they run. `IsWorldReady`, `HoldPlayer`, `ReleasePlayer`, `ReleaseHeldPlayers`, `IsPlayerHeld` and `IsPlayerWaitingForGround` hold players until the ground under them has loaded, `OnPlayerHeld`, `OnPlayerReleased` and `OnWorldReady` report the holds and their end, and `URollySaveWaitWorldReadyAction` is Wait for Rolly World Ready (see [Hold players until the ground has loaded](https://rolly-docs.pages.dev/save/guides/hold-players/)). `MakeDebugSnapshot` and `MakeDebugActor`, in every build but Shipping, give the game's and an actor's save state as the Gameplay Debugger shows it, and `FRollySaveDebugSnapshotBuild` makes the full snapshot over several frames (see [See what an actor saves while you play](https://rolly-docs.pages.dev/save/guides/debug-while-playing/)).

## Run the game's flow

`RequestAutosave`, `SaveCheckpoint` and `LoadCheckpoint` save and retry the game in its flow; `StartRun` and `EndRun` bind the game's saves to one slot; `GetProfile`, `LoadProfile`, `SaveProfile` and `ResetProfile` reach each local player's `URollySaveProfile` (`Profile/RollySaveProfile.h`), whose Blueprint Project Settings names, and with Profile Keys at Named, `ListProfiles`, `CreateProfile`, `RenameProfile`, `DeleteProfile`, `UseProfile` and `GetProfileKey` manage named profiles; `StartNewGamePlus` starts over with the parts of an `FRollySaveScope`; and `RenameSlot`, `ExportToFile`, `ImportFromFile`, `ExportToBytes` and `ImportFromBytes` move saves, and `ExportSlotToJson`, `ExportSlotToJsonString` and `ImportSlotFromJson` move them as Rolly Save JSON (see [Export and import saves as JSON](https://rolly-docs.pages.dev/save/guides/saves-as-json/)). Each takes an `FRollySaveDone` or a callback with what it gives, on a later tick.

`OnBeforeLifecycleSave` fires before the saves Rolly Save writes as the game leaves, `OnUserSignedIn` and `OnUserSignedOut` report platform users on storage that keeps users apart, and `OnLowStorage` and `CheckStorageSpace` tell how much space the saves have (see [Save when the game closes or goes to the background](https://rolly-docs.pages.dev/save/guides/app-lifecycle/) and [Keep saves with each player's account](https://rolly-docs.pages.dev/save/guides/platform-users/)). `OnSaveChangedOutsideGame` reports a save that save protection found changed, and a subclass of `URollySaveProtectionKeyProvider` gives the keys from code (see [Protect saves from editing](https://rolly-docs.pages.dev/save/guides/protect-saves/)).

## Extend what saves

The Blueprint nodes are `URollySaveSlotAction`, `URollySaveLoadAction`, `URollySaveListAction`, `URollySaveImportAction`, `URollySaveBytesAction`, `URollySaveProfileAction`, `URollySaveThumbnailAction`, `URollySaveProfilesAction`, `URollySaveProfileInfoAction`, `URollySaveJsonAction` and `URollySaveStorageSpaceAction` (`Nodes/`), which call these functions; `ImportEngineSaveGame` reads a save of the engine's Save Game to Slot.

- **Migration:** to change saved data between versions of your game, raise Game Data Version and subclass `URollySaveMigrationStep` (`Migration/RollySaveMigrations.h`), or use a built-in step, in the Migrations asset (see [Keep old saves loading after an update](https://rolly-docs.pages.dev/save/guides/keep-old-saves-loading/)).
- **State that is not a property:** subclass `URollySaveHandler` (`Handler/RollySaveHandler.h`) and list the class in Project Settings > Plugins > Rolly Save > Global Handlers or attach it in a Save Rule (see [Save what is not a variable](https://rolly-docs.pages.dev/save/guides/save-handlers/)).
- **Engine state:** the handlers `URollySaveMaterialHandler`, `URollySaveTimelineHandler`, `URollySaveSequenceHandler`, `URollySaveMontageHandler` and `URollySaveAudioHandler` (`EngineState/`) subclass `URollySaveEngineStateHandler`, which finds an actor's components through `FRollySaveComponentFilter` and notes the assets they show as their design (see [Save materials, timelines, sequences, montages and sounds](https://rolly-docs.pages.dev/save/guides/engine-state/)).
- **Gameplay Abilities:** `URollySaveGASHandler` (`RollySaveGASHandler.h`, module RollySaveGAS) saves Ability System Components; a C++ subclass saves values of your effect context type through `CaptureContextValues` and `ApplyContextValues`, and a C++ handler reads `IsInPlaceApply` to tell a load in place from an actor the load made fresh (see [Save Gameplay Ability System state](https://rolly-docs.pages.dev/save/guides/gameplay-abilities/)).
- **Save Rules:** `URollySaveRule` (`Rules/RollySaveRule.h`) is a Save Rule; `ApplySavedValues` gives an actor with Apply Timing When Asked its values, and `ReloadSaveRules` finds rules of plugins mounted during play (see [Choose what saves](https://rolly-docs.pages.dev/save/guides/choose-what-saves/)).
- **Level tools:** `URollySaveTriggerComponent` (`Level/RollySaveTriggerComponent.h`) saves when an actor enters its actor's shape or `Trigger` is called, refused by `IRollySaveTriggerInterface::CanTriggerRollySave` on its actor; `URollySaveResetAreaComponent` resets the saved actors inside its shape when the level is next built, counting After Game Time on play time or a `URollySaveGameClock` subclass; `MarkAllAreasForReset`, `IsRestoring` and `RequestSlotScreen` are on the subsystem, and `URollySaveSubsystem::FRestoreScope` makes Is Restoring true around a teleport of your own (see [Place save points, checkpoints and reset areas](https://rolly-docs.pages.dev/save/guides/place-level-tools/)).
- **Instances:** instanced meshes save through `Instances` in `FRollySaveActorSettings` and `FRollySaveActorOverrides` (`FRollySaveInstanceSettings`, `Instances/RollySaveInstanceTypes.h`). `GetInstanceKey`, `FindInstanceByKey` and `EqualInstanceKeys` on the subsystem turn an instance into an `FRollySaveInstanceKey` that names it across saves and loads, and back (see [Save harvested foliage and instanced meshes](https://rolly-docs.pages.dev/save/guides/harvest-and-instances/)).
- **Broken geometry collections:** they save through `Destruction` (`ERollySaveDestruction`, `Destruction/RollySaveDestructionTypes.h`); `RollySaveDestructionSection` (`Destruction/RollySaveDestructionSection.h`) reads and writes their GCOL sections for tools that read saves (see [Keep broken destructibles broken](https://rolly-docs.pages.dev/save/guides/destruction/)).

## Open the screens from code

The screens are in the `RollySaveUI` module, on clients and standalone games: `URollySaveUISubsystem` (`RollySaveUISubsystem.h`) opens the slot screen (`OpenSlotScreen`) and the profiles panel (`OpenProfiles`), fires `OnNewGameChosen`, and runs the saving indicator, notices and loading overlay from the runtime's events; `URollySaveUILibrary::ShowSavingIndicatorPreview` shows the indicator without a save, and `FRollySaveMapLoadScreen` hands the movie player the overlay's copy (`SRollySaveMapLoadScreen`) during a map load. `FRollySaveSlotScreenModel` (`Model/RollySaveSlotScreenModel.h`) gives a screen of your own the slot screen's rows, groups, order and actions (see [Give players a slot screen](https://rolly-docs.pages.dev/save/guides/slot-screen/)).

## Read and write save files

`URollySaveStore` (`Store/RollySaveStore.h`) keeps two copies of every file on a storage backend. Call it on the game thread; results arrive on the game thread.

- `Save`, `Load` and `Delete` take an `FRollySaveFileName` (`Storage/RollySaveFileName.h`), made only by `ForSlot`, `ForProfile` and `ForIndex`, so a backend never receives a name of another product.
- `Inspect` reads both copies and reports what a load would find, with the header only. `LoadCopy` reads one copy's bytes and file, and `FRollySaveFile::Diagnose` reports every checksum of those bytes. `List` gives the slot index's entries.
- `Save` with an expected sequence number writes only while the file's newest save still has it, and ends with `Changed` otherwise, as an edit of an opened save needs.
- `SetReadOptions` lists your own chunk IDs, as `KnownChunks` does for `FRollySaveFile::Read`. `OnWriteFailed` and `OnLoadedFromBackup` report results to code that did not ask, such as a notice on screen. `Flush` blocks until the store's operations have reported, within a time limit, saves that wait for their pictures included, which it writes at once; it may be called from a result callback.

`FRollySaveFile` (`File/RollySaveFile.h`) is the reader and writer: plain C++ without UObjects, safe on any thread. `FRollySaveFile::ReadHeader` reads only the prelude and the header. Chunks of your own take an ID of four printable ASCII characters that starts with a lowercase letter; IDs that start with an uppercase letter belong to Rolly Save.

```cpp
FRollySaveFileReadOptions Options;
Options.KnownChunks.Add(FRollySaveFourCC("mygm")); // decode it; unknown chunks are only carried
FRollySaveFile Loaded;
const FRollySaveFileResult Result = FRollySaveFile::Read(FileBytes, Loaded, Options);
if (Result.Status == ERollySaveFileStatus::NewerVersion)
{
	// Keep the file: a newer version of the game wrote it.
}
```

Tools that read or change saves start from `FRollySaveInspectFile::Make` (`Inspect/RollySaveInspectFile.h`), a file split into chunks and records. `RollySaveValueCodec::Decode` reads a record's values by their saved types alone, without its class, and `Encode` writes them back byte for byte; `FRollySaveStagedEdits` checks each change as it is staged and rebuilds a file that passes a load's checks; `RollySaveFileDiff::Compare` compares two files by key, and `SetValueFrom` and `UseRecord` stage the other file's value or record; `RollySaveJson` (`Json/RollySaveJson.h`) writes and reads Rolly Save JSON. Decode on the game thread, since it looks up structs.

## Capture and apply records yourself

A record holds one object's saved state. `FRollySaveRecordWriter::Capture` (`Record/RollySaveRecordWriter.h`) writes every property flagged `SaveGame`, struct members included when they carry the flag too, property bags whole, and, for objects other than actors and scene components, what their `Serialize` override writes when `Ar.IsSaveGame()` is true. It calls `OnRollySavePreSave` on the object, and on each object it owns, before writing it, and the apply calls `OnRollySaveLoaded` once every record applied, when the object declares them (see [Make your plugin's objects save](https://rolly-docs.pages.dev/save/guides/save-from-other-plugins/)). Applying reads it back with the versions of the file it came from, so a save made by an older version of your game reads the way it was written. Enums are saved by value name, maps and sets load as exactly what was saved, and a value equal to the class default still restores over an edited instance.

A property that points at an object saves it by what the object is:

- **Another saved object:** by its save ID, and the apply finds the object of that ID again. Register such objects under a name in an `FRollySaveNameRegistry` (`Record/RollySaveNameRegistry.h`) and give it to the writer and the reader, or implement `IRollySaveObjectResolver` to give IDs of your own. A pointer to the captured object itself needs neither.
- **An object the saved object owns** (its outer is the saved object, or an object the saved object owns): inline, with its class, name and `SaveGame` properties. The apply reuses an object of that class and name, or creates one; nested objects, shared pointers and cycles come back as they were.
- **An asset or a type:** by path. Load the records' assets with `FRollySavePreloader` (`Record/RollySavePreloader.h`) before they apply: an apply loads nothing, and an asset that is not loaded reads as empty.
- **Anything else** saves as empty and is listed in the result's `Issues`, as is a pointer that loads as empty.

Soft object pointers save their path, except a pointer to the captured object or to a loaded object the resolver gives an ID, which saves as that ID. A path into a Play In Editor copy of a map is saved as the map's own path and points into the copy the record applies in.

Checksums catch damage, not edits, so every record passes a check of its structure (`RollySaveRecordCheck`, `Record/RollySaveRecordCheck.h`) before anything of its file applies: a record whose sizes, counts, nesting, names, types or owned objects a save never writes is `Damaged`, and no record of that file applies. Some bounds hold for a whole file, such as its owned objects and what its texts display; capturing runs the same check and counts them across the captures you give one `FRollySaveCheckBudget`, so a file of your captures never holds what your game would refuse. Capture and apply on the game thread: anywhere else, and during garbage collection, they return `InvalidInput` and do nothing.

```cpp
#include "Record/RollySaveApplySession.h"
#include "Record/RollySaveNameRegistry.h"
#include "Record/RollySavePreloader.h"
#include "Record/RollySaveRecordCheck.h"
#include "Record/RollySaveRecordCodec.h"
#include "Record/RollySaveRecordWriter.h"

FRollySaveNameRegistry Registry; // save IDs of the objects records point at
Registry.Register(TEXT("inventory"), *Inventory);
Registry.Register(TEXT("quests"), *Quests);

FRollySaveRecordWriter Writer(&Registry); // reuse it: it keeps its buffers
FRollySaveCheckBudget FileBudget; // one per file, for every capture of that file
FRollySaveRecord Record;
Writer.Capture(*Inventory, *Registry.FindId(*Inventory), Record, FileBudget);
TArray<uint8> Payload;
RollySaveRecordCodec::EncodePayload(MakeArrayView(&Record, 1), Payload);
File.AddChunk(FRollySaveFourCC("mygm"), TEXT("inventory"), MoveTemp(Payload));

// After FRollySaveFile::Read with "mygm" in KnownChunks. Loaded, Records (TArray<FRollySaveRecord>) and
// Preloader (FRollySavePreloader) are members, so they live until the records applied.
RollySaveRecordCodec::DecodePayload(Loaded.FindChunk(FRollySaveFourCC("mygm"), TEXT("inventory"))->Data, Records);
const FRollySaveRecord* const ToLoad[] = { &Records[0] };
Preloader.Start(ToLoad, FSimpleDelegate::CreateWeakLambda(this, [this]()
{
	// On a later tick, with the assets the records name loaded; Preloader.GetIssues() lists those that are not.
	FRollySaveApplySession Session(Loaded.Header.Versions, &Registry); // one per file
	Session.Prepare(Records[0], *Inventory);
	const TArray<FRollySaveRecordResult> Results = Session.Apply(); // per record: Damaged, NewerVersion or Ok with Issues
	Preloader.Release();
}));
```

Give every record of one file to one `FRollySaveApplySession` (`Record/RollySaveApplySession.h`), each with the object it restores, then call `Apply` once: records that point at each other, such as an inventory and the quests that refer to it, find each other's objects without a resolver, and a damaged record stops the whole file. `FRollySaveRecordReader::Apply` (`Record/RollySaveRecordReader.h`) applies a file's records one at a time instead; use one reader per file, since it counts the file's bounds and refuses every record after a damaged one.

## Keep saves somewhere else

To keep saves somewhere else, such as a cloud store, subclass `URollySaveBackend` (`Storage/RollySaveBackend.h`) and override `StartWrite`, `StartRead`, `StartExists`, `StartDelete` and `StartList`, and `StartQueryFreeSpace` when the storage can tell its free bytes (by default it cannot). Each calls its callback once, from any thread, without waiting for the game thread. `StartList` reports every file the storage holds, or Unsupported; `List` passes on only Rolly Save's. When several backend objects reach the same files, override `GetStorageId` to return the same text for each, so their saves share one queue per slot. Pick the class in Project Settings > Plugins > Rolly Save > Storage Backend.

## Run the automated tests

The tests are `Rolly.Save.*` and `RollySaveCore.*` for the shared foundation and the design system. Run them in the editor from Tools > Session Frontend > Automation (filter `Rolly`), or headless:

```text
UnrealEditor-Cmd.exe <YourProject>.uproject -ExecCmds="Automation RunTests Rolly.Save; Quit" -unattended -nullrhi
```

They make their worlds, actors and rules in memory. Tests that draw pictures (`Rolly.Save.UI.Pictures`, `Rolly.Save.Editor.Pictures` and their kin) render only when the run can render (`-RenderOffScreen` instead of `-nullrhi`) and otherwise say what they skipped. The golden tests read fixture files from the project's `TestData/RollySaveFixtures` folder, which a buyer's project does not have; without it they have no cases. [ARCHITECTURE.md](https://rolly-docs.pages.dev/save/architecture/#tests) lists what each area covers.
