Constants
createHistory
const createHistory: CreateHistory
From @phaser-ae/kernel
Make a history over deterministic rules. See HistorySpec.
Types
Applied
type Applied<R> = { readonly ok: true; readonly result: R } | Refusal
From @phaser-ae/kernel
What a history reports for a move: accepted with whatever the rules returned, or refused.
CreateHistory
type CreateHistory = <S, M, R = unknown>(spec: HistorySpec<S, M, R>) => History<S, M, R>
From @phaser-ae/kernel
Make a history over deterministic rules. See HistorySpec.
History
interface History<S, M, R = unknown>
From @phaser-ae/kernel
A run of play that can be wound back and forth, saved and restored.
readonly state: S— The state as it now stands, afterindexmoves. The live object: read it, and change it only throughapply.readonly seed: number— The seed this run started from.readonly moves: ReadonlyArray<M>— The moves recorded, oldest first. Includes any ahead ofindexthat a redo would reach.readonly index: number— How many moves ofmoveshave been applied: the playhead.readonly canUndo: boolean— Is there anything to undo?readonly canRedo: boolean— Is there anything to redo?apply(move: M): Applied<R>— Apply a move and record it. Anything undone and not yet redone is discarded first, because play has branched. A refused move changes nothing and is not recorded.undo(): boolean— Wind back one move. False when there was nothing to undo.redo(): Applied<R>— Wind forward one undone move and report what the rules returned. Refused when there is nothing to redo.seek(index: number): void— Wind to exactlyindexmoves played, forwards or backwards. Clamped to the recorded range.reset(seed?: number): void— Start again on a fresh state, from a new seed or the same one, with no moves.snapshot(): HistorySave<M>— The run as a save. SeeHistorySave.restore(save: HistorySave<M> | string): Applied<void>— Replace this run with a save, or its JSON text. The save is replayed into a fresh state first and checked; if it is not a history, a move is refused, or the fingerprint differs, this run is left exactly as it was.
HistorySave
interface HistorySave<M>
From @phaser-ae/kernel
A history as a save: plain JSON, safe to store, share or put in a bug report.
readonly format: 'phaser-ae-history'— Always 'phaser-ae-history'.readonly version: 1— Always 1.readonly seed: number— The seed the run started from.readonly moves: ReadonlyArray<M>— Every recorded move, oldest first, including any a redo would reach.readonly index: number— How many ofmoveswere applied: where the playhead was.readonly fingerprint?: string— The state's fingerprint atindex, when the spec hasfingerprint.
HistorySpec
interface HistorySpec<S, M, R = unknown>
From @phaser-ae/kernel
How to build a run of play from nothing and push it forward one move.
create(seed: number): S— A fresh state from a seed. It must be pure in the seed: the same seed gives the same state every time, or undo lands somewhere the player has never been. UsecreateRng(seed)for any chance inside it.apply(state: S, move: M): R | Refusal— Apply one move tostate, in place. Return anything to accept it: the value comes back fromapplyandredo(a presenter animates from it). Return aRefusal,{ ok: false, reason }, to refuse it, and leave the state unchanged. An exception is a refusal too, with its message as the reason.seed?: number— The seed to start from. Default 0. Take it fromgame.rng(game.rng.int(0, 0xffffffff)) so a game replays.checkpointEvery?: number— Keep a copy of the state every this many moves, so undo and seek replay from the nearest copy instead of from the start. Default 0: never, which suits rules that replay in microseconds. Copies are made withclone.clone?(state: S): S— Copy a state, for checkpoints. DefaultstructuredClone, which cannot copy functions or class methods.limit?: number— The most moves to record. Past it a move is refused (history: limit reached) rather than an old one dropped, because dropping one would leave undo unable to rebuild the state. Default unlimited.merge?(previous: M, next: M): M | undefined— Fold a move into the one before it, so they undo as one: return the combined move, or undefined to record them apart. Asked only after the new move was accepted, and only when it would be recorded straight afterprevious. The classic use is time: two{ kind: 'advance', seconds }moves in a row become one, provided the rules step a fixed timestep so that advancing a then b lands where advancing a + b does.fingerprint?(state: S): string— A short fingerprint of a state, such as a hash of its JSON. When given, a save carries the fingerprint of the state it ends in, andrestorerefuses a save whose replay ends anywhere else: a check that the rules really are deterministic and the save was not edited.onChange?(history: History<S, M, R>): void— Called after anything changes the state or the moves: an apply, undo, redo, seek, reset or restore.
Refusal
interface Refusal
From @phaser-ae/kernel
A move the rules refused. Nothing is recorded, and the rules must leave the state exactly as it was.
readonly ok: false— Always false.readonly reason: string— Why, in words a player could be shown.
