diff --git a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx index d129dd5..4247316 100644 --- a/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx +++ b/app/src/components/layout/sidebarRight/properties/ZoneProperties.tsx @@ -1,11 +1,10 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import RenameInput from "../../../ui/inputs/RenameInput"; import Vector3Input from "../customInput/Vector3Input"; import { useSelectedZoneStore } from "../../../../store/visualization/useZoneStore"; import { useEditPosition, usezonePosition, - useZones, usezoneTarget, } from "../../../../store/builder/store"; import { zoneCameraUpdate } from "../../../../services/visulization/zone/zoneCameraUpdation"; @@ -19,12 +18,11 @@ const ZoneProperties: React.FC = () => { const { selectedZone, setSelectedZone } = useSelectedZoneStore(); const { zonePosition, setZonePosition } = usezonePosition(); const { zoneTarget, setZoneTarget } = usezoneTarget(); - // const { zones, setZones } = useZones(); - const { assetStore, zoneStore } = useSceneContext(); + const { zoneStore } = useSceneContext(); const { zones, setZoneName } = zoneStore() const { projectId } = useParams(); - const { userName, userId, organization, email } = getUserData(); + const { organization } = getUserData(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/assemblyAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/assemblyAction.tsx index cc7be80..ba74c7c 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/assemblyAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/assemblyAction.tsx @@ -13,6 +13,7 @@ interface AssemblyActionProps { swapOptions: string[]; swapDefaultOption: string; onSwapSelect: (value: string) => void; + clearPoints: () => void; } const AssemblyAction: React.FC = ({ @@ -20,6 +21,7 @@ const AssemblyAction: React.FC = ({ swapOptions, swapDefaultOption, onSwapSelect, + clearPoints }) => { return ( <> @@ -37,6 +39,19 @@ const AssemblyAction: React.FC = ({ defaultOption={swapDefaultOption} onSelect={onSwapSelect} /> +
+
+
Reset Points
+ +
+
); }; diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/workerAction.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/workerAction.tsx index 6cda9a0..7d52d70 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/actions/workerAction.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/actions/workerAction.tsx @@ -8,18 +8,29 @@ interface WorkerActionProps { max: number; step: number; defaultValue: string; - disabled?: boolean, + disabled?: boolean; onChange: (value: string) => void; }; + loadCount?: { + value: number; + min: number; + max: number; + step: number; + defaultValue: string, + disabled: false, + onChange: (value: number) => void; + }; clearPoints: () => void; } const WorkerAction: React.FC = ({ loadCapacity, + loadCount, clearPoints, }) => { return ( - <> +
+ {/* Load Capacity Input */} = ({ onClick={() => { }} onChange={loadCapacity.onChange} /> + + {/* Load Count Input */} + {loadCount && ( + { }} + onChange={(value) => loadCount.onChange(parseInt(value))} + /> + )} + + {/* Clear Points Button */}
-
Reset
+
Reset Points
- +
); }; -export default WorkerAction; +export default WorkerAction; \ No newline at end of file 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 3c1a2e4..990d046 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx @@ -18,10 +18,17 @@ import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function ConveyorMechanics() { const [activeOption, setActiveOption] = useState<"default" | "spawn" | "swap" | "delay" | "despawn">("default"); + const [speed, setSpeed] = useState("0.5"); + const [actionName, setActionName] = useState("Action Name"); + const [material, setMaterial] = useState("Default material"); + const [spawnCount, setSpawnCount] = useState("1"); + const [spawnInterval, setSpawnInterval] = useState("1"); + const [delay, setDelay] = useState("0"); const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); - const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore(); + const { getPointByUuid, updateEvent, updateAction, getEventByModelUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); @@ -36,9 +43,21 @@ function ConveyorMechanics() { selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint ) as ConveyorPointSchema | undefined; - if (point && "action" in point) { + + const event = getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData?.data.modelUuid + ) as ConveyorEventSchema | undefined; + + if (point && "action" in point && event) { setSelectedPointData(point); - setActiveOption(point.action.actionType as | "default" | "spawn" | "swap" | "delay" | "despawn"); + setActiveOption(point.action.actionType); + setActionName(point.action.actionName); + setSpeed(event.speed?.toString() || "0.5"); + setMaterial(point.action.material || "Default material"); + setSpawnCount(point.action.spawnCount?.toString() || "1"); + setSpawnInterval(point.action.spawnInterval?.toString() || "1"); + setDelay(point.action.delay?.toString() || "0"); setSelectedAction(point.action.actionUuid, point.action.actionName); } } else { @@ -53,19 +72,25 @@ function ConveyorMechanics() { eventData: EventsSchema ) => { upsertProductOrEventApi({ - productName: productName, - productUuid: productUuid, - projectId: projectId, + productName, + productUuid, + projectId, eventDatas: eventData, - versionId: selectedVersion?.versionId || '', - }) - } + versionId: selectedVersion?.versionId || "", + }); + }; const handleSpeedChange = (value: string) => { if (!selectedEventData) return; - const event = updateEvent(selectedProduct.productUuid, selectedEventData.data.modelUuid, { - speed: parseFloat(value), - }); + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + const event = updateEvent( + selectedProduct.productUuid, + selectedEventData.data.modelUuid, + { speed: numericValue } + ); if (event) { updateBackend( @@ -75,16 +100,20 @@ function ConveyorMechanics() { event ); } + setSpeed(value); }; const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; - const validOption = option as | "default" | "spawn" | "swap" | "delay" | "despawn"; + if (!selectedPointData) return; + + const validOption = option as "default" | "spawn" | "swap" | "delay" | "despawn"; setActiveOption(validOption); - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - actionType: validOption, - }); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { actionType: validOption } + ); if (event) { updateBackend( @@ -97,8 +126,14 @@ function ConveyorMechanics() { }; const handleRenameAction = (newName: string) => { - if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName }); + if (!selectedPointData) return; + + setActionName(newName); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { actionName: newName } + ); if (event) { updateBackend( @@ -111,10 +146,17 @@ function ConveyorMechanics() { }; const handleSpawnCountChange = (value: string) => { - if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - spawnCount: parseFloat(value), - }); + if (!selectedPointData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setSpawnCount(value); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { spawnCount: numericValue } + ); if (event) { updateBackend( @@ -127,10 +169,17 @@ function ConveyorMechanics() { }; const handleSpawnIntervalChange = (value: string) => { - if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - spawnInterval: parseFloat(value), - }); + if (!selectedPointData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setSpawnInterval(value); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { spawnInterval: numericValue } + ); if (event) { updateBackend( @@ -142,9 +191,15 @@ function ConveyorMechanics() { } }; - const handleMaterialSelect = (material: string) => { - if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { material }); + const handleMaterialSelect = (selectedMaterial: string) => { + if (!selectedPointData) return; + + setMaterial(selectedMaterial); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { material: selectedMaterial } + ); if (event) { updateBackend( @@ -157,10 +212,17 @@ function ConveyorMechanics() { }; const handleDelayChange = (value: string) => { - if (!selectedEventData || !selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - delay: parseFloat(value), - }); + if (!selectedPointData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setDelay(value); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { delay: numericValue } + ); if (event) { updateBackend( @@ -177,31 +239,6 @@ function ConveyorMechanics() { options: ["default", "spawn", "swap", "delay", "despawn"], }; - // Get current values from store - const currentSpeed = (getEventByModelUuid( - selectedProduct.productUuid, selectedEventData?.data.modelUuid || "" - ) as ConveyorEventSchema | undefined)?.speed?.toString() || "0.5"; - - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; - - const currentMaterial = selectedPointData - ? selectedPointData.action.material - : "Default material"; - - const currentSpawnCount = selectedPointData - ? selectedPointData.action.spawnCount?.toString() || "1" - : "1"; - - const currentSpawnInterval = selectedPointData - ? selectedPointData.action.spawnInterval?.toString() || "1" - : "1"; - - const currentDelay = selectedPointData - ? selectedPointData.action.delay?.toString() || "0" - : "0"; - return ( <>
@@ -209,10 +246,10 @@ function ConveyorMechanics() {
{ }} @@ -222,24 +259,18 @@ function ConveyorMechanics() {
- +
@@ -248,11 +279,11 @@ function ConveyorMechanics() { )} {activeOption === "despawn" && } {activeOption === "delay" && ( ("worker"); const [speed, setSpeed] = useState("0.5"); + const [loadCount, setLoadCount] = useState(0); const [loadCapacity, setLoadCapacity] = useState("1"); const [processTime, setProcessTime] = useState(10); const [swappedMaterial, setSwappedMaterial] = useState("Default material"); @@ -24,7 +27,7 @@ function HumanMechanics() { const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); - const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid } = productStore(); + const { getPointByUuid, updateEvent, updateAction, addAction, removeAction, getEventByModelUuid, getActionByUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); @@ -40,19 +43,21 @@ function HumanMechanics() { selectedEventData.selectedPoint ) as HumanPointSchema | undefined; - if (point?.action) { + if (point?.actions?.length) { setSelectedPointData(point); - setCurrentAction(point.action); - setSelectedAction(point.action.actionUuid, point.action.actionName); + const firstAction = point.actions[0]; + setCurrentAction(firstAction); setSpeed(( getEventByModelUuid( selectedProduct.productUuid, selectedEventData?.data.modelUuid || "" ) as HumanEventSchema | undefined )?.speed?.toString() || "1"); - setLoadCapacity(point.action.loadCapacity.toString()); - setProcessTime(point.action.processTime || 10); - setSwappedMaterial(point.action.swapMaterial || "Default material"); + setLoadCapacity(firstAction.loadCapacity.toString()); + setActiveOption(firstAction.actionType); + setLoadCount(firstAction.loadCount || 0); + setProcessTime(firstAction.processTime || 10); + setSwappedMaterial(firstAction.swapMaterial || "Default material"); } } else { clearSelectedAction(); @@ -60,26 +65,36 @@ function HumanMechanics() { }, [selectedEventData, selectedProduct]); useEffect(() => { - if (selectedEventData && selectedProduct.productUuid) { + if (selectedEventData && selectedEventData.data.type === "human") { const point = getPointByUuid( selectedProduct.productUuid, selectedEventData.data.modelUuid, selectedEventData.selectedPoint ) as HumanPointSchema | undefined; - if (point?.action) { - setSelectedPointData(point); - setCurrentAction(point.action); - setActiveOption(point.action.actionType); - setSelectedAction(point.action.actionUuid, point.action.actionName); + const actionUuid = selectedAction.actionId || point?.actions[0].actionUuid || ''; + + const newCurrentAction = getActionByUuid(selectedProduct.productUuid, actionUuid); + + if (newCurrentAction && (newCurrentAction.actionType === 'assembly' || newCurrentAction?.actionType === 'worker')) { + if (!selectedAction.actionId) { + setSelectedAction(newCurrentAction.actionUuid, newCurrentAction.actionName); + } + setCurrentAction(newCurrentAction); + setActiveOption(newCurrentAction.actionType); + setLoadCapacity(newCurrentAction.loadCapacity.toString()); + setLoadCount(newCurrentAction.loadCount || 0); + + if (newCurrentAction.actionType === 'assembly') { + setProcessTime(newCurrentAction.processTime || 10); + setSwappedMaterial(newCurrentAction.swapMaterial || "Default material"); + } + } else { + clearSelectedAction(); + setCurrentAction(undefined); } - } else { - clearSelectedAction(); - setCurrentAction(undefined); - setSpeed("0.5"); - setLoadCapacity("1"); } - }, [selectedEventData, selectedProduct, selectedAction]); + }, [selectedAction, selectedProduct, selectedEventData]); const updateBackend = ( productName: string, @@ -99,8 +114,9 @@ function HumanMechanics() { const handleSelectActionType = (actionType: string) => { if (!selectedAction.actionId || !currentAction || !selectedPointData) return; - const updatedAction = { ...currentAction, actionType: actionType as "worker" }; - const updatedPoint = { ...selectedPointData, action: updatedAction }; + const updatedAction = { ...currentAction, actionType: actionType as "worker" | "assembly" }; + const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; const event = updateAction( selectedProduct.productUuid, @@ -143,10 +159,9 @@ function HumanMechanics() { const handleLoadCapacityChange = (value: string) => { if (!currentAction || !selectedPointData || !selectedAction.actionId) return; - const updatedAction = { ...currentAction }; - updatedAction.loadCapacity = parseInt(value) - - const updatedPoint = { ...selectedPointData, action: updatedAction }; + const updatedAction = { ...currentAction, loadCapacity: parseInt(value) }; + const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; const event = updateAction( selectedProduct.productUuid, @@ -163,13 +178,34 @@ function HumanMechanics() { setLoadCapacity(value); }; + const handleLoadCountChange = (value: number) => { + if (!currentAction || !selectedPointData || !selectedAction.actionId) return; + + const updatedAction = { ...currentAction, loadCount: value }; + 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(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); + } + + setCurrentAction(updatedAction); + setSelectedPointData(updatedPoint); + setLoadCount(value); + }; + const handleProcessTimeChange = (value: number) => { if (!currentAction || !selectedPointData || !selectedAction.actionId) return; - const updatedAction = { ...currentAction }; - updatedAction.processTime = value - - const updatedPoint = { ...selectedPointData, action: updatedAction }; + const updatedAction = { ...currentAction, processTime: value }; + const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; const event = updateAction( selectedProduct.productUuid, @@ -189,10 +225,9 @@ function HumanMechanics() { const handleMaterialChange = (value: string) => { if (!currentAction || !selectedPointData || !selectedAction.actionId) return; - const updatedAction = { ...currentAction }; - updatedAction.swapMaterial = value - - const updatedPoint = { ...selectedPointData, action: updatedAction }; + const updatedAction = { ...currentAction, swapMaterial: value }; + const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; const event = updateAction( selectedProduct.productUuid, @@ -212,11 +247,17 @@ function HumanMechanics() { const handleClearPoints = () => { if (!currentAction || !selectedPointData || !selectedAction.actionId) return; - const updatedAction = { ...currentAction }; - delete updatedAction.pickUpPoint; - delete updatedAction.dropPoint; + const updatedAction: HumanAction = JSON.parse(JSON.stringify(currentAction)); - const updatedPoint = { ...selectedPointData, action: updatedAction }; + if (updatedAction.actionType === 'assembly') { + updatedAction.assemblyPoint = { position: null, rotation: null, } + } else { + updatedAction.pickUpPoint = { position: null, rotation: null, }; + updatedAction.dropPoint = { position: null, rotation: null, } + } + + const updatedActions = selectedPointData.actions.map(action => action.actionUuid === updatedAction.actionUuid ? updatedAction : action); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; const event = updateAction( selectedProduct.productUuid, @@ -237,12 +278,17 @@ function HumanMechanics() { const newAction: HumanAction = { actionUuid: MathUtils.generateUUID(), - actionName: `Action`, + actionName: `Action ${selectedPointData.actions.length + 1}`, actionType: "worker", + loadCount: 1, loadCapacity: 1, + processTime: 10, triggers: [], }; + const updatedActions = [...(selectedPointData.actions || []), newAction]; + const updatedPoint = { ...selectedPointData, actions: updatedActions }; + const event = addAction( selectedProduct.productUuid, selectedEventData.data.modelUuid, @@ -254,27 +300,39 @@ function HumanMechanics() { updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); } - const updatedPoint = { ...selectedPointData, action: newAction }; setSelectedPointData(updatedPoint); setSelectedAction(newAction.actionUuid, newAction.actionName); }; const handleDeleteAction = () => { - if (!selectedPointData) return; + if (!selectedPointData || !selectedAction.actionId) return; + + const updatedActions = selectedPointData.actions.filter(action => action.actionUuid !== selectedAction.actionId); + const updatedPoint = { ...selectedPointData, actions: updatedActions }; const event = removeAction( selectedProduct.productUuid, - selectedPointData.action.actionUuid + selectedAction.actionId ); if (event) { updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); } - const updatedPoint = { ...selectedPointData, action: undefined as any }; setSelectedPointData(updatedPoint); - clearSelectedAction(); - setCurrentAction(undefined); + + 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 HumanAction); + } + } else { + clearSelectedAction(); + setCurrentAction(undefined); + } }; return ( @@ -299,7 +357,7 @@ function HumanMechanics() {
@@ -315,7 +373,7 @@ function HumanMechanics() { defaultOption={activeOption} options={["worker", "assembly"]} onSelect={handleSelectActionType} - disabled={true} + disabled={false} />
{currentAction.actionType === 'worker' && @@ -323,12 +381,21 @@ function HumanMechanics() { loadCapacity={{ value: loadCapacity, min: 1, - max: 5, + max: 20, step: 1, - defaultValue: "10", + defaultValue: "1", disabled: true, onChange: handleLoadCapacityChange, }} + loadCount={{ + value: loadCount, + min: 0, + max: 20, + step: 1, + defaultValue: "1", + disabled: false, + onChange: handleLoadCountChange, + }} clearPoints={handleClearPoints} /> } @@ -343,6 +410,7 @@ function HumanMechanics() { swapOptions={["Default material", "Material 1", "Material 2", "Material 3"]} swapDefaultOption={swappedMaterial} onSwapSelect={handleMaterialChange} + clearPoints={handleClearPoints} /> }
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx index f714d69..22b3277 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/machineMechanics.tsx @@ -12,8 +12,12 @@ import { useVersionContext } from "../../../../../../modules/builder/version/ver import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function MachineMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "process">("default"); + const [activeOption, setActiveOption] = useState<"process">("process"); + const [actionName, setActionName] = useState("Action Name"); + const [processTime, setProcessTime] = useState("1"); + const [material, setMaterial] = useState("Default material"); const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); const { getPointByUuid, updateAction } = productStore(); @@ -31,9 +35,13 @@ function MachineMechanics() { selectedEventData?.data.modelUuid, selectedEventData?.selectedPoint ) as MachinePointSchema | undefined; + if (point && "action" in point) { setSelectedPointData(point); setActiveOption(point.action.actionType as "process"); + setActionName(point.action.actionName); + setProcessTime(point.action.processTime?.toString() || "1"); + setMaterial(point.action.swapMaterial || "Default material"); setSelectedAction(point.action.actionUuid, point.action.actionName); } } else { @@ -48,22 +56,25 @@ function MachineMechanics() { eventData: EventsSchema ) => { upsertProductOrEventApi({ - productName: productName, - productUuid: productUuid, - projectId: projectId, + productName, + productUuid, + projectId, eventDatas: eventData, - versionId: selectedVersion?.versionId || '', - }) - } + versionId: selectedVersion?.versionId || "", + }); + }; const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; + if (!selectedPointData) return; + const validOption = option as "process"; setActiveOption(validOption); - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - actionType: validOption, - }); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { actionType: validOption } + ); if (event) { updateBackend( @@ -77,7 +88,13 @@ function MachineMechanics() { const handleRenameAction = (newName: string) => { if (!selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { actionName: newName }); + + setActionName(newName); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { actionName: newName } + ); if (event) { updateBackend( @@ -91,9 +108,16 @@ function MachineMechanics() { const handleProcessTimeChange = (value: string) => { if (!selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - processTime: parseFloat(value), - }); + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setProcessTime(value); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { processTime: numericValue } + ); if (event) { updateBackend( @@ -105,11 +129,15 @@ function MachineMechanics() { } }; - const handleMaterialSelect = (material: string) => { + const handleMaterialSelect = (selectedMaterial: string) => { if (!selectedPointData) return; - const event = updateAction(selectedProduct.productUuid, selectedPointData.action.actionUuid, { - swapMaterial: material, - }); + + setMaterial(selectedMaterial); + const event = updateAction( + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { swapMaterial: selectedMaterial } + ); if (event) { updateBackend( @@ -121,19 +149,6 @@ function MachineMechanics() { } }; - // Get current values from store - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; - - const currentProcessTime = selectedPointData - ? selectedPointData.action.processTime.toString() - : "1"; - - const currentMaterial = selectedPointData - ? selectedPointData.action.swapMaterial - : "Default material"; - const availableActions = { defaultOption: "process", options: ["process"], @@ -146,28 +161,26 @@ function MachineMechanics() {
- +
{activeOption === "process" && ( )} @@ -182,4 +195,4 @@ function MachineMechanics() { ); } -export default MachineMechanics; +export default MachineMechanics; \ No newline at end of file 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 d70f6ac..0c7c6e3 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/roboticArmMechanics.tsx @@ -14,11 +14,13 @@ import { useVersionContext } from "../../../../../../modules/builder/version/ver import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; function RoboticArmMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "pickAndPlace">("default"); + const [activeOption, setActiveOption] = useState<"pickAndPlace">("pickAndPlace"); + const [speed, setSpeed] = useState("0.5"); const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); - const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction, } = productStore(); + const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); @@ -33,16 +35,20 @@ function RoboticArmMechanics() { selectedEventData.data.modelUuid, selectedEventData.selectedPoint ) as RoboticArmPointSchema | undefined; + if (point?.actions) { setSelectedPointData(point); + setSpeed( + (getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid + ) as RoboticArmEventSchema | undefined)?.speed?.toString() || "0.5" + ); + if (point.actions.length > 0) { - setActiveOption( - point.actions[0].actionType as "default" | "pickAndPlace" - ); - setSelectedAction( - point.actions[0].actionUuid, - point.actions[0].actionName - ); + const firstAction = point.actions[0]; + setActiveOption(firstAction.actionType); + setSelectedAction(firstAction.actionUuid, firstAction.actionName); } } } else { @@ -57,33 +63,33 @@ function RoboticArmMechanics() { eventData: EventsSchema ) => { upsertProductOrEventApi({ - productName: productName, - productUuid: productUuid, - projectId: projectId, + productName, + productUuid, + projectId, eventDatas: eventData, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", }); }; const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId) return; + if (!selectedAction.actionId || !selectedPointData) return; + const event = updateAction( selectedProduct.productUuid, selectedAction.actionId, { actionName: newName } ); - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - setSelectedPointData({ - ...selectedPointData, - actions: updatedActions, - }); - } + const updatedActions = selectedPointData.actions.map(action => + action.actionUuid === selectedAction.actionId + ? { ...action, actionName: newName } + : action + ); + + setSelectedPointData({ + ...selectedPointData, + actions: updatedActions, + }); if (event) { updateBackend( @@ -97,10 +103,15 @@ function RoboticArmMechanics() { const handleSpeedChange = (value: string) => { if (!selectedEventData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setSpeed(value); const event = updateEvent( selectedProduct.productUuid, selectedEventData.data.modelUuid, - { speed: parseFloat(value), } + { speed: numericValue } ); if (event) { @@ -112,6 +123,7 @@ function RoboticArmMechanics() { ); } }; + const handleClearPoints = () => { if (!selectedAction.actionId || !selectedPointData) return; @@ -166,15 +178,20 @@ function RoboticArmMechanics() { ); } - const updatedPoint = { ...selectedPointData, actions: [...selectedPointData.actions, newAction], }; - setSelectedPointData(updatedPoint); + setSelectedPointData({ + ...selectedPointData, + actions: [...selectedPointData.actions, newAction], + }); setSelectedAction(newAction.actionUuid, newAction.actionName); }; const handleDeleteAction = (actionUuid: string) => { if (!selectedPointData) return; - const event = removeAction(selectedProduct.productUuid, actionUuid); + const event = removeAction( + selectedProduct.productUuid, + actionUuid + ); if (event) { updateBackend( @@ -185,14 +202,13 @@ function RoboticArmMechanics() { ); } - const index = selectedPointData.actions.findIndex((a) => a.actionUuid === actionUuid); - const newActions = selectedPointData.actions.filter((a) => a.actionUuid !== actionUuid); + const index = selectedPointData.actions.findIndex(a => a.actionUuid === actionUuid); + const newActions = selectedPointData.actions.filter(a => a.actionUuid !== actionUuid); - const updatedPoint = { + setSelectedPointData({ ...selectedPointData, actions: newActions, - }; - setSelectedPointData(updatedPoint); + }); if (selectedAction.actionId === actionUuid) { const nextAction = newActions[index] || newActions[index - 1]; @@ -209,16 +225,7 @@ function RoboticArmMechanics() { options: ["pickAndPlace"], }; - const currentSpeed = (getEventByModelUuid(selectedProduct.productUuid, selectedEventData?.data.modelUuid || "") as RoboticArmEventSchema | undefined)?.speed?.toString() || "0.5"; - - const currentAction = selectedPointData?.actions.find((a) => a.actionUuid === selectedAction.actionId); - - const currentPickPoint = currentAction?.process.startPoint - ? `${currentAction.process.startPoint[0]},${currentAction.process.startPoint[1]},${currentAction.process.startPoint[2]}` - : ""; - const currentPlacePoint = currentAction?.process.endPoint - ? `${currentAction.process.endPoint[0]},${currentAction.process.endPoint[1]},${currentAction.process.endPoint[2]}` - : ""; + const currentAction = selectedPointData?.actions.find(a => a.actionUuid === selectedAction.actionId); return ( <> @@ -227,10 +234,10 @@ function RoboticArmMechanics() {
{ }} @@ -252,7 +259,7 @@ function RoboticArmMechanics() {
@@ -277,4 +284,4 @@ function RoboticArmMechanics() { ); } -export default RoboticArmMechanics; +export default RoboticArmMechanics; \ No newline at end of file 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 b29feb5..796dbc5 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/storageMechanics.tsx @@ -192,7 +192,7 @@ function StorageMechanics() {
diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx index 57efd87..fada871 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/vehicleMechanics.tsx @@ -3,10 +3,7 @@ import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; -import { - useSelectedAction, - useSelectedEventData, -} from "../../../../../../store/simulation/useSimulationStore"; +import { useSelectedAction, useSelectedEventData } from "../../../../../../store/simulation/useSimulationStore"; import TravelAction from "../actions/TravelAction"; import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; @@ -17,18 +14,23 @@ import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; import { useSelectedPath } from "../../../../../../store/builder/store"; function VehicleMechanics() { - const [activeOption, setActiveOption] = useState<"default" | "travel">("default"); + const [activeOption, setActiveOption] = useState<"travel">("travel"); + const [speed, setSpeed] = useState("0.5"); + const [actionName, setActionName] = useState("Action Name"); + const [loadCapacity, setLoadCapacity] = useState("1"); + const [unloadDuration, setUnloadDuration] = useState("1"); const [selectedPointData, setSelectedPointData] = useState(); + const { selectedEventData } = useSelectedEventData(); const { productStore } = useSceneContext(); - const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore(); + const { getPointByUuid, updateEvent, updateAction, getEventByModelUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const { setSelectedAction, clearSelectedAction } = useSelectedAction(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { projectId } = useParams(); - const { selectedPath, setSelectedPath } = useSelectedPath(); + const { setSelectedPath } = useSelectedPath(); useEffect(() => { if (selectedEventData && selectedEventData.data.type === "vehicle") { @@ -41,6 +43,15 @@ function VehicleMechanics() { if (point) { setSelectedPointData(point); setActiveOption(point.action.actionType as "travel"); + setActionName(point.action.actionName); + setSpeed( + (getEventByModelUuid( + selectedProduct.productUuid, + selectedEventData.data.modelUuid + ) as VehicleEventSchema | undefined)?.speed?.toString() || "0.5" + ); + setLoadCapacity(point.action.loadCapacity?.toString() || "1"); + setUnloadDuration(point.action.unLoadDuration?.toString() || "1"); setSelectedAction(point.action.actionUuid, point.action.actionName); } } else { @@ -55,22 +66,25 @@ function VehicleMechanics() { eventData: EventsSchema ) => { upsertProductOrEventApi({ - productName: productName, - productUuid: productUuid, - projectId: projectId, + productName, + productUuid, + projectId, eventDatas: eventData, - versionId: selectedVersion?.versionId || '', + versionId: selectedVersion?.versionId || "", }); }; const handleSpeedChange = (value: string) => { if (!selectedEventData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setSpeed(value); const event = updateEvent( selectedProduct.productUuid, selectedEventData.data.modelUuid, - { - speed: parseFloat(value), - } + { speed: numericValue } ); if (event) { @@ -84,16 +98,15 @@ function VehicleMechanics() { }; const handleActionTypeChange = (option: string) => { - if (!selectedEventData || !selectedPointData) return; + if (!selectedPointData) return; + const validOption = option as "travel"; setActiveOption(validOption); const event = updateAction( selectedProduct.productUuid, selectedPointData.action.actionUuid, - { - actionType: validOption, - } + { actionType: validOption } ); if (event) { @@ -108,6 +121,8 @@ function VehicleMechanics() { const handleRenameAction = (newName: string) => { if (!selectedPointData) return; + + setActionName(newName); const event = updateAction( selectedProduct.productUuid, selectedPointData.action.actionUuid, @@ -126,12 +141,15 @@ function VehicleMechanics() { const handleLoadCapacityChange = (value: string) => { if (!selectedPointData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setLoadCapacity(value); const event = updateAction( selectedProduct.productUuid, selectedPointData.action.actionUuid, - { - loadCapacity: parseFloat(value), - } + { loadCapacity: numericValue } ); if (event) { @@ -146,12 +164,15 @@ function VehicleMechanics() { const handleUnloadDurationChange = (value: string) => { if (!selectedPointData) return; + + const numericValue = parseFloat(value); + if (isNaN(numericValue)) return; + + setUnloadDuration(value); const event = updateAction( selectedProduct.productUuid, selectedPointData.action.actionUuid, - { - unLoadDuration: parseFloat(value), - } + { unLoadDuration: numericValue } ); if (event) { @@ -164,46 +185,18 @@ function VehicleMechanics() { } }; - const handlePickPointChange = (value: string) => { + const handleClearPoints = () => { if (!selectedPointData) return; - }; - - const handleUnloadPointChange = (value: string) => { - if (!selectedPointData) return; - }; - - // Get current values from store - - const currentSpeed = - ( - getEventByModelUuid( - selectedProduct.productUuid, - selectedEventData?.data.modelUuid || "" - ) as VehicleEventSchema | undefined - )?.speed?.toString() || "0.5"; - - const currentActionName = selectedPointData - ? selectedPointData.action.actionName - : "Action Name"; - - const currentLoadCapacity = selectedPointData - ? selectedPointData.action.loadCapacity.toString() - : "1"; - - const currentUnloadDuration = selectedPointData - ? selectedPointData.action.unLoadDuration.toString() - : "1"; - - function handleClearPoints() { - - if (!selectedEventData || !selectedPointData?.action.actionUuid) return; const event = updateAction( - selectedProduct.productUuid, selectedPointData.action.actionUuid, { - pickUpPoint: null, - unLoadPoint: null, - steeringAngle: 0, - }) + selectedProduct.productUuid, + selectedPointData.action.actionUuid, + { + pickUpPoint: null, + unLoadPoint: null, + steeringAngle: 0, + } + ); if (event) { updateBackend( @@ -213,7 +206,7 @@ function VehicleMechanics() { event ); } - } + }; const availableActions = { defaultOption: "travel", @@ -229,10 +222,10 @@ function VehicleMechanics() {
{ }} @@ -246,13 +239,13 @@ function VehicleMechanics() {
@@ -260,14 +253,14 @@ function VehicleMechanics() { {activeOption === "travel" && (
-
- - +
+ +
- ) - } + )} ); } -export default VehicleMechanics; +export default VehicleMechanics; \ No newline at end of file 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 eb4b0ac..0697c7b 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/trigger/Trigger.tsx @@ -65,8 +65,11 @@ const Trigger = ({ selectedPointData, type }: TriggerProps) => { const action = getActionByUuid(selectedProduct.productUuid, currentAction); const actionTriggers = action?.triggers || []; setTriggers(actionTriggers); + if (actionTriggers.length === 0) { + setSelectedTrigger(undefined); + } setSelectedTrigger(actionTriggers[0]); - }, [currentAction, selectedProduct]); + }, [currentAction, selectedProduct, selectedTrigger, selectedPointData]); const triggeredModel = useMemo(() => { if (!selectedProduct || !selectedTrigger?.triggeredAsset?.triggeredModel?.modelUuid) diff --git a/app/src/components/ui/Tools.tsx b/app/src/components/ui/Tools.tsx index 1aeb646..e834f28 100644 --- a/app/src/components/ui/Tools.tsx +++ b/app/src/components/ui/Tools.tsx @@ -22,7 +22,6 @@ import { useSelectedZoneStore } from "../../store/visualization/useZoneStore"; import { useActiveTool, useAddAction, - useRefTextUpdate, useSelectedWallItem, useSocketStore, useToggleView, @@ -75,7 +74,6 @@ const Tools: React.FC = () => { const { setActiveSubTool, activeSubTool } = useActiveSubTool(); const { setSelectedWallItem } = useSelectedWallItem(); - const { setRefTextUpdate } = useRefTextUpdate(); const { setToggleUI } = useToggleStore(); const { setToggleView, toggleView } = useToggleView(); @@ -131,7 +129,6 @@ const Tools: React.FC = () => { const resetTools = () => { setToolMode(null); setAddAction(null); - setRefTextUpdate((prev) => prev - 1); }; const updateToolBehavior = (tool: string, is2D: boolean) => { @@ -406,7 +403,6 @@ const useStoreHooks = () => { ...useActiveTool(), ...useToolMode(), ...useAddAction(), - ...useRefTextUpdate(), }; }; diff --git a/app/src/components/ui/inputs/InputWithDropDown.tsx b/app/src/components/ui/inputs/InputWithDropDown.tsx index 61fbaf4..486faea 100644 --- a/app/src/components/ui/inputs/InputWithDropDown.tsx +++ b/app/src/components/ui/inputs/InputWithDropDown.tsx @@ -2,93 +2,89 @@ import React, { useState } from "react"; import RenameInput from "./RenameInput"; type InputWithDropDownProps = { - label: string; - value: string; - min?: number; - max?: number; - step?: number; - defaultValue?: string; - disabled?: boolean; - options?: string[]; // Array of dropdown options - activeOption?: string; // The currently active dropdown option - onClick?: () => void; - onChange: (newValue: string) => void; - editableLabel?: boolean; - placeholder?: string; // New placeholder prop + label: string; + value: string; + min?: number; + max?: number; + step?: number; + defaultValue?: string; + disabled?: boolean; + options?: string[]; + activeOption?: string; + onClick?: () => void; + onChange: (newValue: string) => void; + editableLabel?: boolean; + placeholder?: string; }; const InputWithDropDown: React.FC = ({ - label, - value, - min, - max, - step, - defaultValue, - disabled = false, - options, - activeOption, - onClick, - onChange, - editableLabel = false, - placeholder = "Inherit", // Default empty placeholder + label, + value, + min, + max, + step, + defaultValue, + disabled = false, + options, + activeOption, + onClick, + onChange, + editableLabel = false, + placeholder = "Inherit", }) => { - const separatedWords = label - .split(/(?=[A-Z])/) - .map((word) => word.trim()) - .toString(); + const [openDropdown, setOpenDropdown] = useState(false); - const [openDropdown, setOpenDropdown] = useState(false); + const separatedWords = label + .split(/(?=[A-Z])/) + .map((word) => word.trim()) + .join(" "); - return ( -
- {editableLabel ? ( - - ) : ( - - )} -
- { - onChange(e.target.value); - }} - placeholder={placeholder} // Added placeholder prop - /> - - {activeOption && ( -
{ - setOpenDropdown(true); - }} - > -
{activeOption}
- {options && openDropdown && ( -
- {options.map((option, index) => ( -
- {option} -
- ))} -
+ return ( +
+ {editableLabel ? ( + + ) : ( + )} -
- )} -
-
- ); + +
+ onChange(e.target.value)} + placeholder={placeholder} + /> + + {activeOption && ( +
setOpenDropdown((prev) => !prev)} + > +
{activeOption}
+ {options && openDropdown && ( +
+ {options.map((option, index) => ( +
+ {option} +
+ ))} +
+ )} +
+ )} +
+
+ ); }; -export default InputWithDropDown; \ No newline at end of file +export default InputWithDropDown; diff --git a/app/src/components/ui/list/DropDownList.tsx b/app/src/components/ui/list/DropDownList.tsx index d75387d..b158c80 100644 --- a/app/src/components/ui/list/DropDownList.tsx +++ b/app/src/components/ui/list/DropDownList.tsx @@ -2,7 +2,6 @@ import React, { useEffect, useState } from "react"; import List from "./List"; import { AddIcon, ArrowIcon, FocusIcon } from "../../icons/ExportCommonIcons"; import KebabMenuListMultiSelect from "./KebebMenuListMultiSelect"; -import { useZones } from "../../../store/builder/store"; import { useSceneContext } from "../../../modules/scene/sceneContext"; interface DropDownListProps { @@ -44,14 +43,12 @@ const DropDownList: React.FC = ({ remove, }) => { const [isOpen, setIsOpen] = useState(defaultOpen); - // const { zones } = useZones(); const handleToggle = () => { setIsOpen((prev) => !prev); // Toggle the state }; const [zoneDataList, setZoneDataList] = useState([]); - // const { assetStore } = useSceneContext(); const { assetStore, zoneStore } = useSceneContext(); const { assets } = assetStore(); const { zones } = zoneStore() diff --git a/app/src/components/ui/list/List.tsx b/app/src/components/ui/list/List.tsx index dac4b40..fc0f5ec 100644 --- a/app/src/components/ui/list/List.tsx +++ b/app/src/components/ui/list/List.tsx @@ -14,7 +14,6 @@ import { } from "../../icons/ExportCommonIcons"; import { useZoneAssetId, - useZones, } from "../../../store/builder/store"; import { zoneCameraUpdate } from "../../../services/visulization/zone/zoneCameraUpdation"; import { setAssetsApi } from "../../../services/factoryBuilder/asset/floorAsset/setAssetsApi"; diff --git a/app/src/components/ui/simulation/simulationPlayer.tsx b/app/src/components/ui/simulation/simulationPlayer.tsx index 5fc8790..f7586f8 100644 --- a/app/src/components/ui/simulation/simulationPlayer.tsx +++ b/app/src/components/ui/simulation/simulationPlayer.tsx @@ -34,7 +34,7 @@ import { useComparisonProduct } from "../../../store/simulation/useSimulationSto import InputToggle from "../inputs/InputToggle"; const SimulationPlayer: React.FC = () => { - const MAX_SPEED = 4; // Maximum speed + const MAX_SPEED = 8; // Maximum speed const isDragging = useRef(false); const sliderRef = useRef(null); diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index f51edf1..0210e54 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -256,14 +256,17 @@ 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: "worker", - loadCapacity: 1, - triggers: [] - } - + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "worker", + loadCount: 1, + loadCapacity: 1, + processTime: 10, + triggers: [] + } + ] } } addEvent(humanEvent); diff --git a/app/src/modules/builder/asset/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts index 8a09bb7..74d9100 100644 --- a/app/src/modules/builder/asset/functions/addAssetModel.ts +++ b/app/src/modules/builder/asset/functions/addAssetModel.ts @@ -373,14 +373,17 @@ 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: "worker", - loadCapacity: 1, - triggers: [] - } - + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "worker", + loadCount: 1, + loadCapacity: 1, + processTime: 10, + triggers: [] + } + ] } } addEvent(humanEvent); diff --git a/app/src/modules/builder/builder.tsx b/app/src/modules/builder/builder.tsx index a98805b..ab9434b 100644 --- a/app/src/modules/builder/builder.tsx +++ b/app/src/modules/builder/builder.tsx @@ -15,7 +15,6 @@ import { useToolMode, useRenderDistance, useLimitDistance, - useLoadingProgress, } from "../../store/builder/store"; ////////// 3D Function Imports ////////// @@ -57,7 +56,6 @@ export default function Builder() { const { projectId } = useParams(); const { setHoveredPoint, setHoveredLine } = useBuilderStore(); const { userId, organization } = getUserData(); - const { loadingProgress } = useLoadingProgress(); useEffect(() => { if (!toggleView) { @@ -117,7 +115,8 @@ export default function Builder() { - {loadingProgress == 0 && } + + diff --git a/app/src/modules/builder/dfx/LoadBlueprint.tsx b/app/src/modules/builder/dfx/LoadBlueprint.tsx index 5763d26..216f2fe 100644 --- a/app/src/modules/builder/dfx/LoadBlueprint.tsx +++ b/app/src/modules/builder/dfx/LoadBlueprint.tsx @@ -1,9 +1,8 @@ import { useEffect, useRef } from 'react'; -import { useActiveLayer, useDfxUpload, useSocketStore, useToggleView, useUpdateScene } from '../../../store/builder/store'; +import { useActiveLayer, useDfxUpload, useSocketStore, useToggleView } from '../../../store/builder/store'; import { LineBasicMaterial, Line } from 'three'; import { TransformControls } from '@react-three/drei'; import { getWallPointsFromBlueprint } from './functions/getWallPointsFromBlueprint'; -import * as Types from '../../../types/world/worldTypes'; import { useParams } from 'react-router-dom'; import { getUserData } from '../../../functions/getUserData'; import { useVersionContext } from '../version/versionContext'; diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx index 28b5363..b8219db 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/copyPasteControls3D.tsx @@ -347,13 +347,17 @@ 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: "worker", - loadCapacity: 1, - triggers: [] - } + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "worker", + loadCapacity: 1, + loadCount: 1, + processTime: 10, + triggers: [] + } + ] } } addEvent(humanEvent); diff --git a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx index 11d27ca..1d1cb95 100644 --- a/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx +++ b/app/src/modules/scene/controls/selectionControls/selection3D/duplicationControls3D.tsx @@ -321,13 +321,17 @@ 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: "worker", - loadCapacity: 1, - triggers: [] - } + actions: [ + { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "worker", + loadCapacity: 1, + loadCount: 1, + processTime: 10, + triggers: [] + } + ] } } addEvent(humanEvent); diff --git a/app/src/modules/scene/environment/shadow.tsx b/app/src/modules/scene/environment/shadow.tsx index d8c8002..3321673 100644 --- a/app/src/modules/scene/environment/shadow.tsx +++ b/app/src/modules/scene/environment/shadow.tsx @@ -6,7 +6,6 @@ import { useElevation, useShadows, useSunPosition, - useWallItems, useTileDistance, } from "../../../store/builder/store"; import * as CONSTANTS from "../../../types/world/worldConstants"; @@ -25,13 +24,12 @@ export default function Shadows() { const { controls, gl } = useThree(); const { elevation, setElevation } = useElevation(); const { azimuth, setAzimuth } = useAzimuth(); - const { wallItems } = useWallItems(); const { planeValue } = useTileDistance(); useEffect(() => { gl.shadowMap.enabled = true; gl.shadowMap.type = THREE.PCFShadowMap; - }, [gl, wallItems]); + }, [gl]); useEffect(() => { if (lightRef.current && targetRef.current) { diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts index 2175a97..928c579 100644 --- a/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts +++ b/app/src/modules/simulation/actions/conveyor/actionHandler/useDespawnHandler.ts @@ -3,7 +3,7 @@ import { useSceneContext } from "../../../../scene/sceneContext"; export function useDespawnHandler() { const { materialStore } = useSceneContext(); - const { getMaterialById, removeMaterial, setEndTime } = materialStore(); + const { getMaterialById, removeMaterial, setEndTime, clearLocations } = materialStore(); const deSpawnLogStatus = (materialUuid: string, status: string) => { echo.info(`${materialUuid}, ${status}`); @@ -17,6 +17,7 @@ export function useDespawnHandler() { setEndTime(material.materialId, performance.now()); removeMaterial(material.materialId); + clearLocations(material.materialId); deSpawnLogStatus(material.materialName, `Despawned`); diff --git a/app/src/modules/simulation/actions/human/actionHandler/useAssemblyHandler.ts b/app/src/modules/simulation/actions/human/actionHandler/useAssemblyHandler.ts index a654b35..602de27 100644 --- a/app/src/modules/simulation/actions/human/actionHandler/useAssemblyHandler.ts +++ b/app/src/modules/simulation/actions/human/actionHandler/useAssemblyHandler.ts @@ -8,7 +8,7 @@ export function useAssemblyHandler() { const { getModelUuidByActionUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); - const { incrementHumanLoad, addCurrentMaterial } = humanStore(); + const { incrementHumanLoad, addCurrentMaterial, addCurrentAction } = humanStore(); const assemblyLogStatus = (materialUuid: string, status: string) => { echo.info(`${materialUuid}, ${status}`); @@ -24,6 +24,7 @@ export function useAssemblyHandler() { if (!modelUuid) return; incrementHumanLoad(modelUuid, 1); + addCurrentAction(modelUuid, action.actionUuid); addCurrentMaterial(modelUuid, material.materialType, material.materialId); assemblyLogStatus(material.materialName, `performing assembly action`); diff --git a/app/src/modules/simulation/actions/human/actionHandler/useWorkerHandler.ts b/app/src/modules/simulation/actions/human/actionHandler/useWorkerHandler.ts index 9a1cf99..efefc39 100644 --- a/app/src/modules/simulation/actions/human/actionHandler/useWorkerHandler.ts +++ b/app/src/modules/simulation/actions/human/actionHandler/useWorkerHandler.ts @@ -8,7 +8,7 @@ export function useWorkerHandler() { const { getModelUuidByActionUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); - const { incrementHumanLoad, addCurrentMaterial } = humanStore(); + const { incrementHumanLoad, incrementLoadCount, addCurrentMaterial, addCurrentAction } = humanStore(); const workerLogStatus = (materialUuid: string, status: string) => { echo.info(`${materialUuid}, ${status}`); @@ -24,6 +24,8 @@ export function useWorkerHandler() { if (!modelUuid) return; incrementHumanLoad(modelUuid, 1); + incrementLoadCount(modelUuid, 1); + addCurrentAction(modelUuid, action.actionUuid); addCurrentMaterial(modelUuid, material.materialType, material.materialId); workerLogStatus(material.materialName, `performing worker action`); diff --git a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts index 1135bdc..79d6401 100644 --- a/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts +++ b/app/src/modules/simulation/actions/storageUnit/actionHandler/useRetrieveHandler.ts @@ -11,7 +11,7 @@ export function useRetrieveHandler() { const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = productStore(); const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore(); const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore(); - const { getHumanById, incrementHumanLoad, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore(); + const { getHumanById, incrementHumanLoad, incrementLoadCount, addCurrentMaterial: addCurrentMaterialToHuman } = humanStore(); const { getAssetById, setCurrentAnimation } = assetStore(); const { selectedProduct } = selectedProductStore(); const { getArmBotById, addCurrentAction } = armBotStore(); @@ -298,14 +298,15 @@ export function useRetrieveHandler() { } else if (triggeredModel.type === 'human') { const human = getHumanById(triggeredModel.modelUuid); const humanAsset = getAssetById(triggeredModel.modelUuid); + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); - if (human && !human.isScheduled && human.state === 'idle' && human.currentLoad < human.point.action.loadCapacity) { + if (human && !human.isScheduled && human.state === 'idle' && human.currentLoad < (action as HumanAction).loadCapacity) { if (humanAsset && humanAsset.animationState?.current === 'idle') { setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); } else if (humanAsset && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState.isCompleted) { const lastMaterial = getLastMaterial(storageUnit.modelUuid); if (lastMaterial) { - if (human.currentLoad < human.point.action.loadCapacity) { + if (action && human.currentLoad < (action as HumanAction).loadCapacity) { const material = createNewMaterial( lastMaterial.materialId, lastMaterial.materialType, @@ -315,10 +316,11 @@ export function useRetrieveHandler() { removeLastMaterial(storageUnit.modelUuid); updateCurrentLoad(storageUnit.modelUuid, -1); incrementHumanLoad(human.modelUuid, 1); + incrementLoadCount(human.modelUuid, 1); addCurrentMaterialToHuman(human.modelUuid, material.materialType, material.materialId); retrieveLogStatus(material.materialName, `is picked by ${human.modelName}`); } - if (human.currentLoad + 1 < human.point.action.loadCapacity) { + if (human.currentLoad + 1 < (action as HumanAction).loadCapacity) { } } } diff --git a/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts b/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts index 34407c9..76a1047 100644 --- a/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts +++ b/app/src/modules/simulation/conveyor/eventManager/useConveyorEventManager.ts @@ -6,65 +6,92 @@ import { useSceneContext } from '../../../scene/sceneContext'; type ConveyorCallback = { conveyorId: string; callback: () => void; + except: string[]; }; export function useConveyorEventManager() { - const { conveyorStore } = useSceneContext(); - const { getConveyorById } = conveyorStore(); - const callbacksRef = useRef([]); + const { materialStore } = useSceneContext(); + const { getMaterialsByCurrentModelUuid } = materialStore(); + const callbacksRef = useRef>(new Map()); + const isCooldownRef = useRef>(new Map()); const isMonitoringRef = useRef(false); + const { isPlaying } = usePlayButtonStore(); const { isPaused } = usePauseButtonStore(); const { isReset } = useResetButtonStore(); useEffect(() => { if (isReset) { - callbacksRef.current = []; + callbacksRef.current.clear(); + isCooldownRef.current.clear(); + isMonitoringRef.current = false; } - }, [isReset]) + }, [isReset]); - // Add a new conveyor to monitor - const addConveyorToMonitor = (conveyorId: string, callback: () => void) => { - // Avoid duplicates - if (!callbacksRef.current.some((entry) => entry.conveyorId === conveyorId)) { - callbacksRef.current.push({ conveyorId, callback }); + const addConveyorToMonitor = (conveyorId: string, callback: () => void, except?: string[]) => { + if (!callbacksRef.current.has(conveyorId)) { + callbacksRef.current.set(conveyorId, []); } - // Start monitoring if not already running - if (!isMonitoringRef.current) { - isMonitoringRef.current = true; - } + callbacksRef.current.get(conveyorId)!.push({ conveyorId, callback, except: except || [] }); + isMonitoringRef.current = true; }; - // Remove a conveyor from monitoring const removeConveyorFromMonitor = (conveyorId: string) => { - callbacksRef.current = callbacksRef.current.filter( - (entry) => entry.conveyorId !== conveyorId - ); - - // Stop monitoring if no more conveyors to track - if (callbacksRef.current.length === 0) { + callbacksRef.current.delete(conveyorId); + isCooldownRef.current.delete(conveyorId); + if (callbacksRef.current.size === 0) { isMonitoringRef.current = false; } }; - // Check conveyor states every frame useFrame(() => { - if (!isMonitoringRef.current || callbacksRef.current.length === 0 || !isPlaying || isPaused) return; + if (!isMonitoringRef.current || !isPlaying || isPaused) return; - callbacksRef.current.forEach(({ conveyorId, callback }) => { - const conveyor = getConveyorById(conveyorId); - if (conveyor?.isPaused === false) { - callback(); - removeConveyorFromMonitor(conveyorId); // Remove after triggering + callbacksRef.current.forEach((queue, conveyorId) => { + if (!queue || queue.length === 0) return; + if (isCooldownRef.current.get(conveyorId)) return; + + const { callback, except } = queue[0]; + const conveyorMaterials = getMaterialsByCurrentModelUuid(conveyorId); + + let conditionMet = false; + + if (!conveyorMaterials || conveyorMaterials.length === 0) { + conditionMet = true; + } else { + const pausedMaterials = conveyorMaterials.filter(m => m.isPaused); + + if (pausedMaterials.length === 0) { + conditionMet = true; + } else { + const allPausedInExcept = pausedMaterials.filter(m => !except.includes(m.materialId)); + if (allPausedInExcept.length === 0) { + conditionMet = true; + } + } + } + + if (conditionMet) { + queue.shift(); + if (callback) callback(); + + if (queue.length === 0) { + removeConveyorFromMonitor(conveyorId); + } else { + isCooldownRef.current.set(conveyorId, true); + setTimeout(() => { + isCooldownRef.current.set(conveyorId, false); + }, 1000); + } } }); }); - // Cleanup on unmount useEffect(() => { return () => { - callbacksRef.current = []; + callbacksRef.current.clear(); + isCooldownRef.current.clear(); isMonitoringRef.current = false; }; }, []); @@ -73,4 +100,4 @@ export function useConveyorEventManager() { addConveyorToMonitor, removeConveyorFromMonitor, }; -} \ No newline at end of file +} diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx index fa035cc..236ab55 100644 --- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx +++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import * as THREE from "three"; import { useSubModuleStore } from "../../../../store/useModuleStore"; -import { useSelectedAction, useSelectedAsset } from "../../../../store/simulation/useSimulationStore"; +import { useSelectedAction, useSelectedAsset, useSelectedEventData } from "../../../../store/simulation/useSimulationStore"; import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct"; import { QuadraticBezierLine } from "@react-three/drei"; import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi"; @@ -38,6 +38,7 @@ function TriggerConnector() { const { selectedAction } = useSelectedAction(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); + const { setSelectedEventData } = useSelectedEventData(); const { projectId } = useParams(); const [firstSelectedPoint, setFirstSelectedPoint] = useState<{ @@ -62,6 +63,10 @@ function TriggerConnector() { eventDatas: eventData, versionId: selectedVersion?.versionId || '', }) + + if (firstSelectedPoint?.pointUuid) { + setSelectedEventData(eventData, firstSelectedPoint.pointUuid) + } } useEffect(() => { @@ -155,8 +160,8 @@ function TriggerConnector() { // Handle Human point else if (event.type === "human" && '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}`, @@ -166,7 +171,7 @@ function TriggerConnector() { }); } }); - } + }); } }); diff --git a/app/src/modules/simulation/human/eventManager/useHumanEventManager.ts b/app/src/modules/simulation/human/eventManager/useHumanEventManager.ts index 0449afc..0e37593 100644 --- a/app/src/modules/simulation/human/eventManager/useHumanEventManager.ts +++ b/app/src/modules/simulation/human/eventManager/useHumanEventManager.ts @@ -2,14 +2,19 @@ import { useEffect, useRef } from 'react'; import { useFrame } from '@react-three/fiber'; import { usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../store/usePlayButtonStore'; import { useSceneContext } from '../../../scene/sceneContext'; +import { useProductContext } from '../../products/productContext'; export function useHumanEventManager() { - const { humanStore } = useSceneContext(); - const { getHumanById } = humanStore(); + const { humanStore, productStore } = useSceneContext(); + const { getHumanById, clearLoadCount } = humanStore(); + const { getActionByUuid } = productStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const callbacksRef = useRef void)[]>>(new Map()); - const isMonitoringRef = useRef(false); + const actionQueueRef = useRef>(new Map()); const isCooldownRef = useRef>(new Map()); + const isMonitoringRef = useRef(false); const { isPlaying } = usePlayButtonStore(); const { isPaused } = usePauseButtonStore(); @@ -18,23 +23,34 @@ export function useHumanEventManager() { useEffect(() => { if (isReset) { callbacksRef.current.clear(); + actionQueueRef.current.clear(); isCooldownRef.current.clear(); + isMonitoringRef.current = false; } }, [isReset]); - const addHumanToMonitor = (humanId: string, callback: () => void) => { + const addHumanToMonitor = (humanId: string, callback: () => void, actionUuid: string) => { + const action = getActionByUuid(selectedProduct.productUuid, actionUuid || '') as HumanAction | undefined; + + if (!action) return; + + const actionType = action.actionType; + if (actionType !== "worker" && actionType !== "assembly") return; + if (!callbacksRef.current.has(humanId)) { callbacksRef.current.set(humanId, []); + actionQueueRef.current.set(humanId, []); } - callbacksRef.current.get(humanId)!.push(callback); - if (!isMonitoringRef.current) { - isMonitoringRef.current = true; - } + callbacksRef.current.get(humanId)!.push(callback); + actionQueueRef.current.get(humanId)!.push({ actionType, actionUuid }); + + isMonitoringRef.current = true; }; const removeHumanFromMonitor = (humanId: string) => { callbacksRef.current.delete(humanId); + actionQueueRef.current.delete(humanId); isCooldownRef.current.delete(humanId); if (callbacksRef.current.size === 0) { @@ -43,47 +59,80 @@ export function useHumanEventManager() { }; useFrame(() => { - if (!isMonitoringRef.current || !isPlaying || isPaused) return; callbacksRef.current.forEach((queue, humanId) => { if (queue.length === 0 || isCooldownRef.current.get(humanId)) return; + const actionQueue = actionQueueRef.current.get(humanId); + if (!actionQueue || actionQueue.length === 0) return; + + const { actionType: expectedActionType, actionUuid } = actionQueue[0]; const human = getHumanById(humanId); - const actionType = human?.point.action.actionType; + const action = getActionByUuid(selectedProduct.productUuid, actionUuid) as HumanAction | undefined; + + if (!human || !action || action.actionType !== expectedActionType) return; let conditionMet = false; - if (actionType === 'worker') { - conditionMet = Boolean( - human && - human.isActive === false && - human.state === 'idle' && - human.isScheduled === false && - human.currentLoad < human.point.action.loadCapacity - ); - } else if (actionType === 'assembly') { - conditionMet = Boolean( - human && - human.isActive === false && - human.state === 'idle' && - human.isScheduled === false - ); + const currentAction = getActionByUuid(selectedProduct.productUuid, human.currentAction?.actionUuid || '') as HumanAction | undefined; + + if (expectedActionType === "worker") { + if (currentAction && currentAction.actionType === 'worker') { + conditionMet = ( + !human.isActive && + human.state === "idle" && + human.currentLoad < currentAction.loadCapacity + ); + + if (human.totalLoadCount >= currentAction.loadCount) { + queue.shift(); + actionQueue.shift(); + if (queue.length === 0) { + removeHumanFromMonitor(humanId); + } + return; + } + } else { + conditionMet = ( + !human.isActive && + human.state === "idle" && + human.currentLoad < action.loadCapacity + ); + } + + } else if (expectedActionType === "assembly") { + if (currentAction && currentAction.actionType === 'worker') { + conditionMet = ( + !human.isActive && + human.state === "idle" && + human.currentLoad < currentAction.loadCapacity + ); + } else { + conditionMet = ( + !human.isActive && + human.state === "idle" && + human.currentLoad < action.loadCapacity + ) + } + if (conditionMet) { + clearLoadCount(human.modelUuid); + } } if (conditionMet) { const callback = queue.shift(); - if (callback) { - callback(); + actionQueue.shift(); - if (queue.length === 0) { - removeHumanFromMonitor(humanId); - } else { - isCooldownRef.current.set(humanId, true); - setTimeout(() => { - isCooldownRef.current.set(humanId, false); - }, 1000); - } + if (callback) callback(); + + if (queue.length === 0) { + removeHumanFromMonitor(humanId); + } else { + isCooldownRef.current.set(humanId, true); + setTimeout(() => { + isCooldownRef.current.set(humanId, false); + }, 1000); } } }); @@ -92,8 +141,9 @@ export function useHumanEventManager() { useEffect(() => { return () => { callbacksRef.current.clear(); - isMonitoringRef.current = false; + actionQueueRef.current.clear(); isCooldownRef.current.clear(); + isMonitoringRef.current = false; }; }, []); diff --git a/app/src/modules/simulation/human/instances/animator/humanAnimator.tsx b/app/src/modules/simulation/human/instances/animator/humanAnimator.tsx index 0c06826..29547ac 100644 --- a/app/src/modules/simulation/human/instances/animator/humanAnimator.tsx +++ b/app/src/modules/simulation/human/instances/animator/humanAnimator.tsx @@ -4,6 +4,7 @@ import * as THREE from 'three'; import { Line } from '@react-three/drei'; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore'; import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; interface HumanAnimatorProps { path: [number, number, number][]; @@ -15,7 +16,10 @@ interface HumanAnimatorProps { } function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, startUnloadingProcess }: Readonly) { - const { humanStore, assetStore } = useSceneContext(); + const { humanStore, assetStore, productStore } = useSceneContext(); + const { getActionByUuid } = productStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const { getHumanById } = humanStore(); const { setCurrentAnimation } = assetStore(); const { isPaused } = usePauseButtonStore(); @@ -25,26 +29,29 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start const progressRef = useRef(0); const movingForward = useRef(true); const completedRef = useRef(false); - const [objectRotation, setObjectRotation] = useState<[number, number, number] | null>(human.point?.action?.pickUpPoint?.rotation || [0, 0, 0]) + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); + const [objectRotation, setObjectRotation] = useState<[number, number, number] | null>((action as HumanAction)?.pickUpPoint?.rotation || [0, 0, 0]) const [restRotation, setRestingRotation] = useState(true); const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]); const { scene } = useThree(); useEffect(() => { + if (!human.currentAction?.actionUuid) return; + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); if (currentPhase === 'init-pickup' && path.length > 0) { setCurrentPath(path); - setObjectRotation(human.point.action.pickUpPoint?.rotation ?? null) + setObjectRotation((action as HumanAction).pickUpPoint?.rotation ?? null) } else if (currentPhase === 'init_assembly' && path.length > 0) { - setObjectRotation(human.point.action?.assemblyPoint?.rotation ?? null) + setObjectRotation((action as HumanAction)?.assemblyPoint?.rotation ?? null) setCurrentPath(path); } else if (currentPhase === 'pickup-drop' && path.length > 0) { - setObjectRotation(human.point.action?.dropPoint?.rotation ?? null) + setObjectRotation((action as HumanAction)?.dropPoint?.rotation ?? null) setCurrentPath(path); } else if (currentPhase === 'drop-pickup' && path.length > 0) { - setObjectRotation(human.point.action?.pickUpPoint?.rotation ?? null) + setObjectRotation((action as HumanAction)?.pickUpPoint?.rotation ?? null) setCurrentPath(path); } - }, [currentPhase, path, objectRotation]); + }, [currentPhase, path, objectRotation, selectedProduct, human.currentAction?.actionUuid]); useEffect(() => { completedRef.current = false; @@ -77,7 +84,7 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start const object = scene.getObjectByProperty('uuid', human.modelUuid); if (!object || currentPath.length < 2) return; - if (isPaused) return; + if (isPaused || !isPlaying) return; let totalDistance = 0; const distances = []; @@ -128,13 +135,13 @@ function HumanAnimator({ path, handleCallBack, currentPhase, human, reset, start const t = (progressRef.current - accumulatedDistance) / segmentDistance; const position = start.clone().lerp(end, t); object.position.copy(position); - if (human.currentMaterials.length > 0) { + if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (currentPhase !== 'init-pickup' && currentPhase !== 'init_assembly')) { setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true); } else { setCurrentAnimation(human.modelUuid, 'walking', true, true, true); } } else { - if (human.currentMaterials.length > 0) { + if (human.currentMaterials.length > 0 && action?.actionType === 'worker' && (currentPhase !== 'init-pickup' && currentPhase !== 'init_assembly')) { setCurrentAnimation(human.modelUuid, 'idle_with_box', true, true, true); } else { setCurrentAnimation(human.modelUuid, 'idle', true, true, true); diff --git a/app/src/modules/simulation/human/instances/animator/materialAnimator.tsx b/app/src/modules/simulation/human/instances/animator/materialAnimator.tsx index 398bb2a..2da62ad 100644 --- a/app/src/modules/simulation/human/instances/animator/materialAnimator.tsx +++ b/app/src/modules/simulation/human/instances/animator/materialAnimator.tsx @@ -2,11 +2,18 @@ import { useEffect, useRef, useState } from 'react'; import { useThree } from '@react-three/fiber'; import * as THREE from 'three'; import { MaterialModel } from '../../../materials/instances/material/materialModel'; +import { useSceneContext } from '../../../../scene/sceneContext'; +import { useProductContext } from '../../../products/productContext'; -const MaterialAnimator = ({ human }: { human: HumanStatus }) => { +const MaterialAnimator = ({ human, currentPhase }: { human: HumanStatus, currentPhase: string; }) => { + const { productStore } = useSceneContext(); + const { getActionByUuid } = productStore(); + const { selectedProductStore } = useProductContext(); + const { selectedProduct } = selectedProductStore(); const meshRef = useRef(null!); const [hasLoad, setHasLoad] = useState(false); const [isAttached, setIsAttached] = useState(false); + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const { scene } = useThree(); useEffect(() => { @@ -39,11 +46,11 @@ const MaterialAnimator = ({ human }: { human: HumanStatus }) => { meshRef.current.visible = true; setIsAttached(true); } - }, [hasLoad, human.modelUuid, scene]); + }, [hasLoad, human.modelUuid, scene, currentPhase]); return ( <> - {hasLoad && human.point.action.actionType === 'worker' && human.currentMaterials.length > 0 && ( + {hasLoad && (action as HumanAction).actionType === 'worker' && human.currentMaterials.length > 0 && currentPhase !== 'init-pickup' && currentPhase !== 'init_assembly' && ( { if (isPlaying) { - if (!human.point.action.assemblyPoint || human.point.action.actionType === 'worker') return; + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); + + if (!action || !(action as HumanAction).assemblyPoint || (action as HumanAction).actionType === 'worker') return; + + if (!human.isActive && human.state === 'idle' && (currentPhase === 'init' || currentPhase === 'picking')) { + + const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid); + if (!humanMesh) return; - if (!human.isActive && human.state === 'idle' && currentPhase === 'init') { const toPickupPath = computePath( - new THREE.Vector3(human?.position[0], human?.position[1], human?.position[2]), + new THREE.Vector3(...humanMesh.position.toArray()), new THREE.Vector3( - human?.point?.action?.assemblyPoint?.position?.[0] ?? 0, - human?.point?.action?.assemblyPoint?.position?.[1] ?? 0, - human?.point?.action?.assemblyPoint?.position?.[2] ?? 0 + (action as HumanAction)?.assemblyPoint?.position?.[0] ?? 0, + (action as HumanAction)?.assemblyPoint?.position?.[1] ?? 0, + (action as HumanAction)?.assemblyPoint?.position?.[2] ?? 0 ) ); setPath(toPickupPath); @@ -138,6 +144,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { setCurrentAnimation(human.modelUuid, 'idle', true, true, true); humanStatus(human.modelUuid, 'Human is waiting for material in assembly'); } else if (!human.isActive && human.state === 'idle' && currentPhase === 'waiting') { + if (human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current !== 'working_standing') { setCurrentAnimation(human.modelUuid, 'working_standing', true, true, false); setHumanState(human.modelUuid, 'running'); @@ -145,7 +152,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { setHumanActive(human.modelUuid, true); processStartTimeRef.current = performance.now(); - processTimeRef.current = human.point.action.processTime || 0; + processTimeRef.current = (action as HumanAction).processTime || 0; accumulatedPausedTimeRef.current = 0; lastPauseTimeRef.current = null; hasLoggedHalfway.current = false; @@ -156,7 +163,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { } } } else if (human.isActive && human.state === 'running' && human.currentMaterials.length > 0 && humanAsset && humanAsset.animationState?.current === 'working_standing' && humanAsset.animationState?.isCompleted) { - if (human.point.action.assemblyPoint && currentPhase === 'assembling') { + if ((action as HumanAction).assemblyPoint && currentPhase === 'assembling') { setHumanState(human.modelUuid, 'idle'); setCurrentPhase('waiting'); setHumanActive(human.modelUuid, false); @@ -167,7 +174,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { decrementHumanLoad(human.modelUuid, 1); const material = removeLastMaterial(human.modelUuid); if (material) { - triggerPointActions(human.point.action, material.materialId); + triggerPointActions((action as HumanAction), material.materialId); } } } @@ -179,9 +186,11 @@ function HumanInstance({ human }: { human: HumanStatus }) { }, [human, currentPhase, path, isPlaying, humanAsset?.animationState?.isCompleted]); const trackAssemblyProcess = useCallback(() => { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); + const now = performance.now(); - if (!processStartTimeRef.current || !human.point.action.processTime) { + if (!processStartTimeRef.current || !(action as HumanAction).processTime || !action) { return; } @@ -197,12 +206,12 @@ function HumanInstance({ human }: { human: HumanStatus }) { } const elapsed = (now - processStartTimeRef.current - accumulatedPausedTimeRef.current) * isSpeedRef.current; - const totalProcessTimeMs = human.point.action.processTime * 1000; + const totalProcessTimeMs = ((action as HumanAction).processTime || 1) * 1000; if (elapsed >= totalProcessTimeMs / 2 && !hasLoggedHalfway.current) { hasLoggedHalfway.current = true; if (human.currentMaterials.length > 0) { - setMaterial(human.currentMaterials[0].materialId, human.point.action.swapMaterial || 'Default Material'); + setMaterial(human.currentMaterials[0].materialId, (action as HumanAction).swapMaterial || 'Default Material'); } humanStatus(human.modelUuid, `🟡 Human ${human.modelUuid} reached halfway in assembly.`); } @@ -219,19 +228,24 @@ function HumanInstance({ human }: { human: HumanStatus }) { } processAnimationIdRef.current = requestAnimationFrame(trackAssemblyProcess); - }, [human.modelUuid, human.point.action.processTime, human.currentMaterials]); + }, [human.modelUuid, human.currentMaterials]); useEffect(() => { if (isPlaying) { - if (!human.point.action.pickUpPoint || !human.point.action.dropPoint || human.point.action.actionType === 'assembly') return; + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); + if (!action || action.actionType !== 'worker' || !action.pickUpPoint || !action.dropPoint) return; + + if (!human.isActive && human.state === 'idle' && (currentPhase === 'init' || currentPhase === 'waiting')) { + + const humanMesh = scene.getObjectByProperty('uuid', human.modelUuid); + if (!humanMesh) return; - if (!human.isActive && human.state === 'idle' && currentPhase === 'init') { const toPickupPath = computePath( - new THREE.Vector3(human?.position[0], human?.position[1], human?.position[2]), + new THREE.Vector3(...humanMesh.position.toArray()), new THREE.Vector3( - human?.point?.action?.pickUpPoint?.position?.[0] ?? 0, - human?.point?.action?.pickUpPoint?.position?.[1] ?? 0, - human?.point?.action?.pickUpPoint?.position?.[2] ?? 0 + action?.pickUpPoint?.position?.[0] ?? 0, + action?.pickUpPoint?.position?.[1] ?? 0, + action?.pickUpPoint?.position?.[2] ?? 0 ) ); setPath(toPickupPath); @@ -242,18 +256,18 @@ function HumanInstance({ human }: { human: HumanStatus }) { humanStatus(human.modelUuid, 'Started from init, heading to pickup'); return; } else if (!human.isActive && human.state === 'idle' && currentPhase === 'picking') { - if (humanAsset && human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) { - if (human.point.action.pickUpPoint && human.point.action.dropPoint) { + if (humanAsset && human.currentLoad === action.loadCapacity && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) { + if (action.pickUpPoint && action.dropPoint) { const toDrop = computePath( new THREE.Vector3( - human.point.action.pickUpPoint.position?.[0] ?? 0, - human.point.action.pickUpPoint.position?.[1] ?? 0, - human.point.action.pickUpPoint.position?.[2] ?? 0 + action.pickUpPoint.position?.[0] ?? 0, + action.pickUpPoint.position?.[1] ?? 0, + action.pickUpPoint.position?.[2] ?? 0 ), new THREE.Vector3( - human.point.action.dropPoint.position?.[0] ?? 0, - human.point.action.dropPoint.position?.[1] ?? 0, - human.point.action.dropPoint.position?.[2] ?? 0 + action.dropPoint.position?.[0] ?? 0, + action.dropPoint.position?.[1] ?? 0, + action.dropPoint.position?.[2] ?? 0 ) ); setPath(toDrop); @@ -262,21 +276,24 @@ function HumanInstance({ human }: { human: HumanStatus }) { setCurrentAnimation(human.modelUuid, 'walk_with_box', true, true, true); humanStatus(human.modelUuid, 'Started from pickup point, heading to drop point'); } - } else if (human.currentLoad === human.point.action.loadCapacity && human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') { + } else if (human.currentLoad === action.loadCapacity && human.currentMaterials.length > 0 && humanAsset?.animationState?.current !== 'pickup') { + if (human.currentMaterials[0]?.materialId) { + setIsVisible(human.currentMaterials[0]?.materialId, false); + } setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); } } else if (!human.isActive && human.state === 'idle' && currentPhase === 'dropping' && human.currentLoad === 0) { - if (human.point.action.pickUpPoint && human.point.action.dropPoint) { + if (action.pickUpPoint && action.dropPoint) { const dropToPickup = computePath( new THREE.Vector3( - human.point.action.dropPoint.position?.[0] ?? 0, - human.point.action.dropPoint.position?.[1] ?? 0, - human.point.action.dropPoint.position?.[2] ?? 0 + action.dropPoint.position?.[0] ?? 0, + action.dropPoint.position?.[1] ?? 0, + action.dropPoint.position?.[2] ?? 0 ), new THREE.Vector3( - human.point.action.pickUpPoint.position?.[0] ?? 0, - human.point.action.pickUpPoint.position?.[1] ?? 0, - human.point.action.pickUpPoint.position?.[2] ?? 0 + action.pickUpPoint.position?.[0] ?? 0, + action.pickUpPoint.position?.[1] ?? 0, + action.pickUpPoint.position?.[2] ?? 0 ) ); setPath(dropToPickup); @@ -373,38 +390,35 @@ function HumanInstance({ human }: { human: HumanStatus }) { }, [human, isPlaying]); function startUnloadingProcess() { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); + const humanAsset = getAssetById(human.modelUuid); if (humanAsset?.animationState?.current !== 'drop') { setCurrentAnimation(human.modelUuid, 'drop', true, false, false); } if (humanAsset?.animationState?.current === 'drop' && humanAsset?.animationState?.isCompleted) { - if (human.point.action.triggers.length > 0) { - const trigger = getTriggerByUuid(selectedProduct.productUuid, human.point.action.triggers[0]?.triggerUuid); + if ((action as HumanAction).triggers.length > 0) { + const trigger = getTriggerByUuid(selectedProduct.productUuid, (action as HumanAction).triggers[0]?.triggerUuid); const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || ''); if (trigger && model) { if (model.type === 'transfer') { - const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid); if (action) { handleMaterialDropToConveyor(model); } } else if (model.type === 'machine') { - const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid); if (action) { handleMaterialDropToMachine(model); } } else if (model.type === 'roboticArm') { - const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid); if (action) { handleMaterialDropToArmBot(model); } } else if (model.type === 'storageUnit') { - const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid); if (action) { handleMaterialDropToStorageUnit(model); } } else if (model.type === 'vehicle') { - const action = getActionByUuid(selectedProduct.productUuid, human.point.action.actionUuid); if (action) { handleMaterialDropToVehicle(model); } @@ -423,6 +437,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { } function handleMaterialDropToStorageUnit(model: StorageEventSchema) { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const humanAsset = getAssetById(human.modelUuid); if (model && humanAsset?.animationState?.current !== 'drop') { setCurrentAnimation(human.modelUuid, 'drop', true, false, false); @@ -436,7 +451,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { human.currentLoad, model.modelUuid, model.point.action.storageCapacity, - human.point.action + (action as HumanAction) ); } } else { @@ -490,6 +505,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { } function handleMaterialDropToConveyor(model: ConveyorEventSchema) { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const humanAsset = getAssetById(human.modelUuid); if (humanAsset?.animationState?.current !== 'drop') { setCurrentAnimation(human.modelUuid, 'drop', true, false, false); @@ -503,7 +519,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { human.modelUuid, human.currentLoad, conveyor.modelUuid, - human.point.action + (action as HumanAction) ); } } else { @@ -555,6 +571,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { } function handleMaterialDropToArmBot(model: RoboticArmEventSchema) { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const humanAsset = getAssetById(human.modelUuid); if (humanAsset?.animationState?.current !== 'drop') { setCurrentAnimation(human.modelUuid, 'drop', true, false, false); @@ -568,7 +585,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { human.modelUuid, human.currentLoad, model.modelUuid, - human.point.action + (action as HumanAction) ); } } else { @@ -625,6 +642,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { } function handleMaterialDropToVehicle(model: VehicleEventSchema) { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const humanAsset = getAssetById(human.modelUuid); if (humanAsset?.animationState?.current !== 'drop') { setCurrentAnimation(human.modelUuid, 'drop', true, false, false); @@ -638,7 +656,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { human.modelUuid, human.currentLoad, model.modelUuid, - human.point.action + (action as HumanAction) ); } } else { @@ -695,6 +713,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { } function handleMaterialDropToMachine(model: MachineEventSchema) { + const action = getActionByUuid(selectedProduct.productUuid, human?.currentAction?.actionUuid || ''); const humanAsset = getAssetById(human.modelUuid); if (humanAsset?.animationState?.current !== 'drop') { setCurrentAnimation(human.modelUuid, 'drop', true, false, false); @@ -708,7 +727,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { human.modelUuid, human.currentLoad, model.modelUuid, - human.point.action + (action as HumanAction) ); } } else { @@ -804,7 +823,7 @@ function HumanInstance({ human }: { human: HumanStatus }) { startUnloadingProcess={startUnloadingProcess} /> - + ) } diff --git a/app/src/modules/simulation/human/instances/instance/humanUi.tsx b/app/src/modules/simulation/human/instances/instance/humanUi.tsx index 35bd913..17335b1 100644 --- a/app/src/modules/simulation/human/instances/instance/humanUi.tsx +++ b/app/src/modules/simulation/human/instances/instance/humanUi.tsx @@ -27,7 +27,7 @@ function HumanUi() { const { humanStore, productStore } = useSceneContext(); const { selectedProduct } = selectedProductStore(); const { humans, getHumanById } = humanStore(); - const { updateEvent } = productStore(); + const { updateEvent, updateAction, getActionByUuid } = productStore(); const [startPosition, setStartPosition] = useState<[number, number, number]>([0, 1, 0]); const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 1, 0]); const [assemblyPosition, setAssemblyPosition] = useState<[number, number, number]>([0, 1, 0]); @@ -49,9 +49,8 @@ function HumanUi() { const { selectedVersion } = selectedVersionStore(); const { projectId } = useParams(); - const selectedHuman = selectedEventSphere ? getHumanById(selectedEventSphere.userData.modelUuid) : null; - const actionType = selectedHuman?.point?.action?.actionType || null; - const isAssembly = actionType === 'assembly'; + const currentAction = getActionByUuid(selectedProduct.productUuid, selectedAction.actionId || ''); + const isAssembly = currentAction?.actionType === 'assembly'; const updateBackend = ( productName: string, @@ -69,10 +68,10 @@ function HumanUi() { }; useEffect(() => { - if (!selectedEventSphere) return; + if (!selectedEventSphere || !selectedAction?.actionId) return; const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid); - if (!selectedHuman || !selectedHuman.point?.action) return; + if (!selectedHuman || !selectedHuman.point?.actions) return; setSelectedHumanData({ position: selectedHuman.position, @@ -87,7 +86,8 @@ function HumanUi() { ); } - const action = selectedHuman.point.action; + const action = selectedHuman.point.actions.find(a => a.actionUuid === selectedAction.actionId); + if (!action) return; if (isAssembly) { if (action.assemblyPoint?.position && outerGroup.current) { @@ -170,44 +170,46 @@ function HumanUi() { if (!selectedEventSphere?.userData.modelUuid || !selectedAction?.actionId) return; const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid); - if (!selectedHuman || !outerGroup.current) return; + if (!selectedHuman || !outerGroup.current || !currentAction) return; - let updatedAction; + const updatedActions = selectedHuman.point.actions.map(action => { + if (action.actionUuid !== currentAction.actionUuid) return action; - if (isAssembly) { - if (!assemblyMarker.current) return; + if (isAssembly) { + if (!assemblyMarker.current || !outerGroup.current) return action; - const worldPosAssembly = new Vector3(...assemblyPosition); - const globalAssemblyPosition = outerGroup.current.localToWorld(worldPosAssembly.clone()); + const worldPosAssembly = new Vector3(...assemblyPosition); + const globalAssemblyPosition = outerGroup.current.localToWorld(worldPosAssembly.clone()); - updatedAction = { - ...selectedHuman.point.action, - assemblyPoint: { - position: [globalAssemblyPosition.x, globalAssemblyPosition.y, globalAssemblyPosition.z] as [number, number, number], - rotation: assemblyRotation - }, - }; - } else { - if (!startMarker.current || !endMarker.current) return; + return { + ...action, + assemblyPoint: { + position: [globalAssemblyPosition.x, globalAssemblyPosition.y, globalAssemblyPosition.z] as [number, number, number], + rotation: assemblyRotation + }, + }; + } else { + if (!startMarker.current || !endMarker.current || !outerGroup.current) return action; - const worldPosStart = new Vector3(...startPosition); - const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone()); + const worldPosStart = new Vector3(...startPosition); + const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone()); - const worldPosEnd = new Vector3(...endPosition); - const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone()); + const worldPosEnd = new Vector3(...endPosition); + const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone()); - updatedAction = { - ...selectedHuman.point.action, - pickUpPoint: { - position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number], - rotation: startRotation, - }, - dropPoint: { - position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number], - rotation: endRotation, - }, - }; - } + return { + ...action, + pickUpPoint: { + position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number], + rotation: startRotation, + }, + dropPoint: { + position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number], + rotation: endRotation, + }, + }; + } + }); const event = updateEvent( selectedProduct.productUuid, @@ -216,7 +218,7 @@ function HumanUi() { ...selectedHuman, point: { ...selectedHuman.point, - action: updatedAction, + actions: updatedActions, }, } ); diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx index 9dcfaab..72cd5fe 100644 --- a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx +++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx @@ -12,7 +12,8 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) { const matRef: any = useRef(); const { scene } = useThree(); const { selectedProductStore } = useProductContext(); - const { productStore } = useSceneContext(); + const { productStore, materialStore } = useSceneContext(); + const { setIsPaused } = materialStore(); const { getModelUuidByPointUuid, getPointByUuid, getEventByModelUuid, getActionByPointUuid } = productStore(); const { selectedProduct } = selectedProductStore(); const { speed } = useAnimationPlaySpeed(); @@ -80,16 +81,23 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) { return 1; } + if (event.type === 'human') { + return event.speed; + } + } else { return 1; } } const callTrigger = () => { - if (!material.next) return; - const action = getActionByPointUuid(selectedProduct.productUuid, material.next.pointUuid); - if (action) { - triggerPointActions(action, material.materialId); + if (material.next) { + const action = getActionByPointUuid(selectedProduct.productUuid, material.next.pointUuid); + if (action) { + triggerPointActions(action, material.materialId); + } + } else { + setIsPaused(material.materialId, true); } } @@ -97,7 +105,7 @@ function MaterialInstance({ material }: { readonly material: MaterialSchema }) { <> {material.isRendered && - + } { if (events.type === 'human') { addHuman(selectedProduct.productUuid, events); + + if (events.point.actions.length > 0) { + addCurrentAction(events.modelUuid, events.point.actions[0].actionUuid); + } } }); } diff --git a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts index 58ab562..ac4ca44 100644 --- a/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts +++ b/app/src/modules/simulation/triggers/triggerHandler/useTriggerHandler.ts @@ -330,9 +330,6 @@ export function useTriggerHandler() { if (vehicle) { if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { // Handle current action from vehicle - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } setIsPaused(materialId, true); setHumanScheduled(human.modelUuid, true); handleAction(action, materialId); @@ -343,88 +340,51 @@ export function useTriggerHandler() { setIsPaused(materialId, true); setHumanScheduled(human.modelUuid, true); - addVehicleToMonitor(vehicle.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId); - } - ) + addVehicleToMonitor(vehicle.modelUuid, () => { + handleAction(action, materialId); + }) } } } else { setIsPaused(materialId, true); + setHumanScheduled(human.modelUuid, true); addHumanToMonitor(human.modelUuid, () => { const vehicle = getVehicleById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); if (vehicle) { if (vehicle.isActive === false && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) { // Handle current action from vehicle - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } setIsPaused(materialId, true); - setHumanScheduled(human.modelUuid, true); handleAction(action, materialId); } else { // Handle current action using Event Manager setIsPaused(materialId, true); - setHumanScheduled(human.modelUuid, true); - addVehicleToMonitor(vehicle.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId); - } - ) + addVehicleToMonitor(vehicle.modelUuid, () => { + handleAction(action, materialId); + }) } } - }) + }, action.actionUuid) } } } else if (model?.type === 'transfer') { const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid); if (human) { - if (human.isActive === false && human.state === 'idle') { - const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid); + setIsPaused(materialId, true); + setHumanScheduled(human.modelUuid, true); + addHumanToMonitor(human.modelUuid, () => { + const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); if (conveyor) { // Handle current action using Event Manager setIsPaused(materialId, true); - setHumanScheduled(human.modelUuid, true); - addConveyorToMonitor(conveyor.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId); - } - ) + addConveyorToMonitor(conveyor.modelUuid, () => { + handleAction(action, materialId); + }, [materialId]) } - } else { - setIsPaused(materialId, true); - addHumanToMonitor(human.modelUuid, () => { - const conveyor = getConveyorById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); - if (conveyor) { - // Handle current action using Event Manager - setIsPaused(materialId, true); - setHumanScheduled(human.modelUuid, true); - - addConveyorToMonitor(conveyor.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId); - } - ) - } - }) - } + }, action.actionUuid) } } else if (model?.type === 'machine') { const human = getHumanById(trigger.triggeredAsset?.triggeredModel.modelUuid); @@ -434,9 +394,6 @@ export function useTriggerHandler() { if (machine) { if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) { setIsPaused(materialId, true); - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } setHumanScheduled(human.modelUuid, true); handleAction(action, materialId); } else { @@ -445,46 +402,31 @@ export function useTriggerHandler() { setIsPaused(materialId, true); setHumanScheduled(human.modelUuid, true); - addMachineToMonitor(machine.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId); - } - ) + addMachineToMonitor(machine.modelUuid, () => { + handleAction(action, materialId); + }) } } } else { setIsPaused(materialId, true); + setHumanScheduled(human.modelUuid, true); addHumanToMonitor(human.modelUuid, () => { const machine = getMachineById(action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid || ''); if (machine) { if (machine.isActive === false && machine.state === 'idle' && !machine.currentAction) { setIsPaused(materialId, true); - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - setHumanScheduled(human.modelUuid, true); handleAction(action, materialId); } else { // Handle current action using Event Manager setIsPaused(materialId, true); - setHumanScheduled(human.modelUuid, true); - addMachineToMonitor(machine.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId); - } - ) + addMachineToMonitor(machine.modelUuid, () => { + handleAction(action, materialId); + }) } } - } - ); + }, action.actionUuid); } } } else { @@ -492,23 +434,16 @@ export function useTriggerHandler() { // Handle current action from arm bot setIsPaused(materialId, true); - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } handleAction(action, materialId); } else { // Handle current action using Event Manager + setHumanScheduled(human.modelUuid, true); setIsPaused(materialId, true); - addHumanToMonitor(human.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId) - } - ); + addHumanToMonitor(human.modelUuid, () => { + handleAction(action, materialId) + }, action.actionUuid); } } @@ -517,9 +452,6 @@ export function useTriggerHandler() { // Handle current action from arm bot setIsPaused(materialId, true); - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } setHumanScheduled(human.modelUuid, true); handleAction(action, materialId); @@ -528,14 +460,9 @@ export function useTriggerHandler() { // Handle current action using Event Manager setIsPaused(materialId, true); setHumanScheduled(human.modelUuid, true); - addHumanToMonitor(human.modelUuid, - () => { - if (action.actionType === 'worker') { - setIsVisible(materialId, false); - } - handleAction(action, materialId) - } - ); + addHumanToMonitor(human.modelUuid, () => { + handleAction(action, materialId) + }, action.actionUuid); } } @@ -698,27 +625,12 @@ export function useTriggerHandler() { setNextLocation(material.materialId, null); if (action && human) { - - if (human.isActive === false && human.state === 'idle') { - - // Handle current action from arm bot + setHumanScheduled(human.modelUuid, true); + addHumanToMonitor(human.modelUuid, () => { setIsVisible(materialId, false); - setHumanScheduled(human.modelUuid, true); - handleAction(action, materialId); - - } else { - - setHumanScheduled(human.modelUuid, true); - addHumanToMonitor(human.modelUuid, - () => { - setIsVisible(materialId, false); - - handleAction(action, materialId); - } - ) - } + }, action.actionUuid) } } } @@ -964,8 +876,7 @@ export function useTriggerHandler() { setHumanScheduled(human.modelUuid, true); handleAction(action, materialId) } - } - ); + }, action.actionUuid); } } } @@ -1256,11 +1167,11 @@ export function useTriggerHandler() { setNextLocation(material.materialId, null); - if (action) { + if (action && action.actionType === 'worker') { if (human) { - if (human.isActive === false && human.state === 'idle' && !human.isScheduled && human.currentLoad < human.point.action.loadCapacity) { + if (human.isActive === false && human.state === 'idle' && !human.isScheduled && human.currentLoad < action.loadCapacity) { setIsVisible(materialId, false); @@ -1506,7 +1417,7 @@ export function useTriggerHandler() { }) setIsPaused(material.materialId, false); - }) + }, action.actionUuid) } else { setNextLocation(material.materialId, { modelUuid: trigger.triggeredAsset?.triggeredModel.modelUuid || '', diff --git a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx index 9d79de3..59cd9da 100644 --- a/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx +++ b/app/src/modules/simulation/vehicle/instances/animator/vehicleAnimator.tsx @@ -180,7 +180,6 @@ function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetai setCurrentPath(updated); }; - return ( <> {selectedPath === "auto" && diff --git a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx index 443ffa3..6a08a62 100644 --- a/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx +++ b/app/src/modules/simulation/vehicle/instances/instance/vehicleInstance.tsx @@ -11,16 +11,20 @@ import InteractivePoints from '../animator/interactivePoint'; import MaterialAnimator from '../animator/materialAnimator'; import VehicleAnimator from '../animator/vehicleAnimator'; +import { useHumanEventManager } from '../../../human/eventManager/useHumanEventManager'; + function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) { const { navMesh } = useNavMesh(); const { isPlaying } = usePlayButtonStore(); - const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore } = useSceneContext(); - const { removeMaterial, setEndTime } = materialStore(); + const { materialStore, armBotStore, conveyorStore, vehicleStore, storageUnitStore, humanStore, productStore, assetStore } = useSceneContext(); + const { removeMaterial, setEndTime, setIsVisible } = materialStore(); const { getStorageUnitById } = storageUnitStore(); - const { getHumanById } = humanStore(); + const { getHumanById, addCurrentAction } = humanStore(); const { getArmBotById } = armBotStore(); const { getConveyorById } = conveyorStore(); const { triggerPointActions } = useTriggerHandler(); + const { setCurrentAnimation, getAssetById } = assetStore(); + const { addHumanToMonitor } = useHumanEventManager(); const { getActionByUuid, getEventByModelUuid, getTriggerByUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); @@ -96,7 +100,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) } useEffect(() => { - if (isPlaying || selectedPath === "auto") { + if (isPlaying && selectedPath === "auto") { if (!agvDetail.point.action.unLoadPoint || !agvDetail.point.action.pickUpPoint) return; if (!agvDetail.isActive && agvDetail.state === 'idle' && currentPhase === 'stationed') { @@ -223,6 +227,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) if (agvDetail.point.action.triggers.length > 0) { const trigger = getTriggerByUuid(selectedProduct.productUuid, agvDetail.point.action.triggers[0]?.triggerUuid); const model = getEventByModelUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredModel?.modelUuid || ''); + const triggeredAction = getActionByUuid(selectedProduct.productUuid, trigger?.triggeredAsset?.triggeredAction?.actionUuid || ''); if (trigger && model) { if (model.type === 'transfer') { @@ -244,8 +249,8 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) } } else if (model.type === 'human') { const action = getActionByUuid(selectedProduct.productUuid, agvDetail.point.action.actionUuid); - if (action) { - handleMaterialDropToHuman(model); + if (action && (triggeredAction?.actionType === 'assembly' || triggeredAction?.actionType === 'worker')) { + handleMaterialDropToHuman(model, triggeredAction); } } } else { @@ -260,75 +265,56 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>) } } - function handleMaterialDropToHuman(model: HumanEventSchema) { + function handleMaterialDropToHuman(model: HumanEventSchema, action: HumanAction) { + if (model) { - if (model.point.action.actionType === 'worker') { - loopMaterialDropToHuman( - agvDetail.modelUuid, - agvDetail.currentLoad, - agvDetail.point.action.unLoadDuration, - model.modelUuid, - model.point.action.loadCapacity, - agvDetail.point.action - ); + if (action.actionType === 'worker') { + addHumanToMonitor(model.modelUuid, () => { + loopMaterialDropToHuman( + agvDetail, + model.modelUuid, + agvDetail.point.action, + action.actionUuid + ); + }, action.actionUuid || '') } } } function loopMaterialDropToHuman( - vehicleId: string, - vehicleCurrentLoad: number, - unLoadDuration: number, + vehicle: VehicleStatus, humanId: string, - storageMaxCapacity: number, - action: VehicleAction + vehicleAction: VehicleAction, + humanActionId: string ) { - startTime = performance.now(); - const fixedInterval = ((unLoadDuration / vehicleCurrentLoad) * (1000 / isSpeedRef.current)); + let currentVehicleLoad = vehicle.currentLoad; const unloadLoop = () => { - if (isPausedRef.current) { - pauseTimeRef.current ??= performance.now(); - requestAnimationFrame(unloadLoop); - return; - } - - if (pauseTimeRef.current) { - const pauseDuration = performance.now() - pauseTimeRef.current; - startTime += pauseDuration; - pauseTimeRef.current = null; - } - - const elapsedTime = performance.now() - startTime; const human = getHumanById(humanId); + const humanAsset = getAssetById(humanId); + const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId); - if (elapsedTime >= fixedInterval) { - if (human && agvDetail && - human.currentLoad < storageMaxCapacity && - vehicleCurrentLoad > 0) { + if (!human || human.currentAction?.actionUuid !== humanAction?.actionUuid) return; - decrementVehicleLoad(vehicleId, 1); - vehicleCurrentLoad -= 1; - - const material = removeLastMaterial(vehicleId); - if (material) { - - triggerPointActions(action, material.materialId); - - } - - if (vehicleCurrentLoad > 0 && human.currentLoad < storageMaxCapacity) { - startTime = performance.now(); - requestAnimationFrame(unloadLoop); - } + if (humanAsset && human.currentMaterials.length > 0 && humanAsset.animationState?.current === 'pickup' && humanAsset.animationState?.isCompleted) { + decrementVehicleLoad(vehicle.modelUuid, 1); + currentVehicleLoad -= 1; + const material = removeLastMaterial(vehicle.modelUuid); + if (material) { + setIsVisible(material.materialId, false); } - } else { - requestAnimationFrame(unloadLoop); + } else if (!human.isActive && human.currentLoad < (humanAction?.loadCapacity || 0) && humanAsset?.animationState?.current === 'waiting') { + setCurrentAnimation(human.modelUuid, 'pickup', true, false, false); } + setTimeout(() => { + requestAnimationFrame(unloadLoop); + }, 150) }; const human = getHumanById(humanId); - if (human && vehicleCurrentLoad > 0 && human?.currentLoad < storageMaxCapacity) { + const humanAction = human?.point.actions.find((action) => action.actionUuid === humanActionId); + if (human && human.currentAction?.actionUuid !== humanActionId && human.currentLoad < (humanAction?.loadCapacity || 0)) { + addCurrentAction(humanId, humanActionId); unloadLoop(); } } diff --git a/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx index 3c14ea1..ff07ee9 100644 --- a/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/navMesh.tsx @@ -1,25 +1,32 @@ import { useRef } from "react"; -import { useNavMesh } from "../../../../store/builder/store"; -import PolygonGenerator from "./polygonGenerator"; -import NavMeshDetails from "./navMeshDetails"; import * as CONSTANTS from "../../../../types/world/worldConstants"; import * as Types from "../../../../types/world/worldTypes"; +import { useLoadingProgress, useNavMesh, useTileDistance } from "../../../../store/builder/store"; +import useModuleStore from "../../../../store/useModuleStore"; +import PolygonGenerator from "./polygonGenerator"; +import NavMeshDetails from "./navMeshDetails"; function NavMesh() { let groupRef = useRef() as Types.RefGroup; const { setNavMesh } = useNavMesh(); + const { loadingProgress } = useLoadingProgress(); + const { activeModule } = useModuleStore(); + const { planeValue, gridValue } = useTileDistance(); return ( <> - - + {activeModule === 'simulation' && loadingProgress === 0 && + <> + + - - - - - - + + + + + + + } ) } diff --git a/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx index e0579a0..10da010 100644 --- a/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/navMeshDetails.tsx @@ -1,10 +1,9 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useMemo } from "react"; import * as THREE from "three"; import { useThree } from "@react-three/fiber"; import { generateSoloNavMesh } from "@recast-navigation/generators"; import { init as initRecastNavigation } from "@recast-navigation/core"; import { DebugDrawer, getPositionsAndIndices } from "@recast-navigation/three"; -import { useSceneContext } from "../../../scene/sceneContext"; import { useToggleView } from "../../../../store/builder/store"; interface NavMeshDetailsProps { @@ -12,45 +11,48 @@ interface NavMeshDetailsProps { groupRef: React.MutableRefObject; } +const NAVMESH_CONFIG = { + + // cellSize: 0.2, + // cellHeight: 0.7, + // walkableRadius: 0.5, + + cellSize: 0.3, + cellHeight: 0.7, + walkableRadius: 0.7, +}; + export default function NavMeshDetails({ setNavMesh, groupRef, }: NavMeshDetailsProps) { - const { aisleStore, wallStore } = useSceneContext(); - const { aisles } = aisleStore(); const { scene } = useThree(); - const { walls } = wallStore(); const { toggleView } = useToggleView(); + const meshes = useMemo(() => { + return groupRef.current?.children.filter((child): child is THREE.Mesh => + child instanceof THREE.Mesh + ) || []; + }, [groupRef.current?.children]); + useEffect(() => { - if (toggleView) return; + if (toggleView || meshes.length === 0) return; + const initializeNavigation = async () => { try { await initRecastNavigation(); - if (!groupRef.current || groupRef.current.children.length === 0) { - return; - } - - const meshes = groupRef?.current?.children as THREE.Mesh[]; const [positions, indices] = getPositionsAndIndices(meshes); - // const cellSize = 0.2; - // const cellHeight = 0.7; - // const walkableRadius = 0.5; + const { cellSize, cellHeight, walkableRadius } = NAVMESH_CONFIG; - const cellSize = 0.3; - const cellHeight = 0.7; - const walkableRadius = 0.7; const { success, navMesh } = generateSoloNavMesh(positions, indices, { cs: cellSize, ch: cellHeight, walkableRadius: Math.round(walkableRadius / cellHeight), }); - if (!success || !navMesh) { - return; - } + if (!success || !navMesh) return; setNavMesh(navMesh); @@ -62,12 +64,12 @@ export default function NavMeshDetails({ debugDrawer.drawNavMesh(navMesh); // scene.add(debugDrawer); } catch (error) { - echo.error("Failed to initialize navigation") + console.error("Failed to initialize navigation:", error); } }; initializeNavigation(); - }, [scene, groupRef, aisles, walls, toggleView]); + }, [meshes, setNavMesh, toggleView, scene]); return null; } diff --git a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx index 9ce9ea9..19e9482 100644 --- a/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx +++ b/app/src/modules/simulation/vehicle/navMesh/polygonGenerator.tsx @@ -76,42 +76,18 @@ export default function PolygonGenerator({ turf.lineString(line.map((p: any) => p?.position)) ); - const validLineFeatures = lineFeatures.map(ls => { - const coords = ls.geometry.coordinates.map(coord => coord.join(',')); - - if (coords.length < 2) return null; - - const start = coords[0]; - const end = coords[coords.length - 1]; - const middle = coords.slice(1, -1); - - const seen = new Set([start, end]); - const filteredMiddle: string[] = []; - - for (const point of middle) { - if (!seen.has(point)) { - seen.add(point); - filteredMiddle.push(point); - } + let validLineFeatures = lineFeatures.filter((line) => { + const coords = line.geometry.coordinates; + return coords.length >= 2; + }).filter((line) => { + if (line.geometry.coordinates[0].toString() !== line.geometry.coordinates[1].toString()) { + return true; } + }) - const newCoords = [start, ...filteredMiddle, end]; + if (validLineFeatures.length < 3) { validLineFeatures = [] } - if (newCoords.length >= 4) { - const resultCoords = newCoords.map(str => str.split(',').map(Number)); - return { - ...ls, - geometry: { - ...ls.geometry, - coordinates: resultCoords, - }, - }; - } - - return null; - }).filter(Boolean); - - const polygons = turf.polygonize(turf.featureCollection(validLineFeatures as any) as any); + const polygons = turf.polygonize(turf.featureCollection(validLineFeatures)); renderWallGeometry(wallPoints); diff --git a/app/src/pages/Project.tsx b/app/src/pages/Project.tsx index b257521..1df03f7 100644 --- a/app/src/pages/Project.tsx +++ b/app/src/pages/Project.tsx @@ -4,10 +4,8 @@ import { useSocketStore, useOrganization, useUserName, - useWallItems, useSaveVersion, useProjectName, - useZones, useActiveTool, } from "../store/builder/store"; import { useNavigate, useParams } from "react-router-dom"; @@ -36,8 +34,6 @@ const Project: React.FC = () => { const { setActiveModule } = useModuleStore(); const { setUserName } = useUserName(); const { setOrganization } = useOrganization(); - const { setWallItems } = useWallItems(); - const { setZones } = useZones(); const { isVersionSaved } = useSaveVersion(); const { projectId } = useParams(); const { setProjectName } = useProjectName(); @@ -110,8 +106,6 @@ const Project: React.FC = () => { }, [isVersionSaved]); useEffect(() => { - setWallItems([]); - setZones([]); setActiveModule("builder"); if (email) { const token = localStorage.getItem("token"); diff --git a/app/src/store/builder/store.ts b/app/src/store/builder/store.ts index e62449b..12c231a 100644 --- a/app/src/store/builder/store.ts +++ b/app/src/store/builder/store.ts @@ -1,4 +1,3 @@ -import * as THREE from "three"; import { create } from "zustand"; import { io } from "socket.io-client"; import * as CONSTANTS from "../../types/world/worldConstants"; @@ -146,39 +145,11 @@ export const useToggleView = create((set: any) => ({ setToggleView: (x: any) => set(() => ({ toggleView: x })), })); -export const useUpdateScene = create((set: any) => ({ - updateScene: false, - setUpdateScene: (x: any) => set(() => ({ updateScene: x })), -})); - -export const useWalls = create((set: any) => ({ - walls: [], - setWalls: (x: any) => set(() => ({ walls: x })), -})); - export const useRoomsState = create((set: any) => ({ roomsState: [], setRoomsState: (x: any) => set(() => ({ roomsState: x })), })); -export const useZones = create((set: any) => ({ - zones: [], - setZones: (callback: any) => - set((state: any) => ({ - zones: typeof callback === "function" ? callback(state.zones) : callback, - })), -})); - -interface ZonePointsState { - zonePoints: THREE.Vector3[]; - setZonePoints: (points: THREE.Vector3[]) => void; -} - -export const useZonePoints = create((set) => ({ - zonePoints: [], - setZonePoints: (points) => set({ zonePoints: points }), -})); - export const useSelectedItem = create((set: any) => ({ selectedItem: { name: "", @@ -215,45 +186,11 @@ export const useMenuVisible = create((set: any) => ({ setMenuVisible: (x: any) => set(() => ({ menuVisible: x })), })); -// export const useDeleteTool = create((set: any) => ({ -// deleteTool: false, -// setDeleteTool: (x: any) => set(() => ({ deleteTool: x })), -// })); - export const useToolMode = create((set: any) => ({ toolMode: null, setToolMode: (x: any) => set(() => ({ toolMode: x })), })); -export const useNewLines = create((set: any) => ({ - newLines: [], - setNewLines: (x: any) => set(() => ({ newLines: x })), -})); - -export const useDeletedLines = create((set: any) => ({ - deletedLines: [], - setDeletedLines: (x: any) => set(() => ({ deletedLines: x })), -})); - -export const useMovePoint = create((set: any) => ({ - movePoint: false, - setMovePoint: (x: any) => set(() => ({ movePoint: x })), -})); - -// export const useDeletePointOrLine = create((set: any) => ({ -// deletePointOrLine: false, -// setDeletePointOrLine: (x: any) => set(() => ({ deletePointOrLine: x })), -// })); - -export const useWallItems = create((set: any) => ({ - wallItems: [], - setWallItems: (callback: any) => - set((state: any) => ({ - wallItems: - typeof callback === "function" ? callback(state.wallItems) : callback, - })), -})); - export const useSelectedWallItem = create((set: any) => ({ selectedWallItem: null, setSelectedWallItem: (x: any) => set(() => ({ selectedWallItem: x })), @@ -315,24 +252,6 @@ export const useActiveLayer = create((set: any) => ({ setActiveLayer: (x: any) => set({ activeLayer: x }), })); -interface RefTextUpdateState { - refTextupdate: number; - setRefTextUpdate: ( - callback: (currentValue: number) => number | number - ) => void; -} - -export const useRefTextUpdate = create((set) => ({ - refTextupdate: -1000, - setRefTextUpdate: (callback) => - set((state) => ({ - refTextupdate: - typeof callback === "function" - ? callback(state.refTextupdate) - : callback, - })), -})); - export const useResetCamera = create((set: any) => ({ resetCamera: false, setResetCamera: (x: any) => set({ resetCamera: x }), @@ -353,11 +272,6 @@ export const useActiveSubTool = create((set: any) => ({ setActiveSubTool: (x: any) => set({ activeSubTool: x }), })); -export const use2DUndoRedo = create((set: any) => ({ - is2DUndoRedo: null, - set2DUndoRedo: (x: any) => set({ is2DUndoRedo: x }), -})); - export const useElevation = create((set: any) => ({ elevation: 45, setElevation: (x: any) => set({ elevation: x }), @@ -434,21 +348,6 @@ export const useDrieUIValue = create((set: any) => ({ })), })); -export const useStartSimulation = create((set: any) => ({ - startSimulation: false, - setStartSimulation: (x: any) => set({ startSimulation: x }), -})); - -export const useEyeDropMode = create((set: any) => ({ - eyeDropMode: false, - setEyeDropMode: (x: any) => set({ eyeDropMode: x }), -})); - -export const useEditingPoint = create((set: any) => ({ - editingPoint: false, - setEditingPoint: (x: any) => set({ editingPoint: x }), -})); - export const usezoneTarget = create((set: any) => ({ zoneTarget: [], setZoneTarget: (x: any) => set({ zoneTarget: x }), diff --git a/app/src/store/simulation/useHumanStore.ts b/app/src/store/simulation/useHumanStore.ts index 9cd52e0..a6e84f8 100644 --- a/app/src/store/simulation/useHumanStore.ts +++ b/app/src/store/simulation/useHumanStore.ts @@ -12,6 +12,9 @@ interface HumansStore { ) => void; clearHumans: () => void; + addCurrentAction: (modelUuid: string, actionUuid: string) => void; + removeCurrentAction: (modelUuid: string) => void; + setHumanActive: (modelUuid: string, isActive: boolean) => void; setHumanScheduled: (modelUuid: string, isPicking: boolean) => void; setHumanLoad: (modelUuid: string, load: number) => void; @@ -22,6 +25,11 @@ interface HumansStore { incrementHumanLoad: (modelUuid: string, incrementBy: number) => void; decrementHumanLoad: (modelUuid: string, decrementBy: number) => void; + incrementLoadCount: (modelUuid: string, incrementBy: number) => void; + decrementLoadCount: (modelUuid: string, decrementBy: number) => void; + + clearLoadCount: (modelUuid: string) => void; + addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void; setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string }[]) => void; removeLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined; @@ -54,6 +62,7 @@ export const createHumanStore = () => { isScheduled: false, idleTime: 0, activeTime: 0, + totalLoadCount: 0, currentLoad: 0, currentMaterials: [], distanceTraveled: 0 @@ -83,6 +92,30 @@ export const createHumanStore = () => { }); }, + addCurrentAction: (modelUuid, actionUuid) => { + set((state) => { + const human = state.humans.find(h => h.modelUuid === modelUuid); + if (human) { + const action = human.point.actions.find(h => h.actionUuid === actionUuid); + if (action) { + human.currentAction = { + actionUuid: action.actionUuid, + actionName: action.actionName + }; + } + } + }); + }, + + removeCurrentAction: (modelUuid) => { + set((state) => { + const human = state.humans.find(h => h.modelUuid === modelUuid); + if (human) { + human.currentAction = undefined; + } + }); + }, + setHumanActive: (modelUuid, isActive) => { set((state) => { const human = state.humans.find(h => h.modelUuid === modelUuid); @@ -137,6 +170,33 @@ export const createHumanStore = () => { }); }, + incrementLoadCount: (modelUuid, incrementBy) => { + set((state) => { + const human = state.humans.find(h => h.modelUuid === modelUuid); + if (human) { + human.totalLoadCount += incrementBy; + } + }); + }, + + decrementLoadCount: (modelUuid, decrementBy) => { + set((state) => { + const human = state.humans.find(h => h.modelUuid === modelUuid); + if (human) { + human.totalLoadCount -= decrementBy; + } + }); + }, + + clearLoadCount: (modelUuid) => { + set((state) => { + const human = state.humans.find(h => h.modelUuid === modelUuid); + if (human) { + human.totalLoadCount = 0; + } + }); + }, + addCurrentMaterial: (modelUuid, materialType, materialId) => { set((state) => { const human = state.humans.find(h => h.modelUuid === modelUuid); diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts index a500d9a..98a0928 100644 --- a/app/src/store/simulation/useMaterialStore.ts +++ b/app/src/store/simulation/useMaterialStore.ts @@ -36,6 +36,8 @@ type MaterialsStore = { } | null ) => MaterialSchema | undefined; + clearLocations: (materialId: string) => void; + setMaterial: (materialId: string, materialType: string) => MaterialSchema | undefined; setStartTime: (materialId: string, startTime: number) => MaterialSchema | undefined; setEndTime: (materialId: string, endTime: number) => MaterialSchema | undefined; @@ -140,6 +142,18 @@ export const createMaterialStore = () => { return updatedMaterial; }, + clearLocations: (materialId) => { + let updatedMaterial: MaterialSchema | undefined; + set((state) => { + const material = state.materials.find(m => m.materialId === materialId); + if (material) { + delete material.previous; + delete material.next; + updatedMaterial = JSON.parse(JSON.stringify(material)); + } + }); + return updatedMaterial; + }, setMaterial: (materialId, materialType) => { let updatedMaterial: MaterialSchema | undefined; set((state) => { diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index aa75d68..258a8cb 100644 --- a/app/src/store/simulation/useProductStore.ts +++ b/app/src/store/simulation/useProductStore.ts @@ -32,13 +32,13 @@ type ProductsStore = { productUuid: string, modelUuid: string, pointUuid: string, - action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action'] + action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0] ) => EventsSchema | undefined; removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined; updateAction: ( productUuid: string, actionUuid: string, - updates: Partial + updates: Partial ) => EventsSchema | undefined; // Trigger-level actionss @@ -66,8 +66,8 @@ type ProductsStore = { getEventByTriggerUuid: (productUuid: string, triggerUuid: string) => EventsSchema | undefined; getEventByPointUuid: (productUuid: string, pointUuid: string) => EventsSchema | undefined; getPointByUuid: (productUuid: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema | undefined; - getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']) | undefined; - getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action']) | undefined; + getActionByUuid: (productUuid: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]) | undefined; + getActionByPointUuid: (productUuid: string, pointUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['actions'][0]) | undefined; getModelUuidByPointUuid: (productUuid: string, actionUuid: string) => (string) | undefined; getModelUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined; getPointUuidByActionUuid: (productUuid: string, actionUuid: string) => (string) | undefined; diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index 12ca294..8459eea 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -73,11 +73,12 @@ interface HumanAction { actionUuid: string; actionName: string; actionType: "worker" | "assembly"; - processTime?: number; + processTime: number; swapMaterial?: string; assemblyPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; } pickUpPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; } dropPoint?: { position: [number, number, number] | null; rotation: [number, number, number] | null; } + loadCount: number; loadCapacity: number; triggers: TriggerSchema[]; } @@ -124,7 +125,7 @@ interface HumanPointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - action: HumanAction; + actions: HumanAction[]; } type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema; @@ -227,15 +228,13 @@ interface HumanStatus extends HumanEventSchema { isScheduled: boolean; idleTime: number; activeTime: number; + totalLoadCount: number; currentLoad: number; currentMaterials: { materialType: string; materialId: string; }[]; distanceTraveled: number; currentAction?: { actionUuid: string; actionName: string; - animationUuid: string; - materialType?: string | null; - materialId?: string | null; }; }