Implement storage retrieval functionality: add useRetrieveHandler, update action handling in StorageMechanics, and modify related components for improved material management.

This commit is contained in:
2025-05-10 16:26:54 +05:30
parent bf6e95b7f2
commit 9746cfdf80
13 changed files with 279 additions and 35 deletions

View File

@@ -31,7 +31,8 @@ function StorageMechanics() {
) as StoragePointSchema | undefined;
if (point && "action" in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "store" | "spawn");
const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType;
setActiveOption(uiOption as "store" | "spawn");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
}
@@ -46,7 +47,8 @@ function StorageMechanics() {
) as StoragePointSchema | undefined;
if (point && "action" in point) {
setSelectedPointData(point);
setActiveOption(point.action.actionType as "store" | "spawn");
const uiOption = point.action.actionType === "retrieve" ? "spawn" : point.action.actionType;
setActiveOption(uiOption as "store" | "spawn");
setSelectedAction(point.action.actionUuid, point.action.actionName);
}
} else {
@@ -70,11 +72,12 @@ function StorageMechanics() {
const handleActionTypeChange = (option: string) => {
if (!selectedEventData || !selectedPointData) return;
const validOption = option as "store" | "spawn";
setActiveOption(validOption);
const internalOption = actionTypeMap[option as keyof typeof actionTypeMap] as "store" | "retrieve";
setActiveOption(option as "store" | "spawn");
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
actionType: validOption,
actionType: internalOption,
});
if (event) {
@@ -87,7 +90,7 @@ function StorageMechanics() {
updateSelectedPointData();
}
if (validOption === "spawn") {
if (option === "spawn") {
const storageUnit = getStorageUnitById(selectedEventData.data.modelUuid);
if (storageUnit) {
const materialType = selectedPointData.action.materialType || "Default material";
@@ -211,6 +214,11 @@ function StorageMechanics() {
options: ["store", "spawn"],
};
const actionTypeMap = {
spawn: "retrieve",
store: "store"
};
return (
<>
{selectedEventData && (

View File

@@ -0,0 +1,207 @@
import { useCallback, useState, useEffect, useRef } from "react";
import * as THREE from 'three';
import { useFrame } from "@react-three/fiber";
import { useMaterialStore } from "../../../../../store/simulation/useMaterialStore";
import { useProductStore } from "../../../../../store/simulation/useProductStore";
import { useSelectedProduct } from "../../../../../store/simulation/useSimulationStore";
import { useStorageUnitStore } from "../../../../../store/simulation/useStorageUnitStore";
import { useArmBotStore } from "../../../../../store/simulation/useArmBotStore";
import { useVehicleStore } from "../../../../../store/simulation/useVehicleStore";
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
export function useRetrieveHandler() {
const { addMaterial } = useMaterialStore();
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid } = useProductStore();
const { getStorageUnitById, getLastMaterial } = useStorageUnitStore();
const { selectedProduct } = useSelectedProduct();
const { getArmBotById, addCurrentAction } = useArmBotStore();
const { getVehicleById } = useVehicleStore();
const { isPlaying } = usePlayButtonStore();
const { isPaused } = usePauseButtonStore();
const { isReset } = useResetButtonStore();
const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
const [initialDelayComplete, setInitialDelayComplete] = useState(false);
const delayTimerRef = useRef<NodeJS.Timeout | null>(null);
const retrieveLogStatus = (materialUuid: string, status: string) => {
// console.log(`${materialUuid}, ${status}`);
}
const createNewMaterial = useCallback((materialId: string, materialType: string, action: StorageAction) => {
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
const pointUuid = getPointUuidByActionUuid(selectedProduct.productId, action.actionUuid);
if (!modelUuid || !pointUuid) return null;
const currentTime = performance.now();
if (action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid &&
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid
) {
const newMaterial: MaterialSchema = {
materialId: materialId,
materialName: `${materialType}-${Date.now()}`,
materialType: materialType,
isActive: false,
isVisible: false,
isPaused: false,
isRendered: true,
startTime: currentTime,
previous:{
modelUuid: modelUuid,
pointUuid: pointUuid,
actionUuid: action.actionUuid
},
current: {
modelUuid: action.triggers[0].triggeredAsset.triggeredModel.modelUuid,
pointUuid: action.triggers[0].triggeredAsset.triggeredPoint.pointUuid,
actionUuid: action.triggers[0].triggeredAsset.triggeredAction.actionUuid
},
};
addMaterial(newMaterial);
return newMaterial;
}
return null;
}, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productId]);
useEffect(() => {
if (isPlaying && !initialDelayComplete) {
delayTimerRef.current = setTimeout(() => {
setInitialDelayComplete(true);
}, 3000);
}
return () => {
if (delayTimerRef.current) {
clearTimeout(delayTimerRef.current);
}
};
}, [isPlaying, initialDelayComplete]);
useEffect(() => {
if (isReset || isPaused) {
setInitialDelayComplete(false);
if (delayTimerRef.current) {
clearTimeout(delayTimerRef.current);
}
}
}, [isReset, isPaused]);
useFrame(() => {
if (!isPlaying || isPaused || isReset || !initialDelayComplete) return;
const currentTime = performance.now();
const completedActions: string[] = [];
let hasChanges = false;
activeRetrievals.forEach((retrieval, actionUuid) => {
if (retrieval.isProcessing) return;
const storageUnit = getStorageUnitById(
getModelUuidByActionUuid(selectedProduct.productId, retrieval.action.actionUuid) || ''
);
if (!storageUnit || storageUnit.currentLoad <= 0) {
completedActions.push(actionUuid);
hasChanges = true;
return;
}
if (retrieval.action.triggers.length === 0 || !retrieval.action.triggers[0].triggeredAsset) {
return;
}
const triggeredModel = getEventByModelUuid(
selectedProduct.productId,
retrieval.action.triggers[0].triggeredAsset.triggeredModel.modelUuid
);
if (!triggeredModel) return;
let isIdle = false;
if (triggeredModel.type === 'roboticArm') {
const armBot = getArmBotById(triggeredModel.modelUuid);
isIdle = armBot && !armBot.isActive && armBot.state === 'idle' && !armBot.currentAction || false;
} else if (triggeredModel.type === 'vehicle') {
const vehicle = getVehicleById(triggeredModel.modelUuid);
isIdle = vehicle && !vehicle.isActive && vehicle.state === 'idle' || false;
}
if (isIdle) {
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
newRetrievals.set(actionUuid, {
...retrieval,
isProcessing: true,
lastCheckTime: currentTime
});
return newRetrievals;
});
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
if (lastMaterial) {
const material = createNewMaterial(
lastMaterial.materialId,
lastMaterial.materialType,
storageUnit.point.action
);
if (material && triggeredModel.type === 'roboticArm') {
addCurrentAction(
triggeredModel.modelUuid,
retrieval.action.triggers[0].triggeredAsset.triggeredAction?.actionUuid || '',
material.materialType,
material.materialId
);
}
}
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
newRetrievals.set(actionUuid, {
...retrieval,
isProcessing: false,
lastCheckTime: currentTime
});
return newRetrievals;
});
}
});
if (hasChanges || completedActions.length > 0) {
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
completedActions.forEach(actionUuid => newRetrievals.delete(actionUuid));
return newRetrievals;
});
}
});
const handleRetrieve = useCallback((action: StorageAction) => {
if (!action || action.actionType !== 'retrieve') return;
setActiveRetrievals(prev => {
const newRetrievals = new Map(prev);
newRetrievals.set(action.actionUuid, {
action,
isProcessing: false,
lastCheckTime: performance.now()
});
return newRetrievals;
});
}, []);
useEffect(() => {
if (isReset) {
setActiveRetrievals(new Map());
setInitialDelayComplete(false);
}
}, [isReset]);
return {
handleRetrieve,
};
}

