deadhead-space-freight-tycoon/packages/engine/src/clock.ts

51 lines
1.5 KiB
TypeScript

import type { RealTime } from "@deadhead/sim";
/** The engine's only source of time (CR-014): injected, so tests use a fixed one. */
export interface Clock {
now(): RealTime;
}
/**
* The device clock (decision 0.5.88): device time plus a dev-only offset,
* clamped so it never runs backward. Setting the device clock back leaves
* the game at the last time it saw; setting it forward is accepted.
*/
export class DeviceClock implements Clock {
#lastSeen: RealTime;
#offsetMs: number;
constructor(
/** Device time; Date.now outside tests. */
private readonly deviceNow: () => RealTime = () => Date.now(),
options: { lastTimeSeen?: RealTime; offsetMs?: number } = {},
) {
this.#lastSeen = options.lastTimeSeen ?? 0;
this.#offsetMs = options.offsetMs ?? 0;
}
now(): RealTime {
this.#lastSeen = Math.max(this.deviceNow() + this.#offsetMs, this.#lastSeen);
return this.#lastSeen;
}
/** The latest time handed out, stored in the save (CR-014 §2). */
get lastTimeSeen(): RealTime {
return this.#lastSeen;
}
/** After loading a save: never hand out a time before the one it last saw. */
restore(lastTimeSeen: RealTime): void {
this.#lastSeen = Math.max(this.#lastSeen, lastTimeSeen);
}
get offsetMs(): number {
return this.#offsetMs;
}
/** Developer tool: move the game forward (never back). */
advance(ms: number): void {
if (ms < 0) throw new RangeError("The clock only moves forward");
this.#offsetMs += ms;
}
}