@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.
Files changed (264) hide show
  1. package/README.md +610 -0
  2. package/dist/animation.d.ts +119 -0
  3. package/dist/animation.js +488 -0
  4. package/dist/asset-cooking.d.ts +82 -0
  5. package/dist/asset-cooking.js +364 -0
  6. package/dist/authority-room.d.ts +217 -0
  7. package/dist/authority-room.js +701 -0
  8. package/dist/bot-documents.d.ts +115 -0
  9. package/dist/bot-documents.js +549 -0
  10. package/dist/bot-primitives.d.ts +152 -0
  11. package/dist/bot-primitives.js +472 -0
  12. package/dist/browser.d.ts +57 -0
  13. package/dist/browser.js +53 -0
  14. package/dist/canonical.d.ts +12 -0
  15. package/dist/canonical.js +288 -0
  16. package/dist/certification.d.ts +455 -0
  17. package/dist/certification.js +1855 -0
  18. package/dist/chaos-certification.d.ts +56 -0
  19. package/dist/chaos-certification.js +1397 -0
  20. package/dist/cjs/animation.js +495 -0
  21. package/dist/cjs/asset-cooking.js +372 -0
  22. package/dist/cjs/authority-room.js +704 -0
  23. package/dist/cjs/bot-documents.js +556 -0
  24. package/dist/cjs/bot-primitives.js +482 -0
  25. package/dist/cjs/browser.js +96 -0
  26. package/dist/cjs/canonical.js +299 -0
  27. package/dist/cjs/certification.js +1860 -0
  28. package/dist/cjs/chaos-certification.js +1402 -0
  29. package/dist/cjs/collections.js +36 -0
  30. package/dist/cjs/collision.js +96 -0
  31. package/dist/cjs/commands.js +987 -0
  32. package/dist/cjs/config-bundle.js +491 -0
  33. package/dist/cjs/creator.js +30 -0
  34. package/dist/cjs/deterministic-primitives.js +134 -0
  35. package/dist/cjs/deterministic-session.js +1410 -0
  36. package/dist/cjs/ecs-lite.js +155 -0
  37. package/dist/cjs/effects-adapter.js +97 -0
  38. package/dist/cjs/engine-complete.js +2297 -0
  39. package/dist/cjs/engine-core-proof.js +70 -0
  40. package/dist/cjs/engine-parity-matrix.js +874 -0
  41. package/dist/cjs/engine-parity.js +3183 -0
  42. package/dist/cjs/engine-runtime.js +3141 -0
  43. package/dist/cjs/errors.js +22 -0
  44. package/dist/cjs/events.js +247 -0
  45. package/dist/cjs/examples/counter-duel.js +157 -0
  46. package/dist/cjs/examples/fixed-arena.js +368 -0
  47. package/dist/cjs/index.js +229 -0
  48. package/dist/cjs/input-authority.js +150 -0
  49. package/dist/cjs/input-button.js +256 -0
  50. package/dist/cjs/input-timeline.js +418 -0
  51. package/dist/cjs/instant-replay.js +66 -0
  52. package/dist/cjs/lag-compensation3d.js +837 -0
  53. package/dist/cjs/local-authority-server-runner.js +1121 -0
  54. package/dist/cjs/local-authority-wire.js +1497 -0
  55. package/dist/cjs/local-authority.js +817 -0
  56. package/dist/cjs/local-ws-adapter.js +150 -0
  57. package/dist/cjs/match-log.js +61 -0
  58. package/dist/cjs/math.js +157 -0
  59. package/dist/cjs/mock-network-adapter.js +26 -0
  60. package/dist/cjs/movement.js +703 -0
  61. package/dist/cjs/movement3d.js +1246 -0
  62. package/dist/cjs/multiclient-authority.js +308 -0
  63. package/dist/cjs/multiplayer-service.js +434 -0
  64. package/dist/cjs/navigation.js +347 -0
  65. package/dist/cjs/navmesh.js +1437 -0
  66. package/dist/cjs/networked-client.js +691 -0
  67. package/dist/cjs/networked-input-authority.js +443 -0
  68. package/dist/cjs/node.js +47 -0
  69. package/dist/cjs/number-lab.js +78 -0
  70. package/dist/cjs/offline-session.js +370 -0
  71. package/dist/cjs/package.json +1 -0
  72. package/dist/cjs/pause-resume.js +43 -0
  73. package/dist/cjs/physics-cert.js +426 -0
  74. package/dist/cjs/physics2d.js +751 -0
  75. package/dist/cjs/physics3d.js +1996 -0
  76. package/dist/cjs/prediction-culling.js +203 -0
  77. package/dist/cjs/protocol-lab.js +1299 -0
  78. package/dist/cjs/r3f-render-adapter.js +209 -0
  79. package/dist/cjs/random.js +59 -0
  80. package/dist/cjs/replay-bundle.js +1598 -0
  81. package/dist/cjs/replay-inspect.js +236 -0
  82. package/dist/cjs/replay-scoring.js +68 -0
  83. package/dist/cjs/replay.js +356 -0
  84. package/dist/cjs/reports.js +181 -0
  85. package/dist/cjs/rollback-history.js +251 -0
  86. package/dist/cjs/runtime-guards.js +111 -0
  87. package/dist/cjs/sample-lab.js +145 -0
  88. package/dist/cjs/sample-scenes.js +752 -0
  89. package/dist/cjs/schema-artifacts.js +359 -0
  90. package/dist/cjs/schema-codegen.js +544 -0
  91. package/dist/cjs/schema-dsl-binary.js +655 -0
  92. package/dist/cjs/schema.js +319 -0
  93. package/dist/cjs/sdk-offline.js +99 -0
  94. package/dist/cjs/session-promotion.js +74 -0
  95. package/dist/cjs/session-snapshot.js +265 -0
  96. package/dist/cjs/session-wire.js +216 -0
  97. package/dist/cjs/signals.js +103 -0
  98. package/dist/cjs/sparse-set.js +169 -0
  99. package/dist/cjs/synctest.js +136 -0
  100. package/dist/cjs/system-lifecycle.js +286 -0
  101. package/dist/cjs/timers.js +61 -0
  102. package/dist/cjs/tools/static-checker.js +1468 -0
  103. package/dist/cjs/types.js +2 -0
  104. package/dist/cjs/venus-mp-budget.js +125 -0
  105. package/dist/cjs/ws-frame.js +255 -0
  106. package/dist/cli.d.ts +2 -0
  107. package/dist/cli.js +11379 -0
  108. package/dist/collections.d.ts +9 -0
  109. package/dist/collections.js +30 -0
  110. package/dist/collision.d.ts +25 -0
  111. package/dist/collision.js +85 -0
  112. package/dist/commands.d.ts +137 -0
  113. package/dist/commands.js +977 -0
  114. package/dist/config-bundle.d.ts +89 -0
  115. package/dist/config-bundle.js +483 -0
  116. package/dist/creator.d.ts +20 -0
  117. package/dist/creator.js +11 -0
  118. package/dist/deterministic-primitives.d.ts +59 -0
  119. package/dist/deterministic-primitives.js +126 -0
  120. package/dist/deterministic-session.d.ts +197 -0
  121. package/dist/deterministic-session.js +1401 -0
  122. package/dist/ecs-lite.d.ts +26 -0
  123. package/dist/ecs-lite.js +152 -0
  124. package/dist/effects-adapter.d.ts +21 -0
  125. package/dist/effects-adapter.js +94 -0
  126. package/dist/engine-complete.d.ts +45 -0
  127. package/dist/engine-complete.js +2292 -0
  128. package/dist/engine-core-proof.d.ts +26 -0
  129. package/dist/engine-core-proof.js +66 -0
  130. package/dist/engine-parity-matrix.d.ts +300 -0
  131. package/dist/engine-parity-matrix.js +869 -0
  132. package/dist/engine-parity.d.ts +74 -0
  133. package/dist/engine-parity.js +3178 -0
  134. package/dist/engine-runtime.d.ts +351 -0
  135. package/dist/engine-runtime.js +3123 -0
  136. package/dist/errors.d.ts +11 -0
  137. package/dist/errors.js +17 -0
  138. package/dist/events.d.ts +45 -0
  139. package/dist/events.js +242 -0
  140. package/dist/examples/counter-duel.d.ts +43 -0
  141. package/dist/examples/counter-duel.js +150 -0
  142. package/dist/examples/fixed-arena.d.ts +110 -0
  143. package/dist/examples/fixed-arena.js +356 -0
  144. package/dist/index.d.ts +101 -0
  145. package/dist/index.js +66 -0
  146. package/dist/input-authority.d.ts +82 -0
  147. package/dist/input-authority.js +147 -0
  148. package/dist/input-button.d.ts +36 -0
  149. package/dist/input-button.js +249 -0
  150. package/dist/input-timeline.d.ts +65 -0
  151. package/dist/input-timeline.js +412 -0
  152. package/dist/instant-replay.d.ts +59 -0
  153. package/dist/instant-replay.js +62 -0
  154. package/dist/lag-compensation3d.d.ts +146 -0
  155. package/dist/lag-compensation3d.js +827 -0
  156. package/dist/local-authority-server-runner.d.ts +79 -0
  157. package/dist/local-authority-server-runner.js +1118 -0
  158. package/dist/local-authority-wire.d.ts +142 -0
  159. package/dist/local-authority-wire.js +1477 -0
  160. package/dist/local-authority.d.ts +160 -0
  161. package/dist/local-authority.js +810 -0
  162. package/dist/local-ws-adapter.d.ts +14 -0
  163. package/dist/local-ws-adapter.js +146 -0
  164. package/dist/match-log.d.ts +74 -0
  165. package/dist/match-log.js +57 -0
  166. package/dist/math.d.ts +41 -0
  167. package/dist/math.js +154 -0
  168. package/dist/mock-network-adapter.d.ts +13 -0
  169. package/dist/mock-network-adapter.js +23 -0
  170. package/dist/movement.d.ts +155 -0
  171. package/dist/movement.js +694 -0
  172. package/dist/movement3d.d.ts +195 -0
  173. package/dist/movement3d.js +1238 -0
  174. package/dist/multiclient-authority.d.ts +30 -0
  175. package/dist/multiclient-authority.js +305 -0
  176. package/dist/multiplayer-service.d.ts +153 -0
  177. package/dist/multiplayer-service.js +429 -0
  178. package/dist/navigation.d.ts +91 -0
  179. package/dist/navigation.js +338 -0
  180. package/dist/navmesh.d.ts +236 -0
  181. package/dist/navmesh.js +1423 -0
  182. package/dist/networked-client.d.ts +124 -0
  183. package/dist/networked-client.js +688 -0
  184. package/dist/networked-input-authority.d.ts +51 -0
  185. package/dist/networked-input-authority.js +439 -0
  186. package/dist/node.d.ts +22 -0
  187. package/dist/node.js +19 -0
  188. package/dist/number-lab.d.ts +15 -0
  189. package/dist/number-lab.js +75 -0
  190. package/dist/offline-session.d.ts +2 -0
  191. package/dist/offline-session.js +367 -0
  192. package/dist/pause-resume.d.ts +48 -0
  193. package/dist/pause-resume.js +40 -0
  194. package/dist/physics-cert.d.ts +40 -0
  195. package/dist/physics-cert.js +389 -0
  196. package/dist/physics2d.d.ts +142 -0
  197. package/dist/physics2d.js +741 -0
  198. package/dist/physics3d.d.ts +285 -0
  199. package/dist/physics3d.js +1979 -0
  200. package/dist/prediction-culling.d.ts +34 -0
  201. package/dist/prediction-culling.js +200 -0
  202. package/dist/protocol-lab.d.ts +115 -0
  203. package/dist/protocol-lab.js +1295 -0
  204. package/dist/r3f-render-adapter.d.ts +61 -0
  205. package/dist/r3f-render-adapter.js +203 -0
  206. package/dist/random.d.ts +13 -0
  207. package/dist/random.js +55 -0
  208. package/dist/replay-bundle.d.ts +150 -0
  209. package/dist/replay-bundle.js +1586 -0
  210. package/dist/replay-inspect.d.ts +60 -0
  211. package/dist/replay-inspect.js +228 -0
  212. package/dist/replay-scoring.d.ts +28 -0
  213. package/dist/replay-scoring.js +65 -0
  214. package/dist/replay.d.ts +17 -0
  215. package/dist/replay.js +351 -0
  216. package/dist/reports.d.ts +176 -0
  217. package/dist/reports.js +174 -0
  218. package/dist/rollback-history.d.ts +46 -0
  219. package/dist/rollback-history.js +247 -0
  220. package/dist/runtime-guards.d.ts +1 -0
  221. package/dist/runtime-guards.js +108 -0
  222. package/dist/sample-lab.d.ts +32 -0
  223. package/dist/sample-lab.js +134 -0
  224. package/dist/sample-scenes.d.ts +86 -0
  225. package/dist/sample-scenes.js +745 -0
  226. package/dist/schema-artifacts.d.ts +49 -0
  227. package/dist/schema-artifacts.js +356 -0
  228. package/dist/schema-codegen.d.ts +21 -0
  229. package/dist/schema-codegen.js +538 -0
  230. package/dist/schema-dsl-binary.d.ts +75 -0
  231. package/dist/schema-dsl-binary.js +648 -0
  232. package/dist/schema.d.ts +87 -0
  233. package/dist/schema.js +315 -0
  234. package/dist/sdk-offline.d.ts +34 -0
  235. package/dist/sdk-offline.js +96 -0
  236. package/dist/session-promotion.d.ts +26 -0
  237. package/dist/session-promotion.js +70 -0
  238. package/dist/session-snapshot.d.ts +95 -0
  239. package/dist/session-snapshot.js +255 -0
  240. package/dist/session-wire.d.ts +89 -0
  241. package/dist/session-wire.js +211 -0
  242. package/dist/signals.d.ts +31 -0
  243. package/dist/signals.js +99 -0
  244. package/dist/sparse-set.d.ts +34 -0
  245. package/dist/sparse-set.js +165 -0
  246. package/dist/synctest.d.ts +31 -0
  247. package/dist/synctest.js +133 -0
  248. package/dist/system-lifecycle.d.ts +72 -0
  249. package/dist/system-lifecycle.js +281 -0
  250. package/dist/timers.d.ts +17 -0
  251. package/dist/timers.js +53 -0
  252. package/dist/tools/index.d.ts +4 -0
  253. package/dist/tools/index.js +4 -0
  254. package/dist/tools/static-checker.d.ts +31 -0
  255. package/dist/tools/static-checker.js +1462 -0
  256. package/dist/tools/vite-plugin.d.ts +69 -0
  257. package/dist/tools/vite-plugin.js +203 -0
  258. package/dist/types.d.ts +148 -0
  259. package/dist/types.js +1 -0
  260. package/dist/venus-mp-budget.d.ts +29 -0
  261. package/dist/venus-mp-budget.js +122 -0
  262. package/dist/ws-frame.d.ts +49 -0
  263. package/dist/ws-frame.js +247 -0
  264. package/package.json +169 -0
