Design a save/load architecture for an Unreal Engine game with persistent world state — player progress, inventory, and dynamically spawned actors that must come back on load. Many independent systems each own a slice of savable state, so each must contribute to and restore from the save without one monolithic save routine knowing all their internals. The format must survive across game builds and platforms (it must not break when classes change between versions), so live object memory and raw pointers cannot just be dumped — you need a stable representation that rebuilds live objects on load. Saving must be explicit and durable to disk, not assumed to persist in memory. In multiplayer only the authoritative side persists state. Describe what you store versus what you rebuild, how independent systems plug in, how you keep the save robust across versions, and the trade-offs of your approach.
Use a USaveGame subclass as a plain data container, serialized via UGameplayStatics::SaveGameToSlot. Each savable system writes its state into the object on save and restores it on load; never serialize live Actors directly — store ids and rebuild.
- ✗Trying to serialize live Actor pointers instead of storing ids and rebuilding on load
- ✗Using raw
memcpyof structs, which breaks across builds and platforms - ✗Assuming in-memory state persists without explicitly writing to a save slot
- →How would you save and restore dynamically spawned Actors and their world transforms?
- →How would you handle a save written by an older version of the game?
Key classes
UMySaveGame— aUSaveGamesubclass: a flat container ofUPROPERTYfields and structs. No logic.USaveGameSubsystem— aUGameInstanceSubsystem: orchestrates save/load and polls systems.ISavable— an interface on systems/Actors:WriteSaveData,ReadSaveData.FActorSaveData— aUSTRUCT: class, transform, id, and serialized properties of one actor.
Data model
USaveGame stores data, not objects: instead of Actor pointers it keeps their id, class, and transform. Live objects are rebuilt on load. Actor properties are serialized via FObjectAndNameAsStringProxyArchive over the SaveGame flag on UPROPERTY.
Data flow
Save:
USaveGameSubsystemcreates aUMySaveGame.- Each
ISavablesystem writes its state; dynamic Actors write anFActorSaveData. SaveGameToSlot(SaveObj, Slot, UserIndex)writes to disk asynchronously.
Load:
LoadGameFromSlotreads the object.- The subsystem checks a version field and migrates if needed.
- It re-spawns dynamic Actors from
FActorSaveData, then hands state back to systems.
Replication considerations
In multiplayer only the server saves — clients hold no authoritative state. After loading, the server replicates the restored state to clients through normal mechanisms; the save system has no separate network logic.
Designer-facing config
Which Actors are saved is marked by a tag or an ISavable implementation in Blueprint. Fields to save are tagged with the SaveGame specifier on UPROPERTY. Slot name and autosave points are configured by data.
Trade-offs
- Declarative (
SaveGameflag) vs. manual serialization: the flag is less code but gives less control over format and versioning. - One large slot vs. modular slots: one is simpler, modular ones are cheaper for frequent autosaves.