Update asset loader to async

This commit is contained in:
Bill 2022-11-14 00:22:26 -05:00
parent 206c5eaa1c
commit c21eb0e699
8 changed files with 177 additions and 234 deletions

View File

@ -1,7 +1,5 @@
import { BaseTexture, Resource, Texture } from '@pixi/core'; import { BaseTexture, Resource, Texture } from '@pixi/core';
import { Loader, LoaderResource } from '@pixi/loaders';
import { Spritesheet } from '@pixi/spritesheet'; import { Spritesheet } from '@pixi/spritesheet';
import { NitroLogger } from '../common';
import { ArrayBufferToBase64, NitroBundle } from '../utils'; import { ArrayBufferToBase64, NitroBundle } from '../utils';
import { GraphicAssetCollection } from './GraphicAssetCollection'; import { GraphicAssetCollection } from './GraphicAssetCollection';
import { IAssetData } from './IAssetData'; import { IAssetData } from './IAssetData';
@ -79,123 +77,77 @@ export class AssetManager implements IAssetManager
return collection; return collection;
} }
public downloadAsset(assetUrl: string, cb: (status: boolean) => void): void public async downloadAsset(url: string): Promise<boolean>
{ {
this.downloadAssets([assetUrl], cb); return await this.downloadAssets([url]);
} }
public downloadAssets(assetUrls: string[], cb: (status: boolean) => void): void public async downloadAssets(urls: string[]): Promise<boolean>
{ {
if(!assetUrls || !assetUrls.length) if(!urls || !urls.length) return true;
const responses = await Promise.all(urls.map(url => fetch(url)));
if(!responses || !responses.length) return false;
try
{ {
cb(true); for(const response of responses)
return;
}
const loader = new Loader();
for(const url of assetUrls)
{
if(!url) continue;
loader
.add({
url,
crossOrigin: 'anonymous',
loadType: LoaderResource.LOAD_TYPE.XHR,
xhrType: LoaderResource.XHR_RESPONSE_TYPE.BUFFER
});
}
let remaining = assetUrls.length;
const onDownloaded = (status: boolean, url: string) =>
{
if(!status)
{ {
NitroLogger.error('Failed to download asset', url); const contentType = response.headers.get('Content-Type');
loader.destroy(); switch(contentType)
cb(false);
return;
}
remaining--;
if(!remaining)
{
loader.destroy();
cb(true);
return;
}
};
loader.load((loader, resources) =>
{
for(const key in resources)
{
const resource = resources[key];
if(!resource || resource.error || !resource.xhr)
{ {
onDownloaded(false, resource.url); case 'application/octet-stream': {
const nitroBundle = new NitroBundle(await response.arrayBuffer());
return; await this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData));
} break;
const resourceType = (resource.xhr.getResponseHeader('Content-Type') || 'application/octet-stream');
if(resourceType === 'application/octet-stream')
{
const nitroBundle = new NitroBundle(resource.data);
this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData), status =>
{
onDownloaded(status, resource.url);
});
continue;
}
if((resourceType === 'image/png') || (resourceType === 'image/jpeg') || (resourceType === 'image/gif'))
{
const base64 = ArrayBufferToBase64(resource.data);
const baseTexture = new BaseTexture(`data:${resourceType};base64,${base64}`);
if(baseTexture.valid)
{
const texture = new Texture(baseTexture);
this.setTexture(resource.name, texture);
onDownloaded(true, resource.url);
} }
else case 'image/png':
{ case 'image/jpeg':
baseTexture.once('update', () => 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); const texture = new Texture(baseTexture);
this.setTexture(resource.name, texture); this.setTexture(response.url, texture);
};
onDownloaded(true, resource.url); if(baseTexture.valid)
}); {
await createAsset();
}
else
{
await new Promise<void>((resolve, reject) =>
{
baseTexture.once('update', async () =>
{
await createAsset();
return resolve();
});
});
}
break;
} }
continue;
} }
onDownloaded(false, resource.url);
} }
}); }
catch (err)
{
console.error(err);
}
return true;
} }
private processAsset(baseTexture: BaseTexture, data: IAssetData, onDownloaded: (status: boolean) => void): void private async processAsset(baseTexture: BaseTexture, data: IAssetData): Promise<void>
{ {
const spritesheetData = data.spritesheet; const spritesheetData = data.spritesheet;
@ -203,30 +155,39 @@ export class AssetManager implements IAssetManager
{ {
this.createCollection(data, null); this.createCollection(data, null);
onDownloaded(true);
return; return;
} }
const createAsset = () => const createAsset = async () =>
{ {
const spritesheet = new Spritesheet(baseTexture, spritesheetData); const spritesheet = new Spritesheet(baseTexture, spritesheetData);
spritesheet.parse(() => return new Promise<void>((resolve, reject) =>
{ {
this.createCollection(data, spritesheet); spritesheet.parse(() =>
{
this.createCollection(data, spritesheet);
onDownloaded(true); return resolve();
});
}); });
}; };
if(baseTexture.valid) if(baseTexture.valid)
{ {
createAsset(); await createAsset();
} }
else else
{ {
baseTexture.once('update', () => createAsset()); await new Promise<void>((resolve, reject) =>
{
baseTexture.once('update', async () =>
{
await createAsset();
return resolve();
});
});
} }
} }

