'use strict'; var warn = require('../../utils/logging/warn.js'); var path = require('../../utils/path.js'); var convertToList = require('../utils/convertToList.js'); var isSingleItem = require('../utils/isSingleItem.js'); "use strict"; class Loader { constructor() { this._parsers = []; this._parsersValidated = false; /** * All loader parsers registered * @type {assets.LoaderParser[]} */ this.parsers = new Proxy(this._parsers, { set: (target, key, value) => { this._parsersValidated = false; target[key] = value; return true; } }); /** Cache loading promises that ae currently active */ this.promiseCache = {}; } /** function used for testing */ reset() { this._parsersValidated = false; this.promiseCache = {}; } /** * Used internally to generate a promise for the asset to be loaded. * @param url - The URL to be loaded * @param data - any custom additional information relevant to the asset being loaded * @returns - a promise that will resolve to an Asset for example a Texture of a JSON object */ _getLoadPromiseAndParser(url, data) { const result = { promise: null, parser: null }; result.promise = (async () => { let asset = null; let parser = null; if (data.loadParser) { parser = this._parserHash[data.loadParser]; if (!parser) { warn.warn(`[Assets] specified load parser "${data.loadParser}" not found while loading ${url}`); } } if (!parser) { for (let i = 0; i < this.parsers.length; i++) { const parserX = this.parsers[i]; if (parserX.load && parserX.test?.(url, data, this)) { parser = parserX; break; } } if (!parser) { warn.warn(`[Assets] ${url} could not be loaded as we don't know how to parse it, ensure the correct parser has been added`); return null; } } asset = await parser.load(url, data, this); result.parser = parser; for (let i = 0; i < this.parsers.length; i++) { const parser2 = this.parsers[i]; if (parser2.parse) { if (parser2.parse && await parser2.testParse?.(asset, data, this)) { asset = await parser2.parse(asset, data, this) || asset; result.parser = parser2; } } } return asset; })(); return result; } async load(assetsToLoadIn, onProgress) { if (!this._parsersValidated) { this._validateParsers(); } let count = 0; const assets = {}; const singleAsset = isSingleItem.isSingleItem(assetsToLoadIn); const assetsToLoad = convertToList.convertToList(assetsToLoadIn, (item) => ({ alias: [item], src: item, data: {} })); const total = assetsToLoad.length; const promises = assetsToLoad.map(async (asset) => { const url = path.path.toAbsolute(asset.src); if (!assets[asset.src]) { try { if (!this.promiseCache[url]) { this.promiseCache[url] = this._getLoadPromiseAndParser(url, asset); } assets[asset.src] = await this.promiseCache[url].promise; if (onProgress) onProgress(++count / total); } catch (e) { delete this.promiseCache[url]; delete assets[asset.src]; throw new Error(`[Loader.load] Failed to load ${url}. ${e}`); } } }); await Promise.all(promises); return singleAsset ? assets[assetsToLoad[0].src] : assets; } /** * Unloads one or more assets. Any unloaded assets will be destroyed, freeing up memory for your app. * The parser that created the asset, will be the one that unloads it. * @example * // Single asset: * const asset = await Loader.load('cool.png'); * * await Loader.unload('cool.png'); * * console.log(asset.destroyed); // true * @param assetsToUnloadIn - urls that you want to unload, or a single one! */ async unload(assetsToUnloadIn) { const assetsToUnload = convertToList.convertToList(assetsToUnloadIn, (item) => ({ alias: [item], src: item })); const promises = assetsToUnload.map(async (asset) => { const url = path.path.toAbsolute(asset.src); const loadPromise = this.promiseCache[url]; if (loadPromise) { const loadedAsset = await loadPromise.promise; delete this.promiseCache[url]; await loadPromise.parser?.unload?.(loadedAsset, asset, this); } }); await Promise.all(promises); } /** validates our parsers, right now it only checks for name conflicts but we can add more here as required! */ _validateParsers() { this._parsersValidated = true; this._parserHash = this._parsers.filter((parser) => parser.name).reduce((hash, parser) => { if (!parser.name) { warn.warn(`[Assets] loadParser should have a name`); } else if (hash[parser.name]) { warn.warn(`[Assets] loadParser name conflict "${parser.name}"`); } return { ...hash, [parser.name]: parser }; }, {}); } } exports.Loader = Loader; //# sourceMappingURL=Loader.js.map