Fix cluster deletion (#3185)

## Description:

When a train station is removed, the clusters are recomputed. However
the cluster recomputation code has not been changed from the original
rail network implementation, which was a tree.

The deletion code made assumptions that are not true anymore since we
introduced loops in the network. As a result the cluster recomputation
was very inefficient, although the data was correct.

Changes:
- Fix clusters computation when a structure is deleted

- Structures are frequently deleted in bulk: atom/hydro/MIRV.
Re-computing the clusters when a single structure is deleted would be
inefficient because the recomputed cluster would probably need to be
recomputed again in the same tick.
Instead, when a structure is deleted, flag the cluster as "dirty", and
recompute all the dirty clusters once per tick only.

Previous performances (hydro over a dense area):
<img width="700" height="160" alt="image"
src="https://github.com/user-attachments/assets/cd3ceb42-6d5f-4ad1-b35a-f8e5e0513821"
/>


Now:
<img width="450" height="269" alt="image"
src="https://github.com/user-attachments/assets/55dec3b9-8619-4a6c-9a16-f5368fe40da1"
/>

## 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:

IngloriousTom
This commit is contained in:
DevelopingTom
2026-02-12 15:00:56 -08:00
committed by GitHub
parent cb6e97ed11
commit a1b3afe534
5 changed files with 66 additions and 15 deletions
+7
View File
@@ -1,6 +1,7 @@
import { placeName } from "../client/graphics/NameBoxCalculator";
import { getConfig } from "./configuration/ConfigLoader";
import { Executor } from "./execution/ExecutionManager";
import { RecomputeRailClusterExecution } from "./execution/RecomputeRailClusterExecution";
import { WinCheckExecution } from "./execution/WinCheckExecution";
import {
AllPlayers,
@@ -16,6 +17,7 @@ import {
PlayerInfo,
PlayerProfile,
PlayerType,
UnitType,
} from "./game/Game";
import { createGame } from "./game/GameImpl";
import { TileRef } from "./game/GameMap";
@@ -105,6 +107,11 @@ export class GameRunner {
this.game.addExecution(...this.execManager.nationExecutions());
}
this.game.addExecution(new WinCheckExecution());
if (!this.game.config().isUnitDisabled(UnitType.Factory)) {
this.game.addExecution(
new RecomputeRailClusterExecution(this.game.railNetwork()),
);
}
}
public addTurn(turn: Turn): void {