@forgeax/engine-runtime 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 +98 -0
- package/dist/collect-scene-asset.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +480 -15
- package/dist/index.mjs.map +1 -1
- package/dist/scene-utils/mount-override-fold.d.ts +3 -1
- package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
- package/package.json +37 -30
- package/src/__tests__/animation-graph-collect-roundtrip.test.ts +4 -2
- package/src/__tests__/asset-registry-aabb.cases.unit.test.ts +5 -4
- package/src/__tests__/asset-registry-guid-reverse.test.ts +22 -27
- package/src/__tests__/asset-registry-mounts.test.ts +174 -734
- package/src/__tests__/asset-registry-scene.cases.unit.test.ts +9 -18
- package/src/__tests__/asset-registry.recursive.spec.ts +23 -29
- package/src/__tests__/camera-ortho.cases.unit.test.ts +12 -3
- package/src/__tests__/collect-scene-asset.test.ts +96 -113
- package/src/__tests__/collect-scene-mount-collapse.test.ts +64 -66
- package/src/__tests__/collect-transient-children-absent.test.ts +11 -17
- package/src/__tests__/collect-transient-roundtrip.test.ts +12 -13
- package/src/__tests__/collect-transient-skip.test.ts +20 -27
- package/src/__tests__/components.test-d.ts +17 -1
- package/src/__tests__/components.unit.test.ts +75 -27
- package/src/__tests__/composite-skybox-cross-world.browser.test.ts +4 -2
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +8 -4
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +4 -1
- package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +66 -92
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +200 -4
- package/src/__tests__/errors.unit.test.ts +13 -0
- package/src/__tests__/feature-depth-material.dawn.test.ts +23 -0
- package/src/__tests__/feature-depth-material.fixture.ts +473 -0
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +14 -14
- package/src/__tests__/geometry.unit.test.ts +42 -43
- package/src/__tests__/gpu-resource-release.cases.unit.test.ts +16 -9
- package/src/__tests__/handle-migration.test.ts +0 -1
- package/src/__tests__/instances-renderer-lifecycle.integration.test.ts +20 -14
- package/src/__tests__/instances.test-d.ts +13 -52
- package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +42 -80
- package/src/__tests__/lazy-catalog.cases.unit.test.ts +17 -3
- package/src/__tests__/loader-registry.cases.unit.test.ts +4 -4
- package/src/__tests__/material-publication.browser.test.ts +29 -0
- package/src/__tests__/material-publication.commands.ts +23 -0
- package/src/__tests__/material-publication.dawn.test.ts +24 -0
- package/src/__tests__/material-publication.fixture.ts +349 -0
- package/src/__tests__/material-publication.server.ts +109 -0
- package/src/__tests__/parse-scene-payload-refs.cases.unit.test.ts +73 -96
- package/src/__tests__/pbr-pipeline.unit.test.ts +25 -11
- package/src/__tests__/point-light-shadow.browser.test.ts +8 -2
- package/src/__tests__/point-light-shadow.unit.test.ts +37 -8
- package/src/__tests__/record-all-topology.cases.unit.test.ts +52 -0
- package/src/__tests__/record-draw-branch.cases.unit.test.ts +1 -0
- package/src/__tests__/record-worldid-isolation.test.ts +47 -28
- package/src/__tests__/render-error-exhaustive.test-d.ts +24 -0
- package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +15 -4
- package/src/__tests__/render-system-extract.test.ts +61 -0
- package/src/__tests__/render-system-extract.unit.test.ts +21 -7
- package/src/__tests__/render-system-fold-bucket.unit.test.ts +33 -1
- package/src/__tests__/render-system-fold-material.unit.test.ts +32 -6
- package/src/__tests__/render-system-fold-modegate.unit.test.ts +26 -4
- package/src/__tests__/render-system-fold.dawn.test.ts +4 -1
- package/src/__tests__/render-system-mega.test.ts +50 -62
- package/src/__tests__/renderer-device-loss-provider-feasibility.dawn.test.ts +0 -1
- package/src/__tests__/renderer-device-loss-recovery.dawn.test.ts +0 -3
- package/src/__tests__/renderer-draw-world.cases.unit.test.ts +16 -513
- package/src/__tests__/resolve-scene-guids.cases.unit.test.ts +48 -43
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +9 -7
- package/src/__tests__/roots-to-scene-asset.test.ts +27 -28
- package/src/__tests__/roundtrip-primitive.test.ts +24 -23
- package/src/__tests__/scene-equirect-roundtrip.test.ts +5 -16
- package/src/__tests__/scene-instantiate-cycle-runtime.test.ts +13 -29
- package/src/__tests__/scene-mount-fixed-point.test.ts +104 -227
- package/src/__tests__/scene-mount-roundtrip.test.ts +95 -961
- package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +36 -182
- package/src/__tests__/scene-sugar-instantiate.test.ts +20 -15
- package/src/__tests__/serialize-mounts-roundtrip.test.ts +108 -492
- package/src/__tests__/serialize-scene-asset.test.ts +36 -50
- package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -1
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +34 -19
- package/src/__tests__/shadow-mesh-ssbo-order.test.ts +5 -12
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +6 -4
- package/src/__tests__/skin-m2-extract-happy.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-m2-extract-joint-error.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-m2-extract-null-assets.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-m2-extract-skeleton-error.cases.unit.test.ts +50 -2
- package/src/__tests__/skin-palette-extract.cases.unit.test.ts +2 -0
- package/src/__tests__/skinned-shadow-mixed.dawn.test.ts +93 -48
- package/src/__tests__/skylight-pipeline-layout.cases.unit.test.ts +6 -2
- package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +1 -1
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +11 -3
- package/src/__tests__/template-game-default-api-contract.test.ts +21 -21
- package/src/__tests__/tonemap-hdr-target.cases.unit.test.ts +8 -5
- package/src/__tests__/tonemap-pipeline-split.cases.unit.test.ts +3 -0
- package/src/__tests__/transient-fields-collect.test.ts +4 -4
- package/src/__tests__/transient-runtime-behavior.test.ts +9 -9
- package/src/__tests__/vfx-depth-material.dawn.test.ts +42 -0
- package/src/__tests__/vfx-mesh-lighting.browser.test.ts +16 -0
- package/src/__tests__/vfx-mesh-lighting.commands.ts +14 -0
- package/src/__tests__/vfx-mesh-lighting.dawn.test.ts +16 -0
- package/src/__tests__/vfx-mesh-lighting.fixture.ts +883 -0
- package/src/__tests__/wave1-dynamic-geometry.browser.test.ts +326 -0
- package/src/__tests__/wave1-rendering-materials.browser.test.ts +617 -0
- package/src/__tests__/wave1-rendering-p0.browser.test.ts +751 -0
- package/src/__tests__/wave1-rendering-recovery.browser.test.ts +666 -0
- package/src/__tests__/wave1-shadow-diagnostic.browser.test.ts +582 -0
- package/src/__tests__/world-scene-despawn.test.ts +8 -8
- package/src/__tests__/world-scene-instantiate.test.ts +23 -29
- package/src/__tests__/world-scene-nested.test.ts +90 -163
- package/src/__tests__/world-scene-override.test.ts +17 -16
- package/src/__tests__/zero-compression-zero-load.integration.test.ts +1 -0
- package/src/collect-scene-asset.ts +637 -19
- package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
- package/src/index.ts +1 -0
- package/src/scene-utils/mount-override-fold.ts +5 -14
- package/src/__tests__/node-shims.d.ts +0 -31
package/dist/index.mjs
CHANGED
|
@@ -359,10 +359,6 @@ function foldMountOverrides(world, state) {
|
|
|
359
359
|
);
|
|
360
360
|
if (!sourceRes.ok) return [];
|
|
361
361
|
const source = sourceRes.value;
|
|
362
|
-
const sourceByLid = /* @__PURE__ */ new Map();
|
|
363
|
-
for (const node of source.entities) {
|
|
364
|
-
sourceByLid.set(node.localId, node);
|
|
365
|
-
}
|
|
366
362
|
const excluded = excludedComponentNames();
|
|
367
363
|
const registered = world.components.entries();
|
|
368
364
|
const overrides = [];
|
|
@@ -372,7 +368,8 @@ function foldMountOverrides(world, state) {
|
|
|
372
368
|
}
|
|
373
369
|
members.sort((a, b) => a[1] - b[1]);
|
|
374
370
|
for (const [entity, lid] of members) {
|
|
375
|
-
const
|
|
371
|
+
const sourceKey = state.keyByLocalId.get(lid);
|
|
372
|
+
const sourceNode = sourceKey === void 0 ? void 0 : source.entities[sourceKey];
|
|
376
373
|
const sourceComps = sourceNode?.components ?? {};
|
|
377
374
|
for (const [compName, compToken] of registered) {
|
|
378
375
|
if (excluded.has(compName)) continue;
|
|
@@ -481,6 +478,436 @@ function _serializeOverrideValueHandles(world, registry, ov) {
|
|
|
481
478
|
}
|
|
482
479
|
return ok$1(out);
|
|
483
480
|
}
|
|
481
|
+
function isSceneEntityAddress(value) {
|
|
482
|
+
return typeof value === "string" || value.length > 0;
|
|
483
|
+
}
|
|
484
|
+
function collectKeyedSceneAsset(world, registry, _roots, visited, ownedEntities, legacyEntities, mounts, anchors, memberOrigin) {
|
|
485
|
+
const sceneInstanceToken = world.components.resolve("SceneInstance");
|
|
486
|
+
const childOfToken = world.components.resolve("ChildOf");
|
|
487
|
+
const stateInfos = [];
|
|
488
|
+
if (sceneInstanceToken !== void 0) {
|
|
489
|
+
const queryResult = world.query({ read: [SceneInstance] });
|
|
490
|
+
if (queryResult.ok) {
|
|
491
|
+
for (const row of queryResult.value) {
|
|
492
|
+
const stateResult = worldGetSceneInstanceState(world, row.entity);
|
|
493
|
+
if (!stateResult.ok) continue;
|
|
494
|
+
const rowValue = row.get(SceneInstance);
|
|
495
|
+
stateInfos.push({
|
|
496
|
+
root: row.entity,
|
|
497
|
+
state: stateResult.value,
|
|
498
|
+
mapping: Uint32Array.from(rowValue.mapping)
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
const stateByRoot = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const info of stateInfos) stateByRoot.set(info.root, info);
|
|
505
|
+
const parentByChildRoot = /* @__PURE__ */ new Map();
|
|
506
|
+
const relationCandidates = [];
|
|
507
|
+
for (const child of stateInfos) {
|
|
508
|
+
if (child.state.instanceKey === void 0 || childOfToken === void 0) continue;
|
|
509
|
+
const parentResult = world.get(
|
|
510
|
+
child.root,
|
|
511
|
+
childOfToken
|
|
512
|
+
);
|
|
513
|
+
if (!parentResult.ok) continue;
|
|
514
|
+
const carrier = parentResult.value.parent;
|
|
515
|
+
if (carrier === void 0) continue;
|
|
516
|
+
for (const parent of stateInfos) {
|
|
517
|
+
const bound = parent.state.bindings.get(child.state.instanceKey);
|
|
518
|
+
if (bound === carrier) {
|
|
519
|
+
parentByChildRoot.set(child.root, parent);
|
|
520
|
+
relationCandidates.push({ child, parent, key: child.state.instanceKey });
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
const findSequence = (haystack, needle, start) => {
|
|
526
|
+
if (needle.length === 0) return start;
|
|
527
|
+
for (let index = Math.max(0, start); index + needle.length <= haystack.length; index += 1) {
|
|
528
|
+
let match = true;
|
|
529
|
+
for (let offset = 0; offset < needle.length; offset += 1) {
|
|
530
|
+
if (haystack[index + offset] !== needle[offset]) {
|
|
531
|
+
match = false;
|
|
532
|
+
break;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
if (match) return index;
|
|
536
|
+
}
|
|
537
|
+
return void 0;
|
|
538
|
+
};
|
|
539
|
+
const relations = [];
|
|
540
|
+
for (const candidate of relationCandidates) {
|
|
541
|
+
const slot = [...candidate.parent.state.keyByLocalId.entries()].find(
|
|
542
|
+
([, value]) => value === candidate.key
|
|
543
|
+
)?.[0];
|
|
544
|
+
if (slot === void 0) continue;
|
|
545
|
+
const memberFirst = findSequence(candidate.parent.mapping, candidate.child.mapping, slot + 1);
|
|
546
|
+
if (memberFirst === void 0) continue;
|
|
547
|
+
relations.push({ ...candidate, memberFirst });
|
|
548
|
+
}
|
|
549
|
+
const relationsByParent = /* @__PURE__ */ new Map();
|
|
550
|
+
for (const relation of relations) {
|
|
551
|
+
const list = relationsByParent.get(relation.parent.root);
|
|
552
|
+
if (list === void 0) relationsByParent.set(relation.parent.root, [relation]);
|
|
553
|
+
else list.push(relation);
|
|
554
|
+
}
|
|
555
|
+
const statePrefixMemo = /* @__PURE__ */ new Map();
|
|
556
|
+
const statePrefix = (info, stack = /* @__PURE__ */ new Set()) => {
|
|
557
|
+
const prior = statePrefixMemo.get(info.root);
|
|
558
|
+
if (prior !== void 0) return prior;
|
|
559
|
+
if (stack.has(info.root)) return [];
|
|
560
|
+
if (info.state.instanceKey === void 0) {
|
|
561
|
+
statePrefixMemo.set(info.root, []);
|
|
562
|
+
return [];
|
|
563
|
+
}
|
|
564
|
+
const next = new Set(stack);
|
|
565
|
+
next.add(info.root);
|
|
566
|
+
const parent = parentByChildRoot.get(info.root);
|
|
567
|
+
const prefix = parent === void 0 ? [info.state.instanceKey] : [...statePrefix(parent, next), info.state.instanceKey];
|
|
568
|
+
statePrefixMemo.set(info.root, prefix);
|
|
569
|
+
return prefix;
|
|
570
|
+
};
|
|
571
|
+
const stateSlotAddress = (info, slot, prefix, stack = /* @__PURE__ */ new Set()) => {
|
|
572
|
+
if (slot < 0 || stack.has(info.root)) return void 0;
|
|
573
|
+
const key = info.state.keyByLocalId.get(slot);
|
|
574
|
+
if (key !== void 0) return [...prefix, key];
|
|
575
|
+
const next = new Set(stack);
|
|
576
|
+
next.add(info.root);
|
|
577
|
+
for (const relation of relationsByParent.get(info.root) ?? []) {
|
|
578
|
+
const end = relation.memberFirst + relation.child.mapping.length;
|
|
579
|
+
if (slot >= relation.memberFirst && slot < end) {
|
|
580
|
+
return stateSlotAddress(
|
|
581
|
+
relation.child,
|
|
582
|
+
slot - relation.memberFirst,
|
|
583
|
+
[...prefix, relation.key],
|
|
584
|
+
next
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return void 0;
|
|
589
|
+
};
|
|
590
|
+
const rawToAddress = /* @__PURE__ */ new Map();
|
|
591
|
+
const orderedStates = [...stateInfos].sort(
|
|
592
|
+
(a, b) => statePrefix(a).length - statePrefix(b).length
|
|
593
|
+
);
|
|
594
|
+
for (const info of orderedStates) {
|
|
595
|
+
const prefix = statePrefix(info);
|
|
596
|
+
for (let slot = 0; slot < info.mapping.length; slot += 1) {
|
|
597
|
+
const raw = info.mapping[slot];
|
|
598
|
+
if (raw === void 0 || raw === 4294967295 || !visited.has(raw)) continue;
|
|
599
|
+
const address = stateSlotAddress(info, slot, prefix);
|
|
600
|
+
if (address !== void 0 && !rawToAddress.has(raw)) rawToAddress.set(raw, address);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
for (const [raw, origin] of memberOrigin) {
|
|
604
|
+
if (!visited.has(raw) || rawToAddress.has(raw)) continue;
|
|
605
|
+
const child = stateByRoot.get(origin.anchorRaw);
|
|
606
|
+
if (child === void 0) continue;
|
|
607
|
+
const address = stateSlotAddress(child, origin.memberLocalId, statePrefix(child));
|
|
608
|
+
if (address !== void 0) rawToAddress.set(raw, address);
|
|
609
|
+
}
|
|
610
|
+
const generatedKeys = /* @__PURE__ */ new Set();
|
|
611
|
+
const keyForOwnedRaw = /* @__PURE__ */ new Map();
|
|
612
|
+
for (let index = 0; index < ownedEntities.length; index += 1) {
|
|
613
|
+
const raw = ownedEntities[index];
|
|
614
|
+
const known = rawToAddress.get(raw);
|
|
615
|
+
let key = known?.length === 1 ? known[0] : void 0;
|
|
616
|
+
if (key === void 0 || key.length === 0 || generatedKeys.has(key)) {
|
|
617
|
+
const base = `entity-${index}`;
|
|
618
|
+
key = base;
|
|
619
|
+
let suffix = 1;
|
|
620
|
+
while (generatedKeys.has(key)) key = `${base}-${suffix++}`;
|
|
621
|
+
}
|
|
622
|
+
generatedKeys.add(key);
|
|
623
|
+
keyForOwnedRaw.set(raw, key);
|
|
624
|
+
rawToAddress.set(raw, [key]);
|
|
625
|
+
}
|
|
626
|
+
const slotAddress = (slot) => {
|
|
627
|
+
if (slot >= 0 && slot < ownedEntities.length) {
|
|
628
|
+
const raw = ownedEntities[slot];
|
|
629
|
+
const key = raw === void 0 ? void 0 : keyForOwnedRaw.get(raw);
|
|
630
|
+
return key;
|
|
631
|
+
}
|
|
632
|
+
const mountIndex = mounts.findIndex((mount) => mount.localId === slot);
|
|
633
|
+
if (mountIndex >= 0) {
|
|
634
|
+
const anchor = anchors[mountIndex];
|
|
635
|
+
const child = anchor === void 0 ? void 0 : stateByRoot.get(anchor.entityRaw);
|
|
636
|
+
const key = child?.state.instanceKey;
|
|
637
|
+
if (key !== void 0) return key;
|
|
638
|
+
}
|
|
639
|
+
for (let index = 0; index < mounts.length; index += 1) {
|
|
640
|
+
const mount = mounts[index];
|
|
641
|
+
if (mount === void 0) continue;
|
|
642
|
+
const first = mount.memberFirst;
|
|
643
|
+
if (slot < first || slot >= first + mount.memberCount) continue;
|
|
644
|
+
const anchor = anchors[index];
|
|
645
|
+
const child = anchor === void 0 ? void 0 : stateByRoot.get(anchor.entityRaw);
|
|
646
|
+
const mountKey = child?.state.instanceKey;
|
|
647
|
+
if (child === void 0 || mountKey === void 0) return void 0;
|
|
648
|
+
const address = stateSlotAddress(child, slot - first, []);
|
|
649
|
+
if (address === void 0) return void 0;
|
|
650
|
+
return [mountKey, ...address];
|
|
651
|
+
}
|
|
652
|
+
const top = orderedStates.find((info) => statePrefix(info).length === 0);
|
|
653
|
+
if (top !== void 0) {
|
|
654
|
+
const address = stateSlotAddress(top, slot, []);
|
|
655
|
+
if (address !== void 0) {
|
|
656
|
+
return address.length === 1 ? address[0] : address;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
return void 0;
|
|
660
|
+
};
|
|
661
|
+
const convertComponents = (entityRaw, source) => {
|
|
662
|
+
const out = {};
|
|
663
|
+
for (const [componentName, rawFields] of Object.entries(source)) {
|
|
664
|
+
const token = world.components.resolve(componentName);
|
|
665
|
+
if (token === void 0) {
|
|
666
|
+
out[componentName] = { ...rawFields };
|
|
667
|
+
continue;
|
|
668
|
+
}
|
|
669
|
+
const converted = {};
|
|
670
|
+
for (const [fieldName, value] of Object.entries(rawFields)) {
|
|
671
|
+
const kind = classifyEntityField(token, fieldName);
|
|
672
|
+
if (kind === null) {
|
|
673
|
+
converted[fieldName] = value;
|
|
674
|
+
continue;
|
|
675
|
+
}
|
|
676
|
+
const convertSlot = (localSlot) => {
|
|
677
|
+
if (typeof localSlot !== "number") return void 0;
|
|
678
|
+
return slotAddress(localSlot);
|
|
679
|
+
};
|
|
680
|
+
if (kind.isArray) {
|
|
681
|
+
if (!Array.isArray(value)) {
|
|
682
|
+
return err$1(
|
|
683
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
684
|
+
entityRaw,
|
|
685
|
+
`${componentName}.${fieldName}`,
|
|
686
|
+
-1
|
|
687
|
+
)
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
const addresses = [];
|
|
691
|
+
for (const item of value) {
|
|
692
|
+
const address = convertSlot(item);
|
|
693
|
+
if (address === void 0 || !isSceneEntityAddress(address)) {
|
|
694
|
+
return err$1(
|
|
695
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
696
|
+
entityRaw,
|
|
697
|
+
`${componentName}.${fieldName}`,
|
|
698
|
+
Number(item)
|
|
699
|
+
)
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
addresses.push(address);
|
|
703
|
+
}
|
|
704
|
+
converted[fieldName] = addresses;
|
|
705
|
+
} else if (value === null) {
|
|
706
|
+
converted[fieldName] = null;
|
|
707
|
+
} else {
|
|
708
|
+
const address = convertSlot(value);
|
|
709
|
+
if (address === void 0 || !isSceneEntityAddress(address)) {
|
|
710
|
+
return err$1(
|
|
711
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
712
|
+
entityRaw,
|
|
713
|
+
`${componentName}.${fieldName}`,
|
|
714
|
+
Number(value)
|
|
715
|
+
)
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
converted[fieldName] = address;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
out[componentName] = converted;
|
|
722
|
+
}
|
|
723
|
+
return ok$1(out);
|
|
724
|
+
};
|
|
725
|
+
const entities = {};
|
|
726
|
+
for (const legacy of legacyEntities) {
|
|
727
|
+
const raw = ownedEntities[legacy.localId];
|
|
728
|
+
if (raw === void 0) continue;
|
|
729
|
+
const key = keyForOwnedRaw.get(raw);
|
|
730
|
+
const converted = convertComponents(raw, legacy.components);
|
|
731
|
+
if (!converted.ok) return converted;
|
|
732
|
+
entities[key] = { components: converted.value };
|
|
733
|
+
}
|
|
734
|
+
const resolveOverrideTarget = (child, memberFirst, localId) => {
|
|
735
|
+
if (child === void 0) return void 0;
|
|
736
|
+
const target = stateSlotAddress(child, localId - memberFirst, []);
|
|
737
|
+
if (target === void 0 || target.length === 0) return void 0;
|
|
738
|
+
return target;
|
|
739
|
+
};
|
|
740
|
+
const convertOverrideValue = (entityRaw, componentName, fieldName, value) => {
|
|
741
|
+
const token = world.components.resolve(componentName);
|
|
742
|
+
if (token === void 0) return ok$1(value);
|
|
743
|
+
const schema = componentSchema(token);
|
|
744
|
+
const convertFields = (field, fieldValue) => {
|
|
745
|
+
const kind = classifyEntityField(token, field);
|
|
746
|
+
if (kind === null) {
|
|
747
|
+
const sharedType = schema[field];
|
|
748
|
+
const shared = sharedType?.startsWith("shared<") ? { scalar: true } : sharedType?.startsWith("array<shared<") ? { scalar: false } : void 0;
|
|
749
|
+
if (shared === void 0) return ok$1(fieldValue);
|
|
750
|
+
return _serializeSharedFieldValue(world, registry, shared, fieldValue, field);
|
|
751
|
+
}
|
|
752
|
+
const resolveLiveOrSlot = (item) => {
|
|
753
|
+
if (typeof item !== "number") return void 0;
|
|
754
|
+
const live = rawToAddress.get(item);
|
|
755
|
+
if (live !== void 0) {
|
|
756
|
+
return live.length === 1 ? live[0] : live;
|
|
757
|
+
}
|
|
758
|
+
return slotAddress(item);
|
|
759
|
+
};
|
|
760
|
+
if (kind.isArray) {
|
|
761
|
+
if (!Array.isArray(fieldValue)) return ok$1(fieldValue);
|
|
762
|
+
const mapped = [];
|
|
763
|
+
for (const item of fieldValue) {
|
|
764
|
+
const address2 = resolveLiveOrSlot(item);
|
|
765
|
+
if (address2 === void 0 || !isSceneEntityAddress(address2)) {
|
|
766
|
+
return err$1(
|
|
767
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
768
|
+
entityRaw,
|
|
769
|
+
`${componentName}.${field}`,
|
|
770
|
+
Number(item)
|
|
771
|
+
)
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
mapped.push(address2);
|
|
775
|
+
}
|
|
776
|
+
return ok$1(mapped);
|
|
777
|
+
}
|
|
778
|
+
if (fieldValue === null) return ok$1(null);
|
|
779
|
+
const address = resolveLiveOrSlot(fieldValue);
|
|
780
|
+
if (address === void 0 || !isSceneEntityAddress(address)) {
|
|
781
|
+
return err$1(
|
|
782
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
783
|
+
entityRaw,
|
|
784
|
+
`${componentName}.${field}`,
|
|
785
|
+
Number(fieldValue)
|
|
786
|
+
)
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
return ok$1(address);
|
|
790
|
+
};
|
|
791
|
+
if (fieldName !== void 0) return convertFields(fieldName, value);
|
|
792
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return ok$1(value);
|
|
793
|
+
const result = {};
|
|
794
|
+
for (const [field, fieldValue] of Object.entries(value)) {
|
|
795
|
+
const converted = convertFields(field, fieldValue);
|
|
796
|
+
if (!converted.ok) return converted;
|
|
797
|
+
result[field] = converted.value;
|
|
798
|
+
}
|
|
799
|
+
return ok$1(result);
|
|
800
|
+
};
|
|
801
|
+
const declarationOverrides = (parent, child, mount, anchor) => {
|
|
802
|
+
const memberFirst = mount.memberFirst;
|
|
803
|
+
const candidates = [];
|
|
804
|
+
if (parent !== void 0) {
|
|
805
|
+
for (const override of parent.state.mountTimeOverrides) {
|
|
806
|
+
const localId = override.localId;
|
|
807
|
+
if (localId >= memberFirst && localId < memberFirst + mount.memberCount)
|
|
808
|
+
candidates.push(override);
|
|
809
|
+
}
|
|
810
|
+
for (const [localId, records] of parent.state.overrides) {
|
|
811
|
+
const numeric = localId;
|
|
812
|
+
if (numeric < memberFirst || numeric >= memberFirst + mount.memberCount) continue;
|
|
813
|
+
for (const record of records.values()) {
|
|
814
|
+
candidates.push({
|
|
815
|
+
localId,
|
|
816
|
+
comp: record.comp,
|
|
817
|
+
...record.field === void 0 ? {} : { field: record.field },
|
|
818
|
+
value: record.value
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
if (candidates.length === 0) candidates.push(...mount.overrides ?? []);
|
|
824
|
+
if (candidates.length === 0 || child === void 0) return ok$1(void 0);
|
|
825
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
826
|
+
for (const override of candidates) {
|
|
827
|
+
const localId = override.localId;
|
|
828
|
+
const target = resolveOverrideTarget(child, memberFirst, localId);
|
|
829
|
+
if (target === void 0) {
|
|
830
|
+
return err$1(
|
|
831
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
832
|
+
anchor.entityRaw,
|
|
833
|
+
"instance.override.target",
|
|
834
|
+
localId
|
|
835
|
+
)
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
const converted = convertOverrideValue(
|
|
839
|
+
anchor.entityRaw,
|
|
840
|
+
override.comp,
|
|
841
|
+
override.field,
|
|
842
|
+
override.value
|
|
843
|
+
);
|
|
844
|
+
if (!converted.ok) return converted;
|
|
845
|
+
const targetKey = JSON.stringify(target);
|
|
846
|
+
const prior = byTarget.get(targetKey);
|
|
847
|
+
const components = {};
|
|
848
|
+
if (prior !== void 0) {
|
|
849
|
+
for (const [name, fields] of Object.entries(
|
|
850
|
+
prior.components
|
|
851
|
+
)) {
|
|
852
|
+
components[name] = { ...fields };
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const priorFields = components[override.comp];
|
|
856
|
+
const existing = { ...priorFields ?? {} };
|
|
857
|
+
if (override.field === void 0 && typeof converted.value === "object" && converted.value !== null) {
|
|
858
|
+
Object.assign(existing, converted.value);
|
|
859
|
+
} else if (override.field !== void 0) {
|
|
860
|
+
existing[override.field] = converted.value;
|
|
861
|
+
}
|
|
862
|
+
components[override.comp] = existing;
|
|
863
|
+
byTarget.set(targetKey, { target, components });
|
|
864
|
+
}
|
|
865
|
+
return ok$1([...byTarget.values()]);
|
|
866
|
+
};
|
|
867
|
+
for (let index = 0; index < mounts.length; index += 1) {
|
|
868
|
+
const mount = mounts[index];
|
|
869
|
+
const anchor = anchors[index];
|
|
870
|
+
if (mount === void 0 || anchor === void 0) continue;
|
|
871
|
+
const child = stateByRoot.get(anchor.entityRaw);
|
|
872
|
+
const parent = child === void 0 ? void 0 : parentByChildRoot.get(child.root);
|
|
873
|
+
const instanceKey = child?.state.instanceKey ?? `instance-${index}`;
|
|
874
|
+
const carrierRaw = childOfToken === void 0 ? void 0 : (() => {
|
|
875
|
+
const parentResult = world.get(
|
|
876
|
+
anchor.entityRaw,
|
|
877
|
+
childOfToken
|
|
878
|
+
);
|
|
879
|
+
return parentResult.ok ? parentResult.value.parent : void 0;
|
|
880
|
+
})();
|
|
881
|
+
const converted = convertComponents(
|
|
882
|
+
carrierRaw ?? anchor.entityRaw,
|
|
883
|
+
mount.components ?? {}
|
|
884
|
+
);
|
|
885
|
+
if (!converted.ok) return converted;
|
|
886
|
+
if (mount.parent !== void 0) {
|
|
887
|
+
const parentAddress = slotAddress(mount.parent);
|
|
888
|
+
if (parentAddress === void 0) {
|
|
889
|
+
return err$1(
|
|
890
|
+
new SceneCollectEntityRefOutOfClosureError(
|
|
891
|
+
carrierRaw ?? anchor.entityRaw,
|
|
892
|
+
"ChildOf.parent",
|
|
893
|
+
mount.parent
|
|
894
|
+
)
|
|
895
|
+
);
|
|
896
|
+
}
|
|
897
|
+
converted.value.ChildOf = { parent: parentAddress };
|
|
898
|
+
}
|
|
899
|
+
const overrides = declarationOverrides(parent, child, mount, anchor);
|
|
900
|
+
if (!overrides.ok) return overrides;
|
|
901
|
+
entities[instanceKey] = {
|
|
902
|
+
components: converted.value,
|
|
903
|
+
instance: {
|
|
904
|
+
source: String(mount.source),
|
|
905
|
+
...overrides.value === void 0 ? {} : { overrides: overrides.value }
|
|
906
|
+
}
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
return ok$1({ kind: "scene", entities });
|
|
910
|
+
}
|
|
484
911
|
function serializeSceneAssetToPack(sceneAsset, components, guid) {
|
|
485
912
|
const externalized = externalizeSceneAsset(sceneAsset, (componentName) => {
|
|
486
913
|
const component = components.get(componentName);
|
|
@@ -513,7 +940,7 @@ function rootsToSceneAsset(registry, world, roots) {
|
|
|
513
940
|
const collectProfile = SCENE_COLLECT_PROFILE;
|
|
514
941
|
const visited = /* @__PURE__ */ new Set();
|
|
515
942
|
for (const root of roots) collectSubtree(world, root, visited);
|
|
516
|
-
if (visited.size === 0) return ok$1({ kind: "scene", entities:
|
|
943
|
+
if (visited.size === 0) return ok$1({ kind: "scene", entities: {} });
|
|
517
944
|
const rootRawSet = /* @__PURE__ */ new Set();
|
|
518
945
|
for (const r of roots) rootRawSet.add(r);
|
|
519
946
|
const anchorEntities = /* @__PURE__ */ new Set();
|
|
@@ -527,13 +954,41 @@ function rootsToSceneAsset(registry, world, roots) {
|
|
|
527
954
|
if (rootRawSet.has(er)) continue;
|
|
528
955
|
const sr = worldGetSceneInstanceState(world, er);
|
|
529
956
|
if (!sr.ok) continue;
|
|
530
|
-
|
|
957
|
+
const retainedState = sr.value;
|
|
958
|
+
for (const [me, lid] of retainedState.entityToLocalId) {
|
|
531
959
|
const mr = me;
|
|
532
960
|
if (visited.has(mr) && !anchorEntities.has(mr) && !memberEntities.has(mr)) {
|
|
533
961
|
memberEntities.add(mr);
|
|
534
962
|
memberOrigin.set(mr, { anchorRaw: er, memberLocalId: lid });
|
|
535
963
|
}
|
|
536
964
|
}
|
|
965
|
+
for (const [key, member] of retainedState.bindings) {
|
|
966
|
+
const mr = member;
|
|
967
|
+
const localId = [...retainedState.keyByLocalId.entries()].find(
|
|
968
|
+
([, value]) => value === key
|
|
969
|
+
)?.[0];
|
|
970
|
+
if (localId !== void 0 && visited.has(mr) && !anchorEntities.has(mr) && !memberEntities.has(mr)) {
|
|
971
|
+
memberEntities.add(mr);
|
|
972
|
+
memberOrigin.set(mr, { anchorRaw: er, memberLocalId: localId });
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
const childOfForAnchor = world.components.resolve("ChildOf");
|
|
977
|
+
if (childOfForAnchor !== void 0) {
|
|
978
|
+
for (const anchorRaw of [...anchorEntities]) {
|
|
979
|
+
if (rootRawSet.has(anchorRaw) || memberEntities.has(anchorRaw)) continue;
|
|
980
|
+
const parentRes = world.get(
|
|
981
|
+
anchorRaw,
|
|
982
|
+
childOfForAnchor
|
|
983
|
+
);
|
|
984
|
+
if (!parentRes.ok) continue;
|
|
985
|
+
const carrierRaw = parentRes.value.parent;
|
|
986
|
+
const origin = carrierRaw === void 0 ? void 0 : memberOrigin.get(carrierRaw);
|
|
987
|
+
if (origin !== void 0) {
|
|
988
|
+
memberEntities.add(anchorRaw);
|
|
989
|
+
memberOrigin.set(anchorRaw, origin);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
537
992
|
}
|
|
538
993
|
for (const er of anchorEntities) {
|
|
539
994
|
if (memberEntities.has(er) && !rootRawSet.has(er)) anchorEntities.delete(er);
|
|
@@ -588,7 +1043,8 @@ function rootsToSceneAsset(registry, world, roots) {
|
|
|
588
1043
|
const ownedEntities = [];
|
|
589
1044
|
for (const er of orderedEntities) {
|
|
590
1045
|
if (carrierToAnchor.has(er)) continue;
|
|
591
|
-
if (
|
|
1046
|
+
if (rootRawSet.has(er) && anchorEntities.has(er)) continue;
|
|
1047
|
+
if (!anchorEntities.has(er) && !memberEntities.has(er)) {
|
|
592
1048
|
ownedEntities.push(er);
|
|
593
1049
|
}
|
|
594
1050
|
}
|
|
@@ -727,7 +1183,7 @@ function rootsToSceneAsset(registry, world, roots) {
|
|
|
727
1183
|
return void 0;
|
|
728
1184
|
}
|
|
729
1185
|
const registeredComps = world.components.entries();
|
|
730
|
-
const
|
|
1186
|
+
const legacyEntities = [];
|
|
731
1187
|
for (let lid = 0; lid < ownedEntities.length; lid++) {
|
|
732
1188
|
const entityRaw = ownedEntities[lid];
|
|
733
1189
|
if (entityRaw === void 0) continue;
|
|
@@ -774,6 +1230,9 @@ function rootsToSceneAsset(registry, world, roots) {
|
|
|
774
1230
|
continue;
|
|
775
1231
|
}
|
|
776
1232
|
if (entityKind !== null) {
|
|
1233
|
+
if (!entityKind.isArray && typeof rawValue === "number" && rootRawSet.has(rawValue) && anchorEntities.has(rawValue)) {
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
777
1236
|
if (entityKind.isArray) {
|
|
778
1237
|
const arr = _isArrayLike(rawValue) ? _normalizeArray(rawValue) : rawValue;
|
|
779
1238
|
const mapped = [];
|
|
@@ -821,13 +1280,19 @@ function rootsToSceneAsset(registry, world, roots) {
|
|
|
821
1280
|
}
|
|
822
1281
|
if (Object.keys(fieldValues).length > 0) components[compName] = fieldValues;
|
|
823
1282
|
}
|
|
824
|
-
|
|
1283
|
+
legacyEntities.push({ localId: lid, components });
|
|
825
1284
|
}
|
|
826
|
-
return
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1285
|
+
return collectKeyedSceneAsset(
|
|
1286
|
+
world,
|
|
1287
|
+
registry,
|
|
1288
|
+
roots,
|
|
1289
|
+
visited,
|
|
1290
|
+
ownedEntities,
|
|
1291
|
+
legacyEntities,
|
|
1292
|
+
outMounts,
|
|
1293
|
+
nonRootAnchors,
|
|
1294
|
+
memberOrigin
|
|
1295
|
+
);
|
|
831
1296
|
}
|
|
832
1297
|
|
|
833
1298
|
export { createDevImportTransport, createRenderer, defaultAssetDecoderContributions, rootsToSceneAsset, serializeSceneAssetToPack, spriteAnimationTickSystem };
|