import { Client, Room } from 'colyseus.js' import { ref, reactive } from 'vue' export interface TokenInventory { turkey: number coffee: number corn: number } export interface TradeOffer { id: string offererId: string targetId: string offering: TokenInventory requesting: TokenInventory status: string } export interface Player { id: string name: string producerRole: string tokens: TokenInventory points: number shameTokens: number isSuspended: boolean role: string } export interface GameState { players: Map activeTradeOffers: TradeOffer[] round: number gamePhase: string gameStarted: boolean minPlayers: number maxPlayers: number } export const useGameClient = () => { const client = ref(null) const room = ref(null) const gameState = ref(null) const currentPlayerId = ref('') const isConnected = ref(false) const connectionStatus = ref('') // Event callbacks const onStateChangeCallbacks = ref<((state: GameState) => void)[]>([]) const onGamePhaseChangeCallbacks = ref<((phase: string) => void)[]>([]) const onAdminKickedCallbacks = ref<((data: any) => void)[]>([]) const onRoundChangedCallbacks = ref<((data: any) => void)[]>([]) const connect = async (playerName: string, gameMode: string = 'classic') => { try { connectionStatus.value = 'Conectando...' // Use runtime config for WebSocket URL const config = useRuntimeConfig() const wsUrl = config.public.wsUrl || 'ws://localhost:2567' client.value = new Client(wsUrl) console.log('Connecting to:', wsUrl) room.value = await client.value.joinOrCreate('game', { playerName, gameMode }) currentPlayerId.value = room.value.sessionId isConnected.value = true connectionStatus.value = 'Conectado exitosamente!' console.log('Successfully joined room:', room.value.id) console.log('Player ID:', currentPlayerId.value) // Setup event listeners room.value.onStateChange((state) => { console.log('State changed:', state) const previousPhase = gameState.value?.gamePhase gameState.value = state // Notify all state change callbacks onStateChangeCallbacks.value.forEach(callback => callback(state)) // Notify phase change if it changed if (previousPhase !== state.gamePhase) { console.log('Game phase changed:', previousPhase, '->', state.gamePhase) onGamePhaseChangeCallbacks.value.forEach(callback => callback(state.gamePhase)) } }) room.value.onMessage('adminKicked', (data) => { console.log('Admin kicked:', data) onAdminKickedCallbacks.value.forEach(callback => callback(data)) }) room.value.onMessage('roundChanged', (data) => { console.log('Round changed:', data) onRoundChangedCallbacks.value.forEach(callback => callback(data)) }) room.value.onMessage('gamePaused', (data) => { console.log('Game paused:', data) alert(`⏸️ ${data.message}`) }) room.value.onMessage('gameResumed', (data) => { console.log('Game resumed:', data) alert(`▶️ ${data.message}`) }) room.value.onLeave((code) => { console.log('Left room with code:', code) isConnected.value = false connectionStatus.value = 'Desconectado' // Handle forced disconnect by admin if (code === 4000) { console.log('Disconnected by admin (code 4000)') } }) room.value.onError((code, message) => { console.error('Room error:', code, message) connectionStatus.value = `Error: ${message}` }) return room.value } catch (error) { console.error('Failed to connect:', error) connectionStatus.value = 'Error de conexión: ' + (error as Error).message throw error } } const disconnect = () => { if (room.value) { room.value.leave() room.value = null } client.value = null isConnected.value = false gameState.value = null currentPlayerId.value = '' connectionStatus.value = 'Desconectado' } const makeOffer = (targetId: string, offering: TokenInventory, requesting: TokenInventory) => { if (!room.value) return room.value.send('makeOffer', { targetId, offering, requesting }) } const respondToOffer = (offerId: string, response: 'accept' | 'reject' | 'snatch') => { if (!room.value) return room.value.send('respondToOffer', { offerId, response }) } const cancelOffer = (offerId: string) => { if (!room.value) return room.value.send('cancelOffer', { offerId }) } const onStateChange = (callback: (state: GameState) => void) => { onStateChangeCallbacks.value.push(callback) } const onGamePhaseChange = (callback: (phase: string) => void) => { onGamePhaseChangeCallbacks.value.push(callback) } const onAdminKicked = (callback: (data: any) => void) => { onAdminKickedCallbacks.value.push(callback) } const onRoundChanged = (callback: (data: any) => void) => { onRoundChangedCallbacks.value.push(callback) } return { // State client: readonly(client), room: readonly(room), gameState: readonly(gameState), currentPlayerId: readonly(currentPlayerId), isConnected: readonly(isConnected), connectionStatus: readonly(connectionStatus), // Methods connect, disconnect, makeOffer, respondToOffer, cancelOffer, // Event handlers onStateChange, onGamePhaseChange, onAdminKicked, onRoundChanged } }