v2 #78
|
@ -28,6 +28,4 @@ export default async function setCameraView({
|
||||||
controls?.setLookAt(...newPosition.toArray(), newPosition.x, 0, newPosition.z, true);
|
controls?.setLookAt(...newPosition.toArray(), newPosition.x, 0, newPosition.z, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optionally you can log
|
|
||||||
console.log(`Camera view updated by ${username ?? 'unknown user'}`);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { useSelectedProduct } from "../../../../../store/simulation/useSimulatio
|
||||||
|
|
||||||
export function useSpawnHandler() {
|
export function useSpawnHandler() {
|
||||||
const { addMaterial } = useMaterialStore();
|
const { addMaterial } = useMaterialStore();
|
||||||
const { getModelUuidByActionUuid } = useProductStore();
|
const { getModelUuidByActionUuid, getPointUuidByActionUuid } = useProductStore();
|
||||||
const { selectedProduct } = useSelectedProduct();
|
const { selectedProduct } = useSelectedProduct();
|
||||||
const lastSpawnTime = useRef<number | null>(null);
|
const lastSpawnTime = useRef<number | null>(null);
|
||||||
const startTime = useRef<number | null>(null);
|
const startTime = useRef<number | null>(null);
|
||||||
|
@ -16,7 +16,7 @@ export function useSpawnHandler() {
|
||||||
material: string;
|
material: string;
|
||||||
intervalMs: number;
|
intervalMs: number;
|
||||||
totalCount: number;
|
totalCount: number;
|
||||||
point: ConveyorPointSchema;
|
action: ConveyorAction;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
const clearCurrentSpawn = useCallback(() => {
|
const clearCurrentSpawn = useCallback(() => {
|
||||||
|
@ -27,12 +27,13 @@ export function useSpawnHandler() {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const spawnLogStatus = (materialUuid: string, status: string) => {
|
const spawnLogStatus = (materialUuid: string, status: string) => {
|
||||||
// console.log(`${materialUuid}, ${status}`);
|
console.log(`${materialUuid}, ${status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const createNewMaterial = useCallback((materialType: string, point: ConveyorPointSchema) => {
|
const createNewMaterial = useCallback((materialType: string, action: ConveyorAction) => {
|
||||||
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, point.action.actionUuid);
|
const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, action.actionUuid);
|
||||||
if (!modelUuid || !point.uuid) return;
|
const pointUuid = getPointUuidByActionUuid(selectedProduct.productId, action.actionUuid);
|
||||||
|
if (!modelUuid || !pointUuid) return;
|
||||||
|
|
||||||
const newMaterial: MaterialSchema = {
|
const newMaterial: MaterialSchema = {
|
||||||
materialId: THREE.MathUtils.generateUUID(),
|
materialId: THREE.MathUtils.generateUUID(),
|
||||||
|
@ -43,8 +44,8 @@ export function useSpawnHandler() {
|
||||||
isRendered: true,
|
isRendered: true,
|
||||||
current: {
|
current: {
|
||||||
modelUuid: modelUuid,
|
modelUuid: modelUuid,
|
||||||
pointUuid: point.uuid,
|
pointUuid: pointUuid,
|
||||||
actionUuid: point.action?.actionUuid || ''
|
actionUuid: action?.actionUuid || ''
|
||||||
},
|
},
|
||||||
weight: 1,
|
weight: 1,
|
||||||
cost: 1
|
cost: 1
|
||||||
|
@ -58,14 +59,14 @@ export function useSpawnHandler() {
|
||||||
if (!spawnParams.current || !startTime.current) return;
|
if (!spawnParams.current || !startTime.current) return;
|
||||||
|
|
||||||
const currentTime = performance.now();
|
const currentTime = performance.now();
|
||||||
const { material, intervalMs, totalCount, point } = spawnParams.current;
|
const { material, intervalMs, totalCount, action } = spawnParams.current;
|
||||||
const isFirstSpawn = lastSpawnTime.current === null;
|
const isFirstSpawn = lastSpawnTime.current === null;
|
||||||
const elapsed = currentTime - startTime.current;
|
const elapsed = currentTime - startTime.current;
|
||||||
|
|
||||||
// First spawn
|
// First spawn
|
||||||
if (isFirstSpawn) {
|
if (isFirstSpawn) {
|
||||||
if (elapsed >= intervalMs) {
|
if (elapsed >= intervalMs) {
|
||||||
const createdMaterial = createNewMaterial(material, point);
|
const createdMaterial = createNewMaterial(material, action);
|
||||||
if (createdMaterial) {
|
if (createdMaterial) {
|
||||||
spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
|
spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
|
||||||
}
|
}
|
||||||
|
@ -84,9 +85,9 @@ export function useSpawnHandler() {
|
||||||
const timeSinceLast = currentTime - lastSpawnTime.current;
|
const timeSinceLast = currentTime - lastSpawnTime.current;
|
||||||
if (timeSinceLast >= intervalMs) {
|
if (timeSinceLast >= intervalMs) {
|
||||||
const count = spawnCountRef.current + 1;
|
const count = spawnCountRef.current + 1;
|
||||||
const createdMaterial = createNewMaterial(material, point);
|
const createdMaterial = createNewMaterial(material, action);
|
||||||
if (createdMaterial) {
|
if (createdMaterial) {
|
||||||
spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
|
spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (${count}/${totalCount})`);
|
||||||
}
|
}
|
||||||
lastSpawnTime.current = currentTime;
|
lastSpawnTime.current = currentTime;
|
||||||
spawnCountRef.current = count;
|
spawnCountRef.current = count;
|
||||||
|
@ -98,10 +99,10 @@ export function useSpawnHandler() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSpawn = useCallback((point: ConveyorPointSchema) => {
|
const handleSpawn = useCallback((action: ConveyorAction) => {
|
||||||
if (!point.action || point.action.actionType !== 'spawn') return;
|
if (!action || action.actionType !== 'spawn') return;
|
||||||
|
|
||||||
const { material, spawnInterval = 0, spawnCount = 1 } = point.action;
|
const { material, spawnInterval = 0, spawnCount = 1 } = action;
|
||||||
const intervalMs = spawnInterval * 1000;
|
const intervalMs = spawnInterval * 1000;
|
||||||
|
|
||||||
clearCurrentSpawn();
|
clearCurrentSpawn();
|
||||||
|
@ -110,7 +111,7 @@ export function useSpawnHandler() {
|
||||||
material,
|
material,
|
||||||
intervalMs,
|
intervalMs,
|
||||||
totalCount: spawnCount,
|
totalCount: spawnCount,
|
||||||
point: point
|
action: action
|
||||||
};
|
};
|
||||||
|
|
||||||
startTime.current = performance.now();
|
startTime.current = performance.now();
|
|
@ -1,40 +1,66 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect, useCallback, useRef } from "react";
|
||||||
import { useSpawnHandler } from "./actionHandler/spawnActionHandler";
|
import { useSpawnHandler } from "./actionHandler/useSpawnHandler";
|
||||||
|
|
||||||
// Conveyor Actions
|
export function useConveyorActions() {
|
||||||
export function useConveyorActions(point: ConveyorPointSchema) {
|
const { handleSpawn, clearCurrentSpawn } = useSpawnHandler();
|
||||||
const { handleSpawn } = useSpawnHandler();
|
|
||||||
|
const handleDefaultAction = useCallback((action: ConveyorAction) => {
|
||||||
|
console.log(`Default conveyor action ${action.actionUuid}`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleSpawnAction = useCallback((action: ConveyorAction) => {
|
||||||
|
handleSpawn(action);
|
||||||
|
}, [handleSpawn]);
|
||||||
|
|
||||||
|
const handleSwapAction = useCallback((action: ConveyorAction) => {
|
||||||
|
console.log(`Swapping to material ${action.material}`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDelayAction = useCallback((action: ConveyorAction) => {
|
||||||
|
const delayMs = (action.delay || 0) * 1000;
|
||||||
|
console.log(`Delaying for ${delayMs}ms`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDespawnAction = useCallback((action: ConveyorAction) => {
|
||||||
|
console.log(`Despawning material`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleConveyorAction = useCallback((action: ConveyorAction) => {
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
|
switch (action.actionType) {
|
||||||
|
case 'default':
|
||||||
|
handleDefaultAction(action);
|
||||||
|
break;
|
||||||
|
case 'spawn':
|
||||||
|
handleSpawnAction(action);
|
||||||
|
break;
|
||||||
|
case 'swap':
|
||||||
|
handleSwapAction(action);
|
||||||
|
break;
|
||||||
|
case 'delay':
|
||||||
|
handleDelayAction(action);
|
||||||
|
break;
|
||||||
|
case 'despawn':
|
||||||
|
handleDespawnAction(action);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown conveyor action type: ${action.actionType}`);
|
||||||
|
}
|
||||||
|
}, [handleDefaultAction, handleSpawnAction, handleSwapAction, handleDelayAction, handleDespawnAction]);
|
||||||
|
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
clearCurrentSpawn();
|
||||||
|
}, [clearCurrentSpawn]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!point.action) return;
|
|
||||||
|
|
||||||
const { actionType, material, delay, spawnInterval, spawnCount } = point.action;
|
|
||||||
|
|
||||||
const handleAction = () => {
|
|
||||||
switch (actionType) {
|
|
||||||
case 'default':
|
|
||||||
console.log(`Default conveyor action at point ${point.uuid}`);
|
|
||||||
break;
|
|
||||||
case 'spawn':
|
|
||||||
console.log(`Spawning material ${material} at point ${point.uuid}`);
|
|
||||||
handleSpawn(point);
|
|
||||||
break;
|
|
||||||
case 'swap':
|
|
||||||
console.log(`Swapping to material ${material} at point ${point.uuid}`);
|
|
||||||
break;
|
|
||||||
case 'delay':
|
|
||||||
console.log(`Delaying for ${delay}ms at point ${point.uuid}`);
|
|
||||||
break;
|
|
||||||
case 'despawn':
|
|
||||||
console.log(`Despawning material at point ${point.uuid}`);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
handleAction();
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Cleanup if needed
|
cleanup();
|
||||||
};
|
};
|
||||||
}, [point]);
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleConveyorAction,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -1,23 +1,35 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export function useMachineActions() {
|
||||||
|
|
||||||
|
const handleProcessAction = useCallback((action: MachineAction) => {
|
||||||
|
if (!action || action.actionType !== 'process') return;
|
||||||
|
console.log(`Machine processing for ${action.processTime}ms`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleMachineAction = useCallback((action: MachineAction) => {
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
|
switch (action.actionType) {
|
||||||
|
case 'process':
|
||||||
|
handleProcessAction(action);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown machine action type: ${action.actionType}`);
|
||||||
|
}
|
||||||
|
}, [handleProcessAction]);
|
||||||
|
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Machine Actions
|
|
||||||
export function useMachineActions(point: MachinePointSchema) {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!point.action) return;
|
|
||||||
|
|
||||||
const { actionType, processTime, swapMaterial } = point.action;
|
|
||||||
|
|
||||||
const handleAction = () => {
|
|
||||||
if (actionType === 'process') {
|
|
||||||
console.log(`Machine processing for ${processTime}ms at point ${point.uuid}`);
|
|
||||||
if (swapMaterial) {
|
|
||||||
console.log(`Swapping material to ${swapMaterial}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Cleanup if needed
|
cleanup();
|
||||||
};
|
};
|
||||||
}, [point]);
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleMachineAction,
|
||||||
|
cleanup,
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -1,26 +1,32 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
|
export function useRoboticArmActions() {
|
||||||
|
|
||||||
|
const handlePickAndPlace = useCallback((action: RoboticArmAction) => {
|
||||||
|
console.log(`Robotic arm pick and place`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleRoboticArmAction = useCallback((action: RoboticArmAction) => {
|
||||||
|
switch (action.actionType) {
|
||||||
|
case 'pickAndPlace':
|
||||||
|
handlePickAndPlace(action);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown robotic arm action type: ${action.actionType}`);
|
||||||
|
}
|
||||||
|
}, [handlePickAndPlace]);
|
||||||
|
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Robotic Arm Actions
|
|
||||||
export function useRoboticArmActions(point: RoboticArmPointSchema) {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
point.actions.forEach(action => {
|
|
||||||
const { actionType, process } = action;
|
|
||||||
|
|
||||||
const handleAction = () => {
|
|
||||||
if (actionType === 'pickAndPlace') {
|
|
||||||
console.log(`Robotic arm pick and place at point ${point.uuid}`);
|
|
||||||
if (process.startPoint) {
|
|
||||||
console.log(`Start point: ${process.startPoint}`);
|
|
||||||
}
|
|
||||||
if (process.endPoint) {
|
|
||||||
console.log(`End point: ${process.endPoint}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Cleanup if needed
|
cleanup();
|
||||||
};
|
};
|
||||||
}, [point]);
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleRoboticArmAction,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -1,22 +1,33 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useCallback, useRef, useState } from 'react';
|
||||||
|
|
||||||
|
export function useStorageActions() {
|
||||||
|
const handleStoreAction = useCallback((action: StorageAction) => {
|
||||||
|
if (!action || action.actionType !== 'store') return;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleStorageAction = useCallback((action: StorageAction) => {
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
|
switch (action.actionType) {
|
||||||
|
case 'store':
|
||||||
|
handleStoreAction(action);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown storage action type: ${action.actionType}`);
|
||||||
|
}
|
||||||
|
}, [handleStoreAction]);
|
||||||
|
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Storage Actions
|
|
||||||
export function useStorageActions(point: StoragePointSchema) {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!point.action) return;
|
|
||||||
|
|
||||||
const { actionType, materials, storageCapacity } = point.action;
|
|
||||||
|
|
||||||
const handleAction = () => {
|
|
||||||
if (actionType === 'store') {
|
|
||||||
console.log(`Storage action at point ${point.uuid}`);
|
|
||||||
console.log(`Materials: ${materials.map(m => m.materialName).join(', ')}`);
|
|
||||||
console.log(`Capacity: ${storageCapacity}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Cleanup if needed
|
cleanup();
|
||||||
};
|
};
|
||||||
}, [point]);
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleStorageAction,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -3,23 +3,76 @@ import { useMachineActions } from "./machine/useMachineActions";
|
||||||
import { useRoboticArmActions } from "./roboticArm/useRoboticArmActions";
|
import { useRoboticArmActions } from "./roboticArm/useRoboticArmActions";
|
||||||
import { useStorageActions } from "./storageUnit/useStorageUnitActions";
|
import { useStorageActions } from "./storageUnit/useStorageUnitActions";
|
||||||
import { useVehicleActions } from "./vehicle/useVehicleActions";
|
import { useVehicleActions } from "./vehicle/useVehicleActions";
|
||||||
|
import { useCallback, useEffect } from "react";
|
||||||
|
|
||||||
// Master hook that selects the appropriate action handler
|
export function useActionHandler() {
|
||||||
export function useActionHandler(point: PointsScheme) {
|
// Initialize all action handlers
|
||||||
if ('actions' in point) {
|
const { handleConveyorAction, cleanup: cleanupConveyor } = useConveyorActions();
|
||||||
// Robotic Arm
|
const { handleVehicleAction, cleanup: cleanupVehicle } = useVehicleActions();
|
||||||
useRoboticArmActions(point);
|
const { handleRoboticArmAction, cleanup: cleanupRoboticArm } = useRoboticArmActions();
|
||||||
} else if (point.action.actionType === 'travel') {
|
const { handleMachineAction, cleanup: cleanupMachine } = useMachineActions();
|
||||||
// Vehicle
|
const { handleStorageAction, cleanup: cleanupStorage } = useStorageActions();
|
||||||
useVehicleActions(point as VehiclePointSchema);
|
|
||||||
} else if (point.action.actionType === 'process') {
|
// Main handler function
|
||||||
// Machine
|
const handleAction = useCallback((action: Action) => {
|
||||||
useMachineActions(point as MachinePointSchema);
|
if (!action) return;
|
||||||
} else if (point.action.actionType === 'store') {
|
|
||||||
// Storage
|
try {
|
||||||
useStorageActions(point as StoragePointSchema);
|
switch (action.actionType) {
|
||||||
} else {
|
case 'default': case 'spawn': case 'swap': case 'delay': case 'despawn':
|
||||||
// Conveyor
|
handleConveyorAction(action as ConveyorAction);
|
||||||
useConveyorActions(point as ConveyorPointSchema);
|
break;
|
||||||
}
|
case 'travel':
|
||||||
|
handleVehicleAction(action as VehicleAction);
|
||||||
|
break;
|
||||||
|
case 'pickAndPlace':
|
||||||
|
handleRoboticArmAction(action as RoboticArmAction);
|
||||||
|
break;
|
||||||
|
case 'process':
|
||||||
|
handleMachineAction(action as MachineAction);
|
||||||
|
break;
|
||||||
|
case 'store':
|
||||||
|
handleStorageAction(action as StorageAction);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown action type: ${(action as Action).actionType}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error handling action:', error);
|
||||||
|
// Consider adding error recovery or notification here
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
handleConveyorAction,
|
||||||
|
handleVehicleAction,
|
||||||
|
handleRoboticArmAction,
|
||||||
|
handleMachineAction,
|
||||||
|
handleStorageAction
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cleanup all actions
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
cleanupConveyor();
|
||||||
|
cleanupVehicle();
|
||||||
|
cleanupRoboticArm();
|
||||||
|
cleanupMachine();
|
||||||
|
cleanupStorage();
|
||||||
|
}, [
|
||||||
|
cleanupConveyor,
|
||||||
|
cleanupVehicle,
|
||||||
|
cleanupRoboticArm,
|
||||||
|
cleanupMachine,
|
||||||
|
cleanupStorage
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Auto cleanup on unmount
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
cleanup();
|
||||||
|
};
|
||||||
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleAction,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -1,26 +1,37 @@
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
|
export function useVehicleActions() {
|
||||||
|
|
||||||
|
const handleTravelAction = useCallback((action: VehicleAction) => {
|
||||||
|
if (!action || action.actionType !== 'travel') return;
|
||||||
|
|
||||||
|
console.log(`Vehicle travel action ${action.actionUuid}`);
|
||||||
|
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleVehicleAction = useCallback((action: VehicleAction) => {
|
||||||
|
if (!action) return;
|
||||||
|
|
||||||
|
switch (action.actionType) {
|
||||||
|
case 'travel':
|
||||||
|
handleTravelAction(action);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`Unknown vehicle action type: ${action.actionType}`);
|
||||||
|
}
|
||||||
|
}, [handleTravelAction]);
|
||||||
|
|
||||||
|
const cleanup = useCallback(() => {
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Vehicle Actions
|
|
||||||
export function useVehicleActions(point: VehiclePointSchema) {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!point.action) return;
|
|
||||||
|
|
||||||
const { actionType, unLoadDuration, loadCapacity, steeringAngle } = point.action;
|
|
||||||
|
|
||||||
const handleAction = () => {
|
|
||||||
if (actionType === 'travel') {
|
|
||||||
console.log(`Vehicle travel action at point ${point.uuid}`);
|
|
||||||
if (point.action.pickUpPoint) {
|
|
||||||
console.log(`Pick up at: ${JSON.stringify(point.action.pickUpPoint)}`);
|
|
||||||
}
|
|
||||||
if (point.action.unLoadPoint) {
|
|
||||||
console.log(`Unload at: ${JSON.stringify(point.action.unLoadPoint)}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
// Cleanup if needed
|
cleanup();
|
||||||
};
|
};
|
||||||
}, [point]);
|
}, [cleanup]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleVehicleAction,
|
||||||
|
cleanup
|
||||||
|
};
|
||||||
}
|
}
|
|
@ -1,114 +1,21 @@
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useProductStore } from '../../../store/simulation/useProductStore';
|
import { useProductStore } from '../../../store/simulation/useProductStore';
|
||||||
import { useActionHandler } from '../actions/useActionHandler';
|
import { useActionHandler } from '../actions/useActionHandler';
|
||||||
|
|
||||||
function Simulator() {
|
function Simulator() {
|
||||||
const { products } = useProductStore();
|
const { products } = useProductStore();
|
||||||
|
const { handleAction } = useActionHandler();
|
||||||
|
|
||||||
const executionOrder = determineExecutionOrder(products);
|
useEffect(() => {
|
||||||
|
const executionOrder = determineExecutionOrder(products);
|
||||||
executionOrder.forEach(point => {
|
executionOrder.forEach(point => {
|
||||||
useActionHandler(point);
|
if ('actions' in point) {
|
||||||
});
|
handleAction(point.actions[0]);
|
||||||
|
}else{
|
||||||
function determineExecutionSequences(products: productsSchema): PointsScheme[][] {
|
handleAction(point.action);
|
||||||
// Create maps for all points
|
|
||||||
const pointMap = new Map<string, PointsScheme>();
|
|
||||||
const allPoints: PointsScheme[] = [];
|
|
||||||
|
|
||||||
// First pass: collect all points
|
|
||||||
products.forEach(product => {
|
|
||||||
product.eventDatas.forEach(event => {
|
|
||||||
if (event.type === 'transfer') {
|
|
||||||
event.points.forEach(point => {
|
|
||||||
pointMap.set(point.uuid, point);
|
|
||||||
allPoints.push(point);
|
|
||||||
});
|
|
||||||
} else if (event.type === 'vehicle' ||
|
|
||||||
event.type === 'machine' ||
|
|
||||||
event.type === 'storageUnit' ||
|
|
||||||
event.type === 'roboticArm') {
|
|
||||||
pointMap.set(event.point.uuid, event.point);
|
|
||||||
allPoints.push(event.point);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Build complete dependency graph
|
|
||||||
const dependencyGraph = new Map<string, string[]>();
|
|
||||||
const reverseDependencyGraph = new Map<string, string[]>();
|
|
||||||
const triggeredPoints = new Set<string>();
|
|
||||||
|
|
||||||
allPoints.forEach(point => {
|
|
||||||
const triggers = extractTriggersFromPoint(point);
|
|
||||||
const dependencies: string[] = [];
|
|
||||||
|
|
||||||
triggers.forEach(trigger => {
|
|
||||||
const targetUuid = trigger.triggeredAsset?.triggeredPoint?.pointUuid;
|
|
||||||
if (targetUuid && pointMap.has(targetUuid)) {
|
|
||||||
dependencies.push(targetUuid);
|
|
||||||
triggeredPoints.add(targetUuid);
|
|
||||||
|
|
||||||
if (!reverseDependencyGraph.has(targetUuid)) {
|
|
||||||
reverseDependencyGraph.set(targetUuid, []);
|
|
||||||
}
|
|
||||||
reverseDependencyGraph.get(targetUuid)!.push(point.uuid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dependencyGraph.set(point.uuid, dependencies);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Identify independent root points (points that trigger others but aren't triggered themselves)
|
|
||||||
const rootPoints = allPoints.filter(point => {
|
|
||||||
const hasOutgoingTriggers = extractTriggersFromPoint(point).some(
|
|
||||||
t => t.triggeredAsset?.triggeredPoint?.pointUuid
|
|
||||||
);
|
|
||||||
return hasOutgoingTriggers && !triggeredPoints.has(point.uuid);
|
|
||||||
});
|
|
||||||
|
|
||||||
// For each root point, build its complete trigger chain
|
|
||||||
const executionSequences: PointsScheme[][] = [];
|
|
||||||
|
|
||||||
function buildSequence(startUuid: string): PointsScheme[] {
|
|
||||||
const sequence: PointsScheme[] = [];
|
|
||||||
const visited = new Set<string>();
|
|
||||||
|
|
||||||
function traverse(uuid: string) {
|
|
||||||
if (visited.has(uuid)) return;
|
|
||||||
visited.add(uuid);
|
|
||||||
|
|
||||||
const point = pointMap.get(uuid);
|
|
||||||
if (point) {
|
|
||||||
sequence.push(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Follow forward dependencies
|
|
||||||
const nextPoints = dependencyGraph.get(uuid) || [];
|
|
||||||
nextPoints.forEach(nextUuid => traverse(nextUuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(startUuid);
|
|
||||||
return sequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build sequences for all root points
|
|
||||||
rootPoints.forEach(root => {
|
|
||||||
executionSequences.push(buildSequence(root.uuid));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle any triggered points not reachable from roots (isolated chains)
|
|
||||||
const processedPoints = new Set(
|
|
||||||
executionSequences.flat().map(p => p.uuid)
|
|
||||||
);
|
|
||||||
|
|
||||||
allPoints.forEach(point => {
|
|
||||||
if (triggeredPoints.has(point.uuid) && !processedPoints.has(point.uuid)) {
|
|
||||||
executionSequences.push(buildSequence(point.uuid));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}, [products, handleAction]);
|
||||||
return executionSequences;
|
|
||||||
}
|
|
||||||
|
|
||||||
function determineExecutionOrder(products: productsSchema): PointsScheme[] {
|
function determineExecutionOrder(products: productsSchema): PointsScheme[] {
|
||||||
// Create maps for all events and points
|
// Create maps for all events and points
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
import { useActionHandler } from '../../actions/useActionHandler';
|
||||||
|
|
||||||
|
export function useTriggerHandler() {
|
||||||
|
|
||||||
|
const triggerPointActions = useCallback((point: PointsScheme) => {
|
||||||
|
if (!point) return;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
triggerPointActions
|
||||||
|
};
|
||||||
|
}
|
|
@ -64,6 +64,7 @@ type ProductsStore = {
|
||||||
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => ConveyorPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
|
||||||
getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
getActionByUuid: (productId: string, actionUuid: string) => (ConveyorPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
|
||||||
getModelUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
getModelUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
||||||
|
getPointUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
|
||||||
getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined;
|
getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined;
|
||||||
getIsEventInProduct: (productId: string, modelUuid: string) => boolean;
|
getIsEventInProduct: (productId: string, modelUuid: string) => boolean;
|
||||||
};
|
};
|
||||||
|
@ -598,6 +599,30 @@ export const useProductStore = create<ProductsStore>()(
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getPointUuidByActionUuid: (productId, actionUuid) => {
|
||||||
|
const product = get().products.find(p => p.productId === productId);
|
||||||
|
if (!product) return undefined;
|
||||||
|
|
||||||
|
for (const event of product.eventDatas) {
|
||||||
|
if ('points' in event) {
|
||||||
|
for (const point of (event as ConveyorEventSchema).points) {
|
||||||
|
if (point.action?.actionUuid === actionUuid) {
|
||||||
|
return point.uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ('point' in event) {
|
||||||
|
const point = (event as any).point;
|
||||||
|
if ('action' in point && point.action?.actionUuid === actionUuid) {
|
||||||
|
return point.uuid;
|
||||||
|
} else if ('actions' in point) {
|
||||||
|
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
|
||||||
|
if (action) return point.uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
|
||||||
getTriggerByUuid: (productId, triggerUuid) => {
|
getTriggerByUuid: (productId, triggerUuid) => {
|
||||||
const product = get().products.find(p => p.productId === productId);
|
const product = get().products.find(p => p.productId === productId);
|
||||||
if (!product) return undefined;
|
if (!product) return undefined;
|
||||||
|
|
|
@ -203,4 +203,56 @@ interface MaterialSchema {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
type MaterialsSchema = MaterialSchema[];
|
type MaterialsSchema = MaterialSchema[];
|
||||||
|
|
||||||
|
|
||||||
|
interface ConveyorAction {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
actionType: "default" | "spawn" | "swap" | "delay" | "despawn";
|
||||||
|
material: string;
|
||||||
|
delay: number;
|
||||||
|
spawnInterval: number;
|
||||||
|
spawnCount: number;
|
||||||
|
triggers: TriggerSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VehicleAction {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
actionType: "travel";
|
||||||
|
unLoadDuration: number;
|
||||||
|
loadCapacity: number;
|
||||||
|
steeringAngle: number;
|
||||||
|
pickUpPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
|
||||||
|
unLoadPoint: { position: { x: number; y: number, z: number }, rotation: { x: number; y: number, z: number } } | null;
|
||||||
|
triggers: TriggerSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RoboticArmAction {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
actionType: "pickAndPlace";
|
||||||
|
process: { startPoint: [number, number, number] | null; endPoint: [number, number, number] | null; };
|
||||||
|
triggers: TriggerSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MachineAction {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
actionType: "process";
|
||||||
|
processTime: number;
|
||||||
|
swapMaterial: string;
|
||||||
|
triggers: TriggerSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StorageAction {
|
||||||
|
actionUuid: string;
|
||||||
|
actionName: string;
|
||||||
|
actionType: "store";
|
||||||
|
materials: { materialName: string; materialId: string; }[];
|
||||||
|
storageCapacity: number;
|
||||||
|
triggers: TriggerSchema[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type Action = ConveyorAction | VehicleAction | RoboticArmAction | MachineAction | StorageAction;
|
||||||
|
|
Loading…
Reference in New Issue