171 lines
6.7 KiB
TypeScript
171 lines
6.7 KiB
TypeScript
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, assetStore } = useSceneContext();
|
|
const { getHumanById, clearLoadCount, setCurrentPhase } = humanStore();
|
|
const { getAssetById } = assetStore();
|
|
const { getActionByUuid } = productStore();
|
|
const { selectedProductStore } = useProductContext();
|
|
const { selectedProduct } = selectedProductStore();
|
|
|
|
const callbacksRef = useRef<Map<string, (() => void)[]>>(new Map());
|
|
const actionQueueRef = useRef<Map<string, { actionType: "worker" | "assembly", actionUuid: string }[]>>(new Map());
|
|
const isCooldownRef = useRef<Map<string, boolean>>(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 humanAsset = getAssetById(humanId);
|
|
const action = getActionByUuid(selectedProduct.productUuid, actionUuid) as HumanAction | undefined;
|
|
|
|
if (!humanAsset || !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" &&
|
|
humanAsset.animationState?.current === 'idle' &&
|
|
human.currentLoad < currentAction.loadCapacity
|
|
);
|
|
|
|
if (human.totalLoadCount >= currentAction.loadCount && actionUuid === human.currentAction?.actionUuid) {
|
|
queue.shift();
|
|
actionQueue.shift();
|
|
if (queue.length === 0) {
|
|
removeHumanFromMonitor(humanId);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
|
setCurrentPhase(human.modelUuid, 'init');
|
|
}
|
|
} else {
|
|
conditionMet = (
|
|
!human.isActive &&
|
|
human.state === "idle" &&
|
|
humanAsset.animationState?.current === 'idle' &&
|
|
human.currentLoad < action.loadCapacity
|
|
);
|
|
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
|
setCurrentPhase(human.modelUuid, 'init');
|
|
}
|
|
}
|
|
|
|
} else if (expectedActionType === "assembly") {
|
|
if (currentAction && currentAction.actionType === 'worker') {
|
|
conditionMet = (
|
|
!human.isActive &&
|
|
human.state === "idle" &&
|
|
humanAsset.animationState?.current === 'idle' &&
|
|
human.currentLoad < currentAction.loadCapacity
|
|
);
|
|
if (conditionMet && actionUuid !== human.currentAction?.actionUuid) {
|
|
setCurrentPhase(human.modelUuid, 'init');
|
|
}
|
|
} else {
|
|
conditionMet = (
|
|
!human.isActive &&
|
|
human.state === "idle" &&
|
|
humanAsset.animationState?.current === '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);
|
|
}
|
|
}
|
|
});
|
|
}, 0);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
callbacksRef.current.clear();
|
|
actionQueueRef.current.clear();
|
|
isCooldownRef.current.clear();
|
|
isMonitoringRef.current = false;
|
|
};
|
|
}, []);
|
|
|
|
return {
|
|
addHumanToMonitor,
|
|
removeHumanFromMonitor,
|
|
};
|
|
}
|