Save/Load Strategy (Client-Driven)
This guide explains how to use the client-driven save/load flow introduced for RPGJS. The client requests the slot list and triggers save/load actions, while the server executesplayer.save(slot) and player.load(slot) using a pluggable storage strategy.
Concepts
- Save storage strategy (server): decides where snapshots are stored (DB, file, memory).
- Auto-save strategy (server): decides when saving/loading is allowed and the auto slot.
- Save client service (client): requests slot list and triggers save/load actions.
- Slots metadata: what the UI displays (level, exp, map, date, custom fields).
Server: provide a storage strategy
The server exposessave.list, save.save, and save.load actions. A storage
strategy is injected via DI; if none is provided, a memory-only strategy is used.
The server can also control whether saving/loading is allowed.
Strategy contract
Server: provide an auto-save strategy
getDefaultSlot() function is the auto slot. When you call player.save()
without a slot, this strategy decides which slot is used (e.g. always slot 0, or last
used slot).
Auto-save example (server)
Register auto-save strategy
Save points (server authority)
If you want to restrict saving to specific points, you can deny saves by default and only allow them when the player interacts with a save point.Register the strategy
Built-in localStorage strategy (standalone)
For standalone mode (server running in the browser), use the built-in localStorage strategy. It stores full slots (meta + snapshot) under a single key and can carry an optional policy.Client: request slots and trigger save/load
The client usesSaveClientService to talk to the server. It is already included
in provideRpg() and provideMmorpg().
Typical flow
- Call
saveClient.listSlots()to get the current slot list. - Show the Save/Load UI with those slots.
- On interaction:
saveClient.saveSlot(index)for save.saveClient.loadSlot(index)for load.
Player API (server-side)
player.snapshot()-> returns the raw snapshot object (low-level).player.save(slot?)-> stores a snapshot using the storage strategy.- If
slotis omitted, the policygetDefaultSlot()is used.
- If
player.load(slot?)-> loads a slot using the storage strategy.
player.snapshot() if you need to serialize or inspect state without saving.
Examples:
GUI options (auto slot + save disabled)
The save/load GUI can display a dedicated “Auto Save” slot at the top. It is read-only in save mode, and selectable in load mode.Menu GUI (server-side)
MenuGui.open() accepts these options:
saveShowAutoSlot(boolean) -> show the auto slot in the GUIsaveAutoSlotIndex(number) -> which slot index to use for auto savesaveAutoSlotLabel(string) -> label displayed for auto slot
canSave is computed from the AutoSaveStrategy and sent to the client; if false,
the “Save” entry is disabled in the menu.
Save/Load component (client-side)
Props supported by the component:showAutoSlot(boolean)autoSlotIndex(number)autoSlotLabel(string)
showAutoSlot is enabled:
- save mode: auto slot is displayed but read-only
- load mode: auto slot behaves like a normal slot and loads as usual
Example (menu or title screen)
Events sent by the server
These are emitted to the client and handled bySaveClientService:
save.list.result->{ requestId, slots }save.save.result->{ requestId, index, slots }save.load.result->{ requestId, index, ok, slot }save.error->{ requestId, message }
Notes
- Works in standalone and client/server modes.
- Slot metadata is a free object, so you can display any custom fields.
- The Save/Load GUI only handles interactions; it does not fetch or persist slots.