@series-inc/rundot-syncplay 5.23.0-beta.7
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/README.md +610 -0
- package/dist/animation.d.ts +119 -0
- package/dist/animation.js +488 -0
- package/dist/asset-cooking.d.ts +82 -0
- package/dist/asset-cooking.js +364 -0
- package/dist/authority-room.d.ts +217 -0
- package/dist/authority-room.js +701 -0
- package/dist/bot-documents.d.ts +115 -0
- package/dist/bot-documents.js +549 -0
- package/dist/bot-primitives.d.ts +152 -0
- package/dist/bot-primitives.js +472 -0
- package/dist/browser.d.ts +57 -0
- package/dist/browser.js +53 -0
- package/dist/canonical.d.ts +12 -0
- package/dist/canonical.js +288 -0
- package/dist/certification.d.ts +455 -0
- package/dist/certification.js +1855 -0
- package/dist/chaos-certification.d.ts +56 -0
- package/dist/chaos-certification.js +1397 -0
- package/dist/cjs/animation.js +495 -0
- package/dist/cjs/asset-cooking.js +372 -0
- package/dist/cjs/authority-room.js +704 -0
- package/dist/cjs/bot-documents.js +556 -0
- package/dist/cjs/bot-primitives.js +482 -0
- package/dist/cjs/browser.js +96 -0
- package/dist/cjs/canonical.js +299 -0
- package/dist/cjs/certification.js +1860 -0
- package/dist/cjs/chaos-certification.js +1402 -0
- package/dist/cjs/collections.js +36 -0
- package/dist/cjs/collision.js +96 -0
- package/dist/cjs/commands.js +987 -0
- package/dist/cjs/config-bundle.js +491 -0
- package/dist/cjs/creator.js +30 -0
- package/dist/cjs/deterministic-primitives.js +134 -0
- package/dist/cjs/deterministic-session.js +1410 -0
- package/dist/cjs/ecs-lite.js +155 -0
- package/dist/cjs/effects-adapter.js +97 -0
- package/dist/cjs/engine-complete.js +2297 -0
- package/dist/cjs/engine-core-proof.js +70 -0
- package/dist/cjs/engine-parity-matrix.js +874 -0
- package/dist/cjs/engine-parity.js +3183 -0
- package/dist/cjs/engine-runtime.js +3141 -0
- package/dist/cjs/errors.js +22 -0
- package/dist/cjs/events.js +247 -0
- package/dist/cjs/examples/counter-duel.js +157 -0
- package/dist/cjs/examples/fixed-arena.js +368 -0
- package/dist/cjs/index.js +229 -0
- package/dist/cjs/input-authority.js +150 -0
- package/dist/cjs/input-button.js +256 -0
- package/dist/cjs/input-timeline.js +418 -0
- package/dist/cjs/instant-replay.js +66 -0
- package/dist/cjs/lag-compensation3d.js +837 -0
- package/dist/cjs/local-authority-server-runner.js +1121 -0
- package/dist/cjs/local-authority-wire.js +1497 -0
- package/dist/cjs/local-authority.js +817 -0
- package/dist/cjs/local-ws-adapter.js +150 -0
- package/dist/cjs/match-log.js +61 -0
- package/dist/cjs/math.js +157 -0
- package/dist/cjs/mock-network-adapter.js +26 -0
- package/dist/cjs/movement.js +703 -0
- package/dist/cjs/movement3d.js +1246 -0
- package/dist/cjs/multiclient-authority.js +308 -0
- package/dist/cjs/multiplayer-service.js +434 -0
- package/dist/cjs/navigation.js +347 -0
- package/dist/cjs/navmesh.js +1437 -0
- package/dist/cjs/networked-client.js +691 -0
- package/dist/cjs/networked-input-authority.js +443 -0
- package/dist/cjs/node.js +47 -0
- package/dist/cjs/number-lab.js +78 -0
- package/dist/cjs/offline-session.js +370 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/pause-resume.js +43 -0
- package/dist/cjs/physics-cert.js +426 -0
- package/dist/cjs/physics2d.js +751 -0
- package/dist/cjs/physics3d.js +1996 -0
- package/dist/cjs/prediction-culling.js +203 -0
- package/dist/cjs/protocol-lab.js +1299 -0
- package/dist/cjs/r3f-render-adapter.js +209 -0
- package/dist/cjs/random.js +59 -0
- package/dist/cjs/replay-bundle.js +1598 -0
- package/dist/cjs/replay-inspect.js +236 -0
- package/dist/cjs/replay-scoring.js +68 -0
- package/dist/cjs/replay.js +356 -0
- package/dist/cjs/reports.js +181 -0
- package/dist/cjs/rollback-history.js +251 -0
- package/dist/cjs/runtime-guards.js +111 -0
- package/dist/cjs/sample-lab.js +145 -0
- package/dist/cjs/sample-scenes.js +752 -0
- package/dist/cjs/schema-artifacts.js +359 -0
- package/dist/cjs/schema-codegen.js +544 -0
- package/dist/cjs/schema-dsl-binary.js +655 -0
- package/dist/cjs/schema.js +319 -0
- package/dist/cjs/sdk-offline.js +99 -0
- package/dist/cjs/session-promotion.js +74 -0
- package/dist/cjs/session-snapshot.js +265 -0
- package/dist/cjs/session-wire.js +216 -0
- package/dist/cjs/signals.js +103 -0
- package/dist/cjs/sparse-set.js +169 -0
- package/dist/cjs/synctest.js +136 -0
- package/dist/cjs/system-lifecycle.js +286 -0
- package/dist/cjs/timers.js +61 -0
- package/dist/cjs/tools/static-checker.js +1468 -0
- package/dist/cjs/types.js +2 -0
- package/dist/cjs/venus-mp-budget.js +125 -0
- package/dist/cjs/ws-frame.js +255 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +11379 -0
- package/dist/collections.d.ts +9 -0
- package/dist/collections.js +30 -0
- package/dist/collision.d.ts +25 -0
- package/dist/collision.js +85 -0
- package/dist/commands.d.ts +137 -0
- package/dist/commands.js +977 -0
- package/dist/config-bundle.d.ts +89 -0
- package/dist/config-bundle.js +483 -0
- package/dist/creator.d.ts +20 -0
- package/dist/creator.js +11 -0
- package/dist/deterministic-primitives.d.ts +59 -0
- package/dist/deterministic-primitives.js +126 -0
- package/dist/deterministic-session.d.ts +197 -0
- package/dist/deterministic-session.js +1401 -0
- package/dist/ecs-lite.d.ts +26 -0
- package/dist/ecs-lite.js +152 -0
- package/dist/effects-adapter.d.ts +21 -0
- package/dist/effects-adapter.js +94 -0
- package/dist/engine-complete.d.ts +45 -0
- package/dist/engine-complete.js +2292 -0
- package/dist/engine-core-proof.d.ts +26 -0
- package/dist/engine-core-proof.js +66 -0
- package/dist/engine-parity-matrix.d.ts +300 -0
- package/dist/engine-parity-matrix.js +869 -0
- package/dist/engine-parity.d.ts +74 -0
- package/dist/engine-parity.js +3178 -0
- package/dist/engine-runtime.d.ts +351 -0
- package/dist/engine-runtime.js +3123 -0
- package/dist/errors.d.ts +11 -0
- package/dist/errors.js +17 -0
- package/dist/events.d.ts +45 -0
- package/dist/events.js +242 -0
- package/dist/examples/counter-duel.d.ts +43 -0
- package/dist/examples/counter-duel.js +150 -0
- package/dist/examples/fixed-arena.d.ts +110 -0
- package/dist/examples/fixed-arena.js +356 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +66 -0
- package/dist/input-authority.d.ts +82 -0
- package/dist/input-authority.js +147 -0
- package/dist/input-button.d.ts +36 -0
- package/dist/input-button.js +249 -0
- package/dist/input-timeline.d.ts +65 -0
- package/dist/input-timeline.js +412 -0
- package/dist/instant-replay.d.ts +59 -0
- package/dist/instant-replay.js +62 -0
- package/dist/lag-compensation3d.d.ts +146 -0
- package/dist/lag-compensation3d.js +827 -0
- package/dist/local-authority-server-runner.d.ts +79 -0
- package/dist/local-authority-server-runner.js +1118 -0
- package/dist/local-authority-wire.d.ts +142 -0
- package/dist/local-authority-wire.js +1477 -0
- package/dist/local-authority.d.ts +160 -0
- package/dist/local-authority.js +810 -0
- package/dist/local-ws-adapter.d.ts +14 -0
- package/dist/local-ws-adapter.js +146 -0
- package/dist/match-log.d.ts +74 -0
- package/dist/match-log.js +57 -0
- package/dist/math.d.ts +41 -0
- package/dist/math.js +154 -0
- package/dist/mock-network-adapter.d.ts +13 -0
- package/dist/mock-network-adapter.js +23 -0
- package/dist/movement.d.ts +155 -0
- package/dist/movement.js +694 -0
- package/dist/movement3d.d.ts +195 -0
- package/dist/movement3d.js +1238 -0
- package/dist/multiclient-authority.d.ts +30 -0
- package/dist/multiclient-authority.js +305 -0
- package/dist/multiplayer-service.d.ts +153 -0
- package/dist/multiplayer-service.js +429 -0
- package/dist/navigation.d.ts +91 -0
- package/dist/navigation.js +338 -0
- package/dist/navmesh.d.ts +236 -0
- package/dist/navmesh.js +1423 -0
- package/dist/networked-client.d.ts +124 -0
- package/dist/networked-client.js +688 -0
- package/dist/networked-input-authority.d.ts +51 -0
- package/dist/networked-input-authority.js +439 -0
- package/dist/node.d.ts +22 -0
- package/dist/node.js +19 -0
- package/dist/number-lab.d.ts +15 -0
- package/dist/number-lab.js +75 -0
- package/dist/offline-session.d.ts +2 -0
- package/dist/offline-session.js +367 -0
- package/dist/pause-resume.d.ts +48 -0
- package/dist/pause-resume.js +40 -0
- package/dist/physics-cert.d.ts +40 -0
- package/dist/physics-cert.js +389 -0
- package/dist/physics2d.d.ts +142 -0
- package/dist/physics2d.js +741 -0
- package/dist/physics3d.d.ts +285 -0
- package/dist/physics3d.js +1979 -0
- package/dist/prediction-culling.d.ts +34 -0
- package/dist/prediction-culling.js +200 -0
- package/dist/protocol-lab.d.ts +115 -0
- package/dist/protocol-lab.js +1295 -0
- package/dist/r3f-render-adapter.d.ts +61 -0
- package/dist/r3f-render-adapter.js +203 -0
- package/dist/random.d.ts +13 -0
- package/dist/random.js +55 -0
- package/dist/replay-bundle.d.ts +150 -0
- package/dist/replay-bundle.js +1586 -0
- package/dist/replay-inspect.d.ts +60 -0
- package/dist/replay-inspect.js +228 -0
- package/dist/replay-scoring.d.ts +28 -0
- package/dist/replay-scoring.js +65 -0
- package/dist/replay.d.ts +17 -0
- package/dist/replay.js +351 -0
- package/dist/reports.d.ts +176 -0
- package/dist/reports.js +174 -0
- package/dist/rollback-history.d.ts +46 -0
- package/dist/rollback-history.js +247 -0
- package/dist/runtime-guards.d.ts +1 -0
- package/dist/runtime-guards.js +108 -0
- package/dist/sample-lab.d.ts +32 -0
- package/dist/sample-lab.js +134 -0
- package/dist/sample-scenes.d.ts +86 -0
- package/dist/sample-scenes.js +745 -0
- package/dist/schema-artifacts.d.ts +49 -0
- package/dist/schema-artifacts.js +356 -0
- package/dist/schema-codegen.d.ts +21 -0
- package/dist/schema-codegen.js +538 -0
- package/dist/schema-dsl-binary.d.ts +75 -0
- package/dist/schema-dsl-binary.js +648 -0
- package/dist/schema.d.ts +87 -0
- package/dist/schema.js +315 -0
- package/dist/sdk-offline.d.ts +34 -0
- package/dist/sdk-offline.js +96 -0
- package/dist/session-promotion.d.ts +26 -0
- package/dist/session-promotion.js +70 -0
- package/dist/session-snapshot.d.ts +95 -0
- package/dist/session-snapshot.js +255 -0
- package/dist/session-wire.d.ts +89 -0
- package/dist/session-wire.js +211 -0
- package/dist/signals.d.ts +31 -0
- package/dist/signals.js +99 -0
- package/dist/sparse-set.d.ts +34 -0
- package/dist/sparse-set.js +165 -0
- package/dist/synctest.d.ts +31 -0
- package/dist/synctest.js +133 -0
- package/dist/system-lifecycle.d.ts +72 -0
- package/dist/system-lifecycle.js +281 -0
- package/dist/timers.d.ts +17 -0
- package/dist/timers.js +53 -0
- package/dist/tools/index.d.ts +4 -0
- package/dist/tools/index.js +4 -0
- package/dist/tools/static-checker.d.ts +31 -0
- package/dist/tools/static-checker.js +1462 -0
- package/dist/tools/vite-plugin.d.ts +69 -0
- package/dist/tools/vite-plugin.js +203 -0
- package/dist/types.d.ts +148 -0
- package/dist/types.js +1 -0
- package/dist/venus-mp-budget.d.ts +29 -0
- package/dist/venus-mp-budget.js +122 -0
- package/dist/ws-frame.d.ts +49 -0
- package/dist/ws-frame.js +247 -0
- package/package.json +169 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDeterministicR3fRenderAdapter = createDeterministicR3fRenderAdapter;
|
|
4
|
+
exports.createDeterministicR3fDebugOverlay = createDeterministicR3fDebugOverlay;
|
|
5
|
+
exports.interpolateDeterministicRenderNumber = interpolateDeterministicRenderNumber;
|
|
6
|
+
exports.interpolateDeterministicRenderVec2 = interpolateDeterministicRenderVec2;
|
|
7
|
+
const canonical_js_1 = require("./canonical.js");
|
|
8
|
+
function createDeterministicR3fRenderAdapter(config) {
|
|
9
|
+
const smoother = config.errorCorrection === undefined ? undefined : createRenderErrorSmoother(config.errorCorrection);
|
|
10
|
+
if (smoother !== undefined && config.errorCorrection !== undefined) {
|
|
11
|
+
const extractPoses = config.errorCorrection.poses;
|
|
12
|
+
config.runtime.subscribe((frame) => {
|
|
13
|
+
smoother.observe(frame.frame, extractPoses(toRenderFrame(frame, config.projectState).state));
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
const adapter = {
|
|
17
|
+
getFrame() {
|
|
18
|
+
return toRenderFrame(config.runtime.getFrame(), config.projectState);
|
|
19
|
+
},
|
|
20
|
+
setInput(slot, input) {
|
|
21
|
+
config.runtime.setInput(slot, input);
|
|
22
|
+
},
|
|
23
|
+
bindInput(slot, normalize) {
|
|
24
|
+
return (rawInput) => {
|
|
25
|
+
const input = normalize(rawInput);
|
|
26
|
+
config.runtime.setInput(slot, input);
|
|
27
|
+
return input;
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
update(deltaMs) {
|
|
31
|
+
// Decay before stepping so a correction detected in this update renders
|
|
32
|
+
// at the full mispredicted pose first, then blends on subsequent updates.
|
|
33
|
+
smoother?.advance(deltaMs);
|
|
34
|
+
return config.runtime.update(deltaMs);
|
|
35
|
+
},
|
|
36
|
+
stepFrames(count) {
|
|
37
|
+
config.runtime.stepFrames(count);
|
|
38
|
+
},
|
|
39
|
+
subscribe(listener) {
|
|
40
|
+
return config.runtime.subscribe((frame) => {
|
|
41
|
+
listener(toRenderFrame(frame, config.projectState));
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
getSmoothedPose(key) {
|
|
45
|
+
if (smoother === undefined) {
|
|
46
|
+
throw new Error('getSmoothedPose requires errorCorrection to be configured on the render adapter');
|
|
47
|
+
}
|
|
48
|
+
return smoother.pose(key);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
return adapter;
|
|
52
|
+
}
|
|
53
|
+
// Render-side only (plain floats, never fed back into sim state): when a
|
|
54
|
+
// rollback re-emits an already-rendered frame with a different pose, the
|
|
55
|
+
// rendered transform blends mispredicted -> corrected over errorCorrectionMs
|
|
56
|
+
// instead of snapping (Quantum "Error Prediction" analog).
|
|
57
|
+
function createRenderErrorSmoother(options) {
|
|
58
|
+
const windowMs = options.errorCorrectionMs ?? 120;
|
|
59
|
+
const snapThreshold = options.snapThreshold ?? 1e-6;
|
|
60
|
+
const maxErrorSnapDistance = options.maxErrorSnapDistance ?? Number.POSITIVE_INFINITY;
|
|
61
|
+
if (!Number.isFinite(windowMs) || windowMs < 0) {
|
|
62
|
+
throw new Error('errorCorrectionMs must be a finite number >= 0');
|
|
63
|
+
}
|
|
64
|
+
if (!Number.isFinite(snapThreshold) || snapThreshold < 0) {
|
|
65
|
+
throw new Error('snapThreshold must be a finite number >= 0');
|
|
66
|
+
}
|
|
67
|
+
if (Number.isNaN(maxErrorSnapDistance) || maxErrorSnapDistance < 0) {
|
|
68
|
+
throw new Error('maxErrorSnapDistance must be >= 0');
|
|
69
|
+
}
|
|
70
|
+
let lastFrame;
|
|
71
|
+
let tracked = new Map();
|
|
72
|
+
const errors = new Map();
|
|
73
|
+
function currentError(key) {
|
|
74
|
+
const entry = errors.get(key);
|
|
75
|
+
if (entry === undefined || windowMs <= 0) {
|
|
76
|
+
return { x: 0, y: 0, z: 0 };
|
|
77
|
+
}
|
|
78
|
+
const remaining = Math.min(1, Math.max(0, 1 - entry.elapsedMs / windowMs));
|
|
79
|
+
return { x: entry.x * remaining, y: entry.y * remaining, z: entry.z * remaining };
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
observe(frame, poses) {
|
|
83
|
+
const isCorrection = lastFrame !== undefined && frame <= lastFrame;
|
|
84
|
+
const nextTracked = new Map();
|
|
85
|
+
for (const pose of poses) {
|
|
86
|
+
if (!Number.isFinite(pose.x) || (pose.y !== undefined && !Number.isFinite(pose.y)) || (pose.z !== undefined && !Number.isFinite(pose.z))) {
|
|
87
|
+
throw new Error(`Render pose "${pose.key}" requires finite coordinates`);
|
|
88
|
+
}
|
|
89
|
+
if (nextTracked.has(pose.key)) {
|
|
90
|
+
throw new Error(`Duplicate render pose key: ${pose.key}`);
|
|
91
|
+
}
|
|
92
|
+
const previous = tracked.get(pose.key);
|
|
93
|
+
if (isCorrection && previous !== undefined) {
|
|
94
|
+
const carried = currentError(pose.key);
|
|
95
|
+
const dx = previous.x + carried.x - pose.x;
|
|
96
|
+
const dy = (previous.y ?? 0) + carried.y - (pose.y ?? 0);
|
|
97
|
+
const dz = (previous.z ?? 0) + carried.z - (pose.z ?? 0);
|
|
98
|
+
const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
99
|
+
if (windowMs > 0 && distance > snapThreshold && distance <= maxErrorSnapDistance) {
|
|
100
|
+
errors.set(pose.key, { x: dx, y: dy, z: dz, elapsedMs: 0 });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
errors.delete(pose.key);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
nextTracked.set(pose.key, { x: pose.x, y: pose.y, z: pose.z });
|
|
107
|
+
}
|
|
108
|
+
tracked = nextTracked;
|
|
109
|
+
for (const key of [...errors.keys()]) {
|
|
110
|
+
if (!tracked.has(key)) {
|
|
111
|
+
errors.delete(key);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
lastFrame = frame;
|
|
115
|
+
},
|
|
116
|
+
advance(deltaMs) {
|
|
117
|
+
if (!Number.isFinite(deltaMs)) {
|
|
118
|
+
throw new Error('Render error-correction advance requires a finite deltaMs');
|
|
119
|
+
}
|
|
120
|
+
if (deltaMs <= 0) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
for (const [key, entry] of errors) {
|
|
124
|
+
entry.elapsedMs += deltaMs;
|
|
125
|
+
if (entry.elapsedMs >= windowMs) {
|
|
126
|
+
errors.delete(key);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
pose(key) {
|
|
131
|
+
const base = tracked.get(key);
|
|
132
|
+
if (base === undefined) {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
const error = currentError(key);
|
|
136
|
+
const result = { key, x: base.x + error.x };
|
|
137
|
+
if (base.y !== undefined) {
|
|
138
|
+
result.y = base.y + error.y;
|
|
139
|
+
}
|
|
140
|
+
if (base.z !== undefined) {
|
|
141
|
+
result.z = base.z + error.z;
|
|
142
|
+
}
|
|
143
|
+
return freezeRenderValue(result);
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function createDeterministicR3fDebugOverlay(frame) {
|
|
148
|
+
return freezeRenderValue({
|
|
149
|
+
frame: frame.frame,
|
|
150
|
+
predictedFrame: frame.predictedFrame,
|
|
151
|
+
verifiedFrame: frame.verifiedFrame,
|
|
152
|
+
correctionFrames: Math.max(0, frame.predictedFrame - frame.verifiedFrame),
|
|
153
|
+
isPredicted: frame.predictedFrame > frame.verifiedFrame,
|
|
154
|
+
isVerified: frame.predictedFrame === frame.verifiedFrame,
|
|
155
|
+
checksum: frame.checksum,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function interpolateDeterministicRenderNumber(previous, next, alpha) {
|
|
159
|
+
if (!Number.isFinite(previous) || !Number.isFinite(next) || !Number.isFinite(alpha)) {
|
|
160
|
+
throw new Error('Render interpolation requires finite numbers');
|
|
161
|
+
}
|
|
162
|
+
const clampedAlpha = Math.min(1, Math.max(0, alpha));
|
|
163
|
+
return previous + (next - previous) * clampedAlpha;
|
|
164
|
+
}
|
|
165
|
+
function interpolateDeterministicRenderVec2(previous, next, alpha) {
|
|
166
|
+
return freezeRenderValue({
|
|
167
|
+
x: interpolateDeterministicRenderNumber(previous.x, next.x, alpha),
|
|
168
|
+
y: interpolateDeterministicRenderNumber(previous.y, next.y, alpha),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
function toRenderFrame(frame, projectState) {
|
|
172
|
+
const state = freezeRenderValue((0, canonical_js_1.cloneCanonical)(frame.state));
|
|
173
|
+
const renderState = projectState === undefined ? state : projectState(state);
|
|
174
|
+
const frozenRenderState = freezeRenderValue((0, canonical_js_1.cloneCanonical)(renderState));
|
|
175
|
+
const renderFrame = {
|
|
176
|
+
mode: frame.mode,
|
|
177
|
+
frame: frame.frame,
|
|
178
|
+
predictedFrame: frame.predictedFrame,
|
|
179
|
+
verifiedFrame: frame.verifiedFrame,
|
|
180
|
+
checksum: frame.checksum,
|
|
181
|
+
debug: freezeRenderValue({
|
|
182
|
+
frame: frame.frame,
|
|
183
|
+
predictedFrame: frame.predictedFrame,
|
|
184
|
+
verifiedFrame: frame.verifiedFrame,
|
|
185
|
+
correctionFrames: Math.max(0, frame.predictedFrame - frame.verifiedFrame),
|
|
186
|
+
isPredicted: frame.predictedFrame > frame.verifiedFrame,
|
|
187
|
+
isVerified: frame.predictedFrame === frame.verifiedFrame,
|
|
188
|
+
checksum: frame.checksum,
|
|
189
|
+
}),
|
|
190
|
+
state: frozenRenderState,
|
|
191
|
+
};
|
|
192
|
+
return freezeRenderValue(renderFrame);
|
|
193
|
+
}
|
|
194
|
+
function freezeRenderValue(value) {
|
|
195
|
+
if (value === null || typeof value !== 'object') {
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(value)) {
|
|
199
|
+
for (const item of value) {
|
|
200
|
+
freezeRenderValue(item);
|
|
201
|
+
}
|
|
202
|
+
return Object.freeze(value);
|
|
203
|
+
}
|
|
204
|
+
const record = value;
|
|
205
|
+
for (const key of Object.keys(record).sort()) {
|
|
206
|
+
freezeRenderValue(record[key]);
|
|
207
|
+
}
|
|
208
|
+
return Object.freeze(value);
|
|
209
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DeterministicRandom = void 0;
|
|
4
|
+
class DeterministicRandom {
|
|
5
|
+
state;
|
|
6
|
+
constructor(seed) {
|
|
7
|
+
this.state = seed >>> 0;
|
|
8
|
+
if (this.state === 0) {
|
|
9
|
+
this.state = 0x6d2b79f5;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
nextUint32() {
|
|
13
|
+
let nextState = this.state;
|
|
14
|
+
nextState ^= nextState << 13;
|
|
15
|
+
nextState ^= nextState >>> 17;
|
|
16
|
+
nextState ^= nextState << 5;
|
|
17
|
+
this.state = nextState >>> 0;
|
|
18
|
+
return this.state;
|
|
19
|
+
}
|
|
20
|
+
nextInt(minInclusive, maxInclusive) {
|
|
21
|
+
if (!Number.isInteger(minInclusive) || !Number.isInteger(maxInclusive) || maxInclusive < minInclusive) {
|
|
22
|
+
throw new Error('nextInt requires integer bounds with max >= min');
|
|
23
|
+
}
|
|
24
|
+
const range = maxInclusive - minInclusive + 1;
|
|
25
|
+
return minInclusive + (this.nextUint32() % range);
|
|
26
|
+
}
|
|
27
|
+
nextFixed(scale = 1_000_000) {
|
|
28
|
+
if (!Number.isInteger(scale) || scale <= 0) {
|
|
29
|
+
throw new Error('nextFixed scale must be a positive integer');
|
|
30
|
+
}
|
|
31
|
+
return this.nextUint32() % scale;
|
|
32
|
+
}
|
|
33
|
+
fork(label) {
|
|
34
|
+
const labelHash = hashLabel(label);
|
|
35
|
+
const child = new DeterministicRandom(1);
|
|
36
|
+
child.restore({ state: (this.state ^ labelHash) >>> 0 });
|
|
37
|
+
return child;
|
|
38
|
+
}
|
|
39
|
+
snapshot() {
|
|
40
|
+
return { state: this.state };
|
|
41
|
+
}
|
|
42
|
+
restore(snapshot) {
|
|
43
|
+
// Mirror the constructor's zero-guard: xorshift32 is permanently dead at 0.
|
|
44
|
+
// Reachable via fork() when `state ^ labelHash` lands on 0 — a 1-in-2^32
|
|
45
|
+
// landmine per fork on a frozen deterministic RNG.
|
|
46
|
+
const state = snapshot.state >>> 0;
|
|
47
|
+
this.state = state === 0 ? 0x6d2b79f5 : state;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.DeterministicRandom = DeterministicRandom;
|
|
51
|
+
function hashLabel(label) {
|
|
52
|
+
const value = String(label);
|
|
53
|
+
let hash = 0x811c9dc5;
|
|
54
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
55
|
+
hash ^= value.charCodeAt(index);
|
|
56
|
+
hash = Math.imul(hash, 0x01000193) >>> 0;
|
|
57
|
+
}
|
|
58
|
+
return hash;
|
|
59
|
+
}
|