@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,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createInputAuthority = createInputAuthority;
|
|
4
|
+
const canonical_js_1 = require("./canonical.js");
|
|
5
|
+
const errors_js_1 = require("./errors.js");
|
|
6
|
+
function createInputAuthority(config) {
|
|
7
|
+
(0, errors_js_1.invariant)(Number.isInteger(config.playerCount) && config.playerCount >= 1, 'playerCount must be a positive integer', 'input-authority.player-count');
|
|
8
|
+
(0, errors_js_1.invariant)(Number.isInteger(config.hardToleranceTicks) && config.hardToleranceTicks >= 0, 'hardToleranceTicks must be a non-negative integer', 'input-authority.hard-tolerance');
|
|
9
|
+
const playerCount = config.playerCount;
|
|
10
|
+
const maxFutureTicks = config.maxFutureTicks ?? Number.POSITIVE_INFINITY;
|
|
11
|
+
const retainedConfirmedFrames = config.retainedConfirmedFrames ?? 512;
|
|
12
|
+
const pending = new Map();
|
|
13
|
+
const lastConfirmedInput = Array.from({ length: playerCount }, () => config.neutralInput);
|
|
14
|
+
const retained = new Map();
|
|
15
|
+
let confirmedThrough = -1;
|
|
16
|
+
let earliestRetained = -1;
|
|
17
|
+
let confirmedTicks = 0;
|
|
18
|
+
if (config.restoreFrom !== undefined) {
|
|
19
|
+
const { confirmedThrough: restoredThrough, frames } = config.restoreFrom;
|
|
20
|
+
(0, errors_js_1.invariant)(frames.length > 0, 'restoreFrom requires at least one frame', 'input-authority.restore-empty');
|
|
21
|
+
for (let index = 0; index < frames.length; index += 1) {
|
|
22
|
+
const frame = frames[index];
|
|
23
|
+
(0, errors_js_1.invariant)(Number.isInteger(frame.tick) && (index === 0 || frame.tick === frames[index - 1].tick + 1), 'restoreFrom frames must be tick-contiguous', 'input-authority.restore-gap');
|
|
24
|
+
(0, errors_js_1.invariant)(frame.inputs.length === playerCount, 'restoreFrom frame inputs must cover every player slot', 'input-authority.restore-inputs');
|
|
25
|
+
retained.set(frame.tick, frame);
|
|
26
|
+
}
|
|
27
|
+
(0, errors_js_1.invariant)(frames[frames.length - 1].tick === restoredThrough, 'restoreFrom frames must end at the restored frontier', 'input-authority.restore-frontier');
|
|
28
|
+
earliestRetained = frames[0].tick;
|
|
29
|
+
confirmedThrough = restoredThrough;
|
|
30
|
+
const lastFrame = frames[frames.length - 1];
|
|
31
|
+
for (let slot = 0; slot < playerCount; slot += 1) {
|
|
32
|
+
lastConfirmedInput[slot] = lastFrame.inputs[slot];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
let substitutedInputs = 0;
|
|
36
|
+
let droppedLateInputs = 0;
|
|
37
|
+
let rejectedFutureInputs = 0;
|
|
38
|
+
function receiveInput(slot, tick, input) {
|
|
39
|
+
if (!Number.isInteger(slot) || slot < 0 || slot >= playerCount) {
|
|
40
|
+
return { accepted: false, reason: 'slot-out-of-range' };
|
|
41
|
+
}
|
|
42
|
+
if (!Number.isInteger(tick) || tick < 0) {
|
|
43
|
+
return { accepted: false, reason: 'invalid-tick' };
|
|
44
|
+
}
|
|
45
|
+
if (tick <= confirmedThrough) {
|
|
46
|
+
droppedLateInputs += 1;
|
|
47
|
+
return { accepted: false, reason: 'tick-already-confirmed' };
|
|
48
|
+
}
|
|
49
|
+
if (tick > confirmedThrough + maxFutureTicks) {
|
|
50
|
+
rejectedFutureInputs += 1;
|
|
51
|
+
return { accepted: false, reason: 'tick-too-far-ahead' };
|
|
52
|
+
}
|
|
53
|
+
let slots = pending.get(tick);
|
|
54
|
+
if (slots === undefined) {
|
|
55
|
+
slots = Array.from({ length: playerCount }, () => undefined);
|
|
56
|
+
pending.set(tick, slots);
|
|
57
|
+
}
|
|
58
|
+
slots[slot] = input;
|
|
59
|
+
return { accepted: true };
|
|
60
|
+
}
|
|
61
|
+
function confirmTick(tick) {
|
|
62
|
+
const slots = pending.get(tick);
|
|
63
|
+
const inputs = [];
|
|
64
|
+
const substitutedSlots = [];
|
|
65
|
+
for (let slot = 0; slot < playerCount; slot += 1) {
|
|
66
|
+
const submitted = slots?.[slot];
|
|
67
|
+
if (submitted === undefined) {
|
|
68
|
+
inputs.push(lastConfirmedInput[slot]);
|
|
69
|
+
substitutedSlots.push(slot);
|
|
70
|
+
substitutedInputs += 1;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
inputs.push(submitted);
|
|
74
|
+
lastConfirmedInput[slot] = submitted;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
pending.delete(tick);
|
|
78
|
+
const frame = {
|
|
79
|
+
tick,
|
|
80
|
+
inputs,
|
|
81
|
+
substitutedSlots,
|
|
82
|
+
checksum: String((0, canonical_js_1.defaultChecksum)({ tick, inputs })),
|
|
83
|
+
};
|
|
84
|
+
retained.set(tick, frame);
|
|
85
|
+
if (earliestRetained === -1) {
|
|
86
|
+
earliestRetained = tick;
|
|
87
|
+
}
|
|
88
|
+
if (retained.size > retainedConfirmedFrames) {
|
|
89
|
+
const oldest = tick - retainedConfirmedFrames;
|
|
90
|
+
if (retained.delete(oldest)) {
|
|
91
|
+
earliestRetained = oldest + 1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
confirmedThrough = tick;
|
|
95
|
+
confirmedTicks += 1;
|
|
96
|
+
return frame;
|
|
97
|
+
}
|
|
98
|
+
function advance(now) {
|
|
99
|
+
const frames = [];
|
|
100
|
+
let next = confirmedThrough + 1;
|
|
101
|
+
while (next <= now) {
|
|
102
|
+
const slots = pending.get(next);
|
|
103
|
+
const allPresent = slots !== undefined && slots.every((value) => value !== undefined);
|
|
104
|
+
const deadlinePassed = now - next >= config.hardToleranceTicks;
|
|
105
|
+
if (!allPresent && !deadlinePassed) {
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
frames.push(confirmTick(next));
|
|
109
|
+
next += 1;
|
|
110
|
+
}
|
|
111
|
+
return frames;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
playerCount,
|
|
115
|
+
get confirmedThrough() {
|
|
116
|
+
return confirmedThrough;
|
|
117
|
+
},
|
|
118
|
+
receiveInput,
|
|
119
|
+
advance,
|
|
120
|
+
get earliestRetainedTick() {
|
|
121
|
+
return earliestRetained;
|
|
122
|
+
},
|
|
123
|
+
confirmedFrame(tick) {
|
|
124
|
+
return retained.get(tick);
|
|
125
|
+
},
|
|
126
|
+
confirmedFrameRange(from, to) {
|
|
127
|
+
(0, errors_js_1.invariant)(Number.isInteger(from) && Number.isInteger(to) && from <= to, 'confirmedFrameRange requires an ordered integer range', 'input-authority.range-invalid');
|
|
128
|
+
const frames = [];
|
|
129
|
+
for (let tick = from; tick <= to; tick += 1) {
|
|
130
|
+
const frame = retained.get(tick);
|
|
131
|
+
(0, errors_js_1.invariant)(frame !== undefined, `confirmed frame ${tick} is no longer retained`, 'input-authority.range-unavailable');
|
|
132
|
+
frames.push(frame);
|
|
133
|
+
}
|
|
134
|
+
return frames;
|
|
135
|
+
},
|
|
136
|
+
pruneConfirmedBefore(tick) {
|
|
137
|
+
(0, errors_js_1.invariant)(Number.isInteger(tick) && tick <= confirmedThrough + 1, 'pruneConfirmedBefore tick must be an integer at or below the confirmed frontier + 1', 'input-authority.prune-tick');
|
|
138
|
+
if (earliestRetained === -1 || tick <= earliestRetained) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
for (let t = earliestRetained; t < tick; t += 1) {
|
|
142
|
+
retained.delete(t);
|
|
143
|
+
}
|
|
144
|
+
earliestRetained = tick;
|
|
145
|
+
},
|
|
146
|
+
stats() {
|
|
147
|
+
return { confirmedTicks, substitutedInputs, droppedLateInputs, rejectedFutureInputs };
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.deterministicButtonInitialState = void 0;
|
|
4
|
+
exports.stepDeterministicButton = stepDeterministicButton;
|
|
5
|
+
exports.runDeterministicButtonFixture = runDeterministicButtonFixture;
|
|
6
|
+
exports.runDeterministicDescriptorButtonFixture = runDeterministicDescriptorButtonFixture;
|
|
7
|
+
exports.readDeterministicDescriptorButtonValue = readDeterministicDescriptorButtonValue;
|
|
8
|
+
const canonical_js_1 = require("./canonical.js");
|
|
9
|
+
const schema_artifacts_js_1 = require("./schema-artifacts.js");
|
|
10
|
+
exports.deterministicButtonInitialState = {
|
|
11
|
+
down: false,
|
|
12
|
+
previousDown: false,
|
|
13
|
+
pressedFrame: -1,
|
|
14
|
+
releasedFrame: -1,
|
|
15
|
+
};
|
|
16
|
+
function stepDeterministicButton(state, down, frame) {
|
|
17
|
+
if (!Number.isInteger(frame) || frame < 0) {
|
|
18
|
+
throw new Error('Deterministic button frame must be a non-negative integer');
|
|
19
|
+
}
|
|
20
|
+
const wasPressed = down && !state.down;
|
|
21
|
+
const wasReleased = !down && state.down;
|
|
22
|
+
const next = {
|
|
23
|
+
down,
|
|
24
|
+
previousDown: state.down,
|
|
25
|
+
pressedFrame: wasPressed ? frame : state.pressedFrame,
|
|
26
|
+
releasedFrame: wasReleased ? frame : state.releasedFrame,
|
|
27
|
+
};
|
|
28
|
+
return {
|
|
29
|
+
state: next,
|
|
30
|
+
isDown: next.down,
|
|
31
|
+
wasPressed,
|
|
32
|
+
wasReleased,
|
|
33
|
+
checksum: (0, canonical_js_1.defaultChecksum)({ frame, next, wasPressed, wasReleased }),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function runDeterministicButtonFixture(frames = 512) {
|
|
37
|
+
let state = exports.deterministicButtonInitialState;
|
|
38
|
+
let snapshot = state;
|
|
39
|
+
let pressedCount = 0;
|
|
40
|
+
let releasedCount = 0;
|
|
41
|
+
let heldFrames = 0;
|
|
42
|
+
let repeatedFrames = 0;
|
|
43
|
+
const transitions = [];
|
|
44
|
+
for (let frame = 0; frame < frames; frame += 1) {
|
|
45
|
+
if (frame === Math.floor(frames / 2)) {
|
|
46
|
+
snapshot = state;
|
|
47
|
+
}
|
|
48
|
+
const down = buttonDownAt(frame);
|
|
49
|
+
const step = stepDeterministicButton(state, down, frame);
|
|
50
|
+
state = step.state;
|
|
51
|
+
pressedCount += step.wasPressed ? 1 : 0;
|
|
52
|
+
releasedCount += step.wasReleased ? 1 : 0;
|
|
53
|
+
heldFrames += step.isDown ? 1 : 0;
|
|
54
|
+
repeatedFrames += step.isDown && !step.wasPressed ? 1 : 0;
|
|
55
|
+
if (step.wasPressed || step.wasReleased) {
|
|
56
|
+
transitions.push(`${frame}:${step.wasPressed ? 'pressed' : 'released'}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const checksum = (0, canonical_js_1.defaultChecksum)({ state, pressedCount, releasedCount, heldFrames, repeatedFrames, transitions });
|
|
60
|
+
let restored = snapshot;
|
|
61
|
+
let restoredPressedCount = 0;
|
|
62
|
+
let restoredReleasedCount = 0;
|
|
63
|
+
let restoredHeldFrames = 0;
|
|
64
|
+
let restoredRepeatedFrames = 0;
|
|
65
|
+
const restoredTransitions = [];
|
|
66
|
+
for (let frame = Math.floor(frames / 2); frame < frames; frame += 1) {
|
|
67
|
+
const step = stepDeterministicButton(restored, buttonDownAt(frame), frame);
|
|
68
|
+
restored = step.state;
|
|
69
|
+
restoredPressedCount += step.wasPressed ? 1 : 0;
|
|
70
|
+
restoredReleasedCount += step.wasReleased ? 1 : 0;
|
|
71
|
+
restoredHeldFrames += step.isDown ? 1 : 0;
|
|
72
|
+
restoredRepeatedFrames += step.isDown && !step.wasPressed ? 1 : 0;
|
|
73
|
+
if (step.wasPressed || step.wasReleased) {
|
|
74
|
+
restoredTransitions.push(`${frame}:${step.wasPressed ? 'pressed' : 'released'}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const prefix = replayButtonPrefix(Math.floor(frames / 2));
|
|
78
|
+
const restoredChecksum = (0, canonical_js_1.defaultChecksum)({
|
|
79
|
+
state: restored,
|
|
80
|
+
pressedCount: prefix.pressedCount + restoredPressedCount,
|
|
81
|
+
releasedCount: prefix.releasedCount + restoredReleasedCount,
|
|
82
|
+
heldFrames: prefix.heldFrames + restoredHeldFrames,
|
|
83
|
+
repeatedFrames: prefix.repeatedFrames + restoredRepeatedFrames,
|
|
84
|
+
transitions: [...prefix.transitions, ...restoredTransitions],
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
checksum,
|
|
88
|
+
restoredChecksum,
|
|
89
|
+
rollbackEquivalent: checksum === restoredChecksum,
|
|
90
|
+
pressedCount,
|
|
91
|
+
releasedCount,
|
|
92
|
+
heldFrames,
|
|
93
|
+
repeatedFrames,
|
|
94
|
+
transitionsStable: pressedCount === releasedCount && transitions.length === pressedCount + releasedCount,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function runDeterministicDescriptorButtonFixture(frames = 512) {
|
|
98
|
+
const artifacts = (0, schema_artifacts_js_1.createSchemaArtifacts)(buttonDescriptor());
|
|
99
|
+
const missingDefault = artifacts.deserializeInput(artifacts.serializeInput({ axis: 0 }));
|
|
100
|
+
let state = exports.deterministicButtonInitialState;
|
|
101
|
+
let snapshot = state;
|
|
102
|
+
let pressedCount = 0;
|
|
103
|
+
let releasedCount = 0;
|
|
104
|
+
let heldFrames = 0;
|
|
105
|
+
let repeatedFrames = 0;
|
|
106
|
+
let serializedBytes = 0;
|
|
107
|
+
const transitions = [];
|
|
108
|
+
for (let frame = 0; frame < frames; frame += 1) {
|
|
109
|
+
if (frame === Math.floor(frames / 2)) {
|
|
110
|
+
snapshot = state;
|
|
111
|
+
}
|
|
112
|
+
const input = descriptorButtonInputAt(frame);
|
|
113
|
+
const serialized = artifacts.serializeInput(input);
|
|
114
|
+
const roundTrip = artifacts.deserializeInput(serialized);
|
|
115
|
+
serializedBytes += serialized.byteLength;
|
|
116
|
+
const step = stepDeterministicButton(state, buttonValue(roundTrip), frame);
|
|
117
|
+
state = step.state;
|
|
118
|
+
pressedCount += step.wasPressed ? 1 : 0;
|
|
119
|
+
releasedCount += step.wasReleased ? 1 : 0;
|
|
120
|
+
heldFrames += step.isDown ? 1 : 0;
|
|
121
|
+
repeatedFrames += step.isDown && !step.wasPressed ? 1 : 0;
|
|
122
|
+
if (step.wasPressed || step.wasReleased) {
|
|
123
|
+
transitions.push(`${frame}:${step.wasPressed ? 'pressed' : 'released'}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const checksum = (0, canonical_js_1.defaultChecksum)({ state, pressedCount, releasedCount, heldFrames, repeatedFrames, transitions });
|
|
127
|
+
const prefix = replayDescriptorButtonPrefix(Math.floor(frames / 2), artifacts);
|
|
128
|
+
let restored = snapshot;
|
|
129
|
+
let restoredPressedCount = 0;
|
|
130
|
+
let restoredReleasedCount = 0;
|
|
131
|
+
let restoredHeldFrames = 0;
|
|
132
|
+
let restoredRepeatedFrames = 0;
|
|
133
|
+
const restoredTransitions = [];
|
|
134
|
+
for (let frame = Math.floor(frames / 2); frame < frames; frame += 1) {
|
|
135
|
+
const roundTrip = artifacts.deserializeInput(artifacts.serializeInput(descriptorButtonInputAt(frame)));
|
|
136
|
+
const step = stepDeterministicButton(restored, buttonValue(roundTrip), frame);
|
|
137
|
+
restored = step.state;
|
|
138
|
+
restoredPressedCount += step.wasPressed ? 1 : 0;
|
|
139
|
+
restoredReleasedCount += step.wasReleased ? 1 : 0;
|
|
140
|
+
restoredHeldFrames += step.isDown ? 1 : 0;
|
|
141
|
+
restoredRepeatedFrames += step.isDown && !step.wasPressed ? 1 : 0;
|
|
142
|
+
if (step.wasPressed || step.wasReleased) {
|
|
143
|
+
restoredTransitions.push(`${frame}:${step.wasPressed ? 'pressed' : 'released'}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const restoredChecksum = (0, canonical_js_1.defaultChecksum)({
|
|
147
|
+
state: restored,
|
|
148
|
+
pressedCount: prefix.pressedCount + restoredPressedCount,
|
|
149
|
+
releasedCount: prefix.releasedCount + restoredReleasedCount,
|
|
150
|
+
heldFrames: prefix.heldFrames + restoredHeldFrames,
|
|
151
|
+
repeatedFrames: prefix.repeatedFrames + restoredRepeatedFrames,
|
|
152
|
+
transitions: [...prefix.transitions, ...restoredTransitions],
|
|
153
|
+
});
|
|
154
|
+
const roundTripA = artifacts.serializeInput({ axis: 1, jump: true });
|
|
155
|
+
const roundTripB = artifacts.serializeInput(artifacts.deserializeInput(roundTripA));
|
|
156
|
+
const descriptorArtifactId = artifacts.descriptor.artifactId;
|
|
157
|
+
const descriptorButtonFields = artifacts.descriptor.input.fields.filter((field) => field.kind === 'button').length;
|
|
158
|
+
const defaultApplied = buttonValue(missingDefault) === false;
|
|
159
|
+
const schemaRoundTripStable = (0, canonical_js_1.defaultChecksum)(roundTripA) === (0, canonical_js_1.defaultChecksum)(roundTripB);
|
|
160
|
+
return {
|
|
161
|
+
checksum,
|
|
162
|
+
restoredChecksum,
|
|
163
|
+
rollbackEquivalent: checksum === restoredChecksum,
|
|
164
|
+
pressedCount,
|
|
165
|
+
releasedCount,
|
|
166
|
+
heldFrames,
|
|
167
|
+
repeatedFrames,
|
|
168
|
+
transitionsStable: pressedCount === releasedCount && transitions.length === pressedCount + releasedCount,
|
|
169
|
+
descriptorArtifactId,
|
|
170
|
+
descriptorButtonFields,
|
|
171
|
+
serializedBytes,
|
|
172
|
+
defaultApplied,
|
|
173
|
+
schemaRoundTripStable,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function replayButtonPrefix(frames) {
|
|
177
|
+
let state = exports.deterministicButtonInitialState;
|
|
178
|
+
let pressedCount = 0;
|
|
179
|
+
let releasedCount = 0;
|
|
180
|
+
let heldFrames = 0;
|
|
181
|
+
let repeatedFrames = 0;
|
|
182
|
+
const transitions = [];
|
|
183
|
+
for (let frame = 0; frame < frames; frame += 1) {
|
|
184
|
+
const step = stepDeterministicButton(state, buttonDownAt(frame), frame);
|
|
185
|
+
state = step.state;
|
|
186
|
+
pressedCount += step.wasPressed ? 1 : 0;
|
|
187
|
+
releasedCount += step.wasReleased ? 1 : 0;
|
|
188
|
+
heldFrames += step.isDown ? 1 : 0;
|
|
189
|
+
repeatedFrames += step.isDown && !step.wasPressed ? 1 : 0;
|
|
190
|
+
if (step.wasPressed || step.wasReleased) {
|
|
191
|
+
transitions.push(`${frame}:${step.wasPressed ? 'pressed' : 'released'}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return { pressedCount, releasedCount, heldFrames, repeatedFrames, transitions };
|
|
195
|
+
}
|
|
196
|
+
function replayDescriptorButtonPrefix(frames, artifacts) {
|
|
197
|
+
let state = exports.deterministicButtonInitialState;
|
|
198
|
+
let pressedCount = 0;
|
|
199
|
+
let releasedCount = 0;
|
|
200
|
+
let heldFrames = 0;
|
|
201
|
+
let repeatedFrames = 0;
|
|
202
|
+
const transitions = [];
|
|
203
|
+
for (let frame = 0; frame < frames; frame += 1) {
|
|
204
|
+
const roundTrip = artifacts.deserializeInput(artifacts.serializeInput(descriptorButtonInputAt(frame)));
|
|
205
|
+
const step = stepDeterministicButton(state, buttonValue(roundTrip), frame);
|
|
206
|
+
state = step.state;
|
|
207
|
+
pressedCount += step.wasPressed ? 1 : 0;
|
|
208
|
+
releasedCount += step.wasReleased ? 1 : 0;
|
|
209
|
+
heldFrames += step.isDown ? 1 : 0;
|
|
210
|
+
repeatedFrames += step.isDown && !step.wasPressed ? 1 : 0;
|
|
211
|
+
if (step.wasPressed || step.wasReleased) {
|
|
212
|
+
transitions.push(`${frame}:${step.wasPressed ? 'pressed' : 'released'}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return { pressedCount, releasedCount, heldFrames, repeatedFrames, transitions };
|
|
216
|
+
}
|
|
217
|
+
function buttonDownAt(frame) {
|
|
218
|
+
const phase = frame % 16;
|
|
219
|
+
return (phase >= 2 && phase <= 6) || phase === 10 || phase === 11;
|
|
220
|
+
}
|
|
221
|
+
function descriptorButtonInputAt(frame) {
|
|
222
|
+
return {
|
|
223
|
+
axis: (frame % 3) - 1,
|
|
224
|
+
jump: buttonDownAt(frame),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
function readDeterministicDescriptorButtonValue(value) {
|
|
228
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
229
|
+
throw new Error('Descriptor button input did not deserialize to a boolean jump field');
|
|
230
|
+
}
|
|
231
|
+
const record = value;
|
|
232
|
+
if (typeof record.jump !== 'boolean') {
|
|
233
|
+
throw new Error('Descriptor button input did not deserialize to a boolean jump field');
|
|
234
|
+
}
|
|
235
|
+
return record.jump;
|
|
236
|
+
}
|
|
237
|
+
const buttonValue = readDeterministicDescriptorButtonValue;
|
|
238
|
+
function buttonDescriptor() {
|
|
239
|
+
return {
|
|
240
|
+
deterministicVersion: 'button-input@1',
|
|
241
|
+
tickRate: 60,
|
|
242
|
+
maxPlayers: 128,
|
|
243
|
+
input: {
|
|
244
|
+
id: 'button-input/v1',
|
|
245
|
+
fields: [
|
|
246
|
+
{ name: 'axis', kind: 'integer', policy: 'repeat', defaultValue: 0, min: -1, max: 1, bitPacking: { bits: 2, signed: true } },
|
|
247
|
+
{ name: 'jump', kind: 'button', policy: 'command', defaultValue: false, bitPacking: { bits: 1 } },
|
|
248
|
+
],
|
|
249
|
+
},
|
|
250
|
+
state: {
|
|
251
|
+
id: 'button-state/v1',
|
|
252
|
+
fields: [{ name: 'pressed', kind: 'integer', numericMode: 'integer', checksummed: true }],
|
|
253
|
+
},
|
|
254
|
+
systems: [{ id: 'button-input' }],
|
|
255
|
+
};
|
|
256
|
+
}
|