From b6596c88ee5fcbdc2fccdb36512e79607d2a5539 Mon Sep 17 00:00:00 2001 From: DevelopingTom Date: Wed, 28 May 2025 06:43:33 +0200 Subject: [PATCH] Improve territory drawing performances (#696) ## Description: Territory drawing are computing the same information for each pixel drawn. A few fixes can noticably improve the performances: ### Caching colors some colors are computed each time they are retrieved, and according to the profiler the border color is the most expensive to compute each frame: ![image](https://github.com/user-attachments/assets/147c2e9d-0ce2-4859-92de-c6f99b763642) This PR adds a cache for this color. The other colors have almost no impact on performance, so there's no need to cache them. After caching: ![image](https://github.com/user-attachments/assets/7b2601b2-19c9-4535-8315-6b2fe328731f) ### Retrieving player info Drawing the player territory leads to unecessary and expensive data gathering, such as the anonymous name list: ![442410324-2e7dbcc9-e7ba-4051-b38f-3ae57cb072e8](https://github.com/user-attachments/assets/67894616-ecec-4748-85f9-9f665c58aab1) Instead, after retrieving the proper data directly: ![442410386-0eaffd72-045d-40b7-96c3-e04030de3d40](https://github.com/user-attachments/assets/ff59f988-9f80-4f52-b972-a155d6ae94dd) ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [x] I understand that submitting code with bugs that could have been caught through manual testing blocks releases and new features for all contributors ## Please put your Discord username so you can be contacted if a bug or regression is found: IngloriousTom --- src/core/configuration/DefaultConfig.ts | 10 +++++++--- src/core/configuration/PastelTheme.ts | 23 +++++++++++++++-------- src/core/configuration/PastelThemeDark.ts | 23 +++++++++++++++-------- src/core/game/GameView.ts | 4 ++-- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index dd88cca52..cdd5d7205 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -23,8 +23,8 @@ import { UserSettings } from "../game/UserSettings"; import { GameConfig, GameID } from "../Schemas"; import { assertNever, simpleHash, within } from "../Util"; import { Config, GameEnv, NukeMagnitude, ServerConfig, Theme } from "./Config"; -import { pastelTheme } from "./PastelTheme"; -import { pastelThemeDark } from "./PastelThemeDark"; +import { PastelTheme } from "./PastelTheme"; +import { PastelThemeDark } from "./PastelThemeDark"; const JwksSchema = z.object({ keys: z @@ -165,6 +165,8 @@ export abstract class DefaultServerConfig implements ServerConfig { } export class DefaultConfig implements Config { + private pastelTheme: PastelTheme = new PastelTheme(); + private pastelThemeDark: PastelThemeDark = new PastelThemeDark(); constructor( private _serverConfig: ServerConfig, private _gameConfig: GameConfig, @@ -460,7 +462,9 @@ export class DefaultConfig implements Config { return this.bots(); } theme(): Theme { - return this.userSettings()?.darkMode() ? pastelThemeDark : pastelTheme; + return this.userSettings()?.darkMode() + ? this.pastelThemeDark + : this.pastelTheme; } attackLogic( diff --git a/src/core/configuration/PastelTheme.ts b/src/core/configuration/PastelTheme.ts index 4527f6162..8846348d0 100644 --- a/src/core/configuration/PastelTheme.ts +++ b/src/core/configuration/PastelTheme.ts @@ -19,7 +19,10 @@ import { } from "./Colors"; import { Theme } from "./Config"; -export const pastelTheme = new (class implements Theme { +type ColorCache = Map; + +export class PastelTheme implements Theme { + private borderColorCache: ColorCache = new Map(); private rand = new PseudoRandom(123); private background = colord({ r: 60, g: 60, b: 60 }); @@ -69,19 +72,17 @@ export const pastelTheme = new (class implements Theme { if (team !== null) { return this.teamColor(team); } - if (player.info().playerType === PlayerType.Human) { + if (player.type() === PlayerType.Human) { return humanColors[simpleHash(player.id()) % humanColors.length]; } - if (player.info().playerType === PlayerType.Bot) { + if (player.type() === PlayerType.Bot) { return botColors[simpleHash(player.id()) % botColors.length]; } return territoryColors[simpleHash(player.id()) % territoryColors.length]; } textColor(player: PlayerView): string { - return player.info().playerType === PlayerType.Human - ? "#000000" - : "#4D4D4D"; + return player.type() === PlayerType.Human ? "#000000" : "#4D4D4D"; } specialBuildingColor(player: PlayerView): Colord { @@ -94,12 +95,18 @@ export const pastelTheme = new (class implements Theme { } borderColor(player: PlayerView): Colord { + if (this.borderColorCache.has(player.id())) { + return this.borderColorCache.get(player.id())!; + } const tc = this.territoryColor(player).rgba; - return colord({ + const color = colord({ r: Math.max(tc.r - 40, 0), g: Math.max(tc.g - 40, 0), b: Math.max(tc.b - 40, 0), }); + + this.borderColorCache.set(player.id(), color); + return color; } defendedBorderColors(player: PlayerView): { light: Colord; dark: Colord } { @@ -177,4 +184,4 @@ export const pastelTheme = new (class implements Theme { spawnHighlightColor(): Colord { return this._spawnHighlightColor; } -})(); +} diff --git a/src/core/configuration/PastelThemeDark.ts b/src/core/configuration/PastelThemeDark.ts index 050bfa807..3d428c447 100644 --- a/src/core/configuration/PastelThemeDark.ts +++ b/src/core/configuration/PastelThemeDark.ts @@ -19,7 +19,10 @@ import { } from "./Colors"; import { Theme } from "./Config"; -export const pastelThemeDark = new (class implements Theme { +type ColorCache = Map; + +export class PastelThemeDark implements Theme { + private borderColorCache: ColorCache = new Map(); private rand = new PseudoRandom(123); private background = colord({ r: 0, g: 0, b: 0 }); @@ -69,19 +72,17 @@ export const pastelThemeDark = new (class implements Theme { if (team !== null) { return this.teamColor(team); } - if (player.info().playerType === PlayerType.Human) { + if (player.type() === PlayerType.Human) { return humanColors[simpleHash(player.id()) % humanColors.length]; } - if (player.info().playerType === PlayerType.Bot) { + if (player.type() === PlayerType.Bot) { return botColors[simpleHash(player.id()) % botColors.length]; } return territoryColors[simpleHash(player.id()) % territoryColors.length]; } textColor(player: PlayerView): string { - return player.info().playerType === PlayerType.Human - ? "#ffffff" - : "#e6e6e6"; + return player.type() === PlayerType.Human ? "#ffffff" : "#e6e6e6"; } specialBuildingColor(player: PlayerView): Colord { @@ -94,12 +95,18 @@ export const pastelThemeDark = new (class implements Theme { } borderColor(player: PlayerView): Colord { + if (this.borderColorCache.has(player.id())) { + return this.borderColorCache.get(player.id())!; + } const tc = this.territoryColor(player).rgba; - return colord({ + const color = colord({ r: Math.max(tc.r - 40, 0), g: Math.max(tc.g - 40, 0), b: Math.max(tc.b - 40, 0), }); + + this.borderColorCache.set(player.id(), color); + return color; } defendedBorderColors(player: PlayerView): { light: Colord; dark: Colord } { @@ -179,4 +186,4 @@ export const pastelThemeDark = new (class implements Theme { spawnHighlightColor(): Colord { return this._spawnHighlightColor; } -})(); +} diff --git a/src/core/game/GameView.ts b/src/core/game/GameView.ts index ab570918e..b32170dc7 100644 --- a/src/core/game/GameView.ts +++ b/src/core/game/GameView.ts @@ -182,12 +182,12 @@ export class PlayerView { return this.data.flag; } name(): string { - return userSettings.anonymousNames() && this.anonymousName !== null + return this.anonymousName !== null && userSettings.anonymousNames() ? this.anonymousName : this.data.name; } displayName(): string { - return userSettings.anonymousNames() && this.anonymousName !== null + return this.anonymousName !== null && userSettings.anonymousNames() ? this.anonymousName : this.data.name; }