@2112-lab/central-plant 0.3.45 → 0.3.47

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 (31) hide show
  1. package/dist/bundle/index.js +635 -337
  2. package/dist/cjs/src/core/centralPlant.js +342 -218
  3. package/dist/cjs/src/core/centralPlantInternals.js +2 -0
  4. package/dist/cjs/src/core/sceneViewer.js +0 -1
  5. package/dist/cjs/src/managers/behaviors/IoBehaviorManager.js +1 -2
  6. package/dist/cjs/src/managers/components/componentDataManager.js +0 -1
  7. package/dist/cjs/src/managers/controls/componentDragManager.js +4 -8
  8. package/dist/cjs/src/managers/pathfinding/pathfindingManager.js +55 -1
  9. package/dist/cjs/src/managers/scene/collisionManager.js +142 -0
  10. package/dist/cjs/src/managers/scene/componentTooltipManager.js +2 -3
  11. package/dist/cjs/src/managers/scene/sceneExportManager.js +32 -11
  12. package/dist/cjs/src/managers/scene/sceneOperationsManager.js +17 -33
  13. package/dist/cjs/src/utils/behaviorDispatch.js +11 -42
  14. package/dist/cjs/src/utils/boundingBoxUtils.js +54 -8
  15. package/dist/cjs/src/utils/ioDeviceUtils.js +3 -9
  16. package/dist/esm/src/core/centralPlant.js +342 -218
  17. package/dist/esm/src/core/centralPlantInternals.js +2 -0
  18. package/dist/esm/src/core/sceneViewer.js +0 -1
  19. package/dist/esm/src/managers/behaviors/IoBehaviorManager.js +1 -2
  20. package/dist/esm/src/managers/components/componentDataManager.js +0 -1
  21. package/dist/esm/src/managers/controls/componentDragManager.js +4 -8
  22. package/dist/esm/src/managers/pathfinding/pathfindingManager.js +56 -2
  23. package/dist/esm/src/managers/scene/collisionManager.js +118 -0
  24. package/dist/esm/src/managers/scene/componentTooltipManager.js +2 -3
  25. package/dist/esm/src/managers/scene/sceneExportManager.js +33 -12
  26. package/dist/esm/src/managers/scene/sceneOperationsManager.js +17 -33
  27. package/dist/esm/src/utils/behaviorDispatch.js +11 -42
  28. package/dist/esm/src/utils/boundingBoxUtils.js +55 -10
  29. package/dist/esm/src/utils/ioDeviceUtils.js +3 -9
  30. package/dist/index.d.ts +0 -6
  31. package/package.json +1 -1
