From f336c667f3e202ac9451ddb0202dc3d6c6063274 Mon Sep 17 00:00:00 2001 From: scamiv <6170744+scamiv@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:17:33 +0100 Subject: [PATCH] mark trade ships plan-driven on spawn Add `Game.markUnitPlanDriven()` so executions can suppress per-step Unit updates before the first motion plan is recorded. Use it in TradeShipExecution to drop the spawn-time placeholder motion plan, and align TransportShipExecution re-plan `startTick` with `ticksPerMove`. --- src/core/execution/TradeShipExecution.ts | 19 ++++--------------- src/core/execution/TransportShipExecution.ts | 2 +- src/core/game/Game.ts | 5 +++++ src/core/game/GameImpl.ts | 4 ++++ 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/core/execution/TradeShipExecution.ts b/src/core/execution/TradeShipExecution.ts index b1771c46f..262ba3744 100644 --- a/src/core/execution/TradeShipExecution.ts +++ b/src/core/execution/TradeShipExecution.ts @@ -8,7 +8,6 @@ import { UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; -import { MotionPlanRecord } from "../game/MotionPlans"; import { PathFinding } from "../pathfinding/PathFinder"; import { PathStatus, SteppingPathFinder } from "../pathfinding/types"; import { distSortUnit } from "../Util"; @@ -35,7 +34,6 @@ export class TradeShipExecution implements Execution { } tick(ticks: number): void { - let spawnedThisTick = false; if (this.tradeShip === undefined) { const spawn = this.origOwner.canBuild( UnitType.TradeShip, @@ -50,19 +48,10 @@ 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()); - spawnedThisTick = true; - - const placeholderPlan: MotionPlanRecord = { - kind: "grid", - unitId: this.tradeShip.id(), - planId: this.motionPlanId, - startTick: ticks + 1, - ticksPerStep: 1, - path: [spawn], - }; - this.mg.recordMotionPlan(placeholderPlan); - this.motionPlanDst = this._dstPort.tile(); } if (!this.tradeShip.isActive()) { @@ -146,7 +135,7 @@ export class TradeShipExecution implements Execution { } const dst = this._dstPort.tile(); - if (spawnedThisTick || dst !== this.motionPlanDst) { + if (dst !== this.motionPlanDst) { this.motionPlanId++; const from = this.tradeShip.tile(); const path = this.pathFinder.findPath(from, dst) ?? [from]; diff --git a/src/core/execution/TransportShipExecution.ts b/src/core/execution/TransportShipExecution.ts index c1f127ffe..cd69aa6ab 100644 --- a/src/core/execution/TransportShipExecution.ts +++ b/src/core/execution/TransportShipExecution.ts @@ -282,7 +282,7 @@ export class TransportShipExecution implements Execution { kind: "grid", unitId: this.boat.id(), planId: this.motionPlanId, - startTick: ticks + 1, + startTick: ticks + this.ticksPerMove, ticksPerStep: this.ticksPerMove, path: fullPath, }); diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index 0fa214165..619da8211 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -768,6 +768,11 @@ 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; diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index af289638d..8dbb56835 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -433,6 +433,10 @@ export class GameImpl implements Game { return packed; } + markUnitPlanDriven(unitId: number): void { + this.planDrivenUnitIds.add(unitId); + } + recordMotionPlan(record: MotionPlanRecord): void { switch (record.kind) { case "grid":