@forgeax/engine-scene 0.1.27 → 0.1.29
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 +50 -0
- package/dist/__tests__/keyed-scene.integration.test.d.ts +2 -0
- package/dist/__tests__/keyed-scene.integration.test.d.ts.map +1 -0
- package/dist/assets/scene-decoder.d.ts.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +848 -229
- package/dist/index.mjs.map +1 -1
- package/dist/instances/binding.d.ts +7 -5
- package/dist/instances/binding.d.ts.map +1 -1
- package/dist/instances/externalization.d.ts +1 -1
- package/dist/instances/externalization.d.ts.map +1 -1
- package/dist/instances/keyed.d.ts +38 -0
- package/dist/instances/keyed.d.ts.map +1 -0
- package/dist/instances/legacy.d.ts +20 -0
- package/dist/instances/legacy.d.ts.map +1 -0
- package/dist/instances/runtime-types.d.ts +20 -0
- package/dist/instances/runtime-types.d.ts.map +1 -0
- package/dist/instances/scene-instances.d.ts +27 -37
- package/dist/instances/scene-instances.d.ts.map +1 -1
- package/dist/instances/state.d.ts +6 -1
- package/dist/instances/state.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/asset-owner.integration.test.ts +4 -7
- package/src/__tests__/flat-propagation.perf.test.ts +18 -17
- package/src/__tests__/keyed-scene.integration.test.ts +269 -0
- package/src/__tests__/scene-binding.integration.test.ts +141 -32
- package/src/__tests__/structural.test.ts +4 -1
- package/src/assets/scene-decoder.ts +123 -33
- package/src/collect-subtree.ts +2 -2
- package/src/index.ts +10 -1
- package/src/instances/binding.ts +26 -19
- package/src/instances/externalization.ts +115 -97
- package/src/instances/keyed.ts +505 -0
- package/src/instances/legacy.ts +108 -0
- package/src/instances/runtime-types.ts +21 -0
- package/src/instances/scene-instances.ts +220 -83
- package/src/instances/state.ts +6 -1
package/dist/index.mjs
CHANGED
|
@@ -3,13 +3,81 @@ import {
|
|
|
3
3
|
err,
|
|
4
4
|
ok
|
|
5
5
|
} from "@forgeax/engine-types";
|
|
6
|
+
|
|
7
|
+
// src/instances/legacy.ts
|
|
8
|
+
function migrateLegacySceneComponentFields(componentName, source, addressByLocalId) {
|
|
9
|
+
const fields = { ...source };
|
|
10
|
+
const address = (value) => Number.isSafeInteger(value) ? addressByLocalId?.get(value) ?? String(value) : value;
|
|
11
|
+
if (componentName === "DirectionalLight" && Object.hasOwn(fields, "pcfKernelSize")) {
|
|
12
|
+
const kernel = fields.pcfKernelSize;
|
|
13
|
+
const shadowFilter = kernel === 1 ? 1 : kernel === 3 ? 2 : kernel === 5 ? 3 : void 0;
|
|
14
|
+
if (shadowFilter !== void 0 && !Object.hasOwn(fields, "shadowFilter")) {
|
|
15
|
+
delete fields.pcfKernelSize;
|
|
16
|
+
fields.shadowFilter = shadowFilter;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (componentName === "ChildOf" && Number.isSafeInteger(fields.parent)) {
|
|
20
|
+
fields.parent = address(fields.parent);
|
|
21
|
+
}
|
|
22
|
+
if (componentName === "Children" && Array.isArray(fields.entities)) {
|
|
23
|
+
fields.entities = fields.entities.map(address);
|
|
24
|
+
}
|
|
25
|
+
return fields;
|
|
26
|
+
}
|
|
27
|
+
function normalizeLegacySceneAsset(scene) {
|
|
28
|
+
if (scene === null || typeof scene !== "object") return scene;
|
|
29
|
+
const candidate = scene;
|
|
30
|
+
if (!Array.isArray(candidate.entities))
|
|
31
|
+
return scene;
|
|
32
|
+
const rows = candidate.entities;
|
|
33
|
+
const addressByLocalId = /* @__PURE__ */ new Map();
|
|
34
|
+
const rowKeys = [];
|
|
35
|
+
const used = /* @__PURE__ */ new Set();
|
|
36
|
+
for (const [index, row] of rows.entries()) {
|
|
37
|
+
const localId = Number.isSafeInteger(row?.localId) ? row.localId : index;
|
|
38
|
+
const bindingKey = typeof row?.bindingKey === "string" && row.bindingKey.length > 0 ? row.bindingKey : String(localId);
|
|
39
|
+
const key = used.has(bindingKey) ? String(localId) : bindingKey;
|
|
40
|
+
used.add(key);
|
|
41
|
+
addressByLocalId.set(localId, key);
|
|
42
|
+
rowKeys.push(key);
|
|
43
|
+
}
|
|
44
|
+
const entities = {};
|
|
45
|
+
for (const [index, row] of rows.entries()) {
|
|
46
|
+
const key = rowKeys[index];
|
|
47
|
+
const rawComponents = row?.components;
|
|
48
|
+
const components = {};
|
|
49
|
+
if (rawComponents !== null && typeof rawComponents === "object" && !Array.isArray(rawComponents)) {
|
|
50
|
+
for (const [componentName, rawFields] of Object.entries(
|
|
51
|
+
rawComponents
|
|
52
|
+
)) {
|
|
53
|
+
if (rawFields === null || typeof rawFields !== "object" || Array.isArray(rawFields))
|
|
54
|
+
continue;
|
|
55
|
+
components[componentName] = migrateLegacySceneComponentFields(
|
|
56
|
+
componentName,
|
|
57
|
+
rawFields,
|
|
58
|
+
addressByLocalId
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
entities[key] = {
|
|
63
|
+
components,
|
|
64
|
+
...row?.instance === void 0 ? {} : { instance: row.instance }
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...scene,
|
|
69
|
+
entities
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/assets/scene-decoder.ts
|
|
6
74
|
var sceneAssetKind = {
|
|
7
75
|
kind: "scene"
|
|
8
76
|
};
|
|
9
77
|
function invalidScene(guid, reason) {
|
|
10
78
|
return err({
|
|
11
79
|
code: "asset-package-invalid",
|
|
12
|
-
expected: "a scene payload with
|
|
80
|
+
expected: "a scene payload with keyed entities",
|
|
13
81
|
hint: "recook the SceneAsset and publish its complete envelope",
|
|
14
82
|
detail: { guid, reason }
|
|
15
83
|
});
|
|
@@ -25,19 +93,12 @@ function resolveWireRef(refs, value, location) {
|
|
|
25
93
|
}
|
|
26
94
|
return { ok: true, value: guid };
|
|
27
95
|
}
|
|
28
|
-
function
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (typeof mount.source !== "number" || !Number.isInteger(mount.source)) {
|
|
33
|
-
resolved.push(mount);
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
const ref = resolveWireRef(refs, mount.source, `mount ${mount.localId} source`);
|
|
37
|
-
if (!ref.ok) return ref;
|
|
38
|
-
resolved.push({ ...mount, source: ref.value });
|
|
96
|
+
function resolveInstanceSource(source, refs, location) {
|
|
97
|
+
if (typeof source === "string" && source.length > 0) return { ok: true, value: source };
|
|
98
|
+
if (typeof source !== "number" || !Number.isInteger(source)) {
|
|
99
|
+
return { ok: false, reason: `${location} must be a GUID or refs index` };
|
|
39
100
|
}
|
|
40
|
-
return
|
|
101
|
+
return resolveWireRef(refs, source, location);
|
|
41
102
|
}
|
|
42
103
|
function resolveSkinGuids(skinGuids, refs) {
|
|
43
104
|
if (skinGuids === void 0) return { ok: true, value: void 0 };
|
|
@@ -58,22 +119,88 @@ function resolveSkinGuids(skinGuids, refs) {
|
|
|
58
119
|
return { ok: true, value: resolved };
|
|
59
120
|
}
|
|
60
121
|
function resolveSceneWireRefs(payload, refs) {
|
|
61
|
-
const
|
|
62
|
-
|
|
122
|
+
const normalized = normalizeLegacySceneAsset({ kind: "scene", entities: payload.entities });
|
|
123
|
+
const rawEntities = normalized.entities;
|
|
124
|
+
if (rawEntities === null || typeof rawEntities !== "object" || Array.isArray(rawEntities)) {
|
|
125
|
+
return { ok: false, reason: "entities must be a keyed object" };
|
|
126
|
+
}
|
|
127
|
+
const entities = {};
|
|
128
|
+
for (const [key, rawEntity] of Object.entries(rawEntities)) {
|
|
129
|
+
const entity = rawEntity;
|
|
130
|
+
if (key.length === 0 || entity === void 0 || typeof entity !== "object") {
|
|
131
|
+
return { ok: false, reason: `entities[${JSON.stringify(key)}] is malformed` };
|
|
132
|
+
}
|
|
133
|
+
if (entity.components === null || typeof entity.components !== "object" || Array.isArray(entity.components)) {
|
|
134
|
+
return { ok: false, reason: `entities.${key}.components must be an object` };
|
|
135
|
+
}
|
|
63
136
|
const components = {};
|
|
64
|
-
for (const [componentName, rawFields] of Object.entries(
|
|
137
|
+
for (const [componentName, rawFields] of Object.entries(
|
|
138
|
+
entity.components
|
|
139
|
+
)) {
|
|
140
|
+
if (rawFields === null || typeof rawFields !== "object" || Array.isArray(rawFields)) {
|
|
141
|
+
return {
|
|
142
|
+
ok: false,
|
|
143
|
+
reason: `entities.${key}.components.${componentName} must be an object`
|
|
144
|
+
};
|
|
145
|
+
}
|
|
65
146
|
components[componentName] = { ...rawFields };
|
|
66
147
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
148
|
+
const instance = entity.instance;
|
|
149
|
+
let resolvedInstance;
|
|
150
|
+
if (instance !== void 0) {
|
|
151
|
+
if (instance === null || typeof instance !== "object") {
|
|
152
|
+
return { ok: false, reason: `entities.${key}.instance must be an object` };
|
|
153
|
+
}
|
|
154
|
+
const source = resolveInstanceSource(
|
|
155
|
+
instance.source,
|
|
156
|
+
refs,
|
|
157
|
+
`entities.${key}.instance.source`
|
|
158
|
+
);
|
|
159
|
+
if (!source.ok) return source;
|
|
160
|
+
if (instance.overrides !== void 0 && !Array.isArray(instance.overrides)) {
|
|
161
|
+
return { ok: false, reason: `entities.${key}.instance.overrides must be an array` };
|
|
162
|
+
}
|
|
163
|
+
let overrides;
|
|
164
|
+
if (instance.overrides === void 0) {
|
|
165
|
+
overrides = void 0;
|
|
166
|
+
} else {
|
|
167
|
+
const resolvedOverrides = [];
|
|
168
|
+
for (const [index, rawOverride] of instance.overrides.entries()) {
|
|
169
|
+
if (rawOverride === null || typeof rawOverride !== "object" || Array.isArray(rawOverride) || !Array.isArray(rawOverride.target) || rawOverride.target?.some(
|
|
170
|
+
(part) => typeof part !== "string" || part.length === 0
|
|
171
|
+
)) {
|
|
172
|
+
return {
|
|
173
|
+
ok: false,
|
|
174
|
+
reason: `entities.${key}.instance.overrides[${index}] is malformed`
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
const target = rawOverride.target;
|
|
178
|
+
const rawComponents = rawOverride.components;
|
|
179
|
+
if (rawComponents === null || typeof rawComponents !== "object" || Array.isArray(rawComponents)) {
|
|
180
|
+
return {
|
|
181
|
+
ok: false,
|
|
182
|
+
reason: `entities.${key}.instance.overrides[${index}].components is malformed`
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
resolvedOverrides.push({
|
|
186
|
+
target: [...target],
|
|
187
|
+
components: rawComponents
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
overrides = resolvedOverrides;
|
|
191
|
+
}
|
|
192
|
+
resolvedInstance = {
|
|
193
|
+
source: source.value,
|
|
194
|
+
...overrides === void 0 ? {} : { overrides }
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
entities[key] = {
|
|
198
|
+
components,
|
|
199
|
+
...resolvedInstance === void 0 ? {} : { instance: resolvedInstance }
|
|
200
|
+
};
|
|
72
201
|
}
|
|
73
|
-
const mounts = resolveMounts(payload.mounts, refs);
|
|
74
|
-
if (!mounts.ok) return mounts;
|
|
75
202
|
const skinGuids = resolveSkinGuids(
|
|
76
|
-
payload.skinGuids,
|
|
203
|
+
Array.isArray(payload.skinGuids) ? payload.skinGuids : payload.skinGuids === void 0 ? void 0 : [],
|
|
77
204
|
refs
|
|
78
205
|
);
|
|
79
206
|
if (!skinGuids.ok) return skinGuids;
|
|
@@ -81,9 +208,7 @@ function resolveSceneWireRefs(payload, refs) {
|
|
|
81
208
|
ok: true,
|
|
82
209
|
value: {
|
|
83
210
|
kind: "scene",
|
|
84
|
-
...payload.sourceKey === void 0 ? {} : { sourceKey: payload.sourceKey },
|
|
85
211
|
entities,
|
|
86
|
-
...mounts.value === void 0 ? {} : { mounts: mounts.value },
|
|
87
212
|
...skinGuids.value === void 0 ? {} : { skinGuids: skinGuids.value }
|
|
88
213
|
}
|
|
89
214
|
};
|
|
@@ -91,8 +216,8 @@ function resolveSceneWireRefs(payload, refs) {
|
|
|
91
216
|
var sceneAssetDecoder = {
|
|
92
217
|
async decode({ envelope }) {
|
|
93
218
|
const payload = envelope.payload;
|
|
94
|
-
if (payload.kind !== "scene" ||
|
|
95
|
-
return invalidScene(envelope.guid, "scene payload is missing entities");
|
|
219
|
+
if (payload.kind !== "scene" || payload.entities === null || typeof payload.entities !== "object") {
|
|
220
|
+
return invalidScene(envelope.guid, "scene payload is missing keyed entities");
|
|
96
221
|
}
|
|
97
222
|
const resolved = resolveSceneWireRefs(payload, envelope.refs);
|
|
98
223
|
if (!resolved.ok) return invalidScene(envelope.guid, resolved.reason);
|
|
@@ -151,8 +276,8 @@ function collectSubtree(world, spawnRoot, visited) {
|
|
|
151
276
|
if (visited.has(spawnRoot)) return visited;
|
|
152
277
|
const queue = [spawnRoot];
|
|
153
278
|
visited.add(spawnRoot);
|
|
154
|
-
|
|
155
|
-
const current = queue
|
|
279
|
+
for (let cursor = 0; cursor < queue.length; cursor += 1) {
|
|
280
|
+
const current = queue[cursor];
|
|
156
281
|
const children = world.get(current, Children);
|
|
157
282
|
if (!children.ok) continue;
|
|
158
283
|
const entities = children.value.entities;
|
|
@@ -195,7 +320,7 @@ var SceneError = class extends Error {
|
|
|
195
320
|
|
|
196
321
|
// src/instances/binding.ts
|
|
197
322
|
import { err as err2, ok as ok2 } from "@forgeax/engine-types";
|
|
198
|
-
function
|
|
323
|
+
function validateSceneEntityKeys(sceneSourceKey, entityKeys) {
|
|
199
324
|
if (sceneSourceKey.length === 0) {
|
|
200
325
|
return err2({
|
|
201
326
|
code: "scene-binding-source-missing",
|
|
@@ -205,21 +330,26 @@ function validateSceneBindings(sceneSourceKey, bindingKeys) {
|
|
|
205
330
|
});
|
|
206
331
|
}
|
|
207
332
|
const seen = /* @__PURE__ */ new Set();
|
|
208
|
-
for (const
|
|
209
|
-
if (
|
|
333
|
+
for (const entityKey of entityKeys) {
|
|
334
|
+
if (entityKey.length === 0 || seen.has(entityKey)) {
|
|
210
335
|
return err2({
|
|
211
336
|
code: "scene-binding-duplicate",
|
|
212
|
-
expected: "unique non-empty
|
|
213
|
-
hint: "rename the duplicate
|
|
214
|
-
detail: { sceneSourceKey,
|
|
337
|
+
expected: "unique non-empty entity keys within one scene",
|
|
338
|
+
hint: "rename the duplicate entity key in the scene producer",
|
|
339
|
+
detail: { sceneSourceKey, address: entityKey }
|
|
215
340
|
});
|
|
216
341
|
}
|
|
217
|
-
seen.add(
|
|
342
|
+
seen.add(entityKey);
|
|
218
343
|
}
|
|
219
|
-
return ok2([...
|
|
344
|
+
return ok2([...entityKeys]);
|
|
220
345
|
}
|
|
221
|
-
function sceneEntity(sceneSourceKey,
|
|
222
|
-
return { sceneSourceKey,
|
|
346
|
+
function sceneEntity(sceneSourceKey, address) {
|
|
347
|
+
return { sceneSourceKey, address };
|
|
348
|
+
}
|
|
349
|
+
function sceneEntityAddressKey(address) {
|
|
350
|
+
if (typeof address === "string") return `s:${JSON.stringify(address)}`;
|
|
351
|
+
if (address.length === 1) return `s:${JSON.stringify(address[0] ?? "")}`;
|
|
352
|
+
return `a:${JSON.stringify(address)}`;
|
|
223
353
|
}
|
|
224
354
|
function resolveSceneEntity(ref, instance) {
|
|
225
355
|
if (ref.sceneSourceKey !== instance.sceneSourceKey) {
|
|
@@ -227,16 +357,16 @@ function resolveSceneEntity(ref, instance) {
|
|
|
227
357
|
code: "scene-binding-wrong-instance",
|
|
228
358
|
expected: `scene instance ${ref.sceneSourceKey}`,
|
|
229
359
|
hint: "resolve the SceneEntityRef against its owning SceneInstance",
|
|
230
|
-
detail: { sceneSourceKey: ref.sceneSourceKey,
|
|
360
|
+
detail: { sceneSourceKey: ref.sceneSourceKey, address: ref.address }
|
|
231
361
|
});
|
|
232
362
|
}
|
|
233
|
-
const value = instance.bindings.get(ref.
|
|
363
|
+
const value = instance.bindings.get(sceneEntityAddressKey(ref.address));
|
|
234
364
|
if (value === void 0) {
|
|
235
365
|
return err2({
|
|
236
366
|
code: "scene-binding-missing",
|
|
237
|
-
expected: "
|
|
238
|
-
hint: "declare the
|
|
239
|
-
detail: { sceneSourceKey: ref.sceneSourceKey,
|
|
367
|
+
expected: "entity key declared by the scene producer",
|
|
368
|
+
hint: "declare the entity key in the scene producer before consuming it",
|
|
369
|
+
detail: { sceneSourceKey: ref.sceneSourceKey, address: ref.address }
|
|
240
370
|
});
|
|
241
371
|
}
|
|
242
372
|
return ok2(value);
|
|
@@ -255,108 +385,488 @@ function sharedKind(type) {
|
|
|
255
385
|
if (type?.startsWith("array<shared<")) return "many";
|
|
256
386
|
return void 0;
|
|
257
387
|
}
|
|
258
|
-
function
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
}
|
|
267
|
-
return [];
|
|
388
|
+
function addRef(context, guid, sourceField, sceneEntityKey) {
|
|
389
|
+
const prior = context.indexByGuid.get(guid);
|
|
390
|
+
if (prior !== void 0) return prior;
|
|
391
|
+
const index = context.refs.length;
|
|
392
|
+
context.refs.push({
|
|
393
|
+
guid,
|
|
394
|
+
sourceField,
|
|
395
|
+
...sceneEntityKey === void 0 ? {} : { sceneEntityKey }
|
|
268
396
|
});
|
|
397
|
+
context.indexByGuid.set(guid, index);
|
|
398
|
+
return index;
|
|
399
|
+
}
|
|
400
|
+
function externalizeFields(componentName, source, resolveSchema, context, sceneEntityKey) {
|
|
401
|
+
const schema = resolveSchema(componentName);
|
|
402
|
+
const fields = {};
|
|
403
|
+
for (const [fieldName, value] of Object.entries(
|
|
404
|
+
migrateLegacySceneComponentFields(componentName, source)
|
|
405
|
+
)) {
|
|
406
|
+
if (value === void 0) continue;
|
|
407
|
+
const kind = sharedKind(schema?.[fieldName]);
|
|
408
|
+
if (kind === "one" && typeof value === "string") {
|
|
409
|
+
fields[fieldName] = addRef(context, value, { componentName, fieldName }, sceneEntityKey);
|
|
410
|
+
} else if (kind === "many" && Array.isArray(value)) {
|
|
411
|
+
fields[fieldName] = value.map(
|
|
412
|
+
(item, arrayIndex) => typeof item === "string" ? addRef(context, item, { componentName, fieldName, arrayIndex }, sceneEntityKey) : item
|
|
413
|
+
);
|
|
414
|
+
} else {
|
|
415
|
+
fields[fieldName] = value;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return fields;
|
|
269
419
|
}
|
|
270
|
-
function
|
|
271
|
-
const
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
420
|
+
function externalizeOverride(override, resolveSchema, context, sceneEntityKey) {
|
|
421
|
+
const components = {};
|
|
422
|
+
for (const [componentName, rawFields] of Object.entries(override.components)) {
|
|
423
|
+
components[componentName] = externalizeFields(
|
|
424
|
+
componentName,
|
|
425
|
+
{ ...rawFields },
|
|
426
|
+
resolveSchema,
|
|
427
|
+
context,
|
|
428
|
+
sceneEntityKey
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
target: [...override.target],
|
|
433
|
+
components
|
|
280
434
|
};
|
|
281
|
-
|
|
435
|
+
}
|
|
436
|
+
function externalizeSceneAsset(scene, resolveSchema) {
|
|
437
|
+
const normalized = normalizeLegacySceneAsset(scene);
|
|
438
|
+
const context = { refs: [], indexByGuid: /* @__PURE__ */ new Map() };
|
|
439
|
+
const entities = {};
|
|
440
|
+
for (const [key, entity] of Object.entries(normalized.entities)) {
|
|
282
441
|
const components = {};
|
|
283
|
-
for (const componentName of Object.
|
|
284
|
-
const
|
|
285
|
-
const source = entity.components[componentName];
|
|
442
|
+
for (const [componentName, raw] of Object.entries(entity.components)) {
|
|
443
|
+
const source = raw;
|
|
286
444
|
if (source === void 0) continue;
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
445
|
+
components[componentName] = externalizeFields(
|
|
446
|
+
componentName,
|
|
447
|
+
source,
|
|
448
|
+
resolveSchema,
|
|
449
|
+
context,
|
|
450
|
+
key
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
const instance = entity.instance;
|
|
454
|
+
entities[key] = {
|
|
455
|
+
components,
|
|
456
|
+
...instance === void 0 ? {} : {
|
|
457
|
+
instance: {
|
|
458
|
+
source: addRef(
|
|
459
|
+
context,
|
|
460
|
+
instance.source,
|
|
461
|
+
{ componentName: "SceneInstance", fieldName: "source" },
|
|
462
|
+
key
|
|
463
|
+
),
|
|
464
|
+
...instance.overrides === void 0 ? {} : {
|
|
465
|
+
overrides: instance.overrides.map(
|
|
466
|
+
(override) => externalizeOverride(override, resolveSchema, context, key)
|
|
467
|
+
)
|
|
468
|
+
}
|
|
300
469
|
}
|
|
301
470
|
}
|
|
302
|
-
if (Object.keys(fields).length > 0 || Object.keys(schema ?? {}).length === 0) {
|
|
303
|
-
components[componentName] = fields;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
return {
|
|
307
|
-
localId: entity.localId,
|
|
308
|
-
...entity.bindingKey === void 0 ? {} : { bindingKey: entity.bindingKey },
|
|
309
|
-
components
|
|
310
471
|
};
|
|
311
|
-
}
|
|
312
|
-
const
|
|
313
|
-
const source = typeof mount.source === "string" ? addRef(
|
|
314
|
-
mount.source,
|
|
315
|
-
{ componentName: "SceneInstance", fieldName: "source" },
|
|
316
|
-
mount.localId
|
|
317
|
-
) : mount.source;
|
|
318
|
-
for (const { field, guid } of (mount.overrides ?? []).flatMap(
|
|
319
|
-
(override) => overrideGuids(override, resolveSchema)
|
|
320
|
-
)) {
|
|
321
|
-
addRef(guid, { componentName: "SceneInstance", fieldName: `overrides.${field}` });
|
|
322
|
-
}
|
|
323
|
-
return {
|
|
324
|
-
localId: mount.localId,
|
|
325
|
-
source,
|
|
326
|
-
memberFirst: mount.memberFirst,
|
|
327
|
-
memberCount: mount.memberCount,
|
|
328
|
-
...mount.parent === void 0 ? {} : { parent: mount.parent },
|
|
329
|
-
...mount.publicationFence === void 0 ? {} : { publicationFence: mount.publicationFence },
|
|
330
|
-
...mount.overrides === void 0 ? {} : { overrides: mount.overrides.map((item) => ({ ...item })) }
|
|
331
|
-
};
|
|
332
|
-
});
|
|
333
|
-
for (const [arrayIndex, guid] of (scene.skinGuids ?? []).entries()) {
|
|
472
|
+
}
|
|
473
|
+
for (const [arrayIndex, guid] of (normalized.skinGuids ?? []).entries()) {
|
|
334
474
|
if (typeof guid !== "string") return err3({ field: "skinGuids", value: guid });
|
|
335
|
-
addRef(guid, { componentName: "<scene>", fieldName: "skinGuids", arrayIndex });
|
|
475
|
+
addRef(context, guid, { componentName: "<scene>", fieldName: "skinGuids", arrayIndex });
|
|
336
476
|
}
|
|
337
477
|
return ok3({
|
|
338
478
|
payload: {
|
|
339
479
|
kind: "scene",
|
|
340
|
-
...scene.sourceKey === void 0 ? {} : { sourceKey: scene.sourceKey },
|
|
341
480
|
entities,
|
|
342
|
-
...
|
|
343
|
-
|
|
481
|
+
...normalized.skinGuids === void 0 ? {} : {
|
|
482
|
+
skinGuids: normalized.skinGuids.map((guid) => context.indexByGuid.get(guid))
|
|
483
|
+
}
|
|
344
484
|
},
|
|
345
|
-
refs
|
|
485
|
+
refs: context.refs
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// src/instances/keyed.ts
|
|
490
|
+
import { classifyEntityField, remapEntityFieldValue } from "@forgeax/engine-ecs/externalization";
|
|
491
|
+
import { componentSchema } from "@forgeax/engine-ecs/internal";
|
|
492
|
+
import {
|
|
493
|
+
err as err4,
|
|
494
|
+
ok as ok4,
|
|
495
|
+
PACK_ERROR_HINTS
|
|
496
|
+
} from "@forgeax/engine-types";
|
|
497
|
+
function fail(reason, detail = {}) {
|
|
498
|
+
return err4({
|
|
499
|
+
code: "asset-package-invalid",
|
|
500
|
+
expected: "a keyed SceneAsset with valid entity and instance addresses",
|
|
501
|
+
hint: "repair the SceneAsset source and recook the asset",
|
|
502
|
+
detail: { reason, ...detail }
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
function keyList(entities) {
|
|
506
|
+
return Object.keys(entities).sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
507
|
+
}
|
|
508
|
+
function addressParts(value) {
|
|
509
|
+
if (typeof value === "string" && value.length > 0) return [value];
|
|
510
|
+
if (Number.isSafeInteger(value)) return [String(value)];
|
|
511
|
+
if (!Array.isArray(value) || value.length === 0) return void 0;
|
|
512
|
+
if (!value.every((part) => typeof part === "string" && part.length > 0)) return void 0;
|
|
513
|
+
return value;
|
|
514
|
+
}
|
|
515
|
+
function fieldRemap(world, componentName, fields, resolveAddress, entityKey) {
|
|
516
|
+
const token = world.components.resolve(componentName);
|
|
517
|
+
if (token === void 0) return fail("unknown component", { component: componentName });
|
|
518
|
+
const schema = componentSchema(token);
|
|
519
|
+
const out = {};
|
|
520
|
+
for (const [fieldName, value] of Object.entries(
|
|
521
|
+
migrateLegacySceneComponentFields(componentName, fields)
|
|
522
|
+
)) {
|
|
523
|
+
const fieldType = schema[fieldName];
|
|
524
|
+
if (fieldType === void 0) {
|
|
525
|
+
return fail("unknown component field", {
|
|
526
|
+
component: componentName,
|
|
527
|
+
field: fieldName,
|
|
528
|
+
...entityKey === void 0 ? {} : { entity: entityKey }
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
const kind = classifyEntityField(token, fieldName);
|
|
532
|
+
if (kind === null) {
|
|
533
|
+
out[fieldName] = value;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
const remap = (address) => resolveAddress(address, `${componentName}.${fieldName}`) ?? address;
|
|
537
|
+
if (kind.isArray) {
|
|
538
|
+
if (!Array.isArray(value))
|
|
539
|
+
return fail("array entity field is not an array", {
|
|
540
|
+
component: componentName,
|
|
541
|
+
field: fieldName
|
|
542
|
+
});
|
|
543
|
+
const numeric = [];
|
|
544
|
+
for (const item of value) {
|
|
545
|
+
const parts2 = addressParts(item);
|
|
546
|
+
if (parts2 === void 0)
|
|
547
|
+
return fail("invalid entity address", {
|
|
548
|
+
component: componentName,
|
|
549
|
+
field: fieldName,
|
|
550
|
+
address: item
|
|
551
|
+
});
|
|
552
|
+
const slot2 = resolveAddress(parts2, `${componentName}.${fieldName}`);
|
|
553
|
+
if (slot2 === void 0)
|
|
554
|
+
return fail("missing entity address target", {
|
|
555
|
+
component: componentName,
|
|
556
|
+
field: fieldName,
|
|
557
|
+
address: parts2
|
|
558
|
+
});
|
|
559
|
+
numeric.push(slot2);
|
|
560
|
+
}
|
|
561
|
+
out[fieldName] = remapEntityFieldValue(numeric, kind, remap);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (value === null) {
|
|
565
|
+
out[fieldName] = null;
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
const parts = addressParts(value);
|
|
569
|
+
if (parts === void 0)
|
|
570
|
+
return fail("invalid entity address", {
|
|
571
|
+
component: componentName,
|
|
572
|
+
field: fieldName,
|
|
573
|
+
address: value
|
|
574
|
+
});
|
|
575
|
+
const slot = resolveAddress(parts, `${componentName}.${fieldName}`);
|
|
576
|
+
if (slot === void 0)
|
|
577
|
+
return fail("missing entity address target", {
|
|
578
|
+
component: componentName,
|
|
579
|
+
field: fieldName,
|
|
580
|
+
address: parts
|
|
581
|
+
});
|
|
582
|
+
out[fieldName] = remapEntityFieldValue(slot, kind, remap);
|
|
583
|
+
}
|
|
584
|
+
return ok4(out);
|
|
585
|
+
}
|
|
586
|
+
function compileKeyedSceneAsset(world, handle, asset, context) {
|
|
587
|
+
asset = normalizeLegacySceneAsset(asset);
|
|
588
|
+
if (asset.kind !== "scene" || asset.entities === null || typeof asset.entities !== "object" || Array.isArray(asset.entities)) {
|
|
589
|
+
return fail("entities must be a keyed object");
|
|
590
|
+
}
|
|
591
|
+
const currentRaw = Number(handle);
|
|
592
|
+
const activeStack = context.stack.has(currentRaw) ? context.stack : /* @__PURE__ */ new Set([...context.stack, currentRaw]);
|
|
593
|
+
const keys = keyList(asset.entities);
|
|
594
|
+
if (keys.some((key) => key.length === 0)) return fail("entity keys must be non-empty");
|
|
595
|
+
const ownKeys = keys.filter((key) => asset.entities[key]?.instance === void 0);
|
|
596
|
+
const instanceKeys = keys.filter((key) => asset.entities[key]?.instance !== void 0);
|
|
597
|
+
const ownSlotByKey = /* @__PURE__ */ new Map();
|
|
598
|
+
const instanceSlotByKey = /* @__PURE__ */ new Map();
|
|
599
|
+
const keyByLocalId = /* @__PURE__ */ new Map();
|
|
600
|
+
for (let index = 0; index < ownKeys.length; index += 1) {
|
|
601
|
+
const key = ownKeys[index];
|
|
602
|
+
ownSlotByKey.set(key, index);
|
|
603
|
+
keyByLocalId.set(index, key);
|
|
604
|
+
}
|
|
605
|
+
for (let index = 0; index < instanceKeys.length; index += 1) {
|
|
606
|
+
const key = instanceKeys[index];
|
|
607
|
+
const slot = ownKeys.length + index;
|
|
608
|
+
instanceSlotByKey.set(key, slot);
|
|
609
|
+
keyByLocalId.set(slot, key);
|
|
610
|
+
}
|
|
611
|
+
const childCompiled = /* @__PURE__ */ new Map();
|
|
612
|
+
for (const key of instanceKeys) {
|
|
613
|
+
const declaration = asset.entities[key]?.instance;
|
|
614
|
+
if (declaration === void 0 || typeof declaration.source !== "string" || declaration.source.length === 0) {
|
|
615
|
+
return fail("instance source must be a non-empty GUID", { entity: key });
|
|
616
|
+
}
|
|
617
|
+
const childHandle = context.resolveSource(declaration.source, handle);
|
|
618
|
+
if (!childHandle.ok) return childHandle;
|
|
619
|
+
const childRaw = Number(childHandle.value);
|
|
620
|
+
if (activeStack.has(childRaw)) {
|
|
621
|
+
return err4({
|
|
622
|
+
code: "pack-cyclic-reference",
|
|
623
|
+
expected: "acyclic SceneAsset instance graph",
|
|
624
|
+
hint: PACK_ERROR_HINTS["pack-cyclic-reference"],
|
|
625
|
+
detail: {
|
|
626
|
+
code: "pack-cyclic-reference",
|
|
627
|
+
kind: "mount-asset",
|
|
628
|
+
cycle: [...activeStack, childRaw].map(String)
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
const childAsset = context.resolveAsset(childHandle.value);
|
|
633
|
+
if (!childAsset.ok) return childAsset;
|
|
634
|
+
const childContext = {
|
|
635
|
+
...context,
|
|
636
|
+
stack: activeStack
|
|
637
|
+
};
|
|
638
|
+
const compiled = compileKeyedSceneAsset(
|
|
639
|
+
world,
|
|
640
|
+
childHandle.value,
|
|
641
|
+
childAsset.value,
|
|
642
|
+
childContext
|
|
643
|
+
);
|
|
644
|
+
if (!compiled.ok) return compiled;
|
|
645
|
+
childCompiled.set(key, { handle: childHandle.value, compiled: compiled.value });
|
|
646
|
+
}
|
|
647
|
+
const mountKeyByLocalId = /* @__PURE__ */ new Map();
|
|
648
|
+
const mounts = [];
|
|
649
|
+
let nextMemberFirst = ownKeys.length + instanceKeys.length;
|
|
650
|
+
for (let index = 0; index < instanceKeys.length; index += 1) {
|
|
651
|
+
const key = instanceKeys[index];
|
|
652
|
+
const slot = instanceSlotByKey.get(key);
|
|
653
|
+
const child = childCompiled.get(key);
|
|
654
|
+
const node = asset.entities[key];
|
|
655
|
+
mountKeyByLocalId.set(slot, key);
|
|
656
|
+
mounts.push({
|
|
657
|
+
localId: slot,
|
|
658
|
+
source: Number(child.handle),
|
|
659
|
+
memberFirst: nextMemberFirst,
|
|
660
|
+
memberCount: child.compiled.asset.entities.length + (child.compiled.asset.mounts?.length ?? 0) + (child.compiled.asset.mounts ?? []).reduce((sum, mount) => sum + mount.memberCount, 0),
|
|
661
|
+
...Object.keys(node.components).length > 0 ? { components: node.components } : {}
|
|
662
|
+
});
|
|
663
|
+
nextMemberFirst += mounts[index]?.memberCount ?? 0;
|
|
664
|
+
}
|
|
665
|
+
const mountByKey = /* @__PURE__ */ new Map();
|
|
666
|
+
for (const mount of mounts)
|
|
667
|
+
mountByKey.set(mountKeyByLocalId.get(Number(mount.localId)), mount);
|
|
668
|
+
const resolveInChild = (childResult, value, _field) => {
|
|
669
|
+
const parts = addressParts(value);
|
|
670
|
+
if (parts === void 0) return void 0;
|
|
671
|
+
return childResult.resolveAddress(parts);
|
|
672
|
+
};
|
|
673
|
+
const resolveAddress = (value, field) => {
|
|
674
|
+
const parts = addressParts(value);
|
|
675
|
+
if (parts === void 0) return void 0;
|
|
676
|
+
const first = parts[0];
|
|
677
|
+
if (first === void 0) return void 0;
|
|
678
|
+
const own = ownSlotByKey.get(first) ?? instanceSlotByKey.get(first);
|
|
679
|
+
if (own !== void 0 && parts.length === 1) return own;
|
|
680
|
+
const mount = mountByKey.get(first);
|
|
681
|
+
if (mount === void 0) return void 0;
|
|
682
|
+
const child = childCompiled.get(first);
|
|
683
|
+
if (child === void 0) return void 0;
|
|
684
|
+
const childSlot = resolveInChild(child.compiled, parts.slice(1), field);
|
|
685
|
+
return childSlot === void 0 ? void 0 : mount.memberFirst + childSlot;
|
|
686
|
+
};
|
|
687
|
+
for (const key of instanceKeys) {
|
|
688
|
+
const node = asset.entities[key];
|
|
689
|
+
const mount = mountByKey.get(key);
|
|
690
|
+
const convertedFields = Object.fromEntries(
|
|
691
|
+
Object.entries(node.components).map(([componentName, raw]) => [
|
|
692
|
+
componentName,
|
|
693
|
+
fieldRemap(
|
|
694
|
+
world,
|
|
695
|
+
componentName,
|
|
696
|
+
{ ...raw },
|
|
697
|
+
resolveAddress,
|
|
698
|
+
key
|
|
699
|
+
)
|
|
700
|
+
])
|
|
701
|
+
);
|
|
702
|
+
const bad = Object.values(convertedFields).find((result) => !result.ok);
|
|
703
|
+
if (bad !== void 0 && !bad.ok) return bad;
|
|
704
|
+
const components = {};
|
|
705
|
+
for (const [componentName, result] of Object.entries(convertedFields)) {
|
|
706
|
+
if (!result.ok) return result;
|
|
707
|
+
components[componentName] = result.value;
|
|
708
|
+
}
|
|
709
|
+
const index = mounts.findIndex((item) => item.localId === mount.localId);
|
|
710
|
+
if (index >= 0) {
|
|
711
|
+
const childOf = components.ChildOf?.parent;
|
|
712
|
+
if (typeof childOf === "number") {
|
|
713
|
+
const { ChildOf: _ignored, ...mountComponents } = components;
|
|
714
|
+
void _ignored;
|
|
715
|
+
mounts[index] = { ...mount, components: mountComponents, parent: childOf };
|
|
716
|
+
} else {
|
|
717
|
+
mounts[index] = { ...mount, components };
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
const converted = [];
|
|
722
|
+
for (const key of ownKeys) {
|
|
723
|
+
const node = asset.entities[key];
|
|
724
|
+
const components = {};
|
|
725
|
+
for (const [componentName, raw] of Object.entries(node.components)) {
|
|
726
|
+
const convertedFields = fieldRemap(
|
|
727
|
+
world,
|
|
728
|
+
componentName,
|
|
729
|
+
{ ...raw },
|
|
730
|
+
resolveAddress,
|
|
731
|
+
key
|
|
732
|
+
);
|
|
733
|
+
if (!convertedFields.ok) return convertedFields;
|
|
734
|
+
components[componentName] = convertedFields.value;
|
|
735
|
+
}
|
|
736
|
+
converted.push({ localId: ownSlotByKey.get(key), components });
|
|
737
|
+
}
|
|
738
|
+
const childHasComponent = (result, target, componentName) => {
|
|
739
|
+
const own = result.asset.entities.find((entity) => Number(entity.localId) === target);
|
|
740
|
+
if (own !== void 0 && own.components[componentName] !== void 0) return true;
|
|
741
|
+
const mount = result.asset.mounts?.find((entry) => Number(entry.localId) === target);
|
|
742
|
+
return mount?.components?.[componentName] !== void 0;
|
|
743
|
+
};
|
|
744
|
+
for (const key of instanceKeys) {
|
|
745
|
+
const node = asset.entities[key];
|
|
746
|
+
const declaration = node.instance;
|
|
747
|
+
const mount = mountByKey.get(key);
|
|
748
|
+
const child = childCompiled.get(key);
|
|
749
|
+
const childSlot = (target) => resolveInChild(child.compiled, target, `${key}.instance`);
|
|
750
|
+
const overrides = [];
|
|
751
|
+
for (const override of declaration.overrides ?? []) {
|
|
752
|
+
const target = childSlot(override.target);
|
|
753
|
+
if (target === void 0)
|
|
754
|
+
return fail("instance override target does not exist", {
|
|
755
|
+
entity: key,
|
|
756
|
+
target: override.target
|
|
757
|
+
});
|
|
758
|
+
for (const [componentName, fields] of Object.entries(override.components)) {
|
|
759
|
+
const convertedFields = fieldRemap(
|
|
760
|
+
world,
|
|
761
|
+
componentName,
|
|
762
|
+
{ ...fields },
|
|
763
|
+
resolveAddress,
|
|
764
|
+
`${key}.instance.${override.target.join(".")}`
|
|
765
|
+
);
|
|
766
|
+
if (!convertedFields.ok) return convertedFields;
|
|
767
|
+
if (!childHasComponent(child.compiled, target, componentName)) {
|
|
768
|
+
overrides.push({
|
|
769
|
+
localId: mount.memberFirst + target,
|
|
770
|
+
comp: componentName,
|
|
771
|
+
value: convertedFields.value
|
|
772
|
+
});
|
|
773
|
+
} else {
|
|
774
|
+
overrides.push(
|
|
775
|
+
...Object.entries(convertedFields.value).map(([field, value]) => ({
|
|
776
|
+
localId: mount.memberFirst + target,
|
|
777
|
+
comp: componentName,
|
|
778
|
+
field,
|
|
779
|
+
value
|
|
780
|
+
}))
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
if (overrides.length > 0) {
|
|
786
|
+
const index = mounts.findIndex((item) => item.localId === mount.localId);
|
|
787
|
+
const existing = mounts[index];
|
|
788
|
+
if (index >= 0 && existing !== void 0) mounts[index] = { ...existing, overrides };
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
const rootLocalIds = [
|
|
792
|
+
...convertedRootLocalIds(converted),
|
|
793
|
+
...mounts.filter((mount) => mount.parent === void 0).map((mount) => Number(mount.localId))
|
|
794
|
+
];
|
|
795
|
+
const hierarchyParentByLocalId = /* @__PURE__ */ new Map();
|
|
796
|
+
for (const node of converted) {
|
|
797
|
+
const parent = node.components.ChildOf?.parent;
|
|
798
|
+
if (typeof parent === "number" && parent >= 0) {
|
|
799
|
+
hierarchyParentByLocalId.set(Number(node.localId), parent);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
for (const mount of mounts) {
|
|
803
|
+
if (mount.parent !== void 0) {
|
|
804
|
+
hierarchyParentByLocalId.set(Number(mount.localId), mount.parent);
|
|
805
|
+
}
|
|
806
|
+
const key = mountKeyByLocalId.get(Number(mount.localId));
|
|
807
|
+
const child = key === void 0 ? void 0 : childCompiled.get(key);
|
|
808
|
+
if (child !== void 0) {
|
|
809
|
+
for (const [childLocalId, childParent] of child.compiled.hierarchyParentByLocalId) {
|
|
810
|
+
hierarchyParentByLocalId.set(
|
|
811
|
+
Number(mount.memberFirst) + childLocalId,
|
|
812
|
+
Number(mount.memberFirst) + childParent
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
for (const childRoot of child.compiled.rootLocalIds) {
|
|
816
|
+
hierarchyParentByLocalId.set(Number(mount.memberFirst) + childRoot, Number(mount.localId));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
for (const override of mount.overrides ?? []) {
|
|
820
|
+
if (override.comp !== "ChildOf") continue;
|
|
821
|
+
if (override.field === "parent" && typeof override.value === "number") {
|
|
822
|
+
hierarchyParentByLocalId.set(Number(override.localId), override.value);
|
|
823
|
+
} else if (override.field === void 0 && typeof override.value === "object" && override.value !== null) {
|
|
824
|
+
const parentValue = override.value.parent;
|
|
825
|
+
if (typeof parentValue === "number") {
|
|
826
|
+
hierarchyParentByLocalId.set(Number(override.localId), parentValue);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
for (const start of hierarchyParentByLocalId.keys()) {
|
|
832
|
+
const seen = /* @__PURE__ */ new Set();
|
|
833
|
+
let current = start;
|
|
834
|
+
while (current !== void 0 && hierarchyParentByLocalId.has(current)) {
|
|
835
|
+
if (seen.has(current))
|
|
836
|
+
return fail("hierarchy cycle", { entity: keyByLocalId.get(start), address: [...seen] });
|
|
837
|
+
seen.add(current);
|
|
838
|
+
current = hierarchyParentByLocalId.get(current);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return ok4({
|
|
842
|
+
asset: {
|
|
843
|
+
kind: "scene",
|
|
844
|
+
entities: converted,
|
|
845
|
+
...mounts.length > 0 ? { mounts } : {},
|
|
846
|
+
...asset.skinGuids === void 0 ? {} : { skinGuids: asset.skinGuids }
|
|
847
|
+
},
|
|
848
|
+
keyByLocalId,
|
|
849
|
+
mountKeyByLocalId,
|
|
850
|
+
rootLocalIds,
|
|
851
|
+
hierarchyParentByLocalId,
|
|
852
|
+
resolveAddress
|
|
346
853
|
});
|
|
347
854
|
}
|
|
855
|
+
function convertedRootLocalIds(nodes) {
|
|
856
|
+
return nodes.filter((node) => node.components.ChildOf === void 0).map((node) => Number(node.localId));
|
|
857
|
+
}
|
|
348
858
|
|
|
349
859
|
// src/instances/scene-instances.ts
|
|
350
860
|
import {
|
|
351
861
|
ENTITY_NULL_RAW
|
|
352
862
|
} from "@forgeax/engine-ecs";
|
|
353
|
-
import { classifyEntityField, remapEntityFieldValue } from "@forgeax/engine-ecs/externalization";
|
|
354
|
-
import { componentSchema } from "@forgeax/engine-ecs/internal";
|
|
863
|
+
import { classifyEntityField as classifyEntityField2, remapEntityFieldValue as remapEntityFieldValue2 } from "@forgeax/engine-ecs/externalization";
|
|
864
|
+
import { componentSchema as componentSchema2 } from "@forgeax/engine-ecs/internal";
|
|
355
865
|
import { fillComponentDefaults, StaleEntityError } from "@forgeax/engine-ecs/projection";
|
|
356
866
|
import {
|
|
357
|
-
err as
|
|
358
|
-
ok as
|
|
359
|
-
PACK_ERROR_HINTS,
|
|
867
|
+
err as err5,
|
|
868
|
+
ok as ok5,
|
|
869
|
+
PACK_ERROR_HINTS as PACK_ERROR_HINTS2,
|
|
360
870
|
toUnique,
|
|
361
871
|
unwrapHandle
|
|
362
872
|
} from "@forgeax/engine-types";
|
|
@@ -388,18 +898,50 @@ function primitiveJsType(fieldType) {
|
|
|
388
898
|
// src/instances/scene-instances.ts
|
|
389
899
|
var entityIndex = (entity) => entity & 16777215;
|
|
390
900
|
var entityGeneration = (entity) => entity >>> 24 & 255;
|
|
901
|
+
function collectSceneEntityBindings(world, root, prefix, bindings, visited = /* @__PURE__ */ new Set()) {
|
|
902
|
+
const rootRaw = root;
|
|
903
|
+
if (visited.has(rootRaw)) return;
|
|
904
|
+
visited.add(rootRaw);
|
|
905
|
+
const state = worldResolveSceneInstanceStatePayload(world, root);
|
|
906
|
+
if (!state.ok) return;
|
|
907
|
+
const sceneInstance = world.components.resolve("SceneInstance");
|
|
908
|
+
if (sceneInstance === void 0) return;
|
|
909
|
+
const component = world.get(root, sceneInstance);
|
|
910
|
+
if (!component.ok) return;
|
|
911
|
+
const mapping = component.value.mapping;
|
|
912
|
+
for (const [slot, key] of state.value.keyByLocalId) {
|
|
913
|
+
const raw = mapping[slot];
|
|
914
|
+
if (raw === void 0 || raw === ENTITY_NULL_RAW) continue;
|
|
915
|
+
const address = prefix.length === 0 ? key : [...prefix, key];
|
|
916
|
+
bindings.set(sceneEntityAddressKey(address), raw);
|
|
917
|
+
}
|
|
918
|
+
for (const childRoot of state.value.mountRoots) {
|
|
919
|
+
const childState = worldResolveSceneInstanceStatePayload(world, childRoot);
|
|
920
|
+
const childKey = childState.ok ? childState.value.instanceKey : void 0;
|
|
921
|
+
if (childKey === void 0) continue;
|
|
922
|
+
collectSceneEntityBindings(world, childRoot, [...prefix, childKey], bindings, visited);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
391
925
|
function worldSetSceneAssetResolver(world, resolver) {
|
|
392
926
|
sceneWorldState(world).resolver = resolver;
|
|
393
927
|
}
|
|
394
928
|
function worldGetSceneAssetResolver(world) {
|
|
395
929
|
return sceneWorldState(world).resolver;
|
|
396
930
|
}
|
|
397
|
-
function worldInstantiateScene(world, handle, parent) {
|
|
931
|
+
function worldInstantiateScene(world, handle, parent, sceneSourceKey) {
|
|
398
932
|
const stack = /* @__PURE__ */ new Set();
|
|
399
933
|
const diagnostics = [];
|
|
400
|
-
const r = worldInstantiateSceneRec(
|
|
934
|
+
const r = worldInstantiateSceneRec(
|
|
935
|
+
world,
|
|
936
|
+
handle,
|
|
937
|
+
parent,
|
|
938
|
+
stack,
|
|
939
|
+
diagnostics,
|
|
940
|
+
void 0,
|
|
941
|
+
sceneSourceKey
|
|
942
|
+
);
|
|
401
943
|
if (!r.ok) return r;
|
|
402
|
-
return
|
|
944
|
+
return ok5({ root: r.value, diagnostics });
|
|
403
945
|
}
|
|
404
946
|
function worldInstantiateScenePayload(world, asset, parent) {
|
|
405
947
|
const handle = world.allocSharedRef("SceneAsset", asset);
|
|
@@ -423,9 +965,9 @@ function worldInstantiateSceneFlat(world, handle) {
|
|
|
423
965
|
stack.delete(handleKey);
|
|
424
966
|
}
|
|
425
967
|
if (!r.ok) return r;
|
|
426
|
-
return
|
|
968
|
+
return ok5({ ...r.value, diagnostics });
|
|
427
969
|
}
|
|
428
|
-
function worldInstantiateSceneRec(world, handle, parent, stack, diagnostics) {
|
|
970
|
+
function worldInstantiateSceneRec(world, handle, parent, stack, diagnostics, instanceKey, sceneSourceKey) {
|
|
429
971
|
const handleKey = unwrapHandle(handle);
|
|
430
972
|
if (stack.has(handleKey)) {
|
|
431
973
|
const cycleArr = [];
|
|
@@ -436,10 +978,10 @@ function worldInstantiateSceneRec(world, handle, parent, stack, diagnostics) {
|
|
|
436
978
|
kind: "mount-asset",
|
|
437
979
|
cycle: cycleArr
|
|
438
980
|
};
|
|
439
|
-
return
|
|
981
|
+
return err5({
|
|
440
982
|
code: "pack-cyclic-reference",
|
|
441
983
|
expected: "acyclic SceneAsset mount graph",
|
|
442
|
-
hint:
|
|
984
|
+
hint: PACK_ERROR_HINTS2["pack-cyclic-reference"],
|
|
443
985
|
detail
|
|
444
986
|
});
|
|
445
987
|
}
|
|
@@ -448,7 +990,16 @@ function worldInstantiateSceneRec(world, handle, parent, stack, diagnostics) {
|
|
|
448
990
|
const asset = resolved.value;
|
|
449
991
|
stack.add(handleKey);
|
|
450
992
|
try {
|
|
451
|
-
return worldInstantiateSceneAsset(
|
|
993
|
+
return worldInstantiateSceneAsset(
|
|
994
|
+
world,
|
|
995
|
+
handle,
|
|
996
|
+
asset,
|
|
997
|
+
parent,
|
|
998
|
+
stack,
|
|
999
|
+
diagnostics,
|
|
1000
|
+
instanceKey,
|
|
1001
|
+
sceneSourceKey
|
|
1002
|
+
);
|
|
452
1003
|
} finally {
|
|
453
1004
|
stack.delete(handleKey);
|
|
454
1005
|
}
|
|
@@ -456,27 +1007,18 @@ function worldInstantiateSceneRec(world, handle, parent, stack, diagnostics) {
|
|
|
456
1007
|
function worldResolveSceneAsset(world, handle) {
|
|
457
1008
|
const r = world.sharedRefs.resolve(handle);
|
|
458
1009
|
if (!r.ok) {
|
|
459
|
-
return
|
|
1010
|
+
return err5(r.error);
|
|
460
1011
|
}
|
|
461
|
-
return
|
|
1012
|
+
return ok5(r.value);
|
|
462
1013
|
}
|
|
463
|
-
function worldSpawnSceneMembers(world, handle, asset, stack, diagnostics) {
|
|
1014
|
+
function worldSpawnSceneMembers(world, handle, asset, stack, diagnostics, mountKeys) {
|
|
464
1015
|
const sceneInstanceToken = world.components.resolve("SceneInstance");
|
|
465
1016
|
if (sceneInstanceToken === void 0) {
|
|
466
|
-
return
|
|
1017
|
+
return err5(new ComponentNotDefinedError("SceneInstance"));
|
|
467
1018
|
}
|
|
468
1019
|
const childOfToken = world.components.resolve("ChildOf");
|
|
469
1020
|
const ownEntities = asset.entities;
|
|
470
1021
|
const ownMounts = asset.mounts ?? [];
|
|
471
|
-
const bindingKeys = ownEntities.flatMap(
|
|
472
|
-
(entity) => entity.bindingKey === void 0 ? [] : [entity.bindingKey]
|
|
473
|
-
);
|
|
474
|
-
if (bindingKeys.length > 0) {
|
|
475
|
-
const bindingCheck = validateSceneBindings(asset.sourceKey ?? "", bindingKeys);
|
|
476
|
-
if (!bindingCheck.ok) {
|
|
477
|
-
return err4(bindingCheck.error);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
1022
|
const memberSum = ownMounts.reduce((s, m) => s + m.memberCount, 0);
|
|
481
1023
|
const countBaseline = ownEntities.length + ownMounts.length + memberSum;
|
|
482
1024
|
let maxLocalId = ownEntities.reduce((m, e) => Math.max(m, e.localId), -1);
|
|
@@ -517,10 +1059,10 @@ function worldSpawnSceneMembers(world, handle, asset, stack, diagnostics) {
|
|
|
517
1059
|
}
|
|
518
1060
|
if (overlapLids.size > 0) {
|
|
519
1061
|
const overlapping = Array.from(overlapLids).sort((a, b) => a - b);
|
|
520
|
-
return
|
|
1062
|
+
return err5({
|
|
521
1063
|
code: "pack-mount-localid-overlap",
|
|
522
1064
|
expected: "each LocalEntityId claimed by exactly one entity or mount slot",
|
|
523
|
-
hint:
|
|
1065
|
+
hint: PACK_ERROR_HINTS2["pack-mount-localid-overlap"],
|
|
524
1066
|
detail: {
|
|
525
1067
|
code: "pack-mount-localid-overlap",
|
|
526
1068
|
overlapping,
|
|
@@ -550,17 +1092,29 @@ function worldSpawnSceneMembers(world, handle, asset, stack, diagnostics) {
|
|
|
550
1092
|
const childHandleRes = worldResolveMountSource(world, mount.source, handle);
|
|
551
1093
|
if (!childHandleRes.ok) return childHandleRes;
|
|
552
1094
|
const childHandle = childHandleRes.value;
|
|
553
|
-
const childRes = worldInstantiateSceneRec(
|
|
1095
|
+
const childRes = worldInstantiateSceneRec(
|
|
1096
|
+
world,
|
|
1097
|
+
childHandle,
|
|
1098
|
+
mountEntity,
|
|
1099
|
+
stack,
|
|
1100
|
+
diagnostics,
|
|
1101
|
+
mountKeys?.get(mountLid)
|
|
1102
|
+
);
|
|
554
1103
|
if (!childRes.ok) return childRes;
|
|
555
1104
|
const childInstRes = world.get(childRes.value, sceneInstanceToken);
|
|
556
1105
|
if (!childInstRes.ok) return childInstRes;
|
|
557
1106
|
const childMapping = childInstRes.value.mapping;
|
|
558
|
-
mountInstances.push({
|
|
1107
|
+
mountInstances.push({
|
|
1108
|
+
mount,
|
|
1109
|
+
root: childRes.value,
|
|
1110
|
+
mapping: childMapping,
|
|
1111
|
+
...mountKeys?.get(mountLid) === void 0 ? {} : { key: mountKeys.get(mountLid) }
|
|
1112
|
+
});
|
|
559
1113
|
if (childMapping.length !== mount.memberCount) {
|
|
560
|
-
return
|
|
1114
|
+
return err5({
|
|
561
1115
|
code: "pack-mount-count-mismatch",
|
|
562
1116
|
expected: "mount.memberCount === child SceneAsset totalSlots",
|
|
563
|
-
hint:
|
|
1117
|
+
hint: PACK_ERROR_HINTS2["pack-mount-count-mismatch"],
|
|
564
1118
|
detail: {
|
|
565
1119
|
code: "pack-mount-count-mismatch",
|
|
566
1120
|
mountLocalId: mountLid,
|
|
@@ -628,7 +1182,7 @@ function worldSpawnSceneMembers(world, handle, asset, stack, diagnostics) {
|
|
|
628
1182
|
}
|
|
629
1183
|
}
|
|
630
1184
|
}
|
|
631
|
-
return
|
|
1185
|
+
return ok5({
|
|
632
1186
|
mapping,
|
|
633
1187
|
entityToLocalId,
|
|
634
1188
|
rootEntities,
|
|
@@ -638,17 +1192,31 @@ function worldSpawnSceneMembers(world, handle, asset, stack, diagnostics) {
|
|
|
638
1192
|
totalSlots
|
|
639
1193
|
});
|
|
640
1194
|
}
|
|
641
|
-
function worldInstantiateSceneAsset(world, handle, asset, parent, stack, diagnostics) {
|
|
1195
|
+
function worldInstantiateSceneAsset(world, handle, asset, parent, stack, diagnostics, instanceKey, sceneSourceKey) {
|
|
642
1196
|
const sceneInstanceToken = world.components.resolve("SceneInstance");
|
|
643
1197
|
if (sceneInstanceToken === void 0) {
|
|
644
|
-
return
|
|
1198
|
+
return err5(new ComponentNotDefinedError("SceneInstance"));
|
|
645
1199
|
}
|
|
646
1200
|
const childOfToken = world.components.resolve("ChildOf");
|
|
647
|
-
const
|
|
1201
|
+
const compiled = compileKeyedSceneAsset(world, handle, asset, {
|
|
1202
|
+
resolveSource: (source, parentHandle) => worldResolveMountSource(world, source, parentHandle),
|
|
1203
|
+
resolveAsset: (childHandle) => worldResolveSceneAsset(world, childHandle),
|
|
1204
|
+
stack
|
|
1205
|
+
});
|
|
1206
|
+
if (!compiled.ok) return err5(compiled.error);
|
|
1207
|
+
const compiledAsset = compiled.value.asset;
|
|
1208
|
+
const membersRes = worldSpawnSceneMembers(
|
|
1209
|
+
world,
|
|
1210
|
+
handle,
|
|
1211
|
+
compiledAsset,
|
|
1212
|
+
stack,
|
|
1213
|
+
diagnostics,
|
|
1214
|
+
compiled.value.mountKeyByLocalId
|
|
1215
|
+
);
|
|
648
1216
|
if (!membersRes.ok) return membersRes;
|
|
649
1217
|
const { mapping, entityToLocalId, rootEntities, mountEntitiesNeedingRootParent, totalSlots } = membersRes.value;
|
|
650
1218
|
const { mountInstances } = membersRes.value;
|
|
651
|
-
const ownMounts =
|
|
1219
|
+
const ownMounts = compiledAsset.mounts ?? [];
|
|
652
1220
|
let stateRef;
|
|
653
1221
|
stateRef = world.allocUniqueRef("SceneInstanceState", null, () => {
|
|
654
1222
|
sceneWorldState(world).statePayloads.delete(Number(stateRef));
|
|
@@ -691,7 +1259,11 @@ function worldInstantiateSceneAsset(world, handle, asset, parent, stack, diagnos
|
|
|
691
1259
|
const memberEntityRaw = mapping[lid];
|
|
692
1260
|
if (memberEntityRaw !== void 0 && memberEntityRaw !== ENTITY_NULL_RAW) {
|
|
693
1261
|
const memberEntity = memberEntityRaw;
|
|
694
|
-
const applyRes = worldApplyMountOverride(
|
|
1262
|
+
const applyRes = worldApplyMountOverride(
|
|
1263
|
+
world,
|
|
1264
|
+
memberEntity,
|
|
1265
|
+
worldRemapMountOverride(world, ov, mapping)
|
|
1266
|
+
);
|
|
695
1267
|
if (!applyRes.ok) {
|
|
696
1268
|
return applyRes;
|
|
697
1269
|
}
|
|
@@ -700,16 +1272,11 @@ function worldInstantiateSceneAsset(world, handle, asset, parent, stack, diagnos
|
|
|
700
1272
|
}
|
|
701
1273
|
const detached = /* @__PURE__ */ new Set();
|
|
702
1274
|
const bindings = /* @__PURE__ */ new Map();
|
|
703
|
-
for (const entity of asset.entities) {
|
|
704
|
-
if (entity.bindingKey === void 0) continue;
|
|
705
|
-
const live = mapping[entity.localId];
|
|
706
|
-
if (live !== void 0 && live !== ENTITY_NULL_RAW) {
|
|
707
|
-
bindings.set(entity.bindingKey, live);
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
1275
|
const state = {
|
|
711
1276
|
source: handle,
|
|
712
|
-
sceneSourceKey:
|
|
1277
|
+
...sceneSourceKey === void 0 ? {} : { sceneSourceKey },
|
|
1278
|
+
keyByLocalId: new Map(compiled.value.keyByLocalId),
|
|
1279
|
+
...instanceKey === void 0 ? {} : { instanceKey },
|
|
713
1280
|
bindings,
|
|
714
1281
|
entityToLocalId,
|
|
715
1282
|
detachedLocalIds: detached,
|
|
@@ -722,6 +1289,7 @@ function worldInstantiateSceneAsset(world, handle, asset, parent, stack, diagnos
|
|
|
722
1289
|
mountTimeOverrides: ownMounts.flatMap((m) => m.overrides ?? [])
|
|
723
1290
|
};
|
|
724
1291
|
worldSetUniqueRefPayload(world, stateRef, state);
|
|
1292
|
+
collectSceneEntityBindings(world, rootEntity, [], bindings);
|
|
725
1293
|
if (childOfToken !== void 0) {
|
|
726
1294
|
for (const rootE of rootEntities) {
|
|
727
1295
|
const has = world.get(rootE, childOfToken);
|
|
@@ -751,10 +1319,23 @@ function worldInstantiateSceneAsset(world, handle, asset, parent, stack, diagnos
|
|
|
751
1319
|
if (!r.ok) return r;
|
|
752
1320
|
}
|
|
753
1321
|
}
|
|
754
|
-
return
|
|
1322
|
+
return ok5(rootEntity);
|
|
755
1323
|
}
|
|
756
1324
|
function worldInstantiateSceneAssetFlat(world, handle, asset, stack, diagnostics) {
|
|
757
|
-
const
|
|
1325
|
+
const compiled = compileKeyedSceneAsset(world, handle, asset, {
|
|
1326
|
+
resolveSource: (source, parentHandle) => worldResolveMountSource(world, source, parentHandle),
|
|
1327
|
+
resolveAsset: (childHandle) => worldResolveSceneAsset(world, childHandle),
|
|
1328
|
+
stack
|
|
1329
|
+
});
|
|
1330
|
+
if (!compiled.ok) return err5(compiled.error);
|
|
1331
|
+
const membersRes = worldSpawnSceneMembers(
|
|
1332
|
+
world,
|
|
1333
|
+
handle,
|
|
1334
|
+
compiled.value.asset,
|
|
1335
|
+
stack,
|
|
1336
|
+
diagnostics,
|
|
1337
|
+
compiled.value.mountKeyByLocalId
|
|
1338
|
+
);
|
|
758
1339
|
if (!membersRes.ok) return membersRes;
|
|
759
1340
|
const { rootEntities, mountEntitiesNeedingRootParent, mountEntities, mountInstances } = membersRes.value;
|
|
760
1341
|
const childOfToken = world.components.resolve("ChildOf");
|
|
@@ -766,7 +1347,11 @@ function worldInstantiateSceneAssetFlat(world, handle, asset, stack, diagnostics
|
|
|
766
1347
|
const memberEntityRaw = childMapping[childLocalId];
|
|
767
1348
|
if (memberEntityRaw === void 0 || memberEntityRaw === ENTITY_NULL_RAW) continue;
|
|
768
1349
|
const memberEntity = memberEntityRaw;
|
|
769
|
-
const applyRes = worldApplyMountOverride(
|
|
1350
|
+
const applyRes = worldApplyMountOverride(
|
|
1351
|
+
world,
|
|
1352
|
+
memberEntity,
|
|
1353
|
+
worldRemapMountOverride(world, ov, childMapping)
|
|
1354
|
+
);
|
|
770
1355
|
if (!applyRes.ok) {
|
|
771
1356
|
return applyRes;
|
|
772
1357
|
}
|
|
@@ -790,34 +1375,43 @@ function worldInstantiateSceneAssetFlat(world, handle, asset, stack, diagnostics
|
|
|
790
1375
|
}
|
|
791
1376
|
}
|
|
792
1377
|
}
|
|
793
|
-
return
|
|
1378
|
+
return ok5({ roots: [...rootEntities, ...mountEntitiesNeedingRootParent], mountEntities });
|
|
794
1379
|
}
|
|
795
|
-
function worldBuildSceneEntityComponentDatas(world, node, mapping,
|
|
1380
|
+
function worldBuildSceneEntityComponentDatas(world, node, mapping, _diagnostics) {
|
|
796
1381
|
const out = [];
|
|
797
1382
|
const nodeLocalId = node.localId;
|
|
798
1383
|
for (const compName of Object.keys(node.components)) {
|
|
799
1384
|
const token = world.components.resolve(compName);
|
|
800
1385
|
if (token === void 0) {
|
|
801
|
-
return
|
|
1386
|
+
return err5(new ComponentNotDefinedError(compName));
|
|
802
1387
|
}
|
|
803
1388
|
const raw = node.components[compName] ?? {};
|
|
804
|
-
const schema =
|
|
1389
|
+
const schema = componentSchema2(token);
|
|
805
1390
|
const remappedRaw = {};
|
|
806
1391
|
for (const fieldName of Object.keys(raw)) {
|
|
807
1392
|
const fieldType = schema[fieldName];
|
|
808
1393
|
if (fieldType === void 0) {
|
|
809
|
-
|
|
810
|
-
|
|
1394
|
+
return err5({
|
|
1395
|
+
code: "spawn-data-unknown-field",
|
|
1396
|
+
expected: `field name in {${Object.keys(schema).sort().join(", ")}}`,
|
|
1397
|
+
hint: `unknown field '${fieldName}' on component '${compName}' at scene localId ${nodeLocalId}`,
|
|
1398
|
+
detail: {
|
|
1399
|
+
component: compName,
|
|
1400
|
+
field: fieldName,
|
|
1401
|
+
entity: nodeLocalId,
|
|
1402
|
+
knownFields: Object.keys(schema).sort()
|
|
1403
|
+
}
|
|
1404
|
+
});
|
|
811
1405
|
}
|
|
812
1406
|
const value = raw[fieldName];
|
|
813
|
-
const kind =
|
|
1407
|
+
const kind = classifyEntityField2(token, fieldName);
|
|
814
1408
|
if (kind !== null) {
|
|
815
1409
|
const sceneRemap = (localId) => {
|
|
816
1410
|
if (localId < 0 || localId >= mapping.length) return ENTITY_NULL_RAW;
|
|
817
1411
|
const live = mapping[localId];
|
|
818
1412
|
return live === void 0 || live === ENTITY_NULL_RAW ? ENTITY_NULL_RAW : live;
|
|
819
1413
|
};
|
|
820
|
-
remappedRaw[fieldName] =
|
|
1414
|
+
remappedRaw[fieldName] = remapEntityFieldValue2(value, kind, sceneRemap);
|
|
821
1415
|
} else {
|
|
822
1416
|
remappedRaw[fieldName] = value;
|
|
823
1417
|
}
|
|
@@ -825,11 +1419,35 @@ function worldBuildSceneEntityComponentDatas(world, node, mapping, diagnostics)
|
|
|
825
1419
|
const filled = fillComponentDefaults(token, remappedRaw);
|
|
826
1420
|
out.push({ component: token, data: filled });
|
|
827
1421
|
}
|
|
828
|
-
return
|
|
1422
|
+
return ok5(out);
|
|
1423
|
+
}
|
|
1424
|
+
function worldRemapMountOverride(world, override, mapping) {
|
|
1425
|
+
const token = world.components.resolve(override.comp);
|
|
1426
|
+
if (token === void 0) return override;
|
|
1427
|
+
const remapField = (field, value2) => {
|
|
1428
|
+
const kind = classifyEntityField2(token, field);
|
|
1429
|
+
if (kind === null) return value2;
|
|
1430
|
+
const toLive = (slot) => {
|
|
1431
|
+
if (slot < 0 || slot >= mapping.length) return ENTITY_NULL_RAW;
|
|
1432
|
+
return mapping[slot] ?? ENTITY_NULL_RAW;
|
|
1433
|
+
};
|
|
1434
|
+
return remapEntityFieldValue2(value2, kind, toLive);
|
|
1435
|
+
};
|
|
1436
|
+
if (override.field !== void 0) {
|
|
1437
|
+
return { ...override, value: remapField(override.field, override.value) };
|
|
1438
|
+
}
|
|
1439
|
+
if (typeof override.value !== "object" || override.value === null || Array.isArray(override.value)) {
|
|
1440
|
+
return override;
|
|
1441
|
+
}
|
|
1442
|
+
const value = {};
|
|
1443
|
+
for (const [field, fieldValue] of Object.entries(override.value)) {
|
|
1444
|
+
value[field] = remapField(field, fieldValue);
|
|
1445
|
+
}
|
|
1446
|
+
return { ...override, value };
|
|
829
1447
|
}
|
|
830
1448
|
function worldApplyMountOverride(world, member, ov) {
|
|
831
1449
|
const ovToken = world.components.resolve(ov.comp);
|
|
832
|
-
if (ovToken === void 0) return
|
|
1450
|
+
if (ovToken === void 0) return ok5(void 0);
|
|
833
1451
|
if (ov.field !== void 0) {
|
|
834
1452
|
return world.set(member, ovToken, { [ov.field]: ov.value });
|
|
835
1453
|
}
|
|
@@ -843,7 +1461,7 @@ function worldApplyMountOverride(world, member, ov) {
|
|
|
843
1461
|
}
|
|
844
1462
|
function worldValidateMountOverrides(world, mount) {
|
|
845
1463
|
const overrides = mount.overrides;
|
|
846
|
-
if (overrides === void 0) return
|
|
1464
|
+
if (overrides === void 0) return ok5(void 0);
|
|
847
1465
|
const memberFirst = mount.memberFirst;
|
|
848
1466
|
const memberCount = mount.memberCount;
|
|
849
1467
|
const memberLast = memberFirst + memberCount;
|
|
@@ -851,10 +1469,10 @@ function worldValidateMountOverrides(world, mount) {
|
|
|
851
1469
|
for (const ov of overrides) {
|
|
852
1470
|
const ovLid = ov.localId;
|
|
853
1471
|
if (ovLid < memberFirst || ovLid >= memberLast) {
|
|
854
|
-
return
|
|
1472
|
+
return err5({
|
|
855
1473
|
code: "pack-mount-override-localid-out-of-range",
|
|
856
1474
|
expected: `override.localId in [${memberFirst}, ${memberLast})`,
|
|
857
|
-
hint:
|
|
1475
|
+
hint: PACK_ERROR_HINTS2["pack-mount-override-localid-out-of-range"],
|
|
858
1476
|
detail: {
|
|
859
1477
|
code: "pack-mount-override-localid-out-of-range",
|
|
860
1478
|
overrideLocalId: ovLid,
|
|
@@ -866,12 +1484,12 @@ function worldValidateMountOverrides(world, mount) {
|
|
|
866
1484
|
const ovToken = world.components.resolve(ov.comp);
|
|
867
1485
|
if (ov.field !== void 0) {
|
|
868
1486
|
if (ovToken !== void 0) {
|
|
869
|
-
const schema =
|
|
1487
|
+
const schema = componentSchema2(ovToken);
|
|
870
1488
|
if (!(ov.field in schema)) {
|
|
871
|
-
return
|
|
1489
|
+
return err5({
|
|
872
1490
|
code: "pack-mount-override-unknown-field",
|
|
873
1491
|
expected: `override.field defined on component '${ov.comp}'`,
|
|
874
|
-
hint:
|
|
1492
|
+
hint: PACK_ERROR_HINTS2["pack-mount-override-unknown-field"],
|
|
875
1493
|
detail: {
|
|
876
1494
|
code: "pack-mount-override-unknown-field",
|
|
877
1495
|
comp: ov.comp,
|
|
@@ -883,16 +1501,16 @@ function worldValidateMountOverrides(world, mount) {
|
|
|
883
1501
|
}
|
|
884
1502
|
} else {
|
|
885
1503
|
if (ovToken === void 0) {
|
|
886
|
-
return
|
|
1504
|
+
return err5(new ComponentNotDefinedError(ov.comp));
|
|
887
1505
|
}
|
|
888
|
-
const schema =
|
|
1506
|
+
const schema = componentSchema2(ovToken);
|
|
889
1507
|
const valueMap = ov.value ?? {};
|
|
890
1508
|
for (const key of Object.keys(valueMap)) {
|
|
891
1509
|
if (!(key in schema)) {
|
|
892
|
-
return
|
|
1510
|
+
return err5({
|
|
893
1511
|
code: "pack-mount-override-unknown-field",
|
|
894
1512
|
expected: `override.value keys defined on component '${ov.comp}'`,
|
|
895
|
-
hint:
|
|
1513
|
+
hint: PACK_ERROR_HINTS2["pack-mount-override-unknown-field"],
|
|
896
1514
|
detail: {
|
|
897
1515
|
code: "pack-mount-override-unknown-field",
|
|
898
1516
|
comp: ov.comp,
|
|
@@ -904,7 +1522,7 @@ function worldValidateMountOverrides(world, mount) {
|
|
|
904
1522
|
}
|
|
905
1523
|
}
|
|
906
1524
|
}
|
|
907
|
-
return
|
|
1525
|
+
return ok5(void 0);
|
|
908
1526
|
}
|
|
909
1527
|
function worldSpawnMountEntity(world, mount, mapping, diagnostics) {
|
|
910
1528
|
const fakeNode = {
|
|
@@ -923,7 +1541,7 @@ function worldSpawnMountEntity(world, mount, mapping, diagnostics) {
|
|
|
923
1541
|
if (cdRes.value.length === 0) {
|
|
924
1542
|
const childOfToken = world.components.resolve("ChildOf");
|
|
925
1543
|
if (childOfToken === void 0) {
|
|
926
|
-
return
|
|
1544
|
+
return err5(new ComponentNotDefinedError("ChildOf"));
|
|
927
1545
|
}
|
|
928
1546
|
cdRes.value.push({
|
|
929
1547
|
component: childOfToken,
|
|
@@ -935,7 +1553,7 @@ function worldSpawnMountEntity(world, mount, mapping, diagnostics) {
|
|
|
935
1553
|
function worldResolveMountSource(world, source, parentHandle) {
|
|
936
1554
|
const resolver = worldGetSceneAssetResolver(world);
|
|
937
1555
|
if (resolver === null) {
|
|
938
|
-
return
|
|
1556
|
+
return err5({
|
|
939
1557
|
code: "stale-entity",
|
|
940
1558
|
expected: "wired SceneAssetResolver (auto-wired by engine.assets.instantiate)",
|
|
941
1559
|
hint: "engine.assets.instantiate sugar wires this for you; call worldSetSceneAssetResolver before nested scene expansion.",
|
|
@@ -944,9 +1562,9 @@ function worldResolveMountSource(world, source, parentHandle) {
|
|
|
944
1562
|
}
|
|
945
1563
|
const r = resolver(source, parentHandle);
|
|
946
1564
|
if (!r.ok) {
|
|
947
|
-
return
|
|
1565
|
+
return err5(r.error);
|
|
948
1566
|
}
|
|
949
|
-
return
|
|
1567
|
+
return ok5(r.value);
|
|
950
1568
|
}
|
|
951
1569
|
function worldMountOverridesToStateMap(src) {
|
|
952
1570
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -969,7 +1587,7 @@ function worldSetUniqueRefPayload(world, handle, payload) {
|
|
|
969
1587
|
function worldResolveSceneInstanceStatePayload(world, root) {
|
|
970
1588
|
const sceneInstanceToken = world.components.resolve("SceneInstance");
|
|
971
1589
|
if (sceneInstanceToken === void 0) {
|
|
972
|
-
return
|
|
1590
|
+
return err5(new ComponentNotDefinedError("SceneInstance"));
|
|
973
1591
|
}
|
|
974
1592
|
const r = world.get(root, sceneInstanceToken);
|
|
975
1593
|
if (!r.ok) return r;
|
|
@@ -977,7 +1595,7 @@ function worldResolveSceneInstanceStatePayload(world, root) {
|
|
|
977
1595
|
const stateRefHandle = toUnique(stateRefRaw);
|
|
978
1596
|
const payload = sceneWorldState(world).statePayloads.get(Number(stateRefHandle));
|
|
979
1597
|
if (payload === void 0) {
|
|
980
|
-
return
|
|
1598
|
+
return err5(
|
|
981
1599
|
new StaleEntityError(root, entityIndex(root), entityGeneration(root), {
|
|
982
1600
|
operation: "resolveSceneInstanceState",
|
|
983
1601
|
component: "SceneInstance",
|
|
@@ -986,7 +1604,7 @@ function worldResolveSceneInstanceStatePayload(world, root) {
|
|
|
986
1604
|
})
|
|
987
1605
|
);
|
|
988
1606
|
}
|
|
989
|
-
return
|
|
1607
|
+
return ok5(payload);
|
|
990
1608
|
}
|
|
991
1609
|
function worldGetSceneInstanceState(world, root) {
|
|
992
1610
|
return worldResolveSceneInstanceStatePayload(world, root);
|
|
@@ -995,18 +1613,18 @@ function worldResolveSceneEntity(world, root, ref) {
|
|
|
995
1613
|
const state = worldResolveSceneInstanceStatePayload(world, root);
|
|
996
1614
|
if (!state.ok) return state;
|
|
997
1615
|
const resolved = resolveSceneEntity(ref, {
|
|
998
|
-
sceneSourceKey: state.value.sceneSourceKey ??
|
|
1616
|
+
sceneSourceKey: state.value.sceneSourceKey ?? "",
|
|
999
1617
|
bindings: state.value.bindings
|
|
1000
1618
|
});
|
|
1001
|
-
if (!resolved.ok) return
|
|
1002
|
-
return
|
|
1619
|
+
if (!resolved.ok) return err5(resolved.error);
|
|
1620
|
+
return ok5(resolved.value);
|
|
1003
1621
|
}
|
|
1004
1622
|
function worldDespawnScene(world, root, opts) {
|
|
1005
1623
|
const dRes = worldDespawnDescendants(world, root, opts);
|
|
1006
1624
|
if (!dRes.ok) return dRes;
|
|
1007
1625
|
const drop = world.despawn(root);
|
|
1008
1626
|
if (!drop.ok) return drop;
|
|
1009
|
-
return
|
|
1627
|
+
return ok5(dRes.value + 1);
|
|
1010
1628
|
}
|
|
1011
1629
|
function worldDespawnDescendants(world, root, opts) {
|
|
1012
1630
|
let detached = null;
|
|
@@ -1083,7 +1701,7 @@ function worldDespawnDescendants(world, root, opts) {
|
|
|
1083
1701
|
}
|
|
1084
1702
|
count += 1;
|
|
1085
1703
|
}
|
|
1086
|
-
return
|
|
1704
|
+
return ok5(count);
|
|
1087
1705
|
}
|
|
1088
1706
|
function worldSetSceneOverride(world, root, member, component, field, value) {
|
|
1089
1707
|
const stateRes = worldResolveSceneInstanceStatePayload(world, root);
|
|
@@ -1091,7 +1709,7 @@ function worldSetSceneOverride(world, root, member, component, field, value) {
|
|
|
1091
1709
|
const state = stateRes.value;
|
|
1092
1710
|
const lid = state.entityToLocalId.get(member);
|
|
1093
1711
|
if (lid === void 0) {
|
|
1094
|
-
return
|
|
1712
|
+
return err5(
|
|
1095
1713
|
new StaleEntityError(
|
|
1096
1714
|
member,
|
|
1097
1715
|
entityIndex(member),
|
|
@@ -1105,12 +1723,12 @@ function worldSetSceneOverride(world, root, member, component, field, value) {
|
|
|
1105
1723
|
)
|
|
1106
1724
|
);
|
|
1107
1725
|
}
|
|
1108
|
-
const schemaType =
|
|
1726
|
+
const schemaType = componentSchema2(component)[field];
|
|
1109
1727
|
if (schemaType !== void 0 && isPrimitiveScalarFieldType(schemaType)) {
|
|
1110
1728
|
const expectJsType = primitiveJsType(schemaType);
|
|
1111
1729
|
const actualJsType = typeof value;
|
|
1112
1730
|
if (expectJsType !== actualJsType) {
|
|
1113
|
-
return
|
|
1731
|
+
return err5({
|
|
1114
1732
|
code: "scene-override-type-mismatch",
|
|
1115
1733
|
expected: `value typeof === ${expectJsType}`,
|
|
1116
1734
|
hint: `setSceneOverride(${component.name}.${field}) expected ${expectJsType}, got ${actualJsType}; coerce or pick a different override path.`,
|
|
@@ -1136,14 +1754,14 @@ function worldSetSceneOverride(world, root, member, component, field, value) {
|
|
|
1136
1754
|
field,
|
|
1137
1755
|
value
|
|
1138
1756
|
});
|
|
1139
|
-
return
|
|
1757
|
+
return ok5(void 0);
|
|
1140
1758
|
}
|
|
1141
1759
|
function worldRemoveSceneOverride(world, root, member, component, field) {
|
|
1142
1760
|
const stateRes = worldResolveSceneInstanceStatePayload(world, root);
|
|
1143
1761
|
if (!stateRes.ok) return stateRes;
|
|
1144
1762
|
const state = stateRes.value;
|
|
1145
1763
|
const lid = state.entityToLocalId.get(member);
|
|
1146
|
-
if (lid === void 0) return
|
|
1764
|
+
if (lid === void 0) return ok5(void 0);
|
|
1147
1765
|
const fieldMap = state.overrides.get(lid);
|
|
1148
1766
|
if (fieldMap !== void 0) {
|
|
1149
1767
|
fieldMap.delete(`${component.name}:${field}`);
|
|
@@ -1151,42 +1769,41 @@ function worldRemoveSceneOverride(world, root, member, component, field) {
|
|
|
1151
1769
|
}
|
|
1152
1770
|
const assetRes = worldResolveSceneAsset(world, state.source);
|
|
1153
1771
|
if (!assetRes.ok) return assetRes;
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1156
|
-
);
|
|
1772
|
+
const key = state.keyByLocalId.get(lid);
|
|
1773
|
+
const node = key === void 0 ? void 0 : assetRes.value.entities[key];
|
|
1157
1774
|
const layer1 = node?.components[component.name];
|
|
1158
1775
|
if (layer1 !== void 0 && field in layer1) {
|
|
1159
1776
|
const r = world.set(member, component, { [field]: layer1[field] });
|
|
1160
1777
|
if (!r.ok) return r;
|
|
1161
1778
|
}
|
|
1162
|
-
return
|
|
1779
|
+
return ok5(void 0);
|
|
1163
1780
|
}
|
|
1164
1781
|
function worldDetachSceneMember(world, root, member) {
|
|
1165
1782
|
const sceneInstanceToken = world.components.resolve("SceneInstance");
|
|
1166
1783
|
if (sceneInstanceToken === void 0) {
|
|
1167
|
-
return
|
|
1784
|
+
return err5(new ComponentNotDefinedError("SceneInstance"));
|
|
1168
1785
|
}
|
|
1169
1786
|
const stateRes = worldResolveSceneInstanceStatePayload(world, root);
|
|
1170
1787
|
if (!stateRes.ok) return stateRes;
|
|
1171
1788
|
const state = stateRes.value;
|
|
1172
1789
|
const lid = state.entityToLocalId.get(member);
|
|
1173
|
-
if (lid === void 0) return
|
|
1790
|
+
if (lid === void 0) return ok5(void 0);
|
|
1174
1791
|
state.detachedLocalIds.add(lid);
|
|
1175
|
-
return
|
|
1792
|
+
return ok5(void 0);
|
|
1176
1793
|
}
|
|
1177
1794
|
function worldReattachSceneMember(world, root, member) {
|
|
1178
1795
|
const stateRes = worldResolveSceneInstanceStatePayload(world, root);
|
|
1179
1796
|
if (!stateRes.ok) return stateRes;
|
|
1180
1797
|
const state = stateRes.value;
|
|
1181
1798
|
const lid = state.entityToLocalId.get(member);
|
|
1182
|
-
if (lid === void 0) return
|
|
1799
|
+
if (lid === void 0) return ok5(void 0);
|
|
1183
1800
|
state.detachedLocalIds.delete(lid);
|
|
1184
|
-
return
|
|
1801
|
+
return ok5(void 0);
|
|
1185
1802
|
}
|
|
1186
1803
|
function worldGetSceneAssetForInstance(world, root) {
|
|
1187
1804
|
const stateRes = worldResolveSceneInstanceStatePayload(world, root);
|
|
1188
1805
|
if (!stateRes.ok) return stateRes;
|
|
1189
|
-
return
|
|
1806
|
+
return ok5(stateRes.value.source);
|
|
1190
1807
|
}
|
|
1191
1808
|
function sceneTopoSort(nodes) {
|
|
1192
1809
|
const n = nodes.length;
|
|
@@ -1243,7 +1860,7 @@ import {
|
|
|
1243
1860
|
} from "@forgeax/engine-ecs/internal";
|
|
1244
1861
|
import { worldRead } from "@forgeax/engine-ecs/world-read";
|
|
1245
1862
|
import { mat4 } from "@forgeax/engine-math";
|
|
1246
|
-
import { err as
|
|
1863
|
+
import { err as err6, ok as ok6 } from "@forgeax/engine-types";
|
|
1247
1864
|
var PROPAGATE_TRANSFORMS_SYSTEM = "propagateTransforms";
|
|
1248
1865
|
var PROPAGATE_TRANSFORMS_FIXED_SYSTEM = "propagateTransformsFixed";
|
|
1249
1866
|
var TransformSet = defineSystemSet({ name: "transform" });
|
|
@@ -1261,7 +1878,7 @@ function countPropagation(name) {
|
|
|
1261
1878
|
var SCRATCH = /* @__PURE__ */ new WeakMap();
|
|
1262
1879
|
var REGISTRATION_LEASES = /* @__PURE__ */ new WeakMap();
|
|
1263
1880
|
function pairError(entity, expected) {
|
|
1264
|
-
return
|
|
1881
|
+
return err6(
|
|
1265
1882
|
new SceneError({
|
|
1266
1883
|
code: "hierarchy-broken",
|
|
1267
1884
|
expected,
|
|
@@ -1272,7 +1889,7 @@ function pairError(entity, expected) {
|
|
|
1272
1889
|
}
|
|
1273
1890
|
function ensureQueries(world, scratch) {
|
|
1274
1891
|
if (scratch.flatQuery !== void 0 && scratch.hierarchyQuery !== void 0 && scratch.transformQuery !== void 0 && scratch.hierarchyWriter !== void 0 && scratch.transformWriter !== void 0 && scratch.missingGlobalQuery !== void 0 && scratch.missingTransformQuery !== void 0) {
|
|
1275
|
-
return
|
|
1892
|
+
return ok6(void 0);
|
|
1276
1893
|
}
|
|
1277
1894
|
const flatOutput = world.query({
|
|
1278
1895
|
read: [Transform],
|
|
@@ -1299,7 +1916,7 @@ function ensureQueries(world, scratch) {
|
|
|
1299
1916
|
scratch.transformWriter = transformWriter.value;
|
|
1300
1917
|
scratch.missingGlobalQuery = missingGlobal.value;
|
|
1301
1918
|
scratch.missingTransformQuery = missingTransform.value;
|
|
1302
|
-
return
|
|
1919
|
+
return ok6(void 0);
|
|
1303
1920
|
}
|
|
1304
1921
|
function validateTransformPairs(world, scratch) {
|
|
1305
1922
|
const queryResult = ensureQueries(world, scratch);
|
|
@@ -1315,7 +1932,7 @@ function validateTransformPairs(world, scratch) {
|
|
|
1315
1932
|
for (const row of missingTransform) {
|
|
1316
1933
|
return pairError(row.entity, "each GlobalTransform entity to carry a Transform pair");
|
|
1317
1934
|
}
|
|
1318
|
-
return
|
|
1935
|
+
return ok6(void 0);
|
|
1319
1936
|
}
|
|
1320
1937
|
function scratchFor(world) {
|
|
1321
1938
|
const existing = SCRATCH.get(world);
|
|
@@ -1406,7 +2023,7 @@ function composeFlatColumns(positions, rotations, scales, worlds, count) {
|
|
|
1406
2023
|
function propagateFlat(world, scratch) {
|
|
1407
2024
|
const query = scratch.flatQuery;
|
|
1408
2025
|
if (query === void 0)
|
|
1409
|
-
return
|
|
2026
|
+
return err6(
|
|
1410
2027
|
new SceneError({
|
|
1411
2028
|
code: "hierarchy-broken",
|
|
1412
2029
|
expected: "a valid changed Transform write query",
|
|
@@ -1425,7 +2042,7 @@ function propagateFlat(world, scratch) {
|
|
|
1425
2042
|
}
|
|
1426
2043
|
} catch (cause) {
|
|
1427
2044
|
const error = cause;
|
|
1428
|
-
return
|
|
2045
|
+
return err6(derivedWriteError(error, bindingIndex));
|
|
1429
2046
|
}
|
|
1430
2047
|
const transformWriter = scratch.transformWriter;
|
|
1431
2048
|
if (transformWriter === void 0) {
|
|
@@ -1433,7 +2050,7 @@ function propagateFlat(world, scratch) {
|
|
|
1433
2050
|
}
|
|
1434
2051
|
const transformBindings = transformWriter.bindings;
|
|
1435
2052
|
const structureEpoch = world.getStructureEpoch();
|
|
1436
|
-
if (scratch.flatStructureEpoch === structureEpoch) return
|
|
2053
|
+
if (scratch.flatStructureEpoch === structureEpoch) return ok6(void 0);
|
|
1437
2054
|
ensureFlatBuffers(scratch, transformBindings);
|
|
1438
2055
|
resetFlatBuffers(scratch);
|
|
1439
2056
|
for (let bindingIndex2 = 0; bindingIndex2 < transformBindings.length; bindingIndex2 += 1) {
|
|
@@ -1452,10 +2069,10 @@ function propagateFlat(world, scratch) {
|
|
|
1452
2069
|
const changed = scratch.flatChanged[bindingIndex2];
|
|
1453
2070
|
if (changed === void 0) continue;
|
|
1454
2071
|
const published = transformWriter.publishChangedRows(bindingIndex2, changed);
|
|
1455
|
-
if (!published.ok) return
|
|
2072
|
+
if (!published.ok) return err6(derivedWriteError(published.error, bindingIndex2));
|
|
1456
2073
|
}
|
|
1457
2074
|
scratch.flatStructureEpoch = structureEpoch;
|
|
1458
|
-
return
|
|
2075
|
+
return ok6(void 0);
|
|
1459
2076
|
}
|
|
1460
2077
|
function transformColumns(binding) {
|
|
1461
2078
|
return binding.read;
|
|
@@ -2007,7 +2624,7 @@ function propagateHierarchy(world, scratch) {
|
|
|
2007
2624
|
const hierarchyWriter = scratch.hierarchyWriter;
|
|
2008
2625
|
const transformWriter = scratch.transformWriter;
|
|
2009
2626
|
if (hierarchyWriter === void 0 || transformWriter === void 0) {
|
|
2010
|
-
return
|
|
2627
|
+
return err6(
|
|
2011
2628
|
new SceneError({
|
|
2012
2629
|
code: "hierarchy-broken",
|
|
2013
2630
|
expected: "paired Transform and GlobalTransform derived bindings",
|
|
@@ -2022,7 +2639,7 @@ function propagateHierarchy(world, scratch) {
|
|
|
2022
2639
|
scratch.hierarchyBindingRows.length = 0;
|
|
2023
2640
|
scratch.hierarchyStates.length = 0;
|
|
2024
2641
|
scratch.hierarchyChanged.length = 0;
|
|
2025
|
-
return
|
|
2642
|
+
return ok6(void 0);
|
|
2026
2643
|
}
|
|
2027
2644
|
ensureHierarchyBuffers(scratch, hierarchyBindings);
|
|
2028
2645
|
resetHierarchyBuffers(scratch);
|
|
@@ -2080,7 +2697,7 @@ function propagateHierarchy(world, scratch) {
|
|
|
2080
2697
|
report(derivedWriteError(cause, bindingIndex));
|
|
2081
2698
|
}
|
|
2082
2699
|
}
|
|
2083
|
-
return firstError === void 0 ?
|
|
2700
|
+
return firstError === void 0 ? ok6(void 0) : err6(firstError);
|
|
2084
2701
|
}
|
|
2085
2702
|
function propagateTransforms(world) {
|
|
2086
2703
|
const scratch = scratchFor(world);
|
|
@@ -2291,6 +2908,7 @@ export {
|
|
|
2291
2908
|
Transform,
|
|
2292
2909
|
TransformSet,
|
|
2293
2910
|
collectSubtree,
|
|
2911
|
+
compileKeyedSceneAsset,
|
|
2294
2912
|
externalizeSceneAsset,
|
|
2295
2913
|
projectHierarchy,
|
|
2296
2914
|
propagateTransforms,
|
|
@@ -2298,8 +2916,9 @@ export {
|
|
|
2298
2916
|
resolveSceneEntity,
|
|
2299
2917
|
sceneAssetContribution,
|
|
2300
2918
|
sceneEntity,
|
|
2919
|
+
sceneEntityAddressKey,
|
|
2301
2920
|
scenePlugin,
|
|
2302
|
-
|
|
2921
|
+
validateSceneEntityKeys,
|
|
2303
2922
|
worldApplyMountOverride,
|
|
2304
2923
|
worldBuildSceneEntityComponentDatas,
|
|
2305
2924
|
worldDespawnDescendants,
|