@@ -21,6 +21,7 @@ var keyboardControlsManager = require('../managers/controls/keyboardControlsMana
21
21
  var pathfindingManager = require('../managers/pathfinding/pathfindingManager.js');
22
22
  var PathFlowManager = require('../managers/pathfinding/PathFlowManager.js');
23
23
  var sceneOperationsManager = require('../managers/scene/sceneOperationsManager.js');
24
+ var collisionManager = require('../managers/scene/collisionManager.js');
24
25
  var animationManager = require('../managers/scene/animationManager.js');
25
26
  var cameraControlsManager = require('../managers/controls/cameraControlsManager.js');
26
27
  var componentDragManager = require('../managers/controls/componentDragManager.js');
@@ -169,6 +170,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
169
170
  this.centralPlant.managers.keyboardControlsManager = new keyboardControlsManager.KeyboardControlsManager(this.centralPlant.sceneViewer);
170
171
  this.centralPlant.managers.pathfindingManager = new pathfindingManager.PathfindingManager(this.centralPlant.sceneViewer);
171
172
  this.centralPlant.managers.pathFlowManager = new PathFlowManager.PathFlowManager(this.centralPlant.sceneViewer);
173
+ this.centralPlant.managers.collisionManager = new collisionManager.CollisionManager(this.centralPlant.sceneViewer);
172
174
  this.centralPlant.managers.sceneOperationsManager = new sceneOperationsManager.SceneOperationsManager(this.centralPlant.sceneViewer);
173
175
  this.centralPlant.managers.animationManager = new animationManager.AnimationManager(this.centralPlant.sceneViewer);
174
176
  this.centralPlant.managers.cameraControlsManager = new cameraControlsManager.CameraControlsManager(this.centralPlant.sceneViewer);
@@ -647,7 +647,6 @@ var sceneViewer = /*#__PURE__*/function (_BaseDisposable) {
647
647
  }, {
648
648
  key: "updatePaths",
649
649
  value: function updatePaths() {
650
- console.log("updatePaths started");
651
650
  // Delegate pathfinding update to PathfindingManager
652
651
  if (this.pathfindingManager) {
653
652
  this.pathfindingManager.updatePathfindingAfterTransform(this.currentSceneData);
@@ -537,8 +537,7 @@ var IoBehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
537
537
  /**
538
538
  * Return tooltip-compatible data point definitions derived from the loaded
539
539
  * animation entries for a given attachment. Used by componentTooltipManager
540
- * to replace the static ioConfig.states[] snapshot with the richer animation
541
- * state definitions created in the Animate window.
540
+ * to provide the richer animation state definitions created in the Animate window.
542
541
  *
543
542
  * One dp object is emitted per unique stateVariable; multiple mesh entries
544
543
  * that share the same stateVariable are collapsed into one.
@@ -888,7 +888,6 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
888
888
  };
889
889
  return _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, baseData), {}, {
890
890
  metadata: component.metadata || {},
891
- ioConfig: component.ioConfig || null,
892
891
  boundingBox: component.boundingBox || null,
893
892
  adaptedBoundingBox: component.adaptedBoundingBox || null,
894
893
  children: component.children || [],
@@ -345,7 +345,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
345
345
  key: "_attachIODeviceModelsToPreview",
346
346
  value: (function () {
347
347
  var _attachIODeviceModelsToPreview2 = _rollupPluginBabelHelpers.asyncToGenerator(/*#__PURE__*/_rollupPluginBabelHelpers.regenerator().m(function _callee3(parentObject, componentData, modelPreloader) {
348
- var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t3;
348
+ var _i, _Object$entries, _Object$entries$_i, attachmentId, attachment, _modelPreloader$compo, _attachment$attachmen, _attachment$attachmen2, deviceData, cachedDevice, _modelPreloader$loadi, deviceModel, pos, rot, deg2rad, _t3;
349
349
  return _rollupPluginBabelHelpers.regenerator().w(function (_context3) {
350
350
  while (1) switch (_context3.n) {
351
351
  case 0:
@@ -408,12 +408,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
408
408
  deviceId: attachment.deviceId,
409
409
  attachmentId: attachmentId,
410
410
  attachmentLabel: attachment.attachmentLabel,
411
- deviceName: deviceData.name || '',
412
- // Snapshot of data point definitions so the tooltip can render state
413
- // ioConfig can use either 'states' (preferred) or legacy 'dataPoints' as the array key
414
- dataPoints: ((_deviceData$ioConfig = deviceData.ioConfig) === null || _deviceData$ioConfig === void 0 ? void 0 : _deviceData$ioConfig.states) || ((_deviceData$ioConfig2 = deviceData.ioConfig) === null || _deviceData$ioConfig2 === void 0 ? void 0 : _deviceData$ioConfig2.dataPoints) || [],
415
- // Device-level I/O direction: 'input' means the user can write state via the tooltip
416
- ioDirection: ((_deviceData$ioConfig3 = deviceData.ioConfig) === null || _deviceData$ioConfig3 === void 0 ? void 0 : _deviceData$ioConfig3.direction) || 'output'
411
+ deviceName: deviceData.name || ''
417
412
  };
418
413
  if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
419
414
  pos = attachment.attachmentPoint.position;
@@ -667,6 +662,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
667
662
  // Find intersection with ground plane
668
663
  var intersection = this.raycaster.ray.intersectPlane(this.dropPlane, this.dropIntersection);
669
664
  if (intersection) {
665
+ var _this$sceneViewer$col;
670
666
  // Apply 0.5 unit transform snapping to intersection point
671
667
  var snappedPosition = this._applyTransformSnap(intersection);
672
668
  this.dragData.previewObject.position.copy(snappedPosition);
@@ -674,7 +670,7 @@ var ComponentDragManager = /*#__PURE__*/function (_BaseDisposable) {
674
670
 
675
671
  // Check for overlap and update color accordingly
676
672
  var wasOverlapping = this.dragData.isOverlapping;
677
- this.dragData.isOverlapping = this._checkBoundingBoxOverlap();
673
+ this.dragData.isOverlapping = !!((_this$sceneViewer$col = this.sceneViewer.collisionManager) !== null && _this$sceneViewer$col !== void 0 && _this$sceneViewer$col.checkCollision(this.dragData.previewObject));
678
674
 
679
675
  // Update color if overlap state changed
680
676
  if (wasOverlapping !== this.dragData.isOverlapping) {
@@ -328,6 +328,31 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
328
328
  }
329
329
  });
330
330
  }
331
+
332
+ // Also reinject connectors from cache
333
+ if (_cached.connectorBBoxes && _cached.connectorBBoxes.length > 0) {
334
+ if (!_enrichedChild.children) _enrichedChild.children = [];
335
+ _cached.connectorBBoxes.forEach(function (connBBox) {
336
+ var existingIndex = _enrichedChild.children.findIndex(function (c) {
337
+ return c.uuid === connBBox.uuid;
338
+ });
339
+ if (existingIndex >= 0) {
340
+ _enrichedChild.children[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _enrichedChild.children[existingIndex]), {}, {
341
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, _enrichedChild.children[existingIndex].userData), {}, {
342
+ worldBoundingBox: connBBox.worldBoundingBox
343
+ })
344
+ });
345
+ } else {
346
+ _enrichedChild.children.push({
347
+ uuid: connBBox.uuid,
348
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, connBBox.userData), {}, {
349
+ worldBoundingBox: connBBox.worldBoundingBox
350
+ }),
351
+ children: []
352
+ });
353
+ }
354
+ });
355
+ }
331
356
  return _enrichedChild;
332
357
  }
333
358
 
@@ -385,11 +410,40 @@ var PathfindingManager = /*#__PURE__*/function (_BaseDisposable) {
385
410
  console.log("\uD83D\uDCE6 Injected ".concat(ioDeviceBBoxes.length, " io-device bounding box(es) for component ").concat(child.uuid));
386
411
  }
387
412
 
413
+ // PHASE 2: Enrich Connectors (CRITICAL for pathfinding API)
414
+ // Also compute world bounding boxes for connectors and inject into children.
415
+ // This ensures endpoints have world coordinates in sceneDataCopy.
416
+ var connectorBBoxes = boundingBoxUtils.computeConnectorBoundingBoxes(componentObject);
417
+ if (connectorBBoxes.length > 0) {
418
+ if (!enrichedChild.children) enrichedChild.children = [];
419
+ connectorBBoxes.forEach(function (connBBox) {
420
+ var existingIndex = enrichedChild.children.findIndex(function (c) {
421
+ return c.uuid === connBBox.uuid;
422
+ });
423
+ if (existingIndex >= 0) {
424
+ enrichedChild.children[existingIndex] = _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedChild.children[existingIndex]), {}, {
425
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, enrichedChild.children[existingIndex].userData), {}, {
426
+ worldBoundingBox: connBBox.worldBoundingBox
427
+ })
428
+ });
429
+ } else {
430
+ enrichedChild.children.push({
431
+ uuid: connBBox.uuid,
432
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, connBBox.userData), {}, {
433
+ worldBoundingBox: connBBox.worldBoundingBox
434
+ }),
435
+ children: []
436
+ });
437
+ }
438
+ });
439
+ }
440
+
388
441
  // Store in cache
