feat: Implement socket responses for collaboration features including model updates, line management, and zone handling

feat: Add temporary markdown files for simulation actions, events, products, and triggers

feat: Create events store with actions for managing events, points, actions, and triggers, including syncing with product store
This commit is contained in:
Jerald-Golden-B 2025-04-21 16:49:03 +05:30
parent 54cc3deb98
commit 78b9663d0f
15 changed files with 1564 additions and 1737 deletions

View File

@ -18,20 +18,20 @@ import Window from "../../assets/gltf-glb/window.glb";
////////// Zustand State Imports ////////// ////////// Zustand State Imports //////////
import { import {
useToggleView, useToggleView,
useDeletePointOrLine, useDeletePointOrLine,
useMovePoint, useMovePoint,
useActiveLayer, useActiveLayer,
useSocketStore, useSocketStore,
useWallVisibility, useWallVisibility,
useRoofVisibility, useRoofVisibility,
useShadows, useShadows,
useUpdateScene, useUpdateScene,
useWalls, useWalls,
useToolMode, useToolMode,
useRefTextUpdate, useRefTextUpdate,
useRenderDistance, useRenderDistance,
useLimitDistance, useLimitDistance,
} from "../../store/store"; } from "../../store/store";
////////// 3D Function Imports ////////// ////////// 3D Function Imports //////////
@ -40,7 +40,7 @@ import loadWalls from "./geomentries/walls/loadWalls";
import * as Types from "../../types/world/worldTypes"; import * as Types from "../../types/world/worldTypes";
import SocketResponses from "../collaboration/socketResponses.dev"; import SocketResponses from "../collaboration/socket/socketResponses.dev";
import FloorItemsGroup from "./groups/floorItemsGroup"; import FloorItemsGroup from "./groups/floorItemsGroup";
import FloorPlanGroup from "./groups/floorPlanGroup"; import FloorPlanGroup from "./groups/floorPlanGroup";
import FloorGroup from "./groups/floorGroup"; import FloorGroup from "./groups/floorGroup";
@ -57,317 +57,296 @@ import useModuleStore from "../../store/useModuleStore";
import MeasurementTool from "../scene/tools/measurementTool"; import MeasurementTool from "../scene/tools/measurementTool";
export default function Builder() { export default function Builder() {
const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements. const state = useThree<Types.ThreeState>(); // Importing the state from the useThree hook, which contains the scene, camera, and other Three.js elements.
const csg = useRef(); // Reference for CSG object, used for 3D modeling. const csg = useRef(); // Reference for CSG object, used for 3D modeling.
const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects. const CSGGroup = useRef() as Types.RefMesh; // Reference to a group of CSG objects.
const scene = useRef() as Types.RefScene; // Reference to the scene. const scene = useRef() as Types.RefScene; // Reference to the scene.
const camera = useRef() as Types.RefCamera; // Reference to the camera object. const camera = useRef() as Types.RefCamera; // Reference to the camera object.
const controls = useRef<any>(); // Reference to the controls object. const controls = useRef<any>(); // Reference to the controls object.
const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene. const raycaster = useRef() as Types.RefRaycaster; // Reference for raycaster used for detecting objects being pointed at in the scene.
const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control. const dragPointControls = useRef() as Types.RefDragControl; // Reference for drag point controls, an array for drag control.
// Assigning the scene and camera from the Three.js state to the references. // Assigning the scene and camera from the Three.js state to the references.
scene.current = state.scene; scene.current = state.scene;
camera.current = state.camera; camera.current = state.camera;
controls.current = state.controls; controls.current = state.controls;
raycaster.current = state.raycaster; raycaster.current = state.raycaster;
const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference. const plane = useRef<THREE.Mesh>(null); // Reference for a plane object for raycaster reference.
const grid = useRef() as any; // Reference for a grid object for raycaster reference. const grid = useRef() as any; // Reference for a grid object for raycaster reference.
const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line. const snappedPoint = useRef() as Types.RefVector3; // Reference for storing a snapped point at the (end = isSnapped) and (start = ispreSnapped) of the line.
const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end). const isSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (end).
const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc... const anglesnappedPoint = useRef() as Types.RefVector3; // Reference for storing an angle-snapped point when the line is in 90 degree etc...
const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active. const isAngleSnapped = useRef(false) as Types.RefBoolean; // Boolean to indicate if angle snapping is active.
const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point. const isSnappedUUID = useRef() as Types.RefString; // UUID reference to identify the snapped point.
const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start). const ispreSnapped = useRef(false) as Types.RefBoolean; // Boolean reference to indicate if an object is snapped at the (start).
const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items. const tempLoader = useRef() as Types.RefMesh; // Reference for a temporary loader for the floor items.
const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active. const isTempLoader = useRef() as Types.RefBoolean; // Reference to check if a temporary loader is active.
const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation. const Tube = useRef() as Types.RefTubeGeometry; // Reference for tubes used for reference line creation and updation.
const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn. const line = useRef([]) as Types.RefLine; // Reference for line which stores the current line that is being drawn.
const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn. const lines = useRef([]) as Types.RefLines; // Reference for lines which stores all the lines that are ever drawn.
const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn. const onlyFloorline = useRef<Types.OnlyFloorLine>([]); // Reference for floor lines which does not have walls or roof and have only floor used to store the current line that is being drawn.
const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn. const onlyFloorlines = useRef<Types.OnlyFloorLines>([]); // Reference for all the floor lines that are ever drawn.
const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw. const ReferenceLineMesh = useRef() as Types.RefMesh; // Reference for storing the mesh of the reference line for moving it during draw.
const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not. const LineCreated = useRef(false) as Types.RefBoolean; // Boolean to track whether the reference line is created or not.
const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed. const referencePole = useRef() as Types.RefMesh; // Reference for a pole that is used as the reference for the user to show where it is placed.
const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf). const itemsGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the floor items (Gltf).
const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors. const floorGroup = useRef() as Types.RefGroup; // Reference to the THREE.Group that has the roofs and the floors.
const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation. const AttachedObject = useRef() as Types.RefMesh; // Reference for an object that is attached using dbl click for transform controls rotation.
const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group. const floorPlanGroup = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines group and the points group.
const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn. const floorPlanGroupLine = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the lines that are drawn.
const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created. const floorPlanGroupPoint = useRef() as Types.RefGroup; // Reference for a THREE.Group that has the points that are created.
const floorGroupAisle = useRef() as Types.RefGroup; const floorGroupAisle = useRef() as Types.RefGroup;
const zoneGroup = useRef() as Types.RefGroup; const zoneGroup = useRef() as Types.RefGroup;
const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls. const currentLayerPoint = useRef([]) as Types.RefMeshArray; // Reference for points that re in the current layer used to update the points in drag controls.
const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted. const hoveredDeletablePoint = useRef() as Types.RefMesh; // Reference for the currently hovered point that can be deleted.
const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted. const hoveredDeletableLine = useRef() as Types.RefMesh; // Reference for the currently hovered line that can be deleted.
const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted. const hoveredDeletableFloorItem = useRef() as Types.RefMesh; // Reference for the currently hovered floor item that can be deleted.
const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted. const hoveredDeletableWallItem = useRef() as Types.RefMesh; // Reference for the currently hovered wall item that can be deleted.
const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted. const hoveredDeletablePillar = useRef() as Types.RefMesh; // Reference for the currently hovered pillar that can be deleted.
const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc... const currentWallItem = useRef() as Types.RefMesh; // Reference for the currently selected wall item that can be scaled, dragged etc...
const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position. const cursorPosition = new THREE.Vector3(); // 3D vector for storing the cursor position.
const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item. const [selectedItemsIndex, setSelectedItemsIndex] = useState<Types.Number | null>(null); // State for tracking the index of the selected item.
const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx. const { activeLayer, setActiveLayer } = useActiveLayer(); // State that changes based on which layer the user chooses in Layers.jsx.
const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D. const { toggleView, setToggleView } = useToggleView(); // State for toggling between 2D and 3D.
const { toolMode, setToolMode } = useToolMode(); const { toolMode, setToolMode } = useToolMode();
const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not. const { movePoint, setMovePoint } = useMovePoint(); // State that stores a boolean which represents whether the move mode is active or not.
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine(); const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { socket } = useSocketStore(); const { socket } = useSocketStore();
const { roofVisibility, setRoofVisibility } = useRoofVisibility(); const { roofVisibility, setRoofVisibility } = useRoofVisibility();
const { wallVisibility, setWallVisibility } = useWallVisibility(); const { wallVisibility, setWallVisibility } = useWallVisibility();
const { shadows, setShadows } = useShadows(); const { shadows, setShadows } = useShadows();
const { renderDistance, setRenderDistance } = useRenderDistance(); const { renderDistance, setRenderDistance } = useRenderDistance();
const { limitDistance, setLimitDistance } = useLimitDistance(); const { limitDistance, setLimitDistance } = useLimitDistance();
const { updateScene, setUpdateScene } = useUpdateScene(); const { updateScene, setUpdateScene } = useUpdateScene();
const { walls, setWalls } = useWalls(); const { walls, setWalls } = useWalls();
const { refTextupdate, setRefTextUpdate } = useRefTextUpdate(); const { refTextupdate, setRefTextUpdate } = useRefTextUpdate();
const { activeModule } = useModuleStore(); const { activeModule } = useModuleStore();
// const loader = new GLTFLoader(); // const loader = new GLTFLoader();
// const dracoLoader = new DRACOLoader(); // const dracoLoader = new DRACOLoader();
// dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/'); // dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
// loader.setDRACOLoader(dracoLoader); // loader.setDRACOLoader(dracoLoader);
////////// Assest Configuration Values ////////// ////////// Assest Configuration Values //////////
const AssetConfigurations: Types.AssetConfigurations = { const AssetConfigurations: Types.AssetConfigurations = {
arch: { arch: {
modelUrl: arch, modelUrl: arch,
scale: [0.75, 0.75, 0.75], scale: [0.75, 0.75, 0.75],
csgscale: [2, 4, 0.5], csgscale: [2, 4, 0.5],
csgposition: [0, 2, 0], csgposition: [0, 2, 0],
positionY: () => 0, positionY: () => 0,
type: "Fixed-Move", type: "Fixed-Move",
}, },
door: { door: {
modelUrl: door, modelUrl: door,
scale: [0.75, 0.75, 0.75], scale: [0.75, 0.75, 0.75],
csgscale: [2, 4, 0.5], csgscale: [2, 4, 0.5],
csgposition: [0, 2, 0], csgposition: [0, 2, 0],
positionY: () => 0, positionY: () => 0,
type: "Fixed-Move", type: "Fixed-Move",
}, },
window: { window: {
modelUrl: Window, modelUrl: Window,
scale: [0.75, 0.75, 0.75], scale: [0.75, 0.75, 0.75],
csgscale: [5, 3, 0.5], csgscale: [5, 3, 0.5],
csgposition: [0, 1.5, 0], csgposition: [0, 1.5, 0],
positionY: (intersectionPoint) => intersectionPoint.point.y, positionY: (intersectionPoint) => intersectionPoint.point.y,
type: "Free-Move", type: "Free-Move",
}, },
}; };
////////// All Toggle's ////////// ////////// All Toggle's //////////
useEffect(() => { useEffect(() => {
setRefTextUpdate((prevUpdate: number) => prevUpdate - 1); setRefTextUpdate((prevUpdate: number) => prevUpdate - 1);
if (dragPointControls.current) { if (dragPointControls.current) {
dragPointControls.current.enabled = false; dragPointControls.current.enabled = false;
} }
if (toggleView) { if (toggleView) {
Layer2DVisibility( Layer2DVisibility(
activeLayer, activeLayer,
floorPlanGroup, floorPlanGroup,
floorPlanGroupLine, floorPlanGroupLine,
floorPlanGroupPoint, floorPlanGroupPoint,
currentLayerPoint, currentLayerPoint,
dragPointControls dragPointControls
); );
} else { } else {
setToolMode(null); setToolMode(null);
setDeletePointOrLine(false); setDeletePointOrLine(false);
setMovePoint(false); setMovePoint(false);
loadWalls(lines, setWalls); loadWalls(lines, setWalls);
setUpdateScene(true); setUpdateScene(true);
line.current = []; line.current = [];
} }
}, [toggleView]); }, [toggleView]);
useEffect(() => { useEffect(() => {
THREE.Cache.clear(); THREE.Cache.clear();
THREE.Cache.enabled = true; THREE.Cache.enabled = true;
}, []); }, []);
useEffect(() => { useEffect(() => {
const email = localStorage.getItem("email"); const email = localStorage.getItem("email");
const organization = email!.split("@")[1].split(".")[0]; const organization = email!.split("@")[1].split(".")[0];
async function fetchVisibility() { async function fetchVisibility() {
const visibility = await findEnvironment( const visibility = await findEnvironment(
organization, organization,
localStorage.getItem("userId")! localStorage.getItem("userId")!
); );
if (visibility) { if (visibility) {
setRoofVisibility(visibility.roofVisibility); setRoofVisibility(visibility.roofVisibility);
setWallVisibility(visibility.wallVisibility); setWallVisibility(visibility.wallVisibility);
setShadows(visibility.shadowVisibility); setShadows(visibility.shadowVisibility);
setRenderDistance(visibility.renderDistance); setRenderDistance(visibility.renderDistance);
setLimitDistance(visibility.limitDistance); setLimitDistance(visibility.limitDistance);
} }
} }
fetchVisibility(); fetchVisibility();
}, []); }, []);
////////// UseFrame is Here ////////// ////////// UseFrame is Here //////////
useFrame(() => { useFrame(() => {
if (toolMode) { if (toolMode) {
Draw( Draw(
state, state,
plane, plane,
cursorPosition, cursorPosition,
floorPlanGroupPoint, floorPlanGroupPoint,
floorPlanGroupLine, floorPlanGroupLine,
snappedPoint, snappedPoint,
isSnapped, isSnapped,
isSnappedUUID, isSnappedUUID,
line, line,
lines, lines,
ispreSnapped, ispreSnapped,
floorPlanGroup, floorPlanGroup,
ReferenceLineMesh, ReferenceLineMesh,
LineCreated, LineCreated,
setRefTextUpdate, setRefTextUpdate,
Tube, Tube,
anglesnappedPoint, anglesnappedPoint,
isAngleSnapped, isAngleSnapped,
toolMode toolMode
); );
} }
}); });
////////// Return ////////// ////////// Return //////////
return ( return (
<> <>
<Ground grid={grid} plane={plane} /> <Ground grid={grid} plane={plane} />
<DistanceText key={toggleView} /> <DistanceText key={toggleView} />
<ReferenceDistanceText <ReferenceDistanceText
key={refTextupdate} key={refTextupdate}
line={ReferenceLineMesh.current} line={ReferenceLineMesh.current}
/> />
<SocketResponses <SocketResponses
floorPlanGroup={floorPlanGroup} floorPlanGroup={floorPlanGroup}
lines={lines} lines={lines}
floorGroup={floorGroup} floorGroup={floorGroup}
floorGroupAisle={floorGroupAisle} floorGroupAisle={floorGroupAisle}
scene={scene} scene={scene}
onlyFloorlines={onlyFloorlines} onlyFloorlines={onlyFloorlines}
AssetConfigurations={AssetConfigurations} AssetConfigurations={AssetConfigurations}
itemsGroup={itemsGroup} itemsGroup={itemsGroup}
isTempLoader={isTempLoader} isTempLoader={isTempLoader}
tempLoader={tempLoader} tempLoader={tempLoader}
currentLayerPoint={currentLayerPoint} currentLayerPoint={currentLayerPoint}
floorPlanGroupPoint={floorPlanGroupPoint} floorPlanGroupPoint={floorPlanGroupPoint}
floorPlanGroupLine={floorPlanGroupLine} floorPlanGroupLine={floorPlanGroupLine}
zoneGroup={zoneGroup} zoneGroup={zoneGroup}
dragPointControls={dragPointControls} dragPointControls={dragPointControls}
/> />
<WallsAndWallItems <WallsAndWallItems
CSGGroup={CSGGroup} CSGGroup={CSGGroup}
AssetConfigurations={AssetConfigurations} AssetConfigurations={AssetConfigurations}
setSelectedItemsIndex={setSelectedItemsIndex} setSelectedItemsIndex={setSelectedItemsIndex}
selectedItemsIndex={selectedItemsIndex} selectedItemsIndex={selectedItemsIndex}
currentWallItem={currentWallItem} currentWallItem={currentWallItem}
csg={csg} csg={csg}
lines={lines} lines={lines}
hoveredDeletableWallItem={hoveredDeletableWallItem} hoveredDeletableWallItem={hoveredDeletableWallItem}
/> />
<FloorItemsGroup <FloorItemsGroup
itemsGroup={itemsGroup} itemsGroup={itemsGroup}
hoveredDeletableFloorItem={hoveredDeletableFloorItem} hoveredDeletableFloorItem={hoveredDeletableFloorItem}
AttachedObject={AttachedObject} AttachedObject={AttachedObject}
floorGroup={floorGroup} floorGroup={floorGroup}
tempLoader={tempLoader} tempLoader={tempLoader}
isTempLoader={isTempLoader} isTempLoader={isTempLoader}
plane={plane} plane={plane}
/> />
<FloorGroup <FloorGroup
floorGroup={floorGroup} floorGroup={floorGroup}
lines={lines} lines={lines}
referencePole={referencePole} referencePole={referencePole}
hoveredDeletablePillar={hoveredDeletablePillar} hoveredDeletablePillar={hoveredDeletablePillar}
/> />
<FloorPlanGroup <FloorPlanGroup
floorPlanGroup={floorPlanGroup} floorPlanGroup={floorPlanGroup}
floorPlanGroupLine={floorPlanGroupLine} floorPlanGroupLine={floorPlanGroupLine}
floorPlanGroupPoint={floorPlanGroupPoint} floorPlanGroupPoint={floorPlanGroupPoint}
floorGroup={floorGroup} floorGroup={floorGroup}
currentLayerPoint={currentLayerPoint} currentLayerPoint={currentLayerPoint}
dragPointControls={dragPointControls} dragPointControls={dragPointControls}
hoveredDeletablePoint={hoveredDeletablePoint} hoveredDeletablePoint={hoveredDeletablePoint}
hoveredDeletableLine={hoveredDeletableLine} hoveredDeletableLine={hoveredDeletableLine}
plane={plane} plane={plane}
line={line} line={line}
lines={lines} lines={lines}
onlyFloorline={onlyFloorline} onlyFloorline={onlyFloorline}
onlyFloorlines={onlyFloorlines} onlyFloorlines={onlyFloorlines}
ReferenceLineMesh={ReferenceLineMesh} ReferenceLineMesh={ReferenceLineMesh}
LineCreated={LineCreated} LineCreated={LineCreated}
isSnapped={isSnapped} isSnapped={isSnapped}
ispreSnapped={ispreSnapped} ispreSnapped={ispreSnapped}
snappedPoint={snappedPoint} snappedPoint={snappedPoint}
isSnappedUUID={isSnappedUUID} isSnappedUUID={isSnappedUUID}
isAngleSnapped={isAngleSnapped} isAngleSnapped={isAngleSnapped}
anglesnappedPoint={anglesnappedPoint} anglesnappedPoint={anglesnappedPoint}
/> />
{/* <ZoneGroup <ZoneGroup />
zoneGroup={zoneGroup}
plane={plane}
floorPlanGroupLine={floorPlanGroupLine}
floorPlanGroupPoint={floorPlanGroupPoint}
line={line}
lines={lines}
currentLayerPoint={currentLayerPoint}
dragPointControls={dragPointControls}
floorPlanGroup={floorPlanGroup}
ReferenceLineMesh={ReferenceLineMesh}
LineCreated={LineCreated}
isSnapped={isSnapped}
ispreSnapped={ispreSnapped}
snappedPoint={snappedPoint}
isSnappedUUID={isSnappedUUID}
isAngleSnapped={isAngleSnapped}
anglesnappedPoint={anglesnappedPoint}
/> */}
<ZoneGroup /> <FloorGroupAilse
floorGroupAisle={floorGroupAisle}
plane={plane}
floorPlanGroupLine={floorPlanGroupLine}
floorPlanGroupPoint={floorPlanGroupPoint}
line={line}
lines={lines}
currentLayerPoint={currentLayerPoint}
dragPointControls={dragPointControls}
floorPlanGroup={floorPlanGroup}
ReferenceLineMesh={ReferenceLineMesh}
LineCreated={LineCreated}
isSnapped={isSnapped}
ispreSnapped={ispreSnapped}
snappedPoint={snappedPoint}
isSnappedUUID={isSnappedUUID}
isAngleSnapped={isAngleSnapped}
anglesnappedPoint={anglesnappedPoint}
/>
<FloorGroupAilse <MeasurementTool />
floorGroupAisle={floorGroupAisle}
plane={plane}
floorPlanGroupLine={floorPlanGroupLine}
floorPlanGroupPoint={floorPlanGroupPoint}
line={line}
lines={lines}
currentLayerPoint={currentLayerPoint}
dragPointControls={dragPointControls}
floorPlanGroup={floorPlanGroup}
ReferenceLineMesh={ReferenceLineMesh}
LineCreated={LineCreated}
isSnapped={isSnapped}
ispreSnapped={ispreSnapped}
snappedPoint={snappedPoint}
isSnappedUUID={isSnappedUUID}
isAngleSnapped={isAngleSnapped}
anglesnappedPoint={anglesnappedPoint}
/>
<MeasurementTool /> </>
);
{/* <DrieHtmlTemp itemsGroup={itemsGroup} /> */}
</>
);
} }

