@relu-interactives/spatial-ecs 0.2.21 → 0.2.23
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-7BEZBIVB.js} +428 -65
- package/dist/chunk-7BEZBIVB.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 +115 -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 +684 -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 +410 -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
package/dist/systems/index.cjs
CHANGED
|
@@ -1891,7 +1891,6 @@ var _ScriptComponent = class _ScriptComponent extends Component {
|
|
|
1891
1891
|
className: typeof entry.className === "string" ? entry.className : "",
|
|
1892
1892
|
scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
|
|
1893
1893
|
enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
|
|
1894
|
-
executeInEditor: typeof entry.executeInEditor === "boolean" ? entry.executeInEditor : false,
|
|
1895
1894
|
data: entry.data && typeof entry.data === "object" && !Array.isArray(entry.data) ? entry.data : {},
|
|
1896
1895
|
runtimeState: entry.runtimeState,
|
|
1897
1896
|
runtimeMessage: typeof entry.runtimeMessage === "string" ? entry.runtimeMessage : void 0
|
|
@@ -1913,6 +1912,27 @@ var _ScriptComponent = class _ScriptComponent extends Component {
|
|
|
1913
1912
|
__name(_ScriptComponent, "ScriptComponent");
|
|
1914
1913
|
var ScriptComponent = _ScriptComponent;
|
|
1915
1914
|
|
|
1915
|
+
// core/components/ScriptObjectComponent.ts
|
|
1916
|
+
var _ScriptObjectComponent = class _ScriptObjectComponent extends Component {
|
|
1917
|
+
constructor(input = {}) {
|
|
1918
|
+
super();
|
|
1919
|
+
this.scriptUrl = typeof input.scriptUrl === "string" && input.scriptUrl.length > 0 ? input.scriptUrl : null;
|
|
1920
|
+
this.className = typeof input.className === "string" && input.className.length > 0 ? input.className : null;
|
|
1921
|
+
this.enabled = typeof input.enabled === "boolean" ? input.enabled : true;
|
|
1922
|
+
this.data = input.data && typeof input.data === "object" && !Array.isArray(input.data) ? input.data : {};
|
|
1923
|
+
this.runtimeState = input.runtimeState === "idle" || input.runtimeState === "loading" || input.runtimeState === "ready" || input.runtimeState === "error" ? input.runtimeState : "idle";
|
|
1924
|
+
this.runtimeMessage = typeof input.runtimeMessage === "string" ? input.runtimeMessage : void 0;
|
|
1925
|
+
Object.defineProperty(this, "instance", {
|
|
1926
|
+
value: null,
|
|
1927
|
+
writable: true,
|
|
1928
|
+
configurable: true,
|
|
1929
|
+
enumerable: false
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
};
|
|
1933
|
+
__name(_ScriptObjectComponent, "ScriptObjectComponent");
|
|
1934
|
+
var ScriptObjectComponent = _ScriptObjectComponent;
|
|
1935
|
+
|
|
1916
1936
|
// core/components/Selectable.ts
|
|
1917
1937
|
var _Selectable = class _Selectable extends Component {
|
|
1918
1938
|
constructor(enabled = true) {
|
|
@@ -4760,6 +4780,10 @@ function buildComponentValueMaps(snapshot) {
|
|
|
4760
4780
|
animationValues: readByComponent(snapshot.components, "AnimationComponent"),
|
|
4761
4781
|
imageTargetAnchorValues: readByComponent(snapshot.components, "ImageTargetAnchor"),
|
|
4762
4782
|
scriptValues: readByComponent(snapshot.components, "ScriptComponent"),
|
|
4783
|
+
scriptObjectValues: readByComponent(
|
|
4784
|
+
snapshot.components,
|
|
4785
|
+
"ScriptObjectComponent"
|
|
4786
|
+
),
|
|
4763
4787
|
instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
|
|
4764
4788
|
instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
|
|
4765
4789
|
prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
|
|
@@ -4877,6 +4901,14 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
4877
4901
|
new ScriptComponent(entries)
|
|
4878
4902
|
);
|
|
4879
4903
|
}
|
|
4904
|
+
const sourceScriptObject = asRecord3(values.scriptObjectValues.get(sourceEntityId));
|
|
4905
|
+
if (sourceScriptObject) {
|
|
4906
|
+
const soc = world.getComponent(targetEntityId, ScriptObjectComponent);
|
|
4907
|
+
const data = asRecord3(sourceScriptObject.data);
|
|
4908
|
+
if (soc && data) {
|
|
4909
|
+
soc.data = remapEntityRefsInScriptData(data, idMap);
|
|
4910
|
+
}
|
|
4911
|
+
}
|
|
4880
4912
|
{
|
|
4881
4913
|
const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
|
|
4882
4914
|
if (imComponent && imComponent.instanceEntityIds.length > 0) {
|
|
@@ -5463,7 +5495,8 @@ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
|
5463
5495
|
"spotLight",
|
|
5464
5496
|
"areaLight",
|
|
5465
5497
|
"instancedMesh",
|
|
5466
|
-
"instanceSlot"
|
|
5498
|
+
"instanceSlot",
|
|
5499
|
+
"scriptObject"
|
|
5467
5500
|
]);
|
|
5468
5501
|
|
|
5469
5502
|
// core/hydration/hydrateWorld.ts
|
|
@@ -5565,6 +5598,16 @@ function buildEntityCreationPayload(sourceEntityId, kind, componentValues) {
|
|
|
5565
5598
|
};
|
|
5566
5599
|
}
|
|
5567
5600
|
}
|
|
5601
|
+
if (kind === "scriptObject") {
|
|
5602
|
+
const so = asRecord3(componentValues.scriptObjectValues.get(sourceEntityId));
|
|
5603
|
+
if (so) {
|
|
5604
|
+
payload.options = {
|
|
5605
|
+
scriptUrl: typeof so.scriptUrl === "string" ? so.scriptUrl : null,
|
|
5606
|
+
className: typeof so.className === "string" ? so.className : null,
|
|
5607
|
+
enabled: typeof so.enabled === "boolean" ? so.enabled : true
|
|
5608
|
+
};
|
|
5609
|
+
}
|
|
5610
|
+
}
|
|
5568
5611
|
return payload;
|
|
5569
5612
|
}
|
|
5570
5613
|
__name(buildEntityCreationPayload, "buildEntityCreationPayload");
|
|
@@ -6124,22 +6167,14 @@ var _Behaviour = class _Behaviour {
|
|
|
6124
6167
|
/**
|
|
6125
6168
|
* Called once before the first {@link Behaviour.onUpdate}. Override to
|
|
6126
6169
|
* default and validate {@link Behaviour.data}, cache references, or set
|
|
6127
|
-
* initial state.
|
|
6128
|
-
*
|
|
6129
|
-
* @remarks
|
|
6130
|
-
* Also called in editor mode when `executeInEditor` is `true` on the script
|
|
6131
|
-
* entry.
|
|
6170
|
+
* initial state. Runs at preview/runtime only — never in the editor.
|
|
6132
6171
|
*/
|
|
6133
6172
|
init() {
|
|
6134
6173
|
}
|
|
6135
6174
|
/**
|
|
6136
6175
|
* Called every frame while the script is enabled. Override with the
|
|
6137
|
-
* script's main per-frame logic.
|
|
6138
|
-
*
|
|
6139
|
-
* @remarks
|
|
6140
|
-
* Also called every frame in editor mode when `executeInEditor` is `true`.
|
|
6141
|
-
* Access the Three.js scene with `this.world.getScene()` for editor-only
|
|
6142
|
-
* rendering work such as custom shaders or procedural geometry.
|
|
6176
|
+
* script's main per-frame logic. Runs at preview/runtime only — never in the
|
|
6177
|
+
* editor (use {@link ScriptObject} for editor-visible visuals).
|
|
6143
6178
|
*/
|
|
6144
6179
|
onUpdate() {
|
|
6145
6180
|
}
|
|
@@ -6178,7 +6213,14 @@ __name(_Behaviour, "Behaviour");
|
|
|
6178
6213
|
_Behaviour.__reluBehaviourClass = true;
|
|
6179
6214
|
var Behaviour = _Behaviour;
|
|
6180
6215
|
|
|
6181
|
-
// core/systems/
|
|
6216
|
+
// core/systems/scriptShared.ts
|
|
6217
|
+
async function defaultModuleLoader(scriptUrl) {
|
|
6218
|
+
return await import(
|
|
6219
|
+
/* webpackIgnore: true */
|
|
6220
|
+
scriptUrl
|
|
6221
|
+
);
|
|
6222
|
+
}
|
|
6223
|
+
__name(defaultModuleLoader, "defaultModuleLoader");
|
|
6182
6224
|
function toErrorMessage(error) {
|
|
6183
6225
|
const sanitize = /* @__PURE__ */ __name((value) => value.replace(/localasset:\/\/[^/]+\//g, "localasset://").replace(/\/Users\/[^\s)]+/g, "[local path]"), "sanitize");
|
|
6184
6226
|
if (error instanceof Error && error.message) {
|
|
@@ -6190,26 +6232,22 @@ function toErrorMessage(error) {
|
|
|
6190
6232
|
return "Unknown script error.";
|
|
6191
6233
|
}
|
|
6192
6234
|
__name(toErrorMessage, "toErrorMessage");
|
|
6193
|
-
function
|
|
6194
|
-
return `${entityId}:${scriptUrl}:${className}`;
|
|
6195
|
-
}
|
|
6196
|
-
__name(buildInstanceKey, "buildInstanceKey");
|
|
6197
|
-
function resolveBehaviourCtor(moduleValue, className) {
|
|
6235
|
+
function resolveScriptCtor(moduleValue, className, options) {
|
|
6198
6236
|
const named = moduleValue[className];
|
|
6199
6237
|
const fallback = moduleValue.default;
|
|
6200
6238
|
const candidate = typeof named === "function" ? named : typeof fallback === "function" ? fallback : null;
|
|
6201
6239
|
if (!candidate) {
|
|
6202
6240
|
return null;
|
|
6203
6241
|
}
|
|
6204
|
-
if (!(candidate.prototype instanceof
|
|
6205
|
-
const
|
|
6206
|
-
if (!
|
|
6242
|
+
if (!(candidate.prototype instanceof options.baseClass)) {
|
|
6243
|
+
const marker = candidate[options.markerKey];
|
|
6244
|
+
if (!marker) {
|
|
6207
6245
|
return null;
|
|
6208
6246
|
}
|
|
6209
6247
|
}
|
|
6210
6248
|
return candidate;
|
|
6211
6249
|
}
|
|
6212
|
-
__name(
|
|
6250
|
+
__name(resolveScriptCtor, "resolveScriptCtor");
|
|
6213
6251
|
function normalizeScriptData(value) {
|
|
6214
6252
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
6215
6253
|
}
|
|
@@ -6291,8 +6329,8 @@ function resolveInputData(world, rawData) {
|
|
|
6291
6329
|
return resolved;
|
|
6292
6330
|
}
|
|
6293
6331
|
__name(resolveInputData, "resolveInputData");
|
|
6294
|
-
function serializeDataForStorage(rawData,
|
|
6295
|
-
const result = { ...
|
|
6332
|
+
function serializeDataForStorage(rawData, instanceData) {
|
|
6333
|
+
const result = { ...instanceData };
|
|
6296
6334
|
for (const [key, rawValue] of Object.entries(rawData)) {
|
|
6297
6335
|
if (isRawEntityInput(rawValue) || isRawComponentInput(rawValue)) {
|
|
6298
6336
|
result[key] = rawValue;
|
|
@@ -6301,13 +6339,25 @@ function serializeDataForStorage(rawData, behaviourData) {
|
|
|
6301
6339
|
return result;
|
|
6302
6340
|
}
|
|
6303
6341
|
__name(serializeDataForStorage, "serializeDataForStorage");
|
|
6342
|
+
|
|
6343
|
+
// core/systems/ScriptBehaviourSystem.ts
|
|
6344
|
+
function buildInstanceKey(entityId, scriptUrl, className) {
|
|
6345
|
+
return `${entityId}:${scriptUrl}:${className}`;
|
|
6346
|
+
}
|
|
6347
|
+
__name(buildInstanceKey, "buildInstanceKey");
|
|
6348
|
+
function resolveBehaviourCtor(moduleValue, className) {
|
|
6349
|
+
return resolveScriptCtor(moduleValue, className, {
|
|
6350
|
+
baseClass: Behaviour,
|
|
6351
|
+
markerKey: "__reluBehaviourClass"
|
|
6352
|
+
});
|
|
6353
|
+
}
|
|
6354
|
+
__name(resolveBehaviourCtor, "resolveBehaviourCtor");
|
|
6304
6355
|
function normalizeEntry(value, fallbackEntityId) {
|
|
6305
6356
|
return {
|
|
6306
6357
|
entityId: typeof value?.entityId === "number" ? value.entityId : fallbackEntityId,
|
|
6307
6358
|
className: typeof value?.className === "string" ? value.className : "",
|
|
6308
6359
|
scriptUrl: typeof value?.scriptUrl === "string" ? value.scriptUrl : "",
|
|
6309
6360
|
enabled: typeof value?.enabled === "boolean" ? value.enabled : true,
|
|
6310
|
-
executeInEditor: typeof value?.executeInEditor === "boolean" ? value.executeInEditor : false,
|
|
6311
6361
|
data: normalizeScriptData(value?.data),
|
|
6312
6362
|
runtimeState: value?.runtimeState === "idle" || value?.runtimeState === "loading" || value?.runtimeState === "ready" || value?.runtimeState === "error" ? value.runtimeState : void 0,
|
|
6313
6363
|
runtimeMessage: typeof value?.runtimeMessage === "string" ? value.runtimeMessage : void 0
|
|
@@ -6330,13 +6380,6 @@ function writeScriptEntries(component, entries) {
|
|
|
6330
6380
|
}
|
|
6331
6381
|
}
|
|
6332
6382
|
__name(writeScriptEntries, "writeScriptEntries");
|
|
6333
|
-
async function defaultModuleLoader(scriptUrl) {
|
|
6334
|
-
return await import(
|
|
6335
|
-
/* webpackIgnore: true */
|
|
6336
|
-
scriptUrl
|
|
6337
|
-
);
|
|
6338
|
-
}
|
|
6339
|
-
__name(defaultModuleLoader, "defaultModuleLoader");
|
|
6340
6383
|
var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
6341
6384
|
constructor(moduleLoader, selectionContext) {
|
|
6342
6385
|
this.instances = /* @__PURE__ */ new Map();
|
|
@@ -6452,11 +6495,11 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
6452
6495
|
let hasEnabledScript = false;
|
|
6453
6496
|
for (let entryIndex = 0; entryIndex < nextEntries.length; entryIndex += 1) {
|
|
6454
6497
|
const entry = nextEntries[entryIndex];
|
|
6455
|
-
const skipInEditor = world.isEditorMode()
|
|
6498
|
+
const skipInEditor = world.isEditorMode();
|
|
6456
6499
|
if (!entry.enabled || !entry.scriptUrl || skipInEditor) {
|
|
6457
6500
|
nextEntries[entryIndex] = {
|
|
6458
6501
|
...entry,
|
|
6459
|
-
runtimeState:
|
|
6502
|
+
runtimeState: "idle",
|
|
6460
6503
|
runtimeMessage: void 0
|
|
6461
6504
|
};
|
|
6462
6505
|
continue;
|
|
@@ -6643,7 +6686,7 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
6643
6686
|
const mergedData = mergeDataByCurrentDefaults(defaults, currentData);
|
|
6644
6687
|
const resolvedData = resolveInputData(world, mergedData);
|
|
6645
6688
|
behaviour.data = resolvedData;
|
|
6646
|
-
if (!world.isEditorMode()
|
|
6689
|
+
if (!world.isEditorMode()) {
|
|
6647
6690
|
behaviour.init();
|
|
6648
6691
|
}
|
|
6649
6692
|
liveEntries[entryIndex] = {
|
|
@@ -6671,6 +6714,335 @@ __name(_ScriptBehaviourSystem, "ScriptBehaviourSystem");
|
|
|
6671
6714
|
_ScriptBehaviourSystem.CLICK_THRESHOLD = 6;
|
|
6672
6715
|
var ScriptBehaviourSystem = _ScriptBehaviourSystem;
|
|
6673
6716
|
|
|
6717
|
+
// core/ScriptObject.ts
|
|
6718
|
+
var _ScriptObject = class _ScriptObject {
|
|
6719
|
+
/**
|
|
6720
|
+
* Engine-managed constructor. `ScriptObjectSystem` instantiates subclasses
|
|
6721
|
+
* with the owning world, the entity id, and the component's `data`. User code
|
|
6722
|
+
* should not call this directly.
|
|
6723
|
+
*/
|
|
6724
|
+
constructor(world, entityId, data) {
|
|
6725
|
+
/**
|
|
6726
|
+
* The script's data payload (the `ScriptObjectComponent.data`). Declare a
|
|
6727
|
+
* concrete shape on subclasses with `declare data: MyShape` for type safety.
|
|
6728
|
+
* Use the same typed input envelopes as Behaviours (`ColorInput`,
|
|
6729
|
+
* `SliderInput`, `EntityInput`, …) to get inspector fields.
|
|
6730
|
+
*/
|
|
6731
|
+
this.data = {};
|
|
6732
|
+
/**
|
|
6733
|
+
* The Object3D returned by {@link ScriptObject.build}. Assigned by
|
|
6734
|
+
* `ScriptObjectSystem` after `build()` runs; `null` until then.
|
|
6735
|
+
*/
|
|
6736
|
+
this.root = null;
|
|
6737
|
+
this.world = world;
|
|
6738
|
+
this.entityId = entityId;
|
|
6739
|
+
if (data) this.data = data;
|
|
6740
|
+
}
|
|
6741
|
+
/**
|
|
6742
|
+
* REQUIRED — build and return the visual root. Called once by
|
|
6743
|
+
* `ScriptObjectSystem` after construction. The returned object is attached
|
|
6744
|
+
* under the entity's Object3D (so it inherits the entity transform, selection
|
|
6745
|
+
* and visibility). Subclasses MUST override.
|
|
6746
|
+
*/
|
|
6747
|
+
build() {
|
|
6748
|
+
throw new Error("ScriptObject subclasses must implement build()");
|
|
6749
|
+
}
|
|
6750
|
+
};
|
|
6751
|
+
__name(_ScriptObject, "ScriptObject");
|
|
6752
|
+
/**
|
|
6753
|
+
* Static marker used by `ScriptObjectSystem` to detect `ScriptObject`
|
|
6754
|
+
* subclasses even when a bundler ships a second copy of the package into the
|
|
6755
|
+
* script blob (breaking `instanceof`). Do NOT override.
|
|
6756
|
+
*/
|
|
6757
|
+
_ScriptObject.__reluScriptObjectClass = true;
|
|
6758
|
+
var ScriptObject = _ScriptObject;
|
|
6759
|
+
|
|
6760
|
+
// core/systems/ScriptObjectSystem.ts
|
|
6761
|
+
var SCRIPT_OBJECT_ROOT_FLAG = "__scriptObjectRoot";
|
|
6762
|
+
function setInstanceRef(component, value) {
|
|
6763
|
+
Object.defineProperty(component, "instance", {
|
|
6764
|
+
value,
|
|
6765
|
+
writable: true,
|
|
6766
|
+
configurable: true,
|
|
6767
|
+
enumerable: false
|
|
6768
|
+
});
|
|
6769
|
+
}
|
|
6770
|
+
__name(setInstanceRef, "setInstanceRef");
|
|
6771
|
+
function disposeBuiltObject(root) {
|
|
6772
|
+
root.parent?.remove(root);
|
|
6773
|
+
root.traverse((node) => {
|
|
6774
|
+
const mesh = node;
|
|
6775
|
+
const geometry = mesh.geometry;
|
|
6776
|
+
if (geometry?.dispose && !geometry.userData?.[SHARED_MODEL_RESOURCE_FLAG]) {
|
|
6777
|
+
geometry.dispose();
|
|
6778
|
+
}
|
|
6779
|
+
const material = mesh.material;
|
|
6780
|
+
const materials = Array.isArray(material) ? material : material ? [material] : [];
|
|
6781
|
+
for (const mat of materials) {
|
|
6782
|
+
if (mat.userData?.[SHARED_MODEL_RESOURCE_FLAG]) continue;
|
|
6783
|
+
for (const value of Object.values(mat)) {
|
|
6784
|
+
if (value instanceof THREE14__namespace.Texture) value.dispose();
|
|
6785
|
+
}
|
|
6786
|
+
mat.dispose?.();
|
|
6787
|
+
}
|
|
6788
|
+
});
|
|
6789
|
+
}
|
|
6790
|
+
__name(disposeBuiltObject, "disposeBuiltObject");
|
|
6791
|
+
var _ScriptObjectSystem = class _ScriptObjectSystem {
|
|
6792
|
+
constructor(moduleLoader) {
|
|
6793
|
+
this.instances = /* @__PURE__ */ new Map();
|
|
6794
|
+
this.loading = /* @__PURE__ */ new Map();
|
|
6795
|
+
/** Bumped by invalidate*() so in-flight loads that predate it are discarded. */
|
|
6796
|
+
this.epoch = 0;
|
|
6797
|
+
this.moduleLoader = moduleLoader ?? defaultModuleLoader;
|
|
6798
|
+
}
|
|
6799
|
+
update(world, deltaTime) {
|
|
6800
|
+
const active = /* @__PURE__ */ new Map();
|
|
6801
|
+
for (const entityId of world.query(ScriptObjectComponent)) {
|
|
6802
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
6803
|
+
if (!component) continue;
|
|
6804
|
+
const wantsRun = component.enabled && typeof component.scriptUrl === "string" && typeof component.className === "string";
|
|
6805
|
+
if (!wantsRun) {
|
|
6806
|
+
const record = this.instances.get(entityId);
|
|
6807
|
+
if (record) this.teardownRecord(world, entityId, record, false);
|
|
6808
|
+
this.loading.delete(entityId);
|
|
6809
|
+
if (component.runtimeState !== "idle") {
|
|
6810
|
+
component.runtimeState = "idle";
|
|
6811
|
+
component.runtimeMessage = void 0;
|
|
6812
|
+
}
|
|
6813
|
+
continue;
|
|
6814
|
+
}
|
|
6815
|
+
active.set(entityId, component);
|
|
6816
|
+
}
|
|
6817
|
+
for (const [entityId, record] of this.instances) {
|
|
6818
|
+
const component = active.get(entityId);
|
|
6819
|
+
const identityChanged = !component || record.scriptUrl !== component.scriptUrl || record.className !== component.className;
|
|
6820
|
+
if (!world.hasEntity(entityId) || identityChanged) {
|
|
6821
|
+
this.teardownRecord(world, entityId, record, false);
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
for (const [entityId, component] of active) {
|
|
6825
|
+
const record = this.instances.get(entityId);
|
|
6826
|
+
if (!record || record.status !== "ready" || !record.instance) continue;
|
|
6827
|
+
if (!world.isEntityVisible(entityId)) continue;
|
|
6828
|
+
if (component.data !== record.lastWrittenData) {
|
|
6829
|
+
try {
|
|
6830
|
+
const merged = mergeDataByCurrentDefaults(
|
|
6831
|
+
record.rawData,
|
|
6832
|
+
normalizeScriptData(component.data)
|
|
6833
|
+
);
|
|
6834
|
+
record.rawData = merged;
|
|
6835
|
+
record.instance.data = resolveInputData(world, merged);
|
|
6836
|
+
const stored = serializeDataForStorage(merged, merged);
|
|
6837
|
+
component.data = stored;
|
|
6838
|
+
record.lastWrittenData = stored;
|
|
6839
|
+
} catch (error) {
|
|
6840
|
+
this.markError(world, entityId, component, error);
|
|
6841
|
+
continue;
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6844
|
+
try {
|
|
6845
|
+
record.instance.update?.(deltaTime);
|
|
6846
|
+
} catch (error) {
|
|
6847
|
+
this.markError(world, entityId, component, error);
|
|
6848
|
+
}
|
|
6849
|
+
}
|
|
6850
|
+
for (const [entityId, component] of active) {
|
|
6851
|
+
if (this.instances.has(entityId) || this.loading.has(entityId)) continue;
|
|
6852
|
+
const scriptUrl = component.scriptUrl;
|
|
6853
|
+
const className = component.className;
|
|
6854
|
+
if (component.runtimeState !== "loading") {
|
|
6855
|
+
component.runtimeState = "loading";
|
|
6856
|
+
component.runtimeMessage = void 0;
|
|
6857
|
+
}
|
|
6858
|
+
const epochAtStart = this.epoch;
|
|
6859
|
+
const key = `${epochAtStart}:${scriptUrl}:${className}`;
|
|
6860
|
+
const promise = this.loadScriptObject(
|
|
6861
|
+
world,
|
|
6862
|
+
entityId,
|
|
6863
|
+
scriptUrl,
|
|
6864
|
+
className,
|
|
6865
|
+
key,
|
|
6866
|
+
epochAtStart
|
|
6867
|
+
).catch((error) => {
|
|
6868
|
+
this.markError(world, entityId, void 0, error);
|
|
6869
|
+
console.error(
|
|
6870
|
+
`[ScriptObjectSystem] Failed loading ${className} (${scriptUrl})`,
|
|
6871
|
+
error
|
|
6872
|
+
);
|
|
6873
|
+
}).finally(() => {
|
|
6874
|
+
if (this.loading.get(entityId)?.key === key) {
|
|
6875
|
+
this.loading.delete(entityId);
|
|
6876
|
+
}
|
|
6877
|
+
});
|
|
6878
|
+
this.loading.set(entityId, { key, promise });
|
|
6879
|
+
}
|
|
6880
|
+
for (const entityId of this.loading.keys()) {
|
|
6881
|
+
if (!active.has(entityId)) this.loading.delete(entityId);
|
|
6882
|
+
}
|
|
6883
|
+
}
|
|
6884
|
+
async loadScriptObject(world, entityId, scriptUrl, className, key, epochAtStart) {
|
|
6885
|
+
const moduleValue = await this.moduleLoader(scriptUrl);
|
|
6886
|
+
if (this.loading.get(entityId)?.key !== key || epochAtStart !== this.epoch || !world.hasEntity(entityId)) {
|
|
6887
|
+
return;
|
|
6888
|
+
}
|
|
6889
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
6890
|
+
if (!component || !component.enabled || component.scriptUrl !== scriptUrl || component.className !== className) {
|
|
6891
|
+
return;
|
|
6892
|
+
}
|
|
6893
|
+
const ctor = resolveScriptCtor(moduleValue, className, {
|
|
6894
|
+
baseClass: ScriptObject,
|
|
6895
|
+
markerKey: "__reluScriptObjectClass"
|
|
6896
|
+
});
|
|
6897
|
+
if (!ctor) {
|
|
6898
|
+
throw new Error(
|
|
6899
|
+
`Missing ScriptObject export '${className}' in ${scriptUrl}`
|
|
6900
|
+
);
|
|
6901
|
+
}
|
|
6902
|
+
const currentData = normalizeScriptData(component.data);
|
|
6903
|
+
let instance;
|
|
6904
|
+
try {
|
|
6905
|
+
instance = new ctor(world, entityId, void 0);
|
|
6906
|
+
} catch {
|
|
6907
|
+
instance = new ctor(world, entityId, currentData);
|
|
6908
|
+
}
|
|
6909
|
+
const literalDefaults = normalizeScriptData(instance.data);
|
|
6910
|
+
const seed = Object.keys(literalDefaults).length > 0 ? mergeDataByCurrentDefaults(literalDefaults, currentData) : { ...currentData };
|
|
6911
|
+
instance.data = resolveInputData(world, seed);
|
|
6912
|
+
const parent = world.getComponent(entityId, Object3DRef)?.object;
|
|
6913
|
+
if (!parent) {
|
|
6914
|
+
throw new Error("Script object entity has no Object3D to attach to.");
|
|
6915
|
+
}
|
|
6916
|
+
for (const child of [...parent.children]) {
|
|
6917
|
+
if (child.userData?.[SCRIPT_OBJECT_ROOT_FLAG]) {
|
|
6918
|
+
disposeBuiltObject(child);
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
let built;
|
|
6922
|
+
try {
|
|
6923
|
+
built = instance.build();
|
|
6924
|
+
} catch (error) {
|
|
6925
|
+
try {
|
|
6926
|
+
instance.dispose?.();
|
|
6927
|
+
} catch {
|
|
6928
|
+
}
|
|
6929
|
+
throw error;
|
|
6930
|
+
}
|
|
6931
|
+
if (!built || built.isObject3D !== true) {
|
|
6932
|
+
try {
|
|
6933
|
+
instance.dispose?.();
|
|
6934
|
+
} catch {
|
|
6935
|
+
}
|
|
6936
|
+
throw new Error("build() must return a THREE.Object3D.");
|
|
6937
|
+
}
|
|
6938
|
+
built.userData[SCRIPT_OBJECT_ROOT_FLAG] = true;
|
|
6939
|
+
parent.add(built);
|
|
6940
|
+
instance.root = built;
|
|
6941
|
+
const postBuildData = normalizeScriptData(instance.data);
|
|
6942
|
+
const schemaDefaults = { ...literalDefaults };
|
|
6943
|
+
for (const [key2, value] of Object.entries(postBuildData)) {
|
|
6944
|
+
if (!(key2 in schemaDefaults)) schemaDefaults[key2] = value;
|
|
6945
|
+
}
|
|
6946
|
+
const merged = mergeDataByCurrentDefaults(schemaDefaults, currentData);
|
|
6947
|
+
instance.data = resolveInputData(world, merged);
|
|
6948
|
+
const stored = serializeDataForStorage(merged, merged);
|
|
6949
|
+
component.data = stored;
|
|
6950
|
+
component.runtimeState = "ready";
|
|
6951
|
+
component.runtimeMessage = void 0;
|
|
6952
|
+
setInstanceRef(component, instance);
|
|
6953
|
+
this.instances.set(entityId, {
|
|
6954
|
+
entityId,
|
|
6955
|
+
scriptUrl,
|
|
6956
|
+
className,
|
|
6957
|
+
status: "ready",
|
|
6958
|
+
instance,
|
|
6959
|
+
root: built,
|
|
6960
|
+
rawData: merged,
|
|
6961
|
+
lastWrittenData: stored
|
|
6962
|
+
});
|
|
6963
|
+
}
|
|
6964
|
+
/** Dispose a record's instance + built subtree. `keepTombstone` leaves an error marker. */
|
|
6965
|
+
teardownRecord(world, entityId, record, keepTombstone) {
|
|
6966
|
+
try {
|
|
6967
|
+
record.instance?.dispose?.();
|
|
6968
|
+
} catch {
|
|
6969
|
+
}
|
|
6970
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
6971
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
6972
|
+
if (component) setInstanceRef(component, null);
|
|
6973
|
+
if (keepTombstone) {
|
|
6974
|
+
this.instances.set(entityId, {
|
|
6975
|
+
...record,
|
|
6976
|
+
status: "error",
|
|
6977
|
+
instance: null,
|
|
6978
|
+
root: null
|
|
6979
|
+
});
|
|
6980
|
+
} else {
|
|
6981
|
+
this.instances.delete(entityId);
|
|
6982
|
+
}
|
|
6983
|
+
}
|
|
6984
|
+
markError(world, entityId, component, error) {
|
|
6985
|
+
const comp = component ?? world.getComponent(entityId, ScriptObjectComponent) ?? null;
|
|
6986
|
+
if (comp) {
|
|
6987
|
+
comp.runtimeState = "error";
|
|
6988
|
+
comp.runtimeMessage = toErrorMessage(error);
|
|
6989
|
+
}
|
|
6990
|
+
const record = this.instances.get(entityId);
|
|
6991
|
+
if (record) {
|
|
6992
|
+
this.teardownRecord(world, entityId, record, true);
|
|
6993
|
+
} else {
|
|
6994
|
+
this.instances.set(entityId, {
|
|
6995
|
+
entityId,
|
|
6996
|
+
scriptUrl: comp?.scriptUrl ?? "",
|
|
6997
|
+
className: comp?.className ?? "",
|
|
6998
|
+
status: "error",
|
|
6999
|
+
instance: null,
|
|
7000
|
+
root: null,
|
|
7001
|
+
rawData: {},
|
|
7002
|
+
lastWrittenData: null
|
|
7003
|
+
});
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
/** Dispose all live instances so the next update() reloads with fresh modules. */
|
|
7007
|
+
invalidateAll() {
|
|
7008
|
+
this.epoch += 1;
|
|
7009
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
7010
|
+
try {
|
|
7011
|
+
record.instance?.dispose?.();
|
|
7012
|
+
} catch {
|
|
7013
|
+
}
|
|
7014
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
7015
|
+
this.instances.delete(entityId);
|
|
7016
|
+
}
|
|
7017
|
+
this.loading.clear();
|
|
7018
|
+
}
|
|
7019
|
+
/** Invalidate only the entities whose script matches `scriptUrl`. */
|
|
7020
|
+
invalidate(scriptUrl) {
|
|
7021
|
+
this.epoch += 1;
|
|
7022
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
7023
|
+
if (record.scriptUrl !== scriptUrl) continue;
|
|
7024
|
+
try {
|
|
7025
|
+
record.instance?.dispose?.();
|
|
7026
|
+
} catch {
|
|
7027
|
+
}
|
|
7028
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
7029
|
+
this.instances.delete(entityId);
|
|
7030
|
+
}
|
|
7031
|
+
for (const [entityId, entry] of [...this.loading]) {
|
|
7032
|
+
if (entry.key.includes(`:${scriptUrl}:`)) this.loading.delete(entityId);
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
dispose(world) {
|
|
7036
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
7037
|
+
this.teardownRecord(world, entityId, record, false);
|
|
7038
|
+
}
|
|
7039
|
+
this.instances.clear();
|
|
7040
|
+
this.loading.clear();
|
|
7041
|
+
}
|
|
7042
|
+
};
|
|
7043
|
+
__name(_ScriptObjectSystem, "ScriptObjectSystem");
|
|
7044
|
+
var ScriptObjectSystem = _ScriptObjectSystem;
|
|
7045
|
+
|
|
6674
7046
|
// core/systems/TransformSyncSystem.ts
|
|
6675
7047
|
var _TransformSyncSystem = class _TransformSyncSystem {
|
|
6676
7048
|
update(world) {
|
|
@@ -6947,7 +7319,9 @@ exports.ObjectVisibilitySystem = ObjectVisibilitySystem;
|
|
|
6947
7319
|
exports.PhysicsSyncSystem = PhysicsSyncSystem;
|
|
6948
7320
|
exports.PostprocessingSyncSystem = PostprocessingSyncSystem;
|
|
6949
7321
|
exports.RenderSystem = RenderSystem;
|
|
7322
|
+
exports.SCRIPT_OBJECT_ROOT_FLAG = SCRIPT_OBJECT_ROOT_FLAG;
|
|
6950
7323
|
exports.ScriptBehaviourSystem = ScriptBehaviourSystem;
|
|
7324
|
+
exports.ScriptObjectSystem = ScriptObjectSystem;
|
|
6951
7325
|
exports.TransformSyncSystem = TransformSyncSystem;
|
|
6952
7326
|
exports.VideoSystem = VideoSystem;
|
|
6953
7327
|
//# sourceMappingURL=index.cjs.map
|