first commit
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { useCallback } from "react";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
|
||||
export function useDefaultHandler() {
|
||||
const { materialStore } = useSceneContext();
|
||||
const { getMaterialById } = materialStore();
|
||||
|
||||
const defaultLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleDefault = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'default' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
defaultLogStatus(material.materialName, `performed Default action`);
|
||||
|
||||
}, [getMaterialById]);
|
||||
|
||||
return {
|
||||
handleDefault,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
|
||||
interface DelayInstance {
|
||||
initialDelay: number;
|
||||
delayEndTime: number;
|
||||
materialId?: string;
|
||||
action: ConveyorAction;
|
||||
isPaused: boolean;
|
||||
remainingTime: number;
|
||||
lastUpdateTime: number;
|
||||
elapsedTime: number;
|
||||
}
|
||||
|
||||
export function useDelayHandler() {
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { isPaused } = usePauseButtonStore();
|
||||
const { isReset } = useResetButtonStore();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { materialStore } = useSceneContext();
|
||||
const { setIsPaused } = materialStore();
|
||||
const activeDelays = useRef<Map<string, DelayInstance>>(new Map());
|
||||
const lastUpdateTimeRef = useRef<number>(performance.now());
|
||||
|
||||
const cleanupDelay = useCallback(() => {
|
||||
activeDelays.current.clear();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isReset) {
|
||||
cleanupDelay();
|
||||
}
|
||||
}, [isReset, cleanupDelay]);
|
||||
|
||||
const delayLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
};
|
||||
|
||||
useFrame(() => {
|
||||
const currentTime = performance.now();
|
||||
const deltaTime = currentTime - lastUpdateTimeRef.current;
|
||||
lastUpdateTimeRef.current = currentTime;
|
||||
const completedDelays: string[] = [];
|
||||
|
||||
activeDelays.current.forEach((delay, key) => {
|
||||
if (isPaused && !delay.isPaused) {
|
||||
delay.remainingTime = Math.max(0, delay.delayEndTime - currentTime);
|
||||
delay.isPaused = true;
|
||||
} else if (!isPaused && delay.isPaused) {
|
||||
delay.delayEndTime = currentTime + delay.remainingTime;
|
||||
delay.isPaused = false;
|
||||
delay.lastUpdateTime = currentTime;
|
||||
delay.elapsedTime = 0;
|
||||
} else if (!delay.isPaused && isPlaying) {
|
||||
delay.elapsedTime += deltaTime * speed;
|
||||
|
||||
if (delay.elapsedTime >= delay.initialDelay) {
|
||||
if (delay.materialId) {
|
||||
delayLogStatus(delay.materialId, `Delay completed`);
|
||||
setIsPaused(delay.materialId, false);
|
||||
}
|
||||
completedDelays.push(key);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
completedDelays.forEach(key => {
|
||||
activeDelays.current.delete(key);
|
||||
});
|
||||
});
|
||||
|
||||
const handleDelay = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'delay' || !materialId) return;
|
||||
|
||||
const delayMs = (action.delay || 0) * 1000;
|
||||
if (delayMs <= 0) return;
|
||||
|
||||
const key = materialId ? `${materialId}-${action.actionUuid}` : action.actionUuid;
|
||||
|
||||
if (activeDelays.current.has(key)) {
|
||||
activeDelays.current.delete(key);
|
||||
}
|
||||
|
||||
const now = performance.now();
|
||||
activeDelays.current.set(key, {
|
||||
initialDelay: delayMs,
|
||||
delayEndTime: now + delayMs,
|
||||
materialId,
|
||||
action,
|
||||
isPaused: false,
|
||||
remainingTime: 0,
|
||||
lastUpdateTime: now,
|
||||
elapsedTime: 0
|
||||
});
|
||||
|
||||
delayLogStatus(materialId, `Started ${delayMs / 1000}s delay`);
|
||||
setIsPaused(materialId, true);
|
||||
}, [isPlaying]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanupDelay();
|
||||
};
|
||||
}, [cleanupDelay]);
|
||||
|
||||
return {
|
||||
handleDelay,
|
||||
cleanupDelay
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useCallback } from "react";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
|
||||
export function useDespawnHandler() {
|
||||
const { materialStore } = useSceneContext();
|
||||
const { getMaterialById, removeMaterial, setEndTime } = materialStore();
|
||||
|
||||
const deSpawnLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleDespawn = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'despawn' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
setEndTime(material.materialId, performance.now());
|
||||
removeMaterial(material.materialId);
|
||||
|
||||
deSpawnLogStatus(material.materialName, `Despawned`);
|
||||
|
||||
}, [getMaterialById, removeMaterial]);
|
||||
|
||||
return {
|
||||
handleDespawn,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import * as THREE from 'three';
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import { usePlayButtonStore, useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from "../../../../../store/usePlayButtonStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
interface SpawnInstance {
|
||||
lastSpawnTime: number | null;
|
||||
startTime: number;
|
||||
spawnCount: number;
|
||||
params: {
|
||||
material: string;
|
||||
intervalMs: number;
|
||||
totalCount: number;
|
||||
action: ConveyorAction;
|
||||
};
|
||||
pauseStartTime: number;
|
||||
remainingTime: number;
|
||||
isPaused: boolean;
|
||||
}
|
||||
|
||||
export function useSpawnHandler() {
|
||||
const { materialStore, conveyorStore } = useSceneContext();
|
||||
const { addMaterial } = materialStore();
|
||||
const { getConveyorById } = conveyorStore();
|
||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid } = useProductStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { isPaused } = usePauseButtonStore();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { isReset } = useResetButtonStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
const [activeSpawns, setActiveSpawns] = useState<Map<string, SpawnInstance>>(new Map());
|
||||
|
||||
const getConveyorPausedState = useCallback((action: ConveyorAction) => {
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
if (!modelUuid) return false;
|
||||
|
||||
const conveyor = getConveyorById(modelUuid);
|
||||
if (!conveyor) return false;
|
||||
return conveyor.isPaused;
|
||||
}, [getConveyorById, getModelUuidByActionUuid, selectedProduct.productUuid]);
|
||||
|
||||
const shouldPauseSpawn = useCallback((action: ConveyorAction) => {
|
||||
return isPaused || getConveyorPausedState(action);
|
||||
}, [isPaused, getConveyorPausedState]);
|
||||
|
||||
const clearAllSpawns = useCallback(() => {
|
||||
setActiveSpawns(new Map());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isReset) {
|
||||
clearAllSpawns();
|
||||
}
|
||||
}, [isReset, clearAllSpawns]);
|
||||
|
||||
const spawnLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const createNewMaterial = useCallback((materialType: string, action: ConveyorAction) => {
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
const pointUuid = getPointUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
if (!modelUuid || !pointUuid) return;
|
||||
const currentTime = performance.now();
|
||||
|
||||
const newMaterial: MaterialSchema = {
|
||||
materialId: THREE.MathUtils.generateUUID(),
|
||||
materialName: `${materialType}-${Date.now()}`,
|
||||
materialType: materialType,
|
||||
isActive: false,
|
||||
isVisible: true,
|
||||
isPaused: false,
|
||||
isRendered: true,
|
||||
startTime: currentTime,
|
||||
current: {
|
||||
modelUuid: modelUuid,
|
||||
pointUuid: pointUuid,
|
||||
actionUuid: action.actionUuid
|
||||
},
|
||||
};
|
||||
|
||||
if (action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid &&
|
||||
action.triggers[0]?.triggeredAsset?.triggeredAction?.actionUuid
|
||||
) {
|
||||
newMaterial.next = {
|
||||
modelUuid: action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid,
|
||||
pointUuid: action.triggers[0]?.triggeredAsset?.triggeredPoint?.pointUuid,
|
||||
}
|
||||
}
|
||||
|
||||
addMaterial(newMaterial);
|
||||
return newMaterial;
|
||||
}, [addMaterial, getModelUuidByActionUuid, getPointUuidByActionUuid, selectedProduct.productUuid]);
|
||||
|
||||
useFrame(() => {
|
||||
const currentTime = performance.now();
|
||||
const completedActions: string[] = [];
|
||||
let hasChanges = false;
|
||||
|
||||
activeSpawns.forEach(spawn => {
|
||||
const isPausedNow = shouldPauseSpawn(spawn.params.action);
|
||||
|
||||
if (isPausedNow && !spawn.isPaused) {
|
||||
if (spawn.lastSpawnTime === null) {
|
||||
spawn.remainingTime = Math.max(0, (spawn.params.intervalMs / speed) - (currentTime - spawn.startTime));
|
||||
} else {
|
||||
spawn.remainingTime = Math.max(0, (spawn.params.intervalMs / speed) - (currentTime - spawn.lastSpawnTime));
|
||||
}
|
||||
spawn.pauseStartTime = currentTime;
|
||||
spawn.isPaused = true;
|
||||
hasChanges = true;
|
||||
} else if (!isPausedNow && spawn.isPaused) {
|
||||
const pauseDuration = currentTime - spawn.pauseStartTime;
|
||||
if (spawn.lastSpawnTime === null) {
|
||||
spawn.startTime += pauseDuration;
|
||||
} else {
|
||||
spawn.lastSpawnTime += pauseDuration;
|
||||
}
|
||||
spawn.isPaused = false;
|
||||
spawn.pauseStartTime = 0;
|
||||
spawn.remainingTime = 0;
|
||||
hasChanges = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (isPlaying && !isReset && !isPaused) {
|
||||
activeSpawns.forEach((spawn, actionUuid) => {
|
||||
if (spawn.isPaused) return;
|
||||
|
||||
const { material, intervalMs, totalCount, action } = spawn.params;
|
||||
const adjustedInterval = intervalMs / speed;
|
||||
const isFirstSpawn = spawn.lastSpawnTime === null;
|
||||
|
||||
// First spawn
|
||||
if (isFirstSpawn) {
|
||||
const elapsed = currentTime - spawn.startTime;
|
||||
if (elapsed >= adjustedInterval) {
|
||||
const createdMaterial = createNewMaterial(material, action);
|
||||
if (createdMaterial) {
|
||||
spawnLogStatus(createdMaterial.materialName, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
|
||||
}
|
||||
spawn.lastSpawnTime = currentTime;
|
||||
spawn.spawnCount = 1;
|
||||
hasChanges = true;
|
||||
|
||||
if (totalCount <= 1) {
|
||||
completedActions.push(actionUuid);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Subsequent spawns
|
||||
if (spawn.lastSpawnTime !== null) {
|
||||
const timeSinceLast = currentTime - spawn.lastSpawnTime;
|
||||
if (timeSinceLast >= adjustedInterval) {
|
||||
const count = spawn.spawnCount + 1;
|
||||
const createdMaterial = createNewMaterial(material, action);
|
||||
if (createdMaterial) {
|
||||
spawnLogStatus(createdMaterial.materialName, `[${timeSinceLast.toFixed(2)}ms] Spawned ${material} (${count}/${totalCount})`);
|
||||
}
|
||||
spawn.lastSpawnTime = currentTime;
|
||||
spawn.spawnCount = count;
|
||||
hasChanges = true;
|
||||
|
||||
if (count >= totalCount) {
|
||||
completedActions.push(actionUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (hasChanges || completedActions.length > 0) {
|
||||
setActiveSpawns(prevSpawns => {
|
||||
const newSpawns = new Map(prevSpawns);
|
||||
|
||||
completedActions.forEach(actionUuid => {
|
||||
newSpawns.delete(actionUuid);
|
||||
});
|
||||
|
||||
return newSpawns;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const handleSpawn = useCallback((action: ConveyorAction) => {
|
||||
if (!action || action.actionType !== 'spawn') return;
|
||||
|
||||
const { material, spawnInterval = 0, spawnCount = 1, actionUuid } = action;
|
||||
const intervalMs = spawnInterval * 1000;
|
||||
|
||||
setActiveSpawns(prevSpawns => {
|
||||
const newSpawns = new Map(prevSpawns);
|
||||
|
||||
if (newSpawns.has(actionUuid)) {
|
||||
newSpawns.delete(actionUuid);
|
||||
}
|
||||
|
||||
newSpawns.set(actionUuid, {
|
||||
lastSpawnTime: null,
|
||||
startTime: performance.now(),
|
||||
spawnCount: 0,
|
||||
params: {
|
||||
material,
|
||||
intervalMs,
|
||||
totalCount: spawnCount,
|
||||
action: action
|
||||
},
|
||||
pauseStartTime: 0,
|
||||
remainingTime: 0,
|
||||
isPaused: false
|
||||
});
|
||||
|
||||
return newSpawns;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearAllSpawns();
|
||||
};
|
||||
}, [clearAllSpawns]);
|
||||
|
||||
return {
|
||||
handleSpawn,
|
||||
clearAllSpawns
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { useCallback } from "react";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
|
||||
export function useSwapHandler() {
|
||||
const { materialStore } = useSceneContext();
|
||||
const { getMaterialById, setMaterial } = materialStore();
|
||||
|
||||
const swapLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleSwap = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'swap' || !materialId) return;
|
||||
|
||||
const { material: newMaterialType } = action;
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
setMaterial(material.materialId, newMaterialType);
|
||||
swapLogStatus(material.materialName, `Swapped to ${newMaterialType}`);
|
||||
|
||||
}, [getMaterialById, setMaterial]);
|
||||
|
||||
return {
|
||||
handleSwap,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useEffect, useCallback } from "react";
|
||||
import { useDefaultHandler } from "./actionHandler/useDefaultHandler";
|
||||
import { useSpawnHandler } from "./actionHandler/useSpawnHandler";
|
||||
import { useSwapHandler } from "./actionHandler/useSwapHandler";
|
||||
import { useDelayHandler } from "./actionHandler/useDelayHandler";
|
||||
import { useDespawnHandler } from "./actionHandler/useDespawnHandler";
|
||||
|
||||
export function useConveyorActions() {
|
||||
const { handleDefault } = useDefaultHandler();
|
||||
const { handleSpawn, clearAllSpawns } = useSpawnHandler();
|
||||
const { handleSwap } = useSwapHandler();
|
||||
const { handleDespawn } = useDespawnHandler();
|
||||
const { handleDelay, cleanupDelay } = useDelayHandler();
|
||||
|
||||
const handleDefaultAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
handleDefault(action, materialId);
|
||||
}, [handleDefault]);
|
||||
|
||||
const handleSpawnAction = useCallback((action: ConveyorAction) => {
|
||||
handleSpawn(action);
|
||||
}, [handleSpawn]);
|
||||
|
||||
const handleSwapAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
handleSwap(action, materialId);
|
||||
}, [handleSwap]);
|
||||
|
||||
const handleDelayAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
handleDelay(action, materialId);
|
||||
}, [handleDelay]);
|
||||
|
||||
const handleDespawnAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
handleDespawn(action, materialId)
|
||||
}, [handleDespawn]);
|
||||
|
||||
const handleConveyorAction = useCallback((action: ConveyorAction, materialId?: string) => {
|
||||
if (!action) return;
|
||||
|
||||
switch (action.actionType) {
|
||||
case 'default':
|
||||
handleDefaultAction(action);
|
||||
break;
|
||||
case 'spawn':
|
||||
handleSpawnAction(action);
|
||||
break;
|
||||
case 'swap':
|
||||
handleSwapAction(action, materialId);
|
||||
break;
|
||||
case 'delay':
|
||||
handleDelayAction(action, materialId);
|
||||
break;
|
||||
case 'despawn':
|
||||
handleDespawnAction(action, materialId);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown conveyor action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleDefaultAction, handleSpawnAction, handleSwapAction, handleDelayAction, handleDespawnAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
clearAllSpawns();
|
||||
cleanupDelay();
|
||||
}, [clearAllSpawns, cleanupDelay]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
return {
|
||||
handleConveyorAction,
|
||||
cleanup
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useCallback } from "react";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function useProcessHandler() {
|
||||
const { materialStore, machineStore } = useSceneContext();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { getMaterialById, setMaterial } = materialStore();
|
||||
const { addCurrentAction } = machineStore();
|
||||
const { getModelUuidByActionUuid } = useProductStore();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
const processLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.log(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleProcess = useCallback((action: MachineAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'process' || !materialId) return;
|
||||
|
||||
const { swapMaterial: newMaterialType } = action;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
|
||||
if (!modelUuid) return;
|
||||
setMaterial(material.materialId, newMaterialType);
|
||||
|
||||
addCurrentAction(modelUuid, action.actionUuid, newMaterialType, material.materialId);
|
||||
|
||||
processLogStatus(material.materialName, `Swapped to ${newMaterialType}`);
|
||||
processLogStatus(material.materialName, `starts Process action`);
|
||||
|
||||
}, [getMaterialById]);
|
||||
|
||||
return {
|
||||
handleProcess
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useProcessHandler } from './actionHandler/useProcessHandler';
|
||||
|
||||
export function useMachineActions() {
|
||||
const { handleProcess } = useProcessHandler();
|
||||
|
||||
const handleProcessAction = useCallback((action: MachineAction, materialId: string) => {
|
||||
handleProcess(action, materialId);
|
||||
}, [handleProcess]);
|
||||
|
||||
const handleMachineAction = useCallback((action: MachineAction, materialId: string) => {
|
||||
if (!action) return;
|
||||
|
||||
switch (action.actionType) {
|
||||
case 'process':
|
||||
handleProcessAction(action, materialId);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown machine action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleProcessAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
return {
|
||||
handleMachineAction,
|
||||
cleanup,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { useCallback } from "react";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function usePickAndPlaceHandler() {
|
||||
const { materialStore, armBotStore } = useSceneContext();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { getMaterialById } = materialStore();
|
||||
const { addCurrentAction } = armBotStore();
|
||||
const { getModelUuidByActionUuid } = useProductStore();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
const pickAndPlaceLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.warn(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handlePickAndPlace = useCallback((action: RoboticArmAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'pickAndPlace' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
|
||||
if (!modelUuid) return;
|
||||
|
||||
addCurrentAction(
|
||||
modelUuid,
|
||||
action.actionUuid,
|
||||
material.materialType,
|
||||
material.materialId
|
||||
);
|
||||
|
||||
pickAndPlaceLogStatus(material.materialName, `is going to be picked by armBot ${modelUuid}`);
|
||||
|
||||
}, [getMaterialById, getModelUuidByActionUuid, selectedProduct.productUuid, addCurrentAction]);
|
||||
|
||||
return {
|
||||
handlePickAndPlace,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { usePickAndPlaceHandler } from './actionHandler/usePickAndPlaceHandler';
|
||||
|
||||
export function useRoboticArmActions() {
|
||||
const { handlePickAndPlace } = usePickAndPlaceHandler();
|
||||
|
||||
const handlePickAndPlaceAction = useCallback((action: RoboticArmAction, materialId: string) => {
|
||||
handlePickAndPlace(action, materialId);
|
||||
}, [handlePickAndPlace]);
|
||||
|
||||
const handleRoboticArmAction = useCallback((action: RoboticArmAction, materialId: string) => {
|
||||
if (!action) return;
|
||||
|
||||
switch (action.actionType) {
|
||||
case 'pickAndPlace':
|
||||
handlePickAndPlaceAction(action, materialId);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown robotic arm action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handlePickAndPlaceAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
return {
|
||||
handleRoboticArmAction,
|
||||
cleanup
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
import { useCallback, useState, useEffect, useRef } from "react";
|
||||
import { useFrame } from "@react-three/fiber";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import { usePlayButtonStore, usePauseButtonStore, useResetButtonStore, useAnimationPlaySpeed } from "../../../../../store/usePlayButtonStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function useRetrieveHandler() {
|
||||
const { materialStore, armBotStore, vehicleStore, storageUnitStore } = useSceneContext();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { addMaterial } = materialStore();
|
||||
const { getModelUuidByActionUuid, getPointUuidByActionUuid, getEventByModelUuid, getActionByUuid } = useProductStore();
|
||||
const { getStorageUnitById, getLastMaterial, updateCurrentLoad, removeLastMaterial } = storageUnitStore();
|
||||
const { getVehicleById, incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { getArmBotById, addCurrentAction } = armBotStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { speed } = useAnimationPlaySpeed();
|
||||
const { isPaused } = usePauseButtonStore();
|
||||
const { isReset } = useResetButtonStore();
|
||||
|
||||
const [activeRetrievals, setActiveRetrievals] = useState<Map<string, { action: StorageAction, isProcessing: boolean, lastCheckTime: number }>>(new Map());
|
||||
const retrievalTimeRef = useRef<Map<string, number>>(new Map());
|
||||
|
||||
const [initialDelayComplete, setInitialDelayComplete] = useState(false);
|
||||
const delayTimerRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const retrieveLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const createNewMaterial = useCallback((materialId: string, materialType: string, action: StorageAction) => {
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
const pointUuid = getPointUuidByActionUuid(selectedProduct.productUuid, 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.productUuid]);
|
||||
|
||||
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.productUuid, 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.productUuid,
|
||||
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;
|
||||
|
||||
if (!armBot) return;
|
||||
if (!retrievalTimeRef.current.has(actionUuid) && isIdle) {
|
||||
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||
return;
|
||||
}
|
||||
|
||||
const idleStartTime = retrievalTimeRef.current.get(actionUuid);
|
||||
const minIdleTimeBeforeFirstRetrieval = 5000 / speed;
|
||||
const minDelayBetweenRetrievals = 5000 / speed;
|
||||
|
||||
const canProceedFirstRetrieval = idleStartTime !== undefined &&
|
||||
(currentTime - idleStartTime) >= minIdleTimeBeforeFirstRetrieval;
|
||||
|
||||
const lastRetrievalTime = retrievalTimeRef.current.get(`${actionUuid}_last`) ?? null;
|
||||
const canProceedSubsequent = lastRetrievalTime === null ||
|
||||
(currentTime - lastRetrievalTime) >= minDelayBetweenRetrievals;
|
||||
|
||||
const canProceed = lastRetrievalTime === null ? canProceedFirstRetrieval : canProceedSubsequent;
|
||||
|
||||
if (isIdle && canProceed) {
|
||||
setActiveRetrievals(prev => {
|
||||
const newRetrievals = new Map(prev);
|
||||
newRetrievals.set(actionUuid, {
|
||||
...retrieval,
|
||||
isProcessing: true,
|
||||
lastCheckTime: currentTime
|
||||
});
|
||||
return newRetrievals;
|
||||
});
|
||||
|
||||
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
|
||||
if (lastMaterial) {
|
||||
|
||||
if (retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid) {
|
||||
const action = getActionByUuid(selectedProduct.productUuid, retrieval.action.triggers[0]?.triggeredAsset.triggeredAction.actionUuid);
|
||||
if (action && action.triggers.length > 0 && action.triggers[0]?.triggeredAsset?.triggeredModel.modelUuid) {
|
||||
const model = getEventByModelUuid(selectedProduct.productUuid, action.triggers[0]?.triggeredAsset.triggeredModel.modelUuid);
|
||||
if (model) {
|
||||
if (model.type === 'vehicle') {
|
||||
const vehicle = getVehicleById(model.modelUuid);
|
||||
if (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
|
||||
const material = createNewMaterial(
|
||||
lastMaterial.materialId,
|
||||
lastMaterial.materialType,
|
||||
storageUnit.point.action
|
||||
);
|
||||
if (material) {
|
||||
|
||||
addCurrentAction(
|
||||
triggeredModel.modelUuid,
|
||||
retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid ?? '',
|
||||
material.materialType,
|
||||
material.materialId
|
||||
);
|
||||
retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const material = createNewMaterial(
|
||||
lastMaterial.materialId,
|
||||
lastMaterial.materialType,
|
||||
storageUnit.point.action
|
||||
);
|
||||
if (material) {
|
||||
|
||||
addCurrentAction(
|
||||
triggeredModel.modelUuid,
|
||||
retrieval.action.triggers[0]?.triggeredAsset.triggeredAction?.actionUuid ?? '',
|
||||
material.materialType,
|
||||
material.materialId
|
||||
);
|
||||
retrieveLogStatus(material.materialName, `is being picked by ${armBot?.modelName}`);
|
||||
}
|
||||
}
|
||||
setActiveRetrievals(prev => {
|
||||
const newRetrievals = new Map(prev);
|
||||
newRetrievals.set(actionUuid, {
|
||||
...retrieval,
|
||||
isProcessing: false,
|
||||
lastCheckTime: currentTime,
|
||||
});
|
||||
return newRetrievals;
|
||||
});
|
||||
|
||||
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (!isIdle) {
|
||||
retrievalTimeRef.current.delete(actionUuid);
|
||||
}
|
||||
|
||||
} else if (triggeredModel.type === 'vehicle') {
|
||||
const vehicle = getVehicleById(triggeredModel.modelUuid);
|
||||
isIdle = (vehicle && !vehicle.isActive && vehicle.state === 'idle' && vehicle.isPicking && vehicle.currentLoad < vehicle.point.action.loadCapacity) || false;
|
||||
|
||||
if (!vehicle) return;
|
||||
|
||||
const loadDuration = vehicle.point.action.unLoadDuration;
|
||||
let minDelayBetweenRetrievals = (loadDuration * 1000) / speed;
|
||||
const minIdleTimeBeforeFirstRetrieval = 3000 / speed;
|
||||
|
||||
if (!retrievalTimeRef.current.has(actionUuid) && isIdle) {
|
||||
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||
return;
|
||||
}
|
||||
|
||||
const idleStartTime = retrievalTimeRef.current.get(actionUuid);
|
||||
const lastRetrievalTime = retrievalTimeRef.current.get(`${actionUuid}_last`) ?? null;
|
||||
|
||||
const canProceedFirstRetrieval = idleStartTime !== undefined &&
|
||||
(currentTime - idleStartTime) >= minIdleTimeBeforeFirstRetrieval;
|
||||
|
||||
const canProceedSubsequent = lastRetrievalTime === null ||
|
||||
(currentTime - lastRetrievalTime) >= minDelayBetweenRetrievals;
|
||||
|
||||
const canProceed = lastRetrievalTime === null ? canProceedFirstRetrieval : canProceedSubsequent;
|
||||
|
||||
if (isIdle && canProceed) {
|
||||
setActiveRetrievals(prev => {
|
||||
const newRetrievals = new Map(prev);
|
||||
newRetrievals.set(actionUuid, {
|
||||
...retrieval,
|
||||
isProcessing: true,
|
||||
lastCheckTime: currentTime
|
||||
});
|
||||
return newRetrievals;
|
||||
});
|
||||
|
||||
const lastMaterial = getLastMaterial(storageUnit.modelUuid);
|
||||
if (lastMaterial) {
|
||||
if (vehicle?.currentLoad < vehicle.point.action.loadCapacity) {
|
||||
const material = createNewMaterial(
|
||||
lastMaterial.materialId,
|
||||
lastMaterial.materialType,
|
||||
storageUnit.point.action
|
||||
);
|
||||
|
||||
if (material) {
|
||||
removeLastMaterial(storageUnit.modelUuid);
|
||||
updateCurrentLoad(storageUnit.modelUuid, -1)
|
||||
incrementVehicleLoad(vehicle.modelUuid, 1);
|
||||
addCurrentMaterial(vehicle.modelUuid, material.materialType, material.materialId);
|
||||
retrieveLogStatus(material.materialName, `is picked by ${vehicle.modelName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setActiveRetrievals(prev => {
|
||||
const newRetrievals = new Map(prev);
|
||||
newRetrievals.set(actionUuid, {
|
||||
...retrieval,
|
||||
isProcessing: false,
|
||||
lastCheckTime: currentTime,
|
||||
});
|
||||
return newRetrievals;
|
||||
});
|
||||
|
||||
retrievalTimeRef.current.set(actionUuid, currentTime);
|
||||
retrievalTimeRef.current.set(`${actionUuid}_last`, currentTime);
|
||||
} else if (!isIdle) {
|
||||
retrievalTimeRef.current.delete(actionUuid);
|
||||
retrievalTimeRef.current.delete(`${actionUuid}_last`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useCallback } from "react";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function useStoreHandler() {
|
||||
const { materialStore, storageUnitStore } = useSceneContext();
|
||||
const { getMaterialById, removeMaterial, setEndTime } = materialStore();
|
||||
const { addCurrentMaterial, updateCurrentLoad } = storageUnitStore();
|
||||
const { getModelUuidByActionUuid } = useProductStore();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
|
||||
const storeLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleStore = useCallback((action: StorageAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'store' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
if (!modelUuid) return;
|
||||
|
||||
setEndTime(material.materialId, performance.now());
|
||||
removeMaterial(material.materialId);
|
||||
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||
updateCurrentLoad(modelUuid, 1);
|
||||
|
||||
storeLogStatus(material.materialName, `performed Store action`);
|
||||
|
||||
}, [getMaterialById]);
|
||||
|
||||
return {
|
||||
handleStore,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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;
|
||||
|
||||
switch (action.actionType) {
|
||||
case 'store':
|
||||
handleStoreAction(action, materialId);
|
||||
break;
|
||||
case 'retrieve':
|
||||
handleRetrieveAction(action);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown storage action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleStoreAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
return {
|
||||
handleStorageAction,
|
||||
cleanup
|
||||
};
|
||||
}
|
||||
67
app/src/modules/simulation/actions/useActionHandler.ts
Normal file
67
app/src/modules/simulation/actions/useActionHandler.ts
Normal file
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
usePlayButtonStore,
|
||||
useResetButtonStore,
|
||||
} from "../../../store/usePlayButtonStore";
|
||||
import { useConveyorActions } from "./conveyor/useConveyorActions";
|
||||
import { useMachineActions } from "./machine/useMachineActions";
|
||||
import { useRoboticArmActions } from "./roboticArm/useRoboticArmActions";
|
||||
import { useStorageActions } from "./storageUnit/useStorageUnitActions";
|
||||
import { useVehicleActions } from "./vehicle/useVehicleActions";
|
||||
import { useCallback, useEffect } from "react";
|
||||
|
||||
export function useActionHandler() {
|
||||
const { isReset } = useResetButtonStore();
|
||||
const { isPlaying } = usePlayButtonStore();
|
||||
const { handleConveyorAction, cleanup: cleanupConveyor } = useConveyorActions();
|
||||
const { handleVehicleAction, cleanup: cleanupVehicle } = useVehicleActions();
|
||||
const { handleRoboticArmAction, cleanup: cleanupRoboticArm } = useRoboticArmActions();
|
||||
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
||||
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
||||
|
||||
const handleAction = useCallback((action: Action, materialId?: string) => {
|
||||
if (!action) return;
|
||||
try {
|
||||
switch (action.actionType) {
|
||||
case 'default': case 'spawn': case 'swap': case 'delay': case 'despawn':
|
||||
handleConveyorAction(action as ConveyorAction, materialId as string);
|
||||
break;
|
||||
case 'travel':
|
||||
handleVehicleAction(action as VehicleAction, materialId as string);
|
||||
break;
|
||||
case 'pickAndPlace':
|
||||
handleRoboticArmAction(action as RoboticArmAction, materialId as string);
|
||||
break;
|
||||
case 'process':
|
||||
handleMachineAction(action as MachineAction, materialId as string);
|
||||
break;
|
||||
case 'store': case 'retrieve':
|
||||
handleStorageAction(action as StorageAction, materialId as string);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown action type: ${(action as Action).actionType}`);
|
||||
}
|
||||
} catch (error) {
|
||||
echo.error("Failed to handle action");
|
||||
console.error("Error handling action:", error);
|
||||
}
|
||||
}, [handleConveyorAction, handleVehicleAction, handleRoboticArmAction, handleMachineAction, handleStorageAction,]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
cleanupConveyor();
|
||||
cleanupVehicle();
|
||||
cleanupRoboticArm();
|
||||
cleanupMachine();
|
||||
cleanupStorage();
|
||||
}, [cleanupConveyor, cleanupVehicle, cleanupRoboticArm, cleanupMachine, cleanupStorage,]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup, isReset, isPlaying]);
|
||||
|
||||
return {
|
||||
handleAction,
|
||||
cleanup,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { useCallback } from "react";
|
||||
import { useProductStore } from "../../../../../store/simulation/useProductStore";
|
||||
import { useSceneContext } from "../../../../scene/sceneContext";
|
||||
import { useProductContext } from "../../../products/productContext";
|
||||
|
||||
export function useTravelHandler() {
|
||||
const { materialStore, vehicleStore } = useSceneContext();
|
||||
const { selectedProductStore } = useProductContext();
|
||||
const { getMaterialById } = materialStore();
|
||||
const { getModelUuidByActionUuid } = useProductStore();
|
||||
const { selectedProduct } = selectedProductStore();
|
||||
const { incrementVehicleLoad, addCurrentMaterial } = vehicleStore();
|
||||
|
||||
const travelLogStatus = (materialUuid: string, status: string) => {
|
||||
echo.info(`${materialUuid}, ${status}`);
|
||||
}
|
||||
|
||||
const handleTravel = useCallback((action: VehicleAction, materialId?: string) => {
|
||||
if (!action || action.actionType !== 'travel' || !materialId) return;
|
||||
|
||||
const material = getMaterialById(materialId);
|
||||
if (!material) return;
|
||||
|
||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productUuid, action.actionUuid);
|
||||
|
||||
if (!modelUuid) return;
|
||||
|
||||
incrementVehicleLoad(modelUuid, 1);
|
||||
addCurrentMaterial(modelUuid, material.materialType, material.materialId);
|
||||
|
||||
travelLogStatus(material.materialName, `is triggering travel from ${modelUuid}`);
|
||||
|
||||
}, [addCurrentMaterial, getMaterialById, getModelUuidByActionUuid, incrementVehicleLoad, selectedProduct.productUuid]);
|
||||
|
||||
return {
|
||||
handleTravel,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect, useCallback } from 'react';
|
||||
import { useTravelHandler } from './actionHandler/useTravelHandler';
|
||||
|
||||
export function useVehicleActions() {
|
||||
const { handleTravel } = useTravelHandler();
|
||||
|
||||
const handleTravelAction = useCallback((action: VehicleAction, materialId: string) => {
|
||||
handleTravel(action, materialId);
|
||||
}, [handleTravel]);
|
||||
|
||||
const handleVehicleAction = useCallback((action: VehicleAction, materialId: string) => {
|
||||
if (!action) return;
|
||||
|
||||
switch (action.actionType) {
|
||||
case 'travel':
|
||||
handleTravelAction(action, materialId);
|
||||
break;
|
||||
default:
|
||||
console.warn(`Unknown vehicle action type: ${action.actionType}`);
|
||||
}
|
||||
}, [handleTravelAction]);
|
||||
|
||||
const cleanup = useCallback(() => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
cleanup();
|
||||
};
|
||||
}, [cleanup]);
|
||||
|
||||
return {
|
||||
handleVehicleAction,
|
||||
cleanup
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user