1
0

195 lines
5.4 KiB
TypeScript

/**
* 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';
import type { Session } from '../room/types';
/**
* Proxy handler for Session objects
* Intercepts property access to provide backward compatibility
* Maps session.color -> session.metadata.color, etc.
*/
const sessionProxyHandler: ProxyHandler<GameSession> = {
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<GameRoom> = {
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<string, GameSession> = {};
for (const id in game.sessions) {
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;
}