@2112-lab/central-plant 0.3.34 → 0.3.36

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.
Files changed (28) hide show
  1. package/dist/bundle/index.js +632 -170
  2. package/dist/cjs/src/core/centralPlant.js +41 -17
  3. package/dist/cjs/src/core/centralPlantInternals.js +6 -2
  4. package/dist/cjs/src/core/sceneViewer.js +6 -24
  5. package/dist/cjs/src/managers/behaviors/IoBehaviorManager.js +510 -44
  6. package/dist/cjs/src/managers/cache/S3CacheService.js +2 -33
  7. package/dist/cjs/src/managers/cache/S3MetadataCacheService.js +0 -1
  8. package/dist/cjs/src/managers/components/componentDataManager.js +2 -6
  9. package/dist/cjs/src/managers/controls/transformControlsManager.js +32 -10
  10. package/dist/cjs/src/managers/scene/modelManager.js +11 -5
  11. package/dist/cjs/src/managers/scene/sceneExportManager.js +10 -3
  12. package/dist/cjs/src/managers/scene/sceneOperationsManager.js +11 -3
  13. package/dist/cjs/src/rendering/modelPreloader.js +1 -17
  14. package/dist/cjs/src/utils/ioDeviceUtils.js +0 -5
  15. package/dist/esm/src/core/centralPlant.js +41 -17
  16. package/dist/esm/src/core/centralPlantInternals.js +6 -2
  17. package/dist/esm/src/core/sceneViewer.js +6 -24
  18. package/dist/esm/src/managers/behaviors/IoBehaviorManager.js +511 -45
  19. package/dist/esm/src/managers/cache/S3CacheService.js +2 -33
  20. package/dist/esm/src/managers/cache/S3MetadataCacheService.js +0 -1
  21. package/dist/esm/src/managers/components/componentDataManager.js +2 -6
  22. package/dist/esm/src/managers/controls/transformControlsManager.js +32 -10
  23. package/dist/esm/src/managers/scene/modelManager.js +11 -5
  24. package/dist/esm/src/managers/scene/sceneExportManager.js +10 -3
  25. package/dist/esm/src/managers/scene/sceneOperationsManager.js +11 -3
  26. package/dist/esm/src/rendering/modelPreloader.js +1 -17
  27. package/dist/esm/src/utils/ioDeviceUtils.js +0 -5
  28. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, slicedToArray as _slicedToArray, toConsumableArray as _toConsumableArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper } from '../../../_virtual/_rollupPluginBabelHelpers.js';
1
+ import { inherits as _inherits, createClass as _createClass, createForOfIteratorHelper as _createForOfIteratorHelper, slicedToArray as _slicedToArray, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray, superPropGet as _superPropGet, classCallCheck as _classCallCheck, callSuper as _callSuper } from '../../../_virtual/_rollupPluginBabelHelpers.js';
2
2
  import * as THREE from 'three';
3
3
  import { BaseDisposable } from '../../core/baseDisposable.js';
4
4
 
@@ -18,6 +18,24 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
18
18
  * }>
19
19
  */
20
20
  _this._entries = new Map();
21
+ _this._crossComponentBehaviors = [];
22
+
23
+ /**
24
+ * Map: `${componentUuid}` → Array<{ id, input, outputs }>
25
+ * Component-level behaviors for intra-component io-device linking
26
+ */
27
+ _this._componentBehaviors = new Map();
28
+
29
+ /**
30
+ * Injected by the host application to read and write I/O device state.
31
+ * Set via configure(). Shape:
32
+ * {
33
+ * getState(attachmentId, dataPointId) -> value | null,
34
+ * setState(attachmentId, dataPointId, value) -> void
35
+ * }
36
+ * @type {{ getState: Function, setState: Function } | null}
37
+ */
38
+ _this._stateAdapter = null;
21
39
  return _this;
22
40
  }
23
41
 
@@ -95,9 +113,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
95
113
  }
