Pre-combat-improvements: Combat animations, flee fixes, corpse logic updates

This commit is contained in:
Joan
2026-02-03 19:48:37 +01:00
parent 0b0a23f500
commit e6747b1d05
29 changed files with 827 additions and 243 deletions

View File

@@ -105,6 +105,7 @@ export interface GameEngineActions {
// Interactions
handleInteract: (interactableId: string, actionId: string) => Promise<void>
handleViewCorpseDetails: (corpseId: string) => Promise<void>
handleCloseCorpseDetails: () => void
handleLootCorpse: (corpseId: string) => Promise<void>
handleLootCorpseItem: (corpseId: string, itemIndex: number | null) => Promise<void>
@@ -1046,6 +1047,10 @@ export function useGameEngine(
handleFlee,
handleInteract,
handleViewCorpseDetails,
handleCloseCorpseDetails: () => {
setExpandedCorpse(null)
setCorpseDetails(null)
},
handleLootCorpse,
handleLootCorpseItem,
handleSpendPoint,
@@ -1084,6 +1089,31 @@ export function useGameEngine(
}
}
// Polling fallback for PvP Combat reliability
// Polling fallback for PvP Combat reliability
// optimized: poll less frequently (15s) and rely on WS reconnect event
useEffect(() => {
// 1. Listen for WebSocket reconnection to fetch immediately
const handleReconnect = () => {
console.log("[PvP] WebSocket reconnected, fetching fresh state...");
fetchGameData(true);
};
window.addEventListener('game-ws-connected', handleReconnect);
// 2. Slow polling as safety net
let interval: ReturnType<typeof setInterval> | null = null;
if (combatState?.is_pvp && !combatState?.combat_over) {
interval = setInterval(() => {
fetchGameData(true);
}, 15000); // Poll every 15s instead of 3s
}
return () => {
window.removeEventListener('game-ws-connected', handleReconnect);
if (interval) clearInterval(interval);
};
}, [combatState?.is_pvp, combatState?.combat_over, fetchGameData]);
// Initial data load
useEffect(() => {
if (token) {
@@ -1091,51 +1121,22 @@ export function useGameEngine(
}
}, [token])
// WebSocket connection
// WebSocket Event Bus Listener
// Instead of maintaining a second connection, we listen to the global connection managed by GameHeader
useEffect(() => {
if (!token) return
// Get WebSocket URL based on environment (same logic as api.ts)
const API_BASE = import.meta.env.VITE_API_URL || (
import.meta.env.PROD
? 'https://api-staging.echoesoftheash.com'
: 'http://localhost:8000'
)
const wsBase = API_BASE.replace(/^http/, 'ws')
const wsUrl = `${wsBase}/ws/game/${token}`
console.log('🔌 Connecting to WebSocket:', wsUrl)
const ws = new WebSocket(wsUrl)
ws.onopen = () => {
console.log('✅ WebSocket connection established')
setWebSocket(ws)
}
ws.onmessage = (event) => {
try {
const message = JSON.parse(event.data)
_handleWebSocketMessage(message)
} catch (err) {
console.error('Failed to parse WebSocket message:', err)
const handleGameMessage = (event: Event) => {
const customEvent = event as CustomEvent;
if (customEvent.detail) {
_handleWebSocketMessage(customEvent.detail);
}
}
};
ws.onerror = (error) => {
console.error('❌ WebSocket error:', error)
}
ws.onclose = () => {
console.log('🔌 WebSocket disconnected')
setWebSocket(null)
}
window.addEventListener('game-ws-message', handleGameMessage);
return () => {
if (ws.readyState === WebSocket.OPEN) {
ws.close()
}
}
}, [token]) // Removed _handleWebSocketMessage from dependencies
window.removeEventListener('game-ws-message', handleGameMessage);
};
}, [_handleWebSocketMessage]);
return [state, actions]
}