mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-23 21:26:39 +00:00
feat(livestats): per-player killedBy + deathPosition + winner for live standings (#4593)
## Description: Enriches the admin-bot live-stats snapshot (`/api/adminbot/game/:id/stats`) with the per-player fields a semi-live standings board needs, so it can score kills + placement live instead of waiting for the post-game record. Per player in `liveStats.players[]`: - **`killedBy`** — the eliminator's clientID (null while alive / non-client killer). Invert → live kill points. - **`deathPosition`** — finishing place at elimination = non-bot players still standing + 1 (frozen at "last of the then-standing"). Null while alive → live placement. The **full roster** is reported (dead players are retained in the client view), plus top-level **`winner`** (the decided winner's clientID, else null). Deterministic / consensus-safe: `killedBy` (stamped at `recordKill`) and `deathPosition` (stamped in `PlayerExecution`) are pure sim values, so in-sync clients agree on the majority vote; `winner` is added server-side in `GameServer.liveStats()` from the winner vote (like the existing publicID/username/connected enrichment). ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory
This commit is contained in:
@@ -44,6 +44,8 @@ export function diffPlayerUpdate(
|
||||
prev.playerType === next.playerType &&
|
||||
prev.isAlive === next.isAlive &&
|
||||
prev.isDisconnected === next.isDisconnected &&
|
||||
prev.killedBy === next.killedBy &&
|
||||
prev.deathPosition === next.deathPosition &&
|
||||
prev.isTraitor === next.isTraitor &&
|
||||
prev.traitorRemainingTicks === next.traitorRemainingTicks &&
|
||||
prev.inDoomsdayClock === next.inDoomsdayClock &&
|
||||
@@ -89,6 +91,8 @@ export function diffPlayerUpdate(
|
||||
setIfDifferent("playerType", prev.playerType === next.playerType);
|
||||
setIfDifferent("isAlive", prev.isAlive === next.isAlive);
|
||||
setIfDifferent("isDisconnected", prev.isDisconnected === next.isDisconnected);
|
||||
setIfDifferent("killedBy", prev.killedBy === next.killedBy);
|
||||
setIfDifferent("deathPosition", prev.deathPosition === next.deathPosition);
|
||||
// tilesOwned / gold / troops intentionally absent — see EXCEPTION above.
|
||||
setIfDifferent("isTraitor", prev.isTraitor === next.isTraitor);
|
||||
setIfDifferent(
|
||||
@@ -157,6 +161,8 @@ export function applyStateUpdate(target: PlayerState, pu: PlayerUpdate): void {
|
||||
if (pu.isAlive !== undefined) target.isAlive = pu.isAlive;
|
||||
if (pu.isDisconnected !== undefined)
|
||||
target.isDisconnected = pu.isDisconnected;
|
||||
if (pu.killedBy !== undefined) target.killedBy = pu.killedBy;
|
||||
if (pu.deathPosition !== undefined) target.deathPosition = pu.deathPosition;
|
||||
if (pu.tilesOwned !== undefined) target.tilesOwned = pu.tilesOwned;
|
||||
if (pu.gold !== undefined) target.gold = Number(pu.gold);
|
||||
if (pu.troops !== undefined) target.troops = pu.troops;
|
||||
|
||||
Reference in New Issue
Block a user