2026-04-03 14:17:36 +08:00
|
|
|
import {MutableSignal, mutableSignal} from "@/utils/mutable-signal";
|
2026-04-02 10:48:20 +08:00
|
|
|
import {
|
|
|
|
|
Command,
|
|
|
|
|
CommandRegistry,
|
2026-04-02 14:11:35 +08:00
|
|
|
CommandRunnerContext,
|
2026-04-02 14:39:30 +08:00
|
|
|
CommandRunnerContextExport,
|
|
|
|
|
CommandSchema,
|
|
|
|
|
createCommandRegistry,
|
|
|
|
|
createCommandRunnerContext,
|
|
|
|
|
parseCommandSchema,
|
|
|
|
|
registerCommand
|
2026-04-02 15:59:27 +08:00
|
|
|
} from "@/utils/command";
|
2026-04-04 11:06:41 +08:00
|
|
|
import type { GameModule } from './game-host';
|
2026-04-02 10:26:42 +08:00
|
|
|
|
2026-04-02 12:53:49 +08:00
|
|
|
export interface IGameContext<TState extends Record<string, unknown> = {} > {
|
2026-04-03 14:17:36 +08:00
|
|
|
state: MutableSignal<TState>;
|
|
|
|
|
commands: CommandRunnerContextExport<MutableSignal<TState>>;
|
2026-04-02 10:26:42 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-02 12:53:49 +08:00
|
|
|
export function createGameContext<TState extends Record<string, unknown> = {} >(
|
2026-04-03 14:17:36 +08:00
|
|
|
commandRegistry: CommandRegistry<MutableSignal<TState>>,
|
2026-04-02 12:48:29 +08:00
|
|
|
initialState?: TState | (() => TState)
|
|
|
|
|
): IGameContext<TState> {
|
2026-04-02 14:39:30 +08:00
|
|
|
const stateValue = typeof initialState === 'function' ? initialState() : initialState ?? {} as TState;
|
2026-04-03 14:17:36 +08:00
|
|
|
const state = mutableSignal(stateValue);
|
2026-04-02 14:39:30 +08:00
|
|
|
const commands = createCommandRunnerContext(commandRegistry, state);
|
2026-04-02 12:48:29 +08:00
|
|
|
|
2026-04-02 14:39:30 +08:00
|
|
|
return {
|
|
|
|
|
state,
|
|
|
|
|
commands
|
|
|
|
|
};
|
2026-04-02 10:48:20 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-02 12:48:29 +08:00
|
|
|
/**
|
|
|
|
|
* so that we can do `import * as tictactoe from './tic-tac-toe.ts';\n\n createGameContextFromModule(tictactoe);`
|
|
|
|
|
* @param module
|
|
|
|
|
*/
|
2026-04-02 12:53:49 +08:00
|
|
|
export function createGameContextFromModule<TState extends Record<string, unknown> = {} >(
|
2026-04-02 12:48:29 +08:00
|
|
|
module: {
|
2026-04-03 14:17:36 +08:00
|
|
|
registry: CommandRegistry<MutableSignal<TState>>,
|
2026-04-02 12:48:29 +08:00
|
|
|
createInitialState: () => TState
|
|
|
|
|
},
|
|
|
|
|
): IGameContext<TState> {
|
|
|
|
|
return createGameContext(module.registry, module.createInitialState);
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 14:39:30 +08:00
|
|
|
export function createGameCommandRegistry<TState extends Record<string, unknown> = {} >() {
|
2026-04-03 14:17:36 +08:00
|
|
|
const registry = createCommandRegistry<MutableSignal<TState>>();
|
2026-04-02 14:39:30 +08:00
|
|
|
return {
|
|
|
|
|
registry,
|
|
|
|
|
add<TResult = unknown>(
|
|
|
|
|
schema: CommandSchema | string,
|
2026-04-03 14:17:36 +08:00
|
|
|
run: (this: CommandRunnerContext<MutableSignal<TState>>, command: Command) => Promise<TResult>
|
2026-04-02 14:39:30 +08:00
|
|
|
){
|
|
|
|
|
createGameCommand(registry, schema, run);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-02 13:52:15 +08:00
|
|
|
}
|
|
|
|
|
|
2026-04-02 12:53:49 +08:00
|
|
|
export function createGameCommand<TState extends Record<string, unknown> = {} , TResult = unknown>(
|
2026-04-03 14:17:36 +08:00
|
|
|
registry: CommandRegistry<MutableSignal<TState>>,
|
2026-04-02 10:48:20 +08:00
|
|
|
schema: CommandSchema | string,
|
2026-04-03 14:17:36 +08:00
|
|
|
run: (this: CommandRunnerContext<MutableSignal<TState>>, command: Command) => Promise<TResult>
|
2026-04-02 14:11:35 +08:00
|
|
|
) {
|
|
|
|
|
registerCommand(registry, {
|
2026-04-02 10:48:20 +08:00
|
|
|
schema: typeof schema === 'string' ? parseCommandSchema(schema) : schema,
|
|
|
|
|
run,
|
2026-04-02 14:11:35 +08:00
|
|
|
});
|
2026-04-04 00:54:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export { GameHost, createGameHost } from './game-host';
|
2026-04-04 14:05:23 +08:00
|
|
|
export type { GameHostStatus, GameModule } from './game-host';
|
2026-04-04 11:06:41 +08:00
|
|
|
|
|
|
|
|
export function createGameModule<TState extends Record<string, unknown>>(
|
|
|
|
|
module: GameModule<TState>
|
|
|
|
|
): GameModule<TState> {
|
|
|
|
|
return module;
|
|
|
|
|
}
|