View File

@ -12,7 +12,7 @@ export interface IAssetManager
getAsset(name: string): IGraphicAsset; getAsset(name: string): IGraphicAsset;
getCollection(name: string): IGraphicAssetCollection; getCollection(name: string): IGraphicAssetCollection;
createCollection(data: IAssetData, spritesheet: Spritesheet): IGraphicAssetCollection; createCollection(data: IAssetData, spritesheet: Spritesheet): IGraphicAssetCollection;
downloadAssets(urls: string[], cb: Function): void; downloadAssets(urls: string[]): Promise<boolean>;
downloadAsset(url: string, cb: Function): void; downloadAsset(url: string): Promise<boolean>;
collections: Map<string, IGraphicAssetCollection>; collections: Map<string, IGraphicAssetCollection>;
} }

View File

@ -34,7 +34,7 @@ export class AvatarAssetDownloadLibrary extends EventDispatcher implements IAvat
if(asset) this._state = AvatarAssetDownloadLibrary.LOADED; if(asset) this._state = AvatarAssetDownloadLibrary.LOADED;
} }
public downloadAsset(): void public async downloadAsset(): Promise<void>
{ {
if(!this._assets || (this._state === AvatarAssetDownloadLibrary.LOADING) || (this._state === AvatarAssetDownloadLibrary.LOADED)) return; if(!this._assets || (this._state === AvatarAssetDownloadLibrary.LOADING) || (this._state === AvatarAssetDownloadLibrary.LOADED)) return;
@ -51,15 +51,13 @@ export class AvatarAssetDownloadLibrary extends EventDispatcher implements IAvat
this._state = AvatarAssetDownloadLibrary.LOADING; this._state = AvatarAssetDownloadLibrary.LOADING;
this._assets.downloadAsset(this._downloadUrl, (flag: boolean) => const status = await this._assets.downloadAsset(this._downloadUrl);
{
if(flag)
{
this._state = AvatarAssetDownloadLibrary.LOADED;
this.dispatchEvent(new AvatarRenderLibraryEvent(AvatarRenderLibraryEvent.DOWNLOAD_COMPLETE, this)); if(!status) return;
}
}); this._state = AvatarAssetDownloadLibrary.LOADED;
this.dispatchEvent(new AvatarRenderLibraryEvent(AvatarRenderLibraryEvent.DOWNLOAD_COMPLETE, this));
} }
public get libraryName(): string public get libraryName(): string

View File

