@2112-lab/central-plant 0.1.88 → 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 +237 -154
- 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/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/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
package/dist/bundle/index.js
CHANGED
|
@@ -1980,7 +1980,7 @@ var CentralPlantValidator = /*#__PURE__*/function () {
|
|
|
1980
1980
|
key: "validateImportedSceneData",
|
|
1981
1981
|
value: function validateImportedSceneData(sceneData) {
|
|
1982
1982
|
var results = [];
|
|
1983
|
-
var hardcodedVersion = "2.
|
|
1983
|
+
var hardcodedVersion = "2.3";
|
|
1984
1984
|
|
|
1985
1985
|
// Version validation - MUST be the value of hardcodedVersion
|
|
1986
1986
|
if (!sceneData.version || sceneData.version !== hardcodedVersion) {
|
|
@@ -18749,12 +18749,16 @@ var ComponentManager = /*#__PURE__*/function () {
|
|
|
18749
18749
|
componentMesh.position.set(position.x, position.y, position.z);
|
|
18750
18750
|
|
|
18751
18751
|
// Set userData for the component including dimensions
|
|
18752
|
-
componentMesh.userData = _objectSpread2({
|
|
18752
|
+
componentMesh.userData = _objectSpread2(_objectSpread2({
|
|
18753
18753
|
libraryId: componentData.libraryId,
|
|
18754
18754
|
objectType: 'component',
|
|
18755
18755
|
originalUuid: uuid
|
|
18756
18756
|
}, ((_gltfScene$userData = gltfScene.userData) === null || _gltfScene$userData === void 0 ? void 0 : _gltfScene$userData.dimensions) && {
|
|
18757
18757
|
dimensions: gltfScene.userData.dimensions
|
|
18758
|
+
}), libraryComponent.isS3Component && {
|
|
18759
|
+
isS3Component: true,
|
|
18760
|
+
s3Path: libraryComponent.s3Path,
|
|
18761
|
+
componentKey: libraryComponent.componentKey
|
|
18758
18762
|
});
|
|
18759
18763
|
|
|
18760
18764
|
// Also ensure dimensions are preserved in the userData
|
|
@@ -28556,6 +28560,103 @@ var BehaviorManager = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
28556
28560
|
}]);
|
|
28557
28561
|
}(BaseDisposable);
|
|
28558
28562
|
|
|
28563
|
+
/**
|
|
28564
|
+
* IO Device Utilities
|
|
28565
|
+
* Shared utility functions for attaching IO devices to smart components.
|
|
28566
|
+
* Used by both drag-and-drop (addComponent) and import (loadLibraryModel) flows.
|
|
28567
|
+
*/
|
|
28568
|
+
|
|
28569
|
+
/**
|
|
28570
|
+
* Attach IO device models to a smart component from cached models.
|
|
28571
|
+
* Each device referenced in componentData.attachedDevices is looked up
|
|
28572
|
+
* in the model preloader cache, cloned, positioned, and added as a child.
|
|
28573
|
+
*
|
|
28574
|
+
* @param {THREE.Object3D} componentModel - The parent component model
|
|
28575
|
+
* @param {Object} componentData - Component dictionary entry (has attachedDevices)
|
|
28576
|
+
* @param {Object} modelPreloader - ModelPreloader instance with cache and componentDictionary
|
|
28577
|
+
* @param {string} parentComponentId - The parent component's UUID
|
|
28578
|
+
* @returns {void}
|
|
28579
|
+
*/
|
|
28580
|
+
function attachIODevicesToComponent(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
28581
|
+
var attachedDevices = componentData.attachedDevices;
|
|
28582
|
+
if (!attachedDevices || Object.keys(attachedDevices).length === 0) {
|
|
28583
|
+
return;
|
|
28584
|
+
}
|
|
28585
|
+
console.log("\uD83D\uDD0C attachIODevicesToComponent(): Attaching ".concat(Object.keys(attachedDevices).length, " IO devices to smart component"));
|
|
28586
|
+
for (var _i = 0, _Object$entries = Object.entries(attachedDevices); _i < _Object$entries.length; _i++) {
|
|
28587
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
28588
|
+
attachmentId = _Object$entries$_i[0],
|
|
28589
|
+
attachment = _Object$entries$_i[1];
|
|
28590
|
+
try {
|
|
28591
|
+
var _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen;
|
|
28592
|
+
var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
28593
|
+
if (!deviceData || !deviceData.modelKey) {
|
|
28594
|
+
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary, skipping"));
|
|
28595
|
+
continue;
|
|
28596
|
+
}
|
|
28597
|
+
var cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
28598
|
+
if (!cachedDevice) {
|
|
28599
|
+
console.warn("\u26A0\uFE0F IO device model not in cache: ".concat(deviceData.modelKey, ", skipping"));
|
|
28600
|
+
continue;
|
|
28601
|
+
}
|
|
28602
|
+
|
|
28603
|
+
// Clone so each component instance owns its own io-device subtree and materials.
|
|
28604
|
+
// Without this, all placed copies of the same smart component share the cached
|
|
28605
|
+
// object, causing material mutations (from behaviors) to bleed across instances.
|
|
28606
|
+
var deviceModel = cachedDevice.clone();
|
|
28607
|
+
deviceModel.traverse(function (child) {
|
|
28608
|
+
if (child.isMesh && child.material) {
|
|
28609
|
+
child.material = Array.isArray(child.material) ? child.material.map(function (m) {
|
|
28610
|
+
return m.clone();
|
|
28611
|
+
}) : child.material.clone();
|
|
28612
|
+
}
|
|
28613
|
+
});
|
|
28614
|
+
|
|
28615
|
+
// Name the device model
|
|
28616
|
+
deviceModel.name = "".concat(attachment.attachmentLabel || 'IO Device', " (").concat(attachmentId, ")");
|
|
28617
|
+
|
|
28618
|
+
// Set user data for identification — include ioConfig data points so the
|
|
28619
|
+
// component tooltip can render state displays without an extra lookup.
|
|
28620
|
+
deviceModel.userData = {
|
|
28621
|
+
objectType: 'io-device',
|
|
28622
|
+
deviceId: attachment.deviceId,
|
|
28623
|
+
attachmentId: attachmentId,
|
|
28624
|
+
attachmentLabel: attachment.attachmentLabel,
|
|
28625
|
+
parentComponentId: parentComponentId,
|
|
28626
|
+
deviceName: deviceData.name || '',
|
|
28627
|
+
// Snapshot of the device's data point definitions (stateType, stateConfig, direction, etc.)
|
|
28628
|
+
// ioConfig can use either 'states' (preferred) or legacy 'dataPoints' as the array key
|
|
28629
|
+
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) || [],
|
|
28630
|
+
// Device-level I/O direction: 'input' means the user can write state via the tooltip
|
|
28631
|
+
ioDirection: ((_deviceData$ioConfig3 = deviceData.ioConfig) === null || _deviceData$ioConfig3 === void 0 ? void 0 : _deviceData$ioConfig3.direction) || 'output',
|
|
28632
|
+
// Signal wiring sourced from this attachment (for state propagation reference)
|
|
28633
|
+
signalOutputs: attachment.signalOutputs || []
|
|
28634
|
+
};
|
|
28635
|
+
|
|
28636
|
+
// Position at the attachment point
|
|
28637
|
+
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
28638
|
+
var pos = attachment.attachmentPoint.position;
|
|
28639
|
+
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
28640
|
+
}
|
|
28641
|
+
|
|
28642
|
+
// IO device models are authored at the same real-world unit scale
|
|
28643
|
+
// as the host component, so keep them at their natural (1:1) size.
|
|
28644
|
+
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
28645
|
+
// NOT a desired device model scale.
|
|
28646
|
+
deviceModel.scale.setScalar(1);
|
|
28647
|
+
|
|
28648
|
+
// Add as child of the component
|
|
28649
|
+
componentModel.add(deviceModel);
|
|
28650
|
+
console.log("\u2705 Attached IO device: ".concat(attachment.attachmentLabel || attachment.deviceId, " at"), {
|
|
28651
|
+
position: deviceModel.position,
|
|
28652
|
+
scale: deviceModel.scale
|
|
28653
|
+
});
|
|
28654
|
+
} catch (err) {
|
|
28655
|
+
console.error("\u274C Error attaching IO device ".concat(attachment.deviceId, ":"), err);
|
|
28656
|
+
}
|
|
28657
|
+
}
|
|
28658
|
+
}
|
|
28659
|
+
|
|
28559
28660
|
var ModelManager = /*#__PURE__*/function () {
|
|
28560
28661
|
function ModelManager(sceneViewer) {
|
|
28561
28662
|
_classCallCheck(this, ModelManager);
|
|
@@ -28639,6 +28740,11 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
28639
28740
|
libraryModel.add(connector);
|
|
28640
28741
|
});
|
|
28641
28742
|
|
|
28743
|
+
// Attach IO devices for smart components (import flow)
|
|
28744
|
+
if (componentData.isSmart && componentData.attachedDevices) {
|
|
28745
|
+
attachIODevicesToComponent(libraryModel, componentData, modelPreloader, originalProps.uuid);
|
|
28746
|
+
}
|
|
28747
|
+
|
|
28642
28748
|
// Replace mesh in scene
|
|
28643
28749
|
this._replaceMeshInScene(targetMesh, libraryModel, originalProps.parent, component);
|
|
28644
28750
|
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"));
|
|
@@ -28715,7 +28821,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
28715
28821
|
value: (function () {
|
|
28716
28822
|
var _getLibraryModel2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(modelKey, libraryId) {
|
|
28717
28823
|
var _this2 = this;
|
|
28718
|
-
var gltfScene, preloaderStatus, modelPath, gltf, _t2, _t3;
|
|
28824
|
+
var gltfScene, preloaderStatus, modelPath, gltf, _t2, _t3, _t4;
|
|
28719
28825
|
return _regenerator().w(function (_context2) {
|
|
28720
28826
|
while (1) switch (_context2.n) {
|
|
28721
28827
|
case 0:
|
|
@@ -28752,25 +28858,47 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
28752
28858
|
console.warn("\u26A0\uFE0F Preloading failed:", _t2);
|
|
28753
28859
|
case 6:
|
|
28754
28860
|
_context2.p = 6;
|
|
28861
|
+
if (!modelPreloader.urlResolver) {
|
|
28862
|
+
_context2.n = 11;
|
|
28863
|
+
break;
|
|
28864
|
+
}
|
|
28865
|
+
_context2.p = 7;
|
|
28866
|
+
_context2.n = 8;
|
|
28867
|
+
return modelPreloader.urlResolver(modelKey);
|
|
28868
|
+
case 8:
|
|
28869
|
+
modelPath = _context2.v;
|
|
28870
|
+
console.log("\uD83D\uDD17 Resolved URL for ".concat(modelKey));
|
|
28871
|
+
_context2.n = 10;
|
|
28872
|
+
break;
|
|
28873
|
+
case 9:
|
|
28874
|
+
_context2.p = 9;
|
|
28875
|
+
_t3 = _context2.v;
|
|
28876
|
+
console.warn("\u26A0\uFE0F URL resolver failed for ".concat(modelKey, ", falling back to local path:"), _t3);
|
|
28877
|
+
modelPath = "".concat(modelPreloader.modelsBasePath).concat(modelKey);
|
|
28878
|
+
case 10:
|
|
28879
|
+
_context2.n = 12;
|
|
28880
|
+
break;
|
|
28881
|
+
case 11:
|
|
28755
28882
|
modelPath = "".concat(modelPreloader.modelsBasePath).concat(modelKey);
|
|
28883
|
+
case 12:
|
|
28756
28884
|
console.log("\uD83D\uDCC2 Fallback loading from: ".concat(modelPath));
|
|
28757
|
-
_context2.n =
|
|
28885
|
+
_context2.n = 13;
|
|
28758
28886
|
return new Promise(function (resolve, reject) {
|
|
28759
28887
|
_this2.sceneViewer.gltfLoader.load(modelPath, resolve, undefined, reject);
|
|
28760
28888
|
});
|
|
28761
|
-
case
|
|
28889
|
+
case 13:
|
|
28762
28890
|
gltf = _context2.v;
|
|
28763
28891
|
if (libraryId) {
|
|
28764
28892
|
modelPreloader.cacheModel(modelKey, gltf.scene.clone(), libraryId);
|
|
28765
28893
|
}
|
|
28766
28894
|
return _context2.a(2, gltf.scene);
|
|
28767
|
-
case
|
|
28768
|
-
_context2.p =
|
|
28769
|
-
|
|
28770
|
-
console.error("Failed to load model ".concat(modelKey, ":"),
|
|
28895
|
+
case 14:
|
|
28896
|
+
_context2.p = 14;
|
|
28897
|
+
_t4 = _context2.v;
|
|
28898
|
+
console.error("Failed to load model ".concat(modelKey, ":"), _t4);
|
|
28771
28899
|
return _context2.a(2, null);
|
|
28772
28900
|
}
|
|
28773
|
-
}, _callee2, null, [[6,
|
|
28901
|
+
}, _callee2, null, [[7, 9], [6, 14], [2, 5]]);
|
|
28774
28902
|
}));
|
|
28775
28903
|
function _getLibraryModel(_x4, _x5) {
|
|
28776
28904
|
return _getLibraryModel2.apply(this, arguments);
|
|
@@ -28869,7 +28997,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
28869
28997
|
key: "verifyModelPreloaderCache",
|
|
28870
28998
|
value: (function () {
|
|
28871
28999
|
var _verifyModelPreloaderCache = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3() {
|
|
28872
|
-
var preloaderStatus,
|
|
29000
|
+
var preloaderStatus, _t5;
|
|
28873
29001
|
return _regenerator().w(function (_context3) {
|
|
28874
29002
|
while (1) switch (_context3.n) {
|
|
28875
29003
|
case 0:
|
|
@@ -28892,8 +29020,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
28892
29020
|
break;
|
|
28893
29021
|
case 3:
|
|
28894
29022
|
_context3.p = 3;
|
|
28895
|
-
|
|
28896
|
-
console.warn('⚠️ Model preloading failed, some models may load directly:',
|
|
29023
|
+
_t5 = _context3.v;
|
|
29024
|
+
console.warn('⚠️ Model preloading failed, some models may load directly:', _t5);
|
|
28897
29025
|
case 4:
|
|
28898
29026
|
return _context3.a(2, preloaderStatus);
|
|
28899
29027
|
}
|
|
@@ -28912,7 +29040,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
28912
29040
|
key: "preloadMissingModels",
|
|
28913
29041
|
value: (function () {
|
|
28914
29042
|
var _preloadMissingModels = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(data, componentDictionary) {
|
|
28915
|
-
var _data$scene, _data$scene2, requiredModels, preloaderStatus, cachedModels, missingModels, basePath, modelUrls, _iterator, _step, modelKey,
|
|
29043
|
+
var _data$scene, _data$scene2, requiredModels, preloaderStatus, cachedModels, missingModels, basePath, modelUrls, _iterator, _step, modelKey, _t6, _t7;
|
|
28916
29044
|
return _regenerator().w(function (_context4) {
|
|
28917
29045
|
while (1) switch (_context4.n) {
|
|
28918
29046
|
case 0:
|
|
@@ -29007,8 +29135,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
29007
29135
|
break;
|
|
29008
29136
|
case 7:
|
|
29009
29137
|
_context4.p = 7;
|
|
29010
|
-
|
|
29011
|
-
console.warn("\u274C Failed to preload missing model ".concat(modelKey, ":"),
|
|
29138
|
+
_t6 = _context4.v;
|
|
29139
|
+
console.warn("\u274C Failed to preload missing model ".concat(modelKey, ":"), _t6);
|
|
29012
29140
|
case 8:
|
|
29013
29141
|
_context4.n = 4;
|
|
29014
29142
|
break;
|
|
@@ -29017,8 +29145,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
29017
29145
|
break;
|
|
29018
29146
|
case 10:
|
|
29019
29147
|
_context4.p = 10;
|
|
29020
|
-
|
|
29021
|
-
_iterator.e(
|
|
29148
|
+
_t7 = _context4.v;
|
|
29149
|
+
_iterator.e(_t7);
|
|
29022
29150
|
case 11:
|
|
29023
29151
|
_context4.p = 11;
|
|
29024
29152
|
_iterator.f();
|
|
@@ -29123,7 +29251,7 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
29123
29251
|
key: "loadComponentDictionary",
|
|
29124
29252
|
value: (function () {
|
|
29125
29253
|
var _loadComponentDictionary = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6() {
|
|
29126
|
-
var response, dict,
|
|
29254
|
+
var response, dict, _t8;
|
|
29127
29255
|
return _regenerator().w(function (_context6) {
|
|
29128
29256
|
while (1) switch (_context6.n) {
|
|
29129
29257
|
case 0:
|
|
@@ -29141,8 +29269,8 @@ var ModelManager = /*#__PURE__*/function () {
|
|
|
29141
29269
|
return _context6.a(2, dict);
|
|
29142
29270
|
case 3:
|
|
29143
29271
|
_context6.p = 3;
|
|
29144
|
-
|
|
29145
|
-
console.warn('⚠️ Could not load component dictionary:',
|
|
29272
|
+
_t8 = _context6.v;
|
|
29273
|
+
console.warn('⚠️ Could not load component dictionary:', _t8);
|
|
29146
29274
|
return _context6.a(2, {});
|
|
29147
29275
|
}
|
|
29148
29276
|
}, _callee6, null, [[0, 3]]);
|
|
@@ -29938,7 +30066,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
29938
30066
|
return createSceneMaterials;
|
|
29939
30067
|
}()
|
|
29940
30068
|
/**
|
|
29941
|
-
* Helper function to create geometries
|
|
30069
|
+
* Helper function to create geometries for connectors and gateways
|
|
30070
|
+
* Components use GLB geometry directly, no placeholder needed
|
|
29942
30071
|
*/
|
|
29943
30072
|
)
|
|
29944
30073
|
}, {
|
|
@@ -29953,7 +30082,7 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
29953
30082
|
return geometries;
|
|
29954
30083
|
}
|
|
29955
30084
|
|
|
29956
|
-
// Create geometries
|
|
30085
|
+
// Create geometries only for connectors and gateways (components use GLB geometry)
|
|
29957
30086
|
data.scene.children.forEach(function (child) {
|
|
29958
30087
|
var _child$userData, _child$userData2;
|
|
29959
30088
|
// Skip manual segments - they create their own geometry
|
|
@@ -29962,42 +30091,28 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
29962
30091
|
console.log("\u23ED\uFE0F Skipping geometry creation for manual segment: ".concat(child.uuid));
|
|
29963
30092
|
return;
|
|
29964
30093
|
}
|
|
29965
|
-
if ((_child$userData2 = child.userData) !== null && _child$userData2 !== void 0 && _child$userData2.libraryId && componentDictionary[child.userData.libraryId]) {
|
|
29966
|
-
var component = componentDictionary[child.userData.libraryId];
|
|
29967
|
-
var boundingBox = component.boundingBox;
|
|
29968
30094
|
|
|
29969
|
-
|
|
29970
|
-
|
|
30095
|
+
// Skip components - they will use GLB geometry directly
|
|
30096
|
+
if ((_child$userData2 = child.userData) !== null && _child$userData2 !== void 0 && _child$userData2.libraryId) {
|
|
30097
|
+
return;
|
|
30098
|
+
}
|
|
29971
30099
|
|
|
29972
|
-
|
|
29973
|
-
|
|
29974
|
-
|
|
29975
|
-
|
|
29976
|
-
//
|
|
29977
|
-
|
|
29978
|
-
|
|
29979
|
-
|
|
29980
|
-
|
|
29981
|
-
if (
|
|
29982
|
-
//
|
|
29983
|
-
var
|
|
29984
|
-
|
|
29985
|
-
|
|
29986
|
-
// Match computed gateway size (0.15) for gateways, keep 0.1 for connectors
|
|
29987
|
-
var sphereRadius = isGateway ? 0.15 : 0.1;
|
|
29988
|
-
geometries[geometryKey] = new THREE__namespace.SphereGeometry(sphereRadius, 16, 16);
|
|
29989
|
-
console.log("\uD83D\uDD2E Created shared sphere geometry for ".concat(isGateway ? 'gateways' : 'connectors', " (radius: ").concat(sphereRadius, ")"));
|
|
29990
|
-
}
|
|
30100
|
+
// For non-library objects (connectors, gateways), create shared sphere geometry
|
|
30101
|
+
var isConnectorOrGateway = child.uuid && (child.uuid.toLowerCase().includes('connector') || child.uuid.toLowerCase().includes('gateway'));
|
|
30102
|
+
console.log("createSceneGeometries child:", child);
|
|
30103
|
+
if (isConnectorOrGateway) {
|
|
30104
|
+
// Check if position exists and is not at origin
|
|
30105
|
+
if (child.position && !(child.position.x == 0 && child.position.y == 0 && child.position.z == 0)) {
|
|
30106
|
+
// Determine if this is a gateway or connector
|
|
30107
|
+
var isGateway = child.uuid.toLowerCase().includes('gateway');
|
|
30108
|
+
var geometryKey = isGateway ? 'GATEWAY_SPHERE' : 'CONNECTOR_GATEWAY_SPHERE';
|
|
30109
|
+
if (!geometries[geometryKey]) {
|
|
30110
|
+
// Match computed gateway size (0.15) for gateways, keep 0.1 for connectors
|
|
30111
|
+
var sphereRadius = isGateway ? 0.15 : 0.1;
|
|
30112
|
+
geometries[geometryKey] = new THREE__namespace.SphereGeometry(sphereRadius, 16, 16);
|
|
30113
|
+
console.log("\uD83D\uDD2E Created shared sphere geometry for ".concat(isGateway ? 'gateways' : 'connectors', " (radius: ").concat(sphereRadius, ")"));
|
|
29991
30114
|
}
|
|
29992
30115
|
}
|
|
29993
|
-
// else {
|
|
29994
|
-
// // Default fallback geometry
|
|
29995
|
-
// const geometryKey = child.geometry || 'FALLBACK_BOX'
|
|
29996
|
-
// if (!geometries[geometryKey]) {
|
|
29997
|
-
// geometries[geometryKey] = new THREE.BoxGeometry(1, 1, 1)
|
|
29998
|
-
// console.log(`📦 Created fallback box geometry`)
|
|
29999
|
-
// }
|
|
30000
|
-
// }
|
|
30001
30116
|
}
|
|
30002
30117
|
});
|
|
30003
30118
|
return geometries;
|
|
@@ -30761,7 +30876,8 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
30761
30876
|
key: "_createBasicSceneObjects",
|
|
30762
30877
|
value: (function () {
|
|
30763
30878
|
var _createBasicSceneObjects2 = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
|
|
30764
|
-
var
|
|
30879
|
+
var _this$sceneViewer$cen,
|
|
30880
|
+
_this4 = this;
|
|
30765
30881
|
var componentDictionary, _yield$this$createSce, materials, crosscubeTextureSet, geometries, libraryObjectsToReplace;
|
|
30766
30882
|
return _regenerator().w(function (_context6) {
|
|
30767
30883
|
while (1) switch (_context6.n) {
|
|
@@ -30772,20 +30888,33 @@ var SceneOperationsManager = /*#__PURE__*/function () {
|
|
|
30772
30888
|
}
|
|
30773
30889
|
throw new Error('Invalid scene data structure: data.scene.children must be an array');
|
|
30774
30890
|
case 1:
|
|
30891
|
+
// Use the extended component dictionary (includes S3 components) if available,
|
|
30892
|
+
// otherwise fall back to loading from static file
|
|
30893
|
+
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;
|
|
30894
|
+
if (componentDictionary) {
|
|
30895
|
+
_context6.n = 3;
|
|
30896
|
+
break;
|
|
30897
|
+
}
|
|
30898
|
+
console.log('⚠️ Extended dictionary not available, loading from static file');
|
|
30775
30899
|
_context6.n = 2;
|
|
30776
30900
|
return this.modelManager.loadComponentDictionary();
|
|
30777
30901
|
case 2:
|
|
30778
30902
|
componentDictionary = _context6.v;
|
|
30903
|
+
_context6.n = 4;
|
|
30904
|
+
break;
|
|
30905
|
+
case 3:
|
|
30906
|
+
console.log("\u2705 Using extended component dictionary (".concat(Object.keys(componentDictionary).length, " components)"));
|
|
30907
|
+
case 4:
|
|
30779
30908
|
// Inject connector children from component dictionary into scene data
|
|
30780
30909
|
this._injectConnectorChildrenFromDictionary(data, componentDictionary);
|
|
30781
30910
|
|
|
30782
30911
|
// Ensure models are preloaded
|
|
30783
|
-
_context6.n =
|
|
30912
|
+
_context6.n = 5;
|
|
30784
30913
|
return this.modelManager.preloadMissingModels(data, componentDictionary);
|
|
30785
|
-
case
|
|
30786
|
-
_context6.n =
|
|
30914
|
+
case 5:
|
|
30915
|
+
_context6.n = 6;
|
|
30787
30916
|
return this.createSceneMaterials(data);
|
|
30788
|
-
case
|
|
30917
|
+
case 6:
|
|
30789
30918
|
_yield$this$createSce = _context6.v;
|
|
30790
30919
|
materials = _yield$this$createSce.materials;
|
|
30791
30920
|
crosscubeTextureSet = _yield$this$createSce.crosscubeTextureSet;
|
|
@@ -36527,7 +36656,7 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36527
36656
|
|
|
36528
36657
|
// Add attached IO device models for smart components
|
|
36529
36658
|
if (componentData.isSmart && componentData.attachedDevices) {
|
|
36530
|
-
|
|
36659
|
+
attachIODevicesToComponent(componentModel, componentData, modelPreloader, componentId);
|
|
36531
36660
|
}
|
|
36532
36661
|
|
|
36533
36662
|
// Notify the component manager about the new component
|
|
@@ -36580,95 +36709,6 @@ var CentralPlantInternals = /*#__PURE__*/function () {
|
|
|
36580
36709
|
}
|
|
36581
36710
|
}
|
|
36582
36711
|
|
|
36583
|
-
/**
|
|
36584
|
-
* Attach IO device models to a smart component from cached models.
|
|
36585
|
-
* Each device referenced in componentData.attachedDevices is looked up
|
|
36586
|
-
* in the model preloader cache, cloned, positioned, and added as a child.
|
|
36587
|
-
* @param {THREE.Object3D} componentModel - The parent component model
|
|
36588
|
-
* @param {Object} componentData - Component dictionary entry (has attachedDevices)
|
|
36589
|
-
* @param {Object} modelPreloader - ModelPreloader instance
|
|
36590
|
-
* @param {string} parentComponentId - The parent component's UUID
|
|
36591
|
-
* @private
|
|
36592
|
-
*/
|
|
36593
|
-
}, {
|
|
36594
|
-
key: "_attachIODevicesToComponent",
|
|
36595
|
-
value: function _attachIODevicesToComponent(componentModel, componentData, modelPreloader, parentComponentId) {
|
|
36596
|
-
var attachedDevices = componentData.attachedDevices;
|
|
36597
|
-
console.log("\uD83D\uDD0C addComponent(): Attaching ".concat(Object.keys(attachedDevices).length, " IO devices to smart component"));
|
|
36598
|
-
for (var _i = 0, _Object$entries = Object.entries(attachedDevices); _i < _Object$entries.length; _i++) {
|
|
36599
|
-
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
36600
|
-
attachmentId = _Object$entries$_i[0],
|
|
36601
|
-
attachment = _Object$entries$_i[1];
|
|
36602
|
-
try {
|
|
36603
|
-
var _modelPreloader$compo, _deviceData$ioConfig, _deviceData$ioConfig2, _deviceData$ioConfig3, _attachment$attachmen;
|
|
36604
|
-
var deviceData = (_modelPreloader$compo = modelPreloader.componentDictionary) === null || _modelPreloader$compo === void 0 ? void 0 : _modelPreloader$compo[attachment.deviceId];
|
|
36605
|
-
if (!deviceData || !deviceData.modelKey) {
|
|
36606
|
-
console.warn("\u26A0\uFE0F IO device ".concat(attachment.deviceId, " not found in dictionary, skipping"));
|
|
36607
|
-
continue;
|
|
36608
|
-
}
|
|
36609
|
-
var cachedDevice = modelPreloader.getCachedModelWithDimensions(deviceData.modelKey, attachment.deviceId);
|
|
36610
|
-
if (!cachedDevice) {
|
|
36611
|
-
console.warn("\u26A0\uFE0F IO device model not in cache: ".concat(deviceData.modelKey, ", skipping"));
|
|
36612
|
-
continue;
|
|
36613
|
-
}
|
|
36614
|
-
|
|
36615
|
-
// Clone so each component instance owns its own io-device subtree and materials.
|
|
36616
|
-
// Without this, all placed copies of the same smart component share the cached
|
|
36617
|
-
// object, causing material mutations (from behaviors) to bleed across instances.
|
|
36618
|
-
var deviceModel = cachedDevice.clone();
|
|
36619
|
-
deviceModel.traverse(function (child) {
|
|
36620
|
-
if (child.isMesh && child.material) {
|
|
36621
|
-
child.material = Array.isArray(child.material) ? child.material.map(function (m) {
|
|
36622
|
-
return m.clone();
|
|
36623
|
-
}) : child.material.clone();
|
|
36624
|
-
}
|
|
36625
|
-
});
|
|
36626
|
-
|
|
36627
|
-
// Name the device model
|
|
36628
|
-
deviceModel.name = "".concat(attachment.attachmentLabel || 'IO Device', " (").concat(attachmentId, ")");
|
|
36629
|
-
|
|
36630
|
-
// Set user data for identification — include ioConfig data points so the
|
|
36631
|
-
// component tooltip can render state displays without an extra lookup.
|
|
36632
|
-
deviceModel.userData = {
|
|
36633
|
-
objectType: 'io-device',
|
|
36634
|
-
deviceId: attachment.deviceId,
|
|
36635
|
-
attachmentId: attachmentId,
|
|
36636
|
-
attachmentLabel: attachment.attachmentLabel,
|
|
36637
|
-
parentComponentId: parentComponentId,
|
|
36638
|
-
deviceName: deviceData.name || '',
|
|
36639
|
-
// Snapshot of the device's data point definitions (stateType, stateConfig, direction, etc.)
|
|
36640
|
-
// ioConfig can use either 'states' (preferred) or legacy 'dataPoints' as the array key
|
|
36641
|
-
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) || [],
|
|
36642
|
-
// Device-level I/O direction: 'input' means the user can write state via the tooltip
|
|
36643
|
-
ioDirection: ((_deviceData$ioConfig3 = deviceData.ioConfig) === null || _deviceData$ioConfig3 === void 0 ? void 0 : _deviceData$ioConfig3.direction) || 'output',
|
|
36644
|
-
// Signal wiring sourced from this attachment (for state propagation reference)
|
|
36645
|
-
signalOutputs: attachment.signalOutputs || []
|
|
36646
|
-
};
|
|
36647
|
-
|
|
36648
|
-
// Position at the attachment point
|
|
36649
|
-
if ((_attachment$attachmen = attachment.attachmentPoint) !== null && _attachment$attachmen !== void 0 && _attachment$attachmen.position) {
|
|
36650
|
-
var pos = attachment.attachmentPoint.position;
|
|
36651
|
-
deviceModel.position.set(pos.x || 0, pos.y || 0, pos.z || 0);
|
|
36652
|
-
}
|
|
36653
|
-
|
|
36654
|
-
// IO device models are authored at the same real-world unit scale
|
|
36655
|
-
// as the host component, so keep them at their natural (1:1) size.
|
|
36656
|
-
// Note: attachmentPoint.scale is the connector marker sphere size,
|
|
36657
|
-
// NOT a desired device model scale.
|
|
36658
|
-
deviceModel.scale.setScalar(1);
|
|
36659
|
-
|
|
36660
|
-
// Add as child of the component
|
|
36661
|
-
componentModel.add(deviceModel);
|
|
36662
|
-
console.log("\u2705 Attached IO device: ".concat(attachment.attachmentLabel || attachment.deviceId, " at"), {
|
|
36663
|
-
position: deviceModel.position,
|
|
36664
|
-
scale: deviceModel.scale
|
|
36665
|
-
});
|
|
36666
|
-
} catch (err) {
|
|
36667
|
-
console.error("\u274C Error attaching IO device ".concat(attachment.deviceId, ":"), err);
|
|
36668
|
-
}
|
|
36669
|
-
}
|
|
36670
|
-
}
|
|
36671
|
-
|
|
36672
36712
|
/**
|
|
36673
36713
|
* Delete a component from the scene by componentId (internal implementation)
|
|
36674
36714
|
* @param {string} componentId - The UUID of the component to delete
|
|
@@ -36774,7 +36814,7 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
36774
36814
|
* Initialize the CentralPlant manager
|
|
36775
36815
|
*
|
|
36776
36816
|
* @constructor
|
|
36777
|
-
* @version 0.1.
|
|
36817
|
+
* @version 0.1.90
|
|
36778
36818
|
* @updated 2025-10-22
|
|
36779
36819
|
*
|
|
36780
36820
|
* @description Creates a new CentralPlant instance and initializes internal managers and utilities.
|
|
@@ -38274,6 +38314,50 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38274
38314
|
}
|
|
38275
38315
|
return removeComponentFromDictionary;
|
|
38276
38316
|
}()
|
|
38317
|
+
/**
|
|
38318
|
+
* Get library IDs from scene data that are missing from the component dictionary
|
|
38319
|
+
* @param {Object} sceneData - Scene JSON data to analyze
|
|
38320
|
+
* @returns {string[]} Array of library IDs that are not in the current component dictionary
|
|
38321
|
+
* @description Analyzes scene data to find components whose libraryId is not present in the
|
|
38322
|
+
* component dictionary. This is useful for detecting S3 components that need to be fetched
|
|
38323
|
+
* before importing a scene.
|
|
38324
|
+
* @example
|
|
38325
|
+
* // Check for missing components before import
|
|
38326
|
+
* const missingIds = centralPlant.getMissingLibraryIds(sceneJson);
|
|
38327
|
+
* if (missingIds.length > 0) {
|
|
38328
|
+
* // Fetch missing S3 components
|
|
38329
|
+
* await fetchS3Components(missingIds);
|
|
38330
|
+
* await centralPlant.extendComponentDictionary(fetchedComponents);
|
|
38331
|
+
* }
|
|
38332
|
+
* // Now safe to import
|
|
38333
|
+
* await centralPlant.importScene(sceneJson);
|
|
38334
|
+
*/
|
|
38335
|
+
)
|
|
38336
|
+
}, {
|
|
38337
|
+
key: "getMissingLibraryIds",
|
|
38338
|
+
value: function getMissingLibraryIds(sceneData) {
|
|
38339
|
+
var _sceneData$scene, _this$managers$compon;
|
|
38340
|
+
if (!(sceneData !== null && sceneData !== void 0 && (_sceneData$scene = sceneData.scene) !== null && _sceneData$scene !== void 0 && _sceneData$scene.children) || !Array.isArray(sceneData.scene.children)) {
|
|
38341
|
+
return [];
|
|
38342
|
+
}
|
|
38343
|
+
var componentDictionary = ((_this$managers$compon = this.managers.componentDataManager) === null || _this$managers$compon === void 0 ? void 0 : _this$managers$compon.componentDictionary) || {};
|
|
38344
|
+
var missingIds = [];
|
|
38345
|
+
sceneData.scene.children.forEach(function (child) {
|
|
38346
|
+
var _child$userData;
|
|
38347
|
+
var libraryId = (_child$userData = child.userData) === null || _child$userData === void 0 ? void 0 : _child$userData.libraryId;
|
|
38348
|
+
if (libraryId && !componentDictionary[libraryId]) {
|
|
38349
|
+
// Only add unique IDs
|
|
38350
|
+
if (!missingIds.includes(libraryId)) {
|
|
38351
|
+
missingIds.push(libraryId);
|
|
38352
|
+
}
|
|
38353
|
+
}
|
|
38354
|
+
});
|
|
38355
|
+
if (missingIds.length > 0) {
|
|
38356
|
+
console.log("\uD83D\uDD0D Found ".concat(missingIds.length, " missing library IDs in scene data:"), missingIds);
|
|
38357
|
+
}
|
|
38358
|
+
return missingIds;
|
|
38359
|
+
}
|
|
38360
|
+
|
|
38277
38361
|
/**
|
|
38278
38362
|
* Select an object (component, connector, or gateway) in the scene by its ID
|
|
38279
38363
|
* @param {string} objectId - The UUID or name of the object to select
|
|
@@ -38310,7 +38394,6 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38310
38394
|
* centralPlant.selectComponent(targetObject.uuid);
|
|
38311
38395
|
* }
|
|
38312
38396
|
*/
|
|
38313
|
-
)
|
|
38314
38397
|
}, {
|
|
38315
38398
|
key: "selectComponent",
|
|
38316
38399
|
value: function selectComponent(objectId) {
|
|
@@ -38339,8 +38422,8 @@ var CentralPlant = /*#__PURE__*/function (_BaseDisposable) {
|
|
|
38339
38422
|
// If still not found, try finding by originalUuid in userData
|
|
38340
38423
|
if (!targetObject) {
|
|
38341
38424
|
this.sceneViewer.scene.traverse(function (child) {
|
|
38342
|
-
var _child$
|
|
38343
|
-
if (((_child$
|
|
38425
|
+
var _child$userData2;
|
|
38426
|
+
if (((_child$userData2 = child.userData) === null || _child$userData2 === void 0 ? void 0 : _child$userData2.originalUuid) === objectId) {
|
|
38344
38427
|
targetObject = child;
|
|
38345
38428
|
return;
|
|
38346
38429
|
}
|