96
114
  if (entries.length) {
97
115
  this._entries.set(key, entries);
98
- console.log("[IoBehaviorManager] Loaded ".concat(entries.length, " animation(s) for attachment \"").concat(attachmentId, "\" (parent: ").concat(parentUuid, ") \u2014 stateVariables: ").concat(entries.map(function (e) {
99
- return e.anim.stateVariable;
100
- }).join(', ')));
116
+ // Loaded ${entries.length} animation(s) for attachment "${attachmentId}"
101
117
  } else {
102
118
  console.warn("[IoBehaviorManager] No mesh entries resolved for attachment \"".concat(attachmentId, "\" \u2014 behaviorConfig had ").concat(anims.length, " entries but none matched a mesh"));
103
119
  }
@@ -115,29 +131,479 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
115
131
  }, {
116
132
  key: "triggerState",
117
133
  value: function triggerState(attachmentId, dataPointId, value, parentUuid) {
118
- var _iterator2 = _createForOfIteratorHelper(this._entries.values()),
119
- _step2;
120
- try {
121
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
122
- var entries = _step2.value;
123
- var _iterator3 = _createForOfIteratorHelper(entries),
124
- _step3;
134
+ // triggerState: ${attachmentId}.${dataPointId} = ${value}
135
+
136
+ if (parentUuid) {
137
+ var key = this._key(parentUuid, attachmentId);
138
+ var entries = this._entries.get(key);
139
+ if (entries) {
140
+ var _iterator2 = _createForOfIteratorHelper(entries),
141
+ _step2;
125
142
  try {
126
- for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
127
- var entry = _step3.value;
143
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
144
+ var entry = _step2.value;
128
145
  if (entry.anim.stateVariable !== dataPointId) continue;
129
146
  this._applyAnimation(entry, value);
130
147
  }
131
148
  } catch (err) {
132
- _iterator3.e(err);
149
+ _iterator2.e(err);
133
150
  } finally {
134
- _iterator3.f();
151
+ _iterator2.f();
135
152
  }
136
153
  }
154
+ } else {
155
+ // Fallback when parentUuid is not provided: match by attachmentId suffix or exact key match
156
+ var suffix = "::".concat(attachmentId);
157
+ var _iterator3 = _createForOfIteratorHelper(this._entries.entries()),
158
+ _step3;
159
+ try {
160
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
161
+ var _step3$value = _slicedToArray(_step3.value, 2),
162
+ _key2 = _step3$value[0],
163
+ _entries = _step3$value[1];
164
+ if (_key2 === attachmentId || _key2.endsWith(suffix)) {
165
+ var _iterator4 = _createForOfIteratorHelper(_entries),
166
+ _step4;
167
+ try {
168
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
169
+ var _entry = _step4.value;
170
+ if (_entry.anim.stateVariable !== dataPointId) continue;
171
+ this._applyAnimation(_entry, value);
172
+ }
173
+ } catch (err) {
174
+ _iterator4.e(err);
175
+ } finally {
176
+ _iterator4.f();
177
+ }
178
+ }
179
+ }
180
+ } catch (err) {
181
+ _iterator3.e(err);
182
+ } finally {
183
+ _iterator3.f();
184
+ }
185
+ }
186
+
187
+ // Evaluate component-level behaviors (intra-component io-device linking)
188
+ if (parentUuid && this._componentBehaviors.has(parentUuid)) {
189
+ var componentBehaviors = this._componentBehaviors.get(parentUuid);
190
+ // Checking component-level behaviors (count: ${componentBehaviors.length})
191
+ this.triggerCrossComponentBehaviors(componentBehaviors, parentUuid, attachmentId, dataPointId, value);
192
+ }
193
+
194
+ // Evaluate cross-component behaviors if any are registered
195
+ // Checking cross-component behaviors (count: ${this._crossComponentBehaviors?.length || 0})
196
+ if (this._crossComponentBehaviors && this._crossComponentBehaviors.length > 0) {
197
+ this.triggerCrossComponentBehaviors(this._crossComponentBehaviors, parentUuid, attachmentId, dataPointId, value);
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Register the root-level cross-component behaviors from the scene.
203
+ * Normalizes shorthand syntax to full format.
204
+ *
205
+ * @param {Array} behaviors
206
+ */
207
+ }, {
208
+ key: "setCrossComponentBehaviors",
209
+ value: function setCrossComponentBehaviors(behaviors) {
210
+ var _this2 = this;
211
+ this._crossComponentBehaviors = (behaviors || []).map(function (b) {
212
+ return _this2._normalizeBehavior(b);
213
+ });
214
+ // Loaded ${this._crossComponentBehaviors.length} cross-component behavior(s)
215
+ }
216
+
217
+ /**
218
+ * Register component-level behaviors (intra-component io-device linking).
219
+ * These behaviors are defined in the smart component's JSON and link devices within the same component instance.
220
+ *
221
+ * @param {string} componentUuid - The UUID of the component
222
+ * @param {Array} behaviors - Array of behaviors in shorthand format
223
+ */
224
+ }, {
225
+ key: "registerComponentBehaviors",
226
+ value: function registerComponentBehaviors(componentUuid, behaviors) {
227
+ var _this3 = this;
228
+ if (!behaviors || behaviors.length === 0) return;
229
+ var normalized = behaviors.map(function (b) {
230
+ return _this3._normalizeBehavior(b);
231
+ });
232
+ this._componentBehaviors.set(componentUuid, normalized);
233
+ // Registered ${normalized.length} component-level behavior(s) for component ${componentUuid}
234
+ }
235
+
236
+ /**
237
+ * Normalize behavior from shorthand to full format.
238
+ * Supports:
239
+ * - input: "attachment.state" → { attachment, state }
240
+ * - outputs: ["attachment.state", ...] → converted to individual behaviors
241
+ *
242
+ * @param {Object} behavior - Raw behavior from scene JSON
243
+ * @returns {Object} Normalized behavior
244
+ */
245
+ }, {
246
+ key: "_normalizeBehavior",
247
+ value: function _normalizeBehavior(behavior) {
248
+ var normalized = _objectSpread2({}, behavior);
249
+
250
+ // Parse shorthand input: "attachment.state"
251
+ if (typeof behavior.input === 'string') {
252
+ var _behavior$input$split = behavior.input.split('.'),
253
+ _behavior$input$split2 = _slicedToArray(_behavior$input$split, 2),
254
+ attachment = _behavior$input$split2[0],
255
+ state = _behavior$input$split2[1];
256
+ normalized.input = {
257
+ attachment: attachment,
258
+ state: state
259
+ };
260
+ }
261
+
262
+ // Parse shorthand output/outputs
263
+ if (behavior.outputs) {
264
+ // Multiple outputs - expand to array
265
+ normalized._outputs = behavior.outputs.map(function (out) {
266
+ if (typeof out === 'string') {
267
+ var _out$split = out.split('.'),
268
+ _out$split2 = _slicedToArray(_out$split, 2),
269
+ _attachment = _out$split2[0],
270
+ _state = _out$split2[1];
271
+ return {
272
+ attachment: _attachment,
273
+ state: _state
274
+ };
275
+ }
276
+ return out;
277
+ });
278
+ delete normalized.outputs;
279
+ } else if (typeof behavior.output === 'string') {
280
+ // Single output string
281
+ var _behavior$output$spli = behavior.output.split('.'),
282
+ _behavior$output$spli2 = _slicedToArray(_behavior$output$spli, 2),
283
+ _attachment2 = _behavior$output$spli2[0],
284
+ _state2 = _behavior$output$spli2[1];
285
+ normalized.output = {
286
+ attachment: _attachment2,
287
+ state: _state2
288
+ };
289
+ }
290
+ return normalized;
291
+ }
292
+
293
+ /**
294
+ * Find the parent component UUID for a given attachment ID.
295
+ * Searches the scene tree for the io-device with this attachment ID,
296
+ * then returns its parentComponentId.
297
+ *
298
+ * @param {string} attachmentId
299
+ * @returns {string|null} Component UUID or null if not found
300
+ */
301
+ }, {
302
+ key: "_findComponentByAttachment",
303
+ value: function _findComponentByAttachment(attachmentId) {
304
+ var _this$sceneViewer;
305
+ if (!((_this$sceneViewer = this.sceneViewer) !== null && _this$sceneViewer !== void 0 && _this$sceneViewer.scene)) return null;
306
+ var scene = this.sceneViewer.scene;
307
+ var found = null;
308
+ scene.traverse(function (obj) {
309
+ var _obj$userData, _obj$userData2;
310
+ if (found) return;
311
+ // Find the io-device object with this attachmentId
312
+ if (((_obj$userData = obj.userData) === null || _obj$userData === void 0 ? void 0 : _obj$userData.objectType) === 'io-device' && ((_obj$userData2 = obj.userData) === null || _obj$userData2 === void 0 ? void 0 : _obj$userData2.attachmentId) === attachmentId) {
313
+ found = obj.userData.parentComponentId;
314
+ }
315
+ });
316
+ if (!found) {
317
+ console.warn("[Behavior] Could not find parent component for attachment \"".concat(attachmentId, "\""));
318
+ }
319
+ return found;
320
+ }
321
+
322
+ /**
323
+ * Inject a state adapter so cross-component behaviors can write I/O device state.
324
+ * Call this once after the host application's state store is ready.
325
+ *
326
+ * @param {{ getState: Function, setState: Function }} stateAdapter
327
+ * - getState(attachmentId, dataPointId) -> current value (any) | null
328
+ * - setState(attachmentId, dataPointId, value) -> void
329
+ *
330
+ * @example
331
+ * // Sandbox (Vuex)
332
+ * ioBehaviorManager.configure({
333
+ * getState: (attId, dpId) =>
334
+ * store.getters['assetManagerStore/ioDeviceState'](attId)(dpId) ?? null,
335
+ * setState: (attId, dpId, value) =>
336
+ * store.dispatch('assetManagerStore/setIoDeviceState',
337
+ * { attachmentId: attId, dataPointId: dpId, value })
338
+ * })
339
+ */
340
+ }, {
341
+ key: "configure",
342
+ value: function configure(stateAdapter) {
343
+ this._stateAdapter = stateAdapter || null;
344
+ // State adapter configured
345
+ }
346
+
347
+ /**
348
+ * Evaluate and apply cross-component behaviors loaded from the scene JSON.
349
+ *
350
+ * @param {Array} behaviors - Root-level behaviors array from the scene JSON
351
+ * @param {string} triggerParentUuid - Parent component UUID of the triggering device
352
+ * @param {string} triggerAttachmentId - Attachment ID of the triggering device
353
+ * @param {string} triggerStateId - The state variable ID that changed
354
+ * @param {*} value - The new state value
355
+ */
356
+ }, {
357
+ key: "triggerCrossComponentBehaviors",
358
+ value: function triggerCrossComponentBehaviors(behaviors, triggerParentUuid, triggerAttachmentId, triggerStateId, value) {
359
+ if (!behaviors || !Array.isArray(behaviors)) {
360
+ return;
361
+ }
362
+
363
+ // Evaluating ${behaviors.length} behavior(s)
364
+ var _iterator5 = _createForOfIteratorHelper(behaviors),
365
+ _step5;
366
+ try {
367
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
368
+ var behavior = _step5.value;
369
+ var input = behavior.input,
370
+ output = behavior.output,
371
+ _outputs = behavior._outputs,
372
+ conditions = behavior.conditions;
373
+ if (!input || !output && !_outputs) {
374
+ console.warn('[Behavior] Skipping behavior - missing input or output(s):', behavior);
375
+ continue;
376
+ }
377
+
378
+ // Auto-lookup component if not specified
379
+ var inputComponent = input.component || this._findComponentByAttachment(input.attachment);
380
+ console.log("[Behavior] Checking behavior \"".concat(behavior.id, "\":"), {
381
+ inputMatch: inputComponent === triggerParentUuid,
382
+ attachmentMatch: input.attachment === triggerAttachmentId,
383
+ stateMatch: input.state === triggerStateId,
384
+ expected: {
385
+ component: inputComponent,
386
+ attachment: input.attachment,
387
+ state: input.state
388
+ },
389
+ actual: {
390
+ component: triggerParentUuid,
391
+ attachment: triggerAttachmentId,
392
+ state: triggerStateId
393
+ }
394
+ });
395
+
396
+ // Verify that the input matches the triggering source
397
+ if (inputComponent === triggerParentUuid && input.attachment === triggerAttachmentId && input.state === triggerStateId) {
398
+ // Behavior "${behavior.id}" matched
399
+
400
+ // Collect all outputs (single or multiple)
401
+ var outputs = _outputs || (output ? [output] : []);
402
+
403
+ // Process each output
404
+ var _iterator6 = _createForOfIteratorHelper(outputs),
405
+ _step6;
406
+ try {
407
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
408
+ var out = _step6.value;
409
+ // NEW: State-to-state pass-through pattern
410
+ if (out.state) {
411
+ // Auto-lookup output component if not specified
412
+ var outputComponent = out.component || this._findComponentByAttachment(out.attachment);
413
+
414
+ // Direct state mapping without conditions
415
+ if (this._stateAdapter) {
416
+ // Dispatching state-to-state: ${out.attachment}.${out.state} = ${value}
417
+ this._stateAdapter.setState(out.attachment, out.state, value);
418
+
419
+ // Trigger animations on the output component
420
+ // triggerState(attachmentId, dataPointId, value, parentUuid)
421
+ if (outputComponent) {
422
+ // Triggering animations on output component
423
+ this.triggerState(out.attachment, out.state, value, outputComponent);
424
+ } else {
425
+ console.warn("[Behavior] Could not find component for attachment \"".concat(out.attachment, "\""));
426
+ }
427
+ } else {
428
+ console.warn('[Behavior] ✗ State adapter not configured for state-to-state behavior');
429
+ }
430
+ }
431
+ // LEGACY: Mesh-based pattern with conditions
432
+ else if (conditions && out.child) {
433
+ // Using legacy mesh-based pattern with conditions
434
+ // Evaluate conditions
435
+ var _iterator7 = _createForOfIteratorHelper(conditions),
436
+ _step7;
437
+ try {
438
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
439
+ var condition = _step7.value;
440
+ if (this._evaluateCondition(condition.when, value)) {
441
+ // Apply actions to the target output component/attachment/child mesh
442
+ this._applyCrossComponentActions(out, condition.actions);
443
+ }
444
+ }
445
+ } catch (err) {
446
+ _iterator7.e(err);
447
+ } finally {
448
+ _iterator7.f();
449
+ }
450
+ } else {
451
+ console.warn('[Behavior] Output has neither state nor (child + conditions):', out);
452
+ }
453
+ } // end outputs loop
454
+ } catch (err) {
455
+ _iterator6.e(err);
456
+ } finally {
457
+ _iterator6.f();
458
+ }
459
+ }
460
+ }
461
+ } catch (err) {
462
+ _iterator5.e(err);
463
+ } finally {
464
+ _iterator5.f();
465
+ }
466
+ }
467
+
468
+ /**
469
+ * Safely evaluate a condition expression.
470
+ */
471
+ }, {
472
+ key: "_evaluateCondition",
473
+ value: function _evaluateCondition(whenExpr, value) {
474
+ try {
475
+ var fn = new Function('state', "return (".concat(whenExpr, ");"));
476
+ return fn({
477
+ value: value
478
+ });
479
+ } catch (err) {
480
+ console.warn("[IoBehaviorManager] Failed to evaluate condition: \"".concat(whenExpr, "\""), err);
481
+ return false;
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Resolve target output mesh and apply actions.
487
+ */
488
+ }, {
489
+ key: "_applyCrossComponentActions",
490
+ value: function _applyCrossComponentActions(output, actions) {
491
+ var _this$sceneViewer2;
492
+ if (!actions || !Array.isArray(actions)) return;
493
+
494
+ // 1. Resolve output component
495
+ var scene = (_this$sceneViewer2 = this.sceneViewer) === null || _this$sceneViewer2 === void 0 ? void 0 : _this$sceneViewer2.scene;
496
+ if (!scene) return;
497
+ var componentModel = scene.getObjectByProperty('uuid', output.component) || scene.getObjectByProperty('name', output.component);
498
+ if (!componentModel) {
499
+ console.warn("[IoBehaviorManager] Output component \"".concat(output.component, "\" not found in scene"));
500
+ return;
501
+ }
502
+
503
+ // 2. Resolve attachment model under the component
504
+ var deviceRoot = null;
505
+ componentModel.traverse(function (obj) {
506
+ var _obj$userData3;
507
+ if (!deviceRoot && ((_obj$userData3 = obj.userData) === null || _obj$userData3 === void 0 ? void 0 : _obj$userData3.attachmentId) === output.attachment) {
508
+ deviceRoot = obj;
509
+ }
510
+ });
511
+ if (!deviceRoot) {
512
+ console.warn("[IoBehaviorManager] Output attachment \"".concat(output.attachment, "\" not found on component \"").concat(output.component, "\""));
513
+ return;
514
+ }
515
+
516
+ // 3. Resolve child mesh if specified
517
+ var targetObj = deviceRoot;
518
+ if (output.child) {
519
+ var foundChild = null;
520
+ deviceRoot.traverse(function (obj) {
521
+ if (!foundChild && obj.name === output.child) {
522
+ foundChild = obj;
523
+ }
524
+ });
525
+ if (foundChild) {
526
+ targetObj = foundChild;
527
+ } else {
528
+ console.warn("[IoBehaviorManager] Child \"".concat(output.child, "\" not found under attachment \"").concat(output.attachment, "\" on component \"").concat(output.component, "\""));
529
+ return;
530
+ }
531
+ }
532
+
533
+ // 4. Apply actions to targetObj
534
+ var _iterator8 = _createForOfIteratorHelper(actions),
535
+ _step8;
536
+ try {
537
+ for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
538
+ var action = _step8.value;
539
+ this._applyCrossComponentAction(targetObj, action);
540
+ }
137
541
  } catch (err) {
138
- _iterator2.e(err);
542
+ _iterator8.e(err);
139
543
  } finally {
140
- _iterator2.f();
544
+ _iterator8.f();
545
+ }
546
+ }
547
+
548
+ /**
549
+ * Apply a single action to the target mesh.
550
+ */
551
+ }, {
552
+ key: "_applyCrossComponentAction",
553
+ value: function _applyCrossComponentAction(targetObj, action) {
554
+ var set = action.set,
555
+ value = action.value;
556
+ if (!set) return;
557
+ if (set.startsWith('material.')) {
558
+ var prop = set.slice(9);
559
+ targetObj.traverse(function (obj) {
560
+ if (!obj.isMesh || !obj.material) return;
561
+ if (!obj.userData._materialCloned) {
562
+ obj.material = obj.material.clone();
563
+ obj.userData._materialCloned = true;
564
+ }
565
+ try {
566
+ if (prop === 'color') {
567
+ obj.material.color.set(value);
568
+ } else {
569
+ if (prop in obj.material) {
570
+ if (obj.material[prop] && typeof obj.material[prop].set === 'function') {
571
+ obj.material[prop].set(value);
572
+ } else {
573
+ obj.material[prop] = value;
574
+ }
575
+ }
576
+ }
577
+ } catch (err) {
578
+ console.warn("[IoBehaviorManager] Failed to set material property \"".concat(prop, "\""), err);
579
+ }
580
+ });
581
+ } else if (set === 'visible') {
582
+ targetObj.visible = !!value;
583
+ } else {
584
+ // General fallback path parsing (e.g. position.z)
585
+ var parts = set.split('.');
586
+ var current = targetObj;
587
+ for (var i = 0; i < parts.length - 1; i++) {
588
+ if (current && current[parts[i]]) {
589
+ current = current[parts[i]];
590
+ } else {
591
+ current = null;
592
+ break;
593
+ }
594
+ }
595
+ if (current) {
596
+ var lastPart = parts[parts.length - 1];
597
+ try {
598
+ if (current[lastPart] && typeof current[lastPart].set === 'function') {
599
+ current[lastPart].set(value);
600
+ } else {
601
+ current[lastPart] = value;
602
+ }
603
+ } catch (err) {
604
+ console.warn("[IoBehaviorManager] Failed to set property \"".concat(set, "\""), err);
605
+ }
606
+ }
141
607
  }
142
608
  }
143
609
 
@@ -167,7 +633,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
167
633
  }, {
168
634
  key: "getAnimationDataPoints",
169
635
  value: function getAnimationDataPoints(parentUuid, attachmentId) {
170
- var _this2 = this;
636
+ var _this4 = this;
171
637
  var hitMesh = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
172
638
  var key = this._key(parentUuid, attachmentId);
173
639
  var entries = this._entries.get(key);
@@ -179,35 +645,35 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
179
645
  var filtered = entries;
180
646
  if (hitMesh) {
181
647
  var matching = entries.filter(function (e) {
182
- return _this2._isMeshOrDescendant(hitMesh, e.mesh);
648
+ return _this4._isMeshOrDescendant(hitMesh, e.mesh);
183
649
  });
184
650
  if (matching.length > 0) filtered = matching;
185
651
  }
186
652
 
187
653
  // Collapse multiple mesh entries that share the same stateVariable
188
654
  var seen = new Map(); // stateVariable → anim
189
- var _iterator4 = _createForOfIteratorHelper(filtered),
190
- _step4;
655
+ var _iterator9 = _createForOfIteratorHelper(filtered),
656
+ _step9;
191
657
  try {
192
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
193
- var anim = _step4.value.anim;
658
+ for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
659
+ var anim = _step9.value.anim;
194
660
  if (!seen.has(anim.stateVariable)) {
195
661
  seen.set(anim.stateVariable, anim);
196
662
  }
197
663
  }
198
664
  } catch (err) {
199
- _iterator4.e(err);
665
+ _iterator9.e(err);
200
666
  } finally {
201
- _iterator4.f();
667
+ _iterator9.f();
202
668
  }
203
669
  var dps = [];
204
- var _iterator5 = _createForOfIteratorHelper(seen),
205
- _step5;
670
+ var _iterator0 = _createForOfIteratorHelper(seen),
671
+ _step0;
206
672
  try {
207
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
208
- var _step5$value = _slicedToArray(_step5.value, 2),
209
- stateVar = _step5$value[0],
210
- _anim = _step5$value[1];
673
+ for (_iterator0.s(); !(_step0 = _iterator0.n()).done;) {
674
+ var _step0$value = _slicedToArray(_step0.value, 2),
675
+ stateVar = _step0$value[0],
676
+ _anim = _step0$value[1];
211
677
  // Normalise stateType from AnimateDevicesDialog variants
212
678
  var stateType = void 0;
213
679
  var raw = (_anim.stateType || '').toLowerCase();
@@ -258,9 +724,9 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
258
724
  });
259
725
  }
260
726
  } catch (err) {
261
- _iterator5.e(err);
727
+ _iterator0.e(err);
262
728
  } finally {
263
- _iterator5.f();
729
+ _iterator0.f();
264
730
  }
