Gessa Docs
Recipes

Recipe

Saves persistence player progress and data stores

Anything that must outlive the current match or session: score, inventory, unlocked levels, best time, checkpoint. Durable values live in the data warehouse, addressed by store, record, and field.
engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, persistence.v1Copy for LLM

Use this for

saving score, inventory, unlocks, and progress that survives across sessions; per-player durable state; a game data store

Not for

transient in-match values that need not persist (a plain script variable is enough); replicated motion (see multiplayer-replication-and-rooms)

Pairs with: Collectibles pickups scoring and win condition, Combat damage health and respawn scripting, UI HUD panels widgets and world nameplates, Spawn points checkpoints and respawn flow

The recipe

  1. Declare the store with project_create_data_store (project.data_store.create) so the game has a durable place for records.
  2. Address a value with three coordinates used by every warehouse op: storeKey (defaults progress), recordKey (defaults player), and field.
  3. Read into a script binding: readTypedStateValue { "scope":{"kind":"handler","handlerRef":<key>}, "storeKey":"progress", "recordKey":"player", "field":"coins", "valueType":"number", "assignTo":"coins", "defaultValue": 0 }. valueType is a Script IR value type (number, boolean, string, vector3, json, ...).
  4. Write a value: writeTypedStateValue with the same coordinates plus value. Increment a counter atomically: incrementNumericState { "field":"coins", "by": 1 }. Flip a flag: setBooleanState { "field":"tutorialDone", "value": true }.
  5. From a GessaScript body (replaceScriptFromGessaScript) the full warehouse surface is available: ctx.warehouse.get, set, update, increment, append, query, create, delete.
  6. Surface a saved value in the HUD with wireHudStateBinding (see ui-hud-panels-and-widgets); it reads the same store/record/field.

Pitfalls

  • writeTypedStateValue, incrementNumericState, and setBooleanState carry writeState + durable + requiresAuthority: they run server-authoritatively and persist. Do not treat them as client-local scratch.
  • readTypedStateValue is readState + durable; give it a defaultValue so a missing record does not read as undefined.
  • The valueType must match how the field is written elsewhere; reading a number field as boolean will not coerce.
  • persistence.v1 guards persistence.prefetch_only and persistence.drain_audit mean reads are prefetched and writes audited; keep per-tick warehouse traffic bounded.

Verify

  • simulation_run (qa.run.start) to confirm a written value reads back after a reload path.
  • project_get_graph_snapshot to confirm the data store and the warehouse-op handlers exist.
Was this helpful?Report an issueContact support

On this page