@ -36,7 +36,7 @@ export class EffectAssetDownloadLibrary extends EventDispatcher implements IEffe
if(asset) this._state = EffectAssetDownloadLibrary.LOADED; if(asset) this._state = EffectAssetDownloadLibrary.LOADED;
} }
public downloadAsset(): void public async downloadAsset(): Promise<void>
{ {
if(!this._assets || (this._state === EffectAssetDownloadLibrary.LOADING) || (this._state === EffectAssetDownloadLibrary.LOADED)) return; if(!this._assets || (this._state === EffectAssetDownloadLibrary.LOADING) || (this._state === EffectAssetDownloadLibrary.LOADED)) return;
@ -53,19 +53,17 @@ export class EffectAssetDownloadLibrary extends EventDispatcher implements IEffe
this._state = EffectAssetDownloadLibrary.LOADING; this._state = EffectAssetDownloadLibrary.LOADING;
this._assets.downloadAsset(this._downloadUrl, (flag: boolean) => const status = await this._assets.downloadAsset(this._downloadUrl);
{
if(flag)
{
this._state = EffectAssetDownloadLibrary.LOADED;
const collection = this._assets.getCollection(this._libraryName); if(!status) return;
if(collection) this._animation = collection.data.animations; this._state = EffectAssetDownloadLibrary.LOADED;
this.dispatchEvent(new AvatarRenderEffectLibraryEvent(AvatarRenderEffectLibraryEvent.DOWNLOAD_COMPLETE, this)); const collection = this._assets.getCollection(this._libraryName);
}
}); if(collection) this._animation = collection.data.animations;
this.dispatchEvent(new AvatarRenderEffectLibraryEvent(AvatarRenderEffectLibraryEvent.DOWNLOAD_COMPLETE, this));
} }
public get libraryName(): string public get libraryName(): string

View File

