Files
snatchgame/nuxt-snatchgame/app/composables/useGameClient.ts
josedario87 62226ab5d4
Some checks failed
build-and-deploy / filter (push) Successful in 3s
build-and-deploy / build (push) Failing after 6s
build-and-deploy / deploy (push) Has been skipped
feat: Migración completa de SnatchGame a Nuxt 4
- 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)
2025-08-05 16:05:51 -06:00

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
}
}