fix team names in replay viewer

This commit is contained in:
FURRO404
2026-06-18 20:49:50 -07:00
parent fb08e99e5d
commit edf28855b6
2 changed files with 77 additions and 34 deletions
+76 -32
View File
@@ -132,6 +132,7 @@ class ReplayCanvasEngine {
_buildDOM() {
this.container.innerHTML = ''
this._panelRows = []
const layout = document.createElement('div')
layout.className = 'rc-layout'
@@ -222,32 +223,28 @@ class ReplayCanvasEngine {
_buildTeamPanel(panel, isWinner) {
const teamEntities = this.entities.filter((e) => e.playerId > 0 && e.isWinner === isWinner)
const seen = new Set()
const unique = []
// One row per player; a player may have several entities (one per spawn).
const byPlayer = new Map()
for (const e of teamEntities) {
if (e.type === 'ground' && !seen.has(e.playerId)) {
seen.add(e.playerId)
unique.push(e)
}
}
for (const e of teamEntities) {
if (!seen.has(e.playerId)) {
seen.add(e.playerId)
unique.push(e)
}
if (!byPlayer.has(e.playerId)) byPlayer.set(e.playerId, [])
byPlayer.get(e.playerId).push(e)
}
for (const list of byPlayer.values()) list.sort((a, b) => a.times[0] - b.times[0])
const color = isWinner ? RC.WIN : RC.LOSE
const firstPlayer = unique.length ? this.players[unique[0].playerId] : null
const clanTag = firstPlayer?.clan || ''
const label = clanTag ? `<span class="rc-clan-tag">${esc(clanTag)}</span>` : (isWinner ? 'Winners' : 'Losers')
const firstId = byPlayer.size ? byPlayer.keys().next().value : null
const firstPlayer = firstId ? this.players[firstId] : null
const teamSlot = firstPlayer ? firstPlayer.team : (isWinner ? this.data.teamWon : null)
const teamName = teamSlot != null ? this.data.teamNames?.[String(teamSlot)] : ''
const label = teamName ? esc(teamName) : (isWinner ? 'Winners' : 'Losers')
let html = `<div class="rc-panel-head"><span class="rc-panel-label" style="color:${color}">${label}</span></div><div class="rc-panel-list">`
for (const ent of unique) {
const p = this.players[ent.playerId]
for (const [pid, list] of byPlayer) {
const p = this.players[pid]
const name = p ? esc(p.name) : '?'
const ent = list[0]
const veh = esc(ent.vehicleName)
const panelIcon = ent.miniIcon ? ent.miniIcon.replace('mini:', '') : (ent.iconKey || 'medium')
html += `<div class="rc-row" data-player-id="${ent.playerId}" data-entity-index="${ent.entityIndex}">
html += `<div class="rc-row" data-player-id="${pid}">
<img class="rc-type-icon" src="/api/icons/type/${panelIcon}" alt="" loading="lazy" onerror="this.style.display='none'">
<div class="rc-row-info">
<span class="rc-row-name">${name}</span>
@@ -258,13 +255,51 @@ class ReplayCanvasEngine {
}
html += '</div>'
panel.innerHTML = html
panel.querySelectorAll('.rc-row').forEach((row) => {
const rows = panel.querySelectorAll('.rc-row')
let i = 0
for (const [pid, list] of byPlayer) {
const row = rows[i++]
if (!row) continue
const pr = {
row,
playerId: pid,
entities: list,
vehEl: row.querySelector('.rc-row-veh'),
iconEl: row.querySelector('.rc-type-icon'),
statusEl: row.querySelector('.rc-row-status'),
shownEntityIndex: list[0].entityIndex,
currentEntityIndex: list[0].entityIndex,
}
this._panelRows.push(pr)
row.addEventListener('mouseenter', () => {
const ent = this.entities.find((e) => e.entityIndex === Number(row.dataset.entityIndex))
if (ent && !this._isEntityGone(ent, this.currentTime)) this._setHighlight(Number(row.dataset.playerId))
const ent = pr.currentEntityIndex != null
? this.entities.find((e) => e.entityIndex === pr.currentEntityIndex)
: null
if (ent && !this._isEntityGone(ent, this.currentTime)) this._setHighlight(pid)
})
row.addEventListener('mouseleave', () => this._setHighlight(null))
})
}
}
// Resolve which of a player's spawned vehicles is relevant at time t, and
// whether the player is currently alive, down (awaiting respawn), or gone.
_playerStateAtTime(entities, t) {
for (const e of entities) {
const first = e.times[0]
const last = e.times[e.times.length - 1]
if (t >= first && t <= last && !this._isEntityDead(e, t)) {
return { entity: e, dead: false, gone: false }
}
}
let recent = null
for (const e of entities) {
if (e.times[0] <= t && (!recent || e.times[0] >= recent.times[0])) recent = e
}
if (!recent) return { entity: entities[0] || null, dead: false, gone: false }
const hasFutureSpawn = entities.some((e) => e.times[0] > t)
const gone = !hasFutureSpawn && this._isEntityGone(recent, t)
return { entity: recent, dead: true, gone }
}
_buildEventList() {
@@ -402,16 +437,25 @@ class ReplayCanvasEngine {
_updatePanelDeathStates() {
const t = this.currentTime
this.container.querySelectorAll('.rc-row').forEach((row) => {
const ent = this.entities.find((e) => e.entityIndex === Number(row.dataset.entityIndex))
if (!ent) return
const dead = this._isEntityDead(ent, t)
const gone = this._isEntityGone(ent, t)
row.classList.toggle('rc-dead', dead)
row.classList.toggle('rc-gone', gone)
const status = row.querySelector('.rc-row-status')
status.textContent = dead || gone ? 'x' : ''
})
if (!this._panelRows) return
for (const pr of this._panelRows) {
const st = this._playerStateAtTime(pr.entities, t)
pr.currentEntityIndex = st.entity ? st.entity.entityIndex : null
if (st.entity && st.entity.entityIndex !== pr.shownEntityIndex) {
pr.shownEntityIndex = st.entity.entityIndex
if (pr.vehEl) pr.vehEl.textContent = st.entity.vehicleName || ''
if (pr.iconEl) {
const panelIcon = st.entity.miniIcon
? st.entity.miniIcon.replace('mini:', '')
: (st.entity.iconKey || 'medium')
pr.iconEl.src = `/api/icons/type/${panelIcon}`
pr.iconEl.style.display = ''
}
}
pr.row.classList.toggle('rc-dead', st.dead)
pr.row.classList.toggle('rc-gone', st.gone)
if (pr.statusEl) pr.statusEl.textContent = st.dead || st.gone ? 'x' : ''
}
}
_updateBattleLog() {
+1 -2
View File
@@ -524,8 +524,7 @@ h3 {
.rc-layout {
display: grid;
grid-template-columns: minmax(190px, 230px) minmax(560px, 720px) minmax(190px, 230px);
width: min(100%, 1210px);
grid-template-columns: minmax(160px, 200px) min(720px, 60vh, 92vw) minmax(160px, 200px);
gap: 0.5rem;
align-items: start;
justify-content: center;