- Creado nuevo proyecto Nuxt 4 con estructura app/ - Servidor Colyseus separado para evitar problemas con decoradores - Migrado GameRoom y toda la lógica del juego - Implementado cliente con composables useGameClient - Panel de administración funcional - Componentes Vue migrados (HomeScreen, GameScreen, PlayerCard, etc) - Configuración para ejecutar ambos servidores (npm run dev:all)
214 lines
5.7 KiB
TypeScript
214 lines
5.7 KiB
TypeScript
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<string, Player>
|
|
activeTradeOffers: TradeOffer[]
|
|
round: number
|
|
gamePhase: string
|
|
gameStarted: boolean
|
|
minPlayers: number
|
|
maxPlayers: number
|
|
}
|
|
|
|
export const useGameClient = () => {
|
|
const client = ref<Client | null>(null)
|
|
const room = ref<Room | null>(null)
|
|
const gameState = ref<GameState | null>(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
|
|
}
|
|
} |