mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-16 20:52:25 +00:00
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:  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:
@@ -195,13 +195,14 @@ export class GameRunner {
|
||||
playerID: PlayerID,
|
||||
x?: number,
|
||||
y?: number,
|
||||
units?: UnitType[],
|
||||
): PlayerActions {
|
||||
const player = this.game.player(playerID);
|
||||
const tile =
|
||||
x !== undefined && y !== undefined ? this.game.ref(x, y) : null;
|
||||
const actions = {
|
||||
canAttack: tile !== null && player.canAttack(tile),
|
||||
buildableUnits: player.buildableUnits(tile),
|
||||
canAttack: tile !== null && units === undefined && player.canAttack(tile),
|
||||
buildableUnits: player.buildableUnits(tile, units),
|
||||
canSendEmojiAllPlayers: player.canSendEmoji(AllPlayers),
|
||||
canEmbargoAll: player.canEmbargoAll(),
|
||||
} as PlayerActions;
|
||||
|
||||
@@ -627,7 +627,7 @@ export interface Player {
|
||||
unitCount(type: UnitType): number;
|
||||
unitsConstructed(type: UnitType): number;
|
||||
unitsOwned(type: UnitType): number;
|
||||
buildableUnits(tile: TileRef | null): BuildableUnit[];
|
||||
buildableUnits(tile: TileRef | null, units?: UnitType[]): BuildableUnit[];
|
||||
canBuild(type: UnitType, targetTile: TileRef): TileRef | false;
|
||||
buildUnit<T extends UnitType>(
|
||||
type: T,
|
||||
|
||||
@@ -403,11 +403,12 @@ export class PlayerView {
|
||||
return { hasEmbargo, hasFriendly };
|
||||
}
|
||||
|
||||
async actions(tile?: TileRef): Promise<PlayerActions> {
|
||||
async actions(tile?: TileRef, units?: UnitType[]): Promise<PlayerActions> {
|
||||
return this.game.worker.playerInteraction(
|
||||
this.id(),
|
||||
tile && this.game.x(tile),
|
||||
tile && this.game.y(tile),
|
||||
units,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+34
-24
@@ -22,6 +22,7 @@ import {
|
||||
EmojiMessage,
|
||||
GameMode,
|
||||
Gold,
|
||||
isStructureType,
|
||||
MessageType,
|
||||
MutableAlliance,
|
||||
Player,
|
||||
@@ -960,31 +961,40 @@ export class PlayerImpl implements Player {
|
||||
this.recordUnitConstructed(unit.type());
|
||||
}
|
||||
|
||||
public buildableUnits(tile: TileRef | null): BuildableUnit[] {
|
||||
const validTiles = tile !== null ? this.validStructureSpawnTiles(tile) : [];
|
||||
return Object.values(UnitType).map((u) => {
|
||||
let canUpgrade: number | false = false;
|
||||
let canBuild: TileRef | false = false;
|
||||
if (!this.mg.inSpawnPhase()) {
|
||||
const existingUnit = tile !== null && this.findUnitToUpgrade(u, tile);
|
||||
if (existingUnit !== false) {
|
||||
canUpgrade = existingUnit.id();
|
||||
public buildableUnits(
|
||||
tile: TileRef | null,
|
||||
units?: UnitType[],
|
||||
): BuildableUnit[] {
|
||||
const validTiles =
|
||||
tile !== null &&
|
||||
(units === undefined || units.some((u) => isStructureType(u)))
|
||||
? this.validStructureSpawnTiles(tile)
|
||||
: [];
|
||||
return Object.values(UnitType)
|
||||
.filter((u) => units === undefined || units.includes(u))
|
||||
.map((u) => {
|
||||
let canUpgrade: number | false = false;
|
||||
let canBuild: TileRef | false = false;
|
||||
if (!this.mg.inSpawnPhase()) {
|
||||
const existingUnit = tile !== null && this.findUnitToUpgrade(u, tile);
|
||||
if (existingUnit !== false) {
|
||||
canUpgrade = existingUnit.id();
|
||||
}
|
||||
if (tile !== null) {
|
||||
canBuild = this.canBuild(u, tile, validTiles);
|
||||
}
|
||||
}
|
||||
if (tile !== null) {
|
||||
canBuild = this.canBuild(u, tile, validTiles);
|
||||
}
|
||||
}
|
||||
return {
|
||||
type: u,
|
||||
canBuild,
|
||||
canUpgrade,
|
||||
cost: this.mg.config().unitInfo(u).cost(this.mg, this),
|
||||
overlappingRailroads:
|
||||
canBuild !== false
|
||||
? this.mg.railNetwork().overlappingRailroads(canBuild)
|
||||
: [],
|
||||
} as BuildableUnit;
|
||||
});
|
||||
return {
|
||||
type: u,
|
||||
canBuild,
|
||||
canUpgrade,
|
||||
cost: this.mg.config().unitInfo(u).cost(this.mg, this),
|
||||
overlappingRailroads:
|
||||
canBuild !== false
|
||||
? this.mg.railNetwork().overlappingRailroads(canBuild)
|
||||
: [],
|
||||
} as BuildableUnit;
|
||||
});
|
||||
}
|
||||
|
||||
canBuild(
|
||||
|
||||
@@ -94,6 +94,7 @@ ctx.addEventListener("message", async (e: MessageEvent<MainThreadMessage>) => {
|
||||
message.playerID,
|
||||
message.x,
|
||||
message.y,
|
||||
message.units,
|
||||
);
|
||||
sendMessage({
|
||||
type: "player_actions_result",
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
PlayerBorderTiles,
|
||||
PlayerID,
|
||||
PlayerProfile,
|
||||
UnitType,
|
||||
} from "../game/Game";
|
||||
import { TileRef } from "../game/GameMap";
|
||||
import { ErrorUpdate, GameUpdateViewData } from "../game/GameUpdates";
|
||||
@@ -164,6 +165,7 @@ export class WorkerClient {
|
||||
playerID: PlayerID,
|
||||
x?: number,
|
||||
y?: number,
|
||||
units?: UnitType[],
|
||||
): Promise<PlayerActions> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInitialized) {
|
||||
@@ -185,9 +187,10 @@ export class WorkerClient {
|
||||
this.worker.postMessage({
|
||||
type: "player_actions",
|
||||
id: messageId,
|
||||
playerID: playerID,
|
||||
x: x,
|
||||
y: y,
|
||||
playerID,
|
||||
x,
|
||||
y,
|
||||
units,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
PlayerBorderTiles,
|
||||
PlayerID,
|
||||
PlayerProfile,
|
||||
UnitType,
|
||||
} from "../game/Game";
|
||||
import { TileRef } from "../game/GameMap";
|
||||
import { GameUpdateViewData } from "../game/GameUpdates";
|
||||
@@ -62,6 +63,7 @@ export interface PlayerActionsMessage extends BaseWorkerMessage {
|
||||
playerID: PlayerID;
|
||||
x?: number;
|
||||
y?: number;
|
||||
units?: UnitType[];
|
||||
}
|
||||
|
||||
export interface PlayerActionsResultMessage extends BaseWorkerMessage {
|
||||
|
||||
Reference in New Issue
Block a user