import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader"; import * as THREE from "three"; import * as Types from "../../../types/world/worldTypes"; import { getWallItems } from "../../../services/factoryBuilder/assest/wallAsset/getWallItemsApi"; import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils"; import { getUserData } from "../../../functions/getUserData"; async function loadInitialWallItems( setWallItems: Types.setWallItemSetState, projectId?: string, versionId?: string ): Promise { if (!projectId || !versionId) return; try { const { organization, email } = getUserData(); if (!email) { throw new Error("No email found in localStorage"); } const items = await getWallItems(organization, projectId, versionId); let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`; if (!items || items.length === 0) { localStorage.removeItem("WallItems"); return; } localStorage.setItem("WallItems", JSON.stringify(items)); 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); const loadedWallItems = await Promise.all( items.map(async (item: Types.WallItem) => { // Check THREE.js cache first const cachedModel = THREE.Cache.get(item.assetId!); if (cachedModel) { return processModel(cachedModel, item); } // Check IndexedDB cache const cachedModelBlob = await retrieveGLTF(item.assetId!); if (cachedModelBlob) { const blobUrl = URL.createObjectURL(cachedModelBlob); return new Promise((resolve) => { loader.load(blobUrl, (gltf) => { URL.revokeObjectURL(blobUrl); THREE.Cache.add(item.assetId!, gltf); resolve(processModel(gltf, item)); }); }); } // Load from original URL if not cached const modelUrl = `${url_Backend_dwinzo}/api/v2/AssetFile/${item.assetId!}`; return new Promise((resolve) => { loader.load(modelUrl, async (gltf) => { try { // Cache the model const modelBlob = await fetch(modelUrl).then((res) => res.blob()); await storeGLTF(item.assetId!, modelBlob); THREE.Cache.add(item.assetId!, gltf); resolve(processModel(gltf, item)); } catch (error) { console.error("Failed to cache model:", error); resolve(processModel(gltf, item)); } }); }); }) ); setWallItems(loadedWallItems); } catch (error) { console.error("Failed to load wall items:", error); } } function processModel(gltf: GLTF, item: Types.WallItem): Types.WallItem { const model = gltf.scene.clone(); model.uuid = item.modelUuid!; model.children[0]?.children?.forEach((child: THREE.Object3D) => { if (child.name !== "CSG_REF") { child.castShadow = true; child.receiveShadow = true; } }); return { type: item.type, model: model, modelName: item.modelName, assetId: item.assetId, scale: item.scale, csgscale: item.csgscale, csgposition: item.csgposition, position: item.position, quaternion: item.quaternion, }; } export default loadInitialWallItems;