@relu-interactives/spatial-ecs 0.2.21 → 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-me3iAcMF.d.cts → System-CYWZ_Zx5.d.cts} +4 -3
- package/dist/{System-me3iAcMF.d.ts → System-CYWZ_Zx5.d.ts} +4 -3
- package/dist/{Video-DHnxjGhW.d.ts → Video-C1IOat7L.d.ts} +38 -9
- package/dist/{Video-U9hAnf9y.d.cts → Video-ppAXaKt0.d.cts} +38 -9
- package/dist/{chunk-K6KMKKJ6.js → chunk-52CHDPRQ.js} +118 -92
- package/dist/chunk-52CHDPRQ.js.map +1 -0
- package/dist/{chunk-5U3YS4JD.js → chunk-GZ2NKSMV.js} +421 -65
- package/dist/chunk-GZ2NKSMV.js.map +1 -0
- package/dist/{chunk-V7BNVTJW.js → chunk-JHCPRVBC.js} +25 -4
- package/dist/chunk-JHCPRVBC.js.map +1 -0
- package/dist/{chunk-AXRCGF63.js → chunk-WKGCC7YL.js} +3 -3
- package/dist/{chunk-AXRCGF63.js.map → chunk-WKGCC7YL.js.map} +1 -1
- package/dist/components/index.cjs +22 -1
- 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/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-D7FSg0Au.d.ts → index-Cu2Pt7wN.d.cts} +6 -3
- package/dist/{index-CZo5I5Gs.d.cts → index-DdiWu1b6.d.ts} +6 -3
- package/dist/index.cjs +677 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -28
- package/dist/index.d.ts +117 -28
- package/dist/index.js +13 -8
- package/dist/index.js.map +1 -1
- package/dist/systems/index.cjs +403 -36
- 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-5U3YS4JD.js.map +0 -1
- package/dist/chunk-K6KMKKJ6.js.map +0 -1
- package/dist/chunk-V7BNVTJW.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) {
|
|
@@ -3444,7 +3456,8 @@ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
|
3444
3456
|
"spotLight",
|
|
3445
3457
|
"areaLight",
|
|
3446
3458
|
"instancedMesh",
|
|
3447
|
-
"instanceSlot"
|
|
3459
|
+
"instanceSlot",
|
|
3460
|
+
"scriptObject"
|
|
3448
3461
|
]);
|
|
3449
3462
|
|
|
3450
3463
|
// core/hydration/hydrateWorld.ts
|
|
@@ -3546,6 +3559,16 @@ function buildEntityCreationPayload(sourceEntityId, kind, componentValues) {
|
|
|
3546
3559
|
};
|
|
3547
3560
|
}
|
|
3548
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
|
+
}
|
|
3549
3572
|
return payload;
|
|
3550
3573
|
}
|
|
3551
3574
|
__name(buildEntityCreationPayload, "buildEntityCreationPayload");
|
|
@@ -3877,6 +3900,33 @@ var toRefOrRaw = /* @__PURE__ */ __name((id, idToNode) => {
|
|
|
3877
3900
|
const nodeId = idToNode.get(id);
|
|
3878
3901
|
return nodeId !== void 0 ? makeNodeRef(nodeId) : id;
|
|
3879
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");
|
|
3880
3930
|
function canonicalizeComponentValue(componentName, value, idToNode) {
|
|
3881
3931
|
const cloned = clone(value);
|
|
3882
3932
|
const record = asRecord3(cloned);
|
|
@@ -3902,39 +3952,23 @@ function canonicalizeComponentValue(componentName, value, idToNode) {
|
|
|
3902
3952
|
if (!entry) {
|
|
3903
3953
|
return rawEntry;
|
|
3904
3954
|
}
|
|
3905
|
-
const data = asRecord3(entry.data) ?? {};
|
|
3906
|
-
const canonicalData = {};
|
|
3907
|
-
for (const [key, fieldValue] of Object.entries(data)) {
|
|
3908
|
-
const field = asRecord3(fieldValue);
|
|
3909
|
-
if (field?.type === "entity" && typeof field.value === "number") {
|
|
3910
|
-
canonicalData[key] = {
|
|
3911
|
-
...field,
|
|
3912
|
-
value: toRefOrRaw(field.value, idToNode)
|
|
3913
|
-
};
|
|
3914
|
-
continue;
|
|
3915
|
-
}
|
|
3916
|
-
const componentRef = asRecord3(field?.value);
|
|
3917
|
-
if (field?.type === "component" && componentRef && typeof componentRef.entityId === "number") {
|
|
3918
|
-
canonicalData[key] = {
|
|
3919
|
-
...field,
|
|
3920
|
-
value: {
|
|
3921
|
-
...componentRef,
|
|
3922
|
-
entityId: toRefOrRaw(componentRef.entityId, idToNode)
|
|
3923
|
-
}
|
|
3924
|
-
};
|
|
3925
|
-
continue;
|
|
3926
|
-
}
|
|
3927
|
-
canonicalData[key] = fieldValue;
|
|
3928
|
-
}
|
|
3929
3955
|
return {
|
|
3930
3956
|
className: typeof entry.className === "string" ? entry.className : "",
|
|
3931
3957
|
scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
|
|
3932
3958
|
enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
|
|
3933
|
-
data:
|
|
3959
|
+
data: canonicalizeScriptDataFields(asRecord3(entry.data) ?? {}, idToNode)
|
|
3934
3960
|
};
|
|
3935
3961
|
})
|
|
3936
3962
|
};
|
|
3937
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
|
+
}
|
|
3938
3972
|
if (componentName === "InstancedMeshComponent") {
|
|
3939
3973
|
if (Array.isArray(record.instanceEntityIds)) {
|
|
3940
3974
|
record.instanceEntityIds = record.instanceEntityIds.map(
|
|
@@ -4637,22 +4671,14 @@ var _Behaviour = class _Behaviour {
|
|
|
4637
4671
|
/**
|
|
4638
4672
|
* Called once before the first {@link Behaviour.onUpdate}. Override to
|
|
4639
4673
|
* default and validate {@link Behaviour.data}, cache references, or set
|
|
4640
|
-
* initial state.
|
|
4641
|
-
*
|
|
4642
|
-
* @remarks
|
|
4643
|
-
* Also called in editor mode when `executeInEditor` is `true` on the script
|
|
4644
|
-
* entry.
|
|
4674
|
+
* initial state. Runs at preview/runtime only — never in the editor.
|
|
4645
4675
|
*/
|
|
4646
4676
|
init() {
|
|
4647
4677
|
}
|
|
4648
4678
|
/**
|
|
4649
4679
|
* Called every frame while the script is enabled. Override with the
|
|
4650
|
-
* script's main per-frame logic.
|
|
4651
|
-
*
|
|
4652
|
-
* @remarks
|
|
4653
|
-
* Also called every frame in editor mode when `executeInEditor` is `true`.
|
|
4654
|
-
* Access the Three.js scene with `this.world.getScene()` for editor-only
|
|
4655
|
-
* 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).
|
|
4656
4682
|
*/
|
|
4657
4683
|
onUpdate() {
|
|
4658
4684
|
}
|
|
@@ -4691,7 +4717,14 @@ __name(_Behaviour, "Behaviour");
|
|
|
4691
4717
|
_Behaviour.__reluBehaviourClass = true;
|
|
4692
4718
|
var Behaviour = _Behaviour;
|
|
4693
4719
|
|
|
4694
|
-
// 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");
|
|
4695
4728
|
function toErrorMessage(error) {
|
|
4696
4729
|
const sanitize = /* @__PURE__ */ __name((value) => value.replace(/localasset:\/\/[^/]+\//g, "localasset://").replace(/\/Users\/[^\s)]+/g, "[local path]"), "sanitize");
|
|
4697
4730
|
if (error instanceof Error && error.message) {
|
|
@@ -4703,26 +4736,22 @@ function toErrorMessage(error) {
|
|
|
4703
4736
|
return "Unknown script error.";
|
|
4704
4737
|
}
|
|
4705
4738
|
__name(toErrorMessage, "toErrorMessage");
|
|
4706
|
-
function
|
|
4707
|
-
return `${entityId}:${scriptUrl}:${className}`;
|
|
4708
|
-
}
|
|
4709
|
-
__name(buildInstanceKey, "buildInstanceKey");
|
|
4710
|
-
function resolveBehaviourCtor(moduleValue, className) {
|
|
4739
|
+
function resolveScriptCtor(moduleValue, className, options) {
|
|
4711
4740
|
const named = moduleValue[className];
|
|
4712
4741
|
const fallback = moduleValue.default;
|
|
4713
4742
|
const candidate = typeof named === "function" ? named : typeof fallback === "function" ? fallback : null;
|
|
4714
4743
|
if (!candidate) {
|
|
4715
4744
|
return null;
|
|
4716
4745
|
}
|
|
4717
|
-
if (!(candidate.prototype instanceof
|
|
4718
|
-
const
|
|
4719
|
-
if (!
|
|
4746
|
+
if (!(candidate.prototype instanceof options.baseClass)) {
|
|
4747
|
+
const marker = candidate[options.markerKey];
|
|
4748
|
+
if (!marker) {
|
|
4720
4749
|
return null;
|
|
4721
4750
|
}
|
|
4722
4751
|
}
|
|
4723
4752
|
return candidate;
|
|
4724
4753
|
}
|
|
4725
|
-
__name(
|
|
4754
|
+
__name(resolveScriptCtor, "resolveScriptCtor");
|
|
4726
4755
|
function normalizeScriptData(value) {
|
|
4727
4756
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
4728
4757
|
}
|
|
@@ -4804,8 +4833,8 @@ function resolveInputData(world, rawData) {
|
|
|
4804
4833
|
return resolved;
|
|
4805
4834
|
}
|
|
4806
4835
|
__name(resolveInputData, "resolveInputData");
|
|
4807
|
-
function serializeDataForStorage(rawData,
|
|
4808
|
-
const result = { ...
|
|
4836
|
+
function serializeDataForStorage(rawData, instanceData) {
|
|
4837
|
+
const result = { ...instanceData };
|
|
4809
4838
|
for (const [key, rawValue] of Object.entries(rawData)) {
|
|
4810
4839
|
if (isRawEntityInput(rawValue) || isRawComponentInput(rawValue)) {
|
|
4811
4840
|
result[key] = rawValue;
|
|
@@ -4814,13 +4843,25 @@ function serializeDataForStorage(rawData, behaviourData) {
|
|
|
4814
4843
|
return result;
|
|
4815
4844
|
}
|
|
4816
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");
|
|
4817
4859
|
function normalizeEntry(value, fallbackEntityId) {
|
|
4818
4860
|
return {
|
|
4819
4861
|
entityId: typeof value?.entityId === "number" ? value.entityId : fallbackEntityId,
|
|
4820
4862
|
className: typeof value?.className === "string" ? value.className : "",
|
|
4821
4863
|
scriptUrl: typeof value?.scriptUrl === "string" ? value.scriptUrl : "",
|
|
4822
4864
|
enabled: typeof value?.enabled === "boolean" ? value.enabled : true,
|
|
4823
|
-
executeInEditor: typeof value?.executeInEditor === "boolean" ? value.executeInEditor : false,
|
|
4824
4865
|
data: normalizeScriptData(value?.data),
|
|
4825
4866
|
runtimeState: value?.runtimeState === "idle" || value?.runtimeState === "loading" || value?.runtimeState === "ready" || value?.runtimeState === "error" ? value.runtimeState : void 0,
|
|
4826
4867
|
runtimeMessage: typeof value?.runtimeMessage === "string" ? value.runtimeMessage : void 0
|
|
@@ -4843,13 +4884,6 @@ function writeScriptEntries(component, entries) {
|
|
|
4843
4884
|
}
|
|
4844
4885
|
}
|
|
4845
4886
|
__name(writeScriptEntries, "writeScriptEntries");
|
|
4846
|
-
async function defaultModuleLoader(scriptUrl) {
|
|
4847
|
-
return await import(
|
|
4848
|
-
/* webpackIgnore: true */
|
|
4849
|
-
scriptUrl
|
|
4850
|
-
);
|
|
4851
|
-
}
|
|
4852
|
-
__name(defaultModuleLoader, "defaultModuleLoader");
|
|
4853
4887
|
var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
4854
4888
|
constructor(moduleLoader, selectionContext) {
|
|
4855
4889
|
this.instances = /* @__PURE__ */ new Map();
|
|
@@ -4965,11 +4999,11 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
4965
4999
|
let hasEnabledScript = false;
|
|
4966
5000
|
for (let entryIndex = 0; entryIndex < nextEntries.length; entryIndex += 1) {
|
|
4967
5001
|
const entry = nextEntries[entryIndex];
|
|
4968
|
-
const skipInEditor = world.isEditorMode()
|
|
5002
|
+
const skipInEditor = world.isEditorMode();
|
|
4969
5003
|
if (!entry.enabled || !entry.scriptUrl || skipInEditor) {
|
|
4970
5004
|
nextEntries[entryIndex] = {
|
|
4971
5005
|
...entry,
|
|
4972
|
-
runtimeState:
|
|
5006
|
+
runtimeState: "idle",
|
|
4973
5007
|
runtimeMessage: void 0
|
|
4974
5008
|
};
|
|
4975
5009
|
continue;
|
|
@@ -5156,7 +5190,7 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
5156
5190
|
const mergedData = mergeDataByCurrentDefaults(defaults, currentData);
|
|
5157
5191
|
const resolvedData = resolveInputData(world, mergedData);
|
|
5158
5192
|
behaviour.data = resolvedData;
|
|
5159
|
-
if (!world.isEditorMode()
|
|
5193
|
+
if (!world.isEditorMode()) {
|
|
5160
5194
|
behaviour.init();
|
|
5161
5195
|
}
|
|
5162
5196
|
liveEntries[entryIndex] = {
|
|
@@ -5184,6 +5218,328 @@ __name(_ScriptBehaviourSystem, "ScriptBehaviourSystem");
|
|
|
5184
5218
|
_ScriptBehaviourSystem.CLICK_THRESHOLD = 6;
|
|
5185
5219
|
var ScriptBehaviourSystem = _ScriptBehaviourSystem;
|
|
5186
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
|
+
|
|
5187
5543
|
// core/systems/TransformSyncSystem.ts
|
|
5188
5544
|
var _TransformSyncSystem = class _TransformSyncSystem {
|
|
5189
5545
|
update(world) {
|
|
@@ -5445,6 +5801,6 @@ var _VideoSystem = class _VideoSystem {
|
|
|
5445
5801
|
__name(_VideoSystem, "VideoSystem");
|
|
5446
5802
|
var VideoSystem = _VideoSystem;
|
|
5447
5803
|
|
|
5448
|
-
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, ScriptBehaviourSystem, 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 };
|
|
5449
|
-
//# sourceMappingURL=chunk-
|
|
5450
|
-
//# 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
|