322 lines
7.8 KiB
TypeScript
322 lines
7.8 KiB
TypeScript
import {
|
|
AvatarFigurePartType,
|
|
IAvatarImageListener,
|
|
IAvatarRenderManager,
|
|
IFigurePart,
|
|
IFigurePartSet,
|
|
IGraphicAsset,
|
|
IPartColor,
|
|
NitroAlphaFilter,
|
|
NitroContainer,
|
|
NitroSprite,
|
|
TextureUtils,
|
|
} from "@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;
|
|
}
|
|
}
|