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, productStore } = useSceneContext(); const { getHumanById, clearLoadCount } = humanStore(); const { getActionByUuid } = productStore(); const { selectedProductStore } = useProductContext(); const { selectedProduct } = selectedProductStore(); const callbacksRef = useRef void)[]>>(new Map()); const actionQueueRef = 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.clear(); actionQueueRef.current.clear(); isCooldownRef.current.clear(); isMonitoringRef.current = false; } }, [isReset]); 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); 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) { isMonitoringRef.current = false; } }; 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 action = getActionByUuid(selectedProduct.productUuid, actionUuid) as HumanAction | undefined; if (!human || !action || action.actionType !== expectedActionType) return; let conditionMet = 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(); actionQueue.shift(); if (callback) callback(); if (queue.length === 0) { removeHumanFromMonitor(humanId); } else { isCooldownRef.current.set(humanId, true); setTimeout(() => { isCooldownRef.current.set(humanId, false); }, 1000); } } }); }); useEffect(() => { return () => { callbacksRef.current.clear(); actionQueueRef.current.clear(); isCooldownRef.current.clear(); isMonitoringRef.current = false; }; }, []); return { addHumanToMonitor, removeHumanFromMonitor, }; }