From b5840d78876217ad502df980ae750378f85b4cb4 Mon Sep 17 00:00:00 2001 From: evanpelle Date: Tue, 9 Jun 2026 19:35:32 -0700 Subject: [PATCH] Fix troop count precision in name labels, throttle/stagger updates Replace the hand-rolled formatTroops() in the name-pass with the canonical renderTroops() so map name labels match troop precision used elsewhere in the UI (Leaderboard, PlayerPanel, etc.). Also refresh each player's troop string at most every 500ms instead of every simulation tick, staggered by slot index so GPU string uploads spread across the window rather than bursting on a single tick. --- .../render/gl/passes/name-pass/TextLayout.ts | 12 --------- .../render/gl/passes/name-pass/Types.ts | 2 ++ .../render/gl/passes/name-pass/index.ts | 25 ++++++++++++------- 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/client/render/gl/passes/name-pass/TextLayout.ts b/src/client/render/gl/passes/name-pass/TextLayout.ts index 6b41dca4e..a5277830a 100644 --- a/src/client/render/gl/passes/name-pass/TextLayout.ts +++ b/src/client/render/gl/passes/name-pass/TextLayout.ts @@ -60,15 +60,3 @@ export function layoutString( return (visualRight - visualLeft) * 0.5; } - -/** Format internal troop count for display (internal values are 10x display). */ -export function formatTroops(internalTroops: number): string { - const troops = internalTroops / 10; - if (troops >= 1_000_000) { - return (troops / 1_000_000).toFixed(1) + "M"; - } - if (troops >= 1_000) { - return (troops / 1_000).toFixed(1) + "K"; - } - return troops.toFixed(0); -} diff --git a/src/client/render/gl/passes/name-pass/Types.ts b/src/client/render/gl/passes/name-pass/Types.ts index 9bacac274..a1b6e8ce4 100644 --- a/src/client/render/gl/passes/name-pass/Types.ts +++ b/src/client/render/gl/passes/name-pass/Types.ts @@ -56,6 +56,8 @@ export interface PlayerSlot { nameLen: number; troopLen: number; lastTroopStr: string; + /** Last 500ms bucket this slot's troop string was refreshed in (staggered per slot). */ + lastTroopBucket: number; /** URL identifying which flag this player wants (dedup key). undefined = none. */ flagUrl: string | undefined; /** Layer index in FlagAtlasArray, or -1 if not loaded yet / no flag. */ diff --git a/src/client/render/gl/passes/name-pass/index.ts b/src/client/render/gl/passes/name-pass/index.ts index e8e7e910c..fd5210e28 100644 --- a/src/client/render/gl/passes/name-pass/index.ts +++ b/src/client/render/gl/passes/name-pass/index.ts @@ -27,6 +27,7 @@ import { PlayerTypeEnum } from "../../../types"; import type { RenderSettings } from "../../RenderSettings"; import { createFullscreenQuad } from "../../utils/GlUtils"; +import { renderTroops } from "../../../../Utils"; import type { GlyphTables } from "./AtlasData"; import { buildEmojiLookup, @@ -44,7 +45,7 @@ import { DebugProgram } from "./DebugProgram"; import { FlagAtlasArray } from "./FlagAtlasArray"; import { IconProgram } from "./IconProgram"; import { StatusIconProgram } from "./StatusIconProgram"; -import { formatTroops, layoutString } from "./TextLayout"; +import { layoutString } from "./TextLayout"; import { TextProgram } from "./TextProgram"; import type { PlayerSlot } from "./Types"; import { LINES_PER_PLAYER, MAX_CHARS } from "./Types"; @@ -279,6 +280,7 @@ export class NamePass { nameLen: 0, troopLen: 0, lastTroopStr: "", + lastTroopBucket: -1, flagUrl: p.flag, flagLayerIdx: -1, emojiAtlasIdx: -1, @@ -336,14 +338,19 @@ export class NamePass { dirty = true; } - // Write troop count string (only if changed) - const troops = troopsByPlayerID.get(playerID) ?? 0; - const troopStr = formatTroops(troops); - if (troopStr !== slot.lastTroopStr) { - slot.troopLen = Math.min(troopStr.length, MAX_CHARS); - slot.lastTroopStr = troopStr; - this.uploadStringRow(slot.index * LINES_PER_PLAYER + 1, troopStr); - dirty = true; + // Write troop count string (refreshed per slot every 500ms, staggered by + // slot index so updates spread across the window instead of bursting). + const troopBucket = Math.floor((now + (slot.index % 5) * 0.1) / 0.5); + if (snap || slot.troopLen === 0 || troopBucket !== slot.lastTroopBucket) { + slot.lastTroopBucket = troopBucket; + const troops = troopsByPlayerID.get(playerID) ?? 0; + const troopStr = renderTroops(troops); + if (troopStr !== slot.lastTroopStr) { + slot.troopLen = Math.min(troopStr.length, MAX_CHARS); + slot.lastTroopStr = troopStr; + this.uploadStringRow(slot.index * LINES_PER_PLAYER + 1, troopStr); + dirty = true; + } } // Check if target position changed — only then recompute lerp source