@ -1,5 +1,4 @@
import { BaseTexture, Resource, Texture } from '@pixi/core'; import { BaseTexture, Resource, Texture } from '@pixi/core';
import { Loader, LoaderResource } from '@pixi/loaders';
import { Spritesheet } from '@pixi/spritesheet'; import { Spritesheet } from '@pixi/spritesheet';
import { FurnitureType, GetAssetManager, GraphicAssetCollection, GraphicAssetGifCollection, IAssetData, IEventDispatcher, IFurnitureData, IFurnitureDataListener, IGraphicAssetCollection, IGraphicAssetGifCollection, IPetColorResult, IRoomContentListener, IRoomContentLoader, IRoomObject, ISessionDataManager, NitroBundle, NitroConfiguration, NitroLogger, RoomObjectCategory, RoomObjectUserType, RoomObjectVariable, RoomObjectVisualizationType } from '../../api'; import { FurnitureType, GetAssetManager, GraphicAssetCollection, GraphicAssetGifCollection, IAssetData, IEventDispatcher, IFurnitureData, IFurnitureDataListener, IGraphicAssetCollection, IGraphicAssetGifCollection, IPetColorResult, IRoomContentListener, IRoomContentLoader, IRoomObject, ISessionDataManager, NitroBundle, NitroConfiguration, NitroLogger, RoomObjectCategory, RoomObjectUserType, RoomObjectVariable, RoomObjectVisualizationType } from '../../api';
import { NitroEvent } from '../../events'; import { NitroEvent } from '../../events';
@ -481,94 +480,48 @@ export class RoomContentLoader implements IFurnitureDataListener, IRoomContentLo
return false; return false;
} }
public downloadAsset(type: string, events: IEventDispatcher): void public async downloadAsset(type: string, events: IEventDispatcher): Promise<void>
{ {
const assetUrls: string[] = this.getAssetUrls(type); const assetUrl: string = this.getAssetUrls(type)?.[0];
if(!assetUrls || !assetUrls.length) return; if(!assetUrl || !assetUrl.length) return;
if((this._pendingContentTypes.indexOf(type) >= 0) || this.getOrRemoveEventDispatcher(type)) return; if((this._pendingContentTypes.indexOf(type) >= 0) || this.getOrRemoveEventDispatcher(type)) return;
this._pendingContentTypes.push(type); this._pendingContentTypes.push(type);
this._events.set(type, events); this._events.set(type, events);
const loader = new Loader(); try
for(const url of assetUrls)
{ {
if(!url || !url.length) continue; const response = await fetch(assetUrl);
const contentType = response.headers.get('Content-Type');
loader switch(contentType)
.add({ {
url, case 'application/octet-stream': {
crossOrigin: 'anonymous', const nitroBundle = new NitroBundle(await response.arrayBuffer());
loadType: LoaderResource.LOAD_TYPE.XHR,
xhrType: LoaderResource.XHR_RESPONSE_TYPE.BUFFER await this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData));
});
const events = this._events.get(type);
if(!events) return;
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_SUCCESS, type));
break;
}
default:
throw new Error();
}
} }
let remaining = assetUrls.length; catch (err)
const onDownloaded = (status: boolean, url: string) =>
{ {
if(!status) events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_FAILURE, type));
{ }
NitroLogger.error('Failed to download asset', url);
loader.destroy();
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_FAILURE, type));
return;
}
remaining--;
if(!remaining)
{
loader.destroy();
const events = this._events.get(type);
if(!events) return;
events.dispatchEvent(new RoomContentLoadedEvent(RoomContentLoadedEvent.RCLE_SUCCESS, type));
return;
}
};
loader.load((loader, resources) =>
{
for(const key in resources)
{
const resource = resources[key];
if(!resource || resource.error || !resource.xhr)
{
onDownloaded(false, resource.url);
return;
}
const resourceType = (resource.xhr.getResponseHeader('Content-Type') || 'application/octet-stream');
if(resourceType === 'application/octet-stream')
{
const nitroBundle = new NitroBundle(resource.data);
this.processAsset(nitroBundle.baseTexture, (nitroBundle.jsonFile as IAssetData), status =>
{
onDownloaded(status, resource.url);
});
continue;
}
}
});
} }
private processAsset(baseTexture: BaseTexture, data: IAssetData, onDownloaded: (status: boolean) => void): void private async processAsset(baseTexture: BaseTexture, data: IAssetData): Promise<void>
{ {
const spritesheetData = data.spritesheet; const spritesheetData = data.spritesheet;
@ -576,30 +529,39 @@ export class RoomContentLoader implements IFurnitureDataListener, IRoomContentLo
{ {
this.createCollection(data, null); this.createCollection(data, null);
onDownloaded(true);
return; return;
} }
const createAsset = () => const createAsset = async () =>
{ {
const spritesheet = new Spritesheet(baseTexture, spritesheetData); const spritesheet = new Spritesheet(baseTexture, spritesheetData);
spritesheet.parse(() => return new Promise<void>((resolve, reject) =>
{ {
this.createCollection(data, spritesheet); spritesheet.parse(() =>
{
this.createCollection(data, spritesheet);
onDownloaded(true); return resolve();
});
}); });
}; };
if(baseTexture.valid) if(baseTexture.valid)
{ {
createAsset(); await createAsset();
} }
else else
{ {
baseTexture.once('update', () => createAsset()); await new Promise<void>((resolve, reject) =>
{
baseTexture.once('update', async () =>
{
await createAsset();
return resolve();
});
});
} }
} }

View File

@ -134,7 +134,7 @@ export class FurnitureRoomBrandingLogic extends FurnitureLogic
super.mouseEvent(event, geometry); super.mouseEvent(event, geometry);
} }
private downloadBackground(): void private async downloadBackground(): Promise<void>
{ {
const model = this.object && this.object.model; const model = this.object && this.object.model;
@ -216,17 +216,16 @@ export class FurnitureRoomBrandingLogic extends FurnitureLogic
if(!texture) if(!texture)
{ {
asset.downloadAsset(imageUrl, (flag: boolean) => const status = await asset.downloadAsset(imageUrl);
if(!status)
{ {
if(flag) this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADING_FAILED));
{ }
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED)); else
} {
else this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADED));
{ }
this.processUpdateMessage(new ObjectAdUpdateMessage(ObjectAdUpdateMessage.IMAGE_LOADING_FAILED));
}
});
return; return;
} }

View File

