import * as THREE from "three" import { useEffect } from 'react' import { getFloorAssets } from '../../../services/factoryBuilder/assest/floorAsset/getFloorItemsApi'; import { useLoadingProgress, useSelectedFloorItem, useSelectedItem, useSocketStore } from '../../../store/builder/store'; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import { FloorItems, RefGroup, RefMesh } from "../../../types/world/worldTypes"; import { useAssetsStore } from "../../../store/builder/useAssetStore"; import { useEventsStore } from "../../../store/simulation/useEventsStore"; import Models from "./models/models"; import useModuleStore from "../../../store/useModuleStore"; import { useThree } from "@react-three/fiber"; import { CameraControls } from "@react-three/drei"; import addAssetModel from "./functions/addAssetModel"; import { useParams } from "react-router-dom"; const gltfLoaderWorker = new Worker( new URL( "../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url ) ); function AssetsGroup({ floorGroup, plane }: { readonly floorGroup: RefGroup, readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); const { socket } = useSocketStore(); const { controls, gl, pointer, camera, raycaster } = useThree(); const { setLoadingProgress } = useLoadingProgress(); const { setAssets, addAsset } = useAssetsStore(); const { addEvent } = useEventsStore(); const { setSelectedFloorItem } = useSelectedFloorItem(); const { selectedItem, setSelectedItem } = useSelectedItem(); const { projectId } = useParams(); const email = localStorage.getItem("email"); const organization = email!.split("@")[1].split(".")[0]; const userId = localStorage.getItem("userId")!; const loader = new GLTFLoader(); const dracoLoader = new DRACOLoader(); dracoLoader.setDecoderPath( "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/" ); loader.setDRACOLoader(dracoLoader); useEffect(() => { let totalAssets = 0; let loadedAssets = 0; const updateLoadingProgress = (progress: number) => { if (progress < 100) { setLoadingProgress(progress); } else if (progress === 100) { setTimeout(() => { setLoadingProgress(100); setTimeout(() => { setLoadingProgress(0); }, 1500); }, 1000); } }; getFloorAssets(organization, projectId).then((data) => { if (data.length > 0) { const uniqueItems = (data as FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.modelfileID === item.modelfileID)); totalAssets = uniqueItems.length; if (totalAssets === 0) { updateLoadingProgress(100); return; } gltfLoaderWorker.postMessage({ floorItems: uniqueItems }); } else { gltfLoaderWorker.postMessage({ floorItems: [] }); updateLoadingProgress(100); } }); gltfLoaderWorker.onmessage = async (event) => { if (event.data.message === "gltfLoaded" && event.data.modelBlob) { const blobUrl = URL.createObjectURL(event.data.modelBlob); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(event.data.modelID, gltf); loadedAssets++; const progress = Math.round((loadedAssets / totalAssets) * 100); updateLoadingProgress(progress); if (loadedAssets === totalAssets) { const assets: Asset[] = []; getFloorAssets(organization, projectId).then((data: FloorItems) => { data.forEach((item) => { if (item.eventData) { assets.push({ modelUuid: item.modelUuid, modelName: item.modelName, assetId: item.modelfileID, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], isLocked: item.isLocked, isCollidable: false, isVisible: item.isVisible, opacity: 1, eventData: item.eventData }) if (item.eventData.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "vehicle", speed: 1, point: { uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "travel", unLoadDuration: 5, loadCapacity: 1, steeringAngle: 0, pickUpPoint: null, unLoadPoint: null, triggers: [] } } }; addEvent(vehicleEvent); } else if (item.eventData.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "transfer", speed: 1, points: item.eventData.points?.map((point: any, index: number) => ({ uuid: point.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); } else if (item.eventData.type === "StaticMachine") { const machineEvent: MachineEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "machine", point: { uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "process", processTime: 10, swapMaterial: "Default Material", triggers: [] } } }; addEvent(machineEvent); } else if (item.eventData.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "roboticArm", speed: 1, point: { uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], actions: [ { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "pickAndPlace", process: { startPoint: null, endPoint: null }, triggers: [] } ] } }; addEvent(roboticArmEvent); } else if (item.eventData.type === 'Storage') { const storageEvent: StorageEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "storageUnit", point: { uuid: item.eventData.point?.uuid || THREE.MathUtils.generateUUID(), position: [item.eventData.point?.position[0] || 0, item.eventData.point?.position[1] || 0, item.eventData.point?.position[2] || 0], rotation: [item.eventData.point?.rotation[0] || 0, item.eventData.point?.rotation[1] || 0, item.eventData.point?.rotation[2] || 0], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: "Action 1", actionType: "store", storageCapacity: 10, triggers: [] } } }; addEvent(storageEvent); } } else { assets.push({ modelUuid: item.modelUuid, modelName: item.modelName, assetId: item.modelfileID, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], isLocked: item.isLocked, isCollidable: false, isVisible: item.isVisible, opacity: 1, }) } }) setAssets(assets); }) updateLoadingProgress(100); } }); } }; }, []); useEffect(() => { const canvasElement = gl.domElement; const onDrop = (event: any) => { if (!event.dataTransfer?.files[0]) return; if (selectedItem.id !== "" && event.dataTransfer?.files[0] && selectedItem.category !== 'Fenestration') { pointer.x = (event.clientX / window.innerWidth) * 2 - 1; pointer.y = -(event.clientY / window.innerHeight) * 2 + 1; addAssetModel(raycaster, camera, pointer, floorGroup, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, projectId, userId); } }; const onDragOver = (event: any) => { event.preventDefault(); }; if (activeModule === "builder") { canvasElement.addEventListener("drop", onDrop); canvasElement.addEventListener("dragover", onDragOver); } else { if ((controls as CameraControls)) { const target = (controls as CameraControls).getTarget(new THREE.Vector3()); (controls as CameraControls).setTarget(target.x, 0, target.z, true); setSelectedFloorItem(null); } } return () => { canvasElement.removeEventListener("drop", onDrop); canvasElement.removeEventListener("dragover", onDragOver); }; }, [selectedItem, camera, pointer, activeModule, controls]); return ( ) } export default AssetsGroup;