diff --git a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx
index a6a1fa9..4f96674 100644
--- a/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx
+++ b/app/src/components/layout/sidebarRight/properties/eventProperties/mechanics/conveyorMechanics.tsx
@@ -103,7 +103,7 @@ function ConveyorMechanics() {
const handleSpawnCountChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
- spawnCount: value === "inherit" ? "inherit" : parseFloat(value),
+ spawnCount: parseFloat(value),
});
if (event) {
@@ -119,7 +119,7 @@ function ConveyorMechanics() {
const handleSpawnIntervalChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
- spawnInterval: value === "inherit" ? "inherit" : parseFloat(value),
+ spawnInterval: parseFloat(value),
});
if (event) {
@@ -149,7 +149,7 @@ function ConveyorMechanics() {
const handleDelayChange = (value: string) => {
if (!selectedEventData || !selectedPointData) return;
const event = updateAction(selectedProduct.productId, selectedPointData.action.actionUuid, {
- delay: value === "inherit" ? "inherit" : parseFloat(value),
+ delay: parseFloat(value),
});
if (event) {
@@ -271,7 +271,7 @@ function ConveyorMechanics() {
-
+
>
diff --git a/app/src/modules/simulation/actions/conveyor/actionHandler/spawnActionHandler.ts b/app/src/modules/simulation/actions/conveyor/actionHandler/spawnActionHandler.ts
new file mode 100644
index 0000000..c28f1d0
--- /dev/null
+++ b/app/src/modules/simulation/actions/conveyor/actionHandler/spawnActionHandler.ts
@@ -0,0 +1,129 @@
+import { useCallback, 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";
+
+export function useSpawnHandler() {
+ const { addMaterial } = useMaterialStore();
+ const { getModelUuidByActionUuid } = useProductStore();
+ const { selectedProduct } = useSelectedProduct();
+ const lastSpawnTime = useRef(null);
+ const startTime = useRef(null);
+ const spawnCountRef = useRef(0);
+ const spawnParams = useRef<{
+ material: string;
+ intervalMs: number;
+ totalCount: number;
+ point: ConveyorPointSchema;
+ } | null>(null);
+
+ const clearCurrentSpawn = useCallback(() => {
+ lastSpawnTime.current = null;
+ startTime.current = null;
+ spawnCountRef.current = 0;
+ spawnParams.current = null;
+ }, []);
+
+ const spawnLogStatus = (materialUuid: string, status: string) => {
+ // console.log(`${materialUuid}, ${status}`);
+ }
+
+ const createNewMaterial = useCallback((materialType: string, point: ConveyorPointSchema) => {
+ const modelUuid = getModelUuidByActionUuid(selectedProduct.productId, point.action.actionUuid);
+ if (!modelUuid || !point.uuid) return;
+
+ const newMaterial: MaterialSchema = {
+ materialId: THREE.MathUtils.generateUUID(),
+ materialName: `${materialType}-${Date.now()}`,
+ materialType: materialType,
+ isActive: false,
+ isVisible: true,
+ isRendered: true,
+ current: {
+ modelUuid: modelUuid,
+ pointUuid: point.uuid,
+ actionUuid: point.action?.actionUuid || ''
+ },
+ weight: 1,
+ cost: 1
+ };
+
+ addMaterial(newMaterial);
+ return newMaterial;
+ }, [addMaterial]);
+
+ useFrame(() => {
+ if (!spawnParams.current || !startTime.current) return;
+
+ const currentTime = performance.now();
+ const { material, intervalMs, totalCount, point } = spawnParams.current;
+ const isFirstSpawn = lastSpawnTime.current === null;
+ const elapsed = currentTime - startTime.current;
+
+ // First spawn
+ if (isFirstSpawn) {
+ if (elapsed >= intervalMs) {
+ const createdMaterial = createNewMaterial(material, point);
+ if (createdMaterial) {
+ spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
+ }
+ lastSpawnTime.current = currentTime;
+ spawnCountRef.current = 1;
+
+ if (totalCount <= 1) {
+ clearCurrentSpawn();
+ }
+ }
+ return;
+ }
+
+ // Subsequent spawns
+ if (lastSpawnTime.current !== null) {
+ const timeSinceLast = currentTime - lastSpawnTime.current;
+ if (timeSinceLast >= intervalMs) {
+ const count = spawnCountRef.current + 1;
+ const createdMaterial = createNewMaterial(material, point);
+ if (createdMaterial) {
+ spawnLogStatus(createdMaterial.materialId, `[${elapsed.toFixed(2)}ms] Spawned ${material} (1/${totalCount})`);
+ }
+ lastSpawnTime.current = currentTime;
+ spawnCountRef.current = count;
+
+ if (count >= totalCount) {
+ clearCurrentSpawn();
+ }
+ }
+ }
+ });
+
+ const handleSpawn = useCallback((point: ConveyorPointSchema) => {
+ if (!point.action || point.action.actionType !== 'spawn') return;
+
+ const { material, spawnInterval = 0, spawnCount = 1 } = point.action;
+ const intervalMs = spawnInterval * 1000;
+
+ clearCurrentSpawn();
+
+ spawnParams.current = {
+ material,
+ intervalMs,
+ totalCount: spawnCount,
+ point: point
+ };
+
+ startTime.current = performance.now();
+ }, [clearCurrentSpawn]);
+
+ useEffect(() => {
+ return () => {
+ clearCurrentSpawn();
+ };
+ }, [clearCurrentSpawn]);
+
+ return {
+ handleSpawn,
+ clearCurrentSpawn
+ };
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts b/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts
new file mode 100644
index 0000000..e10e115
--- /dev/null
+++ b/app/src/modules/simulation/actions/conveyor/useConveyorActions.ts
@@ -0,0 +1,40 @@
+import { useEffect } from "react";
+import { useSpawnHandler } from "./actionHandler/spawnActionHandler";
+
+// Conveyor Actions
+export function useConveyorActions(point: ConveyorPointSchema) {
+ const { handleSpawn } = useSpawnHandler();
+
+ 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 () => {
+ // Cleanup if needed
+ };
+ }, [point]);
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/machine/useMachineActions.ts b/app/src/modules/simulation/actions/machine/useMachineActions.ts
new file mode 100644
index 0000000..0ac9865
--- /dev/null
+++ b/app/src/modules/simulation/actions/machine/useMachineActions.ts
@@ -0,0 +1,23 @@
+import { useEffect } from 'react';
+
+// Machine Actions
+export function useMachineActions(point: MachinePointSchema) {
+ 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 () => {
+ // Cleanup if needed
+ };
+ }, [point]);
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts b/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts
new file mode 100644
index 0000000..50a6196
--- /dev/null
+++ b/app/src/modules/simulation/actions/roboticArm/useRoboticArmActions.ts
@@ -0,0 +1,26 @@
+import { useEffect } from 'react';
+
+// Robotic Arm Actions
+export function useRoboticArmActions(point: RoboticArmPointSchema) {
+ 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 () => {
+ // Cleanup if needed
+ };
+ }, [point]);
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/storageUnit/useStorageUnitActions.ts b/app/src/modules/simulation/actions/storageUnit/useStorageUnitActions.ts
new file mode 100644
index 0000000..6ffa8ad
--- /dev/null
+++ b/app/src/modules/simulation/actions/storageUnit/useStorageUnitActions.ts
@@ -0,0 +1,22 @@
+import { useEffect } from 'react';
+
+// Storage Actions
+export function useStorageActions(point: StoragePointSchema) {
+ 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 () => {
+ // Cleanup if needed
+ };
+ }, [point]);
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/temp.md b/app/src/modules/simulation/actions/temp.md
deleted file mode 100644
index e69de29..0000000
diff --git a/app/src/modules/simulation/actions/useActionHandler.ts b/app/src/modules/simulation/actions/useActionHandler.ts
new file mode 100644
index 0000000..0975e83
--- /dev/null
+++ b/app/src/modules/simulation/actions/useActionHandler.ts
@@ -0,0 +1,25 @@
+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";
+
+// Master hook that selects the appropriate action handler
+export function useActionHandler(point: PointsScheme) {
+ if ('actions' in point) {
+ // Robotic Arm
+ useRoboticArmActions(point);
+ } else if (point.action.actionType === 'travel') {
+ // Vehicle
+ useVehicleActions(point as VehiclePointSchema);
+ } else if (point.action.actionType === 'process') {
+ // Machine
+ useMachineActions(point as MachinePointSchema);
+ } else if (point.action.actionType === 'store') {
+ // Storage
+ useStorageActions(point as StoragePointSchema);
+ } else {
+ // Conveyor
+ useConveyorActions(point as ConveyorPointSchema);
+ }
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts b/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts
new file mode 100644
index 0000000..7a6ce4d
--- /dev/null
+++ b/app/src/modules/simulation/actions/vehicle/useVehicleActions.ts
@@ -0,0 +1,26 @@
+import { useEffect } from 'react';
+
+// Vehicle Actions
+export function useVehicleActions(point: VehiclePointSchema) {
+ 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 () => {
+ // Cleanup if needed
+ };
+ }, [point]);
+}
\ No newline at end of file
diff --git a/app/src/modules/simulation/machine/instances/machineInstances.tsx b/app/src/modules/simulation/machine/instances/machineInstances.tsx
index 8536cac..594265d 100644
--- a/app/src/modules/simulation/machine/instances/machineInstances.tsx
+++ b/app/src/modules/simulation/machine/instances/machineInstances.tsx
@@ -6,8 +6,8 @@ function MachineInstances() {
const { machines } = useMachineStore();
return (
<>
- {machines.map((val: MachineStatus) => (
-
+ {machines.map((machine: MachineStatus) => (
+
))}
>
diff --git a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
index 466e235..01a5e43 100644
--- a/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
+++ b/app/src/modules/simulation/materials/instances/instance/materialInstance.tsx
@@ -1,9 +1,22 @@
-import React from 'react'
+import React, { useEffect, useState } from 'react'
+import * as THREE from 'three';
+import MaterialAnimator from '../animator/materialAnimator'
-function MaterialInstance() {
- return (
- <>>
- )
+function MaterialInstance({ material }: { material: MaterialSchema }) {
+ const [position, setPosition] = useState();
+ const [rotation, setRotation] = useState();
+
+ useEffect(() => {
+ // console.log('material: ', material);
+ }, [material])
+
+ return (
+ <>
+
+
+
+ >
+ )
}
export default MaterialInstance
\ No newline at end of file
diff --git a/app/src/modules/simulation/materials/instances/materialInstances.tsx b/app/src/modules/simulation/materials/instances/materialInstances.tsx
index 519cba9..1864f0f 100644
--- a/app/src/modules/simulation/materials/instances/materialInstances.tsx
+++ b/app/src/modules/simulation/materials/instances/materialInstances.tsx
@@ -1,14 +1,20 @@
-import React from 'react'
+import React, { useEffect } from 'react'
import MaterialInstance from './instance/materialInstance'
-import MaterialAnimator from './animator/materialAnimator'
+import { useMaterialStore } from '../../../../store/simulation/useMaterialStore';
function MaterialInstances() {
+ const { materials } = useMaterialStore();
+
+ useEffect(() => {
+ // console.log('materials: ', materials);
+ }, [materials])
+
return (
<>
-
-
-
+ {materials.map((material: MaterialSchema) =>
+
+ )}
>
)
diff --git a/app/src/modules/simulation/products/temp.md b/app/src/modules/simulation/products/temp.md
deleted file mode 100644
index e69de29..0000000
diff --git a/app/src/modules/simulation/simulation.tsx b/app/src/modules/simulation/simulation.tsx
index efacd53..7fe3c50 100644
--- a/app/src/modules/simulation/simulation.tsx
+++ b/app/src/modules/simulation/simulation.tsx
@@ -23,7 +23,7 @@ function Simulation() {
}, [events])
useEffect(() => {
- console.log('products: ', products);
+ // console.log('products: ', products);
}, [products])
return (
diff --git a/app/src/modules/simulation/simulator/simulator.tsx b/app/src/modules/simulation/simulator/simulator.tsx
index c4f1c40..66a1dc3 100644
--- a/app/src/modules/simulation/simulator/simulator.tsx
+++ b/app/src/modules/simulation/simulator/simulator.tsx
@@ -1,18 +1,238 @@
-import { useEffect } from 'react'
-import { useProductStore } from '../../../store/simulation/useProductStore'
+import { useProductStore } from '../../../store/simulation/useProductStore';
+import { useActionHandler } from '../actions/useActionHandler';
function Simulator() {
const { products } = useProductStore();
- useEffect(() => {
- // console.log('products: ', products);
- }, [products])
+ const executionOrder = determineExecutionOrder(products);
- return (
- <>
+ executionOrder.forEach(point => {
+ useActionHandler(point);
+ });
- >
- )
+ function determineExecutionSequences(products: productsSchema): PointsScheme[][] {
+ // Create maps for all points
+ const pointMap = new Map();
+ 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();
+ const reverseDependencyGraph = new Map();
+ const triggeredPoints = new Set();
+
+ 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();
+
+ 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));
+ }
+ });
+
+ return executionSequences;
+ }
+
+ function determineExecutionOrder(products: productsSchema): PointsScheme[] {
+ // Create maps for all events and points
+ const eventMap = new Map();
+ const pointMap = new Map();
+ const allPoints: PointsScheme[] = [];
+
+ // First pass: collect all points
+ products.forEach(product => {
+ product.eventDatas.forEach(event => {
+ eventMap.set(event.modelUuid, 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') {
+ pointMap.set(event.point.uuid, event.point);
+ allPoints.push(event.point);
+ } else if (event.type === 'roboticArm') {
+ pointMap.set(event.point.uuid, event.point);
+ allPoints.push(event.point);
+ }
+ });
+ });
+
+ // Build dependency graphs
+ const graph = new Map();
+ const reverseGraph = new Map();
+ const allTriggeredPoints = new Set();
+
+ 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);
+ allTriggeredPoints.add(targetUuid);
+
+ if (!reverseGraph.has(targetUuid)) {
+ reverseGraph.set(targetUuid, []);
+ }
+ reverseGraph.get(targetUuid)!.push(point.uuid);
+ }
+ });
+
+ graph.set(point.uuid, dependencies);
+ });
+
+ // Identify root points (points that trigger others but aren't triggered themselves)
+ const rootPoints = allPoints
+ .filter(point => !allTriggeredPoints.has(point.uuid))
+ .filter(point => {
+ // Only include roots that actually have triggers pointing FROM them
+ const triggers = extractTriggersFromPoint(point);
+ return triggers.some(t => t.triggeredAsset?.triggeredPoint?.pointUuid);
+ });
+
+ // If no root points found but we have triggered points, find the earliest triggers
+ if (rootPoints.length === 0 && allTriggeredPoints.size > 0) {
+ // This handles cases where we have circular dependencies
+ // but still want to include the triggered points
+ const minTriggerCount = Math.min(
+ ...Array.from(allTriggeredPoints)
+ .map(uuid => (graph.get(uuid) || []).length)
+ );
+ const potentialRoots = Array.from(allTriggeredPoints)
+ .filter(uuid => (graph.get(uuid) || []).length === minTriggerCount);
+
+ rootPoints.push(...potentialRoots.map(uuid => pointMap.get(uuid)!));
+ }
+
+ // Topological sort only for triggered points
+ const visited = new Set();
+ const temp = new Set();
+ const order: string[] = [];
+ let hasCycle = false;
+
+ function visit(node: string) {
+ if (temp.has(node)) {
+ hasCycle = true;
+ return;
+ }
+ if (visited.has(node)) return;
+
+ temp.add(node);
+
+ const dependencies = reverseGraph.get(node) || [];
+ for (const dep of dependencies) {
+ visit(dep);
+ }
+
+ temp.delete(node);
+ visited.add(node);
+ order.push(node);
+ }
+
+ // Start processing from root points
+ rootPoints.forEach(root => visit(root.uuid));
+
+ // Convert UUIDs back to points and filter out untriggered points
+ const triggeredPoints = order
+ .map(uuid => pointMap.get(uuid)!)
+ .filter(point => allTriggeredPoints.has(point.uuid) ||
+ rootPoints.some(root => root.uuid === point.uuid));
+
+ return triggeredPoints;
+ }
+
+ function extractTriggersFromPoint(point: PointsScheme): TriggerSchema[] {
+ if ('actions' in point) {
+ return point.actions.flatMap(action => action.triggers);
+ } else if ('action' in point) {
+ return point.action.triggers;
+ }
+ return [];
+ }
+
+ return <>>;
}
-export default Simulator
\ No newline at end of file
+export default Simulator;
\ No newline at end of file
diff --git a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
index fcc840d..7b29e2f 100644
--- a/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
+++ b/app/src/modules/simulation/vehicle/instances/vehicleInstances.tsx
@@ -9,8 +9,8 @@ function VehicleInstances() {
return (
<>
- {vehicles.map((val: VehicleStatus) =>
-
+ {vehicles.map((vehicle: VehicleStatus) =>
+
)}
>
diff --git a/app/src/store/simulation/useMaterialStore.ts b/app/src/store/simulation/useMaterialStore.ts
index 56a35a7..ba75460 100644
--- a/app/src/store/simulation/useMaterialStore.ts
+++ b/app/src/store/simulation/useMaterialStore.ts
@@ -4,16 +4,39 @@ import { immer } from 'zustand/middleware/immer';
type MaterialsStore = {
materials: MaterialsSchema;
- addMaterial: (material: MaterialSchema) => void;
- removeMaterial: (materialId: string) => void;
- updateMaterial: (materialId: string, updates: Partial) => void;
+ addMaterial: (material: MaterialSchema) => MaterialSchema | undefined;
+ removeMaterial: (materialId: string) => MaterialSchema | undefined;
+ updateMaterial: (materialId: string, updates: Partial) => MaterialSchema | undefined;
- setStartTime: (materialId: string, startTime: string) => void;
- setEndTime: (materialId: string, endTime: string) => void;
- setCost: (materialId: string, cost: number) => void;
- setWeight: (materialId: string, weight: number) => void;
+ setCurrentLocation: (
+ materialId: string,
+ location: {
+ modelUuid: string;
+ pointUuid: string;
+ actionUuid: string;
+ }
+ ) => MaterialSchema | undefined;
+
+ setNextLocation: (
+ materialId: string,
+ location?: {
+ modelUuid: string;
+ pointUuid: string;
+ actionUuid: string;
+ } | null
+ ) => MaterialSchema | undefined;
+
+ setStartTime: (materialId: string, startTime: string) => MaterialSchema | undefined;
+ setEndTime: (materialId: string, endTime: string) => MaterialSchema | undefined;
+ setCost: (materialId: string, cost: number) => MaterialSchema | undefined;
+ setWeight: (materialId: string, weight: number) => MaterialSchema | undefined;
+ setIsActive: (materialId: string, isActive: boolean) => MaterialSchema | undefined;
+ setIsVisible: (materialId: string, isVisible: boolean) => MaterialSchema | undefined;
+ setIsRendered: (materialId: string, isRendered: boolean) => MaterialSchema | undefined;
getMaterialById: (materialId: string) => MaterialSchema | undefined;
+ getMaterialsByPoint: (pointUuid: string) => MaterialSchema[];
+ getMaterialsByModel: (modelUuid: string) => MaterialSchema[];
};
export const useMaterialStore = create()(
@@ -21,56 +44,161 @@ export const useMaterialStore = create()(
materials: [],
addMaterial: (material) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
state.materials.push(material);
});
+ return updatedMaterial;
},
removeMaterial: (materialId) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
- state.materials = state.materials.filter(m => m.materialId !== materialId);
+ const material = state.materials.find(m => m.materialId === materialId);
+ if (material) {
+ state.materials.filter(m => m.materialId !== material.materialId);
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ }
});
+ return updatedMaterial;
},
updateMaterial: (materialId, updates) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
if (material) {
Object.assign(material, updates);
+ updatedMaterial = JSON.parse(JSON.stringify(material));
}
});
+ return updatedMaterial;
+ },
+
+ setCurrentLocation: (materialId, location) => {
+ let updatedMaterial: MaterialSchema | undefined;
+ set((state) => {
+ const material = state.materials.find(m => m.materialId === materialId);
+ if (material) {
+ material.current = location;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ }
+ });
+ return updatedMaterial;
+ },
+
+ setNextLocation: (materialId, location) => {
+ let updatedMaterial: MaterialSchema | undefined;
+ set((state) => {
+ const material = state.materials.find(m => m.materialId === materialId);
+ if (material) {
+ material.next = location || undefined;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ }
+ });
+ return updatedMaterial;
},
setStartTime: (materialId, startTime) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
- if (material) material.startTime = startTime;
+ if (material) {
+ material.startTime = startTime
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
});
+ return updatedMaterial;
},
setEndTime: (materialId, endTime) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
- if (material) material.endTime = endTime;
+ if (material) {
+ material.endTime = endTime;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
});
+ return updatedMaterial;
},
setCost: (materialId, cost) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
- if (material) material.cost = cost;
+ if (material) {
+ material.cost = cost;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
});
+ return updatedMaterial;
},
setWeight: (materialId, weight) => {
+ let updatedMaterial: MaterialSchema | undefined;
set((state) => {
const material = state.materials.find(m => m.materialId === materialId);
- if (material) material.weight = weight;
+ if (material) {
+ material.weight = weight;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
});
+ return updatedMaterial;
+ },
+
+ setIsActive: (materialId, isActive) => {
+ let updatedMaterial: MaterialSchema | undefined;
+ set((state) => {
+ const material = state.materials.find(m => m.materialId === materialId);
+ if (material) {
+ material.isActive = isActive;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
+ });
+ return updatedMaterial;
+ },
+
+ setIsVisible: (materialId, isVisible) => {
+ let updatedMaterial: MaterialSchema | undefined;
+ set((state) => {
+ const material = state.materials.find(m => m.materialId === materialId);
+ if (material) {
+ material.isVisible = isVisible;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
+ });
+ return updatedMaterial;
+ },
+
+ setIsRendered: (materialId, isRendered) => {
+ let updatedMaterial: MaterialSchema | undefined;
+ set((state) => {
+ const material = state.materials.find(m => m.materialId === materialId);
+ if (material) {
+ material.isRendered = isRendered;
+ updatedMaterial = JSON.parse(JSON.stringify(material));
+ };
+ });
+ return updatedMaterial;
},
getMaterialById: (materialId) => {
return get().materials.find(m => m.materialId === materialId);
},
+
+ getMaterialsByPoint: (pointUuid) => {
+ return get().materials.filter(m =>
+ m.current?.pointUuid === pointUuid ||
+ m.next?.pointUuid === pointUuid
+ );
+ },
+
+ getMaterialsByModel: (modelUuid) => {
+ return get().materials.filter(m =>
+ m.current?.modelUuid === modelUuid ||
+ m.next?.modelUuid === modelUuid
+ );
+ },
}))
-);
+);
\ No newline at end of file
diff --git a/app/src/store/simulation/useProductStore.ts b/app/src/store/simulation/useProductStore.ts
index c0be958..c24ec63 100644
--- a/app/src/store/simulation/useProductStore.ts
+++ b/app/src/store/simulation/useProductStore.ts
@@ -63,6 +63,7 @@ type ProductsStore = {
getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | 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;
+ getModelUuidByActionUuid: (productId: string, actionUuid: string) => (string) | undefined;
getTriggerByUuid: (productId: string, triggerUuid: string) => TriggerSchema | undefined;
getIsEventInProduct: (productId: string, modelUuid: string) => boolean;
};
@@ -573,6 +574,30 @@ export const useProductStore = create()(
return undefined;
},
+ getModelUuidByActionUuid: (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 event.modelUuid;
+ }
+ }
+ } else if ('point' in event) {
+ const point = (event as any).point;
+ if ('action' in point && point.action?.actionUuid === actionUuid) {
+ return event.modelUuid;
+ } else if ('actions' in point) {
+ const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
+ if (action) return event.modelUuid;
+ }
+ }
+ }
+ return undefined;
+ },
+
getTriggerByUuid: (productId, triggerUuid) => {
const product = get().products.find(p => p.productId === productId);
if (!product) return undefined;
diff --git a/app/src/types/simulationTypes.d.ts b/app/src/types/simulationTypes.d.ts
index 11d5156..a33056e 100644
--- a/app/src/types/simulationTypes.d.ts
+++ b/app/src/types/simulationTypes.d.ts
@@ -27,9 +27,9 @@ interface ConveyorPointSchema {
actionName: string;
actionType: "default" | "spawn" | "swap" | "delay" | "despawn";
material: string;
- delay: number | "inherit";
- spawnInterval: number | "inherit";
- spawnCount: number | "inherit";
+ delay: number;
+ spawnInterval: number;
+ spawnCount: number;
triggers: TriggerSchema[];
};
}
@@ -180,13 +180,27 @@ interface StorageUnitStatus extends StorageEventSchema {
interface MaterialSchema {
materialId: string;
- materialName: string;
+ materialName: stri9ng;
materialType: string;
isActive: boolean;
+ isVisible: boolean;
+ isRendered: boolean;
startTime?: string;
endTime?: string;
cost?: number;
weight?: number;
+
+ current: {
+ modelUuid: string;
+ pointUuid: string;
+ actionUuid: string;
+ };
+
+ next?: {
+ modelUuid: string;
+ pointUuid: string;
+ actionUuid: string;
+ };
}
type MaterialsSchema = MaterialSchema[];
\ No newline at end of file