mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-25 09:14:37 +00:00
Big Water-Nukes Performance Improvements 💧 (#3668)
## Description: ### 1. Water Magnitude Calculation Optimization (WaterManager.ts) * Boxed BFS Approach: Refactored the water magnitude recomputation to use "Dirty" and "Seed" boxes. Instead of a global update, the system now only recalculates magnitudes within a specific radius of the affected area, significantly reducing CPU load after water-nuke-explosions * Shoreline Bit Optimization: Narrowed the scope for updating shoreline bits to a 2-ring neighborhood around converted tiles, avoiding unnecessary checks across the entire map. Performance test on the world map: - AtomBomb (r=30): 24ms (was 344ms with global BFS), 2,993 changed tiles (was 630k) - Massive (r=200): 178ms (was 378ms), 130k changed tiles (was 654k) ### 2. Pathfinding Rebuild Staggering (PathFinder.ts, TradeShipExecution.ts, TransportShipExecution.ts) * Distributed Rebuilds: Introduced a staggering mechanism in WaterPathFinder. Ship pathfinders now wait a randomized/distributed number of ticks (0 - 5 seconds) before rebuilding after a water graph change. * CPU Spike Mitigation: By spreading out these expensive A* rebuilds over time, we prevent lag when hundreds of ships attempt to re-path simultaneously * Like Mole said it: "Pretty realistic I;d say the capitan needs a second to realize the big nuke on the left opened a new path" From a performance test on the big new Luna map: Graph rebuild: 256.4ms Pathfinder-Rebuild of 329 ships (Including other Executions): 1564.4ms (No longer noticeable, spread over 5s) ### 3. Performance Refinements * Simplified deep ocean magnitude logic within the optimized BFS flow. * Improved memory efficiency by utilizing clipped BFS wavefronts. ## 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: FloPinguin
This commit is contained in:
@@ -98,11 +98,28 @@ export class WaterPathFinder implements SteppingPathFinder<TileRef> {
|
||||
private _waterGraphVersion: number;
|
||||
private _rebuilt = false;
|
||||
|
||||
constructor(private game: Game) {
|
||||
// Stagger support: spread pathfinder rebuilds over multiple ticks so all
|
||||
// ships don't re-run A* simultaneously after a water-nuke.
|
||||
private _staggerCountdown: number;
|
||||
private _pendingVersion: number = -1;
|
||||
|
||||
/**
|
||||
* @param stagger - How many ticks to wait before rebuilding when the water
|
||||
* graph changes. 0 = immediate (default). Pass a value spread across
|
||||
* [0, STAGGER_SPREAD) to distribute rebuilds over time.
|
||||
*/
|
||||
constructor(
|
||||
private game: Game,
|
||||
private _stagger: number = 0,
|
||||
) {
|
||||
this.inner = PathFinding.Water(game);
|
||||
this._waterGraphVersion = game.waterGraphVersion();
|
||||
this._staggerCountdown = 0;
|
||||
}
|
||||
|
||||
/** Spread to use when auto-staggering ship pathfinders */
|
||||
static readonly STAGGER_SPREAD = 50;
|
||||
|
||||
/** True if the pathfinder was rebuilt since the last call to `rebuilt`. Resets on read. */
|
||||
get rebuilt(): boolean {
|
||||
this.ensureFresh();
|
||||
@@ -113,11 +130,23 @@ export class WaterPathFinder implements SteppingPathFinder<TileRef> {
|
||||
|
||||
private ensureFresh(): void {
|
||||
const v = this.game.waterGraphVersion();
|
||||
if (v !== this._waterGraphVersion) {
|
||||
this._waterGraphVersion = v;
|
||||
this.inner = PathFinding.Water(this.game);
|
||||
this._rebuilt = true;
|
||||
if (v === this._waterGraphVersion) return;
|
||||
|
||||
// New graph version detected — start or continue the stagger countdown.
|
||||
if (this._pendingVersion !== v) {
|
||||
this._pendingVersion = v;
|
||||
this._staggerCountdown = this._stagger;
|
||||
}
|
||||
|
||||
if (this._staggerCountdown > 0) {
|
||||
this._staggerCountdown--;
|
||||
return; // Keep using old pathfinder for now
|
||||
}
|
||||
|
||||
// Countdown complete — rebuild.
|
||||
this._waterGraphVersion = v;
|
||||
this.inner = PathFinding.Water(this.game);
|
||||
this._rebuilt = true;
|
||||
}
|
||||
|
||||
next(from: TileRef, to: TileRef, dist?: number): PathResult<TileRef> {
|
||||
|
||||
Reference in New Issue
Block a user