import * as THREE from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import * as Types from "../../../../types/world/worldTypes"; import { retrieveGLTF, storeGLTF } from "../../../../utils/indexDB/idbUtils"; // import { setFloorItemApi } from '../../../../services/factoryBuilder/assest/floorAsset/setFloorItemApi'; import { Socket } from "socket.io-client"; import * as CONSTANTS from "../../../../types/world/worldConstants"; import PointsCalculator from "../../../simulation/events/points/functions/pointsCalculator"; async function addAssetModel( raycaster: THREE.Raycaster, camera: THREE.Camera, pointer: THREE.Vector2, floorGroup: Types.RefGroup, socket: Socket, selectedItem: any, setSelectedItem: any, addEvent: (event: EventsSchema) => void, addAsset: (asset: Asset) => void, plane: Types.RefMesh, projectId?: string, userId?: string ): Promise { ////////// Load Floor GLtf's and set the positions, rotation, type etc. in state and store in localstorage ////////// let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; try { 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); raycaster.setFromCamera(pointer, camera); const floorIntersections = raycaster.intersectObjects( floorGroup.current.children, true ); const intersectedFloor = floorIntersections.find((intersect) => intersect.object.name.includes("Floor") ); const planeIntersections = raycaster.intersectObject(plane.current!, true); const intersectedPlane = planeIntersections[0]; let intersectPoint: THREE.Vector3 | null = null; if (intersectedFloor && intersectedPlane) { intersectPoint = intersectedFloor.distance < intersectedPlane.distance ? new THREE.Vector3( intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z ) : new THREE.Vector3( intersectedPlane.point.x, 0, intersectedPlane.point.z ); } else if (intersectedFloor) { intersectPoint = new THREE.Vector3( intersectedFloor.point.x, Math.round(intersectedFloor.point.y), intersectedFloor.point.z ); } else if (intersectedPlane) { intersectPoint = new THREE.Vector3( intersectedPlane.point.x, 0, intersectedPlane.point.z ); } if (intersectPoint) { if (intersectPoint.y < 0) { intersectPoint = new THREE.Vector3( intersectPoint.x, 0, intersectPoint.z ); } const cachedModel = THREE.Cache.get(selectedItem.id); if (cachedModel) { handleModelLoad( cachedModel, intersectPoint!, selectedItem, addEvent, addAsset, socket, projectId, userId ); return; } else { const cachedModelBlob = await retrieveGLTF(selectedItem.id); if (cachedModelBlob) { const blobUrl = URL.createObjectURL(cachedModelBlob); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(selectedItem.id, gltf); handleModelLoad( gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, projectId, userId ); }); } else { loader.load( `${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}`, async (gltf) => { const modelBlob = await fetch( `${url_Backend_dwinzo}/api/v2/AssetFile/${selectedItem.id}` ).then((res) => res.blob()); await storeGLTF(selectedItem.id, modelBlob); THREE.Cache.add(selectedItem.id, gltf); await handleModelLoad( gltf, intersectPoint!, selectedItem, addEvent, addAsset, socket, projectId, userId ); } ); } } } } catch (error) { echo.error("Failed to add asset"); } finally { setSelectedItem({}); } } async function handleModelLoad( gltf: any, intersectPoint: THREE.Vector3, selectedItem: any, addEvent: (event: EventsSchema) => void, addAsset: (asset: Asset) => void, socket: Socket, projectId?: string, userId?: string ) { const model = gltf.scene.clone(); model.userData = { name: selectedItem.name, modelId: selectedItem.id, modelUuid: model.uuid, }; model.position.set(intersectPoint!.x, intersectPoint!.y, intersectPoint!.z); model.scale.set(...CONSTANTS.assetConfig.defaultScaleAfterGsap); model.traverse((child: any) => { if (child) { child.castShadow = true; child.receiveShadow = true; } }); const newFloorItem: Asset = { modelUuid: model.uuid, modelName: selectedItem.name, assetId: selectedItem.id, position: [intersectPoint!.x, intersectPoint!.y, intersectPoint!.z], rotation: [0, 0, 0], isLocked: false, isVisible: true, isCollidable: false, opacity: 1, }; const email = localStorage.getItem("email"); const organization = email ? email.split("@")[1].split(".")[0] : ""; // API // await setFloorItemApi( // organization, // newFloorItem.modelUuid, // newFloorItem.modelName, // newFloorItem.modelfileID, // newFloorItem.position, // { x: 0, y: 0, z: 0 }, // false, // true, // ); // SOCKET if (selectedItem.type) { const data = PointsCalculator( selectedItem.type, gltf.scene.clone(), new THREE.Vector3(...model.rotation) ); if (!data || !data.points) return; const eventData: any = { type: selectedItem.type, }; if (selectedItem.type === "Conveyor") { const ConveyorEvent: ConveyorEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: newFloorItem.rotation, state: "idle", type: "transfer", speed: 1, points: data.points.map((point: THREE.Vector3, index: number) => { const triggers: TriggerSchema[] = []; if (data.points && index < data.points.length - 1) { triggers.push({ triggerUuid: THREE.MathUtils.generateUUID(), triggerName: `Trigger 1`, triggerType: "onComplete", delay: 0, triggeredAsset: { triggeredModel: { modelName: newFloorItem.modelName, modelUuid: newFloorItem.modelUuid, }, triggeredPoint: { pointName: `Point`, pointUuid: "", }, triggeredAction: { actionName: `Action 1`, actionUuid: "", }, }, }); } return { uuid: THREE.MathUtils.generateUUID(), position: [point.x, point.y, point.z], rotation: [0, 0, 0], action: { actionUuid: THREE.MathUtils.generateUUID(), actionName: `Action 1`, actionType: "default", material: "Default Material", delay: 0, spawnInterval: 5, spawnCount: 1, triggers: triggers, }, }; }), }; for (let i = 0; i < ConveyorEvent.points.length - 1; i++) { const currentPoint = ConveyorEvent.points[i]; const nextPoint = ConveyorEvent.points[i + 1]; if (currentPoint.action.triggers.length > 0) { currentPoint.action.triggers[0].triggeredAsset!.triggeredPoint!.pointUuid = nextPoint.uuid; currentPoint.action.triggers[0].triggeredAsset!.triggeredAction!.actionUuid = nextPoint.action.actionUuid; } } addEvent(ConveyorEvent); eventData.points = ConveyorEvent.points.map((point) => ({ uuid: point.uuid, position: point.position, rotation: point.rotation, })); } else if (selectedItem.type === "Vehicle") { const vehicleEvent: VehicleEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: newFloorItem.rotation, state: "idle", type: "vehicle", speed: 1, point: { uuid: THREE.MathUtils.generateUUID(), position: [data.points[0].x, data.points[0].y, data.points[0].z], rotation: [0, 0, 0], 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 (selectedItem.type === "ArmBot") { const roboticArmEvent: RoboticArmEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: newFloorItem.rotation, state: "idle", type: "roboticArm", speed: 1, point: { uuid: THREE.MathUtils.generateUUID(), position: [data.points[0].x, data.points[0].y, data.points[0].z], rotation: [0, 0, 0], 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 (selectedItem.type === "StaticMachine") { const machineEvent: MachineEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: newFloorItem.rotation, state: "idle", type: "machine", point: { uuid: THREE.MathUtils.generateUUID(), position: [data.points[0].x, data.points[0].y, data.points[0].z], rotation: [0, 0, 0], 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 (selectedItem.type === "Storage") { const storageEvent: StorageEventSchema = { modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, position: newFloorItem.position, rotation: newFloorItem.rotation, state: "idle", type: "storageUnit", point: { uuid: THREE.MathUtils.generateUUID(), position: [data.points[0].x, data.points[0].y, data.points[0].z], rotation: [0, 0, 0], 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, }; } const completeData = { organization, modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, modelfileID: newFloorItem.assetId, position: newFloorItem.position, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, }, isLocked: false, isVisible: true, socketId: socket.id, eventData: eventData, projectId: projectId, userId: userId, }; console.log("completeData: ", completeData); socket.emit("v1:model-asset:add", completeData); const asset: Asset = { modelUuid: completeData.modelUuid, modelName: completeData.modelName, assetId: completeData.modelfileID, position: completeData.position, rotation: [ completeData.rotation.x, completeData.rotation.y, completeData.rotation.z, ] as [number, number, number], isLocked: completeData.isLocked, isCollidable: false, isVisible: completeData.isVisible, opacity: 1, eventData: completeData.eventData, }; addAsset(asset); } else { const data = { organization, modelUuid: newFloorItem.modelUuid, modelName: newFloorItem.modelName, modelfileID: newFloorItem.assetId, position: newFloorItem.position, rotation: { x: model.rotation.x, y: model.rotation.y, z: model.rotation.z, }, isLocked: false, isVisible: true, socketId: socket.id, projectId: projectId, userId: userId, }; socket.emit("v1:model-asset:add", data); const asset = { modelUuid: data.modelUuid, modelName: data.modelName, assetId: data.modelfileID, position: data.position, rotation: [data.rotation.x, data.rotation.y, data.rotation.z] as [ number, number, number ], isLocked: data.isLocked, isCollidable: false, isVisible: data.isVisible, opacity: 1, }; addAsset(asset); } } export default addAssetModel;