@ -1,7 +1,7 @@
import { RenderTexture, Resource, Texture } from '@pixi/core'; import { Resource, Texture } from '@pixi/core';
import { Matrix } from '@pixi/math'; import { Matrix } from '@pixi/math';
import { IGraphicAsset, IRoomObjectSprite, RoomObjectVariable } from '../../../../../api'; import { IGraphicAsset, IRoomObjectSprite, RoomObjectVariable } from '../../../../../api';
import { NitroSprite, PixiApplicationProxy } from '../../../../../pixi-proxy'; import { NitroSprite, TextureUtils } from '../../../../../pixi-proxy';
import { IsometricImageFurniVisualization } from './IsometricImageFurniVisualization'; import { IsometricImageFurniVisualization } from './IsometricImageFurniVisualization';
export class FurnitureGuildIsometricBadgeVisualization extends IsometricImageFurniVisualization export class FurnitureGuildIsometricBadgeVisualization extends IsometricImageFurniVisualization
@ -42,8 +42,6 @@ export class FurnitureGuildIsometricBadgeVisualization extends IsometricImageFur
const matrix = new Matrix(); const matrix = new Matrix();
const difference = (asset.width / texture.width); const difference = (asset.width / texture.width);
console.log(((0.5 * difference) * texture.width));
switch(this.direction) switch(this.direction)
{ {
case 2: case 2:
@ -52,7 +50,7 @@ export class FurnitureGuildIsometricBadgeVisualization extends IsometricImageFur
matrix.c = 0; matrix.c = 0;
matrix.d = (difference * scale); matrix.d = (difference * scale);
matrix.tx = 0; matrix.tx = 0;
matrix.ty = 20; matrix.ty = ((0.5 * difference) * texture.width);
break; break;
case 0: case 0:
case 4: case 4:
@ -74,18 +72,40 @@ export class FurnitureGuildIsometricBadgeVisualization extends IsometricImageFur
const sprite = new NitroSprite(texture); const sprite = new NitroSprite(texture);
sprite.transform.setFromMatrix(matrix);
sprite.position.set(0);
return TextureUtils.generateTexture(sprite);
/* const renderTexture = RenderTexture.create({
width: asset.width,
height: asset.height
});
PixiApplicationProxy.instance.renderer.render(sprite, {
renderTexture,
clear: true,
});
return renderTexture; */
/* const sprite = new NitroSprite(texture);
const renderTexture = RenderTexture.create({ const renderTexture = RenderTexture.create({
width: (asset.width + matrix.tx), width: (asset.width + matrix.tx),
height: (asset.height + matrix.ty) height: (asset.height + matrix.ty)
}); });
sprite.position.set(0)
PixiApplicationProxy.instance.renderer.render(sprite, { PixiApplicationProxy.instance.renderer.render(sprite, {
renderTexture, renderTexture,
clear: true, clear: true,
transform: matrix transform: matrix
}); });
return renderTexture; return renderTexture; */
} }
protected getLayerColor(scale: number, layerId: number, colorId: number): number protected getLayerColor(scale: number, layerId: number, colorId: number): number

View File

@ -106,17 +106,22 @@ export class BadgeImageManager implements IDisposable
this._requestedBadges.set(badgeName, true); this._requestedBadges.set(badgeName, true);
this._assets.downloadAsset(url, (flag: boolean) => this._assets
{ .downloadAsset(url)
if(flag) .then(status =>
{ {
if(!status) return;
this._requestedBadges.delete(badgeName); this._requestedBadges.delete(badgeName);
const texture = this._assets.getTexture(url); const texture = this._assets.getTexture(url);
if(texture && this._sessionDataManager) this._sessionDataManager.events.dispatchEvent(new BadgeImageReadyEvent(badgeName, texture.clone())); if(texture && this._sessionDataManager) this._sessionDataManager.events.dispatchEvent(new BadgeImageReadyEvent(badgeName, texture.clone()));
} })
}); .catch(err =>
{
});
} }
else if(type === BadgeImageManager.GROUP_BADGE) else if(type === BadgeImageManager.GROUP_BADGE)