@relu-interactives/spatial-ecs 0.2.20 → 0.2.22
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/dist/{System-BjwOBx81.d.cts → System-CYWZ_Zx5.d.cts} +9 -4
- package/dist/{System-BjwOBx81.d.ts → System-CYWZ_Zx5.d.ts} +9 -4
- package/dist/{Video-B8yVI1tF.d.cts → Video-C1IOat7L.d.ts} +38 -9
- package/dist/{Video-B9z5AtIf.d.ts → Video-ppAXaKt0.d.cts} +38 -9
- package/dist/{chunk-HUHN6IFD.js → chunk-52CHDPRQ.js} +118 -92
- package/dist/chunk-52CHDPRQ.js.map +1 -0
- package/dist/{chunk-67MFQDHX.js → chunk-GZ2NKSMV.js} +609 -90
- package/dist/chunk-GZ2NKSMV.js.map +1 -0
- package/dist/{chunk-Z6OMYEXU.js → chunk-JHCPRVBC.js} +34 -5
- package/dist/chunk-JHCPRVBC.js.map +1 -0
- package/dist/{chunk-DY4ETMP2.js → chunk-WKGCC7YL.js} +3 -3
- package/dist/{chunk-DY4ETMP2.js.map → chunk-WKGCC7YL.js.map} +1 -1
- package/dist/components/index.cjs +31 -2
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +3 -3
- package/dist/components/index.d.ts +3 -3
- package/dist/components/index.js +1 -1
- package/dist/docs/guide/authoring-a-behaviour.md +3 -40
- package/dist/docs/guide/authoring-a-script-object.md +102 -0
- package/dist/docs/guide/behaviour-lifecycle.md +4 -4
- package/dist/docs/guide/prefabs.md +24 -5
- package/dist/docs/guide/spawning/script-object.md +36 -0
- package/dist/docs/guide/systems/_sidebar.json +4 -0
- package/dist/docs/guide/systems/script-behaviour-system.md +1 -17
- package/dist/docs/guide/systems/script-object-system.md +44 -0
- package/dist/factories/index.cjs +164 -117
- package/dist/factories/index.cjs.map +1 -1
- package/dist/factories/index.d.cts +5 -3
- package/dist/factories/index.d.ts +5 -3
- package/dist/factories/index.js +3 -3
- package/dist/{index-LHLKpJhZ.d.cts → index-Cu2Pt7wN.d.cts} +33 -14
- package/dist/{index-BBI2YdCu.d.ts → index-DdiWu1b6.d.ts} +33 -14
- package/dist/index.cjs +1132 -302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +219 -32
- package/dist/index.d.ts +219 -32
- package/dist/index.js +254 -11
- package/dist/index.js.map +1 -1
- package/dist/systems/index.cjs +429 -43
- package/dist/systems/index.cjs.map +1 -1
- package/dist/systems/index.d.cts +44 -3
- package/dist/systems/index.d.ts +44 -3
- package/dist/systems/index.js +3 -3
- package/dist/types.d.cts +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/worldSnapshotUtils.d.cts +1 -1
- package/dist/worldSnapshotUtils.d.ts +1 -1
- package/package.json +1 -1
- package/dist/chunk-67MFQDHX.js.map +0 -1
- package/dist/chunk-HUHN6IFD.js.map +0 -1
- package/dist/chunk-Z6OMYEXU.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveDracoDecoderPath, applyTransform } from './chunk-
|
|
2
|
-
import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ParentId, ScriptComponent, InstanceSlotComponent, Name, ImageComponent, SpriteComponent, VideoComponent, AudioComponent, ImageTarget, Selectable, PrefabNode, PrefabInstance } from './chunk-
|
|
1
|
+
import { resolveDracoDecoderPath, applyTransform, SHARED_MODEL_RESOURCE_FLAG } from './chunk-WKGCC7YL.js';
|
|
2
|
+
import { AnimationComponent, ModelComponent, CameraComponent, Object3DRef, Environment, Postprocessing, TransformComponent, PhysicsComponent, LightComponent, MaterialComponent, DEFAULT_MESH_GEOMETRY_PARAMETERS, MeshGeometryComponent, InstancedMeshComponent, ParentId, ScriptComponent, ScriptObjectComponent, InstanceSlotComponent, Name, ImageComponent, SpriteComponent, VideoComponent, AudioComponent, ImageTarget, Selectable, PrefabNode, PrefabInstance } from './chunk-JHCPRVBC.js';
|
|
3
3
|
import { __name } from './chunk-OY7ZODZP.js';
|
|
4
4
|
import * as THREE7 from 'three';
|
|
5
5
|
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
|
|
@@ -2741,6 +2741,10 @@ function buildComponentValueMaps(snapshot) {
|
|
|
2741
2741
|
animationValues: readByComponent(snapshot.components, "AnimationComponent"),
|
|
2742
2742
|
imageTargetAnchorValues: readByComponent(snapshot.components, "ImageTargetAnchor"),
|
|
2743
2743
|
scriptValues: readByComponent(snapshot.components, "ScriptComponent"),
|
|
2744
|
+
scriptObjectValues: readByComponent(
|
|
2745
|
+
snapshot.components,
|
|
2746
|
+
"ScriptObjectComponent"
|
|
2747
|
+
),
|
|
2744
2748
|
instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
|
|
2745
2749
|
instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
|
|
2746
2750
|
prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
|
|
@@ -2858,6 +2862,14 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
2858
2862
|
new ScriptComponent(entries)
|
|
2859
2863
|
);
|
|
2860
2864
|
}
|
|
2865
|
+
const sourceScriptObject = asRecord(values.scriptObjectValues.get(sourceEntityId));
|
|
2866
|
+
if (sourceScriptObject) {
|
|
2867
|
+
const soc = world.getComponent(targetEntityId, ScriptObjectComponent);
|
|
2868
|
+
const data = asRecord(sourceScriptObject.data);
|
|
2869
|
+
if (soc && data) {
|
|
2870
|
+
soc.data = remapEntityRefsInScriptData(data, idMap);
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2861
2873
|
{
|
|
2862
2874
|
const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
|
|
2863
2875
|
if (imComponent && imComponent.instanceEntityIds.length > 0) {
|
|
@@ -3410,7 +3422,13 @@ function restoreComponentState(world, objectManagementSystem, targetEntityId, so
|
|
|
3410
3422
|
) : [];
|
|
3411
3423
|
world.addComponent(
|
|
3412
3424
|
targetEntityId,
|
|
3413
|
-
new PrefabInstance(
|
|
3425
|
+
new PrefabInstance(
|
|
3426
|
+
sourcePrefabInstance.url,
|
|
3427
|
+
overrides,
|
|
3428
|
+
// Preserve the placement identity; the constructor generates a
|
|
3429
|
+
// fresh one for legacy snapshots that predate instanceId.
|
|
3430
|
+
typeof sourcePrefabInstance.instanceId === "string" && sourcePrefabInstance.instanceId.length > 0 ? sourcePrefabInstance.instanceId : void 0
|
|
3431
|
+
)
|
|
3414
3432
|
);
|
|
3415
3433
|
}
|
|
3416
3434
|
}
|
|
@@ -3438,7 +3456,8 @@ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
|
3438
3456
|
"spotLight",
|
|
3439
3457
|
"areaLight",
|
|
3440
3458
|
"instancedMesh",
|
|
3441
|
-
"instanceSlot"
|
|
3459
|
+
"instanceSlot",
|
|
3460
|
+
"scriptObject"
|
|
3442
3461
|
]);
|
|
3443
3462
|
|
|
3444
3463
|
// core/hydration/hydrateWorld.ts
|
|
@@ -3540,6 +3559,16 @@ function buildEntityCreationPayload(sourceEntityId, kind, componentValues) {
|
|
|
3540
3559
|
};
|
|
3541
3560
|
}
|
|
3542
3561
|
}
|
|
3562
|
+
if (kind === "scriptObject") {
|
|
3563
|
+
const so = asRecord(componentValues.scriptObjectValues.get(sourceEntityId));
|
|
3564
|
+
if (so) {
|
|
3565
|
+
payload.options = {
|
|
3566
|
+
scriptUrl: typeof so.scriptUrl === "string" ? so.scriptUrl : null,
|
|
3567
|
+
className: typeof so.className === "string" ? so.className : null,
|
|
3568
|
+
enabled: typeof so.enabled === "boolean" ? so.enabled : true
|
|
3569
|
+
};
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3543
3572
|
return payload;
|
|
3544
3573
|
}
|
|
3545
3574
|
__name(buildEntityCreationPayload, "buildEntityCreationPayload");
|
|
@@ -3657,6 +3686,148 @@ function hydrateWorldFromSnapshot(snapshot, world, objectManagementSystem) {
|
|
|
3657
3686
|
}
|
|
3658
3687
|
__name(hydrateWorldFromSnapshot, "hydrateWorldFromSnapshot");
|
|
3659
3688
|
|
|
3689
|
+
// core/prefab/nodeKeys.ts
|
|
3690
|
+
var NODE_KEY_SEPARATOR = "/";
|
|
3691
|
+
var ADDED_NODE_MARKER_COMPONENT = "+node";
|
|
3692
|
+
var asRecord2 = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null, "asRecord");
|
|
3693
|
+
var readBlock = /* @__PURE__ */ __name((snapshot, component) => {
|
|
3694
|
+
const map = /* @__PURE__ */ new Map();
|
|
3695
|
+
const block = snapshot.components.find((b) => b.component === component);
|
|
3696
|
+
for (const entry of block?.entries ?? []) {
|
|
3697
|
+
const record = asRecord2(entry.value);
|
|
3698
|
+
if (record) {
|
|
3699
|
+
map.set(entry.entityId, record);
|
|
3700
|
+
}
|
|
3701
|
+
}
|
|
3702
|
+
return map;
|
|
3703
|
+
}, "readBlock");
|
|
3704
|
+
var fallbackInstanceId = /* @__PURE__ */ __name((entityId) => `e${entityId}`, "fallbackInstanceId");
|
|
3705
|
+
function buildNodeKeyMapsFromSnapshot(snapshot, options) {
|
|
3706
|
+
const parentValues = readBlock(snapshot, "ParentId");
|
|
3707
|
+
const nodeValues = readBlock(snapshot, "PrefabNode");
|
|
3708
|
+
const instanceValues = readBlock(snapshot, "PrefabInstance");
|
|
3709
|
+
const inDocument = new Set(snapshot.entities);
|
|
3710
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
3711
|
+
const rootIds = [];
|
|
3712
|
+
for (const entityId of snapshot.entities) {
|
|
3713
|
+
const parent = parentValues.get(entityId)?.value;
|
|
3714
|
+
if (typeof parent === "number" && inDocument.has(parent)) {
|
|
3715
|
+
const siblings = childrenByParent.get(parent);
|
|
3716
|
+
if (siblings) siblings.push(entityId);
|
|
3717
|
+
else childrenByParent.set(parent, [entityId]);
|
|
3718
|
+
} else {
|
|
3719
|
+
rootIds.push(entityId);
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
const scopeRoots = options?.scopeRootEntityId !== void 0 ? [options.scopeRootEntityId] : rootIds;
|
|
3723
|
+
const idToKey = /* @__PURE__ */ new Map();
|
|
3724
|
+
const keyToId = /* @__PURE__ */ new Map();
|
|
3725
|
+
const boundaryIds = /* @__PURE__ */ new Map();
|
|
3726
|
+
const scopeRootSet = new Set(scopeRoots);
|
|
3727
|
+
const queue = scopeRoots.map(
|
|
3728
|
+
(entityId) => ({ entityId, prefix: "" })
|
|
3729
|
+
);
|
|
3730
|
+
while (queue.length > 0) {
|
|
3731
|
+
const { entityId, prefix } = queue.shift();
|
|
3732
|
+
const instance = instanceValues.get(entityId);
|
|
3733
|
+
const isBoundary = Boolean(
|
|
3734
|
+
instance && typeof instance.url === "string" && !scopeRootSet.has(entityId)
|
|
3735
|
+
);
|
|
3736
|
+
let ownPrefix = prefix;
|
|
3737
|
+
let childPrefix = prefix;
|
|
3738
|
+
if (isBoundary && instance) {
|
|
3739
|
+
const instanceId = typeof instance.instanceId === "string" && instance.instanceId.length > 0 ? instance.instanceId : fallbackInstanceId(entityId);
|
|
3740
|
+
childPrefix = `${prefix}${instanceId}${NODE_KEY_SEPARATOR}`;
|
|
3741
|
+
ownPrefix = childPrefix;
|
|
3742
|
+
boundaryIds.set(entityId, {
|
|
3743
|
+
url: instance.url,
|
|
3744
|
+
instanceId
|
|
3745
|
+
});
|
|
3746
|
+
}
|
|
3747
|
+
const nodeId = nodeValues.get(entityId)?.nodeId;
|
|
3748
|
+
if (typeof nodeId === "string" && nodeId.length > 0) {
|
|
3749
|
+
const key = `${ownPrefix}${nodeId}`;
|
|
3750
|
+
idToKey.set(entityId, key);
|
|
3751
|
+
keyToId.set(key, entityId);
|
|
3752
|
+
}
|
|
3753
|
+
for (const child of childrenByParent.get(entityId) ?? []) {
|
|
3754
|
+
queue.push({ entityId: child, prefix: childPrefix });
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
const rootEntityId = scopeRoots[0];
|
|
3758
|
+
const rootNodeId = rootEntityId !== void 0 ? nodeValues.get(rootEntityId)?.nodeId : void 0;
|
|
3759
|
+
return {
|
|
3760
|
+
idToKey,
|
|
3761
|
+
keyToId,
|
|
3762
|
+
rootKey: typeof rootNodeId === "string" && rootNodeId.length > 0 ? rootNodeId : null,
|
|
3763
|
+
boundaryIds
|
|
3764
|
+
};
|
|
3765
|
+
}
|
|
3766
|
+
__name(buildNodeKeyMapsFromSnapshot, "buildNodeKeyMapsFromSnapshot");
|
|
3767
|
+
function collectSnapshotSubtreeIds(snapshot, rootEntityId) {
|
|
3768
|
+
const parentValues = readBlock(snapshot, "ParentId");
|
|
3769
|
+
const childrenByParent = /* @__PURE__ */ new Map();
|
|
3770
|
+
for (const entityId of snapshot.entities) {
|
|
3771
|
+
const parent = parentValues.get(entityId)?.value;
|
|
3772
|
+
if (typeof parent === "number") {
|
|
3773
|
+
const siblings = childrenByParent.get(parent);
|
|
3774
|
+
if (siblings) siblings.push(entityId);
|
|
3775
|
+
else childrenByParent.set(parent, [entityId]);
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
const ordered = [];
|
|
3779
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3780
|
+
const queue = [rootEntityId];
|
|
3781
|
+
while (queue.length > 0) {
|
|
3782
|
+
const entityId = queue.shift();
|
|
3783
|
+
if (seen.has(entityId)) continue;
|
|
3784
|
+
seen.add(entityId);
|
|
3785
|
+
ordered.push(entityId);
|
|
3786
|
+
queue.push(...childrenByParent.get(entityId) ?? []);
|
|
3787
|
+
}
|
|
3788
|
+
return ordered;
|
|
3789
|
+
}
|
|
3790
|
+
__name(collectSnapshotSubtreeIds, "collectSnapshotSubtreeIds");
|
|
3791
|
+
function findTopLevelNestedRegions(snapshot) {
|
|
3792
|
+
const parentValues = readBlock(snapshot, "ParentId");
|
|
3793
|
+
const instanceValues = readBlock(snapshot, "PrefabInstance");
|
|
3794
|
+
const inDocument = new Set(snapshot.entities);
|
|
3795
|
+
const roots = new Set(
|
|
3796
|
+
snapshot.entities.filter((entityId) => {
|
|
3797
|
+
const parent = parentValues.get(entityId)?.value;
|
|
3798
|
+
return typeof parent !== "number" || !inDocument.has(parent);
|
|
3799
|
+
})
|
|
3800
|
+
);
|
|
3801
|
+
const regions = [];
|
|
3802
|
+
for (const [entityId, instance] of instanceValues) {
|
|
3803
|
+
if (roots.has(entityId)) continue;
|
|
3804
|
+
if (typeof instance.url !== "string" || instance.url.length === 0) continue;
|
|
3805
|
+
let ancestor = parentValues.get(entityId)?.value;
|
|
3806
|
+
let nestedDeeper = false;
|
|
3807
|
+
let hops = 0;
|
|
3808
|
+
while (typeof ancestor === "number" && hops < 512) {
|
|
3809
|
+
if (instanceValues.has(ancestor) && !roots.has(ancestor)) {
|
|
3810
|
+
nestedDeeper = true;
|
|
3811
|
+
break;
|
|
3812
|
+
}
|
|
3813
|
+
ancestor = parentValues.get(ancestor)?.value;
|
|
3814
|
+
hops += 1;
|
|
3815
|
+
}
|
|
3816
|
+
if (nestedDeeper) continue;
|
|
3817
|
+
regions.push({
|
|
3818
|
+
rootEntityId: entityId,
|
|
3819
|
+
url: instance.url,
|
|
3820
|
+
instanceId: typeof instance.instanceId === "string" && instance.instanceId.length > 0 ? instance.instanceId : fallbackInstanceId(entityId),
|
|
3821
|
+
overrides: Array.isArray(instance.overrides) ? instance.overrides.filter(
|
|
3822
|
+
(entry) => typeof entry === "string"
|
|
3823
|
+
) : []
|
|
3824
|
+
});
|
|
3825
|
+
}
|
|
3826
|
+
regions.sort((a, b) => a.rootEntityId - b.rootEntityId);
|
|
3827
|
+
return regions;
|
|
3828
|
+
}
|
|
3829
|
+
__name(findTopLevelNestedRegions, "findTopLevelNestedRegions");
|
|
3830
|
+
|
|
3660
3831
|
// core/prefab/overrides.ts
|
|
3661
3832
|
var OVERRIDE_DIFF_EXCLUDED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
3662
3833
|
"PrefabNode",
|
|
@@ -3670,10 +3841,10 @@ var OVERRIDE_ROOT_EXCLUDED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
|
3670
3841
|
"Name",
|
|
3671
3842
|
"ParentId"
|
|
3672
3843
|
]);
|
|
3673
|
-
var
|
|
3844
|
+
var asRecord3 = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null, "asRecord");
|
|
3674
3845
|
var clone = /* @__PURE__ */ __name((value) => value === void 0 ? value : structuredClone(value), "clone");
|
|
3675
3846
|
var isNodeRef = /* @__PURE__ */ __name((value) => {
|
|
3676
|
-
const record =
|
|
3847
|
+
const record = asRecord3(value);
|
|
3677
3848
|
return Boolean(
|
|
3678
3849
|
record && typeof record.$node === "string" && Object.keys(record).length === 1
|
|
3679
3850
|
);
|
|
@@ -3685,7 +3856,7 @@ function findSnapshotRootEntityIds(snapshot) {
|
|
|
3685
3856
|
);
|
|
3686
3857
|
const parentByEntity = /* @__PURE__ */ new Map();
|
|
3687
3858
|
for (const entry of parentBlock?.entries ?? []) {
|
|
3688
|
-
parentByEntity.set(entry.entityId,
|
|
3859
|
+
parentByEntity.set(entry.entityId, asRecord3(entry.value)?.value ?? null);
|
|
3689
3860
|
}
|
|
3690
3861
|
return snapshot.entities.filter(
|
|
3691
3862
|
(entityId) => typeof parentByEntity.get(entityId) !== "number"
|
|
@@ -3699,7 +3870,7 @@ function buildNodeMapsFromSnapshot(snapshot) {
|
|
|
3699
3870
|
(block) => block.component === "PrefabNode"
|
|
3700
3871
|
);
|
|
3701
3872
|
for (const entry of nodeBlock?.entries ?? []) {
|
|
3702
|
-
const nodeId =
|
|
3873
|
+
const nodeId = asRecord3(entry.value)?.nodeId;
|
|
3703
3874
|
if (typeof nodeId === "string" && nodeId.length > 0) {
|
|
3704
3875
|
idToNode.set(entry.entityId, nodeId);
|
|
3705
3876
|
nodeToId.set(nodeId, entry.entityId);
|
|
@@ -3729,9 +3900,36 @@ var toRefOrRaw = /* @__PURE__ */ __name((id, idToNode) => {
|
|
|
3729
3900
|
const nodeId = idToNode.get(id);
|
|
3730
3901
|
return nodeId !== void 0 ? makeNodeRef(nodeId) : id;
|
|
3731
3902
|
}, "toRefOrRaw");
|
|
3903
|
+
function canonicalizeScriptDataFields(data, idToNode) {
|
|
3904
|
+
const canonicalData = {};
|
|
3905
|
+
for (const [key, fieldValue] of Object.entries(data)) {
|
|
3906
|
+
const field = asRecord3(fieldValue);
|
|
3907
|
+
if (field?.type === "entity" && typeof field.value === "number") {
|
|
3908
|
+
canonicalData[key] = {
|
|
3909
|
+
...field,
|
|
3910
|
+
value: toRefOrRaw(field.value, idToNode)
|
|
3911
|
+
};
|
|
3912
|
+
continue;
|
|
3913
|
+
}
|
|
3914
|
+
const componentRef = asRecord3(field?.value);
|
|
3915
|
+
if (field?.type === "component" && componentRef && typeof componentRef.entityId === "number") {
|
|
3916
|
+
canonicalData[key] = {
|
|
3917
|
+
...field,
|
|
3918
|
+
value: {
|
|
3919
|
+
...componentRef,
|
|
3920
|
+
entityId: toRefOrRaw(componentRef.entityId, idToNode)
|
|
3921
|
+
}
|
|
3922
|
+
};
|
|
3923
|
+
continue;
|
|
3924
|
+
}
|
|
3925
|
+
canonicalData[key] = fieldValue;
|
|
3926
|
+
}
|
|
3927
|
+
return canonicalData;
|
|
3928
|
+
}
|
|
3929
|
+
__name(canonicalizeScriptDataFields, "canonicalizeScriptDataFields");
|
|
3732
3930
|
function canonicalizeComponentValue(componentName, value, idToNode) {
|
|
3733
3931
|
const cloned = clone(value);
|
|
3734
|
-
const record =
|
|
3932
|
+
const record = asRecord3(cloned);
|
|
3735
3933
|
if (!record) {
|
|
3736
3934
|
return cloned;
|
|
3737
3935
|
}
|
|
@@ -3750,43 +3948,27 @@ function canonicalizeComponentValue(componentName, value, idToNode) {
|
|
|
3750
3948
|
const entries = Array.isArray(record.entries) ? record.entries : [];
|
|
3751
3949
|
return {
|
|
3752
3950
|
entries: entries.map((rawEntry) => {
|
|
3753
|
-
const entry =
|
|
3951
|
+
const entry = asRecord3(rawEntry);
|
|
3754
3952
|
if (!entry) {
|
|
3755
3953
|
return rawEntry;
|
|
3756
3954
|
}
|
|
3757
|
-
const data = asRecord2(entry.data) ?? {};
|
|
3758
|
-
const canonicalData = {};
|
|
3759
|
-
for (const [key, fieldValue] of Object.entries(data)) {
|
|
3760
|
-
const field = asRecord2(fieldValue);
|
|
3761
|
-
if (field?.type === "entity" && typeof field.value === "number") {
|
|
3762
|
-
canonicalData[key] = {
|
|
3763
|
-
...field,
|
|
3764
|
-
value: toRefOrRaw(field.value, idToNode)
|
|
3765
|
-
};
|
|
3766
|
-
continue;
|
|
3767
|
-
}
|
|
3768
|
-
const componentRef = asRecord2(field?.value);
|
|
3769
|
-
if (field?.type === "component" && componentRef && typeof componentRef.entityId === "number") {
|
|
3770
|
-
canonicalData[key] = {
|
|
3771
|
-
...field,
|
|
3772
|
-
value: {
|
|
3773
|
-
...componentRef,
|
|
3774
|
-
entityId: toRefOrRaw(componentRef.entityId, idToNode)
|
|
3775
|
-
}
|
|
3776
|
-
};
|
|
3777
|
-
continue;
|
|
3778
|
-
}
|
|
3779
|
-
canonicalData[key] = fieldValue;
|
|
3780
|
-
}
|
|
3781
3955
|
return {
|
|
3782
3956
|
className: typeof entry.className === "string" ? entry.className : "",
|
|
3783
3957
|
scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
|
|
3784
3958
|
enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
|
|
3785
|
-
data:
|
|
3959
|
+
data: canonicalizeScriptDataFields(asRecord3(entry.data) ?? {}, idToNode)
|
|
3786
3960
|
};
|
|
3787
3961
|
})
|
|
3788
3962
|
};
|
|
3789
3963
|
}
|
|
3964
|
+
if (componentName === "ScriptObjectComponent") {
|
|
3965
|
+
return {
|
|
3966
|
+
scriptUrl: typeof record.scriptUrl === "string" ? record.scriptUrl : null,
|
|
3967
|
+
className: typeof record.className === "string" ? record.className : null,
|
|
3968
|
+
enabled: typeof record.enabled === "boolean" ? record.enabled : true,
|
|
3969
|
+
data: canonicalizeScriptDataFields(asRecord3(record.data) ?? {}, idToNode)
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3790
3972
|
if (componentName === "InstancedMeshComponent") {
|
|
3791
3973
|
if (Array.isArray(record.instanceEntityIds)) {
|
|
3792
3974
|
record.instanceEntityIds = record.instanceEntityIds.map(
|
|
@@ -3811,7 +3993,7 @@ function decanonicalizeComponentValue(value, nodeToId) {
|
|
|
3811
3993
|
if (Array.isArray(value)) {
|
|
3812
3994
|
return value.map((item) => decanonicalizeComponentValue(item, nodeToId));
|
|
3813
3995
|
}
|
|
3814
|
-
const record =
|
|
3996
|
+
const record = asRecord3(value);
|
|
3815
3997
|
if (record) {
|
|
3816
3998
|
const result = {};
|
|
3817
3999
|
for (const [key, item] of Object.entries(record)) {
|
|
@@ -3914,15 +4096,20 @@ function collectDiffPaths(base, current, prefix = "", out = []) {
|
|
|
3914
4096
|
return out;
|
|
3915
4097
|
}
|
|
3916
4098
|
__name(collectDiffPaths, "collectDiffPaths");
|
|
3917
|
-
function computeInstanceOverrides(baseSnapshot, instanceSnapshot) {
|
|
3918
|
-
const baseMaps =
|
|
3919
|
-
const instanceMaps =
|
|
4099
|
+
function computeInstanceOverrides(baseSnapshot, instanceSnapshot, options) {
|
|
4100
|
+
const baseMaps = buildNodeKeyMapsFromSnapshot(baseSnapshot);
|
|
4101
|
+
const instanceMaps = buildNodeKeyMapsFromSnapshot(instanceSnapshot);
|
|
3920
4102
|
const baseByEntity = indexSnapshotByEntity(baseSnapshot);
|
|
3921
4103
|
const instanceByEntity = indexSnapshotByEntity(instanceSnapshot);
|
|
3922
4104
|
const overrides = [];
|
|
3923
|
-
for (const [
|
|
3924
|
-
const baseEntityId = baseMaps.
|
|
4105
|
+
for (const [nodeKey, instanceEntityId] of instanceMaps.keyToId) {
|
|
4106
|
+
const baseEntityId = baseMaps.keyToId.get(nodeKey);
|
|
3925
4107
|
if (baseEntityId === void 0) {
|
|
4108
|
+
if (options?.emitAdditionMarkers) {
|
|
4109
|
+
overrides.push(
|
|
4110
|
+
encodeOverride(nodeKey, ADDED_NODE_MARKER_COMPONENT, "")
|
|
4111
|
+
);
|
|
4112
|
+
}
|
|
3926
4113
|
continue;
|
|
3927
4114
|
}
|
|
3928
4115
|
const baseComponents = baseByEntity.get(baseEntityId);
|
|
@@ -3930,7 +4117,7 @@ function computeInstanceOverrides(baseSnapshot, instanceSnapshot) {
|
|
|
3930
4117
|
if (!baseComponents) {
|
|
3931
4118
|
continue;
|
|
3932
4119
|
}
|
|
3933
|
-
const isRoot =
|
|
4120
|
+
const isRoot = nodeKey === baseMaps.rootKey;
|
|
3934
4121
|
for (const [componentName, baseRaw] of baseComponents) {
|
|
3935
4122
|
if (OVERRIDE_DIFF_EXCLUDED_COMPONENTS.has(componentName)) {
|
|
3936
4123
|
continue;
|
|
@@ -3945,15 +4132,15 @@ function computeInstanceOverrides(baseSnapshot, instanceSnapshot) {
|
|
|
3945
4132
|
const baseCanonical = canonicalizeComponentValue(
|
|
3946
4133
|
componentName,
|
|
3947
4134
|
baseRaw,
|
|
3948
|
-
baseMaps.
|
|
4135
|
+
baseMaps.idToKey
|
|
3949
4136
|
);
|
|
3950
4137
|
const instanceCanonical = canonicalizeComponentValue(
|
|
3951
4138
|
componentName,
|
|
3952
4139
|
instanceRaw,
|
|
3953
|
-
instanceMaps.
|
|
4140
|
+
instanceMaps.idToKey
|
|
3954
4141
|
);
|
|
3955
4142
|
for (const path of collectDiffPaths(baseCanonical, instanceCanonical)) {
|
|
3956
|
-
overrides.push(encodeOverride(
|
|
4143
|
+
overrides.push(encodeOverride(nodeKey, componentName, path));
|
|
3957
4144
|
}
|
|
3958
4145
|
}
|
|
3959
4146
|
}
|
|
@@ -3967,7 +4154,7 @@ function getAtPath(value, tokens) {
|
|
|
3967
4154
|
if (Array.isArray(cursor)) {
|
|
3968
4155
|
cursor = cursor[Number(token)];
|
|
3969
4156
|
} else {
|
|
3970
|
-
const record =
|
|
4157
|
+
const record = asRecord3(cursor);
|
|
3971
4158
|
if (!record) {
|
|
3972
4159
|
return void 0;
|
|
3973
4160
|
}
|
|
@@ -3987,7 +4174,7 @@ function setAtPath(target, tokens, value) {
|
|
|
3987
4174
|
if (Array.isArray(cursor)) {
|
|
3988
4175
|
cursor = cursor[Number(token)];
|
|
3989
4176
|
} else {
|
|
3990
|
-
const record =
|
|
4177
|
+
const record = asRecord3(cursor);
|
|
3991
4178
|
if (!record) {
|
|
3992
4179
|
return;
|
|
3993
4180
|
}
|
|
@@ -4001,7 +4188,7 @@ function setAtPath(target, tokens, value) {
|
|
|
4001
4188
|
if (Array.isArray(cursor)) {
|
|
4002
4189
|
cursor[Number(last)] = value;
|
|
4003
4190
|
} else {
|
|
4004
|
-
const record =
|
|
4191
|
+
const record = asRecord3(cursor);
|
|
4005
4192
|
if (record) {
|
|
4006
4193
|
if (value === void 0) {
|
|
4007
4194
|
delete record[last];
|
|
@@ -4033,15 +4220,20 @@ __name(mergeComponentValue, "mergeComponentValue");
|
|
|
4033
4220
|
var INSTANTIATE_EXCLUDED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
4034
4221
|
"Environment",
|
|
4035
4222
|
"Postprocessing",
|
|
4036
|
-
"SelectionTransformState"
|
|
4037
|
-
"PrefabInstance"
|
|
4223
|
+
"SelectionTransformState"
|
|
4038
4224
|
]);
|
|
4039
4225
|
function instantiateSubtree(world, objectManagementSystem, snapshot) {
|
|
4226
|
+
const snapshotRootIds = new Set(findSnapshotRootEntityIds(snapshot));
|
|
4040
4227
|
const safeSnapshot = {
|
|
4041
4228
|
entities: snapshot.entities,
|
|
4042
|
-
components: snapshot.components.filter(
|
|
4043
|
-
(block) =>
|
|
4044
|
-
|
|
4229
|
+
components: snapshot.components.filter((block) => !INSTANTIATE_EXCLUDED_COMPONENTS.has(block.component)).map(
|
|
4230
|
+
(block) => block.component === "PrefabInstance" ? {
|
|
4231
|
+
component: block.component,
|
|
4232
|
+
entries: block.entries.filter(
|
|
4233
|
+
(entry) => !snapshotRootIds.has(entry.entityId)
|
|
4234
|
+
)
|
|
4235
|
+
} : block
|
|
4236
|
+
).filter((block) => block.entries.length > 0)
|
|
4045
4237
|
};
|
|
4046
4238
|
const result = hydrateWorldFromSnapshotDetailed(
|
|
4047
4239
|
safeSnapshot,
|
|
@@ -4061,6 +4253,11 @@ __name(instantiateSubtree, "instantiateSubtree");
|
|
|
4061
4253
|
|
|
4062
4254
|
// core/prefab/types.ts
|
|
4063
4255
|
var PREFAB_FILE_VERSION = 1;
|
|
4256
|
+
var PREFAB_FILE_VERSION_NESTED = 2;
|
|
4257
|
+
function prefabFileVersionFor(snapshot) {
|
|
4258
|
+
return findTopLevelNestedRegions(snapshot).length > 0 ? PREFAB_FILE_VERSION_NESTED : PREFAB_FILE_VERSION;
|
|
4259
|
+
}
|
|
4260
|
+
__name(prefabFileVersionFor, "prefabFileVersionFor");
|
|
4064
4261
|
var isRecord = /* @__PURE__ */ __name((value) => value !== null && typeof value === "object" && !Array.isArray(value), "isRecord");
|
|
4065
4262
|
function parsePrefabAsset(json) {
|
|
4066
4263
|
if (!isRecord(json)) {
|
|
@@ -4474,22 +4671,14 @@ var _Behaviour = class _Behaviour {
|
|
|
4474
4671
|
/**
|
|
4475
4672
|
* Called once before the first {@link Behaviour.onUpdate}. Override to
|
|
4476
4673
|
* default and validate {@link Behaviour.data}, cache references, or set
|
|
4477
|
-
* initial state.
|
|
4478
|
-
*
|
|
4479
|
-
* @remarks
|
|
4480
|
-
* Also called in editor mode when `executeInEditor` is `true` on the script
|
|
4481
|
-
* entry.
|
|
4674
|
+
* initial state. Runs at preview/runtime only — never in the editor.
|
|
4482
4675
|
*/
|
|
4483
4676
|
init() {
|
|
4484
4677
|
}
|
|
4485
4678
|
/**
|
|
4486
4679
|
* Called every frame while the script is enabled. Override with the
|
|
4487
|
-
* script's main per-frame logic.
|
|
4488
|
-
*
|
|
4489
|
-
* @remarks
|
|
4490
|
-
* Also called every frame in editor mode when `executeInEditor` is `true`.
|
|
4491
|
-
* Access the Three.js scene with `this.world.getScene()` for editor-only
|
|
4492
|
-
* rendering work such as custom shaders or procedural geometry.
|
|
4680
|
+
* script's main per-frame logic. Runs at preview/runtime only — never in the
|
|
4681
|
+
* editor (use {@link ScriptObject} for editor-visible visuals).
|
|
4493
4682
|
*/
|
|
4494
4683
|
onUpdate() {
|
|
4495
4684
|
}
|
|
@@ -4528,7 +4717,14 @@ __name(_Behaviour, "Behaviour");
|
|
|
4528
4717
|
_Behaviour.__reluBehaviourClass = true;
|
|
4529
4718
|
var Behaviour = _Behaviour;
|
|
4530
4719
|
|
|
4531
|
-
// core/systems/
|
|
4720
|
+
// core/systems/scriptShared.ts
|
|
4721
|
+
async function defaultModuleLoader(scriptUrl) {
|
|
4722
|
+
return await import(
|
|
4723
|
+
/* webpackIgnore: true */
|
|
4724
|
+
scriptUrl
|
|
4725
|
+
);
|
|
4726
|
+
}
|
|
4727
|
+
__name(defaultModuleLoader, "defaultModuleLoader");
|
|
4532
4728
|
function toErrorMessage(error) {
|
|
4533
4729
|
const sanitize = /* @__PURE__ */ __name((value) => value.replace(/localasset:\/\/[^/]+\//g, "localasset://").replace(/\/Users\/[^\s)]+/g, "[local path]"), "sanitize");
|
|
4534
4730
|
if (error instanceof Error && error.message) {
|
|
@@ -4540,26 +4736,22 @@ function toErrorMessage(error) {
|
|
|
4540
4736
|
return "Unknown script error.";
|
|
4541
4737
|
}
|
|
4542
4738
|
__name(toErrorMessage, "toErrorMessage");
|
|
4543
|
-
function
|
|
4544
|
-
return `${entityId}:${scriptUrl}:${className}`;
|
|
4545
|
-
}
|
|
4546
|
-
__name(buildInstanceKey, "buildInstanceKey");
|
|
4547
|
-
function resolveBehaviourCtor(moduleValue, className) {
|
|
4739
|
+
function resolveScriptCtor(moduleValue, className, options) {
|
|
4548
4740
|
const named = moduleValue[className];
|
|
4549
4741
|
const fallback = moduleValue.default;
|
|
4550
4742
|
const candidate = typeof named === "function" ? named : typeof fallback === "function" ? fallback : null;
|
|
4551
4743
|
if (!candidate) {
|
|
4552
4744
|
return null;
|
|
4553
4745
|
}
|
|
4554
|
-
if (!(candidate.prototype instanceof
|
|
4555
|
-
const
|
|
4556
|
-
if (!
|
|
4746
|
+
if (!(candidate.prototype instanceof options.baseClass)) {
|
|
4747
|
+
const marker = candidate[options.markerKey];
|
|
4748
|
+
if (!marker) {
|
|
4557
4749
|
return null;
|
|
4558
4750
|
}
|
|
4559
4751
|
}
|
|
4560
4752
|
return candidate;
|
|
4561
4753
|
}
|
|
4562
|
-
__name(
|
|
4754
|
+
__name(resolveScriptCtor, "resolveScriptCtor");
|
|
4563
4755
|
function normalizeScriptData(value) {
|
|
4564
4756
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
4565
4757
|
}
|
|
@@ -4641,8 +4833,8 @@ function resolveInputData(world, rawData) {
|
|
|
4641
4833
|
return resolved;
|
|
4642
4834
|
}
|
|
4643
4835
|
__name(resolveInputData, "resolveInputData");
|
|
4644
|
-
function serializeDataForStorage(rawData,
|
|
4645
|
-
const result = { ...
|
|
4836
|
+
function serializeDataForStorage(rawData, instanceData) {
|
|
4837
|
+
const result = { ...instanceData };
|
|
4646
4838
|
for (const [key, rawValue] of Object.entries(rawData)) {
|
|
4647
4839
|
if (isRawEntityInput(rawValue) || isRawComponentInput(rawValue)) {
|
|
4648
4840
|
result[key] = rawValue;
|
|
@@ -4651,13 +4843,25 @@ function serializeDataForStorage(rawData, behaviourData) {
|
|
|
4651
4843
|
return result;
|
|
4652
4844
|
}
|
|
4653
4845
|
__name(serializeDataForStorage, "serializeDataForStorage");
|
|
4846
|
+
|
|
4847
|
+
// core/systems/ScriptBehaviourSystem.ts
|
|
4848
|
+
function buildInstanceKey(entityId, scriptUrl, className) {
|
|
4849
|
+
return `${entityId}:${scriptUrl}:${className}`;
|
|
4850
|
+
}
|
|
4851
|
+
__name(buildInstanceKey, "buildInstanceKey");
|
|
4852
|
+
function resolveBehaviourCtor(moduleValue, className) {
|
|
4853
|
+
return resolveScriptCtor(moduleValue, className, {
|
|
4854
|
+
baseClass: Behaviour,
|
|
4855
|
+
markerKey: "__reluBehaviourClass"
|
|
4856
|
+
});
|
|
4857
|
+
}
|
|
4858
|
+
__name(resolveBehaviourCtor, "resolveBehaviourCtor");
|
|
4654
4859
|
function normalizeEntry(value, fallbackEntityId) {
|
|
4655
4860
|
return {
|
|
4656
4861
|
entityId: typeof value?.entityId === "number" ? value.entityId : fallbackEntityId,
|
|
4657
4862
|
className: typeof value?.className === "string" ? value.className : "",
|
|
4658
4863
|
scriptUrl: typeof value?.scriptUrl === "string" ? value.scriptUrl : "",
|
|
4659
4864
|
enabled: typeof value?.enabled === "boolean" ? value.enabled : true,
|
|
4660
|
-
executeInEditor: typeof value?.executeInEditor === "boolean" ? value.executeInEditor : false,
|
|
4661
4865
|
data: normalizeScriptData(value?.data),
|
|
4662
4866
|
runtimeState: value?.runtimeState === "idle" || value?.runtimeState === "loading" || value?.runtimeState === "ready" || value?.runtimeState === "error" ? value.runtimeState : void 0,
|
|
4663
4867
|
runtimeMessage: typeof value?.runtimeMessage === "string" ? value.runtimeMessage : void 0
|
|
@@ -4680,13 +4884,6 @@ function writeScriptEntries(component, entries) {
|
|
|
4680
4884
|
}
|
|
4681
4885
|
}
|
|
4682
4886
|
__name(writeScriptEntries, "writeScriptEntries");
|
|
4683
|
-
async function defaultModuleLoader(scriptUrl) {
|
|
4684
|
-
return await import(
|
|
4685
|
-
/* webpackIgnore: true */
|
|
4686
|
-
scriptUrl
|
|
4687
|
-
);
|
|
4688
|
-
}
|
|
4689
|
-
__name(defaultModuleLoader, "defaultModuleLoader");
|
|
4690
4887
|
var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
4691
4888
|
constructor(moduleLoader, selectionContext) {
|
|
4692
4889
|
this.instances = /* @__PURE__ */ new Map();
|
|
@@ -4802,11 +4999,11 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
4802
4999
|
let hasEnabledScript = false;
|
|
4803
5000
|
for (let entryIndex = 0; entryIndex < nextEntries.length; entryIndex += 1) {
|
|
4804
5001
|
const entry = nextEntries[entryIndex];
|
|
4805
|
-
const skipInEditor = world.isEditorMode()
|
|
5002
|
+
const skipInEditor = world.isEditorMode();
|
|
4806
5003
|
if (!entry.enabled || !entry.scriptUrl || skipInEditor) {
|
|
4807
5004
|
nextEntries[entryIndex] = {
|
|
4808
5005
|
...entry,
|
|
4809
|
-
runtimeState:
|
|
5006
|
+
runtimeState: "idle",
|
|
4810
5007
|
runtimeMessage: void 0
|
|
4811
5008
|
};
|
|
4812
5009
|
continue;
|
|
@@ -4993,7 +5190,7 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
4993
5190
|
const mergedData = mergeDataByCurrentDefaults(defaults, currentData);
|
|
4994
5191
|
const resolvedData = resolveInputData(world, mergedData);
|
|
4995
5192
|
behaviour.data = resolvedData;
|
|
4996
|
-
if (!world.isEditorMode()
|
|
5193
|
+
if (!world.isEditorMode()) {
|
|
4997
5194
|
behaviour.init();
|
|
4998
5195
|
}
|
|
4999
5196
|
liveEntries[entryIndex] = {
|
|
@@ -5021,6 +5218,328 @@ __name(_ScriptBehaviourSystem, "ScriptBehaviourSystem");
|
|
|
5021
5218
|
_ScriptBehaviourSystem.CLICK_THRESHOLD = 6;
|
|
5022
5219
|
var ScriptBehaviourSystem = _ScriptBehaviourSystem;
|
|
5023
5220
|
|
|
5221
|
+
// core/ScriptObject.ts
|
|
5222
|
+
var _ScriptObject = class _ScriptObject {
|
|
5223
|
+
/**
|
|
5224
|
+
* Engine-managed constructor. `ScriptObjectSystem` instantiates subclasses
|
|
5225
|
+
* with the owning world, the entity id, and the component's `data`. User code
|
|
5226
|
+
* should not call this directly.
|
|
5227
|
+
*/
|
|
5228
|
+
constructor(world, entityId, data) {
|
|
5229
|
+
/**
|
|
5230
|
+
* The script's data payload (the `ScriptObjectComponent.data`). Declare a
|
|
5231
|
+
* concrete shape on subclasses with `declare data: MyShape` for type safety.
|
|
5232
|
+
* Use the same typed input envelopes as Behaviours (`ColorInput`,
|
|
5233
|
+
* `SliderInput`, `EntityInput`, …) to get inspector fields.
|
|
5234
|
+
*/
|
|
5235
|
+
this.data = {};
|
|
5236
|
+
/**
|
|
5237
|
+
* The Object3D returned by {@link ScriptObject.build}. Assigned by
|
|
5238
|
+
* `ScriptObjectSystem` after `build()` runs; `null` until then.
|
|
5239
|
+
*/
|
|
5240
|
+
this.root = null;
|
|
5241
|
+
this.world = world;
|
|
5242
|
+
this.entityId = entityId;
|
|
5243
|
+
if (data) this.data = data;
|
|
5244
|
+
}
|
|
5245
|
+
/**
|
|
5246
|
+
* REQUIRED — build and return the visual root. Called once by
|
|
5247
|
+
* `ScriptObjectSystem` after construction. The returned object is attached
|
|
5248
|
+
* under the entity's Object3D (so it inherits the entity transform, selection
|
|
5249
|
+
* and visibility). Subclasses MUST override.
|
|
5250
|
+
*/
|
|
5251
|
+
build() {
|
|
5252
|
+
throw new Error("ScriptObject subclasses must implement build()");
|
|
5253
|
+
}
|
|
5254
|
+
};
|
|
5255
|
+
__name(_ScriptObject, "ScriptObject");
|
|
5256
|
+
/**
|
|
5257
|
+
* Static marker used by `ScriptObjectSystem` to detect `ScriptObject`
|
|
5258
|
+
* subclasses even when a bundler ships a second copy of the package into the
|
|
5259
|
+
* script blob (breaking `instanceof`). Do NOT override.
|
|
5260
|
+
*/
|
|
5261
|
+
_ScriptObject.__reluScriptObjectClass = true;
|
|
5262
|
+
var ScriptObject = _ScriptObject;
|
|
5263
|
+
|
|
5264
|
+
// core/systems/ScriptObjectSystem.ts
|
|
5265
|
+
var SCRIPT_OBJECT_ROOT_FLAG = "__scriptObjectRoot";
|
|
5266
|
+
function setInstanceRef(component, value) {
|
|
5267
|
+
Object.defineProperty(component, "instance", {
|
|
5268
|
+
value,
|
|
5269
|
+
writable: true,
|
|
5270
|
+
configurable: true,
|
|
5271
|
+
enumerable: false
|
|
5272
|
+
});
|
|
5273
|
+
}
|
|
5274
|
+
__name(setInstanceRef, "setInstanceRef");
|
|
5275
|
+
function disposeBuiltObject(root) {
|
|
5276
|
+
root.parent?.remove(root);
|
|
5277
|
+
root.traverse((node) => {
|
|
5278
|
+
const mesh = node;
|
|
5279
|
+
const geometry = mesh.geometry;
|
|
5280
|
+
if (geometry?.dispose && !geometry.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
|
|
5281
|
+
geometry.dispose();
|
|
5282
|
+
}
|
|
5283
|
+
const material = mesh.material;
|
|
5284
|
+
const materials = Array.isArray(material) ? material : material ? [material] : [];
|
|
5285
|
+
for (const mat of materials) {
|
|
5286
|
+
if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
|
|
5287
|
+
for (const value of Object.values(mat)) {
|
|
5288
|
+
if (value instanceof THREE7.Texture) value.dispose();
|
|
5289
|
+
}
|
|
5290
|
+
mat.dispose?.();
|
|
5291
|
+
}
|
|
5292
|
+
});
|
|
5293
|
+
}
|
|
5294
|
+
__name(disposeBuiltObject, "disposeBuiltObject");
|
|
5295
|
+
var _ScriptObjectSystem = class _ScriptObjectSystem {
|
|
5296
|
+
constructor(moduleLoader) {
|
|
5297
|
+
this.instances = /* @__PURE__ */ new Map();
|
|
5298
|
+
this.loading = /* @__PURE__ */ new Map();
|
|
5299
|
+
/** Bumped by invalidate*() so in-flight loads that predate it are discarded. */
|
|
5300
|
+
this.epoch = 0;
|
|
5301
|
+
this.moduleLoader = moduleLoader ?? defaultModuleLoader;
|
|
5302
|
+
}
|
|
5303
|
+
update(world, deltaTime) {
|
|
5304
|
+
const active = /* @__PURE__ */ new Map();
|
|
5305
|
+
for (const entityId of world.query(ScriptObjectComponent)) {
|
|
5306
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
5307
|
+
if (!component) continue;
|
|
5308
|
+
const wantsRun = component.enabled && typeof component.scriptUrl === "string" && typeof component.className === "string";
|
|
5309
|
+
if (!wantsRun) {
|
|
5310
|
+
const record = this.instances.get(entityId);
|
|
5311
|
+
if (record) this.teardownRecord(world, entityId, record, false);
|
|
5312
|
+
this.loading.delete(entityId);
|
|
5313
|
+
if (component.runtimeState !== "idle") {
|
|
5314
|
+
component.runtimeState = "idle";
|
|
5315
|
+
component.runtimeMessage = void 0;
|
|
5316
|
+
}
|
|
5317
|
+
continue;
|
|
5318
|
+
}
|
|
5319
|
+
active.set(entityId, component);
|
|
5320
|
+
}
|
|
5321
|
+
for (const [entityId, record] of this.instances) {
|
|
5322
|
+
const component = active.get(entityId);
|
|
5323
|
+
const identityChanged = !component || record.scriptUrl !== component.scriptUrl || record.className !== component.className;
|
|
5324
|
+
if (!world.hasEntity(entityId) || identityChanged) {
|
|
5325
|
+
this.teardownRecord(world, entityId, record, false);
|
|
5326
|
+
}
|
|
5327
|
+
}
|
|
5328
|
+
for (const [entityId, component] of active) {
|
|
5329
|
+
const record = this.instances.get(entityId);
|
|
5330
|
+
if (!record || record.status !== "ready" || !record.instance) continue;
|
|
5331
|
+
if (!world.isEntityVisible(entityId)) continue;
|
|
5332
|
+
if (component.data !== record.lastWrittenData) {
|
|
5333
|
+
try {
|
|
5334
|
+
const merged = mergeDataByCurrentDefaults(
|
|
5335
|
+
record.rawData,
|
|
5336
|
+
normalizeScriptData(component.data)
|
|
5337
|
+
);
|
|
5338
|
+
record.rawData = merged;
|
|
5339
|
+
record.instance.data = resolveInputData(world, merged);
|
|
5340
|
+
const stored = serializeDataForStorage(merged, merged);
|
|
5341
|
+
component.data = stored;
|
|
5342
|
+
record.lastWrittenData = stored;
|
|
5343
|
+
} catch (error) {
|
|
5344
|
+
this.markError(world, entityId, component, error);
|
|
5345
|
+
continue;
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
try {
|
|
5349
|
+
record.instance.update?.(deltaTime);
|
|
5350
|
+
} catch (error) {
|
|
5351
|
+
this.markError(world, entityId, component, error);
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5354
|
+
for (const [entityId, component] of active) {
|
|
5355
|
+
if (this.instances.has(entityId) || this.loading.has(entityId)) continue;
|
|
5356
|
+
const scriptUrl = component.scriptUrl;
|
|
5357
|
+
const className = component.className;
|
|
5358
|
+
if (component.runtimeState !== "loading") {
|
|
5359
|
+
component.runtimeState = "loading";
|
|
5360
|
+
component.runtimeMessage = void 0;
|
|
5361
|
+
}
|
|
5362
|
+
const epochAtStart = this.epoch;
|
|
5363
|
+
const key = `${epochAtStart}:${scriptUrl}:${className}`;
|
|
5364
|
+
const promise = this.loadScriptObject(
|
|
5365
|
+
world,
|
|
5366
|
+
entityId,
|
|
5367
|
+
scriptUrl,
|
|
5368
|
+
className,
|
|
5369
|
+
key,
|
|
5370
|
+
epochAtStart
|
|
5371
|
+
).catch((error) => {
|
|
5372
|
+
this.markError(world, entityId, void 0, error);
|
|
5373
|
+
console.error(
|
|
5374
|
+
`[ScriptObjectSystem] Failed loading ${className} (${scriptUrl})`,
|
|
5375
|
+
error
|
|
5376
|
+
);
|
|
5377
|
+
}).finally(() => {
|
|
5378
|
+
if (this.loading.get(entityId)?.key === key) {
|
|
5379
|
+
this.loading.delete(entityId);
|
|
5380
|
+
}
|
|
5381
|
+
});
|
|
5382
|
+
this.loading.set(entityId, { key, promise });
|
|
5383
|
+
}
|
|
5384
|
+
for (const entityId of this.loading.keys()) {
|
|
5385
|
+
if (!active.has(entityId)) this.loading.delete(entityId);
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
async loadScriptObject(world, entityId, scriptUrl, className, key, epochAtStart) {
|
|
5389
|
+
const moduleValue = await this.moduleLoader(scriptUrl);
|
|
5390
|
+
if (this.loading.get(entityId)?.key !== key || epochAtStart !== this.epoch || !world.hasEntity(entityId)) {
|
|
5391
|
+
return;
|
|
5392
|
+
}
|
|
5393
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
5394
|
+
if (!component || !component.enabled || component.scriptUrl !== scriptUrl || component.className !== className) {
|
|
5395
|
+
return;
|
|
5396
|
+
}
|
|
5397
|
+
const ctor = resolveScriptCtor(moduleValue, className, {
|
|
5398
|
+
baseClass: ScriptObject,
|
|
5399
|
+
markerKey: "__reluScriptObjectClass"
|
|
5400
|
+
});
|
|
5401
|
+
if (!ctor) {
|
|
5402
|
+
throw new Error(
|
|
5403
|
+
`Missing ScriptObject export '${className}' in ${scriptUrl}`
|
|
5404
|
+
);
|
|
5405
|
+
}
|
|
5406
|
+
const currentData = normalizeScriptData(component.data);
|
|
5407
|
+
let instance;
|
|
5408
|
+
try {
|
|
5409
|
+
instance = new ctor(world, entityId, void 0);
|
|
5410
|
+
} catch {
|
|
5411
|
+
instance = new ctor(world, entityId, currentData);
|
|
5412
|
+
}
|
|
5413
|
+
const defaults = normalizeScriptData(instance.data);
|
|
5414
|
+
const merged = mergeDataByCurrentDefaults(defaults, currentData);
|
|
5415
|
+
instance.data = resolveInputData(world, merged);
|
|
5416
|
+
const parent = world.getComponent(entityId, Object3DRef)?.object;
|
|
5417
|
+
if (!parent) {
|
|
5418
|
+
throw new Error("Script object entity has no Object3D to attach to.");
|
|
5419
|
+
}
|
|
5420
|
+
for (const child of [...parent.children]) {
|
|
5421
|
+
if (child.userData?.[SCRIPT_OBJECT_ROOT_FLAG]) {
|
|
5422
|
+
disposeBuiltObject(child);
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
let built;
|
|
5426
|
+
try {
|
|
5427
|
+
built = instance.build();
|
|
5428
|
+
} catch (error) {
|
|
5429
|
+
try {
|
|
5430
|
+
instance.dispose?.();
|
|
5431
|
+
} catch {
|
|
5432
|
+
}
|
|
5433
|
+
throw error;
|
|
5434
|
+
}
|
|
5435
|
+
if (!built || built.isObject3D !== true) {
|
|
5436
|
+
try {
|
|
5437
|
+
instance.dispose?.();
|
|
5438
|
+
} catch {
|
|
5439
|
+
}
|
|
5440
|
+
throw new Error("build() must return a THREE.Object3D.");
|
|
5441
|
+
}
|
|
5442
|
+
built.userData[SCRIPT_OBJECT_ROOT_FLAG] = true;
|
|
5443
|
+
parent.add(built);
|
|
5444
|
+
instance.root = built;
|
|
5445
|
+
const stored = serializeDataForStorage(merged, merged);
|
|
5446
|
+
component.data = stored;
|
|
5447
|
+
component.runtimeState = "ready";
|
|
5448
|
+
component.runtimeMessage = void 0;
|
|
5449
|
+
setInstanceRef(component, instance);
|
|
5450
|
+
this.instances.set(entityId, {
|
|
5451
|
+
entityId,
|
|
5452
|
+
scriptUrl,
|
|
5453
|
+
className,
|
|
5454
|
+
status: "ready",
|
|
5455
|
+
instance,
|
|
5456
|
+
root: built,
|
|
5457
|
+
rawData: merged,
|
|
5458
|
+
lastWrittenData: stored
|
|
5459
|
+
});
|
|
5460
|
+
}
|
|
5461
|
+
/** Dispose a record's instance + built subtree. `keepTombstone` leaves an error marker. */
|
|
5462
|
+
teardownRecord(world, entityId, record, keepTombstone) {
|
|
5463
|
+
try {
|
|
5464
|
+
record.instance?.dispose?.();
|
|
5465
|
+
} catch {
|
|
5466
|
+
}
|
|
5467
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
5468
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
5469
|
+
if (component) setInstanceRef(component, null);
|
|
5470
|
+
if (keepTombstone) {
|
|
5471
|
+
this.instances.set(entityId, {
|
|
5472
|
+
...record,
|
|
5473
|
+
status: "error",
|
|
5474
|
+
instance: null,
|
|
5475
|
+
root: null
|
|
5476
|
+
});
|
|
5477
|
+
} else {
|
|
5478
|
+
this.instances.delete(entityId);
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
markError(world, entityId, component, error) {
|
|
5482
|
+
const comp = component ?? world.getComponent(entityId, ScriptObjectComponent) ?? null;
|
|
5483
|
+
if (comp) {
|
|
5484
|
+
comp.runtimeState = "error";
|
|
5485
|
+
comp.runtimeMessage = toErrorMessage(error);
|
|
5486
|
+
}
|
|
5487
|
+
const record = this.instances.get(entityId);
|
|
5488
|
+
if (record) {
|
|
5489
|
+
this.teardownRecord(world, entityId, record, true);
|
|
5490
|
+
} else {
|
|
5491
|
+
this.instances.set(entityId, {
|
|
5492
|
+
entityId,
|
|
5493
|
+
scriptUrl: comp?.scriptUrl ?? "",
|
|
5494
|
+
className: comp?.className ?? "",
|
|
5495
|
+
status: "error",
|
|
5496
|
+
instance: null,
|
|
5497
|
+
root: null,
|
|
5498
|
+
rawData: {},
|
|
5499
|
+
lastWrittenData: null
|
|
5500
|
+
});
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
/** Dispose all live instances so the next update() reloads with fresh modules. */
|
|
5504
|
+
invalidateAll() {
|
|
5505
|
+
this.epoch += 1;
|
|
5506
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
5507
|
+
try {
|
|
5508
|
+
record.instance?.dispose?.();
|
|
5509
|
+
} catch {
|
|
5510
|
+
}
|
|
5511
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
5512
|
+
this.instances.delete(entityId);
|
|
5513
|
+
}
|
|
5514
|
+
this.loading.clear();
|
|
5515
|
+
}
|
|
5516
|
+
/** Invalidate only the entities whose script matches `scriptUrl`. */
|
|
5517
|
+
invalidate(scriptUrl) {
|
|
5518
|
+
this.epoch += 1;
|
|
5519
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
5520
|
+
if (record.scriptUrl !== scriptUrl) continue;
|
|
5521
|
+
try {
|
|
5522
|
+
record.instance?.dispose?.();
|
|
5523
|
+
} catch {
|
|
5524
|
+
}
|
|
5525
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
5526
|
+
this.instances.delete(entityId);
|
|
5527
|
+
}
|
|
5528
|
+
for (const [entityId, entry] of [...this.loading]) {
|
|
5529
|
+
if (entry.key.includes(`:${scriptUrl}:`)) this.loading.delete(entityId);
|
|
5530
|
+
}
|
|
5531
|
+
}
|
|
5532
|
+
dispose(world) {
|
|
5533
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
5534
|
+
this.teardownRecord(world, entityId, record, false);
|
|
5535
|
+
}
|
|
5536
|
+
this.instances.clear();
|
|
5537
|
+
this.loading.clear();
|
|
5538
|
+
}
|
|
5539
|
+
};
|
|
5540
|
+
__name(_ScriptObjectSystem, "ScriptObjectSystem");
|
|
5541
|
+
var ScriptObjectSystem = _ScriptObjectSystem;
|
|
5542
|
+
|
|
5024
5543
|
// core/systems/TransformSyncSystem.ts
|
|
5025
5544
|
var _TransformSyncSystem = class _TransformSyncSystem {
|
|
5026
5545
|
update(world) {
|
|
@@ -5282,6 +5801,6 @@ var _VideoSystem = class _VideoSystem {
|
|
|
5282
5801
|
__name(_VideoSystem, "VideoSystem");
|
|
5283
5802
|
var VideoSystem = _VideoSystem;
|
|
5284
5803
|
|
|
5285
|
-
export { AnimationSystem, AudioSystem, Behaviour, CameraSyncSystem, EnvironmentSyncSystem, HYDRATABLE_ENTITY_KINDS, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MaterialSyncSystem, MeshGeometrySystem, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PREFAB_FILE_VERSION, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, ScriptBehaviourSystem, TransformSyncSystem, VideoSystem, buildComponentValueMaps, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, computeInstanceOverrides, decanonicalizeComponentValue, despawnPrefab, encodeOverride, findSnapshotRootEntityIds, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, mergeComponentValue, parseOverride, parsePrefabAsset, restoreComponentState, restorePostCreateComponents, setPrefabAssetUrlResolver, spawnPrefab };
|
|
5286
|
-
//# sourceMappingURL=chunk-
|
|
5287
|
-
//# sourceMappingURL=chunk-
|
|
5804
|
+
export { ADDED_NODE_MARKER_COMPONENT, AnimationSystem, AudioSystem, Behaviour, CameraSyncSystem, EnvironmentSyncSystem, HYDRATABLE_ENTITY_KINDS, InputSystem, InstancedMeshSystem, KeyboardKeys, LightSyncSystem, MaterialSyncSystem, MeshGeometrySystem, NODE_KEY_SEPARATOR, OVERRIDE_DIFF_EXCLUDED_COMPONENTS, OVERRIDE_ROOT_EXCLUDED_COMPONENTS, ObjectVisibilitySystem, PREFAB_FILE_VERSION, PREFAB_FILE_VERSION_NESTED, PhysicsSyncSystem, PostprocessingSyncSystem, RenderSystem, SCRIPT_OBJECT_ROOT_FLAG, ScriptBehaviourSystem, ScriptObject, ScriptObjectSystem, TransformSyncSystem, VideoSystem, buildComponentValueMaps, buildNodeKeyMapsFromSnapshot, buildNodeMapsFromSnapshot, canonicalizeComponentValue, clearPrefabCache, collectDiffPaths, collectEntitySubtree, collectSnapshotSubtreeIds, computeInstanceOverrides, decanonicalizeComponentValue, despawnPrefab, encodeOverride, findSnapshotRootEntityIds, findTopLevelNestedRegions, groupOverridePaths, hydrateWorldFromSnapshot, hydrateWorldFromSnapshotDetailed, indexSnapshotByEntity, instantiateSubtree, loadPrefab, mergeComponentValue, parseOverride, parsePrefabAsset, prefabFileVersionFor, restoreComponentState, restorePostCreateComponents, setPrefabAssetUrlResolver, spawnPrefab };
|
|
5805
|
+
//# sourceMappingURL=chunk-GZ2NKSMV.js.map
|
|
5806
|
+
//# sourceMappingURL=chunk-GZ2NKSMV.js.map
|