@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
package/dist/systems/index.cjs
CHANGED
|
@@ -1854,11 +1854,19 @@ __name(_Name, "Name");
|
|
|
1854
1854
|
var Name = _Name;
|
|
1855
1855
|
|
|
1856
1856
|
// core/components/PrefabInstance.ts
|
|
1857
|
+
var generateInstanceId = /* @__PURE__ */ __name(() => {
|
|
1858
|
+
try {
|
|
1859
|
+
return crypto.randomUUID();
|
|
1860
|
+
} catch {
|
|
1861
|
+
return `i-${Math.random().toString(36).slice(2, 10)}${Date.now().toString(36)}`;
|
|
1862
|
+
}
|
|
1863
|
+
}, "generateInstanceId");
|
|
1857
1864
|
var _PrefabInstance = class _PrefabInstance extends Component {
|
|
1858
|
-
constructor(url, overrides = []) {
|
|
1865
|
+
constructor(url, overrides = [], instanceId) {
|
|
1859
1866
|
super();
|
|
1860
1867
|
this.url = url;
|
|
1861
1868
|
this.overrides = overrides;
|
|
1869
|
+
this.instanceId = typeof instanceId === "string" && instanceId.length > 0 ? instanceId : generateInstanceId();
|
|
1862
1870
|
}
|
|
1863
1871
|
};
|
|
1864
1872
|
__name(_PrefabInstance, "PrefabInstance");
|
|
@@ -1883,7 +1891,6 @@ var _ScriptComponent = class _ScriptComponent extends Component {
|
|
|
1883
1891
|
className: typeof entry.className === "string" ? entry.className : "",
|
|
1884
1892
|
scriptUrl: typeof entry.scriptUrl === "string" ? entry.scriptUrl : "",
|
|
1885
1893
|
enabled: typeof entry.enabled === "boolean" ? entry.enabled : true,
|
|
1886
|
-
executeInEditor: typeof entry.executeInEditor === "boolean" ? entry.executeInEditor : false,
|
|
1887
1894
|
data: entry.data && typeof entry.data === "object" && !Array.isArray(entry.data) ? entry.data : {},
|
|
1888
1895
|
runtimeState: entry.runtimeState,
|
|
1889
1896
|
runtimeMessage: typeof entry.runtimeMessage === "string" ? entry.runtimeMessage : void 0
|
|
@@ -1905,6 +1912,27 @@ var _ScriptComponent = class _ScriptComponent extends Component {
|
|
|
1905
1912
|
__name(_ScriptComponent, "ScriptComponent");
|
|
1906
1913
|
var ScriptComponent = _ScriptComponent;
|
|
1907
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
|
+
|
|
1908
1936
|
// core/components/Selectable.ts
|
|
1909
1937
|
var _Selectable = class _Selectable extends Component {
|
|
1910
1938
|
constructor(enabled = true) {
|
|
@@ -4752,6 +4780,10 @@ function buildComponentValueMaps(snapshot) {
|
|
|
4752
4780
|
animationValues: readByComponent(snapshot.components, "AnimationComponent"),
|
|
4753
4781
|
imageTargetAnchorValues: readByComponent(snapshot.components, "ImageTargetAnchor"),
|
|
4754
4782
|
scriptValues: readByComponent(snapshot.components, "ScriptComponent"),
|
|
4783
|
+
scriptObjectValues: readByComponent(
|
|
4784
|
+
snapshot.components,
|
|
4785
|
+
"ScriptObjectComponent"
|
|
4786
|
+
),
|
|
4755
4787
|
instancedMeshValues: readByComponent(snapshot.components, "InstancedMeshComponent"),
|
|
4756
4788
|
instanceSlotValues: readByComponent(snapshot.components, "InstanceSlotComponent"),
|
|
4757
4789
|
prefabNodeValues: readByComponent(snapshot.components, "PrefabNode"),
|
|
@@ -4869,6 +4901,14 @@ function restorePostCreateComponents(world, objectManagementSystem, targetEntity
|
|
|
4869
4901
|
new ScriptComponent(entries)
|
|
4870
4902
|
);
|
|
4871
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
|
+
}
|
|
4872
4912
|
{
|
|
4873
4913
|
const imComponent = world.getComponent(targetEntityId, InstancedMeshComponent);
|
|
4874
4914
|
if (imComponent && imComponent.instanceEntityIds.length > 0) {
|
|
@@ -5421,7 +5461,13 @@ function restoreComponentState(world, objectManagementSystem, targetEntityId, so
|
|
|
5421
5461
|
) : [];
|
|
5422
5462
|
world.addComponent(
|
|
5423
5463
|
targetEntityId,
|
|
5424
|
-
new PrefabInstance(
|
|
5464
|
+
new PrefabInstance(
|
|
5465
|
+
sourcePrefabInstance.url,
|
|
5466
|
+
overrides,
|
|
5467
|
+
// Preserve the placement identity; the constructor generates a
|
|
5468
|
+
// fresh one for legacy snapshots that predate instanceId.
|
|
5469
|
+
typeof sourcePrefabInstance.instanceId === "string" && sourcePrefabInstance.instanceId.length > 0 ? sourcePrefabInstance.instanceId : void 0
|
|
5470
|
+
)
|
|
5425
5471
|
);
|
|
5426
5472
|
}
|
|
5427
5473
|
}
|
|
@@ -5449,7 +5495,8 @@ var HYDRATABLE_ENTITY_KINDS = /* @__PURE__ */ new Set([
|
|
|
5449
5495
|
"spotLight",
|
|
5450
5496
|
"areaLight",
|
|
5451
5497
|
"instancedMesh",
|
|
5452
|
-
"instanceSlot"
|
|
5498
|
+
"instanceSlot",
|
|
5499
|
+
"scriptObject"
|
|
5453
5500
|
]);
|
|
5454
5501
|
|
|
5455
5502
|
// core/hydration/hydrateWorld.ts
|
|
@@ -5551,6 +5598,16 @@ function buildEntityCreationPayload(sourceEntityId, kind, componentValues) {
|
|
|
5551
5598
|
};
|
|
5552
5599
|
}
|
|
5553
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
|
+
}
|
|
5554
5611
|
return payload;
|
|
5555
5612
|
}
|
|
5556
5613
|
__name(buildEntityCreationPayload, "buildEntityCreationPayload");
|
|
@@ -5680,15 +5737,20 @@ __name(findSnapshotRootEntityIds, "findSnapshotRootEntityIds");
|
|
|
5680
5737
|
var INSTANTIATE_EXCLUDED_COMPONENTS = /* @__PURE__ */ new Set([
|
|
5681
5738
|
"Environment",
|
|
5682
5739
|
"Postprocessing",
|
|
5683
|
-
"SelectionTransformState"
|
|
5684
|
-
"PrefabInstance"
|
|
5740
|
+
"SelectionTransformState"
|
|
5685
5741
|
]);
|
|
5686
5742
|
function instantiateSubtree(world, objectManagementSystem, snapshot) {
|
|
5743
|
+
const snapshotRootIds = new Set(findSnapshotRootEntityIds(snapshot));
|
|
5687
5744
|
const safeSnapshot = {
|
|
5688
5745
|
entities: snapshot.entities,
|
|
5689
|
-
components: snapshot.components.filter(
|
|
5690
|
-
(block) =>
|
|
5691
|
-
|
|
5746
|
+
components: snapshot.components.filter((block) => !INSTANTIATE_EXCLUDED_COMPONENTS.has(block.component)).map(
|
|
5747
|
+
(block) => block.component === "PrefabInstance" ? {
|
|
5748
|
+
component: block.component,
|
|
5749
|
+
entries: block.entries.filter(
|
|
5750
|
+
(entry) => !snapshotRootIds.has(entry.entityId)
|
|
5751
|
+
)
|
|
5752
|
+
} : block
|
|
5753
|
+
).filter((block) => block.entries.length > 0)
|
|
5692
5754
|
};
|
|
5693
5755
|
const result = hydrateWorldFromSnapshotDetailed(
|
|
5694
5756
|
safeSnapshot,
|
|
@@ -6105,22 +6167,14 @@ var _Behaviour = class _Behaviour {
|
|
|
6105
6167
|
/**
|
|
6106
6168
|
* Called once before the first {@link Behaviour.onUpdate}. Override to
|
|
6107
6169
|
* default and validate {@link Behaviour.data}, cache references, or set
|
|
6108
|
-
* initial state.
|
|
6109
|
-
*
|
|
6110
|
-
* @remarks
|
|
6111
|
-
* Also called in editor mode when `executeInEditor` is `true` on the script
|
|
6112
|
-
* entry.
|
|
6170
|
+
* initial state. Runs at preview/runtime only — never in the editor.
|
|
6113
6171
|
*/
|
|
6114
6172
|
init() {
|
|
6115
6173
|
}
|
|
6116
6174
|
/**
|
|
6117
6175
|
* Called every frame while the script is enabled. Override with the
|
|
6118
|
-
* script's main per-frame logic.
|
|
6119
|
-
*
|
|
6120
|
-
* @remarks
|
|
6121
|
-
* Also called every frame in editor mode when `executeInEditor` is `true`.
|
|
6122
|
-
* Access the Three.js scene with `this.world.getScene()` for editor-only
|
|
6123
|
-
* 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).
|
|
6124
6178
|
*/
|
|
6125
6179
|
onUpdate() {
|
|
6126
6180
|
}
|
|
@@ -6159,7 +6213,14 @@ __name(_Behaviour, "Behaviour");
|
|
|
6159
6213
|
_Behaviour.__reluBehaviourClass = true;
|
|
6160
6214
|
var Behaviour = _Behaviour;
|
|
6161
6215
|
|
|
6162
|
-
// 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");
|
|
6163
6224
|
function toErrorMessage(error) {
|
|
6164
6225
|
const sanitize = /* @__PURE__ */ __name((value) => value.replace(/localasset:\/\/[^/]+\//g, "localasset://").replace(/\/Users\/[^\s)]+/g, "[local path]"), "sanitize");
|
|
6165
6226
|
if (error instanceof Error && error.message) {
|
|
@@ -6171,26 +6232,22 @@ function toErrorMessage(error) {
|
|
|
6171
6232
|
return "Unknown script error.";
|
|
6172
6233
|
}
|
|
6173
6234
|
__name(toErrorMessage, "toErrorMessage");
|
|
6174
|
-
function
|
|
6175
|
-
return `${entityId}:${scriptUrl}:${className}`;
|
|
6176
|
-
}
|
|
6177
|
-
__name(buildInstanceKey, "buildInstanceKey");
|
|
6178
|
-
function resolveBehaviourCtor(moduleValue, className) {
|
|
6235
|
+
function resolveScriptCtor(moduleValue, className, options) {
|
|
6179
6236
|
const named = moduleValue[className];
|
|
6180
6237
|
const fallback = moduleValue.default;
|
|
6181
6238
|
const candidate = typeof named === "function" ? named : typeof fallback === "function" ? fallback : null;
|
|
6182
6239
|
if (!candidate) {
|
|
6183
6240
|
return null;
|
|
6184
6241
|
}
|
|
6185
|
-
if (!(candidate.prototype instanceof
|
|
6186
|
-
const
|
|
6187
|
-
if (!
|
|
6242
|
+
if (!(candidate.prototype instanceof options.baseClass)) {
|
|
6243
|
+
const marker = candidate[options.markerKey];
|
|
6244
|
+
if (!marker) {
|
|
6188
6245
|
return null;
|
|
6189
6246
|
}
|
|
6190
6247
|
}
|
|
6191
6248
|
return candidate;
|
|
6192
6249
|
}
|
|
6193
|
-
__name(
|
|
6250
|
+
__name(resolveScriptCtor, "resolveScriptCtor");
|
|
6194
6251
|
function normalizeScriptData(value) {
|
|
6195
6252
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
6196
6253
|
}
|
|
@@ -6272,8 +6329,8 @@ function resolveInputData(world, rawData) {
|
|
|
6272
6329
|
return resolved;
|
|
6273
6330
|
}
|
|
6274
6331
|
__name(resolveInputData, "resolveInputData");
|
|
6275
|
-
function serializeDataForStorage(rawData,
|
|
6276
|
-
const result = { ...
|
|
6332
|
+
function serializeDataForStorage(rawData, instanceData) {
|
|
6333
|
+
const result = { ...instanceData };
|
|
6277
6334
|
for (const [key, rawValue] of Object.entries(rawData)) {
|
|
6278
6335
|
if (isRawEntityInput(rawValue) || isRawComponentInput(rawValue)) {
|
|
6279
6336
|
result[key] = rawValue;
|
|
@@ -6282,13 +6339,25 @@ function serializeDataForStorage(rawData, behaviourData) {
|
|
|
6282
6339
|
return result;
|
|
6283
6340
|
}
|
|
6284
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");
|
|
6285
6355
|
function normalizeEntry(value, fallbackEntityId) {
|
|
6286
6356
|
return {
|
|
6287
6357
|
entityId: typeof value?.entityId === "number" ? value.entityId : fallbackEntityId,
|
|
6288
6358
|
className: typeof value?.className === "string" ? value.className : "",
|
|
6289
6359
|
scriptUrl: typeof value?.scriptUrl === "string" ? value.scriptUrl : "",
|
|
6290
6360
|
enabled: typeof value?.enabled === "boolean" ? value.enabled : true,
|
|
6291
|
-
executeInEditor: typeof value?.executeInEditor === "boolean" ? value.executeInEditor : false,
|
|
6292
6361
|
data: normalizeScriptData(value?.data),
|
|
6293
6362
|
runtimeState: value?.runtimeState === "idle" || value?.runtimeState === "loading" || value?.runtimeState === "ready" || value?.runtimeState === "error" ? value.runtimeState : void 0,
|
|
6294
6363
|
runtimeMessage: typeof value?.runtimeMessage === "string" ? value.runtimeMessage : void 0
|
|
@@ -6311,13 +6380,6 @@ function writeScriptEntries(component, entries) {
|
|
|
6311
6380
|
}
|
|
6312
6381
|
}
|
|
6313
6382
|
__name(writeScriptEntries, "writeScriptEntries");
|
|
6314
|
-
async function defaultModuleLoader(scriptUrl) {
|
|
6315
|
-
return await import(
|
|
6316
|
-
/* webpackIgnore: true */
|
|
6317
|
-
scriptUrl
|
|
6318
|
-
);
|
|
6319
|
-
}
|
|
6320
|
-
__name(defaultModuleLoader, "defaultModuleLoader");
|
|
6321
6383
|
var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
6322
6384
|
constructor(moduleLoader, selectionContext) {
|
|
6323
6385
|
this.instances = /* @__PURE__ */ new Map();
|
|
@@ -6433,11 +6495,11 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
6433
6495
|
let hasEnabledScript = false;
|
|
6434
6496
|
for (let entryIndex = 0; entryIndex < nextEntries.length; entryIndex += 1) {
|
|
6435
6497
|
const entry = nextEntries[entryIndex];
|
|
6436
|
-
const skipInEditor = world.isEditorMode()
|
|
6498
|
+
const skipInEditor = world.isEditorMode();
|
|
6437
6499
|
if (!entry.enabled || !entry.scriptUrl || skipInEditor) {
|
|
6438
6500
|
nextEntries[entryIndex] = {
|
|
6439
6501
|
...entry,
|
|
6440
|
-
runtimeState:
|
|
6502
|
+
runtimeState: "idle",
|
|
6441
6503
|
runtimeMessage: void 0
|
|
6442
6504
|
};
|
|
6443
6505
|
continue;
|
|
@@ -6624,7 +6686,7 @@ var _ScriptBehaviourSystem = class _ScriptBehaviourSystem {
|
|
|
6624
6686
|
const mergedData = mergeDataByCurrentDefaults(defaults, currentData);
|
|
6625
6687
|
const resolvedData = resolveInputData(world, mergedData);
|
|
6626
6688
|
behaviour.data = resolvedData;
|
|
6627
|
-
if (!world.isEditorMode()
|
|
6689
|
+
if (!world.isEditorMode()) {
|
|
6628
6690
|
behaviour.init();
|
|
6629
6691
|
}
|
|
6630
6692
|
liveEntries[entryIndex] = {
|
|
@@ -6652,6 +6714,328 @@ __name(_ScriptBehaviourSystem, "ScriptBehaviourSystem");
|
|
|
6652
6714
|
_ScriptBehaviourSystem.CLICK_THRESHOLD = 6;
|
|
6653
6715
|
var ScriptBehaviourSystem = _ScriptBehaviourSystem;
|
|
6654
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 defaults = normalizeScriptData(instance.data);
|
|
6910
|
+
const merged = mergeDataByCurrentDefaults(defaults, currentData);
|
|
6911
|
+
instance.data = resolveInputData(world, merged);
|
|
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 stored = serializeDataForStorage(merged, merged);
|
|
6942
|
+
component.data = stored;
|
|
6943
|
+
component.runtimeState = "ready";
|
|
6944
|
+
component.runtimeMessage = void 0;
|
|
6945
|
+
setInstanceRef(component, instance);
|
|
6946
|
+
this.instances.set(entityId, {
|
|
6947
|
+
entityId,
|
|
6948
|
+
scriptUrl,
|
|
6949
|
+
className,
|
|
6950
|
+
status: "ready",
|
|
6951
|
+
instance,
|
|
6952
|
+
root: built,
|
|
6953
|
+
rawData: merged,
|
|
6954
|
+
lastWrittenData: stored
|
|
6955
|
+
});
|
|
6956
|
+
}
|
|
6957
|
+
/** Dispose a record's instance + built subtree. `keepTombstone` leaves an error marker. */
|
|
6958
|
+
teardownRecord(world, entityId, record, keepTombstone) {
|
|
6959
|
+
try {
|
|
6960
|
+
record.instance?.dispose?.();
|
|
6961
|
+
} catch {
|
|
6962
|
+
}
|
|
6963
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
6964
|
+
const component = world.getComponent(entityId, ScriptObjectComponent);
|
|
6965
|
+
if (component) setInstanceRef(component, null);
|
|
6966
|
+
if (keepTombstone) {
|
|
6967
|
+
this.instances.set(entityId, {
|
|
6968
|
+
...record,
|
|
6969
|
+
status: "error",
|
|
6970
|
+
instance: null,
|
|
6971
|
+
root: null
|
|
6972
|
+
});
|
|
6973
|
+
} else {
|
|
6974
|
+
this.instances.delete(entityId);
|
|
6975
|
+
}
|
|
6976
|
+
}
|
|
6977
|
+
markError(world, entityId, component, error) {
|
|
6978
|
+
const comp = component ?? world.getComponent(entityId, ScriptObjectComponent) ?? null;
|
|
6979
|
+
if (comp) {
|
|
6980
|
+
comp.runtimeState = "error";
|
|
6981
|
+
comp.runtimeMessage = toErrorMessage(error);
|
|
6982
|
+
}
|
|
6983
|
+
const record = this.instances.get(entityId);
|
|
6984
|
+
if (record) {
|
|
6985
|
+
this.teardownRecord(world, entityId, record, true);
|
|
6986
|
+
} else {
|
|
6987
|
+
this.instances.set(entityId, {
|
|
6988
|
+
entityId,
|
|
6989
|
+
scriptUrl: comp?.scriptUrl ?? "",
|
|
6990
|
+
className: comp?.className ?? "",
|
|
6991
|
+
status: "error",
|
|
6992
|
+
instance: null,
|
|
6993
|
+
root: null,
|
|
6994
|
+
rawData: {},
|
|
6995
|
+
lastWrittenData: null
|
|
6996
|
+
});
|
|
6997
|
+
}
|
|
6998
|
+
}
|
|
6999
|
+
/** Dispose all live instances so the next update() reloads with fresh modules. */
|
|
7000
|
+
invalidateAll() {
|
|
7001
|
+
this.epoch += 1;
|
|
7002
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
7003
|
+
try {
|
|
7004
|
+
record.instance?.dispose?.();
|
|
7005
|
+
} catch {
|
|
7006
|
+
}
|
|
7007
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
7008
|
+
this.instances.delete(entityId);
|
|
7009
|
+
}
|
|
7010
|
+
this.loading.clear();
|
|
7011
|
+
}
|
|
7012
|
+
/** Invalidate only the entities whose script matches `scriptUrl`. */
|
|
7013
|
+
invalidate(scriptUrl) {
|
|
7014
|
+
this.epoch += 1;
|
|
7015
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
7016
|
+
if (record.scriptUrl !== scriptUrl) continue;
|
|
7017
|
+
try {
|
|
7018
|
+
record.instance?.dispose?.();
|
|
7019
|
+
} catch {
|
|
7020
|
+
}
|
|
7021
|
+
if (record.root) disposeBuiltObject(record.root);
|
|
7022
|
+
this.instances.delete(entityId);
|
|
7023
|
+
}
|
|
7024
|
+
for (const [entityId, entry] of [...this.loading]) {
|
|
7025
|
+
if (entry.key.includes(`:${scriptUrl}:`)) this.loading.delete(entityId);
|
|
7026
|
+
}
|
|
7027
|
+
}
|
|
7028
|
+
dispose(world) {
|
|
7029
|
+
for (const [entityId, record] of [...this.instances]) {
|
|
7030
|
+
this.teardownRecord(world, entityId, record, false);
|
|
7031
|
+
}
|
|
7032
|
+
this.instances.clear();
|
|
7033
|
+
this.loading.clear();
|
|
7034
|
+
}
|
|
7035
|
+
};
|
|
7036
|
+
__name(_ScriptObjectSystem, "ScriptObjectSystem");
|
|
7037
|
+
var ScriptObjectSystem = _ScriptObjectSystem;
|
|
7038
|
+
|
|
6655
7039
|
// core/systems/TransformSyncSystem.ts
|
|
6656
7040
|
var _TransformSyncSystem = class _TransformSyncSystem {
|
|
6657
7041
|
update(world) {
|
|
@@ -6928,7 +7312,9 @@ exports.ObjectVisibilitySystem = ObjectVisibilitySystem;
|
|
|
6928
7312
|
exports.PhysicsSyncSystem = PhysicsSyncSystem;
|
|
6929
7313
|
exports.PostprocessingSyncSystem = PostprocessingSyncSystem;
|
|
6930
7314
|
exports.RenderSystem = RenderSystem;
|
|
7315
|
+
exports.SCRIPT_OBJECT_ROOT_FLAG = SCRIPT_OBJECT_ROOT_FLAG;
|
|
6931
7316
|
exports.ScriptBehaviourSystem = ScriptBehaviourSystem;
|
|
7317
|
+
exports.ScriptObjectSystem = ScriptObjectSystem;
|
|
6932
7318
|
exports.TransformSyncSystem = TransformSyncSystem;
|
|
6933
7319
|
exports.VideoSystem = VideoSystem;
|
|
6934
7320
|
//# sourceMappingURL=index.cjs.map
|