@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,372 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cookDeterministicAssets = cookDeterministicAssets;
|
|
4
|
+
exports.stableAssetCookJson = stableAssetCookJson;
|
|
5
|
+
exports.materializePrototypeEntities = materializePrototypeEntities;
|
|
6
|
+
exports.materializeDeterministicMapEntities = materializeDeterministicMapEntities;
|
|
7
|
+
exports.validatePrototypeEntitiesAgainstFrameRuntime = validatePrototypeEntitiesAgainstFrameRuntime;
|
|
8
|
+
exports.assertAssetManifestMatches = assertAssetManifestMatches;
|
|
9
|
+
const canonical_js_1 = require("./canonical.js");
|
|
10
|
+
const engine_runtime_js_1 = require("./engine-runtime.js");
|
|
11
|
+
function cookDeterministicAssets(source) {
|
|
12
|
+
validateAssetSource(source);
|
|
13
|
+
const engineVersion = source.engineVersion ?? 'rdm-assets@1';
|
|
14
|
+
const dependencies = [...(source.dependencies ?? [])]
|
|
15
|
+
.map((dependency) => (0, canonical_js_1.cloneCanonical)(dependency))
|
|
16
|
+
.sort(compareDependencies);
|
|
17
|
+
const schemaHash = (0, canonical_js_1.defaultChecksum)({
|
|
18
|
+
kind: 'deterministic-asset-schema',
|
|
19
|
+
schemaVersion: 1,
|
|
20
|
+
requiredFields: ['id'],
|
|
21
|
+
optionalFields: ['type', 'references', 'prototype'],
|
|
22
|
+
numericPolicy: 'integer-only',
|
|
23
|
+
dependencyVersionPolicy: 'exact',
|
|
24
|
+
});
|
|
25
|
+
const dependencyHash = (0, canonical_js_1.defaultChecksum)(dependencies);
|
|
26
|
+
const assets = source.assets
|
|
27
|
+
.map((asset) => (0, canonical_js_1.cloneCanonical)(asset))
|
|
28
|
+
.sort((left, right) => compareStrings(left.id, right.id));
|
|
29
|
+
const cookedAssets = assets.map((asset) => {
|
|
30
|
+
const data = (0, canonical_js_1.cloneCanonical)(asset);
|
|
31
|
+
return {
|
|
32
|
+
id: asset.id,
|
|
33
|
+
type: asset.type ?? 'asset',
|
|
34
|
+
hash: (0, canonical_js_1.defaultChecksum)({ id: asset.id, data }),
|
|
35
|
+
data,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
const lookup = Object.fromEntries(cookedAssets.map((asset, index) => [asset.id, index]));
|
|
39
|
+
const prototypeIds = cookedAssets
|
|
40
|
+
.filter((asset) => asset.data.prototype === true)
|
|
41
|
+
.map((asset) => asset.id)
|
|
42
|
+
.sort(compareStrings);
|
|
43
|
+
const withoutHash = {
|
|
44
|
+
schemaVersion: 1,
|
|
45
|
+
schemaHash,
|
|
46
|
+
engineVersion,
|
|
47
|
+
dependencyHash,
|
|
48
|
+
dependencies,
|
|
49
|
+
lookupHash: (0, canonical_js_1.defaultChecksum)(lookup),
|
|
50
|
+
prototypeIds,
|
|
51
|
+
assetCount: cookedAssets.length,
|
|
52
|
+
assets: cookedAssets.map((asset) => ({
|
|
53
|
+
id: asset.id,
|
|
54
|
+
type: asset.type,
|
|
55
|
+
hash: asset.hash,
|
|
56
|
+
})),
|
|
57
|
+
};
|
|
58
|
+
const manifest = {
|
|
59
|
+
...withoutHash,
|
|
60
|
+
assetDbHash: (0, canonical_js_1.defaultChecksum)({ engineVersion, schemaHash, dependencyHash, dependencies, cookedAssets }),
|
|
61
|
+
};
|
|
62
|
+
const bytes = (0, canonical_js_1.canonicalStringify)({
|
|
63
|
+
manifest,
|
|
64
|
+
assets: cookedAssets,
|
|
65
|
+
});
|
|
66
|
+
return {
|
|
67
|
+
manifest,
|
|
68
|
+
cookedAssets,
|
|
69
|
+
bytes,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function stableAssetCookJson(result) {
|
|
73
|
+
return `${(0, canonical_js_1.canonicalStringify)(result)}\n`;
|
|
74
|
+
}
|
|
75
|
+
function materializePrototypeEntities(cooked, prototypeId, count, options = {}) {
|
|
76
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
77
|
+
throw new Error('Prototype count must be a non-negative integer');
|
|
78
|
+
}
|
|
79
|
+
const startEntityId = options.startEntityId ?? 1;
|
|
80
|
+
if (!Number.isInteger(startEntityId) || startEntityId <= 0) {
|
|
81
|
+
throw new Error('Prototype start entity id must be a positive integer');
|
|
82
|
+
}
|
|
83
|
+
const prototype = cooked.cookedAssets.find((asset) => asset.id === prototypeId);
|
|
84
|
+
if (prototype === undefined) {
|
|
85
|
+
throw new Error(`Unknown prototype ${prototypeId}`);
|
|
86
|
+
}
|
|
87
|
+
if (!cooked.manifest.prototypeIds.includes(prototypeId)) {
|
|
88
|
+
throw new Error(`Asset ${prototypeId} is not a prototype`);
|
|
89
|
+
}
|
|
90
|
+
const components = resolvePrototypeComponents(cooked, prototypeId, new Set());
|
|
91
|
+
const overrides = options.componentOverrides === undefined
|
|
92
|
+
? {}
|
|
93
|
+
: recordOrThrow(options.componentOverrides, `Prototype ${prototypeId} overrides`);
|
|
94
|
+
const resolvedComponents = mergeRecords(components, overrides);
|
|
95
|
+
return Array.from({ length: count }, (_, index) => ({
|
|
96
|
+
entityId: startEntityId + index,
|
|
97
|
+
prototypeId,
|
|
98
|
+
assetDbHash: cooked.manifest.assetDbHash,
|
|
99
|
+
components: materializeDynamicCollections(resolvedComponents),
|
|
100
|
+
}));
|
|
101
|
+
}
|
|
102
|
+
function materializeDeterministicMapEntities(cooked, mapId, options = {}) {
|
|
103
|
+
const mapAsset = cooked.cookedAssets.find((asset) => asset.id === mapId);
|
|
104
|
+
if (mapAsset === undefined) {
|
|
105
|
+
throw new Error(`Unknown map ${mapId}`);
|
|
106
|
+
}
|
|
107
|
+
if (mapAsset.type !== 'map') {
|
|
108
|
+
throw new Error(`Asset ${mapId} is not a map`);
|
|
109
|
+
}
|
|
110
|
+
const mapData = recordOrThrow(mapAsset.data, `Map ${mapId}`);
|
|
111
|
+
const spawns = mapData.spawns;
|
|
112
|
+
if (!Array.isArray(spawns)) {
|
|
113
|
+
throw new Error(`Map ${mapId} requires a spawns array`);
|
|
114
|
+
}
|
|
115
|
+
const materialized = [];
|
|
116
|
+
const prototypeIds = [];
|
|
117
|
+
const usedEntityIds = new Set();
|
|
118
|
+
let nextEntityId = options.startEntityId ?? 1;
|
|
119
|
+
for (const [index, spawn] of spawns.entries()) {
|
|
120
|
+
const spawnRecord = recordOrThrow(spawn, `Map ${mapId}.spawns[${index}]`);
|
|
121
|
+
const prototypeRef = spawnRecord.prototypeRef;
|
|
122
|
+
if (typeof prototypeRef !== 'string') {
|
|
123
|
+
throw new Error(`Map ${mapId}.spawns[${index}].prototypeRef must be a string`);
|
|
124
|
+
}
|
|
125
|
+
const count = optionalInteger(spawnRecord.count, `Map ${mapId}.spawns[${index}].count`) ?? 1;
|
|
126
|
+
if (!Number.isInteger(count) || count < 0) {
|
|
127
|
+
throw new Error(`Map ${mapId}.spawns[${index}].count must be a non-negative integer`);
|
|
128
|
+
}
|
|
129
|
+
const startEntityId = optionalInteger(spawnRecord.startEntityId, `Map ${mapId}.spawns[${index}].startEntityId`) ?? nextEntityId;
|
|
130
|
+
if (!Number.isInteger(startEntityId) || startEntityId <= 0) {
|
|
131
|
+
throw new Error(`Map ${mapId}.spawns[${index}].startEntityId must be a positive integer`);
|
|
132
|
+
}
|
|
133
|
+
const entities = materializePrototypeEntities(cooked, prototypeRef, count, {
|
|
134
|
+
startEntityId,
|
|
135
|
+
componentOverrides: spawnRecord.overrides,
|
|
136
|
+
});
|
|
137
|
+
for (const entity of entities) {
|
|
138
|
+
if (usedEntityIds.has(entity.entityId)) {
|
|
139
|
+
throw new Error(`Map ${mapId}.spawns[${index}] duplicates entityId ${entity.entityId}`);
|
|
140
|
+
}
|
|
141
|
+
usedEntityIds.add(entity.entityId);
|
|
142
|
+
}
|
|
143
|
+
materialized.push(...entities);
|
|
144
|
+
prototypeIds.push(prototypeRef);
|
|
145
|
+
nextEntityId = Math.max(nextEntityId, startEntityId + count);
|
|
146
|
+
}
|
|
147
|
+
const withoutChecksum = {
|
|
148
|
+
mapId,
|
|
149
|
+
assetDbHash: cooked.manifest.assetDbHash,
|
|
150
|
+
mapBakeHash: (0, canonical_js_1.defaultChecksum)({ mapId, assetDbHash: cooked.manifest.assetDbHash, materialized }),
|
|
151
|
+
spawnCount: spawns.length,
|
|
152
|
+
materializedEntityCount: materialized.length,
|
|
153
|
+
prototypeIds: [...new Set(prototypeIds)].sort(compareStrings),
|
|
154
|
+
materializedEntities: materialized,
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
...withoutChecksum,
|
|
158
|
+
checksum: (0, canonical_js_1.defaultChecksum)(withoutChecksum),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function validatePrototypeEntitiesAgainstFrameRuntime(cooked, prototypeId, descriptor, count = 1) {
|
|
162
|
+
const runtime = (0, engine_runtime_js_1.createDeterministicFrameRuntime)(descriptor, 0);
|
|
163
|
+
const entities = materializePrototypeEntities(cooked, prototypeId, count);
|
|
164
|
+
let injectedComponentCount = 0;
|
|
165
|
+
for (const materialized of entities) {
|
|
166
|
+
const runtimeEntity = runtime.createEntity();
|
|
167
|
+
const components = recordOrThrow(materialized.components, `Prototype ${prototypeId} components`);
|
|
168
|
+
for (const componentId of Object.keys(components).sort(compareStrings)) {
|
|
169
|
+
const data = recordOrThrow(components[componentId], `Prototype ${prototypeId}.${componentId}`);
|
|
170
|
+
runtime.setComponent(runtimeEntity, componentId, (0, canonical_js_1.cloneCanonical)(data));
|
|
171
|
+
injectedComponentCount += 1;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const snapshot = runtime.snapshot();
|
|
175
|
+
const result = {
|
|
176
|
+
prototypeId,
|
|
177
|
+
materializedEntityCount: entities.length,
|
|
178
|
+
injectedComponentCount,
|
|
179
|
+
descriptorComponentCount: descriptor.components.filter((component) => component.singleton !== true).length,
|
|
180
|
+
runtimeSnapshotChecksum: snapshot.checksum,
|
|
181
|
+
};
|
|
182
|
+
return {
|
|
183
|
+
...result,
|
|
184
|
+
checksum: (0, canonical_js_1.defaultChecksum)(result),
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function assertAssetManifestMatches(manifest, expected) {
|
|
188
|
+
if (expected.engineVersion !== undefined && manifest.engineVersion !== expected.engineVersion) {
|
|
189
|
+
throw new Error(`Stale deterministic asset engine: expected ${expected.engineVersion}, actual ${manifest.engineVersion}`);
|
|
190
|
+
}
|
|
191
|
+
if (expected.assetDbHash !== undefined && manifest.assetDbHash !== expected.assetDbHash) {
|
|
192
|
+
throw new Error(`Stale deterministic asset database hash: expected ${expected.assetDbHash}, actual ${manifest.assetDbHash}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function validateAssetSource(source) {
|
|
196
|
+
if (!Array.isArray(source.assets)) {
|
|
197
|
+
throw new Error('Deterministic asset source requires an assets array');
|
|
198
|
+
}
|
|
199
|
+
if (source.schemaVersion !== undefined && source.schemaVersion !== 1) {
|
|
200
|
+
throw new Error(`Unsupported deterministic asset schema ${source.schemaVersion}`);
|
|
201
|
+
}
|
|
202
|
+
validateDependencies(source.dependencies ?? []);
|
|
203
|
+
const ids = new Set();
|
|
204
|
+
for (const asset of source.assets) {
|
|
205
|
+
if (typeof asset.id !== 'string' || asset.id.length === 0) {
|
|
206
|
+
throw new Error('Every deterministic asset requires a non-empty string id');
|
|
207
|
+
}
|
|
208
|
+
if (ids.has(asset.id)) {
|
|
209
|
+
throw new Error(`Duplicate deterministic asset id ${asset.id}`);
|
|
210
|
+
}
|
|
211
|
+
ids.add(asset.id);
|
|
212
|
+
rejectUnquantizedNumbers(asset, asset.id);
|
|
213
|
+
}
|
|
214
|
+
for (const asset of source.assets) {
|
|
215
|
+
for (const reference of asset.references ?? []) {
|
|
216
|
+
if (!ids.has(reference)) {
|
|
217
|
+
throw new Error(`Unresolved deterministic asset reference ${asset.id} -> ${reference}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
validateImplicitAssetRefs(asset, ids, asset.id);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function validateImplicitAssetRefs(value, ids, path) {
|
|
224
|
+
if (Array.isArray(value)) {
|
|
225
|
+
value.forEach((entry, index) => validateImplicitAssetRefs(entry, ids, `${path}[${index}]`));
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
if (value === null || typeof value !== 'object') {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
for (const key of Object.keys(value).sort(compareStrings)) {
|
|
232
|
+
const entry = value[key];
|
|
233
|
+
const entryPath = `${path}.${key}`;
|
|
234
|
+
if (key.endsWith('Ref') && typeof entry === 'string' && !ids.has(entry)) {
|
|
235
|
+
throw new Error(`Unresolved deterministic asset ref ${entryPath} -> ${entry}`);
|
|
236
|
+
}
|
|
237
|
+
if (key.endsWith('Refs') && Array.isArray(entry)) {
|
|
238
|
+
for (const [index, ref] of entry.entries()) {
|
|
239
|
+
if (typeof ref === 'string' && !ids.has(ref)) {
|
|
240
|
+
throw new Error(`Unresolved deterministic asset ref ${entryPath}[${index}] -> ${ref}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
validateImplicitAssetRefs(entry, ids, entryPath);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function recordOrThrow(value, label) {
|
|
248
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
249
|
+
throw new Error(`${label} must be an object`);
|
|
250
|
+
}
|
|
251
|
+
return value;
|
|
252
|
+
}
|
|
253
|
+
function resolvePrototypeComponents(cooked, prototypeId, seen) {
|
|
254
|
+
if (seen.has(prototypeId)) {
|
|
255
|
+
throw new Error(`Prototype inheritance cycle at ${prototypeId}`);
|
|
256
|
+
}
|
|
257
|
+
seen.add(prototypeId);
|
|
258
|
+
const prototype = cooked.cookedAssets.find((asset) => asset.id === prototypeId);
|
|
259
|
+
if (prototype === undefined) {
|
|
260
|
+
throw new Error(`Unknown prototype ${prototypeId}`);
|
|
261
|
+
}
|
|
262
|
+
const data = recordOrThrow(prototype.data, `Prototype ${prototypeId}`);
|
|
263
|
+
const parentRef = data.extendsRef;
|
|
264
|
+
const parent = parentRef === undefined
|
|
265
|
+
? {}
|
|
266
|
+
: resolvePrototypeComponents(cooked, stringOrThrow(parentRef, `Prototype ${prototypeId}.extendsRef`), seen);
|
|
267
|
+
const own = data.components === undefined
|
|
268
|
+
? {}
|
|
269
|
+
: recordOrThrow(data.components, `Prototype ${prototypeId} components`);
|
|
270
|
+
return mergeRecords(parent, own);
|
|
271
|
+
}
|
|
272
|
+
function mergeRecords(base, override) {
|
|
273
|
+
const merged = {};
|
|
274
|
+
for (const key of [...new Set([...stableRecordKeys(base), ...stableRecordKeys(override)])].sort(compareStrings)) {
|
|
275
|
+
const baseValue = base[key];
|
|
276
|
+
const overrideValue = override[key];
|
|
277
|
+
if (overrideValue === undefined) {
|
|
278
|
+
merged[key] = (0, canonical_js_1.cloneCanonical)(baseValue);
|
|
279
|
+
}
|
|
280
|
+
else if (isPlainRecord(baseValue) && isPlainRecord(overrideValue) && !isCollectionDescriptor(overrideValue)) {
|
|
281
|
+
merged[key] = mergeRecords(baseValue, overrideValue);
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
merged[key] = (0, canonical_js_1.cloneCanonical)(overrideValue);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return merged;
|
|
288
|
+
}
|
|
289
|
+
function materializeDynamicCollections(value) {
|
|
290
|
+
if (Array.isArray(value)) {
|
|
291
|
+
return value.map(materializeDynamicCollections);
|
|
292
|
+
}
|
|
293
|
+
if (!isPlainRecord(value)) {
|
|
294
|
+
return (0, canonical_js_1.cloneCanonical)(value);
|
|
295
|
+
}
|
|
296
|
+
if (isCollectionDescriptor(value)) {
|
|
297
|
+
const kind = stringOrThrow(value.collection, 'collection');
|
|
298
|
+
if (kind === 'list' || kind === 'buffer') {
|
|
299
|
+
const values = Array.isArray(value.values) ? value.values : [];
|
|
300
|
+
return values.map(materializeDynamicCollections);
|
|
301
|
+
}
|
|
302
|
+
if (kind === 'set') {
|
|
303
|
+
const values = Array.isArray(value.values) ? value.values : [];
|
|
304
|
+
return [...new Set(values.map((entry) => (0, canonical_js_1.canonicalStringify)(materializeDynamicCollections(entry))))]
|
|
305
|
+
.sort(compareStrings)
|
|
306
|
+
.map((entry) => JSON.parse(entry));
|
|
307
|
+
}
|
|
308
|
+
if (kind === 'map' || kind === 'dictionary') {
|
|
309
|
+
const entries = recordOrThrow(value.entries ?? {}, `${kind} entries`);
|
|
310
|
+
return Object.fromEntries(Object.keys(entries).sort(compareStrings).map((key) => [key, materializeDynamicCollections(entries[key])]));
|
|
311
|
+
}
|
|
312
|
+
throw new Error(`Unsupported deterministic prototype collection ${kind}`);
|
|
313
|
+
}
|
|
314
|
+
return Object.fromEntries(Object.keys(value).sort(compareStrings).map((key) => [key, materializeDynamicCollections(value[key])]));
|
|
315
|
+
}
|
|
316
|
+
function isCollectionDescriptor(value) {
|
|
317
|
+
return typeof value.collection === 'string';
|
|
318
|
+
}
|
|
319
|
+
function isPlainRecord(value) {
|
|
320
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
321
|
+
}
|
|
322
|
+
function stringOrThrow(value, label) {
|
|
323
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
324
|
+
throw new Error(`${label} must be a non-empty string`);
|
|
325
|
+
}
|
|
326
|
+
return value;
|
|
327
|
+
}
|
|
328
|
+
function optionalInteger(value, label) {
|
|
329
|
+
if (value === undefined) {
|
|
330
|
+
return undefined;
|
|
331
|
+
}
|
|
332
|
+
if (!Number.isInteger(value)) {
|
|
333
|
+
throw new Error(`${label} must be an integer`);
|
|
334
|
+
}
|
|
335
|
+
return value;
|
|
336
|
+
}
|
|
337
|
+
function stableRecordKeys(record) {
|
|
338
|
+
return Reflect.ownKeys(record)
|
|
339
|
+
.filter((key) => typeof key === 'string')
|
|
340
|
+
.sort(compareStrings);
|
|
341
|
+
}
|
|
342
|
+
function validateDependencies(dependencies) {
|
|
343
|
+
for (const dependency of dependencies) {
|
|
344
|
+
if (/[\^~*xX]/.test(dependency.version) || dependency.version === 'latest') {
|
|
345
|
+
throw new Error(`Nondeterministic dependency version ${dependency.name}@${dependency.version}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function compareDependencies(left, right) {
|
|
350
|
+
return compareStrings(left.name, right.name) || compareStrings(left.version, right.version);
|
|
351
|
+
}
|
|
352
|
+
function rejectUnquantizedNumbers(value, path) {
|
|
353
|
+
if (typeof value === 'number') {
|
|
354
|
+
if (!Number.isInteger(value)) {
|
|
355
|
+
throw new Error(`Unquantized float at ${path}`);
|
|
356
|
+
}
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (Array.isArray(value)) {
|
|
360
|
+
value.forEach((entry, index) => rejectUnquantizedNumbers(entry, `${path}[${index}]`));
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (value !== null && typeof value === 'object') {
|
|
364
|
+
for (const key of Object.keys(value).sort(compareStrings)) {
|
|
365
|
+
const entry = value[key];
|
|
366
|
+
rejectUnquantizedNumbers(entry, `${path}.${key}`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
function compareStrings(left, right) {
|
|
371
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
372
|
+
}
|