From 448a5d8518b76264d0650057ecdac4331e5681a3 Mon Sep 17 00:00:00 2001 From: Juan Cazala Date: Mon, 16 Dec 2024 12:44:49 -0300 Subject: [PATCH] fix: include resources loaded by GLTF into the custom asset package --- .../lib/babylon/decentraland/get-resources.ts | 41 +++++++++++++++++++ .../sdkComponents/gltf-container.ts | 13 +++++- .../data-layer/sagas/create-custom-asset.ts | 8 +++- 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 packages/@dcl/inspector/src/lib/babylon/decentraland/get-resources.ts diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/get-resources.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/get-resources.ts new file mode 100644 index 000000000..e3e2f9fd8 --- /dev/null +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/get-resources.ts @@ -0,0 +1,41 @@ +import { NullEngine, Scene } from '@babylonjs/core' +import { getDataLayerInterface } from '../../../redux/data-layer' +import { loadAssetContainer, resourcesByPath } from './sdkComponents/gltf-container' +import future from 'fp-future' + +// This function takes a path to a gltf or glb file, loads it in Babylon, checks for all the resources loaded by the file, and returns them +export async function getResourcesFromModel(path: string) { + const base = path.split('/').slice(0, -1).join('/') + const src = path + '?base=' + encodeURIComponent(base) + const engine = new NullEngine() + const resources: Set = new Set() + const scene = new Scene(engine) + const extension = path.toLowerCase().endsWith('.gltf') ? '.gltf' : '.glb' + const dataLayer = getDataLayerInterface() + if (!dataLayer) { + return resources + } + const { content } = await dataLayer.getFile({ path }) + const file = new File([content], src) + + const load = future() + + loadAssetContainer( + file, + scene, + () => load.resolve(), + () => {}, + (_scene, _error) => load.reject(new Error(_error)), + extension, + path + ) + + await load + + return resourcesByPath.get(path) +} + +export async function getResourcesFromModels(paths: string[]): Promise { + const results = await Promise.all(paths.map(getResourcesFromModel)) + return results.flatMap((resourceSet) => (resourceSet ? Array.from(resourceSet) : [])) +} diff --git a/packages/@dcl/inspector/src/lib/babylon/decentraland/sdkComponents/gltf-container.ts b/packages/@dcl/inspector/src/lib/babylon/decentraland/sdkComponents/gltf-container.ts index 924b7aa2f..5eb5499d2 100644 --- a/packages/@dcl/inspector/src/lib/babylon/decentraland/sdkComponents/gltf-container.ts +++ b/packages/@dcl/inspector/src/lib/babylon/decentraland/sdkComponents/gltf-container.ts @@ -12,6 +12,8 @@ import { CAMERA, PLAYER } from '../../../sdk/tree' let sceneContext: WeakRef +export const resourcesByPath = new Map>() + BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (plugin) { if (plugin instanceof GLTFFileLoader) { plugin.animationStartMode = GLTFLoaderAnimationStartMode.NONE @@ -30,7 +32,8 @@ BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (plugin) { // caches all the files by their name (CIDv1) const loader: GLTFLoader = (plugin as any)._loader const file: string = (loader as any)._fileName - const [_gltfFilename, strParams] = file.split('?') + const [gltfFilename, strParams] = file.split('?') + if (strParams) { const params = new URLSearchParams(strParams) const base = params.get('base') || '' @@ -40,8 +43,14 @@ BABYLON.SceneLoader.OnPluginActivatedObservable.add(function (plugin) { console.log(`Fetching ${filePath}`) const content = await ctx.getFile(filePath) if (content) { + // This is a hack to get the resources loaded by the gltf file + if (!resourcesByPath.has(gltfFilename)) { + resourcesByPath.set(gltfFilename, new Set()) + } + const resources = resourcesByPath.get(gltfFilename)! + resources.add(filePath) // TODO: this works with File, but it doesn't match the types (it requires string) - return new File([content], _gltfFilename) as any + return new File([content], gltfFilename) as any } } } diff --git a/packages/@dcl/inspector/src/redux/data-layer/sagas/create-custom-asset.ts b/packages/@dcl/inspector/src/redux/data-layer/sagas/create-custom-asset.ts index 596312461..db8434007 100644 --- a/packages/@dcl/inspector/src/redux/data-layer/sagas/create-custom-asset.ts +++ b/packages/@dcl/inspector/src/redux/data-layer/sagas/create-custom-asset.ts @@ -5,6 +5,7 @@ import { ErrorType } from '../index' import { AssetData } from '../../../lib/logic/catalog' import { selectAssetsTab } from '../../ui' import { AssetsTab } from '../../ui/types' +import { getResourcesFromModels } from '../../../lib/babylon/decentraland/get-resources' export function* createCustomAssetSaga( action: PayloadAction<{ name: string; composite: AssetData['composite']; resources: string[] }> @@ -12,10 +13,15 @@ export function* createCustomAssetSaga( const dataLayer: IDataLayer = yield call(getDataLayerInterface) if (!dataLayer) return try { + const models = action.payload.resources.filter( + (resource) => resource.endsWith('.gltf') || resource.endsWith('.glb') + ) + const resourcesFromModels: string[] = yield call(getResourcesFromModels, models) + const resources = [...action.payload.resources, ...resourcesFromModels] yield call(dataLayer.createCustomAsset, { name: action.payload.name, composite: Buffer.from(JSON.stringify(action.payload.composite)), - resources: action.payload.resources + resources }) // Fetch asset catalog again yield put(getAssetCatalog())