v0.64.0: market top-up + coverage spawn run on every tick including frozen ones, so a grounded fleet can never drain the market to zero (#135 follow-up)
CI / build + unit + e2e (pull_request) Successful in 14m12s
CI / build + unit + e2e (pull_request) Successful in 14m12s
This commit is contained in:
+13
-8
@@ -69,8 +69,8 @@ function withLock<T>(fn: () => Promise<T>): Promise<T> {
|
||||
|
||||
// #135: advance decision — pure, so unit tests feed it synthetic fleets. The world clock runs at
|
||||
// full scale only while something is happening (at least one plane flying OR in repair); a fully
|
||||
// grounded fleet freezes it entirely — no expiry/spawn/repair progress until a dispatch or repair
|
||||
// starts again.
|
||||
// grounded fleet freezes it entirely — no expiry/delivery/repair progress until a dispatch or
|
||||
// repair starts again (the market top-up still runs on frozen ticks, #135 follow-up).
|
||||
export function shouldAdvanceTime(planes: Array<{ status: string }>): { advance: boolean; flying: number; repairing: number } {
|
||||
let flying = 0;
|
||||
let repairing = 0;
|
||||
@@ -87,8 +87,9 @@ export async function tickOnce(inst: GameDb): Promise<schema.SimStateRow> {
|
||||
if (!sim) throw new Error('sim_state row missing');
|
||||
|
||||
const nowMs = Date.now();
|
||||
// #135: a fully grounded fleet freezes the world — no advance, no expiry/spawn/repair progress.
|
||||
// lastRealTickMs always tracks real time, so resuming activity never fast-forwards the frozen span.
|
||||
// #135: a fully grounded fleet freezes the world — no advance, no expiry/delivery/repair progress
|
||||
// (the market top-up still runs on frozen ticks — see below). lastRealTickMs always tracks real
|
||||
// time, so resuming activity never fast-forwards the frozen span.
|
||||
const planeRows = await inst.db.select().from(schema.planes);
|
||||
const { advance } = shouldAdvanceTime(planeRows.map((p) => ({ status: p.status })));
|
||||
// #135 (v0.62.0): production ALWAYS runs at the fixed world rate — legacy saves may hold a stale
|
||||
@@ -105,11 +106,15 @@ export async function tickOnce(inst: GameDb): Promise<schema.SimStateRow> {
|
||||
// v0.39.0 (ISS-069): repairs whose gate has passed flip back to 'available' — runs even when
|
||||
// nothing landed this tick; BEFORE the spawns so a just-repaired plane gets coverage work too.
|
||||
await finishRepairs(inst, clockMs);
|
||||
await spawnOpenPackages(inst, clockMs);
|
||||
// AFTER delivery on purpose: a plane that just landed gets work spawned
|
||||
// at its new location within the same tick.
|
||||
await spawnCoveragePackages(inst, clockMs);
|
||||
}
|
||||
// #135 follow-up (v0.64.0): market top-up + coverage spawn run on EVERY tick — frozen ones
|
||||
// included — because while grounded nothing else creates packages but removal paths (ignore)
|
||||
// still run; without this a grounded fleet could drain the market to zero and soft-lock forever.
|
||||
// Both are idempotent no-ops when satisfied, so advancing ticks behave exactly as before.
|
||||
await spawnOpenPackages(inst, clockMs);
|
||||
// AFTER delivery on purpose: a plane that just landed gets work spawned
|
||||
// at its new location within the same tick.
|
||||
await spawnCoveragePackages(inst, clockMs);
|
||||
|
||||
// Persist lastRealTickMs even when nothing advanced — it is the tick anchor.
|
||||
await inst.db.update(schema.simState).set({ clockMs, lastRealTickMs: nowMs });
|
||||
|
||||
Reference in New Issue
Block a user