diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 4abcb18..7cd36c6 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -2789,6 +2789,13 @@ function battleLineColor(line) {
return 'text-text-soft'
}
+function formatLogTime(ms) {
+ const totalSeconds = Math.floor(Number(ms || 0) / 1000)
+ const minutes = String(Math.floor(totalSeconds / 60)).padStart(2, '0')
+ const seconds = String(totalSeconds % 60).padStart(2, '0')
+ return `${minutes}:${seconds}`
+}
+
function deadVehicleKey(uid, cdk) {
return `${String(uid || '').trim()}:${String(cdk || '').trim()}`
}
@@ -2806,16 +2813,61 @@ function deadVehicleKeysFromEventLog(eventLog) {
return keys
}
+function logLookups(participants) {
+ const players = new Map()
+ ;(participants || []).forEach((participant) => {
+ const result = String(participant.result || '').toLowerCase() === 'win' ? 'win' : 'loss'
+ ;(participant.players || []).forEach((player) => {
+ const vehicles = new Map()
+ ;(player.vehicles || []).forEach((vehicle) => {
+ vehicles.set(String(vehicle.cdk || ''), vehicle.name || vehicle.cdk || 'Unknown')
+ })
+ players.set(String(player.uid), {
+ name: player.nick || player.uid,
+ team: participant.team_name || '',
+ result,
+ className: result === 'win' ? 'text-win' : 'text-loss',
+ vehicles,
+ })
+ })
+ })
+ return players
+}
+
+function logPlayer(players, uid) {
+ return players.get(String(uid)) || {
+ name: uid === undefined || uid === null ? 'Unknown' : `Player#${uid}`,
+ team: '',
+ result: '',
+ className: 'text-text-soft',
+ vehicles: new Map(),
+ }
+}
+
+function logVehicle(player, cdk) {
+ if (!cdk) return 'Unknown'
+ return player.vehicles.get(String(cdk)) || String(cdk)
+}
+
+function structuredBattleEvents(eventLog) {
+ const kills = Array.isArray(eventLog?.kills) ? eventLog.kills : []
+ const damage = Array.isArray(eventLog?.damage) ? eventLog.damage : []
+ return [
+ ...kills.map((event) => ({ ...event, kind: 'kill' })),
+ ...damage.map((event) => ({ ...event, kind: 'damage' })),
+ ].sort((a, b) => Number(a.time || 0) - Number(b.time || 0))
+}
+
function GamePage({ gameId, navigate }) {
const [gameState, setGameState] = useState({ status: 'loading', data: null, error: null })
- const [logs, setLogs] = useState({ chat_log: [], battle_log: [], event_log: { kills: [], damage: [] } })
+ const [logs, setLogs] = useState({ chat_log: [], battle_log: [], event_log: { kills: [], damage: [], chat: [] } })
useEffect(() => {
if (!gameId) return
const controller = new AbortController()
setGameState({ status: 'loading', data: null, error: null })
- setLogs({ chat_log: [], battle_log: [], event_log: { kills: [], damage: [] } })
+ setLogs({ chat_log: [], battle_log: [], event_log: { kills: [], damage: [], chat: [] } })
fetchJson(apiEndpoints.game(gameId), controller.signal)
.then((data) => {
@@ -2835,7 +2887,7 @@ function GamePage({ gameId, navigate }) {
setLogs({
chat_log: Array.isArray(data?.chat_log) ? data.chat_log : [],
battle_log: Array.isArray(data?.battle_log) ? data.battle_log : [],
- event_log: data?.event_log || { kills: [], damage: [] },
+ event_log: data?.event_log || { kills: [], damage: [], chat: [] },
})
}
})
@@ -2847,8 +2899,11 @@ function GamePage({ gameId, navigate }) {
}, [gameId])
const game = gameState.data?.game
- const participants = gameState.data?.participants || []
+ const participants = useMemo(() => gameState.data?.participants || [], [gameState.data?.participants])
const deadVehicleKeys = useMemo(() => deadVehicleKeysFromEventLog(logs.event_log), [logs.event_log])
+ const playersByUid = useMemo(() => logLookups(participants), [participants])
+ const battleEvents = useMemo(() => structuredBattleEvents(logs.event_log), [logs.event_log])
+ const chatEvents = Array.isArray(logs.event_log?.chat) ? logs.event_log.chat : []
const participantNames = participants.length
? participants.map((participant) => ({
name: participant.team_name,
@@ -2995,29 +3050,81 @@ function GamePage({ gameId, navigate }) {
- {logs.battle_log.length ? (
+ {battleEvents.length || logs.battle_log.length ? (
Battle Log
Chat Log
-
- {logs.chat_log.join('\n')}
-
+