mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-19 08:35:14 +00:00
Perf alloc (#3241)
If this PR fixes an issue, link it below. If not, delete these two lines. Resolves #(issue number) ## Description: ## PR Title perf(core): reduce hot-path allocations & safe optimizations This PR brings in a set of allocation-focused optimizations in core hot paths ### Scope - `src/core/execution/NukeExecution.ts` - `src/core/execution/WarshipExecution.ts` - `src/core/game/UnitGrid.ts` - `src/core/game/PlayerImpl.ts` - `src/core/configuration/DefaultConfig.ts` - `src/core/execution/SAMLauncherExecution.ts` ### What Changed - `NukeExecution.detonate`: reduced call overhead/allocations by caching `mg`/`config`, avoiding repeated lookups, and using allocation-free loops (no `forEach` closures) in the diminishing-effect pass. - `WarshipExecution.findTargetUnit`: replaced allocate+sort flow with single-pass best-target selection. - `UnitGrid.nearbyUnits`: reduced call overhead and allocations via single-type fast path and cached query coordinates. - `PlayerImpl.units`: added fast paths for common small-arity type queries (1-3 unit types). - `DefaultConfig.unitInfo`: cached `UnitInfo` objects per `UnitType` to avoid repeated object/closure creation. - `SAMLauncherExecution` targeting: removed sort churn and streamlined target selection with single-pass hydrogen prioritization. ### Rebase - One conflict was resolved in `NukeExecution.detonate` by keeping `main`'s diminishing-effect-per-impacted-tile behavior, while retaining the allocation-reduction refactors. ## Please complete the following: - [ ] I have added screenshots for all UI updates - [ ] I process any text displayed to the user through translateText() and I've added it to the en.json file - [ ] I have added relevant tests to the test directory - [ ] 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: DISCORD_USERNAME
This commit is contained in:
@@ -252,28 +252,31 @@ export class NukeExecution implements Execution {
|
||||
throw new Error("Not initialized");
|
||||
}
|
||||
|
||||
const magnitude = this.mg.config().nukeMagnitudes(this.nuke.type());
|
||||
const mg = this.mg;
|
||||
const config = mg.config();
|
||||
|
||||
const magnitude = config.nukeMagnitudes(this.nuke.type());
|
||||
const toDestroy = this.tilesToDestroy();
|
||||
|
||||
// Retrieve all impacted players and the number of tiles
|
||||
const tilesPerPlayers = new Map<Player, number>();
|
||||
for (const tile of toDestroy) {
|
||||
const owner = this.mg.owner(tile);
|
||||
const owner = mg.owner(tile);
|
||||
if (owner.isPlayer()) {
|
||||
owner.relinquish(tile);
|
||||
const numTiles = tilesPerPlayers.get(owner);
|
||||
tilesPerPlayers.set(owner, numTiles === undefined ? 1 : numTiles + 1);
|
||||
tilesPerPlayers.set(owner, (tilesPerPlayers.get(owner) ?? 0) + 1);
|
||||
}
|
||||
if (this.mg.isLand(tile)) {
|
||||
this.mg.setFallout(tile, true);
|
||||
|
||||
if (mg.isLand(tile)) {
|
||||
mg.setFallout(tile, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Then compute the explosion effect on each player
|
||||
for (const [player, numImpactedTiles] of tilesPerPlayers) {
|
||||
const config = this.mg.config();
|
||||
const tilesBeforeNuke = player.numTilesOwned() + numImpactedTiles;
|
||||
const transportShips = player.units(UnitType.TransportShip);
|
||||
const outgoingAttacks = player.outgoingAttacks();
|
||||
const maxTroops = config.maxTroops(player);
|
||||
// nukeDeathFactor could compute the complete fallout in a single call instead
|
||||
for (let i = 0; i < numImpactedTiles; i++) {
|
||||
@@ -287,39 +290,45 @@ export class NukeExecution implements Execution {
|
||||
maxTroops,
|
||||
),
|
||||
);
|
||||
player.outgoingAttacks().forEach((attack) => {
|
||||
for (const attack of outgoingAttacks) {
|
||||
const attackTroops = attack.troops();
|
||||
const deaths = config.nukeDeathFactor(
|
||||
this.nukeType,
|
||||
attack.troops(),
|
||||
attackTroops,
|
||||
numTilesLeft,
|
||||
maxTroops,
|
||||
);
|
||||
attack.setTroops(attack.troops() - deaths);
|
||||
});
|
||||
transportShips.forEach((unit) => {
|
||||
attack.setTroops(attackTroops - deaths);
|
||||
}
|
||||
for (const unit of transportShips) {
|
||||
const unitTroops = unit.troops();
|
||||
const deaths = config.nukeDeathFactor(
|
||||
this.nukeType,
|
||||
unit.troops(),
|
||||
unitTroops,
|
||||
numTilesLeft,
|
||||
maxTroops,
|
||||
);
|
||||
unit.setTroops(unit.troops() - deaths);
|
||||
});
|
||||
unit.setTroops(unitTroops - deaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const outer2 = magnitude.outer * magnitude.outer;
|
||||
for (const unit of this.mg.units()) {
|
||||
const dst = this.dst;
|
||||
const destroyer = this.player;
|
||||
for (const unit of mg.units()) {
|
||||
const type = unit.type();
|
||||
if (
|
||||
unit.type() !== UnitType.AtomBomb &&
|
||||
unit.type() !== UnitType.HydrogenBomb &&
|
||||
unit.type() !== UnitType.MIRVWarhead &&
|
||||
unit.type() !== UnitType.MIRV &&
|
||||
unit.type() !== UnitType.SAMMissile
|
||||
type === UnitType.AtomBomb ||
|
||||
type === UnitType.HydrogenBomb ||
|
||||
type === UnitType.MIRVWarhead ||
|
||||
type === UnitType.MIRV ||
|
||||
type === UnitType.SAMMissile
|
||||
) {
|
||||
if (this.mg.euclideanDistSquared(this.dst, unit.tile()) < outer2) {
|
||||
unit.delete(true, this.player);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (mg.euclideanDistSquared(dst, unit.tile()) < outer2) {
|
||||
unit.delete(true, destroyer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user