/** * Game-specific metadata types * These extend the base Room/Session types with Settlers of Catan specific data */ import type { Player, Turn, Placements, DevelopmentCard } from './types'; /** * Game-specific session metadata * This is stored in Session.metadata for each session */ export interface GameSessionMetadata { // Player association color?: string; // The color this session is playing as player?: Player; // Reference to the player object // Temporary resources (for trading, etc.) resources?: number; } /** * Game-specific room metadata * This is stored in Room.metadata for the game room */ export interface GameRoomMetadata { // Game data developmentCards: DevelopmentCard[]; players: Record; // Keyed by color unselected?: any[]; // Sessions without color selection active?: number; // Number of active players // Game state rules?: any; step?: number; placements: Placements; turn: Turn; // Board setup pipOrder?: number[]; tileOrder?: number[]; borderOrder?: number[]; tiles?: any[]; pips?: any[]; borders?: any[]; // Game flow dice?: number[]; chat?: any[]; activities?: any[]; playerOrder?: string[]; direction?: string; turns?: number; // Game stats robber?: number; robberName?: string; longestRoad?: string | false; longestRoadLength?: number; largestArmy?: string | false; largestArmySize?: number; mostPorts?: string | false; mostDeveloped?: string | false; // Debug debug?: boolean; signature?: string; animationSeeds?: number[]; // Timers turnTimer?: any; } /** * Helper type for a complete game room */ export type GameRoom = { id: string; name: string; sessions: Record; state: string; created: number; lastActivity: number; private?: boolean; metadata: GameRoomMetadata; }; /** * Helper type for a game session */ export type GameSession = { id: string; userId?: number; name: string | null; ws?: any; live: boolean; lastActive: number; keepAlive?: any; connected: boolean; has_media: boolean; protected?: boolean; bot_run_id?: string | null; bot_provider_id?: string | null; bot_instance_id?: string | null; _initialSnapshotSent?: boolean; _getBatch?: { fields: Set; timer?: any }; _pendingMessage?: any; _pendingTimeout?: any; metadata?: GameSessionMetadata; }; /** * Migration helpers to convert between old and new formats */ /** * Convert old Session to new format */ export function migrateSessionToNewFormat(oldSession: any): GameSession { const { color, player, resources, ...baseFields } = oldSession; return { ...baseFields, has_media: baseFields.has_media ?? true, name: baseFields.name ?? null, live: baseFields.live ?? false, connected: baseFields.connected ?? false, lastActive: baseFields.lastActive ?? Date.now(), metadata: { color, player, resources, }, }; } /** * Convert new Session to old format (for backward compatibility) */ export function migrateSessionToOldFormat(newSession: GameSession): any { const { metadata, ...baseFields } = newSession; return { ...baseFields, color: metadata?.color, player: metadata?.player, resources: metadata?.resources, }; } /** * Convert old Game to new Room format */ export function migrateGameToRoomFormat(oldGame: any): GameRoom { const { sessions, id, ...gameFields } = oldGame; // Convert sessions const newSessions: Record = {}; for (const sessionId in sessions) { newSessions[sessionId] = migrateSessionToNewFormat(sessions[sessionId]); } return { id: oldGame.id, name: oldGame.id, // Game ID is the room name sessions: newSessions, state: oldGame.state || 'lobby', created: Date.now(), lastActivity: Date.now(), private: false, metadata: gameFields, }; } /** * Convert new Room to old Game format (for backward compatibility) */ export function migrateRoomToGameFormat(room: GameRoom): any { const { metadata, sessions, ...roomFields } = room; // Convert sessions back const oldSessions: Record = {}; for (const sessionId in sessions) { oldSessions[sessionId] = migrateSessionToOldFormat(sessions[sessionId]); } return { ...roomFields, ...metadata, sessions: oldSessions, }; }