@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.startLocalWebSocketProtocolServer = startLocalWebSocketProtocolServer;
|
|
4
|
+
exports.runLocalWebSocketAdapterTest = runLocalWebSocketAdapterTest;
|
|
5
|
+
const node_http_1 = require("node:http");
|
|
6
|
+
const mock_network_adapter_js_1 = require("./mock-network-adapter.js");
|
|
7
|
+
const ws_frame_js_1 = require("./ws-frame.js");
|
|
8
|
+
async function startLocalWebSocketProtocolServer(port) {
|
|
9
|
+
const server = (0, node_http_1.createServer)((request, response) => {
|
|
10
|
+
if (request.url === '/health') {
|
|
11
|
+
response.statusCode = 200;
|
|
12
|
+
response.setHeader('content-type', 'text/plain');
|
|
13
|
+
response.end('ok');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
response.statusCode = 404;
|
|
17
|
+
response.end('not found');
|
|
18
|
+
});
|
|
19
|
+
server.on('upgrade', (request, socket, head) => {
|
|
20
|
+
if (new URL(request.url ?? '/', 'http://127.0.0.1').pathname !== '/protocol') {
|
|
21
|
+
socket.end('HTTP/1.1 404 Not Found\r\n\r\n');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
acceptWebSocket(request, socket);
|
|
25
|
+
const connection = createLocalProtocolConnection(socket);
|
|
26
|
+
if (head.byteLength > 0) {
|
|
27
|
+
connection.receive(head);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
await new Promise((resolveListen) => {
|
|
31
|
+
server.listen(port, '127.0.0.1', resolveListen);
|
|
32
|
+
});
|
|
33
|
+
const actualPort = serverPort(server);
|
|
34
|
+
return {
|
|
35
|
+
port: actualPort,
|
|
36
|
+
healthUrl: `http://127.0.0.1:${actualPort}/health`,
|
|
37
|
+
url: `ws://127.0.0.1:${actualPort}/protocol`,
|
|
38
|
+
close() {
|
|
39
|
+
return new Promise((resolveClose, rejectClose) => {
|
|
40
|
+
server.close((error) => {
|
|
41
|
+
if (error !== undefined) {
|
|
42
|
+
rejectClose(error);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
resolveClose();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
async function runLocalWebSocketAdapterTest(options) {
|
|
52
|
+
const socket = new WebSocket(options.url);
|
|
53
|
+
const request = {
|
|
54
|
+
kind: 'run-protocol',
|
|
55
|
+
options: options.protocolOptions,
|
|
56
|
+
};
|
|
57
|
+
await new Promise((resolveOpen, rejectOpen) => {
|
|
58
|
+
socket.addEventListener('open', () => resolveOpen(), { once: true });
|
|
59
|
+
socket.addEventListener('error', () => rejectOpen(new Error(`Could not connect to ${options.url}`)), { once: true });
|
|
60
|
+
});
|
|
61
|
+
const response = new Promise((resolveMessage, rejectMessage) => {
|
|
62
|
+
socket.addEventListener('message', (event) => {
|
|
63
|
+
try {
|
|
64
|
+
resolveMessage(JSON.parse(String(event.data)));
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
rejectMessage(error);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
socket.close();
|
|
71
|
+
}
|
|
72
|
+
}, { once: true });
|
|
73
|
+
socket.addEventListener('error', () => rejectMessage(new Error(`WebSocket error from ${options.url}`)), { once: true });
|
|
74
|
+
});
|
|
75
|
+
socket.send(JSON.stringify(request));
|
|
76
|
+
return response;
|
|
77
|
+
}
|
|
78
|
+
function acceptWebSocket(request, socket) {
|
|
79
|
+
const key = request.headers['sec-websocket-key'];
|
|
80
|
+
if (typeof key !== 'string') {
|
|
81
|
+
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
socket.write([
|
|
85
|
+
'HTTP/1.1 101 Switching Protocols',
|
|
86
|
+
'Upgrade: websocket',
|
|
87
|
+
'Connection: Upgrade',
|
|
88
|
+
`Sec-WebSocket-Accept: ${(0, ws_frame_js_1.webSocketAcceptKey)(key)}`,
|
|
89
|
+
'\r\n',
|
|
90
|
+
].join('\r\n'));
|
|
91
|
+
}
|
|
92
|
+
function createLocalProtocolConnection(socket) {
|
|
93
|
+
let pending = new Uint8Array();
|
|
94
|
+
socket.on('data', (chunk) => {
|
|
95
|
+
receive(chunk);
|
|
96
|
+
});
|
|
97
|
+
socket.on('error', () => {
|
|
98
|
+
socket.destroy();
|
|
99
|
+
});
|
|
100
|
+
function receive(chunk) {
|
|
101
|
+
pending = concatBytes(pending, chunk);
|
|
102
|
+
let result = (0, ws_frame_js_1.readWebSocketFrame)(pending);
|
|
103
|
+
while (result.kind === 'frame') {
|
|
104
|
+
const frame = result.frame;
|
|
105
|
+
pending = pending.slice(frame.bytesRead);
|
|
106
|
+
if (frame.opcode === 8) {
|
|
107
|
+
socket.end((0, ws_frame_js_1.encodeWebSocketCloseFrame)());
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (frame.opcode === 1) {
|
|
111
|
+
handleProtocolText(socket, frame.text);
|
|
112
|
+
}
|
|
113
|
+
result = (0, ws_frame_js_1.readWebSocketFrame)(pending);
|
|
114
|
+
}
|
|
115
|
+
if (result.kind === 'invalid') {
|
|
116
|
+
// Malformed frame: close the connection instead of crashing the process.
|
|
117
|
+
socket.end((0, ws_frame_js_1.encodeWebSocketCloseFrame)());
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return { receive };
|
|
121
|
+
}
|
|
122
|
+
function handleProtocolText(socket, text) {
|
|
123
|
+
try {
|
|
124
|
+
const request = JSON.parse(text);
|
|
125
|
+
if (request.kind !== 'run-protocol') {
|
|
126
|
+
throw new Error('Unsupported local WebSocket request');
|
|
127
|
+
}
|
|
128
|
+
const replay = (0, mock_network_adapter_js_1.createDeterministicMockNetworkAdapter)(request.options).exportReplay();
|
|
129
|
+
socket.write((0, ws_frame_js_1.encodeWebSocketTextFrame)(JSON.stringify(replay)));
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
socket.write((0, ws_frame_js_1.encodeWebSocketTextFrame)(JSON.stringify({
|
|
133
|
+
kind: 'error',
|
|
134
|
+
message: error instanceof Error ? error.message : String(error),
|
|
135
|
+
})));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function concatBytes(left, right) {
|
|
139
|
+
const output = new Uint8Array(left.byteLength + right.byteLength);
|
|
140
|
+
output.set(left, 0);
|
|
141
|
+
output.set(right, left.byteLength);
|
|
142
|
+
return output;
|
|
143
|
+
}
|
|
144
|
+
function serverPort(server) {
|
|
145
|
+
const address = server.address();
|
|
146
|
+
if (address === null || typeof address === 'string') {
|
|
147
|
+
throw new Error('Could not determine local WebSocket server port');
|
|
148
|
+
}
|
|
149
|
+
return address.port;
|
|
150
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyScoredMatchLog = verifyScoredMatchLog;
|
|
4
|
+
exports.matchLogSessionFactory = matchLogSessionFactory;
|
|
5
|
+
const offline_session_js_1 = require("./offline-session.js");
|
|
6
|
+
const canonical_js_1 = require("./canonical.js");
|
|
7
|
+
function verifyScoredMatchLog(config) {
|
|
8
|
+
const { log } = config;
|
|
9
|
+
// The log must be the complete, gap-free tick 0..confirmedThrough sequence —
|
|
10
|
+
// a truncated or reordered log must never verify a score.
|
|
11
|
+
if (log.frames.length !== log.confirmedThrough + 1 || log.frames.some((frame, index) => frame.tick !== index)) {
|
|
12
|
+
return { ok: false, reason: 'log-not-contiguous', submittedScore: config.submittedScore, framesReplayed: 0 };
|
|
13
|
+
}
|
|
14
|
+
const session = config.createSession({ seed: log.seed, playerCount: log.playerCount });
|
|
15
|
+
for (const frame of log.frames) {
|
|
16
|
+
for (let slot = 0; slot < log.playerCount; slot += 1) {
|
|
17
|
+
session.setInput(slot, config.decodeInput(frame.inputs[slot]));
|
|
18
|
+
}
|
|
19
|
+
session.stepFrames(1);
|
|
20
|
+
}
|
|
21
|
+
const finalChecksum = String((0, canonical_js_1.defaultChecksum)(session.getState()));
|
|
22
|
+
if (config.expectedFinalChecksum !== undefined && finalChecksum !== config.expectedFinalChecksum) {
|
|
23
|
+
return {
|
|
24
|
+
ok: false,
|
|
25
|
+
reason: 'checksum-mismatch',
|
|
26
|
+
submittedScore: config.submittedScore,
|
|
27
|
+
framesReplayed: log.frames.length,
|
|
28
|
+
finalChecksum,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
const replayScore = config.extractScore(session.getState());
|
|
32
|
+
if (replayScore !== config.submittedScore) {
|
|
33
|
+
return {
|
|
34
|
+
ok: false,
|
|
35
|
+
reason: 'score-mismatch',
|
|
36
|
+
replayScore,
|
|
37
|
+
submittedScore: config.submittedScore,
|
|
38
|
+
framesReplayed: log.frames.length,
|
|
39
|
+
finalChecksum,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: true,
|
|
44
|
+
replayScore,
|
|
45
|
+
submittedScore: config.submittedScore,
|
|
46
|
+
framesReplayed: log.frames.length,
|
|
47
|
+
finalChecksum,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Convenience: build the verifier's session factory from a full
|
|
52
|
+
* DeterministicSessionConfig (creators usually have one of these), overriding
|
|
53
|
+
* seed/playerCount from the log.
|
|
54
|
+
*/
|
|
55
|
+
function matchLogSessionFactory(base) {
|
|
56
|
+
return ({ seed, playerCount }) => (0, offline_session_js_1.createOfflineSession)({
|
|
57
|
+
...base,
|
|
58
|
+
randomSeed: seed,
|
|
59
|
+
playerCount,
|
|
60
|
+
});
|
|
61
|
+
}
|
package/dist/cjs/math.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDeterministicMath = createDeterministicMath;
|
|
4
|
+
const DEFAULT_MIN_FIXED = -2_147_483_648;
|
|
5
|
+
const DEFAULT_MAX_FIXED = 2_147_483_647;
|
|
6
|
+
function createDeterministicMath(fixedScale = 1_000, minFixed = DEFAULT_MIN_FIXED, maxFixed = DEFAULT_MAX_FIXED) {
|
|
7
|
+
if (!Number.isInteger(fixedScale) || fixedScale <= 0) {
|
|
8
|
+
throw new Error('fixedScale must be a positive integer');
|
|
9
|
+
}
|
|
10
|
+
if (!Number.isInteger(minFixed) || !Number.isInteger(maxFixed) || minFixed >= maxFixed) {
|
|
11
|
+
throw new Error('fixed range must be integer min < max');
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
fixedScale,
|
|
15
|
+
minFixed,
|
|
16
|
+
maxFixed,
|
|
17
|
+
toFixed(value) {
|
|
18
|
+
if (!Number.isFinite(value)) {
|
|
19
|
+
throw new Error('Cannot convert a non-finite number to fixed point');
|
|
20
|
+
}
|
|
21
|
+
// normalizeZero: Math.round of a tiny negative yields -0, which the
|
|
22
|
+
// canonical layer tags as {$rdm:'negative-zero'} — keep -0 out of state.
|
|
23
|
+
return normalizeZero(saturate(Math.round(value * fixedScale), minFixed, maxFixed));
|
|
24
|
+
},
|
|
25
|
+
fromFixed(value) {
|
|
26
|
+
if (!Number.isInteger(value)) {
|
|
27
|
+
throw new Error('Fixed point values must be integers');
|
|
28
|
+
}
|
|
29
|
+
return value / fixedScale;
|
|
30
|
+
},
|
|
31
|
+
add(a, b) {
|
|
32
|
+
assertFixed(a);
|
|
33
|
+
assertFixed(b);
|
|
34
|
+
const result = a + b;
|
|
35
|
+
if (result < minFixed || result > maxFixed) {
|
|
36
|
+
throw new Error('Fixed point addition overflow');
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
},
|
|
40
|
+
sub(a, b) {
|
|
41
|
+
assertFixed(a);
|
|
42
|
+
assertFixed(b);
|
|
43
|
+
const result = a - b;
|
|
44
|
+
if (result < minFixed || result > maxFixed) {
|
|
45
|
+
throw new Error('Fixed point subtraction overflow');
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
},
|
|
49
|
+
// Exactness bound: the a*b intermediate is an IEEE double, so results are
|
|
50
|
+
// deterministic everywhere (correctly-rounded *), but INTEGER-EXACT only
|
|
51
|
+
// while |a*b| <= 2^53 — at the default fixedScale 1000 that is operands up
|
|
52
|
+
// to ~95k real units each. Beyond that the product quietly loses low bits
|
|
53
|
+
// (identically on every peer). Keep gameplay magnitudes inside the bound
|
|
54
|
+
// or use a larger fixedScale with smaller ranges. div has the same bound
|
|
55
|
+
// via a*fixedScale.
|
|
56
|
+
mul(a, b) {
|
|
57
|
+
assertFixed(a);
|
|
58
|
+
assertFixed(b);
|
|
59
|
+
return normalizeZero(saturate(Math.trunc((a * b) / fixedScale), minFixed, maxFixed));
|
|
60
|
+
},
|
|
61
|
+
div(a, b) {
|
|
62
|
+
assertFixed(a);
|
|
63
|
+
assertFixed(b);
|
|
64
|
+
if (b === 0) {
|
|
65
|
+
throw new Error('Fixed point division by zero');
|
|
66
|
+
}
|
|
67
|
+
return normalizeZero(saturate(Math.trunc((a * fixedScale) / b), minFixed, maxFixed));
|
|
68
|
+
},
|
|
69
|
+
saturatingAdd(a, b) {
|
|
70
|
+
assertFixed(a);
|
|
71
|
+
assertFixed(b);
|
|
72
|
+
return saturate(a + b, minFixed, maxFixed);
|
|
73
|
+
},
|
|
74
|
+
saturatingSub(a, b) {
|
|
75
|
+
assertFixed(a);
|
|
76
|
+
assertFixed(b);
|
|
77
|
+
return saturate(a - b, minFixed, maxFixed);
|
|
78
|
+
},
|
|
79
|
+
quantize(value, engine) {
|
|
80
|
+
assertFixed(value);
|
|
81
|
+
if (!Number.isInteger(engine) || engine <= 0) {
|
|
82
|
+
throw new Error('engine must be a positive integer');
|
|
83
|
+
}
|
|
84
|
+
return Math.trunc(value / engine) * engine;
|
|
85
|
+
},
|
|
86
|
+
sinTurns(turns) {
|
|
87
|
+
assertFixed(turns);
|
|
88
|
+
return trigLookup(turns, fixedScale, 'sin');
|
|
89
|
+
},
|
|
90
|
+
cosTurns(turns) {
|
|
91
|
+
assertFixed(turns);
|
|
92
|
+
return trigLookup(turns, fixedScale, 'cos');
|
|
93
|
+
},
|
|
94
|
+
vec2(x, y) {
|
|
95
|
+
assertFixed(x);
|
|
96
|
+
assertFixed(y);
|
|
97
|
+
return { x, y };
|
|
98
|
+
},
|
|
99
|
+
vec2Add(a, b) {
|
|
100
|
+
return {
|
|
101
|
+
x: saturate(a.x + b.x, minFixed, maxFixed),
|
|
102
|
+
y: saturate(a.y + b.y, minFixed, maxFixed),
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
vec2Lerp(a, b, t) {
|
|
106
|
+
assertFixed(t);
|
|
107
|
+
return {
|
|
108
|
+
x: normalizeZero(a.x + Math.trunc(((b.x - a.x) * t) / fixedScale)),
|
|
109
|
+
y: normalizeZero(a.y + Math.trunc(((b.y - a.y) * t) / fixedScale)),
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
quatFromYawTurns(turns) {
|
|
113
|
+
assertFixed(turns);
|
|
114
|
+
const halfTurns = Math.trunc(turns / 2);
|
|
115
|
+
return {
|
|
116
|
+
x: 0,
|
|
117
|
+
y: 0,
|
|
118
|
+
z: normalizeZero(trigLookup(halfTurns, fixedScale, 'sin')),
|
|
119
|
+
w: normalizeZero(trigLookup(halfTurns, fixedScale, 'cos')),
|
|
120
|
+
};
|
|
121
|
+
},
|
|
122
|
+
quatLerp(a, b, t) {
|
|
123
|
+
assertFixed(t);
|
|
124
|
+
return {
|
|
125
|
+
x: a.x + Math.trunc(((b.x - a.x) * t) / fixedScale),
|
|
126
|
+
y: a.y + Math.trunc(((b.y - a.y) * t) / fixedScale),
|
|
127
|
+
z: a.z + Math.trunc(((b.z - a.z) * t) / fixedScale),
|
|
128
|
+
w: a.w + Math.trunc(((b.w - a.w) * t) / fixedScale),
|
|
129
|
+
};
|
|
130
|
+
},
|
|
131
|
+
clamp(value, min, max) {
|
|
132
|
+
return Math.min(max, Math.max(min, value));
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function assertFixed(value) {
|
|
137
|
+
if (!Number.isInteger(value)) {
|
|
138
|
+
throw new Error('Fixed point values must be integers');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function saturate(value, min, max) {
|
|
142
|
+
return Math.min(max, Math.max(min, value));
|
|
143
|
+
}
|
|
144
|
+
function trigLookup(turns, fixedScale, op) {
|
|
145
|
+
const normalized = ((turns % fixedScale) + fixedScale) % fixedScale;
|
|
146
|
+
const quadrant = Math.trunc((normalized * 4) / fixedScale) % 4;
|
|
147
|
+
const offset = normalized - Math.trunc((quadrant * fixedScale) / 4);
|
|
148
|
+
const ramp = Math.trunc((offset * fixedScale * 4) / fixedScale);
|
|
149
|
+
const sin = quadrant === 0 ? ramp : quadrant === 1 ? fixedScale - ramp : quadrant === 2 ? -ramp : -fixedScale + ramp;
|
|
150
|
+
if (op === 'sin') {
|
|
151
|
+
return normalizeZero(sin);
|
|
152
|
+
}
|
|
153
|
+
return trigLookup(normalized + Math.trunc(fixedScale / 4), fixedScale, 'sin');
|
|
154
|
+
}
|
|
155
|
+
function normalizeZero(value) {
|
|
156
|
+
return Object.is(value, -0) ? 0 : value;
|
|
157
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createDeterministicMockNetworkAdapter = createDeterministicMockNetworkAdapter;
|
|
4
|
+
const canonical_js_1 = require("./canonical.js");
|
|
5
|
+
const protocol_lab_js_1 = require("./protocol-lab.js");
|
|
6
|
+
function createDeterministicMockNetworkAdapter(options) {
|
|
7
|
+
const stableOptions = (0, canonical_js_1.cloneCanonical)(options);
|
|
8
|
+
let result;
|
|
9
|
+
return {
|
|
10
|
+
options: stableOptions,
|
|
11
|
+
run() {
|
|
12
|
+
result = (0, protocol_lab_js_1.runProtocolRollbackLab)(stableOptions);
|
|
13
|
+
return (0, canonical_js_1.cloneCanonical)(result);
|
|
14
|
+
},
|
|
15
|
+
exportReplay() {
|
|
16
|
+
const replayResult = result ?? (0, protocol_lab_js_1.runProtocolRollbackLab)(stableOptions);
|
|
17
|
+
result = replayResult;
|
|
18
|
+
return {
|
|
19
|
+
formatVersion: 1,
|
|
20
|
+
kind: 'deterministic-mock-network',
|
|
21
|
+
options: (0, canonical_js_1.cloneCanonical)(stableOptions),
|
|
22
|
+
result: (0, canonical_js_1.cloneCanonical)(replayResult),
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
}
|