import { MutableSignal, mutableSignal } from "@/utils/mutable-signal"; import { CommandSchema, parseCommandSchema, PromptDef } from "@/utils/command"; import { PromptValidator } from "@/utils/command/command-runner"; import { Mulberry32RNG, ReadonlyRNG, RNG } from "@/utils/rng"; import { PromptContext } from "@/utils/command/command-prompt"; export interface IGameContext = {}> { get value(): TState; get rng(): ReadonlyRNG; produce(fn: (draft: TState) => undefined): void; produceAsync(fn: (draft: TState) => undefined): Promise; prompt: ( def: PromptDef, validator: PromptValidator, player?: string, ) => Promise; // test only _state: MutableSignal; _rng: RNG; } export type IGameContextExport = {}> = Omit, "_state" | "_commands" | "_rng">; export function createGameContext = {}>( promptContext: PromptContext, initialState?: TState | (() => TState), ): IGameContext { const stateValue = typeof initialState === "function" ? initialState() : (initialState ?? ({} as TState)); const state = mutableSignal(stateValue); const { prompt } = promptContext; const context: IGameContext = { get value(): TState { return state.value; }, get rng() { return this._rng; }, produce(fn: (draft: TState) => undefined) { return state.produce(fn); }, produceAsync(fn: (draft: TState) => undefined) { return state.produceAsync(fn); }, prompt, _state: state, _rng: new Mulberry32RNG(), }; return context; } export function createPromptDef( schema: CommandSchema | string, hintText?: string, ): PromptDef { schema = typeof schema === "string" ? parseCommandSchema(schema) : schema; return { schema, hintText }; }