View File

@@ -21,7 +21,6 @@ export function useStoreHandler() {
if (!material) return;
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
if (!modelUuid) return;
removeMaterial(material.materialId);

View File

@@ -1,13 +1,19 @@
import { useEffect, useCallback } from 'react';
import { useStoreHandler } from './actionHandler/useStoreHandler';
import { useRetrieveHandler } from './actionHandler/useRetrieveHandler';
export function useStorageActions() {
const { handleStore } = useStoreHandler();
const { handleRetrieve } = useRetrieveHandler();
const handleStoreAction = useCallback((action: StorageAction, materialId: string) => {
handleStore(action, materialId);
}, [handleStore]);
const handleRetrieveAction = useCallback((action: StorageAction) => {
handleRetrieve(action);
}, [handleRetrieve]);
const handleStorageAction = useCallback((action: StorageAction, materialId: string) => {
if (!action) return;
@@ -15,6 +21,9 @@ export function useStorageActions() {
case 'store':
handleStoreAction(action, materialId);
break;
case 'retrieve':
handleRetrieveAction(action);
break;
default:
console.warn(`Unknown storage action type: ${action.actionType}`);
}

View File

@@ -35,7 +35,7 @@ export function useActionHandler() {
case 'process':
handleMachineAction(action as MachineAction, materialId as string);
break;
case 'store':
case 'store': case 'retrieve':
handleStorageAction(action as StorageAction, materialId as string);
break;
default:

View File

@@ -104,7 +104,7 @@ function Products() {
if (event.type === 'storageUnit') {
addStorageUnit(selectedProduct.productId, event);
if (event.point.action.actionType === 'spawn') {
if (event.point.action.actionType === 'retrieve') {
const storageAction = event.point.action as StorageAction;
const materials = Array.from({ length: storageAction.storageCapacity }, () => ({
materialType: storageAction.materialType || 'Default material',

View File

@@ -10,6 +10,7 @@ import { useMaterialStore } from '../../../../../store/simulation/useMaterialSto
import { useArmBotStore } from '../../../../../store/simulation/useArmBotStore';
import { useProductStore } from '../../../../../store/simulation/useProductStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';
import { useStorageUnitStore } from '../../../../../store/simulation/useStorageUnitStore';
import { useSelectedProduct } from '../../../../../store/simulation/useSimulationStore';
import { useTriggerHandler } from '../../../triggers/triggerHandler/useTriggerHandler';
@@ -28,6 +29,7 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
const { setArmBotActive, setArmBotState, removeCurrentAction } = useArmBotStore();
const { decrementVehicleLoad, removeLastMaterial } = useVehicleStore();
const { removeLastMaterial: removeLastStorageMaterial, updateCurrentLoad } = useStorageUnitStore();
const { setIsVisible, getMaterialById } = useMaterialStore();
const { selectedProduct } = useSelectedProduct();
const { getActionByUuid, getEventByActionUuid, getEventByModelUuid } = useProductStore();
@@ -58,6 +60,8 @@ function RoboticArmInstance({ armBot }: { armBot: ArmBotStatus }) {
removeLastMaterial(previousModel.modelUuid);
} else if (previousModel.type === 'storageUnit') {
// storage unit logic
removeLastStorageMaterial(previousModel.modelUuid);
updateCurrentLoad(previousModel.modelUuid, -1)
}
} else {
setIsVisible(armBot.currentAction.materialId, false);

View File

@@ -9,7 +9,7 @@ const MaterialAnimator = ({
const meshRef = useRef<any>(null!);
const [hasLoad, setHasLoad] = useState(false);
const { scene } = useThree();
const padding = 0.1;
const padding = 0;
useEffect(() => {
setHasLoad(storage.currentLoad > 0);

View File

@@ -131,6 +131,22 @@ function TriggerConnector() {
});
}
}
// Handle StorageUnit point
else if (event.type === "storageUnit" && 'point' in event) {
const point = event.point;
if (point.action?.triggers) {
point.action.triggers.forEach(trigger => {
if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
newConnections.push({
id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
startPointUuid: point.uuid,
endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
trigger
});
}
});
}
}
});
setConnections(newConnections);

View File

@@ -177,23 +177,7 @@ function VehicleInstance({ agvDetail }: Readonly<{ agvDetail: VehicleStatus }>)
if (action.triggers.length > 0 && action.triggers[0].triggeredAsset?.triggeredModel.modelUuid) {
const storageUnit = getStorageUnitById(action.triggers[0].triggeredAsset?.triggeredModel.modelUuid);
if (storageUnit) {
if (storageUnit.point.action.actionType === 'spawn') {
// const newMaterial: MaterialSchema = {
// materialId: THREE.MathUtils.generateUUID(),
// materialName: `${storageUnit.point.action.materialType}-${Date.now()}`,
// materialType: storageUnit.point.action.materialType || 'Default material',
// isActive: false,
// isVisible: true,
// isPaused: false,
// isRendered: true,
// startTime: performance.now(),
// current: {
// modelUuid: storageUnit.modelUuid,
// pointUuid: storageUnit.point.uuid,
// actionUuid: storageUnit.point.action.actionUuid
// },
// };
} else if (storageUnit.point.action.actionType === 'store') {
if (storageUnit.point.action.actionType === 'store') {
handleMaterialDropToStorage(
agvDetail.modelUuid,
agvDetail.currentLoad,

View File

@@ -22,7 +22,8 @@ interface StorageUnitStore {
addCurrentMaterial: (modelUuid: string, materialType: string, materialId: string) => void;
setCurrentMaterials: (modelUuid: string, materials: { materialType: string; materialId: string; }[]) => void;
removeLastMaterial: (modelUuid: string) => string | undefined;
getLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
removeLastMaterial: (modelUuid: string) => { materialId: string; materialType: string; } | undefined;
clearCurrentMaterials: (modelUuid: string) => void;
getStorageUnitById: (modelUuid: string) => StorageUnitStatus | undefined;
@@ -140,20 +141,36 @@ export const useStorageUnitStore = create<StorageUnitStore>()(
});
},
getLastMaterial: (modelUuid) => {
let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => {
const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
if (storage) {
if (storage.currentMaterials.length > 0) {
const material = storage.currentMaterials[storage.currentMaterials.length - 1];
if (material) {
removedMaterial = { materialId: material.materialId, materialType: material.materialType };
}
}
}
});
return removedMaterial;
},
removeLastMaterial: (modelUuid) => {
let materialId: string | undefined;
let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => {
const storage = state.storageUnits.find((s) => s.modelUuid === modelUuid);
if (storage) {
if (storage.currentMaterials.length > 0) {
const material = storage.currentMaterials.pop();
if (material) {
materialId = material.materialId
removedMaterial = { materialId: material.materialId, materialType: material.materialType };
}
}
}
});
return materialId;
return removedMaterial;
},
clearCurrentMaterials: (modelUuid) => {

View File

@@ -153,19 +153,19 @@ export const useVehicleStore = create<VehiclesStore>()(
},
removeLastMaterial: (modelUuid) => {
let materialId: { materialId: string; materialType: string; } | undefined;
let removedMaterial: { materialId: string; materialType: string; } | undefined;
set((state) => {
const vehicle = state.vehicles.find((v) => v.modelUuid === modelUuid);
if (vehicle) {
if (vehicle.currentMaterials.length > 0) {
const material = vehicle.currentMaterials.pop();
if (material) {
materialId = { materialId: material.materialId, materialType: material.materialType };
removedMaterial = { materialId: material.materialId, materialType: material.materialType };
}
}
}
});
return materialId;
return removedMaterial;
},
clearCurrentMaterials: (modelUuid) => {

View File

@@ -124,7 +124,7 @@ interface MachineAction {
interface StorageAction {
actionUuid: string;
actionName: string;
actionType: "store" | "spawn";
actionType: "store" | "retrieve";
materialType?: string;
storageCapacity: number;
triggers: TriggerSchema[];