From 8b66c8bd53b78cb66fe3df2a93ecdca89fc432d2 Mon Sep 17 00:00:00 2001 From: VariableVince <24507472+VariableVince@users.noreply.github.com> Date: Wed, 18 Feb 2026 23:43:16 +0100 Subject: [PATCH] Perf/refactor: use StructureTypes, remove territoryBound (#3238) ## Description: PR 6/x in effort to break up PR https://github.com/openfrontio/OpenFrontIO/pull/3220. Follows on already merged https://github.com/openfrontio/OpenFrontIO/pull/3237. Please see if these can be merged for v30. - **PlayerImpl**: validStructureSpawnTiles did a filter on unit types to get isTerroritoryBound units, on every call again. It read this from unit info in DefaultConfig. While having it centrally in DefaultConfig unitInfo is good for maintainability, other code uses hardcoded StructureTypes and isisStructureType from Game.ts. Which has the same purpose and thus contains the same unit types. StructureTypes and isisStructureType do need manual maintainance outside of DefaultConfig. And are more bug prone/less type safe. But, using them gives more speed compared to getting these unit types out of DefaultConfig unitInfo centrally with some cached function in GameImpl for example (tested with buildableUnits and MIRVPerf.ts). So I went with StructureTypes in validStructureSpawnTiles too. - **PlayerExecution**: now validStructureSpawnTiles no longer needs isTerritoryBound (see the point above), PlayerExecution is the last place where it was used. Replaced it for isStructureType here too (since it has the same meaning and outcome). - **Game.ts** and **DefaultConfig** unitInfo: remove the now unused _territoryBound_. As it was only used in validStructureSpawnTiles and PlayerExecution and has been replaced in both (see the two points above). ## 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 - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: tryout33 --- src/core/configuration/DefaultConfig.ts | 16 ---------------- src/core/execution/PlayerExecution.ts | 11 +++++++++-- src/core/game/Game.ts | 2 -- src/core/game/PlayerImpl.ts | 5 +---- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index 7cf070af0..f60159d64 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -327,7 +327,6 @@ export class DefaultConfig implements Config { case UnitType.TransportShip: return { cost: () => 0n, - territoryBound: false, }; case UnitType.Warship: return { @@ -335,19 +334,16 @@ export class DefaultConfig implements Config { (numUnits: number) => Math.min(1_000_000, (numUnits + 1) * 250_000), UnitType.Warship, ), - territoryBound: false, maxHealth: 1000, }; case UnitType.Shell: return { cost: () => 0n, - territoryBound: false, damage: 250, }; case UnitType.SAMMissile: return { cost: () => 0n, - territoryBound: false, }; case UnitType.Port: return { @@ -357,19 +353,16 @@ export class DefaultConfig implements Config { UnitType.Port, UnitType.Factory, ), - territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 2 * 10, upgradable: true, }; case UnitType.AtomBomb: return { cost: this.costWrapper(() => 750_000, UnitType.AtomBomb), - territoryBound: false, }; case UnitType.HydrogenBomb: return { cost: this.costWrapper(() => 5_000_000, UnitType.HydrogenBomb), - territoryBound: false, }; case UnitType.MIRV: return { @@ -379,22 +372,18 @@ export class DefaultConfig implements Config { } return 25_000_000n + game.stats().numMirvsLaunched() * 15_000_000n; }, - territoryBound: false, }; case UnitType.MIRVWarhead: return { cost: () => 0n, - territoryBound: false, }; case UnitType.TradeShip: return { cost: () => 0n, - territoryBound: false, }; case UnitType.MissileSilo: return { cost: this.costWrapper(() => 1_000_000, UnitType.MissileSilo), - territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 10 * 10, upgradable: true, }; @@ -404,7 +393,6 @@ export class DefaultConfig implements Config { (numUnits: number) => Math.min(250_000, (numUnits + 1) * 50_000), UnitType.DefensePost, ), - territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 5 * 10, }; case UnitType.SAMLauncher: @@ -414,7 +402,6 @@ export class DefaultConfig implements Config { Math.min(3_000_000, (numUnits + 1) * 1_500_000), UnitType.SAMLauncher, ), - territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 30 * 10, upgradable: true, }; @@ -425,7 +412,6 @@ export class DefaultConfig implements Config { Math.min(1_000_000, Math.pow(2, numUnits) * 125_000), UnitType.City, ), - territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 2 * 10, upgradable: true, }; @@ -437,14 +423,12 @@ export class DefaultConfig implements Config { UnitType.Factory, UnitType.Port, ), - territoryBound: true, constructionDuration: this.instantBuild() ? 0 : 2 * 10, upgradable: true, }; case UnitType.Train: return { cost: () => 0n, - territoryBound: false, }; default: assertNever(type); diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index 1e9ae4a10..35799a781 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -1,5 +1,12 @@ import { Config } from "../configuration/Config"; -import { Cell, Execution, Game, Player, UnitType } from "../game/Game"; +import { + Cell, + Execution, + Game, + isStructureType, + Player, + UnitType, +} from "../game/Game"; import { TileRef } from "../game/GameMap"; import { calculateBoundingBox, getMode, inscribed, simpleHash } from "../Util"; @@ -35,7 +42,7 @@ export class PlayerExecution implements Execution { tick(ticks: number) { this.player.decayRelations(); for (const u of this.player.units()) { - if (!u.info().territoryBound) { + if (!isStructureType(u.type())) { continue; } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 26395acf5..91f635af8 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -227,8 +227,6 @@ export interface PublicGameModifiers { export interface UnitInfo { cost: (game: Game, player: Player) => Gold; - // Determines if its owner changes when its tile is conquered. - territoryBound: boolean; maxHealth?: number; damage?: number; constructionDuration?: number; diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 4d6fabc56..7cb6e689c 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -1151,14 +1151,11 @@ export class PlayerImpl implements Player { } const searchRadius = 15; const searchRadiusSquared = searchRadius ** 2; - const types = Object.values(UnitType).filter((unitTypeValue) => { - return this.mg.config().unitInfo(unitTypeValue).territoryBound; - }); const nearbyUnits = this.mg.nearbyUnits( tile, searchRadius * 2, - types, + StructureTypes, undefined, true, );