View File

@ -1,245 +0,0 @@
import { useEffect } from "react";
import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes';
import * as CONSTANTS from "../../../types/world/worldConstants";
import { useActiveLayer, useSocketStore, useDeleteTool, useDeletePointOrLine, useMovePoint, useToggleView, useUpdateScene, useNewLines, useToolMode } from "../../../store/store";
import { useThree } from "@react-three/fiber";
import arrayLineToObject from "../geomentries/lines/lineConvertions/arrayLineToObject";
import addPointToScene from "../geomentries/points/addPointToScene";
import addLineToScene from "../geomentries/lines/addLineToScene";
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
import getClosestIntersection from "../geomentries/lines/getClosestIntersection";
import loadZones from "../geomentries/zones/loadZones";
const ZoneGroup = ({ zoneGroup, plane, floorPlanGroupLine, floorPlanGroupPoint, line, lines, currentLayerPoint, dragPointControls, floorPlanGroup, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
const { toggleView, setToggleView } = useToggleView();
const { deleteTool, setDeleteTool } = useDeleteTool();
const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
const { toolMode, setToolMode } = useToolMode();
const { movePoint, setMovePoint } = useMovePoint();
const { socket } = useSocketStore();
const { activeLayer } = useActiveLayer();
const { gl, raycaster, camera, pointer } = useThree();
const { updateScene, setUpdateScene } = useUpdateScene();
const { newLines, setNewLines } = useNewLines();
useEffect(() => {
if (updateScene) {
loadZones(lines, zoneGroup);
setUpdateScene(false);
}
}, [updateScene])
useEffect(() => {
if (toolMode === "Zone") {
setDeletePointOrLine(false);
setMovePoint(false);
setDeleteTool(false);
} else {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
}
}, [toolMode])
useEffect(() => {
const canvasElement = gl.domElement;
let drag = false;
let isLeftMouseDown = false;
const onMouseDown = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = true;
drag = false;
}
};
const onMouseUp = (evt: any) => {
if (evt.button === 0) {
isLeftMouseDown = false;
}
}
const onMouseMove = () => {
if (isLeftMouseDown) {
drag = true;
}
};
const onContextMenu = (e: any) => {
e.preventDefault();
if (toolMode === "Zone") {
removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
}
};
const onMouseClick = (evt: any) => {
if (!plane.current || drag) return;
const intersects = raycaster.intersectObject(plane.current, true);
let intersectionPoint = intersects[0].point;
const points = floorPlanGroupPoint.current?.children ?? [];
const intersectsPoint = raycaster.intersectObjects(points, true).find(intersect => intersect.object.visible);
let intersectsLines: any = raycaster.intersectObjects(floorPlanGroupLine.current.children, true);
if (intersectsLines.length > 0 && intersects && intersects.length > 0 && !intersectsPoint) {
const lineType = intersectsLines[0].object.userData.linePoints[0][3];
if (lineType === CONSTANTS.lineConfig.zoneName) {
// console.log("intersected a zone line");
const ThroughPoint = (intersectsLines[0].object.geometry.parameters.path).getPoints(300);
let intersection = getClosestIntersection(ThroughPoint, intersectionPoint);
if (!intersection) return;
const point = addPointToScene(intersection, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
(line.current as Types.Line).push([new THREE.Vector3(intersection.x, 0.01, intersection.z), point.uuid, activeLayer, CONSTANTS.lineConfig.zoneName,]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
socket.emit('v1:Line:create', input);
setNewLines([line.current]);
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint];
}
}
} else if (intersectsPoint && intersects && intersects.length > 0) {
if (intersectsPoint.object.userData.type === CONSTANTS.lineConfig.zoneName) {
// console.log("intersected a zone point");
intersectionPoint = intersectsPoint.object.position;
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), intersectsPoint.object.uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
socket.emit('v1:Line:create', input);
setNewLines([line.current]);
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint];
ispreSnapped.current = false;
isSnapped.current = false;
}
}
} else if (intersects && intersects.length > 0) {
// console.log("intersected a empty area");
let uuid: string = "";
if (isAngleSnapped.current && anglesnappedPoint.current && line.current.length > 0) {
intersectionPoint = anglesnappedPoint.current;
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
uuid = point.uuid;
} else if (isSnapped.current && snappedPoint.current && line.current.length > 0) {
intersectionPoint = snappedPoint.current;
uuid = isSnappedUUID.current!;
} else if (ispreSnapped.current && snappedPoint.current) {
intersectionPoint = snappedPoint.current;
uuid = isSnappedUUID.current!;
} else {
const point = addPointToScene(intersectionPoint, CONSTANTS.pointConfig.zoneOuterColor, currentLayerPoint, floorPlanGroupPoint, dragPointControls, undefined, CONSTANTS.lineConfig.zoneName);
uuid = point.uuid;
}
(line.current as Types.Line).push([new THREE.Vector3(intersectionPoint.x, 0.01, intersectionPoint.z), uuid, activeLayer, CONSTANTS.lineConfig.zoneName]);
if (line.current.length >= 2 && line.current[0] && line.current[1]) {
lines.current.push(line.current as Types.Line);
const data = arrayLineToObject(line.current as Types.Line);
const email = localStorage.getItem('email')
const organization = (email!.split("@")[1]).split(".")[0];
//REST
// setLine(organization, data.layer!, data.line!, data.type!);
//SOCKET
const input = {
organization: organization,
layer: data.layer,
line: data.line,
type: data.type,
socketId: socket.id
}
socket.emit('v1:Line:create', input);
setNewLines([line.current]);
addLineToScene(line.current[0][0], line.current[1][0], CONSTANTS.lineConfig.zoneColor, line.current, floorPlanGroupLine);
let lastPoint = line.current[line.current.length - 1];
line.current = [lastPoint];
ispreSnapped.current = false;
isSnapped.current = false;
}
}
}
if (toolMode === 'Zone') {
canvasElement.addEventListener("mousedown", onMouseDown);
canvasElement.addEventListener("mouseup", onMouseUp);
canvasElement.addEventListener("mousemove", onMouseMove);
canvasElement.addEventListener("click", onMouseClick);
canvasElement.addEventListener("contextmenu", onContextMenu);
}
return () => {
canvasElement.removeEventListener("mousedown", onMouseDown);
canvasElement.removeEventListener("mouseup", onMouseUp);
canvasElement.removeEventListener("mousemove", onMouseMove);
canvasElement.removeEventListener("click", onMouseClick);
canvasElement.removeEventListener("contextmenu", onContextMenu);
};
}, [toolMode])
return (
<group ref={zoneGroup} visible={!toggleView} name="zoneGroup">
</group>
)
}
export default ZoneGroup;

