import { GLTF, GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { toast } from 'react-toastify'; import * as THREE from 'three'; import * as Types from "../../../../types/world/worldTypes"; import * as CONSTANTS from '../../../../types/world/worldConstants'; import { Socket } from 'socket.io-client'; import { retrieveGLTF, storeGLTF } from '../../../../utils/indexDB/idbUtils'; import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'; async function AddWallItems( selected: any, raycaster: THREE.Raycaster, CSGGroup: Types.RefMesh, setWallItems: Types.setWallItemSetState, socket: Socket, projectId?: string ): Promise { let intersects = raycaster?.intersectObject(CSGGroup.current!, true); const wallRaycastIntersection = intersects?.find((child) => child.object.name.includes("WallRaycastReference")); let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; if (!wallRaycastIntersection) return; const intersectionPoint = wallRaycastIntersection; 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); // Check THREE.js cache first const cachedModel = THREE.Cache.get(selected.id); if (cachedModel) { handleModelLoad(cachedModel); return; } // Check IndexedDB cache const cachedModelBlob = await retrieveGLTF(selected.id); if (cachedModelBlob) { const blobUrl = URL.createObjectURL(cachedModelBlob); loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); THREE.Cache.remove(blobUrl); THREE.Cache.add(selected.id, gltf); handleModelLoad(gltf); }); return; } // Load from backend if not in any cache loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`, async (gltf) => { try { const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${selected.id}`).then((res) => res.blob()); await storeGLTF(selected.id, modelBlob); THREE.Cache.add(selected.id, gltf); await handleModelLoad(gltf); } catch (error) { console.error('Failed to cache model:', error); handleModelLoad(gltf); } }); async function handleModelLoad(gltf: GLTF) { const model = gltf.scene.clone(); model.userData = { wall: intersectionPoint.object.parent }; model.children[0].children.forEach((child) => { if (child.name !== "CSG_REF") { child.castShadow = true; child.receiveShadow = true; } }); const boundingBox = new THREE.Box3().setFromObject(model); const size = new THREE.Vector3(); boundingBox.getSize(size); const csgscale = [size.x, size.y, size.z] as [number, number, number]; const center = new THREE.Vector3(); boundingBox.getCenter(center); const csgposition = [center.x, center.y, center.z] as [number, number, number]; let positionY = selected.subCategory === 'fixed-move' ? 0 : intersectionPoint.point.y; if (positionY === 0) { positionY = Math.floor(intersectionPoint.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height; } const newWallItem = { type: selected.subCategory, model: model, modelName: selected.name, modelfileID: selected.id, scale: [1, 1, 1] as [number, number, number], csgscale: csgscale, csgposition: csgposition, position: [intersectionPoint.point.x, positionY, intersectionPoint.point.z] as [number, number, number], quaternion: intersectionPoint.object.quaternion.clone() as Types.QuaternionType }; const email = localStorage.getItem('email'); const organization = email ? (email.split("@")[1]).split(".")[0] : 'default'; const userId = localStorage.getItem("userId"); const data = { organization: organization, modelUuid: model.uuid, modelName: newWallItem.modelName, modelfileID: selected.id, type: selected.subCategory, csgposition: newWallItem.csgposition, csgscale: newWallItem.csgscale, position: newWallItem.position, quaternion: newWallItem.quaternion, scale: newWallItem.scale, socketId: socket.id, projectId, userId }; // console.log('data: ', data); socket.emit('v1:wallItems:set', data); setWallItems((prevItems) => { const updatedItems = [...prevItems, newWallItem]; const WallItemsForStorage = updatedItems.map(item => { const { model, ...rest } = item; return { ...rest, modelUuid: model?.uuid, }; }); localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage)); echo.success("Model Added!"); return updatedItems; }); } } export default AddWallItems;