import { BaseTexture, Resource, Texture } from '@pixi/core'; import { Spritesheet } from '@pixi/spritesheet'; import { NitroLogger } from '../common'; 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 Promise.resolve(true); try { for(const url of urls) { const response = await fetch(url); if(response.status !== 200) continue; let contentType = 'application/octet-stream'; if(response.headers.has('Content-Type')) { contentType = response.headers.get('Content-Type'); } switch(contentType) { case 'application/octet-stream': { const buffer = await response.arrayBuffer(); const nitroBundle = new NitroBundle(buffer); await this.processAsset( nitroBundle.baseTexture, nitroBundle.jsonFile as IAssetData ); break; } case 'image/png': case 'image/jpeg': case 'image/gif': { const buffer = await response.arrayBuffer(); const base64 = ArrayBufferToBase64(buffer); const baseTexture = BaseTexture.from( `data:${ contentType };base64,${ base64 }` ); const createAsset = async () => { const texture = new Texture(baseTexture); this.setTexture(url, texture); }; if(baseTexture.valid) { await createAsset(); } else { await new Promise((resolve, reject) => { baseTexture.once('update', async () => { await createAsset(); return resolve(); }); }); } break; } } } return Promise.resolve(true); } catch (err) { NitroLogger.error(err); return Promise.resolve(false); } } 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); await spritesheet.parse(); this.createCollection(data, spritesheet); }; 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; } }