feat(games): add GamePlugin interface and registry
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
18
shared/games/registry.ts
Normal file
18
shared/games/registry.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import type { GamePlugin } from "./types";
|
||||||
|
|
||||||
|
const games = new Map<string, GamePlugin>();
|
||||||
|
|
||||||
|
export const gameRegistry = {
|
||||||
|
register(plugin: GamePlugin) {
|
||||||
|
if (games.has(plugin.slug)) {
|
||||||
|
throw new Error(`Game "${plugin.slug}" is already registered`);
|
||||||
|
}
|
||||||
|
games.set(plugin.slug, plugin);
|
||||||
|
},
|
||||||
|
get(slug: string): GamePlugin | undefined {
|
||||||
|
return games.get(slug);
|
||||||
|
},
|
||||||
|
list(): GamePlugin[] {
|
||||||
|
return Array.from(games.values());
|
||||||
|
},
|
||||||
|
};
|
||||||
23
shared/games/types.ts
Normal file
23
shared/games/types.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
export interface GamePlugin<TState = unknown, TAction = unknown> {
|
||||||
|
slug: string;
|
||||||
|
name: string;
|
||||||
|
minPlayers: number;
|
||||||
|
maxPlayers: number;
|
||||||
|
|
||||||
|
createInitialState(players: string[]): TState;
|
||||||
|
handleAction(state: TState, action: TAction, playerId: string): GameResult<TState>;
|
||||||
|
getPlayerView(state: TState, playerId: string): unknown;
|
||||||
|
getSpectatorView(state: TState): unknown;
|
||||||
|
|
||||||
|
isGameOver?(state: TState): GameOverResult | null;
|
||||||
|
onPlayerDisconnect?(state: TState, playerId: string): TState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GameResult<TState> =
|
||||||
|
| { ok: true; state: TState }
|
||||||
|
| { ok: false; error: string };
|
||||||
|
|
||||||
|
export type GameOverResult = {
|
||||||
|
winner: string | null;
|
||||||
|
reason: string;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user