View File

@ -2,7 +2,7 @@ import * as THREE from "three";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useFrame } from "@react-three/fiber"; import { useFrame } from "@react-three/fiber";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import camModel from "../../assets/gltf-glb/camera face 2.gltf"; import camModel from "../../../assets/gltf-glb/camera face 2.gltf";
import getActiveUsersData from "../../../services/factoryBuilder/collab/getActiveUsers"; import getActiveUsersData from "../../../services/factoryBuilder/collab/getActiveUsers";
import { useActiveUsers, useSocketStore } from "../../../store/store"; import { useActiveUsers, useSocketStore } from "../../../store/store";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";

View File

@ -6,6 +6,7 @@ import Builder from "../builder/builder";
import Visualization from "../visualization/visualization"; import Visualization from "../visualization/visualization";
import Setup from "./setup/setup"; import Setup from "./setup/setup";
import Simulation from "../simulation/simulation"; import Simulation from "../simulation/simulation";
import Collaboration from "../collaboration/collaboration";
export default function Scene() { export default function Scene() {
const map = useMemo(() => [ const map = useMemo(() => [
@ -21,6 +22,8 @@ export default function Scene() {
<Setup /> <Setup />
<Collaboration />
<Builder /> <Builder />
<Simulation /> <Simulation />

View File

@ -6,11 +6,11 @@ import UI from "./ui";
import { useEffect } from "react"; import { useEffect } from "react";
import { useThree } from "@react-three/fiber"; import { useThree } from "@react-three/fiber";
export default function DrieHtmlTemp({ itemsGroup }: { itemsGroup: Types.RefGroup }) { export default function DrieHtmlTemp() {
const { drieTemp, setDrieTemp } = useDrieTemp(); const { drieTemp, setDrieTemp } = useDrieTemp();
const { drieUIValue, setDrieUIValue } = useDrieUIValue(); const { drieUIValue, setDrieUIValue } = useDrieUIValue();
const state = useThree(); const state = useThree();
const { camera, raycaster } = state; const { camera, raycaster, scene } = state;
useEffect(() => { useEffect(() => {
const canvasElement = state.gl.domElement; const canvasElement = state.gl.domElement;
@ -34,8 +34,8 @@ export default function DrieHtmlTemp({ itemsGroup }: { itemsGroup: Types.RefGrou
if (evt.button === 0) { if (evt.button === 0) {
isLeftMouseDown = false; isLeftMouseDown = false;
if (drag) return; if (drag) return;
if (!itemsGroup.current) return if (!scene) return
let intersects = raycaster.intersectObjects(itemsGroup.current.children, true); let intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) { if (intersects.length > 0) {
let currentObject = intersects[0].object; let currentObject = intersects[0].object;

View File

@ -2,7 +2,8 @@ import React from 'react'
import Dropped3dWidgets from './widgets/3d/Dropped3dWidget' import Dropped3dWidgets from './widgets/3d/Dropped3dWidget'
import ZoneCentreTarget from './zone/zoneCameraTarget' import ZoneCentreTarget from './zone/zoneCameraTarget'
import ZoneAssets from './zone/zoneAssets' import ZoneAssets from './zone/zoneAssets'
// import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents' import MqttEvents from '../../services/factoryBuilder/mqtt/mqttEvents'
import DrieHtmlTemp from './mqttTemp/drieHtmlTemp'
const Visualization = () => { const Visualization = () => {
return ( return (
@ -10,11 +11,14 @@ const Visualization = () => {
<Dropped3dWidgets /> <Dropped3dWidgets />
{/* <ZoneCentreTarget /> <ZoneCentreTarget />
<ZoneAssets /> <ZoneAssets />
<MqttEvents /> */} <MqttEvents />
{/* <DrieHtmlTemp /> */}
</> </>
) )
} }

View File

@ -0,0 +1,349 @@
import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import { useProductStore } from './useSimulationStore';
type EventsStore = {
events: EventsSchema[];
// Sync with product store
syncFromProducts: (products: productsSchema) => void;
// Event-level actions
addEvent: (event: EventsSchema) => void;
removeEvent: (modelUuid: string) => void;
updateEvent: (modelUuid: string, updates: Partial<EventsSchema>) => void;
// Point-level actions
addPoint: (modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
removePoint: (modelUuid: string, pointUuid: string) => void;
updatePoint: (
modelUuid: string,
pointUuid: string,
updates: Partial<TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema>
) => void;
// Action-level actions
addAction: (
modelUuid: string,
pointUuid: string,
action: TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
) => void;
removeAction: (actionUuid: string) => void;
updateAction: (
actionUuid: string,
updates: Partial<TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
) => void;
// Trigger-level actions
addTrigger: (actionUuid: string, trigger: TriggerSchema) => void;
removeTrigger: (triggerUuid: string) => void;
updateTrigger: (triggerUuid: string, updates: Partial<TriggerSchema>) => void;
// Helper functions
getEventByModelUuid: (modelUuid: string) => EventsSchema | undefined;
getPointByUuid: (modelUuid: string, pointUuid: string) => TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
getActionByUuid: (actionUuid: string) => (TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']) | undefined;
getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined;
};
export const useEventsStore = create<EventsStore>()(
immer((set, get) => ({
events: [],
// Sync events from products store
syncFromProducts: (products) => {
set((state) => {
state.events = products.flatMap(product => product.eventsData);
});
},
// Event-level actions
addEvent: (event) => {
set((state) => {
state.events.push(event);
});
},
removeEvent: (modelUuid) => {
set((state) => {
state.events = state.events.filter(e => 'modelUuid' in e && e.modelUuid !== modelUuid);
});
},
updateEvent: (modelUuid, updates) => {
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event) {
Object.assign(event, updates);
}
});
},
// Point-level actions
addPoint: (modelUuid, point) => {
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
(event as TransferEventSchema).points.push(point as TransferPointSchema);
} else if (event && 'point' in event) {
(event as VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent).point = point as any;
}
});
},
removePoint: (modelUuid, pointUuid) => {
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
(event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid);
}
// For single-point events, you might want to handle differently
});
},
updatePoint: (modelUuid, pointUuid, updates) => {
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid);
if (point) {
Object.assign(point, updates);
}
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
Object.assign((event as any).point, updates);
}
});
},
// Action-level actions
addAction: (modelUuid, pointUuid, action) => {
set((state) => {
const event = state.events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid);
if (point) {
point.action = action as any;
}
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
if ('action' in (event as any).point) {
(event as any).point.action = action;
} else if ('actions' in (event as any).point) {
(event as any).point.actions.push(action);
}
}
});
},
removeAction: (actionUuid) => {
set((state) => {
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
// Handle removal for single action points
}
}
} else if ('point' in event) {
const point = (event as any).point;
if (event.type === "roboticArm") {
if ('actions' in point) {
point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
}
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
// Handle single action
}
}
}
});
},
updateAction: (actionUuid, updates) => {
set((state) => {
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
Object.assign(point.action, updates);
return;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) {
Object.assign(point.action, updates);
return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
Object.assign(action, updates);
return;
}
}
}
}
});
},
// Trigger-level actions
addTrigger: (actionUuid, trigger) => {
set((state) => {
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
point.action.triggers.push(trigger);
return;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) {
point.action.triggers.push(trigger);
return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
action.triggers.push(trigger);
return;
}
}
}
}
});
},
removeTrigger: (triggerUuid) => {
set((state) => {
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && 'triggers' in point.action) {
point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && 'triggers' in point.action) {
point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
}
}
}
}
}
});
},
updateTrigger: (triggerUuid, updates) => {
set((state) => {
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && 'triggers' in point.action) {
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
if (trigger) {
Object.assign(trigger, updates);
return;
}
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && 'triggers' in point.action) {
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) {
Object.assign(trigger, updates);
return;
}
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) {
Object.assign(trigger, updates);
return;
}
}
}
}
}
}
});
},
// Helper functions
getEventByModelUuid: (modelUuid) => {
return get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
},
getPointByUuid: (modelUuid, pointUuid) => {
const event = get().events.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
return (event as TransferEventSchema).points.find(p => p.uuid === pointUuid);
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
return (event as any).point;
}
return undefined;
},
getActionByUuid: (actionUuid) => {
const state = get();
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && point.action.actionUuid === actionUuid) {
return point.action;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && point.action.actionUuid === actionUuid) {
return point.action;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) return action;
}
}
}
return undefined;
},
getTriggerByUuid: (triggerUuid) => {
const state = get();
for (const event of state.events) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
if (point.action && 'triggers' in point.action) {
const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
if (trigger) return trigger;
}
}
} else if ('point' in event) {
const point = (event as any).point;
if ('action' in point && 'triggers' in point.action) {
const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) return trigger;
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) return trigger;
}
}
}
}
}
return undefined;
}
}))
);
// Set up automatic syncing between stores
useProductStore.subscribe(
(state) => {
useEventsStore.getState().syncFromProducts(state.products);
}
);

