From 98f4d48db292017ee3029f677bad0dbbac8b3e59 Mon Sep 17 00:00:00 2001 From: Jerald-Golden-B Date: Thu, 3 Jul 2025 12:11:58 +0530 Subject: [PATCH] feat: Refactor human action handling to support animated travel and streamline action structure --- .../mechanics/humanMechanics.tsx | 226 ++++-------------- app/src/modules/builder/asset/assetsGroup.tsx | 27 +-- .../builder/asset/functions/addAssetModel.ts | 27 +-- .../actionHandler/useAnimationHandler.ts | 34 --- .../actions/human/useHumanActions.ts | 11 +- .../simulation/actions/useActionHandler.ts | 2 +- .../triggerConnections/triggerConnector.tsx | 6 +- app/src/store/simulation/useHumanStore.ts | 14 -- app/src/store/simulation/useProductStore.ts | 4 +- app/src/types/simulationTypes.d.ts | 6 +- 10 files changed, 75 insertions(+), 282 deletions(-) delete mode 100644 app/src/modules/simulation/actions/human/actionHandler/useAnimationHandler.ts diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx index 8c5a348..d07022a 100644 --- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx +++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/humanMechanics.tsx @@ -1,31 +1,25 @@ import { useEffect, useState } from "react"; -import { MathUtils } from "three"; import InputWithDropDown from "../../../../../ui/inputs/InputWithDropDown"; import RenameInput from "../../../../../ui/inputs/RenameInput"; import LabledDropdown from "../../../../../ui/inputs/LabledDropdown"; import Trigger from "../trigger/Trigger"; import { useSelectedEventData, useSelectedAction } from "../../../../../../store/simulation/useSimulationStore"; import PickAndPlaceAction from "../actions/PickAndPlaceAction"; -import ActionsList from "../components/ActionsList"; import { upsertProductOrEventApi } from "../../../../../../services/simulation/products/UpsertProductOrEventApi"; import { useProductContext } from "../../../../../../modules/simulation/products/productContext"; import { useParams } from "react-router-dom"; import { useVersionContext } from "../../../../../../modules/builder/version/versionContext"; import { useSceneContext } from "../../../../../../modules/scene/sceneContext"; -import InputToggle from "../../../../../ui/inputs/InputToggle"; +import ActionsList from "../components/ActionsList"; function HumanMechanics() { - const [activeOption, setActiveOption] = useState<"animation" | "animatedTravel">("animation"); - const [activeAnimationOption, setActiveAnimationOption] = useState(""); - const [animationOptions, setAnimationOptions] = useState([]); + const [activeOption, setActiveOption] = useState<"animatedTravel">("animatedTravel"); const [speed, setSpeed] = useState("0.5"); const [currentAction, setCurrentAction] = useState(); - const [isLoopAnimation, setIsLoopAnimation] = useState(false); const [selectedPointData, setSelectedPointData] = useState(); const { selectedEventData } = useSelectedEventData(); - const { productStore, assetStore } = useSceneContext(); - const { getAssetById } = assetStore(); - const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction, addAction, removeAction } = productStore(); + const { productStore } = useSceneContext(); + const { getPointByUuid, getEventByModelUuid, updateEvent, updateAction } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const { selectedAction, setSelectedAction, clearSelectedAction } = useSelectedAction(); @@ -41,15 +35,10 @@ function HumanMechanics() { selectedEventData.selectedPoint ) as HumanPointSchema | undefined; - if (point?.actions) { + if (point?.action) { setSelectedPointData(point); - if (point.actions.length > 0) { - setSelectedAction(point.actions[0].actionUuid, point.actions[0].actionName); - const asset = getAssetById(selectedEventData.data.modelUuid); - if (asset && asset.animations) { - setAnimationOptions(asset.animations) - } - } + const action = point.action; + setSelectedAction(action.actionUuid, action.actionName); } } else { clearSelectedAction(); @@ -73,15 +62,11 @@ function HumanMechanics() { selectedEventData.selectedPoint ) as HumanPointSchema | undefined; - if (point?.actions) { + if (point?.action) { setSelectedPointData(point); - const action = point.actions.find((a) => a.actionUuid === selectedAction.actionId); - if (action) { - setCurrentAction(action); - setIsLoopAnimation(action.loopAnimation ?? false); - setActiveOption(action.actionType as "animation" | "animatedTravel"); - setActiveAnimationOption(action.animation || '') - } + const action = point.action; + setCurrentAction(action); + setActiveOption(action.actionType as "animatedTravel"); } } else { clearSelectedAction(); @@ -106,73 +91,18 @@ function HumanMechanics() { }; const handleSelectActionType = (actionType: string) => { - if (!selectedAction.actionId) return; - setActiveOption(actionType as "animation" | "animatedTravel"); + if (!currentAction) return; + setActiveOption(actionType as "animatedTravel"); const event = updateAction( selectedProduct.productUuid, - selectedAction.actionId, - { actionType: actionType as "animation" | "animatedTravel" } + currentAction.actionUuid, + { actionType: actionType as "animatedTravel" } ); - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, actionType: actionType as "animation" | "animatedTravel" } - : action - ); - setSelectedPointData({ ...selectedPointData, actions: updatedActions }); - } - - if (event) { - updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); - } - } - - const handleSelectAnimation = (animationOption: string) => { - if (!selectedAction.actionId) return; - setActiveAnimationOption(animationOption); - - const event = updateAction( - selectedProduct.productUuid, - selectedAction.actionId, - { animation: animationOption } - ); - - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, animation: animationOption } - : action - ); - setSelectedPointData({ ...selectedPointData, actions: updatedActions }); - } - - if (event) { - updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); - } - } - - const handleLoopAnimationChange = () => { - if (!selectedAction.actionId || !currentAction) return; - - const updatedValue = !isLoopAnimation; - setIsLoopAnimation(updatedValue); - - const event = updateAction( - selectedProduct.productUuid, - selectedAction.actionId, - { loopAnimation: updatedValue } - ); - - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, loopAnimation: updatedValue } - : action - ); - setSelectedPointData({ ...selectedPointData, actions: updatedActions }); - setCurrentAction(updatedActions.find((a) => a.actionUuid === selectedAction.actionId)); + if (event && selectedPointData) { + const updatedAction = { ...selectedPointData.action, actionType: actionType as "animatedTravel" }; + setSelectedPointData({ ...selectedPointData, action: updatedAction }); } if (event) { @@ -181,20 +111,17 @@ function HumanMechanics() { }; const handleRenameAction = (newName: string) => { - if (!selectedAction.actionId) return; + if (!currentAction) return; + const event = updateAction( selectedProduct.productUuid, - selectedAction.actionId, + currentAction.actionUuid, { actionName: newName } ); - if (selectedPointData) { - const updatedActions = selectedPointData.actions.map((action) => - action.actionUuid === selectedAction.actionId - ? { ...action, actionName: newName } - : action - ); - setSelectedPointData({ ...selectedPointData, actions: updatedActions }); + if (event && selectedPointData) { + const updatedAction = { ...selectedPointData.action, actionName: newName }; + setSelectedPointData({ ...selectedPointData, action: updatedAction }); } if (event) { @@ -217,11 +144,11 @@ function HumanMechanics() { }; const handleClearPoints = () => { - if (!selectedAction.actionId || !selectedPointData) return; + if (!currentAction) return; const event = updateAction( selectedProduct.productUuid, - selectedAction.actionId, + currentAction.actionUuid, { travelPoints: { startPoint: null, @@ -235,66 +162,9 @@ function HumanMechanics() { } }; - const handleAddAction = () => { - if (!selectedEventData || !selectedPointData) return; - - const newAction: HumanAction = { - actionUuid: MathUtils.generateUUID(), - actionName: `Action ${selectedPointData.actions.length + 1}`, - actionType: "animation", - animation: null, - loadCapacity: 1, - loopAnimation: true, - travelPoints: { - startPoint: null, - endPoint: null, - }, - triggers: [], - }; - - const event = addAction( - selectedProduct.productUuid, - selectedEventData.data.modelUuid, - selectedEventData.selectedPoint, - newAction - ); - - if (event) { - updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); - } - - const updatedPoint = { ...selectedPointData, actions: [...selectedPointData.actions, newAction] }; - setSelectedPointData(updatedPoint); - setSelectedAction(newAction.actionUuid, newAction.actionName); - }; - - const handleDeleteAction = (actionUuid: string) => { - if (!selectedPointData) return; - - const event = removeAction(selectedProduct.productUuid, actionUuid); - - if (event) { - updateBackend(selectedProduct.productName, selectedProduct.productUuid, projectId || '', event); - } - - const index = selectedPointData.actions.findIndex((a) => a.actionUuid === actionUuid); - const newActions = selectedPointData.actions.filter((a) => a.actionUuid !== actionUuid); - const updatedPoint = { ...selectedPointData, actions: newActions }; - setSelectedPointData(updatedPoint); - - if (selectedAction.actionId === actionUuid) { - const nextAction = newActions[index] || newActions[index - 1]; - if (nextAction) { - setSelectedAction(nextAction.actionUuid, nextAction.actionName); - } else { - clearSelectedAction(); - } - } - }; - const availableActions = { defaultOption: "animatedTravel", - options: ["animation", "animatedTravel"], + options: ["animatedTravel"], }; return ( @@ -316,19 +186,20 @@ function HumanMechanics() { -
- - {selectedAction.actionId && currentAction && ( + {currentAction && ( +
+ + { }} + handleDeleteAction={() => { }} + />
@@ -340,32 +211,19 @@ function HumanMechanics() { onSelect={handleSelectActionType} disabled={true} /> - - - {activeOption === 'animatedTravel' && + {activeOption === 'animatedTravel' && ( - } + )}
- )} -
+
+ )} ); } diff --git a/app/src/modules/builder/asset/assetsGroup.tsx b/app/src/modules/builder/asset/assetsGroup.tsx index 461bf50..fbc2738 100644 --- a/app/src/modules/builder/asset/assetsGroup.tsx +++ b/app/src/modules/builder/asset/assetsGroup.tsx @@ -256,21 +256,18 @@ 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], - actions: [ - { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "animation", - animation: null, - loopAnimation: true, - loadCapacity: 1, - travelPoints: { - startPoint: null, - endPoint: null, - }, - triggers: [] - } - ] + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "animatedTravel", + loadCapacity: 1, + travelPoints: { + startPoint: null, + endPoint: null, + }, + triggers: [] + } + } } addEvent(humanEvent); diff --git a/app/src/modules/builder/asset/functions/addAssetModel.ts b/app/src/modules/builder/asset/functions/addAssetModel.ts index 47274a2..471314f 100644 --- a/app/src/modules/builder/asset/functions/addAssetModel.ts +++ b/app/src/modules/builder/asset/functions/addAssetModel.ts @@ -374,21 +374,18 @@ async function handleModelLoad( uuid: THREE.MathUtils.generateUUID(), position: [data.points[0].x, data.points[0].y, data.points[0].z], rotation: [0, 0, 0], - actions: [ - { - actionUuid: THREE.MathUtils.generateUUID(), - actionName: "Action 1", - actionType: "animation", - animation: null, - loopAnimation: true, - loadCapacity: 1, - travelPoints: { - startPoint: null, - endPoint: null, - }, - triggers: [] - } - ] + action: { + actionUuid: THREE.MathUtils.generateUUID(), + actionName: "Action 1", + actionType: "animatedTravel", + loadCapacity: 1, + travelPoints: { + startPoint: null, + endPoint: null, + }, + triggers: [] + } + } } addEvent(humanEvent); diff --git a/app/src/modules/simulation/actions/human/actionHandler/useAnimationHandler.ts b/app/src/modules/simulation/actions/human/actionHandler/useAnimationHandler.ts deleted file mode 100644 index eb0ed6a..0000000 --- a/app/src/modules/simulation/actions/human/actionHandler/useAnimationHandler.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useCallback } from "react"; -import { useSceneContext } from "../../../../scene/sceneContext"; -import { useProductContext } from "../../../products/productContext"; - -export function useAnimationHandler() { - const { materialStore, humanStore, productStore } = useSceneContext(); - const { getMaterialById } = materialStore(); - const { } = humanStore(); - const { getModelUuidByActionUuid } = productStore(); - const { selectedProductStore } = useProductContext(); - const { selectedProduct } = selectedProductStore(); - - const animationLogStatus = (materialUuid: string, status: string) => { - echo.info(`${materialUuid}, ${status}`); - } - - const handleAnimation = useCallback((action: HumanAction, materialId?: string) => { - if (!action || action.actionType !== 'animation' || !materialId) return; - - const material = getMaterialById(materialId); - if (!material) return; - - const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid); - if (!modelUuid) return; - - - animationLogStatus(material.materialName, `performing animation`); - - }, [getMaterialById]); - - return { - handleAnimation, - }; -} \ No newline at end of file diff --git a/app/src/modules/simulation/actions/human/useHumanActions.ts b/app/src/modules/simulation/actions/human/useHumanActions.ts index b355ff6..96e40b0 100644 --- a/app/src/modules/simulation/actions/human/useHumanActions.ts +++ b/app/src/modules/simulation/actions/human/useHumanActions.ts @@ -1,15 +1,9 @@ import { useEffect, useCallback } from 'react'; -import { useAnimationHandler } from './actionHandler/useAnimationHandler'; import { useAnimatedTravelHandler } from './actionHandler/useAnimatedTravelHandler'; export function useHumanActions() { - const { handleAnimation } = useAnimationHandler(); const { handleAnimatedTravel } = useAnimatedTravelHandler(); - const handleAnimationAction = useCallback((action: HumanAction, materialId: string) => { - handleAnimation(action, materialId); - }, [handleAnimation]); - const handleAnimatedTravelAction = useCallback((action: HumanAction) => { handleAnimatedTravel(action); }, [handleAnimatedTravel]); @@ -18,16 +12,13 @@ export function useHumanActions() { if (!action) return; switch (action.actionType) { - case 'animation': - handleAnimationAction(action, materialId); - break; case 'animatedTravel': handleAnimatedTravelAction(action); break; default: console.warn(`Unknown Human action type: ${action.actionType}`); } - }, [handleAnimationAction, handleAnimatedTravelAction]); + }, [handleAnimatedTravelAction]); const cleanup = useCallback(() => { }, []); diff --git a/app/src/modules/simulation/actions/useActionHandler.ts b/app/src/modules/simulation/actions/useActionHandler.ts index 099e200..aef8d39 100644 --- a/app/src/modules/simulation/actions/useActionHandler.ts +++ b/app/src/modules/simulation/actions/useActionHandler.ts @@ -39,7 +39,7 @@ export function useActionHandler() { case 'store': case 'retrieve': handleStorageAction(action as StorageAction, materialId as string); break; - case 'animation': case 'animatedTravel': + case 'animatedTravel': handleHumanAction(action as HumanAction, materialId as string); break; default: diff --git a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx index 918007a..ec7406c 100644 --- a/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx +++ b/app/src/modules/simulation/events/triggerConnections/triggerConnector.tsx @@ -155,8 +155,8 @@ function TriggerConnector() { // Handle Human point else if (event.type === "human" && 'point' in event) { const point = event.point; - point.actions?.forEach(action => { - action.triggers?.forEach(trigger => { + if (point.action?.triggers) { + point.action.triggers.forEach(trigger => { if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) { newConnections.push({ id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`, @@ -166,7 +166,7 @@ function TriggerConnector() { }); } }); - }); + } } }); diff --git a/app/src/store/simulation/useHumanStore.ts b/app/src/store/simulation/useHumanStore.ts index 75b9c7d..a7ed7d5 100644 --- a/app/src/store/simulation/useHumanStore.ts +++ b/app/src/store/simulation/useHumanStore.ts @@ -24,11 +24,6 @@ interface HumansStore { getLastMaterial: (modelUuid: string) => { materialType: string; materialId: string } | undefined; clearCurrentMaterials: (modelUuid: string) => void; - setCurrentAction: ( - modelUuid: string, - action: HumanStatus["currentAction"] - ) => void; - incrementActiveTime: (modelUuid: string, incrementBy: number) => void; incrementIdleTime: (modelUuid: string, incrementBy: number) => void; incrementDistanceTraveled: (modelUuid: string, incrementBy: number) => void; @@ -175,15 +170,6 @@ export const createHumanStore = () => { }); }, - setCurrentAction: (modelUuid, action) => { - set((state) => { - const human = state.humans.find(h => h.modelUuid === modelUuid); - if (human) { - human.currentAction = action; - } - }); - }, - incrementActiveTime: (modelUuid, incrementBy) => { set((state) => { const human = state.humans.find(h => h.modelUuid === modelUuid); diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts index 18d636b..3b483ea 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['actions'][0] + action: ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action'] | HumanPointSchema['action'] ) => EventsSchema | undefined; removeAction: (productUuid: string, actionUuid: string) => EventsSchema | undefined; updateAction: ( productUuid: string, actionUuid: string, - updates: Partial + updates: Partial ) => EventsSchema | undefined; // Trigger-level actionss diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts index be7cf16..2192101 100644 --- a/app/src/types/simulationTypes.d.ts +++ b/app/src/types/simulationTypes.d.ts @@ -72,9 +72,7 @@ interface StorageAction { interface HumanAction { actionUuid: string; actionName: string; - actionType: "animation" | "animatedTravel"; - animation: string | null; - loopAnimation: boolean; + actionType: "animatedTravel"; loadCapacity: number; travelPoints?: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; } triggers: TriggerSchema[]; @@ -122,7 +120,7 @@ interface HumanPointSchema { uuid: string; position: [number, number, number]; rotation: [number, number, number]; - actions: HumanAction[]; + action: HumanAction; } type PointsScheme = | ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | HumanPointSchema;