From c8a42d4c331ce231b6db185e9d3bc5035d64732b Mon Sep 17 00:00:00 2001 From: Zixer1 <99333209+Zixer1@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:44:51 -0400 Subject: [PATCH] feat: include publicID in admin-bot live stats players (#4404) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: The live stats endpoint enriches each player with username/connected but not publicId, so an account-keyed caller (e.g. an admin bot, which knows players by account, not per-session clientID) can't map a stats row back to a player directly. Add publicId from the same activeClients source — mirrors the kick_player targetPublicID path. ## 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 ## Please put your Discord username so you can be contacted if a bug or regression is found: zixer._ --- src/server/GameServer.ts | 15 ++++++++++----- tests/server/LiveStats.test.ts | 27 ++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/server/GameServer.ts b/src/server/GameServer.ts index 0fa7e9d71..c304d0ecc 100644 --- a/src/server/GameServer.ts +++ b/src/server/GameServer.ts @@ -1419,6 +1419,7 @@ export class GameServer { turn: number; players: (PlayerLiveStats & { username: string | null; + publicID: string | null; connected: boolean; })[]; } | null { @@ -1427,11 +1428,15 @@ export class GameServer { } return { turn: this.latestLiveStats.turn, - players: this.latestLiveStats.players.map((p) => ({ - ...p, - username: this.allClients.get(p.clientID)?.username ?? null, - connected: !this.isClientDisconnected(p.clientID), - })), + players: this.latestLiveStats.players.map((p) => { + const client = this.allClients.get(p.clientID); + return { + ...p, + username: client?.username ?? null, + publicID: client?.publicId ?? null, + connected: !this.isClientDisconnected(p.clientID), + }; + }), }; } } diff --git a/tests/server/LiveStats.test.ts b/tests/server/LiveStats.test.ts index 5e519ba04..03bf62471 100644 --- a/tests/server/LiveStats.test.ts +++ b/tests/server/LiveStats.test.ts @@ -24,7 +24,13 @@ describe("GameServer.handleLiveStats", () => { }); function makeClient(clientID: string, ip: string, username: string) { - return { clientID, ip, persistentID: `pid-${clientID}`, username } as any; + return { + clientID, + ip, + persistentID: `pid-${clientID}`, + username, + publicId: clientID.replace("client", "public"), // 8-char ID, e.g. public01 + } as any; } // A GameServer with three distinct-IP active clients wired up. @@ -83,7 +89,14 @@ describe("GameServer.handleLiveStats", () => { // 2 of 3 IPs -> consensus. expect(game.liveStats()).toEqual({ turn: 100, - players: [{ ...players[0], username: "Alice", connected: true }], + players: [ + { + ...players[0], + username: "Alice", + publicID: "public01", + connected: true, + }, + ], }); }); @@ -138,7 +151,14 @@ describe("GameServer.handleLiveStats", () => { report(game, clients[1], 200, snapshot(42)); expect(game.liveStats()).toEqual({ turn: 200, - players: [{ ...snapshot(42)[0], username: "Alice", connected: true }], + players: [ + { + ...snapshot(42)[0], + username: "Alice", + publicID: "public01", + connected: true, + }, + ], }); }); @@ -204,6 +224,7 @@ describe("admin bot stats endpoint", () => { isAlive: true, team: null, username: "Alice", + publicID: "public01", connected: true, }, ],