import {createEntityCollection} from "../utils/entity"; import {Part} from "./part"; import {Region} from "./region"; import { Command, CommandRegistry, type CommandRunner, CommandRunnerContext, CommandRunnerContextExport, CommandSchema, createCommandRunnerContext, parseCommandSchema, PromptEvent } from "../utils/command"; import {AsyncQueue} from "../utils/async-queue"; import {signal, Signal} from "@preact/signals-core"; export interface IGameContext = {} > { parts: ReturnType>; regions: ReturnType>; commands: CommandRunnerContextExport>; prompts: AsyncQueue; state: Signal } export function createGameContext = {} >( commandRegistry: CommandRegistry>, initialState?: TState | (() => TState) ): IGameContext { const parts = createEntityCollection(); const regions = createEntityCollection(); const prompts = new AsyncQueue(); const state: TState = typeof initialState === 'function' ? (initialState as (() => TState))() : (initialState ?? {} as TState); const ctx = { parts, regions, prompts, commands: null!, state: signal(state), } as IGameContext ctx.commands = createCommandRunnerContext(commandRegistry, ctx); ctx.commands.on('prompt', (prompt: PromptEvent) => ctx.prompts.push(prompt)); return ctx; } /** * so that we can do `import * as tictactoe from './tic-tac-toe.ts';\n\n createGameContextFromModule(tictactoe);` * @param module */ export function createGameContextFromModule = {} >( module: { registry: CommandRegistry>, createInitialState: () => TState }, ): IGameContext { return createGameContext(module.registry, module.createInitialState); } export function createGameCommand = {} , TResult = unknown>( schema: CommandSchema | string, run: (this: CommandRunnerContext>, command: Command) => Promise ): CommandRunner, TResult> { return { schema: typeof schema === 'string' ? parseCommandSchema(schema) : schema, run, }; }