fix team names in replay viewer
This commit is contained in:
@@ -132,6 +132,7 @@ class ReplayCanvasEngine {
|
|||||||
|
|
||||||
_buildDOM() {
|
_buildDOM() {
|
||||||
this.container.innerHTML = ''
|
this.container.innerHTML = ''
|
||||||
|
this._panelRows = []
|
||||||
const layout = document.createElement('div')
|
const layout = document.createElement('div')
|
||||||
layout.className = 'rc-layout'
|
layout.className = 'rc-layout'
|
||||||
|
|
||||||
@@ -222,32 +223,28 @@ class ReplayCanvasEngine {
|
|||||||
|
|
||||||
_buildTeamPanel(panel, isWinner) {
|
_buildTeamPanel(panel, isWinner) {
|
||||||
const teamEntities = this.entities.filter((e) => e.playerId > 0 && e.isWinner === isWinner)
|
const teamEntities = this.entities.filter((e) => e.playerId > 0 && e.isWinner === isWinner)
|
||||||
const seen = new Set()
|
// One row per player; a player may have several entities (one per spawn).
|
||||||
const unique = []
|
const byPlayer = new Map()
|
||||||
for (const e of teamEntities) {
|
for (const e of teamEntities) {
|
||||||
if (e.type === 'ground' && !seen.has(e.playerId)) {
|
if (!byPlayer.has(e.playerId)) byPlayer.set(e.playerId, [])
|
||||||
seen.add(e.playerId)
|
byPlayer.get(e.playerId).push(e)
|
||||||
unique.push(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const e of teamEntities) {
|
|
||||||
if (!seen.has(e.playerId)) {
|
|
||||||
seen.add(e.playerId)
|
|
||||||
unique.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 color = isWinner ? RC.WIN : RC.LOSE
|
||||||
const firstPlayer = unique.length ? this.players[unique[0].playerId] : null
|
const firstId = byPlayer.size ? byPlayer.keys().next().value : null
|
||||||
const clanTag = firstPlayer?.clan || ''
|
const firstPlayer = firstId ? this.players[firstId] : null
|
||||||
const label = clanTag ? `<span class="rc-clan-tag">${esc(clanTag)}</span>` : (isWinner ? 'Winners' : 'Losers')
|
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">`
|
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) {
|
for (const [pid, list] of byPlayer) {
|
||||||
const p = this.players[ent.playerId]
|
const p = this.players[pid]
|
||||||
const name = p ? esc(p.name) : '?'
|
const name = p ? esc(p.name) : '?'
|
||||||
|
const ent = list[0]
|
||||||
const veh = esc(ent.vehicleName)
|
const veh = esc(ent.vehicleName)
|
||||||
const panelIcon = ent.miniIcon ? ent.miniIcon.replace('mini:', '') : (ent.iconKey || 'medium')
|
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'">
|
<img class="rc-type-icon" src="/api/icons/type/${panelIcon}" alt="" loading="lazy" onerror="this.style.display='none'">
|
||||||
<div class="rc-row-info">
|
<div class="rc-row-info">
|
||||||
<span class="rc-row-name">${name}</span>
|
<span class="rc-row-name">${name}</span>
|
||||||
@@ -258,13 +255,51 @@ class ReplayCanvasEngine {
|
|||||||
}
|
}
|
||||||
html += '</div>'
|
html += '</div>'
|
||||||
panel.innerHTML = html
|
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', () => {
|
row.addEventListener('mouseenter', () => {
|
||||||
const ent = this.entities.find((e) => e.entityIndex === Number(row.dataset.entityIndex))
|
const ent = pr.currentEntityIndex != null
|
||||||
if (ent && !this._isEntityGone(ent, this.currentTime)) this._setHighlight(Number(row.dataset.playerId))
|
? 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))
|
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() {
|
_buildEventList() {
|
||||||
@@ -402,16 +437,25 @@ class ReplayCanvasEngine {
|
|||||||
|
|
||||||
_updatePanelDeathStates() {
|
_updatePanelDeathStates() {
|
||||||
const t = this.currentTime
|
const t = this.currentTime
|
||||||
this.container.querySelectorAll('.rc-row').forEach((row) => {
|
if (!this._panelRows) return
|
||||||
const ent = this.entities.find((e) => e.entityIndex === Number(row.dataset.entityIndex))
|
for (const pr of this._panelRows) {
|
||||||
if (!ent) return
|
const st = this._playerStateAtTime(pr.entities, t)
|
||||||
const dead = this._isEntityDead(ent, t)
|
pr.currentEntityIndex = st.entity ? st.entity.entityIndex : null
|
||||||
const gone = this._isEntityGone(ent, t)
|
if (st.entity && st.entity.entityIndex !== pr.shownEntityIndex) {
|
||||||
row.classList.toggle('rc-dead', dead)
|
pr.shownEntityIndex = st.entity.entityIndex
|
||||||
row.classList.toggle('rc-gone', gone)
|
if (pr.vehEl) pr.vehEl.textContent = st.entity.vehicleName || ''
|
||||||
const status = row.querySelector('.rc-row-status')
|
if (pr.iconEl) {
|
||||||
status.textContent = dead || gone ? 'x' : ''
|
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() {
|
_updateBattleLog() {
|
||||||
|
|||||||
@@ -524,8 +524,7 @@ h3 {
|
|||||||
|
|
||||||
.rc-layout {
|
.rc-layout {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: minmax(190px, 230px) minmax(560px, 720px) minmax(190px, 230px);
|
grid-template-columns: minmax(160px, 200px) min(720px, 60vh, 92vw) minmax(160px, 200px);
|
||||||
width: min(100%, 1210px);
|
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user