ugly-game 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/moat.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/** A DETERMINISTIC SIMULATION: pure `step`, clonable state, content-addressable `hash`. Identical (state, input)
|
|
2
|
+
* → byte-identical result, verifiable by the hash. That is the ONLY thing the whole harness, the netcode
|
|
3
|
+
* Reconciler, and the branchable StateTree need from a game — nothing game-specific. */
|
|
4
|
+
export interface DeterministicSim<S, I> {
|
|
3
5
|
clone(s: S): S;
|
|
4
6
|
hash(s: S): string;
|
|
5
7
|
step(s: S, input: I): void;
|
|
6
8
|
}
|
|
9
|
+
/** @deprecated Renamed to {@link DeterministicSim} — the name now describes the property (determinism), not the
|
|
10
|
+
* strategic payoff. Kept as an alias so existing consumers keep compiling. */
|
|
11
|
+
export type MoatSim<S, I> = DeterministicSim<S, I>;
|
|
7
12
|
/** Run a sim over an input stream and record the per-step content hash (index 0 = the initial state). */
|
|
8
|
-
export declare function runTrace<S, I>(sim:
|
|
13
|
+
export declare function runTrace<S, I>(sim: DeterministicSim<S, I>, init: S, inputs: I[]): string[];
|
|
9
14
|
export interface Equivalence {
|
|
10
15
|
inSync: boolean;
|
|
11
16
|
firstDivergentStep: number;
|
|
@@ -18,7 +23,7 @@ export declare function equivalence(reference: string[], candidate: string[]): E
|
|
|
18
23
|
export declare function oracleCheck(reference: () => string[], candidate: () => string[]): Equivalence;
|
|
19
24
|
/** Re-run a sim to a given step and return the state there — for localizing WHICH field diverged (the
|
|
20
25
|
* game supplies a `locate(refState, candState)`, e.g. the factory's "tile (9,7) content A=1 B=0"). */
|
|
21
|
-
export declare function stateAt<S, I>(sim:
|
|
26
|
+
export declare function stateAt<S, I>(sim: DeterministicSim<S, I>, init: S, inputs: I[], step: number): S;
|
|
22
27
|
export interface SweepResult<P, V extends string> {
|
|
23
28
|
results: {
|
|
24
29
|
perturbation: P;
|
package/dist/net/reconcile.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DeterministicSim } from '../moat';
|
|
2
2
|
export interface Correction {
|
|
3
3
|
rewound: number;
|
|
4
4
|
diverged: boolean;
|
|
@@ -10,7 +10,7 @@ export declare class Reconciler<S, I> {
|
|
|
10
10
|
private st;
|
|
11
11
|
private f;
|
|
12
12
|
private window;
|
|
13
|
-
constructor(sim:
|
|
13
|
+
constructor(sim: DeterministicSim<S, I>, base: S, baseFrame?: number, window?: number);
|
|
14
14
|
/** Step the head forward by applying `input` for the current head frame → advance to head+1. */
|
|
15
15
|
advance(input: I): void;
|
|
16
16
|
/** An authoritative/corrected input for `frame` arrives. If it's a past frame within the window, rewind and
|
package/dist/net/reconcile.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
2
|
-
// RECONCILER — client-side rollback over any
|
|
2
|
+
// RECONCILER — client-side rollback over any DeterministicSim (the moat's netcode payoff).
|
|
3
3
|
//
|
|
4
4
|
// Live play can't wait for the network: you PREDICT missing/remote inputs and step
|
|
5
5
|
// ahead. When an authoritative (or corrected) input for a PAST frame arrives, you
|
|
6
6
|
// rewind to a checkpoint at/just-before that frame, splice the input into the frame-
|
|
7
7
|
// indexed stream, and REPLAY forward to the present. Because the sim is a
|
|
8
|
-
// deterministic
|
|
8
|
+
// deterministic sim (clone/hash/step), the replayed head is BYTE-IDENTICAL to
|
|
9
9
|
// what an in-order application would have produced — that's the whole guarantee, and
|
|
10
10
|
// `reconcile.test.mts` proves it via hash equality. Bounded by a checkpoint window;
|
|
11
11
|
// corrections older than the window return rewound<0 so the app can trigger a resync.
|
|
@@ -7,8 +7,10 @@ export declare class SharedClock {
|
|
|
7
7
|
private pinned;
|
|
8
8
|
constructor(tickMs: number, // ms per tick (e.g. 1000/60)
|
|
9
9
|
now: () => number);
|
|
10
|
-
/** From the server `hello`.
|
|
11
|
-
|
|
10
|
+
/** From the server `hello`. Pass the server's `now` to seed a PROVISIONAL offset so `targetTick()` is roughly
|
|
11
|
+
* right immediately — the window between joining and the first ping/pong returning is exactly when lockstep
|
|
12
|
+
* clients stamp their first commands, and an offset of 0 there desyncs them. A real ping sample overrides it. */
|
|
13
|
+
setEpoch(epoch: number, serverNow?: number): void;
|
|
12
14
|
get hasEpoch(): boolean;
|
|
13
15
|
get epochMs(): number;
|
|
14
16
|
/** Feed a ping round-trip: `sentAt` = local ms we sent, `serverNow` = server ms in the pong. Keeps the sample
|
package/dist/net/sharedClock.js
CHANGED
|
@@ -17,10 +17,14 @@ export class SharedClock {
|
|
|
17
17
|
this.tickMs = tickMs;
|
|
18
18
|
this.now = now;
|
|
19
19
|
}
|
|
20
|
-
/** From the server `hello`.
|
|
21
|
-
|
|
20
|
+
/** From the server `hello`. Pass the server's `now` to seed a PROVISIONAL offset so `targetTick()` is roughly
|
|
21
|
+
* right immediately — the window between joining and the first ping/pong returning is exactly when lockstep
|
|
22
|
+
* clients stamp their first commands, and an offset of 0 there desyncs them. A real ping sample overrides it. */
|
|
23
|
+
setEpoch(epoch, serverNow) {
|
|
22
24
|
this.epoch = epoch;
|
|
23
25
|
this.pinned = true;
|
|
26
|
+
if (serverNow !== undefined && this.bestRtt === Infinity)
|
|
27
|
+
this.offset = serverNow - this.now();
|
|
24
28
|
}
|
|
25
29
|
get hasEpoch() {
|
|
26
30
|
return this.pinned;
|