From 11c0994833773dcf70cad0f0c9a90dd103125228 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 20 Aug 2025 17:00:27 +0530 Subject: [PATCH 1/3] schema change --- app/package-lock.json | 85 +++++++++ app/package.json | 1 + .../eventProperties/actions/StorageAction.tsx | 74 ++++---- .../mechanics/storageMechanics.tsx | 172 +++++++++++------- app/src/modules/builder/asset/assetsGroup.tsx | 4 +- .../builder/asset/functions/addAssetModel.ts | 4 +- .../selection3D/copyPasteControls3D.tsx | 4 +- .../selection3D/duplicationControls3D.tsx | 4 +- app/src/modules/scene/helpers/StatsHelper.tsx | 5 +- app/src/modules/scene/scene.tsx | 2 - app/src/modules/scene/setup/setup.tsx | 6 +- app/src/modules/scene/tools/autoRotate.tsx | 47 +++++ .../instance/actions/workerInstance.tsx | 2 +- .../modules/simulation/products/products.tsx | 9 +- .../triggerHandler/useTriggerHandler.ts | 6 +- .../simulation/ui3d/StorageContentUi.tsx | 2 +- .../instances/instance/vehicleInstance.tsx | 2 +- .../store/simulation/useStorageUnitStore.ts | 2 +- app/src/types/simulationTypes.d.ts | 5 +- 19 files changed, 304 insertions(+), 132 deletions(-) create mode 100644 app/src/modules/scene/tools/autoRotate.tsx diff --git a/app/package-lock.json b/app/package-lock.json index b5a2eda..a1bf231 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -38,6 +38,7 @@ "mqtt": "^5.10.4", "postprocessing": "^6.36.4", "prompt-sync": "^4.2.0", + "r3f-perf": "^7.2.3", "react": "^18.3.1", "react-chartjs-2": "^5.3.0", "react-dom": "^18.3.1", @@ -3371,6 +3372,15 @@ "react-dom": "^16.8 || ^17.0 || ^18.0" } }, + "node_modules/@radix-ui/react-icons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", + "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" + } + }, "node_modules/@radix-ui/react-id": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz", @@ -7073,6 +7083,23 @@ "react": ">= 16.8.0" } }, + "node_modules/@utsubo/events": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@utsubo/events/-/events-0.1.7.tgz", + "integrity": "sha512-WB/GEj/0h27Bz8rJ0+CBtNz5mLT79ne1OjB7PUM4n0qLBqEDwm6yBzZC3j6tasHjlBPJDYZiBVIA1glaMlgZ5g==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.7" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -17894,6 +17921,64 @@ "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==", "license": "ISC" }, + "node_modules/r3f-perf": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/r3f-perf/-/r3f-perf-7.2.3.tgz", + "integrity": "sha512-4+P/N/bnO9D8nzdm3suL/NjPZK/HHdjwpvajhi8j7eB41i2ECN6lX9RXiKSpHzpsDi2ui1tBj6q7/sz5opoqXw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-icons": "^1.3.0", + "@react-three/drei": "^9.103.0", + "@stitches/react": "^1.2.8", + "@utsubo/events": "^0.1.7", + "zustand": "~4.5.2" + }, + "peerDependencies": { + "@react-three/fiber": ">=8.0", + "react": ">=18.0", + "react-dom": ">=18.0", + "three": ">=0.133" + }, + "peerDependenciesMeta": { + "@react-three/fiber": { + "optional": true + }, + "dom": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/r3f-perf/node_modules/zustand": { + "version": "4.5.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz", + "integrity": "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==", + "license": "MIT", + "dependencies": { + "use-sync-external-store": "^1.2.2" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0.6", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", diff --git a/app/package.json b/app/package.json index 16c4ac0..aec1d38 100644 --- a/app/package.json +++ b/app/package.json @@ -33,6 +33,7 @@ "mqtt": "^5.10.4", "postprocessing": "^6.36.4", "prompt-sync": "^4.2.0", + "r3f-perf": "^7.2.3", "react": "^18.3.1", "react-chartjs-2": "^5.3.0", "react-dom": "^18.3.1", diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx index 4d280d2..4046d89 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/StorageAction.tsx @@ -3,53 +3,51 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; interface StorageActionProps { - type: "store" | "spawn" | "default"; - value: string; + maxCapacity: string; + spawnedCount: string; min: number; max?: number; - defaultValue: string; + maxCapacityDefault: string; + spawnedCountCefault: string; currentMaterialType: string; handleCapacityChange: (value: string) => void; + handleSpawnCountChange: (value: string) => void; handleMaterialTypeChange: (value: string) => void; } -const StorageAction: React.FC = ({ type, value, min, max, defaultValue, currentMaterialType, handleCapacityChange, handleMaterialTypeChange }) => { +const StorageAction: React.FC = ({ maxCapacity, spawnedCount, min, max, maxCapacityDefault, spawnedCountCefault, currentMaterialType, handleCapacityChange, handleSpawnCountChange, handleMaterialTypeChange }) => { return ( <> - {type === 'store' && - { }} - onChange={handleCapacityChange} - /> - } - {type === 'spawn' && - <> - { }} - onChange={handleCapacityChange} - /> - - - } + { }} + onChange={handleCapacityChange} + /> + { }} + onChange={handleSpawnCountChange} + /> + ); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 796dbc5..e69ceba 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -14,10 +14,13 @@ import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function StorageMechanics() { const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); + const [currentCapacity, setCurrentCapacity] = useState("1"); + const [spawnedCount, setSpawnedCount] = useState("0"); + const [spawnedMaterial, setSpawnedMaterial] = useState("Default material"); const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); - const { getPointByUuid, updateAction } = productStore(); + const { getPointByUuid, updateAction, updateEvent, getEventByModelUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); @@ -52,6 +55,24 @@ function StorageMechanics() { setSelectedPointData(point); const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType; setActiveOption(uiOption as "store" | "spawn"); + setCurrentCapacity( + (getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid + ) as StorageEventSchema | undefined)?.storageCapacity?.toString() || "1" + ); + setSpawnedCount( + (getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid + ) as StorageEventSchema | undefined)?.storageCount?.toString() || "0" + ) + setSpawnedMaterial( + (getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid + ) as StorageEventSchema | undefined)?.materialType?.toString() || "Default material" + ) setSelectedAction(point.action.actionUuid, point.action.actionName); } } else { @@ -95,29 +116,55 @@ function StorageMechanics() { } }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName }); - - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productUuid, - projectId || '', - event - ); - updateSelectedPointData(); - } - }; - const handleCapacityChange = (value: string) => { if (!selectedEventData || !selectedPointData) return; - const newCapacity = parseInt(value); - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - storageCapacity: newCapacity, + const newCapacity = parseInt(value); + let updatedEvent: EventsSchema | undefined; + + updatedEvent = updateEvent( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + { storageCapacity: newCapacity } + ); + + const currentCount = parseInt(spawnedCount); + if (currentCount > newCapacity) { + updatedEvent = updateEvent( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + { storageCount: newCapacity } + ); + setSpawnedCount(newCapacity.toString()); + } + + setCurrentCapacity(value); + + if (updatedEvent) { + updateBackend( + selectedProduct.productName, + selectedProduct.productUuid, + projectId || '', + updatedEvent + ); + updateSelectedPointData(); + } + }; + + const handleSpawnCountChange = (value: string) => { + if (!selectedEventData || !selectedPointData) return; + + const newCount = parseInt(value); + const maxCapacity = parseInt(currentCapacity); + + if (newCount > maxCapacity) return; + + const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { + storageCount: newCount, }); + setSpawnedCount(value); + if (event) { updateBackend( selectedProduct.productName, @@ -129,19 +176,10 @@ function StorageMechanics() { } }; - const createNewMaterial = (materialType: string): { materialType: string; materialId: string } | null => { - if (!selectedEventData || !selectedPointData) return null; - const materialId = THREE.MathUtils.generateUUID(); - return { - materialType, - materialId - }; - }; - const handleMaterialTypeChange = (value: string) => { if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { + const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { materialType: value, }); @@ -161,16 +199,6 @@ function StorageMechanics() { [selectedPointData] ); - const currentCapacity = useMemo(() => - selectedPointData ? selectedPointData.action.storageCapacity.toString() : "0", - [selectedPointData] - ); - - const currentMaterialType = useMemo(() => - selectedPointData?.action.materialType || "Default material", - [selectedPointData] - ); - const availableActions = { defaultOption: "store", options: ["store", "spawn"], @@ -184,38 +212,44 @@ function StorageMechanics() { return ( <> {selectedEventData && ( -
- -
-
- + <> +
+ +
+
+ +
+
+ +
+
+ +
-
- - +
+
-
-
- -
-
+
+ )} ); diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 072c9a7..dbab693 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -232,6 +232,9 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) { rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "storageUnit", + storageCapacity: 10, + storageCount: 10, + materialType: "Default material", subType: item.eventData.subType || '', point: { uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), @@ -241,7 +244,6 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "store", - storageCapacity: 10, triggers: [] } } diff --git a/app/src/modules/builder/asset/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts index c64064a..fca0426 100644 --- a/app/src/modules/builder/asset/functions/addAssetModel.ts +++ b/app/src/modules/builder/asset/functions/addAssetModel.ts @@ -345,6 +345,9 @@ async function handleModelLoad( rotation: newFloorItem.rotation, state: "idle", type: "storageUnit", + storageCapacity: 10, + storageCount: 10, + materialType: "Default material", subType: selectedItem.subType || '', point: { uuid: THREE.MathUtils.generateUUID(), @@ -354,7 +357,6 @@ async function handleModelLoad( actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "store", - storageCapacity: 10, triggers: [], }, }, diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx index e9d7bc3..5b5eb6b 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx @@ -375,6 +375,9 @@ const CopyPasteControls3D = ({ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: "storageUnit", + storageCapacity: 10, + storageCount: 10, + materialType: "Default material", subType: pastedAsset.userData.eventData.subType || '', point: { uuid: THREE.MathUtils.generateUUID(), @@ -384,7 +387,6 @@ const CopyPasteControls3D = ({ actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "store", - storageCapacity: 10, triggers: [] } } diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx index fcac600..8f47996 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx @@ -445,6 +445,9 @@ const DuplicationControls3D = ({ rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: "storageUnit", + storageCapacity: 10, + storageCount: 10, + materialType: "Default material", subType: duplicatedAsset.userData.eventData.subType || '', point: { uuid: THREE.MathUtils.generateUUID(), @@ -454,7 +457,6 @@ const DuplicationControls3D = ({ actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "store", - storageCapacity: 10, triggers: [] } } diff --git a/app/src/modules/scene/helpers/StatsHelper.tsx b/app/src/modules/scene/helpers/StatsHelper.tsx index 486488b..7414b70 100644 --- a/app/src/modules/scene/helpers/StatsHelper.tsx +++ b/app/src/modules/scene/helpers/StatsHelper.tsx @@ -1,7 +1,8 @@ import { useEffect, useState } from "react"; -import { Stats } from "@react-three/drei"; import { detectModifierKeys } from "../../../utils/shortcutkeys/detectModifierKeys"; +import { Perf } from 'r3f-perf'; + export default function StatsHelper() { const [visible, setVisible] = useState(false); @@ -18,5 +19,5 @@ export default function StatsHelper() { return () => window.removeEventListener("keydown", handleKeyDown); }, []); - return visible ? : null; + return visible ? : null; } diff --git a/app/src/modules/scene/scene.tsx b/app/src/modules/scene/scene.tsx index feddc2c..b5e6739 100644 --- a/app/src/modules/scene/scene.tsx +++ b/app/src/modules/scene/scene.tsx @@ -14,7 +14,6 @@ import { getAllProjects } from "../../services/dashboard/getAllProjects"; import { getUserData } from "../../functions/getUserData"; import { useLoadingProgress, useSocketStore } from "../../store/builder/store"; import { Color, SRGBColorSpace } from "three"; -import StatsHelper from "./helpers/StatsHelper"; export default function Scene({ layout }: { readonly layout: "Main Layout" | "Comparison Layout"; }) { const map = useMemo(() => [ @@ -72,7 +71,6 @@ export default function Scene({ layout }: { readonly layout: "Main Layout" | "Co - ); diff --git a/app/src/modules/scene/setup/setup.tsx b/app/src/modules/scene/setup/setup.tsx index 71dcce7..16011f1 100644 --- a/app/src/modules/scene/setup/setup.tsx +++ b/app/src/modules/scene/setup/setup.tsx @@ -1,11 +1,11 @@ import Sun from '../environment/sky' import Shadows from '../environment/shadow' import PostProcessing from '../postProcessing/postProcessing' +import StatsHelper from '../helpers/StatsHelper'; import Controls from '../controls/controls'; import { AdaptiveDpr, AdaptiveEvents, Environment } from '@react-three/drei' import background from "../../../assets/textures/hdr/mudroadpuresky2k.hdr"; -// import { Perf } from 'r3f-perf'; function Setup() { return ( @@ -18,12 +18,12 @@ function Setup() { - {/* */} - {/* */} + + diff --git a/app/src/modules/scene/tools/autoRotate.tsx b/app/src/modules/scene/tools/autoRotate.tsx new file mode 100644 index 0000000..f0ff7a0 --- /dev/null +++ b/app/src/modules/scene/tools/autoRotate.tsx @@ -0,0 +1,47 @@ +import { useEffect, useRef, useState } from 'react' +import { useThree, useFrame } from '@react-three/fiber' +import type CameraControlsImpl from 'camera-controls' + +export default function AutoRotate() { + const { gl, controls } = useThree() + const [isIdle, setIsIdle] = useState(false) + const idleTimeout = useRef(null) + const lastInteractionTime = useRef(Date.now()) + + const cameraControls = controls as CameraControlsImpl | null + + const resetIdleTimer = () => { + lastInteractionTime.current = Date.now() + if (isIdle) setIsIdle(false) + if (idleTimeout.current) clearTimeout(idleTimeout.current) + idleTimeout.current = setTimeout(() => { + setIsIdle(true) + }, 30_000) + } + + useEffect(() => { + const dom = gl.domElement + const listener = () => resetIdleTimer() + + dom.addEventListener('pointerdown', listener) + dom.addEventListener('wheel', listener) + window.addEventListener('keydown', listener) + + resetIdleTimer() + + return () => { + dom.removeEventListener('pointerdown', listener) + dom.removeEventListener('wheel', listener) + window.removeEventListener('keydown', listener) + } + }, [gl]) + + useFrame((_, delta) => { + if (isIdle && cameraControls) { + cameraControls.rotate(delta * 0.1, 0, true) + cameraControls.update(delta) + } + }) + + return null +} diff --git a/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx b/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx index c5645af..558401c 100644 --- a/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx +++ b/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx @@ -238,7 +238,7 @@ function WorkerInstance({ human }: { human: HumanStatus }) { human.modelUuid, human.currentLoad, model.modelUuid, - model.point.action.storageCapacity, + model.storageCapacity, (action as HumanAction) ); } diff --git a/app/src/modules/simulation/products/products.tsx b/app/src/modules/simulation/products/products.tsx index f65e33f..f90c26a 100644 --- a/app/src/modules/simulation/products/products.tsx +++ b/app/src/modules/simulation/products/products.tsx @@ -136,15 +136,14 @@ function Products() { if (event.type === 'storageUnit') { addStorageUnit(selectedProduct.productUuid, event); - if (event.point.action.actionType === 'retrieve') { - const storageAction = event.point.action; - const materials = Array.from({ length: storageAction.storageCapacity }, () => ({ - materialType: storageAction.materialType || 'Default material', + if (event.storageCount > 0) { + const materials = Array.from({ length: event.storageCount }, () => ({ + materialType: event.materialType || 'Default material', materialId: THREE.MathUtils.generateUUID() })); setCurrentMaterials(event.modelUuid, materials); - updateCurrentLoad(event.modelUuid, storageAction.storageCapacity); + updateCurrentLoad(event.modelUuid, event.storageCount); } else { setCurrentMaterials(event.modelUuid, []); updateCurrentLoad(event.modelUuid, 0); diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 9660a6d..5cee999 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -575,7 +575,7 @@ export function useTriggerHandler() { if (action && storageUnit) { - if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) { + if (storageUnit.currentLoad < storageUnit.storageCapacity) { // Handle current action from vehicle handleAction(action, materialId); @@ -1135,7 +1135,7 @@ export function useTriggerHandler() { if (action && storageUnit) { - if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) { + if (storageUnit.currentLoad < storageUnit.storageCapacity) { // Handle current action from vehicle handleAction(action, materialId); @@ -1782,7 +1782,7 @@ export function useTriggerHandler() { if (action && storageUnit) { - if (storageUnit.currentLoad < storageUnit.point.action.storageCapacity) { + if (storageUnit.currentLoad < storageUnit.storageCapacity) { // Handle current action from vehicle handleAction(action, materialId); diff --git a/app/src/modules/simulation/ui3d/StorageContentUi.tsx b/app/src/modules/simulation/ui3d/StorageContentUi.tsx index 38f62dc..7d02932 100644 --- a/app/src/modules/simulation/ui3d/StorageContentUi.tsx +++ b/app/src/modules/simulation/ui3d/StorageContentUi.tsx @@ -31,7 +31,7 @@ const StorageContentUi: React.FC = ({ storageUnit }) => { status={storageUnit.state} count={storageUnit.currentLoad} enableStatue={false} - totalCapacity={storageUnit.point.action.storageCapacity} + totalCapacity={storageUnit.storageCapacity} /> ); diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 0466ba2..89f6bfb 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -394,7 +394,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) agvDetail.currentLoad, agvDetail.point.action.unLoadDuration, model.modelUuid, - model.point.action.storageCapacity, + model.storageCapacity, agvDetail.point.action ); } diff --git a/app/src/store/simulation/useStorageUnitStore.ts b/app/src/store/simulation/useStorageUnitStore.ts index c89e643..deae86a 100644 --- a/app/src/store/simulation/useStorageUnitStore.ts +++ b/app/src/store/simulation/useStorageUnitStore.ts @@ -205,7 +205,7 @@ export const createStorageUnitStore = () => { getFullStorageUnits: () => { return get().storageUnits.filter( - s => s.currentLoad >= s.point.action.storageCapacity + s => s.currentLoad >= s.storageCapacity ); }, diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index ae6c55a..0110fcd 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -90,8 +90,6 @@ interface StorageAction { actionUuid: string; actionName: string; actionType: "store" | "retrieve"; - materialType?: string; - storageCapacity: number; triggers: TriggerSchema[]; } @@ -207,6 +205,9 @@ interface MachineEventSchema extends AssetEventSchema { interface StorageEventSchema extends AssetEventSchema { type: "storageUnit"; subType: string; + storageCapacity: number; + storageCount: number; + materialType: string; point: StoragePointSchema; } From e950b0f54a71b93fe48f9c21c37f639ecbc2ac1c Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Wed, 20 Aug 2025 18:11:01 +0530 Subject: [PATCH 2/3] added multiple actions to storage unit --- .../mechanics/storageMechanics.tsx | 330 +++++++++++------- .../eventProperties/trigger/Trigger.tsx | 8 +- app/src/modules/builder/asset/assetsGroup.tsx | 14 +- .../builder/asset/functions/addAssetModel.ts | 14 +- .../selection3D/copyPasteControls3D.tsx | 14 +- .../selection3D/duplicationControls3D.tsx | 14 +- .../actionHandler/useRetrieveHandler.ts | 41 ++- .../triggerConnections/triggerConnector.tsx | 6 +- .../instance/actions/workerInstance.tsx | 18 +- .../instances/instance/vehicleInstance.tsx | 18 +- app/src/types/simulationTypes.d.ts | 2 +- 11 files changed, 296 insertions(+), 183 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index e69ceba..3966b17 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -1,4 +1,5 @@ -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useState } from "react"; +import { MathUtils } from "three"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; @@ -6,79 +7,88 @@ import StorageAction from "../actions/StorageAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore"; -import * as THREE from 'three'; import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; import { useParams } from "react-router-dom"; import { useVersionContext } from "../../../../../../modules/builder/version/versionContext"; import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function StorageMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "store" | "spawn">("default"); + const [activeOption, setActiveOption] = useState<"store" | "spawn">("store"); const [currentCapacity, setCurrentCapacity] = useState("1"); const [spawnedCount, setSpawnedCount] = useState("0"); const [spawnedMaterial, setSpawnedMaterial] = useState("Default material"); const [selectedPointData, setSelectedPointData] = useState(); + const [currentAction, setCurrentAction] = useState(); const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); - const { getPointByUuid, updateAction, updateEvent, getEventByModelUuid } = productStore(); + const { getPointByUuid, updateAction, updateEvent, getEventByModelUuid, getActionByUuid, addAction, removeAction } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); - const { setSelectedAction, clearSelectedAction } = useSelectedAction(); + const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { projectId } = useParams(); - const updateSelectedPointData = () => { - if (selectedEventData && selectedProduct) { - const point = getPointByUuid( - selectedProduct.productUuid, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint - ) as StoragePointSchema | undefined; - if (point && "action" in point) { - setSelectedPointData(point); - const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType; - setActiveOption(uiOption as "store" | "spawn"); - setSelectedAction(point.action.actionUuid, point.action.actionName); - } - } - }; - useEffect(() => { - if (selectedEventData) { + if (selectedEventData && selectedEventData.data.type === "storageUnit") { const point = getPointByUuid( selectedProduct.productUuid, - selectedEventData?.data.modelUuid, - selectedEventData?.selectedPoint + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint ) as StoragePointSchema | undefined; - if (point && "action" in point) { + + if (point?.actions?.length) { setSelectedPointData(point); - const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType; - setActiveOption(uiOption as "store" | "spawn"); - setCurrentCapacity( - (getEventByModelUuid( - selectedProduct.productUuid, - selectedEventData.data.modelUuid - ) as StorageEventSchema | undefined)?.storageCapacity?.toString() || "1" - ); - setSpawnedCount( - (getEventByModelUuid( - selectedProduct.productUuid, - selectedEventData.data.modelUuid - ) as StorageEventSchema | undefined)?.storageCount?.toString() || "0" - ) - setSpawnedMaterial( - (getEventByModelUuid( - selectedProduct.productUuid, - selectedEventData.data.modelUuid - ) as StorageEventSchema | undefined)?.materialType?.toString() || "Default material" - ) - setSelectedAction(point.action.actionUuid, point.action.actionName); + const firstAction = point.actions[0]; + setCurrentAction(firstAction); + + const eventData = getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid + ) as StorageEventSchema | undefined; + + setCurrentCapacity(eventData?.storageCapacity?.toString() || "1"); + setSpawnedCount(eventData?.storageCount?.toString() || "0"); + setSpawnedMaterial(eventData?.materialType?.toString() || "Default material"); + + const actionUuid = selectedAction.actionId || firstAction.actionUuid; + const newCurrentAction = getActionByUuid(selectedProduct.productUuid, actionUuid); + + if (newCurrentAction) { + const uiOption = newCurrentAction.actionType === "retrieve" ? "spawn" : "store"; + setActiveOption(uiOption); + setSelectedAction(newCurrentAction.actionUuid, newCurrentAction.actionName); + } } } else { clearSelectedAction(); + setCurrentAction(undefined); } - }, [selectedProduct, selectedEventData]); + }, [selectedEventData, selectedProduct]); + + useEffect(() => { + if (selectedEventData && selectedEventData.data.type === "storageUnit" && selectedAction.actionId) { + const point = getPointByUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint + ) as StoragePointSchema | undefined; + + const newCurrentAction = getActionByUuid(selectedProduct.productUuid, selectedAction.actionId); + + if (newCurrentAction && (newCurrentAction.actionType === 'store' || newCurrentAction.actionType === 'retrieve')) { + if (!selectedAction.actionId) { + setSelectedAction(newCurrentAction.actionUuid, newCurrentAction.actionName); + } + setCurrentAction(newCurrentAction); + const uiOption = newCurrentAction.actionType === "retrieve" ? "spawn" : "store"; + setActiveOption(uiOption); + } else { + clearSelectedAction(); + setCurrentAction(undefined); + } + } + }, [selectedAction, selectedProduct, selectedEventData]); const updateBackend = ( productName: string, @@ -96,14 +106,26 @@ function StorageMechanics() { } const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const internalOption = actionTypeMap[option as keyof typeof actionTypeMap] as "store" | "retrieve"; + if (!selectedAction.actionId || !currentAction || !selectedPointData) return; - setActiveOption(option as "store" | "spawn"); + const internalOption = option === "spawn" ? "retrieve" : "store"; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - actionType: internalOption, - }); + const updatedAction = { + ...currentAction, + actionType: internalOption as "store" | "retrieve" + }; + + const updatedActions = selectedPointData.actions.map(action => + action.actionUuid === updatedAction.actionUuid ? updatedAction : action + ); + + const updatedPoint = { ...selectedPointData, actions: updatedActions }; + + const event = updateAction( + selectedProduct.productUuid, + selectedAction.actionId, + updatedAction + ); if (event) { updateBackend( @@ -112,58 +134,67 @@ function StorageMechanics() { projectId || '', event ); - updateSelectedPointData(); } + + setCurrentAction(updatedAction); + setSelectedPointData(updatedPoint); + setActiveOption(option as "store" | "spawn"); }; const handleCapacityChange = (value: string) => { - if (!selectedEventData || !selectedPointData) return; + if (!selectedEventData) return; - const newCapacity = parseInt(value); - let updatedEvent: EventsSchema | undefined; + const numericValue = parseInt(value); + if (isNaN(numericValue)) return; - updatedEvent = updateEvent( - selectedProduct.productUuid, - selectedEventData.data.modelUuid, - { storageCapacity: newCapacity } - ); + const updatedEvent = { + ...selectedEventData.data, + storageCapacity: numericValue + } as StorageEventSchema; const currentCount = parseInt(spawnedCount); - if (currentCount > newCapacity) { - updatedEvent = updateEvent( + if (currentCount > numericValue) { + updatedEvent.storageCount = numericValue; + setSpawnedCount(numericValue.toString()); + } + + const event = updateEvent( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + updatedEvent + ); + + if (event) { + updateBackend( + selectedProduct.productName, selectedProduct.productUuid, - selectedEventData.data.modelUuid, - { storageCount: newCapacity } + projectId || '', + event ); - setSpawnedCount(newCapacity.toString()); } setCurrentCapacity(value); - - if (updatedEvent) { - updateBackend( - selectedProduct.productName, - selectedProduct.productUuid, - projectId || '', - updatedEvent - ); - updateSelectedPointData(); - } }; const handleSpawnCountChange = (value: string) => { - if (!selectedEventData || !selectedPointData) return; + if (!selectedEventData) return; + + const numericValue = parseInt(value); + if (isNaN(numericValue)) return; - const newCount = parseInt(value); const maxCapacity = parseInt(currentCapacity); + if (numericValue > maxCapacity) return; - if (newCount > maxCapacity) return; + const updatedEvent = { + ...selectedEventData.data, + storageCount: numericValue + } as StorageEventSchema; - const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { - storageCount: newCount, - }); - - setSpawnedCount(value); + const event = updateEvent( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + updatedEvent + ); if (event) { updateBackend( @@ -172,16 +203,24 @@ function StorageMechanics() { projectId || '', event ); - updateSelectedPointData(); } + + setSpawnedCount(value); }; const handleMaterialTypeChange = (value: string) => { - if (!selectedEventData || !selectedPointData) return; + if (!selectedEventData) return; - const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { - materialType: value, - }); + const updatedEvent = { + ...selectedEventData.data, + materialType: value + } as StorageEventSchema; + + const event = updateEvent( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + updatedEvent + ); if (event) { updateBackend( @@ -190,28 +229,73 @@ function StorageMechanics() { projectId || '', event ); - updateSelectedPointData(); } + + setSpawnedMaterial(value); }; - const currentActionName = useMemo(() => - selectedPointData ? selectedPointData.action.actionName : "Action Name", - [selectedPointData] - ); + const handleAddAction = () => { + if (!selectedEventData || !selectedPointData) return; - const availableActions = { - defaultOption: "store", - options: ["store", "spawn"], + const newAction: StorageAction = { + actionUuid: MathUtils.generateUUID(), + actionName: `Action ${selectedPointData.actions.length + 1}`, + actionType: "store", + triggers: [], + }; + + const updatedActions = [...(selectedPointData.actions || []), newAction]; + const updatedPoint = { ...selectedPointData, actions: updatedActions }; + + const event = addAction( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + selectedEventData.selectedPoint, + newAction + ); + + if (event) { + updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); + } + + setSelectedPointData(updatedPoint); + setSelectedAction(newAction.actionUuid, newAction.actionName); }; - const actionTypeMap = { - spawn: "retrieve", - store: "store" + const handleDeleteAction = (actionUuid: string) => { + if (!selectedPointData || !actionUuid) return; + + const updatedActions = selectedPointData.actions.filter(action => action.actionUuid !== actionUuid); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; + + const event = removeAction( + selectedProduct.productUuid, + actionUuid + ); + + if (event) { + updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); + } + + setSelectedPointData(updatedPoint); + + const index = selectedPointData.actions.findIndex((a) => a.actionUuid === selectedAction.actionId); + const nextAction = updatedPoint.actions[index] || updatedPoint.actions[index - 1]; + if (nextAction) { + setSelectedAction(nextAction.actionUuid, nextAction.actionName); + const action = getActionByUuid(selectedProduct.productUuid, nextAction.actionUuid); + if (action) { + setCurrentAction(action as StorageAction); + } + } else { + clearSelectedAction(); + setCurrentAction(undefined); + } }; return ( <> - {selectedEventData && ( + {selectedEventData && selectedEventData.data.type === "storageUnit" && ( <>
-
-
- + + {selectedAction.actionId && currentAction && ( +
+
+ +
+
+ +
+
+ +
-
- -
-
-
- -
+ )}
)} diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx index 0697c7b..23c060c 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -13,7 +13,7 @@ import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; type TriggerProps = { selectedPointData?: PointsScheme | undefined; - type?: "Conveyor" | "Vehicle" | "RoboticArm" | "Machine" | "StorageUnit" | "Human"; + type?: "Conveyor" | "Vehicle" | "RoboticArm" | "Machine" | "StorageUnit" | "Human" | "Crane"; }; const Trigger = ({ selectedPointData, type }: TriggerProps) => { @@ -36,9 +36,9 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { let actionUuid: string | undefined; - if (type === "Conveyor" || type === "Vehicle" || type === "Machine" || type === "StorageUnit") { - actionUuid = (selectedPointData as | ConveyorPointSchema | VehiclePointSchema | MachinePointSchema | StoragePointSchema).action?.actionUuid; - } else if ((type === "RoboticArm" || type === "Human") && selectedAction.actionId) { + if (type === "Conveyor" || type === "Vehicle" || type === "Machine") { + actionUuid = (selectedPointData as | ConveyorPointSchema | VehiclePointSchema | MachinePointSchema).action?.actionUuid; + } else if ((type === "RoboticArm" || type === "Human" || type === "StorageUnit" || type === 'Crane') && selectedAction.actionId) { actionUuid = selectedAction.actionId; } diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index dbab693..436ea54 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -240,12 +240,14 @@ function AssetsGroup({ plane }: { readonly plane: RefMesh }) { uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "store", - triggers: [] - } + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "store", + triggers: [] + } + ] } }; addEvent(storageEvent); diff --git a/app/src/modules/builder/asset/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts index fca0426..cd55e4e 100644 --- a/app/src/modules/builder/asset/functions/addAssetModel.ts +++ b/app/src/modules/builder/asset/functions/addAssetModel.ts @@ -353,12 +353,14 @@ async function handleModelLoad( uuid: THREE.MathUtils.generateUUID(), position: [data.points[0].x, data.points[0].y, data.points[0].z], rotation: [0, 0, 0], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "store", - triggers: [], - }, + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "store", + triggers: [], + } + ], }, }; addEvent(storageEvent); diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx index 5b5eb6b..a2c01b6 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx @@ -383,12 +383,14 @@ const CopyPasteControls3D = ({ uuid: THREE.MathUtils.generateUUID(), position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "store", - triggers: [] - } + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "store", + triggers: [] + } + ] } } addEvent(storageEvent); diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx index 8f47996..3b28806 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx @@ -453,12 +453,14 @@ const DuplicationControls3D = ({ uuid: THREE.MathUtils.generateUUID(), position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], - action: { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "store", - triggers: [] - } + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "store", + triggers: [] + } + ] } } addEvent(storageEvent); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index 18e8bfd..3b26e91 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -171,8 +171,9 @@ export function useRetrieveHandler() { if (retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid) { const action = getActionByUuid(selectedProduct.productUuid, retrieval.action.triggers[0]?.triggeredAsset.triggeredAction.actionUuid); if (action && action.triggers.length > 0 && action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid) { - const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid); - if (model) { + const model = getEventByModelUuid(selectedProduct.productUuid, action?.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); + const triggeredAction = getActionByUuid(selectedProduct.productUuid, action?.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || ''); + if (model && triggeredAction) { if (model.type === 'vehicle') { const vehicle = getVehicleById(model.modelUuid); if (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { @@ -180,7 +181,7 @@ export function useRetrieveHandler() { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { @@ -193,11 +194,11 @@ export function useRetrieveHandler() { retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`); } } - } else { + } else if (triggeredAction) { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { @@ -271,10 +272,15 @@ export function useRetrieveHandler() { const lastMaterial = getLastMaterial(storageUnit.modelUuid); if (lastMaterial) { if (vehicle?.currentLoad < vehicle.point.action.loadCapacity) { + const triggeredAction = getActionByUuid( + selectedProduct.productUuid, + retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid || '' + ); + const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { @@ -322,6 +328,12 @@ export function useRetrieveHandler() { const triggeredModel = action.triggers[0]?.triggeredAsset?.triggeredModel?.modelUuid ? getEventByModelUuid(selectedProduct.productUuid, action.triggers[0].triggeredAsset.triggeredModel.modelUuid) : null; + + const triggeredAction = getActionByUuid( + selectedProduct.productUuid, + action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '' + ); + if (triggeredModel?.type === 'vehicle') { const model = getVehicleById(triggeredModel.modelUuid); if (model && !model.isActive && model.state === 'idle' && model.isPicking && model.currentLoad < model.point.action.loadCapacity) { @@ -333,7 +345,7 @@ export function useRetrieveHandler() { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { removeLastMaterial(storageUnit.modelUuid); @@ -359,7 +371,7 @@ export function useRetrieveHandler() { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { removeLastMaterial(storageUnit.modelUuid); @@ -385,7 +397,7 @@ export function useRetrieveHandler() { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { removeLastMaterial(storageUnit.modelUuid); @@ -417,7 +429,7 @@ export function useRetrieveHandler() { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { removeLastMaterial(storageUnit.modelUuid); @@ -438,7 +450,7 @@ export function useRetrieveHandler() { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { removeLastMaterial(storageUnit.modelUuid); @@ -484,10 +496,15 @@ export function useRetrieveHandler() { const lastMaterial = getLastMaterial(storageUnit.modelUuid); if (lastMaterial) { + const triggeredAction = getActionByUuid( + selectedProduct.productUuid, + action?.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid || '' + ); + const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, - storageUnit.point.action + triggeredAction as StorageAction ); if (material) { removeLastMaterial(storageUnit.modelUuid); diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx index 736667b..21a85c3 100644 --- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx +++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx @@ -144,8 +144,8 @@ function TriggerConnector() { // Handle StorageUnit point else if (event.type === "storageUnit" && 'point' in event) { const point = event.point; - if (point.action?.triggers) { - point.action.triggers.forEach(trigger => { + point.actions?.forEach(action => { + action.triggers?.forEach(trigger => { if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { newConnections.push({ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, @@ -155,7 +155,7 @@ function TriggerConnector() { }); } }); - } + }); } // Handle Human point else if (event.type === "human" && 'point' in event) { diff --git a/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx b/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx index 558401c..8c75af2 100644 --- a/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx +++ b/app/src/modules/simulation/human/instances/instance/actions/workerInstance.tsx @@ -108,7 +108,7 @@ function WorkerInstance({ human }: { human: HumanStatus }) { if (!human.isActive && human.state === 'idle' && human.currentPhase === 'init') { const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid); if (!humanMesh) return; - + const toPickupPath = computePath(humanMesh.position.toArray(), action?.pickUpPoint?.position || [0, 0, 0]); setPath(toPickupPath); @@ -233,15 +233,13 @@ function WorkerInstance({ human }: { human: HumanStatus }) { const checkAnimation = () => { if (humanAsset?.animationState?.isCompleted) { - if (model.point.action.actionType === 'store') { - loopMaterialDropToStorage( - human.modelUuid, - human.currentLoad, - model.modelUuid, - model.storageCapacity, - (action as HumanAction) - ); - } + loopMaterialDropToStorage( + human.modelUuid, + human.currentLoad, + model.modelUuid, + model.storageCapacity, + (action as HumanAction) + ); } else { requestAnimationFrame(checkAnimation); } diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 89f6bfb..4327c92 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -388,16 +388,14 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) function handleMaterialDropToStorageUnit(model: StorageEventSchema) { if (model) { - if (model.point.action.actionType === 'store') { - loopMaterialDropToStorage( - agvDetail.modelUuid, - agvDetail.currentLoad, - agvDetail.point.action.unLoadDuration, - model.modelUuid, - model.storageCapacity, - agvDetail.point.action - ); - } + loopMaterialDropToStorage( + agvDetail.modelUuid, + agvDetail.currentLoad, + agvDetail.point.action.unLoadDuration, + model.modelUuid, + model.storageCapacity, + agvDetail.point.action + ); } } diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 0110fcd..759267b 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -153,7 +153,7 @@ interface StoragePointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - action: StorageAction; + actions: StorageAction[]; } interface HumanPointSchema { From c24b0fd414e638d8008b50edeac3fca80937e855 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Fri, 22 Aug 2025 09:52:02 +0530 Subject: [PATCH 3/3] added multiple actions for storage unit , and simulation bug fix --- .../mechanics/conveyorMechanics.tsx | 20 ------- .../mechanics/craneMechanics.tsx | 30 ---------- .../mechanics/humanMechanics.tsx | 1 - .../mechanics/roboticArmMechanics.tsx | 30 ---------- .../mechanics/storageMechanics.tsx | 28 +++------- .../mechanics/vehicleMechanics.tsx | 20 ------- .../actionHandler/useRetrieveHandler.ts | 56 +++++++++---------- .../instances/animator/pillarJibAnimator.tsx | 1 - .../instances/instance/pillarJibInstance.tsx | 20 +++---- .../instance/actions/operatorInstance.tsx | 8 ++- .../functions/determineExecutionOrder.ts | 50 +++++++++++++---- .../simulation/simulator/simulator.tsx | 5 +- .../triggerHandler/useTriggerHandler.ts | 19 ++++--- .../instances/instance/vehicleInstance.tsx | 6 +- app/src/store/simulation/useMaterialStore.ts | 6 ++ app/src/types/simulationTypes.d.ts | 1 - 16 files changed, 112 insertions(+), 189 deletions(-) diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx index 990d046..20ce08a 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -125,26 +125,6 @@ function ConveyorMechanics() { } }; - const handleRenameAction = (newName: string) => { - if (!selectedPointData) return; - - setActionName(newName); - const event = updateAction( - selectedProduct.productUuid, - selectedPointData.action.actionUuid, - { actionName: newName } - ); - - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productUuid, - projectId || '', - event - ); - } - }; - const handleSpawnCountChange = (value: string) => { if (!selectedPointData) return; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/craneMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/craneMechanics.tsx index f5d1229..405eb5d 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/craneMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/craneMechanics.tsx @@ -62,36 +62,6 @@ function CraneMechanics() { }); }; - const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - - const event = updateAction( - selectedProduct.productUuid, - selectedAction.actionId, - { actionName: newName } - ); - - const updatedActions = selectedPointData.actions.map(action => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions, - }); - - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productUuid, - projectId || '', - event - ); - } - }; - const handleAddAction = () => { if (!selectedEventData || !selectedPointData) return; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx index 4b29f8c..2cdcf7d 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx @@ -142,7 +142,6 @@ function HumanMechanics() { if (isNaN(numericValue)) return; const updatedEvent = { - ...selectedEventData.data, speed: numericValue } as HumanEventSchema; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx index 0c7c6e3..120e1c7 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -71,36 +71,6 @@ function RoboticArmMechanics() { }); }; - const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId || !selectedPointData) return; - - const event = updateAction( - selectedProduct.productUuid, - selectedAction.actionId, - { actionName: newName } - ); - - const updatedActions = selectedPointData.actions.map(action => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions, - }); - - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productUuid, - projectId || '', - event - ); - } - }; - const handleSpeedChange = (value: string) => { if (!selectedEventData) return; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx index 3966b17..627dcbd 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -18,7 +18,6 @@ function StorageMechanics() { const [spawnedCount, setSpawnedCount] = useState("0"); const [spawnedMaterial, setSpawnedMaterial] = useState("Default material"); const [selectedPointData, setSelectedPointData] = useState(); - const [currentAction, setCurrentAction] = useState(); const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); const { getPointByUuid, updateAction, updateEvent, getEventByModelUuid, getActionByUuid, addAction, removeAction } = productStore(); @@ -40,7 +39,6 @@ function StorageMechanics() { if (point?.actions?.length) { setSelectedPointData(point); const firstAction = point.actions[0]; - setCurrentAction(firstAction); const eventData = getEventByModelUuid( selectedProduct.productUuid, @@ -62,7 +60,6 @@ function StorageMechanics() { } } else { clearSelectedAction(); - setCurrentAction(undefined); } }, [selectedEventData, selectedProduct]); @@ -74,18 +71,18 @@ function StorageMechanics() { selectedEventData.selectedPoint ) as StoragePointSchema | undefined; - const newCurrentAction = getActionByUuid(selectedProduct.productUuid, selectedAction.actionId); + const actionUuid = selectedAction.actionId || point?.actions[0].actionUuid || ''; + + const newCurrentAction = getActionByUuid(selectedProduct.productUuid, actionUuid); if (newCurrentAction && (newCurrentAction.actionType === 'store' || newCurrentAction.actionType === 'retrieve')) { if (!selectedAction.actionId) { setSelectedAction(newCurrentAction.actionUuid, newCurrentAction.actionName); } - setCurrentAction(newCurrentAction); const uiOption = newCurrentAction.actionType === "retrieve" ? "spawn" : "store"; setActiveOption(uiOption); } else { clearSelectedAction(); - setCurrentAction(undefined); } } }, [selectedAction, selectedProduct, selectedEventData]); @@ -106,17 +103,19 @@ function StorageMechanics() { } const handleActionTypeChange = (option: string) => { - if (!selectedAction.actionId || !currentAction || !selectedPointData) return; + if (!selectedAction.actionId || !selectedPointData) return; const internalOption = option === "spawn" ? "retrieve" : "store"; const updatedAction = { - ...currentAction, actionType: internalOption as "store" | "retrieve" }; const updatedActions = selectedPointData.actions.map(action => - action.actionUuid === updatedAction.actionUuid ? updatedAction : action + action.actionUuid === selectedAction.actionId ? { + ...action, + actionType: updatedAction.actionType + } : action ); const updatedPoint = { ...selectedPointData, actions: updatedActions }; @@ -136,7 +135,6 @@ function StorageMechanics() { ); } - setCurrentAction(updatedAction); setSelectedPointData(updatedPoint); setActiveOption(option as "store" | "spawn"); }; @@ -148,7 +146,6 @@ function StorageMechanics() { if (isNaN(numericValue)) return; const updatedEvent = { - ...selectedEventData.data, storageCapacity: numericValue } as StorageEventSchema; @@ -186,7 +183,6 @@ function StorageMechanics() { if (numericValue > maxCapacity) return; const updatedEvent = { - ...selectedEventData.data, storageCount: numericValue } as StorageEventSchema; @@ -212,7 +208,6 @@ function StorageMechanics() { if (!selectedEventData) return; const updatedEvent = { - ...selectedEventData.data, materialType: value } as StorageEventSchema; @@ -283,13 +278,8 @@ function StorageMechanics() { const nextAction = updatedPoint.actions[index] || updatedPoint.actions[index - 1]; if (nextAction) { setSelectedAction(nextAction.actionUuid, nextAction.actionName); - const action = getActionByUuid(selectedProduct.productUuid, nextAction.actionUuid); - if (action) { - setCurrentAction(action as StorageAction); - } } else { clearSelectedAction(); - setCurrentAction(undefined); } }; @@ -318,7 +308,7 @@ function StorageMechanics() { handleDeleteAction={handleDeleteAction} /> - {selectedAction.actionId && currentAction && ( + {selectedAction.actionId && (
{ - if (!selectedPointData) return; - - setActionName(newName); - const event = updateAction( - selectedProduct.productUuid, - selectedPointData.action.actionUuid, - { actionName: newName } - ); - - if (event) { - updateBackend( - selectedProduct.productName, - selectedProduct.productUuid, - projectId || '', - event - ); - } - }; - const handleLoadCapacityChange = (value: string) => { if (!selectedPointData) return; diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index 3b26e91..ae907b4 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -44,35 +44,29 @@ export function useRetrieveHandler() { if (!modelUuid || !pointUuid) return null; const currentTime = performance.now(); - if (action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid && - action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid && - action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid - ) { - const newMaterial: MaterialSchema = { - materialId: materialId, - materialName: `${materialType}-${Date.now()}`, - materialType: materialType, - isActive: false, - isVisible: false, - isPaused: false, - isRendered: true, - startTime: currentTime, - previous: { - modelUuid: modelUuid, - pointUuid: pointUuid, - actionUuid: action.actionUuid - }, - current: { - modelUuid: modelUuid, - pointUuid: pointUuid, - actionUuid: action.actionUuid - }, - }; + const newMaterial: MaterialSchema = { + materialId: materialId, + materialName: `${materialType}-${Date.now()}`, + materialType: materialType, + isActive: false, + isVisible: false, + isPaused: false, + isRendered: true, + startTime: currentTime, + previous: { + modelUuid: modelUuid, + pointUuid: pointUuid, + actionUuid: action.actionUuid + }, + current: { + modelUuid: modelUuid, + pointUuid: pointUuid, + actionUuid: action.actionUuid + }, + }; - addMaterial(newMaterial); - return newMaterial; - } - return null; + addMaterial(newMaterial); + return newMaterial; }, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productUuid]); useEffect(() => { @@ -112,12 +106,16 @@ export function useRetrieveHandler() { getModelUuidByActionUuid(selectedProduct.productUuid, retrieval.action.actionUuid) ?? '' ); - if (!storageUnit || storageUnit.currentLoad <= 0) { + if (!storageUnit) { completedActions.push(actionUuid); hasChanges = true; return; } + if (storageUnit.currentLoad <= 0) { + return; + } + if (retrieval.action.triggers.length === 0 || !retrieval.action.triggers[0]?.triggeredAsset) { return; } diff --git a/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx b/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx index 96455b2..85e1448 100644 --- a/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx +++ b/app/src/modules/simulation/crane/instances/animator/pillarJibAnimator.tsx @@ -56,7 +56,6 @@ function PillarJibAnimator({ if (crane.currentPhase === 'init-pickup') { if (crane.currentMaterials.length > 0) { const materials = scene.getObjectsByProperty('uuid', crane.currentMaterials[0].materialId); - console.log('materials: ', materials); const material = materials.find((material) => material.visible === true); if (material) { const materialWorld = new THREE.Vector3(); diff --git a/app/src/modules/simulation/crane/instances/instance/pillarJibInstance.tsx b/app/src/modules/simulation/crane/instances/instance/pillarJibInstance.tsx index 11c06a4..4e18eb2 100644 --- a/app/src/modules/simulation/crane/instances/instance/pillarJibInstance.tsx +++ b/app/src/modules/simulation/crane/instances/instance/pillarJibInstance.tsx @@ -35,17 +35,15 @@ function PillarJibInstance({ crane }: { crane: CraneStatus }) { if (!crane.isActive && crane.currentPhase === 'init' && crane.currentMaterials.length > 0 && action.maxPickUpCount <= crane.currentMaterials.length) { setCurrentPhase(crane.modelUuid, 'init-pickup'); } else if (crane.currentPhase === 'picking' && crane.currentMaterials.length > 0 && action.maxPickUpCount <= crane.currentMaterials.length && !crane.isCarrying) { - if (action.triggers.length > 0) { - if (humanAsset?.animationState?.current === "working_standing" && humanAsset?.animationState?.isCompleted && humanId && humanAction && humanAction.actionType === 'operator') { - setCurrentAnimation(humanId, 'idle', true, true, true); - setIsCaryying(crane.modelUuid, true); - setCurrentPhase(crane.modelUuid, 'pickup-drop'); - } else { - setCurrentPhaseHuman(humanId, 'hooking'); - setHumanActive(humanId, true); - setHumanState(humanId, 'running'); - setCurrentAnimation(humanId, 'working_standing', true, false, false); - } + if (humanAsset?.animationState?.current === "working_standing" && humanAsset?.animationState?.isCompleted && humanId && humanAction && humanAction.actionType === 'operator') { + setCurrentAnimation(humanId, 'idle', true, true, true); + setIsCaryying(crane.modelUuid, true); + setCurrentPhase(crane.modelUuid, 'pickup-drop'); + } else { + setCurrentPhaseHuman(humanId, 'hooking'); + setHumanActive(humanId, true); + setHumanState(humanId, 'running'); + setCurrentAnimation(humanId, 'working_standing', true, false, false); } } else if (crane.currentPhase === 'dropping' && crane.currentMaterials.length > 0 && action.maxPickUpCount <= crane.currentMaterials.length && crane.isCarrying && human.currentPhase === 'hooking') { setCurrentPhaseHuman(humanId, 'loadPoint-unloadPoint'); diff --git a/app/src/modules/simulation/human/instances/instance/actions/operatorInstance.tsx b/app/src/modules/simulation/human/instances/instance/actions/operatorInstance.tsx index d938353..fce077f 100644 --- a/app/src/modules/simulation/human/instances/instance/actions/operatorInstance.tsx +++ b/app/src/modules/simulation/human/instances/instance/actions/operatorInstance.tsx @@ -126,9 +126,11 @@ function OperatorInstance({ human }: { human: HumanStatus }) { humanStatus(human.modelUuid, 'Started from loadPoint, heading to unloadPoint'); } } else if (human.state === 'idle' && human.currentPhase === 'unhooking') { - setHumanState(human.modelUuid, 'running'); - setHumanActive(human.modelUuid, true); - setCurrentAnimation(human.modelUuid, 'working_standing', true, false, false); + setTimeout(() => { + setHumanState(human.modelUuid, 'running'); + setHumanActive(human.modelUuid, true); + setCurrentAnimation(human.modelUuid, 'working_standing', true, false, false); + }, 1) } } else { reset() diff --git a/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts b/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts index 09be2f2..f06992b 100644 --- a/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts +++ b/app/src/modules/simulation/simulator/functions/determineExecutionOrder.ts @@ -1,12 +1,13 @@ import { extractTriggersFromPoint } from "./extractTriggersFromPoint"; -export function determineExecutionOrder(products: productsSchema): PointsScheme[] { +export function determineExecutionOrder(products: productsSchema): Action[] { // Create maps for all events and points const eventMap = new Map(); const pointMap = new Map(); const allPoints: PointsScheme[] = []; + const spawnActions: Action[] = []; - // First pass: collect all points + // First pass: collect all points and identify spawn actions products.forEach(product => { product.eventDatas.forEach(event => { eventMap.set(event.modelUuid, event); @@ -15,6 +16,11 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[ event.points.forEach(point => { pointMap.set(point.uuid, point); allPoints.push(point); + + // Check for spawn actions in conveyors + if (point.action.actionType === 'spawn') { + spawnActions.push(point.action); + } }); } else if (event.type === 'vehicle' || event.type === 'machine' || @@ -25,6 +31,16 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[ ) { pointMap.set(event.point.uuid, event.point); allPoints.push(event.point); + + // Check for spawn actions in storage units and other types + if (event.type === 'storageUnit') { + const storagePoint = event.point as StoragePointSchema; + storagePoint.actions.forEach(action => { + if (action.actionType === 'retrieve') { + spawnActions.push(action); + } + }); + } } }); }); @@ -33,11 +49,19 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[ const graph = new Map(); const reverseGraph = new Map(); const allTriggeredPoints = new Set(); + const actionMap = new Map(); // Map point UUID to its primary action allPoints.forEach(point => { const triggers = extractTriggersFromPoint(point); const dependencies: string[] = []; + // Store the primary action for this point + if ('action' in point) { + actionMap.set(point.uuid, point.action); + } else if ('actions' in point && point.actions.length > 0) { + actionMap.set(point.uuid, point.actions[0]); // Use first action as primary + } + triggers.forEach(trigger => { const targetUuid = trigger.triggeredAsset?.triggeredPoint?.pointUuid; if (targetUuid && pointMap.has(targetUuid)) { @@ -58,15 +82,12 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[ const rootPoints = allPoints .filter(point => !allTriggeredPoints.has(point.uuid)) .filter(point => { - // Only include roots that actually have triggers pointing FROM them const triggers = extractTriggersFromPoint(point); return triggers.some(t => t.triggeredAsset?.triggeredPoint?.pointUuid); }); // If no root points found but we have triggered points, find the earliest triggers if (rootPoints.length === 0 && allTriggeredPoints.size > 0) { - // This handles cases where we have circular dependencies - // but still want to include the triggered points const minTriggerCount = Math.min( ...Array.from(allTriggeredPoints) .map(uuid => (graph.get(uuid) || []).length) @@ -105,11 +126,18 @@ export function determineExecutionOrder(products: productsSchema): PointsScheme[ // Start processing from root points rootPoints.forEach(root => visit(root.uuid)); - // Convert UUIDs back to points and filter out untriggered points - const triggeredPoints = order - .map(uuid => pointMap.get(uuid)!) - .filter(point => allTriggeredPoints.has(point.uuid) || - rootPoints.some(root => root.uuid === point.uuid)); + // Convert UUIDs back to actions + const triggeredActions = order + .map(uuid => actionMap.get(uuid)) + .filter((action): action is Action => action !== undefined); - return triggeredPoints; + // Combine triggered actions with ALL spawn actions + const allExecutionActions = [...triggeredActions, ...spawnActions]; + + // Remove duplicate actions while preserving order + const uniqueActions = allExecutionActions.filter((action, index, array) => + array.findIndex(a => a.actionUuid === action.actionUuid) === index + ); + + return uniqueActions; } \ No newline at end of file diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx index 869ffa9..21bf97a 100644 --- a/app/src/modules/simulation/simulator/simulator.tsx +++ b/app/src/modules/simulation/simulator/simulator.tsx @@ -21,12 +21,13 @@ function Simulator() { if (!product) return; const executionOrder = determineExecutionOrder([product]); - executionOrder.forEach(point => { - const action = 'actions' in point ? point.actions[0] : point.action; + + executionOrder.forEach(action => { handleAction(action); }); }, [products, isPlaying, isReset, selectedProduct]); + return ( <> diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 5cee999..020b1d3 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -106,6 +106,7 @@ export function useTriggerHandler() { // Handle current action using Event Manager addVehicleToMonitor(vehicle.modelUuid, () => { + setIsVisible(materialId, false); handleAction(action, materialId); }) } @@ -392,7 +393,7 @@ export function useTriggerHandler() { } } } else if (toEvent?.type === 'crane') { - // Transfer to Human + // Transfer to Crane if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) { const material = getMaterialById(materialId); if (material) { @@ -622,7 +623,7 @@ export function useTriggerHandler() { } } } else if (toEvent?.type === 'crane') { - // Vehicle to Human + // Vehicle to Crane if (materialId && trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint && trigger.triggeredAsset.triggeredAction) { const material = getMaterialById(materialId); if (material) { @@ -1801,25 +1802,25 @@ export function useTriggerHandler() { } } else if (fromEvent?.type === 'crane') { if (toEvent?.type === 'transfer') { - // Crane Unit to Transfer + // Crane to Transfer } else if (toEvent?.type === 'vehicle') { - // Crane Unit to Vehicle + // Crane to Vehicle } else if (toEvent?.type === 'machine') { - // Crane Unit to Machine + // Crane to Machine } else if (toEvent?.type === 'roboticArm') { - // Crane Unit to Robotic Arm + // Crane to Robotic Arm } else if (toEvent?.type === 'storageUnit') { - // Crane Unit to Storage Unit + // Crane to Storage Unit } else if (toEvent?.type === 'human') { - // Crane Unit to Human + // Crane to Human } else if (toEvent?.type === 'crane') { - // Crane Unit to Human + // Crane to Human } } diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 4327c92..e9b13c2 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -378,8 +378,10 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) const human = getHumanById(humanId); const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId); - if (human && human.currentAction?.actionUuid !== humanActionId && human.currentLoad < (humanAction?.loadCapacity || 0)) { - addCurrentAction(humanId, humanActionId); + if (human && human.currentLoad < (humanAction?.loadCapacity || 0)) { + if (human.currentAction?.actionUuid !== humanActionId) { + addCurrentAction(humanId, humanActionId); + } setTimeout(() => { unloadLoop(); }, 500) diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts index 68839a7..3198be1 100644 --- a/app/src/store/simulation/useMaterialStore.ts +++ b/app/src/store/simulation/useMaterialStore.ts @@ -80,7 +80,13 @@ export const createMaterialStore = () => { addMaterial: (material) => { let updatedMaterial: MaterialSchema | undefined; set((state) => { + const existingIndex = state.materials.findIndex(m => m.materialId === material.materialId); + if (existingIndex !== -1) { + state.materials.splice(existingIndex, 1); + } + state.materials.push(material); + updatedMaterial = JSON.parse(JSON.stringify(material)); }); return updatedMaterial; }, diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 759267b..1578b5a 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -456,7 +456,6 @@ type ConveyorPoints = NormalConveyor | YJunctionConveyor | CurvedConveyor; // Crane Constraints - type PillarJibCrane = { trolleySpeed: number; hookSpeed: number;