import * as THREE from "three" import { useEffect } from 'react' import { getFloorAssets } from '../../../services/factoryBuilder/asset/floorAsset/getFloorItemsApi'; import { useLoadingProgress, useRenameModeStore, 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, RefMesh } from "../../../types/world/worldTypes"; 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"; import { useLeftData, useTopData } from "../../../store/visualization/useZone3DWidgetStore"; import { getUserData } from "../../../functions/getUserData"; import { useSceneContext } from "../../scene/sceneContext"; import { useVersionContext } from "../version/versionContext"; const gltfLoaderWorker = new Worker(new URL("../../../services/factoryBuilder/webWorkers/gltfLoaderWorker.js", import.meta.url)); function AssetsGroup({ plane }: { readonly plane: RefMesh }) { const { activeModule } = useModuleStore(); const { socket } = useSocketStore(); const { controls, gl, pointer, camera, raycaster, scene } = useThree(); const { setLoadingProgress } = useLoadingProgress(); const { assetStore, eventStore } = useSceneContext(); const { selectedVersionStore } = useVersionContext(); const { selectedVersion } = selectedVersionStore(); const { setAssets, addAsset, clearAssets } = assetStore(); const { addEvent, clearEvents } = eventStore(); const { setSelectedFloorItem } = useSelectedFloorItem(); const { selectedItem, setSelectedItem } = useSelectedItem(); const { projectId } = useParams(); const { isRenameMode, setIsRenameMode } = useRenameModeStore(); const { userId, organization } = getUserData(); const { setTop } = useTopData(); const { setLeft } = useLeftData(); 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(() => { if (!projectId || !selectedVersion) return; clearEvents(); 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, selectedVersion?.versionId || '').then((data) => { if (data && data.length > 0) { const uniqueItems = (data as FloorItems).filter((item, index, self) => index === self.findIndex((t) => t.assetId === item.assetId)); totalAssets = uniqueItems.length; if (totalAssets === 0) { updateLoadingProgress(100); return; } gltfLoaderWorker.postMessage({ floorItems: uniqueItems }); } else { gltfLoaderWorker.postMessage({ floorItems: [] }); updateLoadingProgress(100); clearAssets(); } }).catch((err) => { console.error(err); }) 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, selectedVersion.versionId || '').then((data: FloorItems) => { data.forEach((item) => { if (item.eventData) { assets.push({ modelUuid: item.modelUuid, modelName: item.modelName, assetId: item.assetId, 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, paths: { initPickup: [], pickupDrop: [], dropPickup: [], }, 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 if (item.eventData.type === 'Human') { const humanEvent: HumanEventSchema = { modelUuid: item.modelUuid, modelName: item.modelName, position: item.position, rotation: [item.rotation.x, item.rotation.y, item.rotation.z], state: "idle", type: "human", 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: "worker", loadCount: 1, assemblyCount: 1, loadCapacity: 1, processTime: 10, triggers: [] } ] } } addEvent(humanEvent); } } else { assets.push({ modelUuid: item.modelUuid, modelName: item.modelName, assetId: item.assetId, 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); } }); } }; }, [selectedVersion?.versionId]); useEffect(() => { const canvasElement = gl.domElement; const onDrop = (event: DragEvent) => { 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(scene, raycaster, camera, pointer, socket, selectedItem, setSelectedItem, addEvent, addAsset, plane, loader, selectedVersion, projectId, userId); } }; const onDragOver = (event: any) => { event.preventDefault(); }; const onMouseMove = (evt: any) => { if (!canvasElement) return; const canvasRect = canvasElement.getBoundingClientRect(); const relativeX = evt.clientX - canvasRect.left; const relativeY = evt.clientY - canvasRect.top; if (!isRenameMode) { setTop(relativeY); setLeft(relativeX); } }; const onMouseUp = (evt: any) => { setIsRenameMode(false); } if (activeModule === "builder") { canvasElement.addEventListener("drop", onDrop); canvasElement.addEventListener("dragover", onDragOver); canvasElement.addEventListener("mousemove", onMouseMove); canvasElement.addEventListener("mouseup", onMouseUp); } 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); canvasElement.removeEventListener("mousemove", onMouseMove); canvasElement.removeEventListener("mouseup", onMouseUp); }; }, [selectedItem, camera, activeModule, controls, isRenameMode]); return ( ) } export default AssetsGroup;