PURPOSE
Zustand store that carries data across the metagame session loop (Hub to Loadout to Game to Results to Hub). Each screen reads what it needs and writes what it produces, keeping mission setup, mission result, and ship selection in one place across screen transitions.
OWNS
selectedShipId— the currently selected ship ID (string), defaulting toIndustria_Towncar.runDef— the assembledRunDefinitionfor the next mission, ornull.missionResult— theMissionResultfrom the last completed mission, ornull.- The internal
initialStateconstant defining the default values for the three fields above.
READS FROM
RunDefinitiontype from../data/run-config.MissionResulttype from../data/mission-result.HULL_CLASSESroster from../data/ships(used byhydrateFromSaveto validate incoming ship IDs).invokeRpcfrom@metagame/services/supabase(used to persist ship selection).createfromzustand.
PUSHES TO
- Supabase via
invokeRpc('update_player_save', { p_selected_ship_id })inpersistSelection, called fromsetShip. - Subscribers to
useSessionStore(consumers across hub, loadout, game bridge, results screens) via Zustand state updates.
DOES NOT
- Does not persist
runDeformissionResultto the cloud save — only ship selection is persisted. - Does not block the UI on persistence failures;
persistSelectionis fire-and-forget and only logs errors viaconsole.error. - Does not write to the store from
hydrateFromSavewhen the supplied ship ID is missing or not present inHULL_CLASSES— old/removed hull IDs from pre-v2 saves silently fall back to the existing starter default. - Does not reset
selectedShipIdinresetSession; onlyrunDefandmissionResultare cleared between runs. - Does not call the engine, render, or schedule any frame work.
Signals
- State changes to
selectedShipId,runDef, andmissionResultare observed by React components via theuseSessionStorehook. setShiptriggers a side-effect RPC to Supabase to mirror the selection into the player’s cloud save.- Failed cloud-save persistence emits a
console.errorwith the prefixFailed to persist selection to cloud save:.
Entry points
useSessionStore— exported Zustand hook used by React screens and the game bridge to read state and dispatch actions.SessionState— exported interface describing the full store surface (fields plus actions).- Actions on the store:
setShip(id)— setsselectedShipIdand callspersistSelection.setRunDef(def)— setsrunDef.setMissionResult(result)— setsmissionResult, intended for the bridgeonGameOvercallback.resetSession()— clearsrunDefandmissionResultfor a new run cycle.hydrateFromSave(shipId)— setsselectedShipIdonly if the ID is inHULL_CLASSES; used during bootstrap.
Pattern notes
- Single Zustand store created with
create<SessionState>and an initial-state spread, no middleware. - Cloud persistence is colocated in a module-private
persistSelectionhelper rather than a separate service, keeping the store self-contained. hydrateFromSaveuses a roster-membership guard againstHULL_CLASSESto defend at the boundary between cloud save data and the in-memory store (pre-v2 saves with removed hull IDs silently fall back to the default starter).- Action handlers are arrow functions on the store-creator object; only
setis destructured (noget). - Flow comment at the top of the file documents the screen-to-screen contract: Ships writes
selectedShipId, LevelSelect writesselectedNodeIdandassembledRunDef, Game writesmissionResultvia the bridge callback, Results readsmissionResultand clears, Hub resets on enter.