@@ -0,0 +1,426 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runPhysicsCert = runPhysicsCert;
37
+ exports.runRapierPhysicsCert = runRapierPhysicsCert;
38
+ const canonical_js_1 = require("./canonical.js");
39
+ const collision_js_1 = require("./collision.js");
40
+ const rapier2dCompatPackage = '@dimforge/rapier2d-compat';
41
+ const physicsCertResults = {
42
+ true: 'pass',
43
+ false: 'fail',
44
+ };
45
+ function runPhysicsCert(options) {
46
+ validateOptions(options);
47
+ const uninterrupted = runPhysicsSimulation(options, false);
48
+ const restored = runPhysicsSimulation(options, true);
49
+ const snapshotBytes = [...restored.snapshotBytes].sort((left, right) => left - right);
50
+ const stepTimings = [...restored.stepTimings].sort((left, right) => left - right);
51
+ const snapshotTimings = [...restored.snapshotTimings].sort((left, right) => left - right);
52
+ const restoreTimings = [...restored.restoreTimings].sort((left, right) => left - right);
53
+ const collisionEventsStable = (0, canonical_js_1.defaultChecksum)(uninterrupted.collisionEvents) === (0, canonical_js_1.defaultChecksum)(restored.collisionEvents);
54
+ const finalRestoreStable = uninterrupted.finalChecksum === restored.finalChecksum;
55
+ const snapshotHashStable = restored.snapshotChecksums.every((snapshot) => snapshot.first === snapshot.second);
56
+ const pass = finalRestoreStable &&
57
+ collisionEventsStable &&
58
+ restored.queryOrderStable &&
59
+ snapshotHashStable;
60
+ return {
61
+ engine: options.engine,
62
+ engineVersion: 'builtin-fixed@1',
63
+ adapterVersion: 'physics-cert@1',
64
+ shape: options.shape,
65
+ players: options.players,
66
+ bodies: createInitialBodies(options).length,
67
+ frames: options.frames,
68
+ snapshotEvery: options.snapshotEvery,
69
+ seed: options.seed,
70
+ uninterruptedChecksum: uninterrupted.finalChecksum,
71
+ restoredChecksum: restored.finalChecksum,
72
+ collisionEvents: restored.collisionEvents.length,
73
+ collisionEventsStable,
74
+ queryOrderStable: restored.queryOrderStable,
75
+ snapshotHashStable,
76
+ finalRestoreStable,
77
+ stepMsP95: percentile(stepTimings, 0.95),
78
+ stepMsMax: maxTiming(stepTimings),
79
+ snapshotMsP95: percentile(snapshotTimings, 0.95),
80
+ restoreMsP95: percentile(restoreTimings, 0.95),
81
+ snapshotBytesP95: percentileNumber(snapshotBytes, 0.95),
82
+ heapUsedBytes: getHeapUsedBytes(),
83
+ knownIssueRapier910: 'not-applicable',
84
+ result: physicsCertResult(pass),
85
+ };
86
+ }
87
+ async function runRapierPhysicsCert(options) {
88
+ validateRapierOptions(options);
89
+ const rapier = await loadRapier2dCompat();
90
+ const uninterrupted = runRapierSimulation(rapier, options, false);
91
+ const restored = runRapierSimulation(rapier, options, true);
92
+ const snapshotBytes = [...restored.snapshotBytes].sort((left, right) => left - right);
93
+ const stepTimings = [...restored.stepTimings].sort((left, right) => left - right);
94
+ const snapshotTimings = [...restored.snapshotTimings].sort((left, right) => left - right);
95
+ const restoreTimings = [...restored.restoreTimings].sort((left, right) => left - right);
96
+ const collisionEventsStable = (0, canonical_js_1.defaultChecksum)(uninterrupted.collisionEvents) === (0, canonical_js_1.defaultChecksum)(restored.collisionEvents);
97
+ const finalRestoreStable = uninterrupted.finalChecksum === restored.finalChecksum;
98
+ const snapshotHashStable = restored.snapshotChecksums.every((snapshot) => snapshot.first === snapshot.second);
99
+ const pass = finalRestoreStable &&
100
+ collisionEventsStable &&
101
+ restored.queryOrderStable &&
102
+ snapshotHashStable;
103
+ return {
104
+ engine: options.engine,
105
+ engineVersion: `rapier2d-compat@${rapier.version()}`,
106
+ adapterVersion: 'physics-cert-rapier@1',
107
+ shape: options.shape,
108
+ players: options.players,
109
+ bodies: countRapierDynamicBodies(options),
110
+ frames: options.frames,
111
+ snapshotEvery: options.snapshotEvery,
112
+ seed: options.seed,
113
+ uninterruptedChecksum: uninterrupted.finalChecksum,
114
+ restoredChecksum: restored.finalChecksum,
115
+ collisionEvents: restored.collisionEvents.length,
116
+ collisionEventsStable,
117
+ queryOrderStable: restored.queryOrderStable,
118
+ snapshotHashStable,
119
+ finalRestoreStable,
120
+ stepMsP95: percentile(stepTimings, 0.95),
121
+ stepMsMax: maxTiming(stepTimings),
122
+ snapshotMsP95: percentile(snapshotTimings, 0.95),
123
+ restoreMsP95: percentile(restoreTimings, 0.95),
124
+ snapshotBytesP95: percentileNumber(snapshotBytes, 0.95),
125
+ heapUsedBytes: getHeapUsedBytes(),
126
+ knownIssueRapier910: finalRestoreStable && snapshotHashStable ? 'not-reproduced' : 'reproduced',
127
+ packageName: rapier2dCompatPackage,
128
+ packageImportPath: rapier2dCompatPackage,
129
+ result: physicsCertResult(pass),
130
+ };
131
+ }
132
+ async function loadRapier2dCompat() {
133
+ const mod = await Promise.resolve(`${rapier2dCompatPackage}`).then(s => __importStar(require(s)));
134
+ const warn = console.warn;
135
+ console.warn = () => { };
136
+ try {
137
+ await mod.init({});
138
+ }
139
+ finally {
140
+ console.warn = warn;
141
+ }
142
+ return mod;
143
+ }
144
+ function runRapierSimulation(rapier, options, withRestore) {
145
+ let world = createRapierWorld(rapier, options);
146
+ const stepTimings = [];
147
+ const snapshotTimings = [];
148
+ const restoreTimings = [];
149
+ const snapshotBytes = [];
150
+ const snapshotChecksums = [];
151
+ const collisionEvents = [];
152
+ let queryOrderStable = true;
153
+ for (let frame = 0; frame < options.frames; frame += 1) {
154
+ const stepStartedAt = performance.now();
155
+ world.step();
156
+ stepTimings.push(performance.now() - stepStartedAt);
157
+ const firstContacts = collectRapierContactPairs(world);
158
+ const secondContacts = collectRapierContactPairs(world);
159
+ queryOrderStable = queryOrderStable && (0, canonical_js_1.defaultChecksum)(firstContacts.raw) === (0, canonical_js_1.defaultChecksum)(secondContacts.raw);
160
+ for (const contact of firstContacts.canonical) {
161
+ collisionEvents.push(`${frame + 1}:${contact}`);
162
+ }
163
+ if (withRestore && frame % options.snapshotEvery === 0) {
164
+ const snapshotStartedAt = performance.now();
165
+ const snapshot = world.takeSnapshot();
166
+ snapshotTimings.push(performance.now() - snapshotStartedAt);
167
+ snapshotBytes.push(snapshot.byteLength);
168
+ const restoreStartedAt = performance.now();
169
+ const restored = rapier.World.restoreSnapshot(snapshot);
170
+ restoreTimings.push(performance.now() - restoreStartedAt);
171
+ snapshotChecksums.push({
172
+ first: (0, canonical_js_1.defaultChecksum)(Array.from(snapshot)),
173
+ second: (0, canonical_js_1.defaultChecksum)(Array.from(restored.takeSnapshot())),
174
+ });
175
+ world.free?.();
176
+ world = restored;
177
+ }
178
+ }
179
+ const finalSnapshot = world.takeSnapshot();
180
+ const finalChecksum = (0, canonical_js_1.defaultChecksum)({
181
+ snapshot: Array.from(finalSnapshot),
182
+ sample: sampleRapierWorld(world),
183
+ });
184
+ world.free?.();
185
+ return {
186
+ finalChecksum,
187
+ collisionEvents,
188
+ queryOrderStable,
189
+ stepTimings,
190
+ snapshotTimings,
191
+ restoreTimings,
192
+ snapshotBytes,
193
+ snapshotChecksums,
194
+ };
195
+ }
196
+ function createRapierWorld(rapier, options) {
197
+ const world = new rapier.World({ x: 0, y: 0 });
198
+ world.integrationParameters.dt = 1 / 30;
199
+ const bounds = options.shape === 'fixed-arena' ? 32 : 96;
200
+ const wall = 1;
201
+ const walls = [
202
+ { x: 0, y: -bounds - wall, halfWidth: bounds + wall, halfHeight: wall },
203
+ { x: 0, y: bounds + wall, halfWidth: bounds + wall, halfHeight: wall },
204
+ { x: -bounds - wall, y: 0, halfWidth: wall, halfHeight: bounds + wall },
205
+ { x: bounds + wall, y: 0, halfWidth: wall, halfHeight: bounds + wall },
206
+ ];
207
+ for (const wallConfig of walls) {
208
+ const body = world.createRigidBody(rapier.RigidBodyDesc.fixed().setTranslation(wallConfig.x, wallConfig.y));
209
+ world.createCollider(rapier.ColliderDesc.cuboid(wallConfig.halfWidth, wallConfig.halfHeight).setRestitution(1).setFriction(0), body);
210
+ }
211
+ const bodiesPerSlot = options.shape === 'fixed-arena' ? 2 : 4;
212
+ for (let slot = 0; slot < options.players; slot += 1) {
213
+ for (let index = 0; index < bodiesPerSlot; index += 1) {
214
+ const bodyIndex = slot * bodiesPerSlot + index;
215
+ const x = -bounds + 4 + ((bodyIndex * 7 + options.seed) % Math.max(8, bounds * 2 - 8));
216
+ const y = -bounds + 4 + ((bodyIndex * 11 + options.seed * 3) % Math.max(8, bounds * 2 - 8));
217
+ const vx = (((slot + index + options.seed) % 5) - 2 || 1) * 2;
218
+ const vy = (((slot * 3 + index + options.seed) % 5) - 2 || -1) * 2;
219
+ const body = world.createRigidBody(rapier.RigidBodyDesc.dynamic()
220
+ .setTranslation(x, y)
221
+ .setLinvel(vx, vy)
222
+ .setLinearDamping(0));
223
+ world.createCollider(rapier.ColliderDesc.ball(1 + ((slot + index + options.seed) % 3) * 0.25).setRestitution(1).setFriction(0), body);
224
+ }
225
+ }
226
+ return world;
227
+ }
228
+ function collectRapierContactPairs(world) {
229
+ const colliderHandles = [];
230
+ const raw = [];
231
+ const canonical = new Set();
232
+ world.colliders.forEach((collider) => {
233
+ colliderHandles.push(String(collider.handle));
234
+ });
235
+ for (const colliderHandle of colliderHandles) {
236
+ world.narrowPhase.contactPairsWith(Number(colliderHandle), (otherCollider) => {
237
+ const pair = [colliderHandle, String(otherCollider)].sort((left, right) => left.localeCompare(right));
238
+ const canonicalPair = `${pair[0]}:${pair[1]}`;
239
+ raw.push(canonicalPair);
240
+ canonical.add(canonicalPair);
241
+ });
242
+ }
243
+ return {
244
+ raw,
245
+ canonical: [...canonical].sort((left, right) => left.localeCompare(right)),
246
+ };
247
+ }
248
+ function sampleRapierWorld(world) {
249
+ const bodies = [];
250
+ world.bodies.forEach((body) => {
251
+ const translation = body.translation();
252
+ const linvel = body.linvel();
253
+ bodies.push({
254
+ handle: String(body.handle),
255
+ x: quantizeRapierNumber(translation.x),
256
+ y: quantizeRapierNumber(translation.y),
257
+ vx: quantizeRapierNumber(linvel.x),
258
+ vy: quantizeRapierNumber(linvel.y),
259
+ });
260
+ });
261
+ return bodies.sort((left, right) => left.handle.localeCompare(right.handle));
262
+ }
263
+ function quantizeRapierNumber(value) {
264
+ const rounded = Math.round(value * 1_000_000);
265
+ return rounded === 0 ? 0 : rounded;
266
+ }
267
+ function countRapierDynamicBodies(options) {
268
+ return options.players * (options.shape === 'fixed-arena' ? 2 : 4);
269
+ }
270
+ function runPhysicsSimulation(options, withRestore) {
271
+ let state = {
272
+ frame: 0,
273
+ bodies: createInitialBodies(options),
274
+ collisionEvents: [],
275
+ };
276
+ const stepTimings = [];
277
+ const snapshotTimings = [];
278
+ const restoreTimings = [];
279
+ const snapshotBytes = [];
280
+ const snapshotChecksums = [];
281
+ let queryOrderStable = true;
282
+ for (let frame = 0; frame < options.frames; frame += 1) {
283
+ const stepStartedAt = performance.now();
284
+ state = stepPhysics(state, options);
285
+ stepTimings.push(performance.now() - stepStartedAt);
286
+ if (withRestore && frame % options.snapshotEvery === 0) {
287
+ const snapshotStartedAt = performance.now();
288
+ const snapshot = JSON.stringify(state);
289
+ snapshotTimings.push(performance.now() - snapshotStartedAt);
290
+ snapshotBytes.push(Buffer.byteLength(snapshot));
291
+ snapshotChecksums.push({ first: (0, canonical_js_1.defaultChecksum)(snapshot), second: (0, canonical_js_1.defaultChecksum)(JSON.stringify(state)) });
292
+ const restoreStartedAt = performance.now();
293
+ state = JSON.parse(snapshot);
294
+ restoreTimings.push(performance.now() - restoreStartedAt);
295
+ }
296
+ const queried = queryBodiesNearOrigin(state);
297
+ const sorted = [...queried].sort((left, right) => left.localeCompare(right));
298
+ queryOrderStable = queryOrderStable && queried.every((id, index) => id === sorted[index]);
299
+ }
300
+ return {
301
+ finalChecksum: (0, canonical_js_1.defaultChecksum)(state),
302
+ collisionEvents: state.collisionEvents,
303
+ queryOrderStable,
304
+ stepTimings,
305
+ snapshotTimings,
306
+ restoreTimings,
307
+ snapshotBytes,
308
+ snapshotChecksums,
309
+ };
310
+ }
311
+ function createInitialBodies(options) {
312
+ const bodiesPerSlot = options.shape === 'fixed-arena' ? 2 : 4;
313
+ const bodies = [];
314
+ for (let slot = 0; slot < options.players; slot += 1) {
315
+ for (let index = 0; index < bodiesPerSlot; index += 1) {
316
+ bodies.push({
317
+ id: `slot-${slot}-body-${index}`,
318
+ slot,
319
+ radius: 6 + ((slot + index + options.seed) % 5),
320
+ x: -400 + slot * 9 + index * 11,
321
+ y: -120 + ((slot * 17 + index * 23 + options.seed) % 240),
322
+ vx: ((slot + index + options.seed) % 7) - 3 || 1,
323
+ vy: ((slot * 3 + index + options.seed) % 5) - 2 || -1,
324
+ });
325
+ }
326
+ }
327
+ return bodies;
328
+ }
329
+ function stepPhysics(state, options) {
330
+ const moved = state.bodies.map((body) => moveBody(body, options));
331
+ const collisionEvents = [...state.collisionEvents];
332
+ const circles = moved.map((body) => ({ body, circle: (0, collision_js_1.fixedCircle)((0, collision_js_1.fixedVec2)(body.x, body.y), body.radius) }));
333
+ for (let leftIndex = 0; leftIndex < circles.length; leftIndex += 1) {
334
+ for (let rightIndex = leftIndex + 1; rightIndex < circles.length; rightIndex += 1) {
335
+ const left = circles[leftIndex];
336
+ const right = circles[rightIndex];
337
+ if ((0, collision_js_1.circleIntersects)(left.circle, right.circle)) {
338
+ const ids = [left.body.id, right.body.id].sort();
339
+ collisionEvents.push(`${state.frame + 1}:${ids[0]}:${ids[1]}`);
340
+ }
341
+ }
342
+ }
343
+ return {
344
+ frame: state.frame + 1,
345
+ bodies: moved.sort((left, right) => left.id.localeCompare(right.id)),
346
+ collisionEvents,
347
+ };
348
+ }
349
+ function moveBody(body, options) {
350
+ const min = options.shape === 'fixed-arena' ? -512 : -1024;
351
+ const max = options.shape === 'fixed-arena' ? 512 : 1024;
352
+ let nextX = body.x + body.vx;
353
+ let nextY = body.y + body.vy;
354
+ let nextVx = body.vx;
355
+ let nextVy = body.vy;
356
+ if (nextX - body.radius < min || nextX + body.radius > max) {
357
+ nextVx = -nextVx;
358
+ nextX = body.x + nextVx;
359
+ }
360
+ if (nextY - body.radius < min || nextY + body.radius > max) {
361
+ nextVy = -nextVy;
362
+ nextY = body.y + nextVy;
363
+ }
364
+ return {
365
+ ...body,
366
+ x: nextX,
367
+ y: nextY,
368
+ vx: nextVx,
369
+ vy: nextVy,
370
+ };
371
+ }
372
+ function queryBodiesNearOrigin(state) {
373
+ const origin = (0, collision_js_1.fixedCircle)((0, collision_js_1.fixedVec2)(0, 0), 256);
374
+ return state.bodies
375
+ .filter((body) => (0, collision_js_1.circleIntersects)(origin, bodyToCircle(body)))
376
+ .map((body) => body.id)
377
+ .sort((left, right) => left.localeCompare(right));
378
+ }
379
+ function bodyToCircle(body) {
380
+ return (0, collision_js_1.fixedCircle)((0, collision_js_1.fixedVec2)(body.x, body.y), body.radius);
381
+ }
382
+ function percentile(timings, percent) {
383
+ return percentileNumber(timings, percent).toFixed(4);
384
+ }
385
+ function percentileNumber(values, percent) {
386
+ const index = Math.min(values.length - 1, Math.ceil(values.length * percent) - 1);
387
+ return values[index];
388
+ }
389
+ function maxTiming(timings) {
390
+ return timings.at(-1).toFixed(4);
391
+ }
392
+ function getHeapUsedBytes() {
393
+ return typeof process === 'undefined' ? 0 : process.memoryUsage().heapUsed;
394
+ }
395
+ function physicsCertResult(pass) {
396
+ return physicsCertResults[String(pass)];
397
+ }
398
+ function validateOptions(options) {
399
+ if (options.engine !== 'builtin-fixed') {
400
+ throw new Error('physics certification currently supports engine=builtin-fixed');
401
+ }
402
+ validateCommonOptions(options);
403
+ }
404
+ function validateRapierOptions(options) {
405
+ if (options.engine !== 'rapier2d-compat') {
406
+ throw new Error('Rapier physics certification requires engine=rapier2d-compat');
407
+ }
408
+ validateCommonOptions(options);
409
+ }
410
+ function validateCommonOptions(options) {
411
+ if (options.shape !== 'fixed-arena' && options.shape !== 'slot-load') {
412
+ throw new Error('physics certification shape must be fixed-arena or slot-load');
413
+ }
414
+ if (!Number.isInteger(options.players) || options.players < 1 || options.players > 128) {
415
+ throw new Error('physics certification players must be between 1 and 128');
416
+ }
417
+ if (!Number.isInteger(options.frames) || options.frames < 1) {
418
+ throw new Error('physics certification frames must be at least 1');
419
+ }
420
+ if (!Number.isInteger(options.seed)) {
421
+ throw new Error('physics certification seed must be an integer');
422
+ }
423
+ if (!Number.isInteger(options.snapshotEvery) || options.snapshotEvery < 1) {
424
+ throw new Error('snapshotEvery must be a positive integer');
425
+ }
426
+ }