From e3bf64eab5e20b3dcc7f00d15875c1e729e82efc Mon Sep 17 00:00:00 2001 From: scamiv <6170744+scamiv@users.noreply.github.com> Date: Wed, 25 Feb 2026 23:05:08 +0100 Subject: [PATCH] perf(client): stop re-updating stationary motion-planned units Only apply derived positions when the tile changes and drop finished grid motion plans once past the last step to avoid per-tick update churn after arrival. --- src/core/game/GameView.ts | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/core/game/GameView.ts b/src/core/game/GameView.ts index e4048d45d..fe5c1224e 100644 --- a/src/core/game/GameView.ts +++ b/src/core/game/GameView.ts @@ -790,11 +790,23 @@ export class GameView implements GameMap { } const oldTile = unit.tile(); - const newTile = this.motionTileAtTick(plan, currentTick); - unit.applyDerivedPosition(newTile); + const dt = currentTick - plan.startTick; + const stepIndex = + dt <= 0 ? 0 : Math.floor(dt / Math.max(1, plan.ticksPerStep)); + const lastIndex = plan.path.length - 1; + const idx = Math.max(0, Math.min(lastIndex, stepIndex)); + const newTile = plan.path[idx] as TileRef; if (newTile !== oldTile) { + unit.applyDerivedPosition(newTile); this.unitGrid.updateUnitCell(unit); + continue; + } + + // Once a plan is past its final step, `newTile` remains clamped to the last path tile. + // Drop finished plans to avoid repeatedly marking static units as updated each tick. + if (dt > 0 && stepIndex >= lastIndex) { + this.unitMotionPlans.delete(unitId); } } @@ -899,20 +911,6 @@ export class GameView implements GameMap { } } - private motionTileAtTick( - plan: { startTick: number; ticksPerStep: number; path: Uint32Array }, - tick: Tick, - ): TileRef { - if (plan.path.length < 1) { - throw new Error("motion plan path must be non-empty"); - } - const dt = tick - plan.startTick; - const stepIndex = - dt <= 0 ? 0 : Math.floor(dt / Math.max(1, plan.ticksPerStep)); - const idx = Math.max(0, Math.min(plan.path.length - 1, stepIndex)); - return plan.path[idx] as TileRef; - } - private applyMotionPlanRecords(records: readonly MotionPlanRecord[]): void { for (const record of records) { switch (record.kind) {