mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 08:11:54 +00:00
Fix anonymous-names setting not hiding names on the map (#4345)
## Problem Enabling the **hidden names** (anonymous names) setting hid names in the leaderboard/HUD but **not on the map**. The GL name renderer (`NamePass`) drew `slot.static.displayName` — always the real name — and never consulted `userSettings.anonymousNames()`. The HUD works because it calls `PlayerView.displayName()` (which honors the setting) on each render, but the names baked into the GPU texture bypassed that path entirely. ## Fix Push the *resolved* name into the renderer instead of the raw static name: - **`WebGLFrameBuilder.syncPlayers`** registers each player with `displayName: p.displayName()` (honors the setting) instead of `static.displayName`. Covers enabling the setting before a game and players who join after a toggle. - **`WebGLFrameBuilder.refreshNames` → `MapRenderer` → `Renderer` → `NamePass.refreshNames`** is a new path that re-resolves cached names and forces a re-upload (resets `slot.nameLen = 0`, which also recomputes the name half-width so it stays centered). - **`ClientGameRunner`** listens for the `settings.anonymousNames` change event and calls `refreshNames`, mirroring the existing territory-patterns live toggle. ## Behavior - Enabled before a game → players register with anonymous names. - Toggled mid-game → map names flip to/from anonymous on the next sim tick (~100ms), matching the leaderboard. - Your own name is unaffected (unchanged — `PlayerView` maps the local player's anonymous name to their real name). ## Testing `tsc --noEmit` passes for all edited files. This is a WebGL rendering change with no straightforward unit test; verified by tracing the data flow (resolved name → cached `slot.static.displayName` → re-upload on dirty). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -525,6 +525,14 @@ async function createClientGame(
|
|||||||
{ signal: graphicsListenerAbort.signal },
|
{ signal: graphicsListenerAbort.signal },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Re-resolve names drawn on the map when the anonymous-names setting toggles
|
||||||
|
// so they switch live, like the leaderboard.
|
||||||
|
globalThis.addEventListener(
|
||||||
|
`${USER_SETTINGS_CHANGED_EVENT}:settings.anonymousNames`,
|
||||||
|
() => webglBuilder.refreshNames(gameView),
|
||||||
|
{ signal: graphicsListenerAbort.signal },
|
||||||
|
);
|
||||||
|
|
||||||
// Re-resolve settings and copy them onto the renderer's live object in
|
// Re-resolve settings and copy them onto the renderer's live object in
|
||||||
// place (passes hold a reference to it, so they pick the change up).
|
// place (passes hold a reference to it, so they pick the change up).
|
||||||
const regenerateRenderSettings = (): void => {
|
const regenerateRenderSettings = (): void => {
|
||||||
|
|||||||
@@ -70,6 +70,19 @@ export class WebGLFrameBuilder {
|
|||||||
this.view.updatePalette(this.palette);
|
this.view.updatePalette(this.palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-resolve every player's display name (e.g. after toggling the
|
||||||
|
* anonymous-names setting) and push it to the renderer so the names drawn on
|
||||||
|
* the map switch live, matching the leaderboard.
|
||||||
|
*/
|
||||||
|
refreshNames(gameView: GameView): void {
|
||||||
|
const displayNames = new Map<string, string>();
|
||||||
|
for (const p of gameView.players()) {
|
||||||
|
displayNames.set(p.id(), p.displayName());
|
||||||
|
}
|
||||||
|
this.view.refreshNames(displayNames);
|
||||||
|
}
|
||||||
|
|
||||||
update(gameView: GameView): void {
|
update(gameView: GameView): void {
|
||||||
this.syncPlayers(gameView);
|
this.syncPlayers(gameView);
|
||||||
this.syncPlayerSpawns(gameView);
|
this.syncPlayerSpawns(gameView);
|
||||||
@@ -224,6 +237,9 @@ export class WebGLFrameBuilder {
|
|||||||
|
|
||||||
newPlayers.push({
|
newPlayers.push({
|
||||||
...p.static,
|
...p.static,
|
||||||
|
// displayName() honors the anonymous-names setting; static.displayName
|
||||||
|
// is always the real name.
|
||||||
|
displayName: p.displayName(),
|
||||||
flag: flagUrl,
|
flag: flagUrl,
|
||||||
color: p.territoryColor().toHex(),
|
color: p.territoryColor().toHex(),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -163,6 +163,9 @@ export class MapRenderer {
|
|||||||
): void {
|
): void {
|
||||||
this.renderer?.updateNames(names, players, snap, statusData);
|
this.renderer?.updateNames(names, players, snap, statusData);
|
||||||
}
|
}
|
||||||
|
refreshNames(displayNames: Map<string, string>): void {
|
||||||
|
this.renderer?.refreshNames(displayNames);
|
||||||
|
}
|
||||||
updateRelations(data: Uint8Array, size: number): void {
|
updateRelations(data: Uint8Array, size: number): void {
|
||||||
this.renderer?.updateRelations(data, size);
|
this.renderer?.updateRelations(data, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -779,6 +779,11 @@ export class GPURenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Re-resolve player name strings live (e.g. anonymous-names toggle). */
|
||||||
|
refreshNames(displayNames: Map<string, string>): void {
|
||||||
|
this.namePass.refreshNames(displayNames);
|
||||||
|
}
|
||||||
|
|
||||||
updateRelations(data: Uint8Array, size: number): void {
|
updateRelations(data: Uint8Array, size: number): void {
|
||||||
this.borderPass.updateRelations(data, size);
|
this.borderPass.updateRelations(data, size);
|
||||||
this.affiliationPalette.updateRelations(data, size);
|
this.affiliationPalette.updateRelations(data, size);
|
||||||
|
|||||||
@@ -244,6 +244,22 @@ export class NamePass {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace cached name strings (e.g. after the anonymous-names setting toggles)
|
||||||
|
* and force a re-upload on the next updateNames pass. slot.static is the same
|
||||||
|
* object as the playerByID entry, so updating displayName here is what the
|
||||||
|
* nameLen === 0 re-upload branch reads.
|
||||||
|
*/
|
||||||
|
refreshNames(displayNames: Map<string, string>): void {
|
||||||
|
for (const [id, name] of displayNames) {
|
||||||
|
const p = this.playerByID.get(id);
|
||||||
|
if (p === undefined) continue;
|
||||||
|
p.displayName = name;
|
||||||
|
const slot = this.slots.get(id);
|
||||||
|
if (slot !== undefined) slot.nameLen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request the texture layer for a slot's flag (called once at slot creation).
|
* Request the texture layer for a slot's flag (called once at slot creation).
|
||||||
* If the image is already loaded the layer index is set immediately; otherwise
|
* If the image is already loaded the layer index is set immediately; otherwise
|
||||||
|
|||||||
Reference in New Issue
Block a user