389
442
  _this3._bboxCache.set(child.uuid, {
390
443
  matrixHash: _hash,
391
444
  filteredBBox: _bboxData,
392
- ioDeviceBBoxes: ioDeviceBBoxes
445
+ ioDeviceBBoxes: ioDeviceBBoxes,
446
+ connectorBBoxes: connectorBBoxes
393
447
  });
394
448
  return enrichedChild;
395
449
  } else {
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _rollupPluginBabelHelpers = require('../../../_virtual/_rollupPluginBabelHelpers.js');
6
+ var THREE = require('three');
7
+
8
+ function _interopNamespace(e) {
9
+ if (e && e.__esModule) return e;
10
+ var n = Object.create(null);
11
+ if (e) {
12
+ Object.keys(e).forEach(function (k) {
13
+ if (k !== 'default') {
14
+ var d = Object.getOwnPropertyDescriptor(e, k);
15
+ Object.defineProperty(n, k, d.get ? d : {
16
+ enumerable: true,
17
+ get: function () { return e[k]; }
18
+ });
19
+ }
20
+ });
21
+ }
22
+ n["default"] = e;
23
+ return Object.freeze(n);
24
+ }
25
+
26
+ var THREE__namespace = /*#__PURE__*/_interopNamespace(THREE);
27
+
28
+ var CollisionManager = /*#__PURE__*/function () {
29
+ /**
30
+ * @param {Object} sceneViewer - The scene viewer instance
31
+ */
32
+ function CollisionManager(sceneViewer) {
33
+ _rollupPluginBabelHelpers.classCallCheck(this, CollisionManager);
34
+ this.sceneViewer = sceneViewer;
35
+ }
36
+
37
+ /**
38
+ * Check if a given object overlaps with any other relevant objects in the scene.
39
+ * @param {THREE.Object3D} object - The object to check for collisions
40
+ * @param {Array<string>} excludeTypes - Object types to exclude from checking (e.g. ['ground'])
41
+ * @returns {Object|null} Collision info {object, objectType} if collision detected, null otherwise
42
+ */
43
+ return _rollupPluginBabelHelpers.createClass(CollisionManager, [{
44
+ key: "checkCollision",
45
+ value: function checkCollision(object) {
46
+ var _this$sceneViewer,
47
+ _this = this;
48
+ var excludeTypes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ['isBaseGround', 'isBaseGrid', 'isBrickWall'];
49
+ if (!((_this$sceneViewer = this.sceneViewer) !== null && _this$sceneViewer !== void 0 && _this$sceneViewer.scene) || !object) return null;
50
+
51
+ // Compute high-quality bounding box for the object being checked
52
+ // We use setFromObject here because the target object just moved
53
+ var objectBBox = new THREE__namespace.Box3().setFromObject(object);
54
+
55
+ // Narrow down potential colliders
56
+ var collisionDetected = null;
57
+
58
+ // Optimization: Only check the root-level CP objects to avoid O(N^2) complexity with meshes
59
+ this.sceneViewer.scene.traverse(function (child) {
60
+ var _child$userData, _child$userData2, _child$userData3, _child$userData4, _child$userData5;
61
+ if (collisionDetected) return; // Short circuit
62
+
63
+ // Skip the object itself and its descendants
64
+ if (child === object || _this._isDescendantOf(object, child)) return;
65
+
66
+ // Filter by CP object types at the root level (skip internal meshes during traverse)
67
+ var isCPRootObject = ((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'component' || ((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'segment' || ((_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType) === 'gateway' || ((_child$userData4 = child.userData) === null || _child$userData4 === void 0 ? void 0 : _child$userData4.objectType) === 'connector' || ((_child$userData5 = child.userData) === null || _child$userData5 === void 0 ? void 0 : _child$userData5.objectType) === 'io-device';
68
+ if (isCPRootObject && !_this._shouldExclude(child, excludeTypes)) {
69
+ // Use cached worldBoundingBox if available, otherwise compute it (and cache it)
70
+ var childBBox;
71
+ if (child.userData.worldBoundingBox && !child.userData.isMoving) {
72
+ var _min$x, _min$y, _min$z, _max$x, _max$y, _max$z;
73
+ // Use stored worldBoundingBox (handles array or Box3 format)
74
+ var min = child.userData.worldBoundingBox.min;
75
+ var max = child.userData.worldBoundingBox.max;
76
+ childBBox = new THREE__namespace.Box3(new THREE__namespace.Vector3((_min$x = min.x) !== null && _min$x !== void 0 ? _min$x : min[0], (_min$y = min.y) !== null && _min$y !== void 0 ? _min$y : min[1], (_min$z = min.z) !== null && _min$z !== void 0 ? _min$z : min[2]), new THREE__namespace.Vector3((_max$x = max.x) !== null && _max$x !== void 0 ? _max$x : max[0], (_max$y = max.y) !== null && _max$y !== void 0 ? _max$y : max[1], (_max$z = max.z) !== null && _max$z !== void 0 ? _max$z : max[2]));
77
+ } else {
78
+ // Fallback to high-quality computation for moving objects or first-time checks
79
+ childBBox = new THREE__namespace.Box3().setFromObject(child);
80
+
81
+ // Cache the result for next time (non-moving objects)
82
+ if (!child.userData.isMoving) {
83
+ child.userData.worldBoundingBox = {
84
+ min: [childBBox.min.x, childBBox.min.y, childBBox.min.z],
85
+ max: [childBBox.max.x, childBBox.max.y, childBBox.max.z]
86
+ };
87
+ }
88
+ }
89
+ if (objectBBox.intersectsBox(childBBox)) {
90
+ collisionDetected = {
91
+ object: child,
92
+ objectType: child.userData.objectType,
93
+ uuid: child.uuid,
94
+ name: child.name || child.userData.libraryId || child.uuid
95
+ };
96
+ }
97
+ }
98
+ });
99
+ return collisionDetected;
100
+ }
101
+
102
+ /**
103
+ * Helper to check if a node is a descendant of a specific parent
104
+ * @private
105
+ */
106
+ }, {
107
+ key: "_isDescendantOf",
108
+ value: function _isDescendantOf(parent, child) {
109
+ var node = child.parent;
110
+ while (node !== null) {
111
+ if (node === parent) return true;
112
+ node = node.parent;
113
+ }
114
+ return false;
115
+ }
116
+
117
+ /**
118
+ * Helper to determine if an object should be excluded from collision checking
119
+ * @private
120
+ */
121
+ }, {
122
+ key: "_shouldExclude",
123
+ value: function _shouldExclude(object, excludeTypes) {
124
+ if (object.userData.isPreview) return true;
125
+ var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(excludeTypes),
126
+ _step;
127
+ try {
128
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
129
+ var type = _step.value;
130
+ if (object.userData[type]) return true;
131
+ }
132
+ } catch (err) {
133
+ _iterator.e(err);
134
+ } finally {
135
+ _iterator.f();
136
+ }
137
+ return false;
138
+ }
139
+ }]);
140
+ }();
141
+
142
+ exports.CollisionManager = CollisionManager;
@@ -482,8 +482,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
482
482
  if (((_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.objectType) === 'io-device') {
483
483
  var attachmentId = child.userData.attachmentId || '';
484
484
 
485
- // Use only data points from the animate window (behaviorConfig).
486
- // The static ioConfig.states[] snapshot on userData is intentionally ignored.
485
+ // Use data points from the animate window (behaviorConfig).
487
486
  var dataPoints = behaviorDispatch.resolveDataPoints(parentUuid, attachmentId, child.userData, behaviorDispatch.getIoBehaviorManager(_this3.sceneViewer));
488
487
 
489
488
  // When data points come from behaviorConfig they already carry direction:'input'.
@@ -696,7 +695,7 @@ var ComponentTooltipManager = /*#__PURE__*/function (_BaseDisposable) {
696
695
  * Input / bidirectional → shows an interactive control.
697
696
  *
698
697
  * @param {string} scopedAttachmentId - Scoped attachment ID (parentUuid::attachmentId) for state isolation
699
- * @param {Object} dp - data point definition from ioConfig.dataPoints
698
+ * @param {Object} dp - data point definition
700
699
  * @param {string} [deviceDirection] - device-level direction ('input'|'output'), overrides dp.direction
701
700
  * @param {string} [originalAttachmentId] - Original attachment ID for behavior triggering
702
701
  * @returns {HTMLElement}
@@ -167,6 +167,8 @@ var SceneExportManager = /*#__PURE__*/function () {
167
167
  // Internal tracking - not needed in export
168
168
  'initialPosition',
169
169
  // Internal tracking - not needed in export
170
+ 'attachedDevices',
171
+ // Stored in smart component dictionary, not scene JSON
170
172
  // Exclude internal segment tracking properties
171
173
  'segmentId',
172
174
  // Internal tracking
@@ -239,11 +241,11 @@ var SceneExportManager = /*#__PURE__*/function () {
239
241
  };
240
242
  }
241
243
 
242
- // For components: no children exported connector positions are defined in the component
243
- // dictionary GLB and will be re-injected at import time via _injectConnectorChildrenFromDictionary.
244
- // Exporting them here would prevent that injection (it skips if children already exist)
245
- // and would leave the pathfinder with connectors in incompatible local-position format.
244
+ // For components: only export child connectors if they were manually added/defined.
245
+ // Most connectors are injected from dictionary at import time, but some (like manually placed ones)
246
+ // need to be persisted to maintain connections in the exported scene.
246
247
  if (threeObject.children && threeObject.children.length > 0) {
248
+ var _threeObject$userData11;
247
249
  var exportableChildren = [];
248
250
  if (isManualSegment) {
249
251
  // For manual segments, export their connector children
@@ -257,6 +259,25 @@ var SceneExportManager = /*#__PURE__*/function () {
257
259
  }
258
260
  }
259
261
  });
262
+ } else if (((_threeObject$userData11 = threeObject.userData) === null || _threeObject$userData11 === void 0 ? void 0 : _threeObject$userData11.objectType) === 'component') {
263
+ // For components, only export connectors that have objectType='connector'
264
+ // Standard dictionary-injected connectors should be exported so connections work on re-import
265
+ threeObject.children.forEach(function (child) {
266
+ var _child$userData2;
267
+ if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType) === 'connector') {
268
+ exportableChildren.push({
269
+ uuid: child.uuid,
270
+ name: child.name,
271
+ type: 'Mesh',
272
+ position: {
273
+ x: roundIfClose(child.position.x),
274
+ y: roundIfClose(child.position.y),
275
+ z: roundIfClose(child.position.z)
276
+ },
277
+ userData: _rollupPluginBabelHelpers.objectSpread2({}, child.userData)
278
+ });
279
+ }
280
+ });
260
281
  }
261
282
  if (exportableChildren.length > 0) {
262
283
  jsonObject.children = exportableChildren;
@@ -271,9 +292,9 @@ var SceneExportManager = /*#__PURE__*/function () {
271
292
  // Extract main scene objects (components and standalone connectors)
272
293
  var sceneChildren = [];
273
294
  this.sceneViewer.scene.children.forEach(function (child) {
274
- var _child$userData2;
295
+ var _child$userData3;
275
296
  // Only export components and connectors; skip segments, gateways, polylines, etc.
276
- var objectType = (_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.objectType;
297
+ var objectType = (_child$userData3 = child.userData) === null || _child$userData3 === void 0 ? void 0 : _child$userData3.objectType;
277
298
  if (objectType !== 'component' && objectType !== 'connector') {
278
299
  return;
279
300
  }
@@ -437,14 +458,14 @@ var SceneExportManager = /*#__PURE__*/function () {
437
458
  BufferGeometryUtils = BufferGeometryUtilsModule.BufferGeometryUtils || BufferGeometryUtilsModule.default || BufferGeometryUtilsModule; // Create a new scene for export instead of cloning
438
459
  exportScene = new _THREE.Scene(); // Helper function to check if an object should be exported
439
460
  shouldExport = function shouldExport(child) {
440
- var _child$name, _child$userData3, _child$userData4, _child$userData5, _child$userData6;
461
+ var _child$name, _child$userData4, _child$userData5, _child$userData6, _child$userData7;
441
462
  if ((_child$name = child.name) !== null && _child$name !== void 0 && _child$name.includes('Polyline')) return false; // Will handle separately
442
463
  if (child.name === 'fogPlane') return false; // Skip fog plane
443
- if ((_child$userData3 = child.userData) !== null && _child$userData3 !== void 0 && _child$userData3.isBrickWall) return false; // Skip environment
444
- if ((_child$userData4 = child.userData) !== null && _child$userData4 !== void 0 && _child$userData4.isBaseGround) return false; // Skip environment
445
- if ((_child$userData5 = child.userData) !== null && _child$userData5 !== void 0 && _child$userData5.isBaseGrid) return false; // Skip environment
464
+ if ((_child$userData4 = child.userData) !== null && _child$userData4 !== void 0 && _child$userData4.isBrickWall) return false; // Skip environment
465
+ if ((_child$userData5 = child.userData) !== null && _child$userData5 !== void 0 && _child$userData5.isBaseGround) return false; // Skip environment
466
+ if ((_child$userData6 = child.userData) !== null && _child$userData6 !== void 0 && _child$userData6.isBaseGrid) return false; // Skip environment
446
467
  if (child.isLight) return false; // Skip lights
447
- if ((_child$userData6 = child.userData) !== null && _child$userData6 !== void 0 && _child$userData6.isTransformControls) return false; // Skip transform controls
468
+ if ((_child$userData7 = child.userData) !== null && _child$userData7 !== void 0 && _child$userData7.isTransformControls) return false; // Skip transform controls
448
469
  if (child.isTransformControls) return false; // Skip transform controls
449
470
  if (child.type && child.type.includes('TransformControls')) return false;
450
471
  if (child.type && child.type.includes('Helper')) return false; // Skip helpers
@@ -1333,51 +1333,36 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1333
1333
  y: componentModel.scale.y,
1334
1334
  z: componentModel.scale.z
1335
1335
  },
1336
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, componentModel.userData), {}, {
1336
+ userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, function () {
1337
+ var ud = _rollupPluginBabelHelpers.objectSpread2({}, componentModel.userData);
1338
+ delete ud.attachedDevices; // Instance data belongs in dictionary, not scene JSON
1339
+ delete ud.isDeclared; // Runtime flag
1340
+ delete ud.originalUuid; // Runtime tracking
1341
+ return ud;
1342
+ }()), {}, {
1337
1343
  worldBoundingBox: {
1338
1344
  min: boundingBox.min.toArray(),
1339
1345
  max: boundingBox.max.toArray()
1340
1346
  }
1341
1347
  }),
1342
- children: []
1348
+ children: [] // Initialize children array
1343
1349
  };
1344
1350
 
1345
- // Process children (connectors, etc.) if they exist
1346
- if (componentModel.children && componentModel.children.length > 0) {
1351
+ // Collect children that are connectors
1352
+ if (componentModel.children) {
1347
1353
  componentModel.children.forEach(function (child) {
1348
- var _child$userData0, _child$userData1;
1349
- var childType = ((_child$userData0 = child.userData) === null || _child$userData0 === void 0 ? void 0 : _child$userData0.objectType) || ((_child$userData1 = child.userData) === null || _child$userData1 === void 0 ? void 0 : _child$userData1.objectType);
1350
- if (childType === 'connector') {
1351
- var _child$geometry;
1352
- var childBoundingBox = new THREE__namespace.Box3().setFromObject(child);
1353
- var childSceneData = {
1354
+ if (child.userData && child.userData.objectType === 'connector') {
1355
+ componentSceneData.children.push({
1354
1356
  uuid: child.uuid,
1355
1357
  name: child.name,
1356
- type: child.type,
1358
+ type: 'Mesh',
1357
1359
  position: {
1358
1360
  x: child.position.x,
1359
1361
  y: child.position.y,
1360
1362
  z: child.position.z
1361
1363
  },
1362
- rotation: {
1363
- x: THREE__namespace.MathUtils.radToDeg(child.rotation.x),
1364
- y: THREE__namespace.MathUtils.radToDeg(child.rotation.y),
1365
- z: THREE__namespace.MathUtils.radToDeg(child.rotation.z)
1366
- },
1367
- scale: {
1368
- x: child.scale.x,
1369
- y: child.scale.y,
1370
- z: child.scale.z
1371
- },
1372
- userData: _rollupPluginBabelHelpers.objectSpread2(_rollupPluginBabelHelpers.objectSpread2({}, child.userData), {}, {
1373
- worldBoundingBox: {
1374
- min: childBoundingBox.min.toArray(),
1375
- max: childBoundingBox.max.toArray()
1376
- }
1377
- }),
1378
- geometry: ((_child$geometry = child.geometry) === null || _child$geometry === void 0 ? void 0 : _child$geometry.uuid) || 'CONNECTOR-GEO'
1379
- };
1380
- componentSceneData.children.push(childSceneData);
1364
+ userData: _rollupPluginBabelHelpers.objectSpread2({}, child.userData)
1365
+ });
1381
1366
  }
1382
1367
  });
1383
1368
  }
@@ -1390,7 +1375,6 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1390
1375
  console.log('✅ addComponentToSceneData: Component added to scene data successfully', {
1391
1376
  componentId: componentModel.uuid,
1392
1377
  libraryId: (_componentModel$userD = componentModel.userData) === null || _componentModel$userD === void 0 ? void 0 : _componentModel$userD.libraryId,
1393
- childrenCount: componentSceneData.children.length,
1394
1378
  totalSceneChildren: currentSceneData.scene.children.length
1395
1379
  });
1396
1380
  return true;
@@ -1431,8 +1415,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
1431
1415
  if (segment.children && segment.children.length > 0) {
1432
1416
  var childrenToRemove = _rollupPluginBabelHelpers.toConsumableArray(segment.children);
1433
1417
  childrenToRemove.forEach(function (child) {
1434
- var _child$userData10;
1435
- if ((_child$userData10 = child.userData) !== null && _child$userData10 !== void 0 && _child$userData10.isPipeElbow) {
1418
+ var _child$userData0;
1419
+ if ((_child$userData0 = child.userData) !== null && _child$userData0 !== void 0 && _child$userData0.isPipeElbow) {
1436
1420
  console.log("\uD83D\uDDD1\uFE0F Removing elbow child from segment before manualization: ".concat(child.uuid));
1437
1421
  segment.remove(child);
1438
1422
  if (child.geometry) child.geometry.dispose();
@@ -30,11 +30,11 @@ function getIoBehaviorManager(sceneViewer) {
30
30
 
31
31
  /**
32
32
  * Resolve tooltip/drag data points for an I/O device attachment.
33
- * Prefers behaviorConfig-driven animation data points; merges legacy ioConfig snapshot.
33
+ * Prefers behaviorConfig-driven animation data points.
34
34
  *
35
35
  * @param {string} parentUuid
36
36
  * @param {string} attachmentId
37
- * @param {Object} userData - io-device userData (may include dataPoints snapshot)
37
+ * @param {Object} userData - io-device userData
38
38
  * @param {import('../managers/behaviors/IoBehaviorManager.js').IoBehaviorManager|null} ioBehaviorManager
39
39
  * @param {THREE.Object3D|null} [hitMesh]
40
40
  * @returns {Object[]}
@@ -42,21 +42,7 @@ function getIoBehaviorManager(sceneViewer) {
42
42
  function resolveDataPoints(parentUuid, attachmentId, userData, ioBehaviorManager) {
43
43
  var hitMesh = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
44
44
  var fromAnimations = (ioBehaviorManager === null || ioBehaviorManager === void 0 ? void 0 : ioBehaviorManager.getAnimationDataPoints(parentUuid, attachmentId, hitMesh)) || [];
45
- if (fromAnimations.length) return fromAnimations;
46
- var legacy = (userData === null || userData === void 0 ? void 0 : userData.dataPoints) || [];
47
- return legacy.map(function (dp) {
48
- var _dp$defaultValue;
49
- return {
50
- id: dp.id || dp.name,
51
- name: dp.name || dp.id,
52
- stateType: dp.stateType || 'binary',
53
- stateConfig: dp.stateConfig || {},
54
- defaultValue: (_dp$defaultValue = dp.defaultValue) !== null && _dp$defaultValue !== void 0 ? _dp$defaultValue : null,
55
- direction: dp.direction || (userData === null || userData === void 0 ? void 0 : userData.ioDirection) || 'output'
56
- };
57
- }).filter(function (dp) {
58
- return dp.id;
59
- });
45
+ return fromAnimations;
60
46
  }
61
47
 
62
48
  /**
@@ -87,35 +73,18 @@ function applyDefaultIoDeviceStates(centralPlant) {
87
73
  if (seen.has(scopedKey)) return;
88
74
  seen.add(scopedKey);
89
75
  var dps = ioBehavMgr.getAnimationDataPoints(objParentUuid, objAttachmentId) || [];
90
- if (dps.length) {
91
- var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(dps),
92
- _step;
93
- try {
94
- for (_iterator.s(); !(_step = _iterator.n()).done;) {
95
- var dp = _step.value;
96
- if (!(dp !== null && dp !== void 0 && dp.id) || dp.defaultValue === undefined || dp.defaultValue === null) continue;
97
- centralPlant.setIoDeviceState(objAttachmentId, dp.id, dp.defaultValue, objParentUuid);
98
- }
99
- } catch (err) {
100
- _iterator.e(err);
101
- } finally {
102
- _iterator.f();
103
- }
104
- return;
105
- }
106
- var _iterator2 = _rollupPluginBabelHelpers.createForOfIteratorHelper(obj.userData.dataPoints || []),
107
- _step2;
76
+ var _iterator = _rollupPluginBabelHelpers.createForOfIteratorHelper(dps),
77
+ _step;
108
78
  try {
109
- for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
110
- var _dp = _step2.value;
111
- var dpId = _dp.id || _dp.name;
112
- if (!dpId || _dp.defaultValue === undefined || _dp.defaultValue === null) continue;
113
- centralPlant.setIoDeviceState(objAttachmentId, dpId, _dp.defaultValue, objParentUuid);
79
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
80
+ var dp = _step.value;
81
+ if (!(dp !== null && dp !== void 0 && dp.id) || dp.defaultValue === undefined || dp.defaultValue === null) continue;
82
+ centralPlant.setIoDeviceState(objAttachmentId, dp.id, dp.defaultValue, objParentUuid);
114
83
  }
115
84
  } catch (err) {
116
- _iterator2.e(err);
85
+ _iterator.e(err);
117
86
  } finally {
118
- _iterator2.f();
87
+ _iterator.f();
119
88
  }
120
89
  });
121
90
  }