refactor: reformat code and fix type signatures in GameHost

Reformat `src/core/game-host.ts` to use double quotes and consistent
spacing. Update `createGameHost` to correctly propagate the `TResult`
generic from `GameModule`.
This commit is contained in:
hypercross 2026-04-19 15:44:59 +08:00
parent 8142fbfa60
commit 1e1d04777f
1 changed files with 165 additions and 157 deletions

View File

@ -1,14 +1,18 @@
import { ReadonlySignal, Signal } from '@preact/signals-core'; import { ReadonlySignal, Signal } from "@preact/signals-core";
import { CommandSchema, CommandRegistry, PromptEvent } from "@/utils/command";
import { import {
CommandSchema, createGameCommandRegistry,
CommandRegistry, createGameContext,
PromptEvent, IGameContext,
} from '@/utils/command'; PromptDef,
import {createGameCommandRegistry, createGameContext, IGameContext, PromptDef} from './game'; } from "./game";
export type GameHostStatus = 'created' | 'running' | 'disposed'; export type GameHostStatus = "created" | "running" | "disposed";
export class GameHost<TState extends Record<string, unknown>, TResult=unknown> { export class GameHost<
TState extends Record<string, unknown>,
TResult = unknown,
> {
readonly state: ReadonlySignal<TState>; readonly state: ReadonlySignal<TState>;
readonly status: ReadonlySignal<GameHostStatus>; readonly status: ReadonlySignal<GameHostStatus>;
readonly activePromptSchema: ReadonlySignal<CommandSchema | null>; readonly activePromptSchema: ReadonlySignal<CommandSchema | null>;
@ -22,13 +26,13 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
private _activePromptPlayer: Signal<string | null>; private _activePromptPlayer: Signal<string | null>;
private _activePromptHint: Signal<string | null>; private _activePromptHint: Signal<string | null>;
private _createInitialState: () => TState; private _createInitialState: () => TState;
private _eventListeners: Map<'start' | 'dispose', Set<() => void>>; private _eventListeners: Map<"start" | "dispose", Set<() => void>>;
private _isDisposed = false; private _isDisposed = false;
constructor( constructor(
registry: CommandRegistry<IGameContext<TState>>, registry: CommandRegistry<IGameContext<TState>>,
createInitialState: () => TState, createInitialState: () => TState,
start: (ctx: IGameContext<TState>) => Promise<TResult> start: (ctx: IGameContext<TState>) => Promise<TResult>,
) { ) {
this._createInitialState = createInitialState; this._createInitialState = createInitialState;
this._eventListeners = new Map(); this._eventListeners = new Map();
@ -38,7 +42,7 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
this._start = start; this._start = start;
this.state = this._context._state; this.state = this._context._state;
this._status = new Signal<GameHostStatus>('created'); this._status = new Signal<GameHostStatus>("created");
this.status = this._status; this.status = this._status;
this._activePromptSchema = new Signal<CommandSchema | null>(null); this._activePromptSchema = new Signal<CommandSchema | null>(null);
@ -56,14 +60,14 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
private _setupPromptTracking() { private _setupPromptTracking() {
let currentPromptEvent: PromptEvent | null = null; let currentPromptEvent: PromptEvent | null = null;
this._context._commands.on('prompt', (e) => { this._context._commands.on("prompt", (e) => {
currentPromptEvent = e as PromptEvent; currentPromptEvent = e as PromptEvent;
this._activePromptSchema.value = currentPromptEvent.schema; this._activePromptSchema.value = currentPromptEvent.schema;
this._activePromptPlayer.value = currentPromptEvent.currentPlayer; this._activePromptPlayer.value = currentPromptEvent.currentPlayer;
this._activePromptHint.value = currentPromptEvent.hintText || null; this._activePromptHint.value = currentPromptEvent.hintText || null;
}); });
this._context._commands.on('promptEnd', () => { this._context._commands.on("promptEnd", () => {
currentPromptEvent = null; currentPromptEvent = null;
this._activePromptSchema.value = null; this._activePromptSchema.value = null;
this._activePromptPlayer.value = null; this._activePromptPlayer.value = null;
@ -78,7 +82,7 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
tryInput(input: string): string | null { tryInput(input: string): string | null {
if (this._isDisposed) { if (this._isDisposed) {
return 'GameHost is disposed'; return "GameHost is disposed";
} }
return this._context._commands._tryCommit(input); return this._context._commands._tryCommit(input);
} }
@ -88,7 +92,7 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
name: def.schema.name, name: def.schema.name,
params: args, params: args,
options: {}, options: {},
flags: {} flags: {},
}); });
} }
@ -110,7 +114,7 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
start(seed?: number): Promise<TResult> { start(seed?: number): Promise<TResult> {
if (this._isDisposed) { if (this._isDisposed) {
throw new Error('GameHost is disposed'); throw new Error("GameHost is disposed");
} }
this._context._commands._cancel(); this._context._commands._cancel();
@ -122,8 +126,8 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
this._context._rng.setSeed(seed); this._context._rng.setSeed(seed);
const promise = this._start(this._context); const promise = this._start(this._context);
this._status.value = 'running'; this._status.value = "running";
this._emitEvent('start'); this._emitEvent("start");
return promise; return promise;
} }
@ -135,14 +139,14 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
this._isDisposed = true; this._isDisposed = true;
this._context._commands._cancel(); this._context._commands._cancel();
this._status.value = 'disposed'; this._status.value = "disposed";
// Emit dispose event BEFORE clearing listeners // Emit dispose event BEFORE clearing listeners
this._emitEvent('dispose'); this._emitEvent("dispose");
this._eventListeners.clear(); this._eventListeners.clear();
} }
on(event: 'start' | 'dispose', listener: () => void): () => void { on(event: "start" | "dispose", listener: () => void): () => void {
if (!this._eventListeners.has(event)) { if (!this._eventListeners.has(event)) {
this._eventListeners.set(event, new Set()); this._eventListeners.set(event, new Set());
} }
@ -153,7 +157,7 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
}; };
} }
private _emitEvent(event: 'start' | 'dispose') { private _emitEvent(event: "start" | "dispose") {
const listeners = this._eventListeners.get(event); const listeners = this._eventListeners.get(event);
if (listeners) { if (listeners) {
for (const listener of listeners) { for (const listener of listeners) {
@ -163,18 +167,22 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
} }
} }
export type GameModule<TState extends Record<string, unknown>, TResult=unknown> = { export type GameModule<
TState extends Record<string, unknown>,
TResult = unknown,
> = {
registry?: CommandRegistry<IGameContext<TState>>; registry?: CommandRegistry<IGameContext<TState>>;
createInitialState: () => TState; createInitialState: () => TState;
start: (ctx: IGameContext<TState>) => Promise<TResult>; start: (ctx: IGameContext<TState>) => Promise<TResult>;
} };
export function createGameHost<TState extends Record<string, unknown>>( export function createGameHost<
gameModule: GameModule<TState> TState extends Record<string, unknown>,
): GameHost<TState> { TResult = unknown,
>(gameModule: GameModule<TState, TResult>): GameHost<TState, TResult> {
return new GameHost( return new GameHost(
gameModule.registry || createGameCommandRegistry(), gameModule.registry || createGameCommandRegistry(),
gameModule.createInitialState, gameModule.createInitialState,
gameModule.start gameModule.start,
); );
} }