feat(02-01): BigQty + scheduler + sim foundations
- Install zustand@^5.0.0 + break_eternity.js@^2.1.3 as dependencies - BigQty immutable wrapper around Decimal (D-31): factories, arithmetic, comparison, JSON round-trip, saturating coercion - formatHumanReadable for K/M/B/T/scientific HUD readouts (UX-11) - Clock interface + wallClock + FakeClock — only file in src/sim/ allowed to read Date.now() (D-33) - drainTicks fixed-timestep accumulator: refuses negative deltas (CORE-11), clamps at MAX_OFFLINE_MS=24h (CORE-03), TICK_MS=200 - computeOfflineCatchup pure descriptor for offline boundaries - SimState root shape with BLOCKER 3 split: lastTickAt (wall-clock, app-layer-only) + tickCount (sim-internal monotonic) - 52 tests across big-qty / format / clock / tick / catchup all green
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* SimState — root shape of the in-memory sim world. Structurally
|
||||
* compatible with V1Payload from src/save/migrations.ts (a SimState
|
||||
* round-trips to a V1Payload via the application layer).
|
||||
*
|
||||
* Wave 0 ships placeholder unknown[] for tiles/plants — Wave 1 (Plan 02-02)
|
||||
* fleshes them out with real interfaces in src/sim/garden/types.ts.
|
||||
*
|
||||
* BLOCKER 3 invariant — two distinct time fields with strict separation:
|
||||
* - lastTickAt: wall-clock milliseconds. Written ONLY by the application
|
||||
* layer at saveSync time (src/PhaserGame.tsx). The sim NEVER writes
|
||||
* this field. computeOfflineCatchup reads it as wall-clock ms.
|
||||
* - tickCount: monotonically-increasing sim-internal counter (one per
|
||||
* simulate() call). Used for STRY-10 narrative gating that must be
|
||||
* immune to wall-clock manipulation. The sim DOES write this field.
|
||||
* The application layer reads it but never writes it.
|
||||
*/
|
||||
export interface SimState {
|
||||
garden: { tiles: unknown[] };
|
||||
plants: unknown[];
|
||||
harvestedFragmentIds: string[];
|
||||
/** Wall-clock milliseconds at last save. Written ONLY at saveSync. */
|
||||
lastTickAt: number;
|
||||
/** Monotonic sim tick counter. Incremented by the sim; used for STRY-10. */
|
||||
tickCount: number;
|
||||
unlockedPlantTypes: string[];
|
||||
luraBeatProgress: {
|
||||
arrived: boolean;
|
||||
mid: boolean;
|
||||
farewell: boolean;
|
||||
pending: 'arrival' | 'mid' | 'farewell' | null;
|
||||
};
|
||||
offlineEvents: unknown | null;
|
||||
settings: {
|
||||
musicVolume: number;
|
||||
ambientVolume: number;
|
||||
sfxVolume: number;
|
||||
persistenceToastShown: boolean;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user