@2112-lab/central-plant 0.1.87 → 0.1.90
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/bundle/index.js +241 -155
- package/dist/cjs/src/core/centralPlant.js +47 -4
- package/dist/cjs/src/core/centralPlantInternals.js +2 -90
- package/dist/cjs/src/core/centralPlantValidator.js +1 -1
- package/dist/cjs/src/managers/components/componentDataManager.js +4 -1
- package/dist/cjs/src/managers/components/componentManager.js +5 -1
- package/dist/cjs/src/managers/scene/modelManager.js +47 -19
- package/dist/cjs/src/managers/scene/sceneOperationsManager.js +40 -39
- package/dist/cjs/src/utils/ioDeviceUtils.js +104 -0
- package/dist/esm/src/core/centralPlant.js +47 -4
- package/dist/esm/src/core/centralPlantInternals.js +3 -91
- package/dist/esm/src/core/centralPlantValidator.js +1 -1
- package/dist/esm/src/managers/components/componentDataManager.js +4 -1
- package/dist/esm/src/managers/components/componentManager.js +5 -1
- package/dist/esm/src/managers/scene/modelManager.js +47 -19
- package/dist/esm/src/managers/scene/sceneOperationsManager.js +40 -39
- package/dist/esm/src/utils/ioDeviceUtils.js +100 -0
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
15
15
|
* Initialize the CentralPlant manager
|
|
16
16
|
*
|
|
17
17
|
* @constructor
|
|
18
|
-
* @version 0.1.
|
|
18
|
+
* @version 0.1.90
|
|
19
19
|
* @updated 2025-10-22
|
|
20
20
|
*
|
|
21
21
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -1515,6 +1515,50 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
1515
1515
|
}
|
|
1516
1516
|
return removeComponentFromDictionary;
|
|
1517
1517
|
}()
|
|
1518
|
+
/**
|
|
1519
|
+
* Get library IDs from scene data that are missing from the component dictionary
|
|
1520
|
+
* @param {Object} sceneData - Scene JSON data to analyze
|
|
1521
|
+
* @returns {string[]} Array of library IDs that are not in the current component dictionary
|
|
1522
|
+
* @description Analyzes scene data to find components whose libraryId is not present in the
|
|
1523
|
+
* component dictionary. This is useful for detecting S3 components that need to be fetched
|
|
1524
|
+
* before importing a scene.
|
|
1525
|
+
* @example
|
|
1526
|
+
* // Check for missing components before import
|
|
1527
|
+
* const missingIds = centralPlant.getMissingLibraryIds(sceneJson);
|
|
1528
|
+
* if (missingIds.length > 0) {
|
|
1529
|
+
* // Fetch missing S3 components
|
|
1530
|
+
* await fetchS3Components(missingIds);
|
|
1531
|
+
* await centralPlant.extendComponentDictionary(fetchedComponents);
|
|
1532
|
+
* }
|
|
1533
|
+
* // Now safe to import
|
|
1534
|
+
* await centralPlant.importScene(sceneJson);
|
|
1535
|
+
*/
|
|
1536
|
+
)
|
|
1537
|
+
}, {
|
|
1538
|
+
key: "getMissingLibraryIds",
|
|
1539
|
+
value: function getMissingLibraryIds(sceneData) {
|
|
1540
|
+
var _sceneData$scene, _this$managers$compon;
|
|
1541
|
+
if (!(sceneData !== null && sceneData !== void 0 && (_sceneData$scene = sceneData.scene) !== null && _sceneData$scene !== void 0 && _sceneData$scene.children) || !Array.isArray(sceneData.scene.children)) {
|
|
1542
|
+
return [];
|
|
1543
|
+
}
|
|
1544
|
+
var componentDictionary = ((_this$managers$compon = this.managers.componentDataManager) === null || _this$managers$compon === void 0 ? void 0 : _this$managers$compon.componentDictionary) || {};
|
|
1545
|
+
var missingIds = [];
|
|
1546
|
+
sceneData.scene.children.forEach(function (child) {
|
|
1547
|
+
var _child$userData;
|
|
1548
|
+
var libraryId = (_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.libraryId;
|
|
1549
|
+
if (libraryId && !componentDictionary[libraryId]) {
|
|
1550
|
+
// Only add unique IDs
|
|
1551
|
+
if (!missingIds.includes(libraryId)) {
|
|
1552
|
+
missingIds.push(libraryId);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
});
|
|
1556
|
+
if (missingIds.length > 0) {
|
|
1557
|
+
console.log("\uD83D\uDD0D Found ".concat(missingIds.length, " missing library IDs in scene data:"), missingIds);
|
|
1558
|
+
}
|
|
1559
|
+
return missingIds;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1518
1562
|
/**
|
|
1519
1563
|
* Select an object (component, connector, or gateway) in the scene by its ID
|
|
1520
1564
|
* @param {string} objectId - The UUID or name of the object to select
|
|
@@ -1551,7 +1595,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
1551
1595
|
* centralPlant.selectComponent(targetObject.uuid);
|
|
1552
1596
|
* }
|
|
1553
1597
|
*/
|
|
1554
|
-
)
|
|
1555
1598
|
}, {
|
|
1556
1599
|
key: "selectComponent",
|
|
1557
1600
|
value: function selectComponent(objectId) {
|
|
@@ -1580,8 +1623,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
1580
1623
|
// If still not found, try finding by originalUuid in userData
|
|
1581
1624
|
if (!targetObject) {
|
|
1582
1625
|
this.sceneViewer.scene.traverse(function (child) {
|
|
1583
|
-
var _child$
|
|
1584
|
-
if (((_child$
|
|
1626
|
+
var _child$userData2;
|
|
1627
|
+
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.originalUuid) === objectId) {
|
|
1585
1628
|
targetObject = child;
|
|
1586
1629
|
return;
|
|
1587
1630
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createClass as _createClass, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof,
|
|
1
|
+
import { createClass as _createClass, objectSpread2 as _objectSpread2, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
3
|
import { CentralPlantValidator } from './centralPlantValidator.js';
|
|
4
4
|
import { createTransformControls } from '../managers/controls/transformControlsManager.js';
|
|
@@ -23,6 +23,7 @@ import { SceneTooltipsManager } from '../managers/scene/sceneTooltipsManager.js'
|
|
|
23
23
|
import { ComponentTooltipManager } from '../managers/scene/componentTooltipManager.js';
|
|
24
24
|
import { Viewport2DManager } from '../managers/scene/viewport2DManager.js';
|
|
25
25
|
import { generateUuidFromName, getHardcodedUuid, findObjectByHardcodedUuid, generateUniqueComponentId } from '../utils/nameUtils.js';
|
|
26
|
+
import { attachIODevicesToComponent } from '../utils/ioDeviceUtils.js';
|
|
26
27
|
import modelPreloader from '../rendering/modelPreloader.js';
|
|
27
28
|
|
|
28
29
|
/**
|
|
@@ -1054,7 +1055,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1054
1055
|
|
|
1055
1056
|
// Add attached IO device models for smart components
|
|
1056
1057
|
if (componentData.isSmart && componentData.attachedDevices) {
|
|
1057
|
-
|
|
1058
|
+
attachIODevicesToComponent(componentModel, componentData, modelPreloader, componentId);
|
|
1058
1059
|
}
|
|
1059
1060
|
|
|
1060
1061
|
// Notify the component manager about the new component
|
|
@@ -1107,95 +1108,6 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
1107
1108
|
}
|
|
1108
1109
|
}
|
|
1109
1110
|
|
|
1110
|
-
/**
|
|
1111
|
-
* Attach IO device models to a smart component from cached models.
|
|
1112
|
-
* Each device referenced in componentData.attachedDevices is looked up
|
|
1113
|
-
* in the model preloader cache, cloned, positioned, and added as a child.
|
|
1114
|
-
* @param {THREE.Object3D} componentModel - The parent component model
|
|
1115
|
-
* @param {Object} componentData - Component dictionary entry (has attachedDevices)
|
|
1116
|
-
* @param {Object} modelPreloader - ModelPreloader instance
|
|
1117
|
-
* @param {string} parentComponentId - The parent component's UUID
|
|
1118
|
-
* @private
|
|
1119
|
-
*/
|
|
1120
|
-
}, {
|
|
1121
|
-
key: "_attachIODevicesToComponent",
|
|
1122
|
-
value: function _attachIODevicesToComponent(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
1123
|
-
var attachedDevices = componentData.attachedDevices;
|
|
1124
|
-
console.log("\uD83D\uDD0C addComponent(): Attaching ".concat(Object.keys(attachedDevices).length, " IO devices to smart component"));
|
|
1125
|
-
for (var _i = 0, _Object$entries = Object.entries(attachedDevices); _i < _Object$entries.length; _i++) {
|
|
1126
|
-
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
1127
|
-
attachmentId = _Object$entries$_i[0],
|
|
1128
|
-
attachment = _Object$entries$_i[1];
|
|
1129
|
-
try {
|
|
1130
|
-
var _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen;
|
|
1131
|
-
var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
1132
|
-
if (!deviceData || !deviceData.modelKey) {
|
|
1133
|
-
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary, skipping"));
|
|
1134
|
-
continue;
|
|
1135
|
-
}
|
|
1136
|
-
var cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
1137
|
-
if (!cachedDevice) {
|
|
1138
|
-
console.warn("\u26A0\uFE0F IO device model not in cache: ".concat(deviceData.modelKey, ", skipping"));
|
|
1139
|
-
continue;
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
// Clone so each component instance owns its own io-device subtree and materials.
|
|
1143
|
-
// Without this, all placed copies of the same smart component share the cached
|
|
1144
|
-
// object, causing material mutations (from behaviors) to bleed across instances.
|
|
1145
|
-
var deviceModel = cachedDevice.clone();
|
|
1146
|
-
deviceModel.traverse(function (child) {
|
|
1147
|
-
if (child.isMesh && child.material) {
|
|
1148
|
-
child.material = Array.isArray(child.material) ? child.material.map(function (m) {
|
|
1149
|
-
return m.clone();
|
|
1150
|
-
}) : child.material.clone();
|
|
1151
|
-
}
|
|
1152
|
-
});
|
|
1153
|
-
|
|
1154
|
-
// Name the device model
|
|
1155
|
-
deviceModel.name = "".concat(attachment.attachmentLabel || 'IO Device', " (").concat(attachmentId, ")");
|
|
1156
|
-
|
|
1157
|
-
// Set user data for identification — include ioConfig data points so the
|
|
1158
|
-
// component tooltip can render state displays without an extra lookup.
|
|
1159
|
-
deviceModel.userData = {
|
|
1160
|
-
objectType: 'io-device',
|
|
1161
|
-
deviceId: attachment.deviceId,
|
|
1162
|
-
attachmentId: attachmentId,
|
|
1163
|
-
attachmentLabel: attachment.attachmentLabel,
|
|
1164
|
-
parentComponentId: parentComponentId,
|
|
1165
|
-
deviceName: deviceData.name || '',
|
|
1166
|
-
// Snapshot of the device's data point definitions (stateType, stateConfig, direction, etc.)
|
|
1167
|
-
// ioConfig can use either 'states' (preferred) or legacy 'dataPoints' as the array key
|
|
1168
|
-
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) || [],
|
|
1169
|
-
// Device-level I/O direction: 'input' means the user can write state via the tooltip
|
|
1170
|
-
ioDirection: ((_deviceData$ioConfig3 = deviceData.ioConfig) === null || _deviceData$ioConfig3 === void 0 ? void 0 : _deviceData$ioConfig3.direction) || 'output',
|
|
1171
|
-
// Signal wiring sourced from this attachment (for state propagation reference)
|
|
1172
|
-
signalOutputs: attachment.signalOutputs || []
|
|
1173
|
-
};
|
|
1174
|
-
|
|
1175
|
-
// Position at the attachment point
|
|
1176
|
-
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
1177
|
-
var pos = attachment.attachmentPoint.position;
|
|
1178
|
-
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
// IO device models are authored at the same real-world unit scale
|
|
1182
|
-
// as the host component, so keep them at their natural (1:1) size.
|
|
1183
|
-
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
1184
|
-
// NOT a desired device model scale.
|
|
1185
|
-
deviceModel.scale.setScalar(1);
|
|
1186
|
-
|
|
1187
|
-
// Add as child of the component
|
|
1188
|
-
componentModel.add(deviceModel);
|
|
1189
|
-
console.log("\u2705 Attached IO device: ".concat(attachment.attachmentLabel || attachment.deviceId, " at"), {
|
|
1190
|
-
position: deviceModel.position,
|
|
1191
|
-
scale: deviceModel.scale
|
|
1192
|
-
});
|
|
1193
|
-
} catch (err) {
|
|
1194
|
-
console.error("\u274C Error attaching IO device ".concat(attachment.deviceId, ":"), err);
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
}
|
|
1198
|
-
|
|
1199
1111
|
/**
|
|
1200
1112
|
* Delete a component from the scene by componentId (internal implementation)
|
|
1201
1113
|
* @param {string} componentId - The UUID of the component to delete
|
|
@@ -817,7 +817,7 @@ var CentralPlantValidator = /*#__PURE__*/function () {
|
|
|
817
817
|
key: "validateImportedSceneData",
|
|
818
818
|
value: function validateImportedSceneData(sceneData) {
|
|
819
819
|
var results = [];
|
|
820
|
-
var hardcodedVersion = "2.
|
|
820
|
+
var hardcodedVersion = "2.3";
|
|
821
821
|
|
|
822
822
|
// Version validation - MUST be the value of hardcodedVersion
|
|
823
823
|
if (!sceneData.version || sceneData.version !== hardcodedVersion) {
|
|
@@ -821,6 +821,7 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
821
821
|
id: key,
|
|
822
822
|
name: component.name,
|
|
823
823
|
type: ((_component$metadata = component.metadata) === null || _component$metadata === void 0 ? void 0 : _component$metadata.type) || 'Component',
|
|
824
|
+
assetType: component.assetType || null,
|
|
824
825
|
category: component.category,
|
|
825
826
|
modelKey: component.modelKey,
|
|
826
827
|
modelType: component.modelType,
|
|
@@ -829,10 +830,12 @@ var ComponentDataManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
829
830
|
// Preserve S3 metadata
|
|
830
831
|
isS3Component: component.isS3Component,
|
|
831
832
|
s3Path: component.s3Path,
|
|
832
|
-
preLoad: component.preLoad
|
|
833
|
+
preLoad: component.preLoad,
|
|
834
|
+
preCache: component.preCache
|
|
833
835
|
};
|
|
834
836
|
return _objectSpread2(_objectSpread2({}, baseData), {}, {
|
|
835
837
|
metadata: component.metadata || {},
|
|
838
|
+
ioConfig: component.ioConfig || null,
|
|
836
839
|
boundingBox: component.boundingBox || null,
|
|
837
840
|
adaptedBoundingBox: component.adaptedBoundingBox || null,
|
|
838
841
|
children: component.children || [],
|
|
@@ -93,12 +93,16 @@ var ComponentManager = /*#__PURE__*/function () {
|
|
|
93
93
|
componentMesh.position.set(position.x, position.y, position.z);
|
|
94
94
|
|
|
95
95
|
// Set userData for the component including dimensions
|
|
96
|
-
componentMesh.userData = _objectSpread2({
|
|
96
|
+
componentMesh.userData = _objectSpread2(_objectSpread2({
|
|
97
97
|
libraryId: componentData.libraryId,
|
|
98
98
|
objectType: 'component',
|
|
99
99
|
originalUuid: uuid
|
|
100
100
|
}, ((_gltfScene$userData = gltfScene.userData) === null || _gltfScene$userData === void 0 ? void 0 : _gltfScene$userData.dimensions) && {
|
|
101
101
|
dimensions: gltfScene.userData.dimensions
|
|
102
|
+
}), libraryComponent.isS3Component && {
|
|
103
|
+
isS3Component: true,
|
|
104
|
+
s3Path: libraryComponent.s3Path,
|
|
105
|
+
componentKey: libraryComponent.componentKey
|
|
102
106
|
});
|
|
103
107
|
|
|
104
108
|
// Also ensure dimensions are preserved in the userData
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createClass as _createClass, objectSpread2 as _objectSpread2, toConsumableArray as _toConsumableArray, classCallCheck as _classCallCheck, asyncToGenerator as _asyncToGenerator, regenerator as _regenerator, createForOfIteratorHelper as _createForOfIteratorHelper, typeof as _typeof } from '../../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
import { attachIODevicesToComponent } from '../../utils/ioDeviceUtils.js';
|
|
3
4
|
import modelPreloader from '../../rendering/modelPreloader.js';
|
|
4
5
|
|
|
5
6
|
var ModelManager = /*#__PURE__*/function () {
|
|
@@ -85,6 +86,11 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
85
86
|
libraryModel.add(connector);
|
|
86
87
|
});
|
|
87
88
|
|
|
89
|
+
// Attach IO devices for smart components (import flow)
|
|
90
|
+
if (componentData.isSmart && componentData.attachedDevices) {
|
|
91
|
+
attachIODevicesToComponent(libraryModel, componentData, modelPreloader, originalProps.uuid);
|
|
92
|
+
}
|
|
93
|
+
|
|
88
94
|
// Replace mesh in scene
|
|
89
95
|
this._replaceMeshInScene(targetMesh, libraryModel, originalProps.parent, component);
|
|
90
96
|
console.log("\uD83C\uDF89 ".concat((_jsonEntry$userData3 = jsonEntry.userData) === null || _jsonEntry$userData3 === void 0 ? void 0 : _jsonEntry$userData3.libraryId, " GLB model successfully rendered in scene"));
|
|
@@ -161,7 +167,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
161
167
|
value: (function () {
|
|
162
168
|
var _getLibraryModel2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(modelKey, libraryId) {
|
|
163
169
|
var _this2 = this;
|
|
164
|
-
var gltfScene, preloaderStatus, modelPath, gltf, _t2, _t3;
|
|
170
|
+
var gltfScene, preloaderStatus, modelPath, gltf, _t2, _t3, _t4;
|
|
165
171
|
return _regenerator().w(function (_context2) {
|
|
166
172
|
while (1) switch (_context2.n) {
|
|
167
173
|
case 0:
|
|
@@ -198,25 +204,47 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
198
204
|
console.warn("\u26A0\uFE0F Preloading failed:", _t2);
|
|
199
205
|
case 6:
|
|
200
206
|
_context2.p = 6;
|
|
207
|
+
if (!modelPreloader.urlResolver) {
|
|
208
|
+
_context2.n = 11;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
_context2.p = 7;
|
|
212
|
+
_context2.n = 8;
|
|
213
|
+
return modelPreloader.urlResolver(modelKey);
|
|
214
|
+
case 8:
|
|
215
|
+
modelPath = _context2.v;
|
|
216
|
+
console.log("\uD83D\uDD17 Resolved URL for ".concat(modelKey));
|
|
217
|
+
_context2.n = 10;
|
|
218
|
+
break;
|
|
219
|
+
case 9:
|
|
220
|
+
_context2.p = 9;
|
|
221
|
+
_t3 = _context2.v;
|
|
222
|
+
console.warn("\u26A0\uFE0F URL resolver failed for ".concat(modelKey, ", falling back to local path:"), _t3);
|
|
223
|
+
modelPath = "".concat(modelPreloader.modelsBasePath).concat(modelKey);
|
|
224
|
+
case 10:
|
|
225
|
+
_context2.n = 12;
|
|
226
|
+
break;
|
|
227
|
+
case 11:
|
|
201
228
|
modelPath = "".concat(modelPreloader.modelsBasePath).concat(modelKey);
|
|
229
|
+
case 12:
|
|
202
230
|
console.log("\uD83D\uDCC2 Fallback loading from: ".concat(modelPath));
|
|
203
|
-
_context2.n =
|
|
231
|
+
_context2.n = 13;
|
|
204
232
|
return new Promise(function (resolve, reject) {
|
|
205
233
|
_this2.sceneViewer.gltfLoader.load(modelPath, resolve, undefined, reject);
|
|
206
234
|
});
|
|
207
|
-
case
|
|
235
|
+
case 13:
|
|
208
236
|
gltf = _context2.v;
|
|
209
237
|
if (libraryId) {
|
|
210
238
|
modelPreloader.cacheModel(modelKey, gltf.scene.clone(), libraryId);
|
|
211
239
|
}
|
|
212
240
|
return _context2.a(2, gltf.scene);
|
|
213
|
-
case
|
|
214
|
-
_context2.p =
|
|
215
|
-
|
|
216
|
-
console.error("Failed to load model ".concat(modelKey, ":"),
|
|
241
|
+
case 14:
|
|
242
|
+
_context2.p = 14;
|
|
243
|
+
_t4 = _context2.v;
|
|
244
|
+
console.error("Failed to load model ".concat(modelKey, ":"), _t4);
|
|
217
245
|
return _context2.a(2, null);
|
|
218
246
|
}
|
|
219
|
-
}, _callee2, null, [[6,
|
|
247
|
+
}, _callee2, null, [[7, 9], [6, 14], [2, 5]]);
|
|
220
248
|
}));
|
|
221
249
|
function _getLibraryModel(_x4, _x5) {
|
|
222
250
|
return _getLibraryModel2.apply(this, arguments);
|
|
@@ -315,7 +343,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
315
343
|
key: "verifyModelPreloaderCache",
|
|
316
344
|
value: (function () {
|
|
317
345
|
var _verifyModelPreloaderCache = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
318
|
-
var preloaderStatus,
|
|
346
|
+
var preloaderStatus, _t5;
|
|
319
347
|
return _regenerator().w(function (_context3) {
|
|
320
348
|
while (1) switch (_context3.n) {
|
|
321
349
|
case 0:
|
|
@@ -338,8 +366,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
338
366
|
break;
|
|
339
367
|
case 3:
|
|
340
368
|
_context3.p = 3;
|
|
341
|
-
|
|
342
|
-
console.warn('⚠️ Model preloading failed, some models may load directly:',
|
|
369
|
+
_t5 = _context3.v;
|
|
370
|
+
console.warn('⚠️ Model preloading failed, some models may load directly:', _t5);
|
|
343
371
|
case 4:
|
|
344
372
|
return _context3.a(2, preloaderStatus);
|
|
345
373
|
}
|
|
@@ -358,7 +386,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
358
386
|
key: "preloadMissingModels",
|
|
359
387
|
value: (function () {
|
|
360
388
|
var _preloadMissingModels = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(data, componentDictionary) {
|
|
361
|
-
var _data$scene, _data$scene2, requiredModels, preloaderStatus, cachedModels, missingModels, basePath, modelUrls, _iterator, _step, modelKey,
|
|
389
|
+
var _data$scene, _data$scene2, requiredModels, preloaderStatus, cachedModels, missingModels, basePath, modelUrls, _iterator, _step, modelKey, _t6, _t7;
|
|
362
390
|
return _regenerator().w(function (_context4) {
|
|
363
391
|
while (1) switch (_context4.n) {
|
|
364
392
|
case 0:
|
|
@@ -453,8 +481,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
453
481
|
break;
|
|
454
482
|
case 7:
|
|
455
483
|
_context4.p = 7;
|
|
456
|
-
|
|
457
|
-
console.warn("\u274C Failed to preload missing model ".concat(modelKey, ":"),
|
|
484
|
+
_t6 = _context4.v;
|
|
485
|
+
console.warn("\u274C Failed to preload missing model ".concat(modelKey, ":"), _t6);
|
|
458
486
|
case 8:
|
|
459
487
|
_context4.n = 4;
|
|
460
488
|
break;
|
|
@@ -463,8 +491,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
463
491
|
break;
|
|
464
492
|
case 10:
|
|
465
493
|
_context4.p = 10;
|
|
466
|
-
|
|
467
|
-
_iterator.e(
|
|
494
|
+
_t7 = _context4.v;
|
|
495
|
+
_iterator.e(_t7);
|
|
468
496
|
case 11:
|
|
469
497
|
_context4.p = 11;
|
|
470
498
|
_iterator.f();
|
|
@@ -569,7 +597,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
569
597
|
key: "loadComponentDictionary",
|
|
570
598
|
value: (function () {
|
|
571
599
|
var _loadComponentDictionary = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
|
|
572
|
-
var response, dict,
|
|
600
|
+
var response, dict, _t8;
|
|
573
601
|
return _regenerator().w(function (_context6) {
|
|
574
602
|
while (1) switch (_context6.n) {
|
|
575
603
|
case 0:
|
|
@@ -587,8 +615,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
587
615
|
return _context6.a(2, dict);
|
|
588
616
|
case 3:
|
|
589
617
|
_context6.p = 3;
|
|
590
|
-
|
|
591
|
-
console.warn('⚠️ Could not load component dictionary:',
|
|
618
|
+
_t8 = _context6.v;
|
|
619
|
+
console.warn('⚠️ Could not load component dictionary:', _t8);
|
|
592
620
|
return _context6.a(2, {});
|
|
593
621
|
}
|
|
594
622
|
}, _callee6, null, [[0, 3]]);
|
|
@@ -188,7 +188,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
188
188
|
return createSceneMaterials;
|
|
189
189
|
}()
|
|
190
190
|
/**
|
|
191
|
-
* Helper function to create geometries
|
|
191
|
+
* Helper function to create geometries for connectors and gateways
|
|
192
|
+
* Components use GLB geometry directly, no placeholder needed
|
|
192
193
|
*/
|
|
193
194
|
)
|
|
194
195
|
}, {
|
|
@@ -203,7 +204,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
203
204
|
return geometries;
|
|
204
205
|
}
|
|
205
206
|
|
|
206
|
-
// Create geometries
|
|
207
|
+
// Create geometries only for connectors and gateways (components use GLB geometry)
|
|
207
208
|
data.scene.children.forEach(function (child) {
|
|
208
209
|
var _child$userData, _child$userData2;
|
|
209
210
|
// Skip manual segments - they create their own geometry
|
|
@@ -212,42 +213,28 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
212
213
|
console.log("\u23ED\uFE0F Skipping geometry creation for manual segment: ".concat(child.uuid));
|
|
213
214
|
return;
|
|
214
215
|
}
|
|
215
|
-
if ((_child$userData2 = child.userData) !== null && _child$userData2 !== void 0 && _child$userData2.libraryId && componentDictionary[child.userData.libraryId]) {
|
|
216
|
-
var component = componentDictionary[child.userData.libraryId];
|
|
217
|
-
var boundingBox = component.boundingBox;
|
|
218
216
|
|
|
219
|
-
|
|
220
|
-
|
|
217
|
+
// Skip components - they will use GLB geometry directly
|
|
218
|
+
if ((_child$userData2 = child.userData) !== null && _child$userData2 !== void 0 && _child$userData2.libraryId) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
221
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
//
|
|
233
|
-
var
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
// Match computed gateway size (0.15) for gateways, keep 0.1 for connectors
|
|
237
|
-
var sphereRadius = isGateway ? 0.15 : 0.1;
|
|
238
|
-
geometries[geometryKey] = new THREE.SphereGeometry(sphereRadius, 16, 16);
|
|
239
|
-
console.log("\uD83D\uDD2E Created shared sphere geometry for ".concat(isGateway ? 'gateways' : 'connectors', " (radius: ").concat(sphereRadius, ")"));
|
|
240
|
-
}
|
|
222
|
+
// For non-library objects (connectors, gateways), create shared sphere geometry
|
|
223
|
+
var isConnectorOrGateway = child.uuid && (child.uuid.toLowerCase().includes('connector') || child.uuid.toLowerCase().includes('gateway'));
|
|
224
|
+
console.log("createSceneGeometries child:", child);
|
|
225
|
+
if (isConnectorOrGateway) {
|
|
226
|
+
// Check if position exists and is not at origin
|
|
227
|
+
if (child.position && !(child.position.x == 0 && child.position.y == 0 && child.position.z == 0)) {
|
|
228
|
+
// Determine if this is a gateway or connector
|
|
229
|
+
var isGateway = child.uuid.toLowerCase().includes('gateway');
|
|
230
|
+
var geometryKey = isGateway ? 'GATEWAY_SPHERE' : 'CONNECTOR_GATEWAY_SPHERE';
|
|
231
|
+
if (!geometries[geometryKey]) {
|
|
232
|
+
// Match computed gateway size (0.15) for gateways, keep 0.1 for connectors
|
|
233
|
+
var sphereRadius = isGateway ? 0.15 : 0.1;
|
|
234
|
+
geometries[geometryKey] = new THREE.SphereGeometry(sphereRadius, 16, 16);
|
|
235
|
+
console.log("\uD83D\uDD2E Created shared sphere geometry for ".concat(isGateway ? 'gateways' : 'connectors', " (radius: ").concat(sphereRadius, ")"));
|
|
241
236
|
}
|
|
242
237
|
}
|
|
243
|
-
// else {
|
|
244
|
-
// // Default fallback geometry
|
|
245
|
-
// const geometryKey = child.geometry || 'FALLBACK_BOX'
|
|
246
|
-
// if (!geometries[geometryKey]) {
|
|
247
|
-
// geometries[geometryKey] = new THREE.BoxGeometry(1, 1, 1)
|
|
248
|
-
// console.log(`📦 Created fallback box geometry`)
|
|
249
|
-
// }
|
|
250
|
-
// }
|
|
251
238
|
}
|
|
252
239
|
});
|
|
253
240
|
return geometries;
|
|
@@ -1011,7 +998,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1011
998
|
key: "_createBasicSceneObjects",
|
|
1012
999
|
value: (function () {
|
|
1013
1000
|
var _createBasicSceneObjects2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
|
|
1014
|
-
var
|
|
1001
|
+
var _this$sceneViewer$cen,
|
|
1002
|
+
_this4 = this;
|
|
1015
1003
|
var componentDictionary, _yield$this$createSce, materials, crosscubeTextureSet, geometries, libraryObjectsToReplace;
|
|
1016
1004
|
return _regenerator().w(function (_context6) {
|
|
1017
1005
|
while (1) switch (_context6.n) {
|
|
@@ -1022,20 +1010,33 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
1022
1010
|
}
|
|
1023
1011
|
throw new Error('Invalid scene data structure: data.scene.children must be an array');
|
|
1024
1012
|
case 1:
|
|
1013
|
+
// Use the extended component dictionary (includes S3 components) if available,
|
|
1014
|
+
// otherwise fall back to loading from static file
|
|
1015
|
+
componentDictionary = (_this$sceneViewer$cen = this.sceneViewer.centralPlant) === null || _this$sceneViewer$cen === void 0 || (_this$sceneViewer$cen = _this$sceneViewer$cen.managers) === null || _this$sceneViewer$cen === void 0 || (_this$sceneViewer$cen = _this$sceneViewer$cen.componentDataManager) === null || _this$sceneViewer$cen === void 0 ? void 0 : _this$sceneViewer$cen.componentDictionary;
|
|
1016
|
+
if (componentDictionary) {
|
|
1017
|
+
_context6.n = 3;
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
1020
|
+
console.log('⚠️ Extended dictionary not available, loading from static file');
|
|
1025
1021
|
_context6.n = 2;
|
|
1026
1022
|
return this.modelManager.loadComponentDictionary();
|
|
1027
1023
|
case 2:
|
|
1028
1024
|
componentDictionary = _context6.v;
|
|
1025
|
+
_context6.n = 4;
|
|
1026
|
+
break;
|
|
1027
|
+
case 3:
|
|
1028
|
+
console.log("\u2705 Using extended component dictionary (".concat(Object.keys(componentDictionary).length, " components)"));
|
|
1029
|
+
case 4:
|
|
1029
1030
|
// Inject connector children from component dictionary into scene data
|
|
1030
1031
|
this._injectConnectorChildrenFromDictionary(data, componentDictionary);
|
|
1031
1032
|
|
|
1032
1033
|
// Ensure models are preloaded
|
|
1033
|
-
_context6.n =
|
|
1034
|
+
_context6.n = 5;
|
|
1034
1035
|
return this.modelManager.preloadMissingModels(data, componentDictionary);
|
|
1035
|
-
case
|
|
1036
|
-
_context6.n =
|
|
1036
|
+
case 5:
|
|
1037
|
+
_context6.n = 6;
|
|
1037
1038
|
return this.createSceneMaterials(data);
|
|
1038
|
-
case
|
|
1039
|
+
case 6:
|
|
1039
1040
|
_yield$this$createSce = _context6.v;
|
|
1040
1041
|
materials = _yield$this$createSce.materials;
|
|
1041
1042
|
crosscubeTextureSet = _yield$this$createSce.crosscubeTextureSet;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { slicedToArray as _slicedToArray } from '../../_virtual/_rollupPluginBabelHelpers.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* IO Device Utilities
|
|
5
|
+
* Shared utility functions for attaching IO devices to smart components.
|
|
6
|
+
* Used by both drag-and-drop (addComponent) and import (loadLibraryModel) flows.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Attach IO device models to a smart component from cached models.
|
|
11
|
+
* Each device referenced in componentData.attachedDevices is looked up
|
|
12
|
+
* in the model preloader cache, cloned, positioned, and added as a child.
|
|
13
|
+
*
|
|
14
|
+
* @param {THREE.Object3D} componentModel - The parent component model
|
|
15
|
+
* @param {Object} componentData - Component dictionary entry (has attachedDevices)
|
|
16
|
+
* @param {Object} modelPreloader - ModelPreloader instance with cache and componentDictionary
|
|
17
|
+
* @param {string} parentComponentId - The parent component's UUID
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
20
|
+
function attachIODevicesToComponent(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
21
|
+
var attachedDevices = componentData.attachedDevices;
|
|
22
|
+
if (!attachedDevices || Object.keys(attachedDevices).length === 0) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
console.log("\uD83D\uDD0C attachIODevicesToComponent(): Attaching ".concat(Object.keys(attachedDevices).length, " IO devices to smart component"));
|
|
26
|
+
for (var _i = 0, _Object$entries = Object.entries(attachedDevices); _i < _Object$entries.length; _i++) {
|
|
27
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
28
|
+
attachmentId = _Object$entries$_i[0],
|
|
29
|
+
attachment = _Object$entries$_i[1];
|
|
30
|
+
try {
|
|
31
|
+
var _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen;
|
|
32
|
+
var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
33
|
+
if (!deviceData || !deviceData.modelKey) {
|
|
34
|
+
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary, skipping"));
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
var cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
38
|
+
if (!cachedDevice) {
|
|
39
|
+
console.warn("\u26A0\uFE0F IO device model not in cache: ".concat(deviceData.modelKey, ", skipping"));
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Clone so each component instance owns its own io-device subtree and materials.
|
|
44
|
+
// Without this, all placed copies of the same smart component share the cached
|
|
45
|
+
// object, causing material mutations (from behaviors) to bleed across instances.
|
|
46
|
+
var deviceModel = cachedDevice.clone();
|
|
47
|
+
deviceModel.traverse(function (child) {
|
|
48
|
+
if (child.isMesh && child.material) {
|
|
49
|
+
child.material = Array.isArray(child.material) ? child.material.map(function (m) {
|
|
50
|
+
return m.clone();
|
|
51
|
+
}) : child.material.clone();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Name the device model
|
|
56
|
+
deviceModel.name = "".concat(attachment.attachmentLabel || 'IO Device', " (").concat(attachmentId, ")");
|
|
57
|
+
|
|
58
|
+
// Set user data for identification — include ioConfig data points so the
|
|
59
|
+
// component tooltip can render state displays without an extra lookup.
|
|
60
|
+
deviceModel.userData = {
|
|
61
|
+
objectType: 'io-device',
|
|
62
|
+
deviceId: attachment.deviceId,
|
|
63
|
+
attachmentId: attachmentId,
|
|
64
|
+
attachmentLabel: attachment.attachmentLabel,
|
|
65
|
+
parentComponentId: parentComponentId,
|
|
66
|
+
deviceName: deviceData.name || '',
|
|
67
|
+
// Snapshot of the device's data point definitions (stateType, stateConfig, direction, etc.)
|
|
68
|
+
// ioConfig can use either 'states' (preferred) or legacy 'dataPoints' as the array key
|
|
69
|
+
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) || [],
|
|
70
|
+
// Device-level I/O direction: 'input' means the user can write state via the tooltip
|
|
71
|
+
ioDirection: ((_deviceData$ioConfig3 = deviceData.ioConfig) === null || _deviceData$ioConfig3 === void 0 ? void 0 : _deviceData$ioConfig3.direction) || 'output',
|
|
72
|
+
// Signal wiring sourced from this attachment (for state propagation reference)
|
|
73
|
+
signalOutputs: attachment.signalOutputs || []
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Position at the attachment point
|
|
77
|
+
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
78
|
+
var pos = attachment.attachmentPoint.position;
|
|
79
|
+
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// IO device models are authored at the same real-world unit scale
|
|
83
|
+
// as the host component, so keep them at their natural (1:1) size.
|
|
84
|
+
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
85
|
+
// NOT a desired device model scale.
|
|
86
|
+
deviceModel.scale.setScalar(1);
|
|
87
|
+
|
|
88
|
+
// Add as child of the component
|
|
89
|
+
componentModel.add(deviceModel);
|
|
90
|
+
console.log("\u2705 Attached IO device: ".concat(attachment.attachmentLabel || attachment.deviceId, " at"), {
|
|
91
|
+
position: deviceModel.position,
|
|
92
|
+
scale: deviceModel.scale
|
|
93
|
+
});
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.error("\u274C Error attaching IO device ".concat(attachment.deviceId, ":"), err);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { attachIODevicesToComponent };
|