nitro/apps/frontend/src/api/avatar/AvatarEditorGridPartItem.ts

338 lines
8.7 KiB
TypeScript

import { AvatarFigurePartType, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroAlphaFilter, NitroContainer, NitroSprite, TextureUtils } from '@nitrots/nitro-renderer';
import { GetAvatarRenderManager } from '../nitro';
import { FigureData } from './FigureData';
export class AvatarEditorGridPartItem implements IAvatarImageListener
{
private static ALPHA_FILTER: NitroAlphaFilter = new NitroAlphaFilter(0.2);
private static THUMB_DIRECTIONS: number[] = [ 2, 6, 0, 4, 3, 1 ];
private static DRAW_ORDER: string[] = [
AvatarFigurePartType.LEFT_HAND_ITEM,
AvatarFigurePartType.LEFT_HAND,
AvatarFigurePartType.LEFT_SLEEVE,
AvatarFigurePartType.LEFT_COAT_SLEEVE,
AvatarFigurePartType.BODY,
AvatarFigurePartType.SHOES,
AvatarFigurePartType.LEGS,
AvatarFigurePartType.CHEST,
AvatarFigurePartType.CHEST_ACCESSORY,
AvatarFigurePartType.COAT_CHEST,
AvatarFigurePartType.CHEST_PRINT,
AvatarFigurePartType.WAIST_ACCESSORY,
AvatarFigurePartType.RIGHT_HAND,
AvatarFigurePartType.RIGHT_SLEEVE,
AvatarFigurePartType.RIGHT_COAT_SLEEVE,
AvatarFigurePartType.HEAD,
AvatarFigurePartType.FACE,
AvatarFigurePartType.EYES,
AvatarFigurePartType.HAIR,
AvatarFigurePartType.HAIR_BIG,
AvatarFigurePartType.FACE_ACCESSORY,
AvatarFigurePartType.EYE_ACCESSORY,
AvatarFigurePartType.HEAD_ACCESSORY,
AvatarFigurePartType.HEAD_ACCESSORY_EXTRA,
AvatarFigurePartType.RIGHT_HAND_ITEM,
];
private _renderManager: IAvatarRenderManager;
private _partSet: IFigurePartSet;
private _partColors: IPartColor[];
private _useColors: boolean;
private _isDisabled: boolean;
private _thumbContainer: NitroContainer;
private _imageUrl: string;
private _maxColorIndex: number;
private _isValidFigure: boolean;
private _isHC: boolean;
private _isSellable: boolean;
private _isClear: boolean;
private _isSelected: boolean;
private _disposed: boolean;
private _isInitalized: boolean;
private _notifier: () => void;
constructor(partSet: IFigurePartSet, partColors: IPartColor[], useColors: boolean = true, isDisabled: boolean = false)
{
this._renderManager = GetAvatarRenderManager();
this._partSet = partSet;
this._partColors = partColors;
this._useColors = useColors;
this._isDisabled = isDisabled;
this._thumbContainer = null;
this._imageUrl = null;
this._maxColorIndex = 0;
this._isValidFigure = false;
this._isHC = false;
this._isSellable = false;
this._isClear = false;
this._isSelected = false;
this._disposed = false;
this._isInitalized = false;
if(partSet)
{
const colors = partSet.parts;
for(const color of colors) this._maxColorIndex = Math.max(this._maxColorIndex, color.colorLayerIndex);
}
}
public init(): void
{
if(this._isInitalized) return;
this._isInitalized = true;
this.update();
}
public dispose(): void
{
if(this._disposed) return;
this._renderManager = null;
this._partSet = null;
this._partColors = null;
this._imageUrl = null;
this._disposed = true;
this._isInitalized = false;
if(this._thumbContainer)
{
this._thumbContainer.destroy();
this._thumbContainer = null;
}
}
public update(): void
{
this.updateThumbVisualization();
}
private analyzeFigure(): boolean
{
if(!this._renderManager || !this._partSet || !this._partSet.parts || !this._partSet.parts.length) return false;
const figureContainer = this._renderManager.createFigureContainer(((this.partSet.type + '-') + this.partSet.id));
if(!this._renderManager.isFigureContainerReady(figureContainer))
{
this._renderManager.downloadAvatarFigure(figureContainer, this);
return false;
}
this._isValidFigure = true;
return true;
}
private renderThumb(): NitroContainer
{
if(!this._renderManager || !this._partSet) return null;
if(!this._isValidFigure)
{
if(!this.analyzeFigure()) return null;
}
const parts = this._partSet.parts.concat().sort(this.sortByDrawOrder);
const container = new NitroContainer();
for(const part of parts)
{
if(!part) continue;
let asset: IGraphicAsset = null;
let direction = 0;
let hasAsset = false;
while(!hasAsset && (direction < AvatarEditorGridPartItem.THUMB_DIRECTIONS.length))
{
const assetName = ((((((((((FigureData.SCALE + '_') + FigureData.STD) + '_') + part.type) + '_') + part.id) + '_') + AvatarEditorGridPartItem.THUMB_DIRECTIONS[direction]) + '_') + FigureData.DEFAULT_FRAME);
asset = this._renderManager.getAssetByName(assetName);
if(asset && asset.texture)
{
hasAsset = true;
}
else
{
direction++;
}
}
if(!hasAsset) continue;
const x = asset.offsetX;
const y = asset.offsetY;
let partColor: IPartColor = null;
if(this._useColors && (part.colorLayerIndex > 0))
{
const color = this._partColors[(part.colorLayerIndex - 1)];
if(color) partColor = color;
}
const sprite = new NitroSprite(asset.texture);
sprite.position.set(x, y);
if(partColor) sprite.tint = partColor.rgb;
container.addChild(sprite);
}
return container;
}
private updateThumbVisualization(): void
{
if(!this._isInitalized) return;
let container = this._thumbContainer;
if(!container) container = this.renderThumb();
if(!container) return;
if(this._partSet)
{
this._isHC = (this._partSet.clubLevel > 0);
this._isSellable = this._partSet.isSellable;
}
else
{
this._isHC = false;
this._isSellable = false;
}
if(this._isDisabled) this.setAlpha(container, 0.2);
this._imageUrl = TextureUtils.generateImageUrl(container);
if(this.notify) this.notify();
}
private setAlpha(container: NitroContainer, alpha: number): NitroContainer
{
container.filters = [ AvatarEditorGridPartItem.ALPHA_FILTER ];
return container;
}
private sortByDrawOrder(a: IFigurePart, b: IFigurePart): number
{
const indexA = AvatarEditorGridPartItem.DRAW_ORDER.indexOf(a.type);
const indexB = AvatarEditorGridPartItem.DRAW_ORDER.indexOf(b.type);
if(indexA < indexB) return -1;
if(indexA > indexB) return 1;
if(a.index < b.index) return -1;
if(a.index > b.index) return 1;
return 0;
}
public resetFigure(figure: string): void
{
if(!this.analyzeFigure()) return;
this.update();
}
public get disposed(): boolean
{
return this._disposed;
}
public get id(): number
{
if(!this._partSet) return -1;
return this._partSet.id;
}
public get partSet(): IFigurePartSet
{
return this._partSet;
}
public set partColors(partColors: IPartColor[])
{
this._partColors = partColors;
this.update();
}
public get isDisabled(): boolean
{
return this._isDisabled;
}
public set thumbContainer(container: NitroContainer)
{
this._thumbContainer = container;
this.update();
}
public get imageUrl(): string
{
return this._imageUrl;
}
public get maxColorIndex(): number
{
return this._maxColorIndex;
}
public get isHC(): boolean
{
return this._isHC;
}
public get isSellable(): boolean
{
return this._isSellable;
}
public get isClear(): boolean
{
return this._isClear;
}
public set isClear(flag: boolean)
{
this._isClear = flag;
}
public get isSelected(): boolean
{
return this._isSelected;
}
public set isSelected(flag: boolean)
{
this._isSelected = flag;
if(this.notify) this.notify();
}
public get notify(): () => void
{
return this._notifier;
}
public set notify(notifier: () => void)
{
this._notifier = notifier;
}
}