Saving while the game runs
A game is saved while it runs: a player digs a crater and picks up the ore in the moment the autosave starts, a client trades while the host saves. A save is only right when everything in it belongs to the same moment, and a load is only right when nothing reacts to a half loaded state. Pulse Foundation gives every plugin the same signals for both, without a dependency on a save plugin.
The save status
A save system reports its saves to UPulseSaveStatusSubsystem of the world, which sends them on the message bus (payload FPulseSaveStatusMessage: status, slot, phase, success, seconds):
| Channel | When |
|---|---|
Pulse.Message.Save.Started | A save started |
Pulse.Message.Save.Phase | It reached a phase (“Collect”, “Write”) |
Pulse.Message.Save.Finished | It finished; bSuccess, Seconds |
Pulse.Message.Save.LoadStarted | The game started loading |
Pulse.Message.Save.LoadFinished | The game finished loading; bSuccess, Seconds |
Is Pulse Saving tells whether a save runs. An interface can show a save icon from these messages alone.
The load barrier
Loading takes several frames: the save is read, components get their state, the world builds its regions, clients get the result by replication. Meanwhile the game runs, and a reward, a toast or a counted kill would act on a half loaded state. Everything that loads holds the barrier:
UPulseSaveStatusSubsystem* status = UPulseSaveStatusSubsystem::Get(this);
const FPulseHandle hold = status->BeginLoad(TEXT("World"));
// ... over several frames ...
status->EndLoad(hold, bSuccess);
The first hold sends LoadStarted, the last one ending sends LoadFinished. Code that must not run for a half loaded state asks Is Pulse Loading, or runs once loading is over with When Pulse Loaded (at once when nothing loads). Events that only bring back an earlier state carry the catch-up flag, so listeners that count or show new events leave them out on their own.
Deferring actions while a save runs
A save can take several frames when a model needs them (quests save on their next tick). An action that changes several systems at once (a trade that moves items and finishes a quest) should then not land half in the save: When Pulse Saved runs it at once when no save runs, else right after the save finished. Is Pulse Saving tells whether one runs.
Rules for consistent saves
- One save for one game. Keep the world and the players in the same save game. Two saves with their own timing (a profile slot and a world slot, regions written on their own) can end up from different moments after a crash.
- Caches stay caches. Data a system writes on its own for speed (the region bytes of Pulse World) is not a second save; the save game is the truth.
- Changes on the server are at once. Everything that changes in one call on the game thread of the server is either in a save or not; nothing is half in it. Exchanges keep changes over several systems in one call.
- Hold back during loading. Rewards, toasts and achievements wait for
LoadFinishedor skip catch-up events.