View File

@ -1,134 +1,6 @@
import { create } from 'zustand'; import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer'; import { immer } from 'zustand/middleware/immer';
interface AssetEventSchema {
modelUuid: string;
modelName: string;
position: [number, number, number];
rotation: [number, number, number];
state: "idle" | "running" | "stopped" | "disabled" | "error";
}
interface TriggerSchema {
triggerUuid: string;
triggerName: string;
triggerType: "onComplete" | "onStart" | "onStop" | "delay" | "onError";
delay: number;
triggeredAsset: {
triggeredModel: { modelName: string, modelUuid: string };
triggeredAction: { actionName: string, actionUuid: string };
} | null;
}
interface TransferPointSchema {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: {
actionUuid: string;
actionName: string;
actionType: "default" | "spawn" | "swap" | "despawn";
material: string | "inherit";
delay: number | "inherit";
spawnInterval: number | "inherit";
spawnCount: number | "inherit";
triggers: TriggerSchema[];
}[];
}
interface VehiclePointSchema {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: {
actionUuid: string;
actionName: string;
actionType: "travel";
material: string;
unLoadDuration: number;
loadCapacity: number;
pickUpPoint: { x: number; y: number, z: number } | {};
unLoadPoint: { x: number; y: number, z: number } | {};
triggers: TriggerSchema[];
}[];
}
interface RoboticArmPointSchema {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: {
actionUuid: string;
actionName: string;
actionType: "pickAndPlace";
process: { startPoint: string; endPoint: string };
triggers: TriggerSchema[];
}[];
}
interface MachinePointSchema {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: {
actionUuid: string;
actionName: string;
actionType: "process";
processTime: number;
swapMaterial: string;
triggers: TriggerSchema[];
}[];
}
interface StoragePointSchema {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: {
actionUuid: string;
actionName: string;
actionType: "storage";
materials: { materialName: string; materialId: string; quantity: number }[];
storageCapacity: number;
}[];
}
interface TransferEventSchema extends AssetEventSchema {
type: "transfer";
speed: number;
points: TransferPointSchema[];
}
interface VehicleSchemaEvent extends AssetEventSchema {
type: "vehicle";
speed: number;
point: VehiclePointSchema;
}
interface RoboticArmSchemaEvent extends AssetEventSchema {
type: "roboticArm";
speed: number;
point: RoboticArmPointSchema;
}
interface MachineSchemaEvent extends AssetEventSchema {
type: "machine";
point: MachinePointSchema;
}
interface StorageSchemaEvent extends AssetEventSchema {
type: "storageUnit";
point: StoragePointSchema;
}
type EventsSchema = TransferEventSchema | VehicleSchemaEvent | RoboticArmSchemaEvent | MachineSchemaEvent | StorageSchemaEvent | [];
type productsSchema = {
productName: string;
productId: string;
eventsData: EventsSchema[];
}[]
type Store = { type Store = {
products: productsSchema; products: productsSchema;
@ -138,14 +10,14 @@ type Store = {
updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void; updateProduct: (productId: string, updates: Partial<{ productName: string; eventsData: EventsSchema[] }>) => void;
// Event-level actions // Event-level actions
addEventToProduct: (productId: string, event: EventsSchema) => void; addEvent: (productId: string, event: EventsSchema) => void;
removeEventFromProduct: (productId: string, modelUuid: string) => void; removeEvent: (productId: string, modelUuid: string) => void;
updateEventInProduct: (productId: string, modelUuid: string, updates: Partial<EventsSchema>) => void; updateEvent: (productId: string, modelUuid: string, updates: Partial<EventsSchema>) => void;
// Point-level actions // Point-level actions
addPointToEvent: (productId: string, modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void; addPoint: (productId: string, modelUuid: string, point: TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema) => void;
removePointFromEvent: (productId: string, modelUuid: string, pointUuid: string) => void; removePoint: (productId: string, modelUuid: string, pointUuid: string) => void;
updatePointInEvent: ( updatePoint: (
productId: string, productId: string,
modelUuid: string, modelUuid: string,
pointUuid: string, pointUuid: string,
@ -157,12 +29,12 @@ type Store = {
productId: string, productId: string,
modelUuid: string, modelUuid: string,
pointUuid: string, pointUuid: string,
action: TransferPointSchema['actions'][0] | VehiclePointSchema['actions'][0] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['actions'][0] | StoragePointSchema['actions'][0] action: TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']
) => void; ) => void;
removeAction: (actionUuid: string) => void; removeAction: (actionUuid: string) => void;
updateAction: ( updateAction: (
actionUuid: string, actionUuid: string,
updates: Partial<TransferPointSchema['actions'][0] | VehiclePointSchema['actions'][0] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['actions'][0] | StoragePointSchema['actions'][0]> updates: Partial<TransferPointSchema['action'] | VehiclePointSchema['action'] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['action'] | StoragePointSchema['action']>
) => void; ) => void;
// Trigger-level actions // Trigger-level actions
@ -178,16 +50,11 @@ type Store = {
// Helper functions // Helper functions
getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined; getProductById: (productId: string) => { productName: string; productId: string; eventsData: EventsSchema[] } | undefined;
getEventByModelUuid: (productId: string, modelUuid: string) => EventsSchema | undefined;
getPointByUuid: (productId: string, modelUuid: string, pointUuid: string) => TransferPointSchema | VehiclePointSchema | RoboticArmPointSchema | MachinePointSchema | StoragePointSchema | undefined;
getActionByUuid: (actionUuid: string) => (TransferPointSchema['actions'][0] | VehiclePointSchema['actions'][0] | RoboticArmPointSchema['actions'][0] | MachinePointSchema['actions'][0] | StoragePointSchema['actions'][0]) | undefined;
getTriggerByUuid: (triggerUuid: string) => TriggerSchema | undefined;
}; };
export const useProductStore = create<Store>()( export const useProductStore = create<Store>()(
immer((set, get) => ({ immer((set, get) => ({
products: [], products: [],
activeProductId: null,
// Product-level actions // Product-level actions
addProduct: (productName, productId) => { addProduct: (productName, productId) => {
@ -217,7 +84,7 @@ export const useProductStore = create<Store>()(
}, },
// Event-level actions // Event-level actions
addEventToProduct: (productId, event) => { addEvent: (productId, event) => {
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@ -226,7 +93,7 @@ export const useProductStore = create<Store>()(
}); });
}, },
removeEventFromProduct: (productId, modelUuid) => { removeEvent: (productId, modelUuid) => {
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@ -235,7 +102,7 @@ export const useProductStore = create<Store>()(
}); });
}, },
updateEventInProduct: (productId, modelUuid, updates) => { updateEvent: (productId, modelUuid, updates) => {
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@ -248,7 +115,7 @@ export const useProductStore = create<Store>()(
}, },
// Point-level actions // Point-level actions
addPointToEvent: (productId, modelUuid, point) => { addPoint: (productId, modelUuid, point) => {
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@ -262,7 +129,7 @@ export const useProductStore = create<Store>()(
}); });
}, },
removePointFromEvent: (productId, modelUuid, pointUuid) => { removePoint: (productId, modelUuid, pointUuid) => {
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@ -271,13 +138,12 @@ export const useProductStore = create<Store>()(
(event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid); (event as TransferEventSchema).points = (event as TransferEventSchema).points.filter(p => p.uuid !== pointUuid);
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
// For events with single point, we can't remove it, only reset to empty // For events with single point, we can't remove it, only reset to empty
// You might want to handle this differently
} }
} }
}); });
}, },
updatePointInEvent: (productId, modelUuid, pointUuid, updates) => { updatePoint: (productId, modelUuid, pointUuid, updates) => {
set((state) => { set((state) => {
const product = state.products.find(p => p.productId === productId); const product = state.products.find(p => p.productId === productId);
if (product) { if (product) {
@ -303,25 +169,37 @@ export const useProductStore = create<Store>()(
if (event && 'points' in event) { if (event && 'points' in event) {
const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid); const point = (event as TransferEventSchema).points.find(p => p.uuid === pointUuid);
if (point) { if (point) {
point.actions.push(action as any); point.action = action as any;
} }
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) { } else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
(event as any).point.actions.push(action); if ('action' in (event as any).point) {
(event as any).point.action = action;
} else if ('actions' in (event as any).point) {
(event as any).point.actions.push(action);
}
} }
} }
}); });
}, },
removeAction: (actionUuid) => { removeAction: (actionUuid: string) => {
set((state) => { set((state) => {
for (const product of state.products) { for (const product of state.products) {
for (const event of product.eventsData) { for (const event of product.eventsData) {
if ('points' in event) { if ('points' in event) {
// Handle TransferEventSchema
for (const point of (event as TransferEventSchema).points) { for (const point of (event as TransferEventSchema).points) {
point.actions = point.actions.filter(a => a.actionUuid !== actionUuid);
} }
} else if ('point' in event) { } else if ('point' in event) {
(event as any).point.actions = (event as any).point.actions.filter((a: any) => a.actionUuid !== actionUuid); const point = (event as any).point;
if (event.type === "roboticArm") {
// Handle RoboticArmSchemaEvent
if ('actions' in point) {
point.actions = point.actions.filter((a: any) => a.actionUuid !== actionUuid);
}
} else if ('action' in point && point.action?.actionUuid === actionUuid) {
// For other schemas with a single 'action'
}
} }
} }
} }
@ -334,17 +212,22 @@ export const useProductStore = create<Store>()(
for (const event of product.eventsData) { for (const event of product.eventsData) {
if ('points' in event) { if ('points' in event) {
for (const point of (event as TransferEventSchema).points) { for (const point of (event as TransferEventSchema).points) {
const action = point.actions.find(a => a.actionUuid === actionUuid); if (point.action && point.action.actionUuid === actionUuid) {
if (action) { Object.assign(point.action, updates);
Object.assign(action, updates);
return; return;
} }
} }
} else if ('point' in event) { } else if ('point' in event) {
const action = (event as any).point.actions.find((a: any) => a.actionUuid === actionUuid); const point = (event as any).point;
if (action) { if ('action' in point && point.action.actionUuid === actionUuid) {
Object.assign(action, updates); Object.assign(point.action, updates);
return; return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
Object.assign(action, updates);
return;
}
} }
} }
} }
@ -359,17 +242,22 @@ export const useProductStore = create<Store>()(
for (const event of product.eventsData) { for (const event of product.eventsData) {
if ('points' in event) { if ('points' in event) {
for (const point of (event as TransferEventSchema).points) { for (const point of (event as TransferEventSchema).points) {
const action = point.actions.find(a => a.actionUuid === actionUuid); if (point.action && point.action.actionUuid === actionUuid) {
if (action && 'triggers' in action) { point.action.triggers.push(trigger);
action.triggers.push(trigger);
return; return;
} }
} }
} else if ('point' in event) { } else if ('point' in event) {
const action = (event as any).point.actions.find((a: any) => a.actionUuid === actionUuid); const point = (event as any).point;
if (action && 'triggers' in action) { if ('action' in point && point.action.actionUuid === actionUuid) {
action.triggers.push(trigger); point.action.triggers.push(trigger);
return; return;
} else if ('actions' in point) {
const action = point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) {
action.triggers.push(trigger);
return;
}
} }
} }
} }
@ -383,16 +271,19 @@ export const useProductStore = create<Store>()(
for (const event of product.eventsData) { for (const event of product.eventsData) {
if ('points' in event) { if ('points' in event) {
for (const point of (event as TransferEventSchema).points) { for (const point of (event as TransferEventSchema).points) {
for (const action of point.actions) { if (point.action && 'triggers' in point.action) {
if ('triggers' in action) { point.action.triggers = point.action.triggers.filter(t => t.triggerUuid !== triggerUuid);
action.triggers = action.triggers.filter(t => t.triggerUuid !== triggerUuid);
}
} }
} }
} else if ('point' in event) { } else if ('point' in event) {
for (const action of (event as any).point.actions) { const point = (event as any).point;
if ('triggers' in action) { if ('action' in point && 'triggers' in point.action) {
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid); point.action.triggers = point.action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
action.triggers = action.triggers.filter((t: any) => t.triggerUuid !== triggerUuid);
}
} }
} }
} }
@ -407,23 +298,30 @@ export const useProductStore = create<Store>()(
for (const event of product.eventsData) { for (const event of product.eventsData) {
if ('points' in event) { if ('points' in event) {
for (const point of (event as TransferEventSchema).points) { for (const point of (event as TransferEventSchema).points) {
for (const action of point.actions) { if (point.action && 'triggers' in point.action) {
if ('triggers' in action) { const trigger = point.action.triggers.find(t => t.triggerUuid === triggerUuid);
const trigger = action.triggers.find(t => t.triggerUuid === triggerUuid); if (trigger) {
if (trigger) { Object.assign(trigger, updates);
Object.assign(trigger, updates); return;
return;
}
} }
} }
} }
} else if ('point' in event) { } else if ('point' in event) {
for (const action of (event as any).point.actions) { const point = (event as any).point;
if ('triggers' in action) { if ('action' in point && 'triggers' in point.action) {
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid); const trigger = point.action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) { if (trigger) {
Object.assign(trigger, updates); Object.assign(trigger, updates);
return; return;
}
} else if ('actions' in point) {
for (const action of point.actions) {
if ('triggers' in action) {
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) {
Object.assign(trigger, updates);
return;
}
} }
} }
} }
@ -436,71 +334,6 @@ export const useProductStore = create<Store>()(
// Helper functions // Helper functions
getProductById: (productId) => { getProductById: (productId) => {
return get().products.find(p => p.productId === productId); return get().products.find(p => p.productId === productId);
},
getEventByModelUuid: (productId, modelUuid) => {
const product = get().products.find(p => p.productId === productId);
if (product) {
return product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
}
return undefined;
},
getPointByUuid: (productId, modelUuid, pointUuid) => {
const product = get().products.find(p => p.productId === productId);
if (product) {
const event = product.eventsData.find(e => 'modelUuid' in e && e.modelUuid === modelUuid);
if (event && 'points' in event) {
return (event as TransferEventSchema).points.find(p => p.uuid === pointUuid);
} else if (event && 'point' in event && (event as any).point.uuid === pointUuid) {
return (event as any).point;
}
}
return undefined;
},
getActionByUuid: (actionUuid) => {
const state = get();
for (const product of state.products) {
for (const event of product.eventsData) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
const action = point.actions.find(a => a.actionUuid === actionUuid);
if (action) return action;
}
} else if ('point' in event) {
const action = (event as any).point.actions.find((a: any) => a.actionUuid === actionUuid);
if (action) return action;
}
}
}
return undefined;
},
getTriggerByUuid: (triggerUuid) => {
const state = get();
for (const product of state.products) {
for (const event of product.eventsData) {
if ('points' in event) {
for (const point of (event as TransferEventSchema).points) {
for (const action of point.actions) {
if ('triggers' in action) {
const trigger = action.triggers.find(t => t.triggerUuid === triggerUuid);
if (trigger) return trigger;
}
}
}
} else if ('point' in event) {
for (const action of (event as any).point.actions) {
if ('triggers' in action) {
const trigger = action.triggers.find((t: any) => t.triggerUuid === triggerUuid);
if (trigger) return trigger;
}
}
}
}
}
return undefined;
} }
})) }))
); );

