Add units filter on playeractions for performance (#3213)

## Description:

The ghost structure calls player actions each frame, which is costly
since it's checking for all possible actions.
This add a unit list filter in actions so if there are units it only
checks for buildability of those units.

Before:
![WhatsApp Image 2026-02-14 at 23 25
25](https://github.com/user-attachments/assets/beda6142-9dc7-4a9c-a702-cee3b6ea043c)
Player actions takes 20-30% of the worker

After:
<img width="825" height="342" alt="image"
src="https://github.com/user-attachments/assets/36e47547-5028-4dc9-bc42-e17df4a87200"
/>
Player actions takes 1-3% of the worker


Both performances are relevant only when a ghost structure is selected

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

Mr. Box
This commit is contained in:
Vivacious Box
2026-02-14 19:54:12 -08:00
committed by GitHub
parent 1e5db18885
commit 040766d417
10 changed files with 66 additions and 45 deletions
@@ -138,7 +138,7 @@ export class NukeTrajectoryPreviewLayer implements Layer {
// Get buildable units to find spawn tile (expensive call - only on tick when tile changes)
player
.actions(targetTile)
.actions(targetTile, [ghostStructure])
.then((actions) => {
// Ignore stale results if target changed
if (this.lastTargetTile !== targetTile) {
@@ -285,7 +285,7 @@ export class StructureIconsLayer implements Layer {
this.game
?.myPlayer()
?.actions(tileRef)
?.actions(tileRef, [this.ghostUnit?.buildableUnit.type])
.then((actions) => {
if (this.potentialUpgrade) {
this.potentialUpgrade.iconContainer.filters = [];
+15 -12
View File
@@ -22,6 +22,19 @@ import portIcon from "/images/PortIcon.svg?url";
import samLauncherIcon from "/images/SamLauncherIconWhite.svg?url";
import defensePostIcon from "/images/ShieldIconWhite.svg?url";
const BUILDABLE_UNITS: UnitType[] = [
UnitType.City,
UnitType.Factory,
UnitType.Port,
UnitType.DefensePost,
UnitType.MissileSilo,
UnitType.SAMLauncher,
UnitType.Warship,
UnitType.AtomBomb,
UnitType.HydrogenBomb,
UnitType.MIRV,
];
@customElement("unit-display")
export class UnitDisplay extends LitElement implements Layer {
public game: GameView;
@@ -55,17 +68,7 @@ export class UnitDisplay extends LitElement implements Layer {
}
}
this.allDisabled =
config.isUnitDisabled(UnitType.City) &&
config.isUnitDisabled(UnitType.Factory) &&
config.isUnitDisabled(UnitType.Port) &&
config.isUnitDisabled(UnitType.DefensePost) &&
config.isUnitDisabled(UnitType.MissileSilo) &&
config.isUnitDisabled(UnitType.SAMLauncher) &&
config.isUnitDisabled(UnitType.Warship) &&
config.isUnitDisabled(UnitType.AtomBomb) &&
config.isUnitDisabled(UnitType.HydrogenBomb) &&
config.isUnitDisabled(UnitType.MIRV);
this.allDisabled = BUILDABLE_UNITS.every((u) => config.isUnitDisabled(u));
this.requestUpdate();
}
@@ -101,7 +104,7 @@ export class UnitDisplay extends LitElement implements Layer {
tick() {
const player = this.game?.myPlayer();
player?.actions().then((actions) => {
player?.actions(undefined, BUILDABLE_UNITS).then((actions) => {
this.playerActions = actions;
});
if (!player) return;