core(game): derive plan-driven state from motion plans

- Remove `markUnitPlanDriven` from `Game`/`GameImpl`
- Centralize “maybe emit UnitUpdate” behind `GameImpl.onUnitMoved`
- Record trade ship motion plan before the first move to avoid redundant per-step unit updates
This commit is contained in:
scamiv
2026-02-25 20:21:08 +01:00
parent 2a7e2f9695
commit 82d4bd5978
4 changed files with 51 additions and 38 deletions
+38 -24
View File
@@ -48,9 +48,6 @@ export class TradeShipExecution implements Execution {
targetUnit: this._dstPort,
lastSetSafeFromPirates: ticks,
});
// This unit can move immediately, but plan-driven units don't emit per-step Unit updates.
// Mark it plan-driven up-front so its first move doesn't generate redundant traffic.
this.mg.markUnitPlanDriven(this.tradeShip.id());
this.mg.stats().boatSendTrade(this.origOwner, this._dstPort.owner());
}
@@ -109,12 +106,49 @@ export class TradeShipExecution implements Execution {
return;
}
const result = this.pathFinder.next(curTile, this._dstPort.tile());
const dst = this._dstPort.tile();
const result = this.pathFinder.next(curTile, dst);
switch (result.status) {
case PathStatus.PENDING:
if (dst !== this.motionPlanDst) {
this.motionPlanId++;
const from = curTile;
const path = this.pathFinder.findPath(from, dst) ?? [from];
if (path.length === 0 || path[0] !== from) {
path.unshift(from);
}
this.mg.recordMotionPlan({
kind: "grid",
unitId: this.tradeShip.id(),
planId: this.motionPlanId,
startTick: ticks + 1,
ticksPerStep: 1,
path,
});
this.motionPlanDst = dst;
}
break;
case PathStatus.NEXT:
if (dst !== this.motionPlanDst) {
this.motionPlanId++;
const from = result.node;
const path = this.pathFinder.findPath(from, dst) ?? [from];
if (path.length === 0 || path[0] !== from) {
path.unshift(from);
}
this.mg.recordMotionPlan({
kind: "grid",
unitId: this.tradeShip.id(),
planId: this.motionPlanId,
startTick: ticks + 1,
ticksPerStep: 1,
path,
});
this.motionPlanDst = dst;
}
// Update safeFromPirates status
if (this.mg.isWater(result.node) && this.mg.isShoreline(result.node)) {
this.tradeShip.setSafeFromPirates();
@@ -133,26 +167,6 @@ export class TradeShipExecution implements Execution {
this.active = false;
return;
}
const dst = this._dstPort.tile();
if (dst !== this.motionPlanDst) {
this.motionPlanId++;
const from = this.tradeShip.tile();
const path = this.pathFinder.findPath(from, dst) ?? [from];
if (path.length === 0 || path[0] !== from) {
path.unshift(from);
}
this.mg.recordMotionPlan({
kind: "grid",
unitId: this.tradeShip.id(),
planId: this.motionPlanId,
startTick: ticks + 1,
ticksPerStep: 1,
path,
});
this.motionPlanDst = dst;
}
}
private complete() {
-5
View File
@@ -778,11 +778,6 @@ export interface Game extends GameMap {
inSpawnPhase(): boolean;
executeNextTick(): GameUpdates;
drainPackedTileUpdates(): Uint32Array;
/**
* Marks a unit as "plan-driven" so its per-tile `Unit` updates can be suppressed.
* The client is expected to advance the unit position via motion plans.
*/
markUnitPlanDriven(unitId: number): void;
recordMotionPlan(record: MotionPlanRecord): void;
drainPackedMotionPlans(): Uint32Array | null;
setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void;
+12 -5
View File
@@ -447,10 +447,6 @@ export class GameImpl implements Game {
return packed;
}
markUnitPlanDriven(unitId: number): void {
this.planDrivenUnitIds.add(unitId);
}
recordMotionPlan(record: MotionPlanRecord): void {
switch (record.kind) {
case "grid":
@@ -466,10 +462,21 @@ export class GameImpl implements Game {
this.motionPlanRecords.push(record);
}
isUnitPlanDriven(unitId: number): boolean {
private isUnitPlanDriven(unitId: number): boolean {
return this.planDrivenUnitIds.has(unitId);
}
maybeAddUnitUpdate(unit: Unit): void {
if (!this.isUnitPlanDriven(unit.id())) {
this.addUpdate(unit.toUpdate());
}
}
onUnitMoved(unit: Unit): void {
this.updateUnitTile(unit);
this.maybeAddUnitUpdate(unit);
}
drainPackedMotionPlans(): Uint32Array | null {
const records = this.motionPlanRecords;
if (records.length === 0) {
+1 -4
View File
@@ -159,10 +159,7 @@ export class UnitImpl implements Unit {
}
this._lastTile = this._tile;
this._tile = tile;
this.mg.updateUnitTile(this);
if (!this.mg.isUnitPlanDriven(this._id)) {
this.mg.addUpdate(this.toUpdate());
}
this.mg.onUnitMoved(this);
}
setTroops(troops: number): void {