View File

@ -1,99 +1,3 @@
interface PathConnection {
fromModelUUID: string;
fromUUID: string;
toConnections: {
toModelUUID: string;
toUUID: string;
}[];
}
interface ConnectionStore {
connections: PathConnection[];
setConnections: (connections: PathConnection[]) => void;
addConnection: (newConnection: PathConnection) => void;
removeConnection: (fromUUID: string, toUUID: string) => void;
}
interface ConveyorEventsSchema {
modeluuid: string;
modelName: string;
type: "Conveyor";
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; material: string; delay: number | string; spawnInterval: number | string; isUsed: boolean; }[] | [];
triggers: { uuid: string; name: string; type: string; isUsed: boolean; bufferTime: number; }[] | [];
connections: {
source: { modelUUID: string; pointUUID: string };
targets: { modelUUID: string; pointUUID: string }[];
};
}[];
position: [number, number, number];
rotation: [number, number, number];
speed: number | string;
}
interface VehicleEventsSchema {
modeluuid: string;
modelName: string;
type: "Vehicle";
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; type: string; start: { x: number; y: number } | {}; hitCount: number; end: { x: number; y: number } | {}; buffer: number; };
connections: {
source: { modelUUID: string; pointUUID: string };
targets: { modelUUID: string; pointUUID: string }[];
};
speed: number;
isPlaying: boolean;
};
position: [number, number, number];
rotation: [number, number, number];
}
interface StaticMachineEventsSchema {
modeluuid: string;
modelName: string;
type: "StaticMachine";
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; buffer: number; material: string; };
triggers: { uuid: string; name: string; type: string };
connections: {
source: { modelUUID: string; pointUUID: string };
targets: { modelUUID: string; pointUUID: string }[];
};
};
position: [number, number, number];
rotation: [number, number, number];
}
interface ArmBotEventsSchema {
modeluuid: string;
modelName: string;
type: "ArmBot";
points: {
uuid: string;
position: [number, number, number];
rotation: [number, number, number];
actions: { uuid: string; name: string; speed: number; processes: { triggerId: string; startPoint: string; endPoint: string }[]; };
triggers: { uuid: string; name: string; type: string };
connections: {
source: { modelUUID: string; pointUUID: string };
targets: { modelUUID: string; pointUUID: string }[];
};
};
position: [number, number, number];
rotation: [number, number, number];
}
interface AssetEventSchema { interface AssetEventSchema {
modelUuid: string; modelUuid: string;
modelName: string; modelName: string;
@ -117,7 +21,7 @@ interface TransferPointSchema {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
actions: { action: {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
actionType: "default" | "spawn" | "swap" | "despawn"; actionType: "default" | "spawn" | "swap" | "despawn";
@ -125,15 +29,15 @@ interface TransferPointSchema {
delay: number | "inherit"; delay: number | "inherit";
spawnInterval: number | "inherit"; spawnInterval: number | "inherit";
spawnCount: number | "inherit"; spawnCount: number | "inherit";
triggers: TriggerSchema[] | []; triggers: TriggerSchema[];
}[]; };
} }
interface VehiclePointSchema { interface VehiclePointSchema {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
actions: { action: {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
actionType: "travel"; actionType: "travel";
@ -142,8 +46,8 @@ interface VehiclePointSchema {
loadCapacity: number; loadCapacity: number;
pickUpPoint: { x: number; y: number, z: number } | {}; pickUpPoint: { x: number; y: number, z: number } | {};
unLoadPoint: { x: number; y: number, z: number } | {}; unLoadPoint: { x: number; y: number, z: number } | {};
triggers: TriggerSchema[] | []; triggers: TriggerSchema[];
}[]; };
} }
interface RoboticArmPointSchema { interface RoboticArmPointSchema {
@ -155,7 +59,7 @@ interface RoboticArmPointSchema {
actionName: string; actionName: string;
actionType: "pickAndPlace"; actionType: "pickAndPlace";
process: { startPoint: string; endPoint: string }; process: { startPoint: string; endPoint: string };
triggers: TriggerSchema[] | []; triggers: TriggerSchema[];
}[]; }[];
} }
@ -163,27 +67,27 @@ interface MachinePointSchema {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
actions: { action: {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
actionType: "process"; actionType: "process";
processTime: number; processTime: number;
swapMaterial: string; swapMaterial: string;
triggers: TriggerSchema[] | []; triggers: TriggerSchema[];
}[]; };
} }
interface StoragePointSchema { interface StoragePointSchema {
uuid: string; uuid: string;
position: [number, number, number]; position: [number, number, number];
rotation: [number, number, number]; rotation: [number, number, number];
actions: { action: {
actionUuid: string; actionUuid: string;
actionName: string; actionName: string;
actionType: "storage"; actionType: "storage";
materials: { materialName: string; materialId: string; quantity: number }[]; materials: { materialName: string; materialId: string; quantity: number }[];
storageCapacity: number; storageCapacity: number;
}[]; };
} }
interface TransferEventSchema extends AssetEventSchema { interface TransferEventSchema extends AssetEventSchema {
@ -220,4 +124,4 @@ type productsSchema = {
productName: string; productName: string;
productId: string; productId: string;
eventsData: EventsSchema[]; eventsData: EventsSchema[];
}[] | [] }[]