First commit perf canbuild transport ship

This commit is contained in:
variablevince
2025-10-24 00:17:10 +02:00
parent 73bf583452
commit 92d2b45340
11 changed files with 94 additions and 57 deletions
+11 -5
View File
@@ -12,7 +12,11 @@ import {
import { createPartialGameRecord, replacer } from "../core/Util";
import { ServerConfig } from "../core/configuration/Config";
import { getConfig } from "../core/configuration/ConfigLoader";
import { PlayerActions, UnitType } from "../core/game/Game";
import {
PlayerActions,
TransportShipFilter,
UnitType,
} from "../core/game/Game";
import { TileRef } from "../core/game/GameMap";
import { GameMapLoader } from "../core/game/GameMapLoader";
import {
@@ -414,13 +418,14 @@ export class ClientGameRunner {
if (myPlayer === null) return;
this.myPlayer = myPlayer;
}
this.myPlayer.actions(tile).then((actions) => {
if (this.myPlayer === null) return;
this.myPlayer.actions(tile, TransportShipFilter.Only).then((actions) => {
// if (this.myPlayer === null) return; //--> redundant check as set above?, but need to add ! below to stop error 'can be null'
if (actions.canAttack) {
//-->maybe only get actions.canAttack + transportship from buildableunits? Not everything else?
this.eventBus.emit(
new SendAttackIntentEvent(
this.gameView.owner(tile).id(),
this.myPlayer.troops() * this.renderer.uiState.attackRatio,
this.myPlayer!.troops() * this.renderer.uiState.attackRatio,
),
);
} else if (this.canAutoBoat(actions, tile)) {
@@ -511,7 +516,8 @@ export class ClientGameRunner {
this.myPlayer = myPlayer;
}
this.myPlayer.actions(tile).then((actions) => {
this.myPlayer.actions(tile, TransportShipFilter.Only).then((actions) => {
//-->> maybe only get transportship from buildableunits? Not everything else?
if (this.canBoatAttack(actions) !== false) {
this.sendBoatAttackIntent(tile);
}
@@ -10,6 +10,7 @@ import {
Cell,
PlayerActions,
PlayerID,
TransportShipFilter,
UnitType,
} from "../../../core/game/Game";
import { TileRef } from "../../../core/game/GameMap";
@@ -249,7 +250,7 @@ export class StructureIconsLayer implements Layer {
this.game
?.myPlayer()
?.actions(tileRef)
?.actions(tileRef, TransportShipFilter.Exclude)
.then((actions) => {
if (this.potentialUpgrade) {
this.potentialUpgrade.iconContainer.filters = [];
+8 -2
View File
@@ -11,7 +11,12 @@ import portIcon from "../../../../resources/images/PortIcon.svg";
import samLauncherIcon from "../../../../resources/images/SamLauncherIconWhite.svg";
import defensePostIcon from "../../../../resources/images/ShieldIconWhite.svg";
import { EventBus } from "../../../core/EventBus";
import { Gold, PlayerActions, UnitType } from "../../../core/game/Game";
import {
Gold,
PlayerActions,
TransportShipFilter,
UnitType,
} from "../../../core/game/Game";
import { GameView } from "../../../core/game/GameView";
import { ToggleStructureEvent } from "../../InputHandler";
import { renderNumber, translateText } from "../../Utils";
@@ -97,7 +102,8 @@ export class UnitDisplay extends LitElement implements Layer {
tick() {
const player = this.game?.myPlayer();
player?.actions().then((actions) => {
player?.actions(undefined, TransportShipFilter.Exclude).then((actions) => {
// player?.actions(undefined, TransportShipFilter.Default).then((actions) => {
this.playerActions = actions;
});
if (!player) return;
+3 -1
View File
@@ -17,6 +17,7 @@ import {
PlayerInfo,
PlayerProfile,
PlayerType,
TransportShipFilter,
} from "./game/Game";
import { createGame } from "./game/GameImpl";
import { TileRef } from "./game/GameMap";
@@ -181,13 +182,14 @@ export class GameRunner {
playerID: PlayerID,
x?: number,
y?: number,
TransportShipFilter?: TransportShipFilter,
): 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),
buildableUnits: player.buildableUnits(tile, TransportShipFilter),
canSendEmojiAllPlayers: player.canSendEmoji(AllPlayers),
} as PlayerActions;
+10 -1
View File
@@ -560,7 +560,10 @@ export interface Player {
unitCount(type: UnitType): number;
unitsConstructed(type: UnitType): number;
unitsOwned(type: UnitType): number;
buildableUnits(tile: TileRef | null): BuildableUnit[];
buildableUnits(
tile: TileRef | null,
TransportShipFilter?: TransportShipFilter,
): BuildableUnit[];
canBuild(type: UnitType, targetTile: TileRef): TileRef | false;
buildUnit<T extends UnitType>(
type: T,
@@ -857,3 +860,9 @@ export interface NameViewData {
y: number;
size: number;
}
export enum TransportShipFilter {
Default = "default", // Include TransportShip with all units
Exclude = "exclude", // Skip TransportShip in the unit list
Only = "only", // Only check TransportShip
}
+6 -1
View File
@@ -22,6 +22,7 @@ import {
TerraNullius,
Tick,
TrainType,
TransportShipFilter,
UnitInfo,
UnitType,
} from "./Game";
@@ -272,11 +273,15 @@ export class PlayerView {
: this._defendedBorderColors.dark;
}
async actions(tile?: TileRef): Promise<PlayerActions> {
async actions(
tile?: TileRef,
TransportShipFilter?: TransportShipFilter,
): Promise<PlayerActions> {
return this.game.worker.playerInteraction(
this.id(),
tile && this.game.x(tile),
tile && this.game.y(tile),
TransportShipFilter,
);
}
+42 -9
View File
@@ -33,6 +33,7 @@ import {
Team,
TerraNullius,
Tick,
TransportShipFilter,
Unit,
UnitParams,
UnitType,
@@ -879,26 +880,58 @@ export class PlayerImpl implements Player {
this.recordUnitConstructed(unit.type());
}
public buildableUnits(tile: TileRef | null): BuildableUnit[] {
public buildableUnits(
tile: TileRef | null,
transportShipFilter: TransportShipFilter = TransportShipFilter.Default,
): BuildableUnit[] {
const inSpawnPhase = this.mg.inSpawnPhase();
if (transportShipFilter === TransportShipFilter.Only) {
const u = UnitType.TransportShip;
return [
{
type: u,
canBuild:
inSpawnPhase || tile === null
? false
: this.canBuild(u, tile, null),
canUpgrade: !this.mg.config().unitInfo(u).upgradable ? false : 0,
cost: this.mg.config().unitInfo(u).cost(this),
} as BuildableUnit,
];
}
const validTiles = tile !== null ? this.validStructureSpawnTiles(tile) : [];
return Object.values(UnitType).map((u) => {
const result: BuildableUnit[] = [];
for (const u of Object.values(UnitType)) {
if (
u === UnitType.TransportShip &&
transportShipFilter === TransportShipFilter.Exclude
) {
continue;
}
let canUpgrade: number | false = false;
if (!this.mg.inSpawnPhase()) {
const existingUnit = tile !== null && this.findUnitToUpgrade(u, tile);
if (!inSpawnPhase && tile !== null) {
const existingUnit = this.findUnitToUpgrade(u, tile);
if (existingUnit !== false) {
canUpgrade = existingUnit.id();
}
}
return {
result.push({
type: u,
canBuild:
this.mg.inSpawnPhase() || tile === null
inSpawnPhase || tile === null
? false
: this.canBuild(u, tile, validTiles),
canUpgrade: canUpgrade,
canUpgrade,
cost: this.mg.config().unitInfo(u).cost(this),
} as BuildableUnit;
});
} as BuildableUnit);
}
return result;
}
canBuild(
+6 -37
View File
@@ -14,11 +14,6 @@ export function canBuildTransportShip(
return false;
}
const dst = targetTransportTile(game, tile);
if (dst === null) {
return false;
}
const other = game.owner(tile);
if (other === player) {
return false;
@@ -27,6 +22,11 @@ export function canBuildTransportShip(
return false;
}
const dst = targetTransportTile(game, tile);
if (dst === null) {
return false;
}
if (game.isOceanShore(dst)) {
let myPlayerBordersOcean = false;
for (const bt of player.borderTiles()) {
@@ -36,28 +36,13 @@ export function canBuildTransportShip(
}
}
let otherPlayerBordersOcean = false;
if (!game.hasOwner(tile)) {
otherPlayerBordersOcean = true;
} else {
for (const bt of (other as Player).borderTiles()) {
if (game.isOceanShore(bt)) {
otherPlayerBordersOcean = true;
break;
}
}
}
if (myPlayerBordersOcean && otherPlayerBordersOcean) {
if (myPlayerBordersOcean) {
return transportShipSpawn(game, player, dst);
} else {
return false;
}
}
// Now we are boating in a lake, so do a bfs from target until we find
// a border tile owned by the player
const tiles = game.bfs(
dst,
andFN(
@@ -93,22 +78,6 @@ function transportShipSpawn(
return spawn;
}
export function sourceDstOceanShore(
gm: Game,
src: Player,
tile: TileRef,
): [TileRef | null, TileRef | null] {
const dst = gm.owner(tile);
const srcTile = closestShoreFromPlayer(gm, src, tile);
let dstTile: TileRef | null = null;
if (dst.isPlayer()) {
dstTile = closestShoreFromPlayer(gm, dst as Player, tile);
} else {
dstTile = closestShoreTN(gm, tile, 50);
}
return [srcTile, dstTile];
}
export function targetTransportTile(gm: Game, tile: TileRef): TileRef | null {
const dst = gm.playerBySmallID(gm.ownerID(tile));
let dstTile: TileRef | null = null;
+1
View File
@@ -83,6 +83,7 @@ ctx.addEventListener("message", async (e: MessageEvent<MainThreadMessage>) => {
message.playerID,
message.x,
message.y,
message.TransportShipFilter,
);
sendMessage({
type: "player_actions_result",
+3
View File
@@ -4,6 +4,7 @@ import {
PlayerBorderTiles,
PlayerID,
PlayerProfile,
TransportShipFilter,
} from "../game/Game";
import { TileRef } from "../game/GameMap";
import { ErrorUpdate, GameUpdateViewData } from "../game/GameUpdates";
@@ -162,6 +163,7 @@ export class WorkerClient {
playerID: PlayerID,
x?: number,
y?: number,
TransportShipFilter?: TransportShipFilter,
): Promise<PlayerActions> {
return new Promise((resolve, reject) => {
if (!this.isInitialized) {
@@ -186,6 +188,7 @@ export class WorkerClient {
playerID: playerID,
x: x,
y: y,
TransportShipFilter: TransportShipFilter,
});
});
}
+2
View File
@@ -3,6 +3,7 @@ import {
PlayerBorderTiles,
PlayerID,
PlayerProfile,
TransportShipFilter,
} 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;
TransportShipFilter?: TransportShipFilter;
}
export interface PlayerActionsResultMessage extends BaseWorkerMessage {