/** * Game Adapter - Provides backward compatibility layer * This allows existing game code to work with the new Room/Session architecture * without requiring immediate refactoring of all game logic */ import type { GameRoom, GameSession, GameSessionMetadata } from "./gameMetadata"; /** * Proxy handler for Session objects * Intercepts property access to provide backward compatibility * Maps session.color -> session.metadata.color, etc. */ const sessionProxyHandler: ProxyHandler = { get(target: GameSession, prop: string | symbol): any { // Direct properties take precedence if (prop in target && prop !== "metadata") { return (target as any)[prop]; } // Map game-specific properties to metadata if (typeof prop === "string") { const gameProps = ["color", "player", "resources"]; if (gameProps.includes(prop)) { return target.metadata?.[prop as keyof GameSessionMetadata]; } } return (target as any)[prop]; }, set(target: GameSession, prop: string | symbol, value: any): boolean { // Direct properties const directProps = [ "id", "userId", "name", "ws", "live", "lastActive", "keepAlive", "connected", "has_media", "protected", "bot_run_id", "bot_provider_id", "bot_instance_id", "_initialSnapshotSent", "_getBatch", "_pendingMessage", "_pendingTimeout", ]; if (typeof prop === "string" && directProps.includes(prop)) { (target as any)[prop] = value; return true; } // Game-specific properties go to metadata if (typeof prop === "string") { const gameProps = ["color", "player", "resources"]; if (gameProps.includes(prop)) { if (!target.metadata) { target.metadata = {}; } (target.metadata as any)[prop] = value; return true; } } // Unknown properties (target as any)[prop] = value; return true; }, has(target: GameSession, prop: string | symbol): boolean { if (prop in target) return true; if (typeof prop === "string") { const gameProps = ["color", "player", "resources"]; return gameProps.includes(prop) && target.metadata !== undefined; } return false; }, }; /** * Proxy handler for Game/Room objects * Maps game.players -> game.metadata.players, etc. */ const gameProxyHandler: ProxyHandler = { get(target: GameRoom, prop: string | symbol): any { // Direct room properties const roomProps = ["id", "name", "sessions", "state", "created", "lastActivity", "private"]; if (typeof prop === "string" && roomProps.includes(prop)) { return (target as any)[prop]; } // Game properties from metadata if (typeof prop === "string" && target.metadata) { if (prop in target.metadata) { return (target.metadata as any)[prop]; } } return (target as any)[prop]; }, set(target: GameRoom, prop: string | symbol, value: any): boolean { // Direct room properties const roomProps = ["id", "name", "sessions", "state", "created", "lastActivity", "private"]; if (typeof prop === "string" && roomProps.includes(prop)) { (target as any)[prop] = value; return true; } // Game properties to metadata if (typeof prop === "string") { if (!target.metadata) { target.metadata = {} as any; } (target.metadata as any)[prop] = value; return true; } (target as any)[prop] = value; return true; }, has(target: GameRoom, prop: string | symbol): boolean { const roomProps = ["id", "name", "sessions", "state", "created", "lastActivity", "private"]; if (typeof prop === "string") { if (roomProps.includes(prop)) return true; if (target.metadata && prop in target.metadata) return true; } return false; }, }; /** * Wrap a session object with backward compatibility proxy */ export function wrapSession(session: GameSession): GameSession { return new Proxy(session, sessionProxyHandler); } /** * Wrap a game/room object with backward compatibility proxy */ export function wrapGame(game: GameRoom): GameRoom { return new Proxy(game, gameProxyHandler); } /** * Wrap all sessions in a game/room */ export function wrapGameSessions(game: GameRoom): GameRoom { const wrappedGame = wrapGame(game); // Wrap each session const wrappedSessions: Record = {}; for (const id in game.sessions) { if (game.sessions[id]) { wrappedSessions[id] = wrapSession(game.sessions[id]); } } wrappedGame.sessions = wrappedSessions; return wrappedGame; } /** * Initialize metadata for a session if it doesn't exist */ export function ensureSessionMetadata(session: GameSession): void { if (!session.metadata) { session.metadata = {}; } } /** * Initialize metadata for a game/room if it doesn't exist */ export function ensureGameMetadata(game: GameRoom): void { if (!game.metadata) { game.metadata = { developmentCards: [], players: {}, placements: { corners: [], roads: [] }, turn: {}, } as any; } } /** * Helper to access session's game metadata safely */ export function getSessionGameData(session: GameSession): GameSessionMetadata { ensureSessionMetadata(session); return session.metadata!; } /** * Helper to access game's metadata safely */ export function getGameMetadata(game: GameRoom) { ensureGameMetadata(game); return game.metadata; }