import { BaseTexture, Resource, Texture } from '@pixi/core'; import { Spritesheet } from '@pixi/spritesheet'; import { ArrayBufferToBase64, NitroBundle } from '../utils'; import { GraphicAssetCollection } from './GraphicAssetCollection'; import { IAssetData } from './IAssetData'; import { IAssetManager } from './IAssetManager'; import { IGraphicAsset } from './IGraphicAsset'; import { IGraphicAssetCollection } from './IGraphicAssetCollection'; export class AssetManager implements IAssetManager { public static _INSTANCE: IAssetManager = new AssetManager(); private _textures: Map> = new Map(); private _collections: Map = new Map(); public getTexture(name: string): Texture { if(!name) return null; const existing = this._textures.get(name); if(!existing) return null; return existing; } public setTexture(name: string, texture: Texture): void { if(!name || !texture) return; this._textures.set(name, texture); } public getAsset(name: string): IGraphicAsset { if(!name) return null; for(const collection of this._collections.values()) { if(!collection) continue; const existing = collection.getAsset(name); if(!existing) continue; return existing; } return null; } public getCollection(name: string): IGraphicAssetCollection { if(!name) return null; const existing = this._collections.get(name); if(!existing) return null; return existing; } public createCollection(data: IAssetData, spritesheet: Spritesheet): IGraphicAssetCollection { if(!data) return null; const collection = new GraphicAssetCollection(data, spritesheet); if(collection) { for(const [name, texture] of collection.textures.entries()) this.setTexture(name, texture); this._collections.set(collection.name, collection); } return collection; } public async downloadAsset(url: string): Promise { return await this.downloadAssets([url]); } public async downloadAssets(urls: string[]): Promise { if(!urls || !urls.length) return true; const responses = await Promise.all(urls.map(url => fetch(url))); if(!responses || !responses.length) return false; try { for(const response of responses) { const contentType = response.headers.get('Content-Type'); switch(contentType) { case 'application/octet-stream': { const nitroBundle = new NitroBundle(await response.arrayBuffer()); await this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData)); break; } case 'image/png': case 'image/jpeg': case 'image/gif': { const base64 = ArrayBufferToBase64(await response.arrayBuffer()); const baseTexture = BaseTexture.from(`data:${contentType};base64,${base64}`); const createAsset = async () => { const texture = new Texture(baseTexture); this.setTexture(response.url, texture); }; if(baseTexture.valid) { await createAsset(); } else { await new Promise((resolve, reject) => { baseTexture.once('update', async () => { await createAsset(); return resolve(); }); }); } break; } } } } catch (err) { console.error(err); } return true; } private async processAsset(baseTexture: BaseTexture, data: IAssetData): Promise { const spritesheetData = data.spritesheet; if(!baseTexture || !spritesheetData || !Object.keys(spritesheetData).length) { this.createCollection(data, null); return; } const createAsset = async () => { const spritesheet = new Spritesheet(baseTexture, spritesheetData); return new Promise((resolve, reject) => { spritesheet.parse(() => { this.createCollection(data, spritesheet); return resolve(); }); }); }; if(baseTexture.valid) { await createAsset(); } else { await new Promise((resolve, reject) => { baseTexture.once('update', async () => { await createAsset(); return resolve(); }); }); } } public get collections(): Map { return this._collections; } }