265
731
  return dps;
266
732
  }
@@ -295,19 +761,19 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
295
761
  key: "unloadForComponent",
296
762
  value: function unloadForComponent(parentUuid) {
297
763
  var prefix = "".concat(parentUuid, "::");
298
- var _iterator6 = _createForOfIteratorHelper(this._entries.keys()),
299
- _step6;
764
+ var _iterator1 = _createForOfIteratorHelper(this._entries.keys()),
765
+ _step1;
300
766
  try {
301
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
302
- var key = _step6.value;
767
+ for (_iterator1.s(); !(_step1 = _iterator1.n()).done;) {
768
+ var key = _step1.value;
303
769
  if (key.startsWith(prefix)) {
304
770
  this._entries.delete(key);
305
771
  }
306
772
  }
307
773
  } catch (err) {
308
- _iterator6.e(err);
774
+ _iterator1.e(err);
309
775
  } finally {
310
- _iterator6.f();
776
+ _iterator1.f();
311
777
  }
312
778
  }
313
779
  }, {
@@ -391,11 +857,11 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
391
857
  var mapping = this._resolveMapping(anim, value);
392
858
  if (!mapping) return;
393
859
  var types = anim.transformTypes || [];
394
- var _iterator7 = _createForOfIteratorHelper(types),
395
- _step7;
860
+ var _iterator10 = _createForOfIteratorHelper(types),
861
+ _step10;
396
862
  try {
397
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
398
- var type = _step7.value;
863
+ for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
864
+ var type = _step10.value;
399
865
  if (type === 'translation') {
400
866
  this._applyTranslation(mesh, origPos, mapping.transform);
401
867
  } else if (type === 'rotation') {
@@ -405,9 +871,9 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
405
871
  }
406
872
  }
407
873
  } catch (err) {
408
- _iterator7.e(err);
874
+ _iterator10.e(err);
409
875
  } finally {
410
- _iterator7.f();
876
+ _iterator10.f();
411
877
  }
412
878
  }
413
879