import * as THREE from "three"; import { useEffect, useMemo } from "react"; import { useFrame, useThree } from "@react-three/fiber"; import { useFloorItems, useSelectedAssets, useSocketStore, useToggleView } from "../../../../store/store"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import * as Types from "../../../../types/world/worldTypes"; import { setFloorItemApi } from "../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi"; import { detectModifierKeys } from "../../../../utils/shortcutkeys/detectModifierKeys"; import { useEventsStore } from "../../../../store/simulation/useEventsStore"; const DuplicationControls = ({ itemsGroupRef, duplicatedObjects, setDuplicatedObjects, setpastedObjects, selectionGroup, movedObjects, setMovedObjects, rotatedObjects, setRotatedObjects, boundingBoxRef }: any) => { const { camera, controls, gl, scene, pointer, raycaster } = useThree(); const { toggleView } = useToggleView(); const { selectedAssets, setSelectedAssets } = useSelectedAssets(); const plane = useMemo(() => new THREE.Plane(new THREE.Vector3(0, 1, 0), 0), []); const { floorItems, setFloorItems } = useFloorItems(); const { socket } = useSocketStore(); const { addEvent } = useEventsStore(); useEffect(() => { if (!camera || !scene || toggleView) return; const canvasElement = gl.domElement; canvasElement.tabIndex = 0; let isMoving = false; const onPointerDown = () => { isMoving = false; }; const onPointerMove = () => { isMoving = true; }; const onPointerUp = (event: PointerEvent) => { if (!isMoving && duplicatedObjects.length > 0 && event.button === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) { event.preventDefault(); addDuplicatedAssets(); } }; const onKeyDown = (event: KeyboardEvent) => { const keyCombination = detectModifierKeys(event); if (keyCombination === "Ctrl+D" && selectedAssets.length > 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) { duplicateSelection(); } }; if (!toggleView) { canvasElement.addEventListener("pointerdown", onPointerDown); canvasElement.addEventListener("pointermove", onPointerMove); canvasElement.addEventListener("pointerup", onPointerUp); canvasElement.addEventListener("keydown", onKeyDown); } return () => { canvasElement.removeEventListener("pointerdown", onPointerDown); canvasElement.removeEventListener("pointermove", onPointerMove); canvasElement.removeEventListener("pointerup", onPointerUp); canvasElement.removeEventListener("keydown", onKeyDown); }; }, [camera, controls, scene, toggleView, selectedAssets, duplicatedObjects, movedObjects, socket, floorItems, rotatedObjects]); useFrame(() => { if (duplicatedObjects.length > 0) { const intersectionPoint = new THREE.Vector3(); raycaster.setFromCamera(pointer, camera); const point = raycaster.ray.intersectPlane(plane, intersectionPoint); if (point) { const position = new THREE.Vector3(); if (boundingBoxRef.current) { boundingBoxRef.current?.getWorldPosition(position) selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z)); } else { const box = new THREE.Box3(); duplicatedObjects.forEach((obj: THREE.Object3D) => box.expandByObject(obj.clone())); const center = new THREE.Vector3(); box.getCenter(center); selectionGroup.current.position.set(point.x - (center.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (center.z - selectionGroup.current.position.z)); } } } }); const duplicateSelection = () => { if (selectedAssets.length > 0 && duplicatedObjects.length === 0) { const newClones = selectedAssets.map((asset: any) => { const clone = asset.clone(); clone.position.copy(asset.position); return clone; }); selectionGroup.current.add(...newClones); setDuplicatedObjects(newClones); const intersectionPoint = new THREE.Vector3(); raycaster.setFromCamera(pointer, camera); const point = raycaster.ray.intersectPlane(plane, intersectionPoint); if (point) { const position = new THREE.Vector3(); boundingBoxRef.current?.getWorldPosition(position) selectionGroup.current.position.set(point.x - (position.x - selectionGroup.current.position.x), selectionGroup.current.position.y, point.z - (position.z - selectionGroup.current.position.z)); } } }; const addDuplicatedAssets = () => { if (duplicatedObjects.length === 0) return; duplicatedObjects.forEach(async (obj: THREE.Object3D) => { const worldPosition = new THREE.Vector3(); obj.getWorldPosition(worldPosition); obj.position.copy(worldPosition); if (itemsGroupRef.current) { const newFloorItem: Types.FloorItemType = { modelUuid: obj.uuid, modelName: obj.userData.name, modelfileID: obj.userData.modelId, position: [worldPosition.x, worldPosition.y, worldPosition.z], rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z, }, isLocked: false, isVisible: true, }; let updatedEventData = null; if (obj.userData.eventData) { updatedEventData = JSON.parse(JSON.stringify(obj.userData.eventData)); updatedEventData.modelUuid = newFloorItem.modelUuid; const eventData: any = { type: obj.userData.eventData.type, }; if (obj.userData.eventData.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: 'transfer', speed: 1, points: updatedEventData.points.map((point: any, index: number) => ({ uuid: THREE.MathUtils.generateUUID(), position: [point.position[0], point.position[1], point.position[2]], rotation: [point.rotation[0], point.rotation[1], point.rotation[2]], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: `Action 1`, actionType: 'default', material: 'Default Material', delay: 0, spawnInterval: 5, spawnCount: 1, triggers: [] } })) }; addEvent(ConveyorEvent); eventData.points = ConveyorEvent.points.map(point => ({ uuid: point.uuid, position: point.position, rotation: point.rotation })); } else if (obj.userData.eventData.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: "vehicle", speed: 1, point: { uuid: THREE.MathUtils.generateUUID(), position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "travel", unLoadDuration: 5, loadCapacity: 1, steeringAngle: 0, pickUpPoint: null, unLoadPoint: null, triggers: [] } } }; addEvent(vehicleEvent); eventData.point = { uuid: vehicleEvent.point.uuid, position: vehicleEvent.point.position, rotation: vehicleEvent.point.rotation }; } else if (obj.userData.eventData.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: "roboticArm", speed: 1, point: { uuid: THREE.MathUtils.generateUUID(), position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], actions: [ { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "pickAndPlace", process: { startPoint: null, endPoint: null }, triggers: [] } ] } }; addEvent(roboticArmEvent); eventData.point = { uuid: roboticArmEvent.point.uuid, position: roboticArmEvent.point.position, rotation: roboticArmEvent.point.rotation }; } else if (obj.userData.eventData.type === "StaticMachine") { const machineEvent: MachineEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: "machine", point: { uuid: THREE.MathUtils.generateUUID(), position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "process", processTime: 10, swapMaterial: "Default Material", triggers: [] } } }; addEvent(machineEvent); eventData.point = { uuid: machineEvent.point.uuid, position: machineEvent.point.position, rotation: machineEvent.point.rotation }; } else if (obj.userData.eventData.type === "Storage") { const storageEvent: StorageEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: [newFloorItem.rotation.x, newFloorItem.rotation.y, newFloorItem.rotation.z], state: "idle", type: "storageUnit", point: { uuid: THREE.MathUtils.generateUUID(), position: [updatedEventData.point.position[0], updatedEventData.point.position[1], updatedEventData.point.position[2]], rotation: [updatedEventData.point.rotation[0], updatedEventData.point.rotation[1], updatedEventData.point.rotation[2]], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "store", storageCapacity: 10, triggers: [] } } } addEvent(storageEvent); eventData.point = { uuid: storageEvent.point.uuid, position: storageEvent.point.position, rotation: storageEvent.point.rotation }; } newFloorItem.eventData = eventData; setFloorItems((prevItems: Types.FloorItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); return updatedItems; }); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; //REST // await setFloorItemApi( // organization, // obj.uuid, // obj.userData.name, // [worldPosition.x, worldPosition.y, worldPosition.z], // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // obj.userData.modelId, // false, // true, // ); //SOCKET const data = { organization, modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, socketId: socket.id, eventData: eventData, }; socket.emit("v2:model-asset:add", data); obj.userData = { name: newFloorItem.modelName, modelId: newFloorItem.modelfileID, modelUuid: newFloorItem.modelUuid, eventData: JSON.parse(JSON.stringify(eventData)) }; itemsGroupRef.current.add(obj); } else { setFloorItems((prevItems: Types.FloorItems) => { const updatedItems = [...(prevItems || []), newFloorItem]; localStorage.setItem("FloorItems", JSON.stringify(updatedItems)); return updatedItems; }); const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : "default"; //REST // await setFloorItemApi( // organization, // obj.uuid, // obj.userData.name, // [worldPosition.x, worldPosition.y, worldPosition.z], // { "x": obj.rotation.x, "y": obj.rotation.y, "z": obj.rotation.z }, // obj.userData.modelId, // false, // true, // ); //SOCKET const data = { organization, modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, modelfileID: newFloorItem.modelfileID, position: newFloorItem.position, rotation: { x: obj.rotation.x, y: obj.rotation.y, z: obj.rotation.z }, isLocked: false, isVisible: true, socketId: socket.id, }; socket.emit("v2:model-asset:add", data); obj.userData = { name: newFloorItem.modelName, modelId: newFloorItem.modelfileID, modelUuid: newFloorItem.modelUuid, }; itemsGroupRef.current.add(obj); } } }); echo.success("Object duplicated!"); clearSelection(); } const clearSelection = () => { selectionGroup.current.children = []; selectionGroup.current.position.set(0, 0, 0); selectionGroup.current.rotation.set(0, 0, 0); setMovedObjects([]); setpastedObjects([]); setDuplicatedObjects([]); setRotatedObjects([]); setSelectedAssets([]); } return null; }; export default DuplicationControls;