nitro-renderer/src/api/asset/AssetManager.ts

206 lines
5.8 KiB
TypeScript

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<string, Texture<Resource>> = new Map();
private _collections: Map<string, IGraphicAssetCollection> = new Map();
public getTexture(name: string): Texture<Resource>
{
if(!name) return null;
const existing = this._textures.get(name);
if(!existing) return null;
return existing;
}
public setTexture(name: string, texture: Texture<Resource>): 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<boolean>
{
return await this.downloadAssets([url]);
}
public async downloadAssets(urls: string[]): Promise<boolean>
{
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<void>((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<void>
{
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<void>((resolve, reject) =>
{
baseTexture.once('update', async () =>
{
await createAsset();
return resolve();
});
});
}
}
public get collections(): Map<string, IGraphicAssetCollection>
{
return this._collections;
}
}