Persistence is modular. SaveCoordinator owns capture/validation/serialization/storage lifecycle, while feature-specific IPlayerSaveModule implementations own sections of player data.
Save lifecycle
Character identity assigned
↓
PlayerSaveContext registered
↓
Server loads snapshot
↓
Modules restore in RestoreOrder
↓
Gameplay mutates authoritative state
↓
Save requested / disconnect / shutdown
↓
Modules capture live state
↓
Snapshot validated + checksum
↓
Serialized payload written atomically
IPlayerSaveModule
namespace GreenCloakGames.TileTickRPGCore.SaveSystem
{
public interface IPlayerSaveModule
{
string ModuleId { get; }
int RestoreOrder { get; }
void Capture(PlayerSaveData data, SaveContext context);
void Restore(PlayerSaveData data, LoadContext context);
}
}
New persistent systems should add a save DTO/section and a module rather than editing every save caller. RestoreOrder is deterministic so dependencies can be restored before systems that rely on them.
ISaveCoordinator extension surface
SaveAsyncandLoadAsyncown disk lifecycle.CaptureRuntimeStatebuilds an in-memory snapshot without disk I/O. Travel uses it to carry complete runtime state across a scene change.ApplyRuntimeStaterestores the in-memory snapshot to the currently registered player before travel overrides arrival position.- Save/load events are available for diagnostics or presentation, but should not become alternate state stores.
Server authority
NetworkBootstrap installs SaveAuthority gates so normal clients cannot write authoritative saves while a network session is active. ServerCharacterPersistence owns networked character lifecycle.
Adding custom persistent data
- Add a stable serialized field/DTO to the save model for your feature.
- Implement
IPlayerSaveModule. - Choose a unique
ModuleId. - Choose a restore order based on dependencies.
- Capture only server-authoritative live state.
- Restore through the same runtime component/service that owns the feature.
- Register the module using the existing save-module bootstrap/registry pattern.
- Add migration logic if shipped data changes shape later.
Lifecycle rule: never defer capture until after player despawn/unregistration. The coordinator cannot serialize authoritative player data that no longer exists.