mirror of
https://github.com/billsonnn/nitro-imager
synced 2024-11-22 23:50:53 +01:00
First commit
This commit is contained in:
commit
a314dc2abe
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Editor configuration, see https://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.ts]
|
||||||
|
quote_type = single
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off
|
||||||
|
trim_trailing_whitespace = false
|
1
.env
Normal file
1
.env
Normal file
@ -0,0 +1 @@
|
|||||||
|
CONFIG_URL=http://client.nitrots.co:3000/renderer-config.json
|
51
.gitignore
vendored
Normal file
51
.gitignore
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
/node_modules
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
chrome-profiler-events*.json
|
||||||
|
speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
/.idea
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
/.sass-cache
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
.git
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
*.zip
|
||||||
|
*.as
|
||||||
|
*.bin
|
16
.vscode/settings.json
vendored
Normal file
16
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules\\typescript\\lib",
|
||||||
|
"typescript.preferences.importModuleSpecifier": "relative",
|
||||||
|
"typescript.preferences.quoteStyle": "single",
|
||||||
|
"typescript.format.placeOpenBraceOnNewLineForControlBlocks": true,
|
||||||
|
"typescript.format.placeOpenBraceOnNewLineForFunctions": true,
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.fixAll": true,
|
||||||
|
"source.organizeImports": true,
|
||||||
|
},
|
||||||
|
"emmet.showExpandedAbbreviation": "never",
|
||||||
|
"git.ignoreLimitWarning": true,
|
||||||
|
"files.eol": "\n",
|
||||||
|
"files.insertFinalNewline": true,
|
||||||
|
"files.trimFinalNewlines": true
|
||||||
|
}
|
1373
package-lock.json
generated
Normal file
1373
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
package.json
Normal file
38
package.json
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"name": "nitro-imager",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"dependencies": {
|
||||||
|
"bytebuffer": "^5.0.1",
|
||||||
|
"canvas": "^2.8.0",
|
||||||
|
"chalk": "^4.1.2",
|
||||||
|
"dotenv": "^10.0.0",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"node-fetch": "^2.6.1",
|
||||||
|
"pako": "^2.0.4"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bytebuffer": "^5.0.42",
|
||||||
|
"@types/chalk": "^2.2.0",
|
||||||
|
"@types/express": "^4.17.13",
|
||||||
|
"@types/node": "^14.17.12",
|
||||||
|
"@types/node-fetch": "^2.5.12",
|
||||||
|
"@types/pako": "^1.0.2",
|
||||||
|
"ts-node-dev": "^1.1.8",
|
||||||
|
"typescript": "^4.4.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start:dev": "ts-node-dev --respawn --transpile-only ./src/main.ts"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/billsonnn/nitro-imager.git"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/billsonnn/nitro-imager/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/billsonnn/nitro-imager#readme"
|
||||||
|
}
|
63
src/app/Application.ts
Normal file
63
src/app/Application.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { INitroCore, NitroManager } from '../core';
|
||||||
|
import { AvatarRenderManager, AvatarScaleType, AvatarSetType, IAvatarRenderManager } from './avatar';
|
||||||
|
import { IApplication } from './IApplication';
|
||||||
|
|
||||||
|
export class Application extends NitroManager implements IApplication
|
||||||
|
{
|
||||||
|
private static INSTANCE: IApplication = null;
|
||||||
|
|
||||||
|
private _core: INitroCore;
|
||||||
|
private _avatar: IAvatarRenderManager;
|
||||||
|
|
||||||
|
constructor(core: INitroCore)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
Application.INSTANCE = this;
|
||||||
|
|
||||||
|
this._core = core;
|
||||||
|
this._avatar = new AvatarRenderManager(core.asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onInit(): Promise<void>
|
||||||
|
{
|
||||||
|
if(this._core) await this._core.init();
|
||||||
|
|
||||||
|
if(this._avatar) await this._avatar.init();
|
||||||
|
|
||||||
|
const image = await this._avatar.createAvatarImage('hd-207-14.lg-3216-1408.cc-3007-86-88.ha-3054-1408-1408.he-3079-64.ea-1402-0.ch-230-72.hr-110-40', AvatarScaleType.LARGE, 'M');
|
||||||
|
|
||||||
|
//image.setDirection(AvatarSetType.FULL, 2);
|
||||||
|
const canvas = await image.getImage(AvatarSetType.FULL, false);
|
||||||
|
console.log(canvas.toDataURL());
|
||||||
|
|
||||||
|
this.logger.log(`Initialized`);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onDispose(): Promise<void>
|
||||||
|
{
|
||||||
|
if(this._avatar) await this._avatar.dispose();
|
||||||
|
|
||||||
|
if(this._core) await this._core.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getConfiguration<T>(key: string, value: T = null): T
|
||||||
|
{
|
||||||
|
return this._core.configuration.getValue<T>(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get core(): INitroCore
|
||||||
|
{
|
||||||
|
return this._core;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get avatar(): IAvatarRenderManager
|
||||||
|
{
|
||||||
|
return this._avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get instance(): IApplication
|
||||||
|
{
|
||||||
|
return this.INSTANCE;
|
||||||
|
}
|
||||||
|
}
|
9
src/app/IApplication.ts
Normal file
9
src/app/IApplication.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { INitroCore, INitroManager } from '../core';
|
||||||
|
import { IAvatarRenderManager } from './avatar';
|
||||||
|
|
||||||
|
export interface IApplication extends INitroManager
|
||||||
|
{
|
||||||
|
getConfiguration<T>(key: string, value?: T): T;
|
||||||
|
core: INitroCore;
|
||||||
|
avatar: IAvatarRenderManager;
|
||||||
|
}
|
67
src/app/avatar/AvatarAssetDownloadLibrary.ts
Normal file
67
src/app/avatar/AvatarAssetDownloadLibrary.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { IAssetManager } from '../../core';
|
||||||
|
|
||||||
|
export class AvatarAssetDownloadLibrary
|
||||||
|
{
|
||||||
|
private static NOT_LOADED: number = 0;
|
||||||
|
private static LOADING: number = 1;
|
||||||
|
private static LOADED: number = 2;
|
||||||
|
|
||||||
|
private _state: number;
|
||||||
|
private _libraryName: string;
|
||||||
|
private _revision: string;
|
||||||
|
private _downloadUrl: string;
|
||||||
|
private _assets: IAssetManager;
|
||||||
|
|
||||||
|
constructor(id: string, revision: string, assets: IAssetManager, assetUrl: string)
|
||||||
|
{
|
||||||
|
this._state = AvatarAssetDownloadLibrary.NOT_LOADED;
|
||||||
|
this._libraryName = id;
|
||||||
|
this._revision = revision;
|
||||||
|
this._downloadUrl = assetUrl;
|
||||||
|
this._assets = assets;
|
||||||
|
|
||||||
|
this._downloadUrl = this._downloadUrl.replace(/%libname%/gi, this._libraryName);
|
||||||
|
this._downloadUrl = this._downloadUrl.replace(/%revision%/gi, this._revision);
|
||||||
|
|
||||||
|
this.checkIfAssetLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkIfAssetLoaded(): boolean
|
||||||
|
{
|
||||||
|
if(this._state === AvatarAssetDownloadLibrary.LOADED) return true;
|
||||||
|
|
||||||
|
const asset = this._assets.getCollection(this._libraryName);
|
||||||
|
|
||||||
|
if(asset)
|
||||||
|
{
|
||||||
|
this._state = AvatarAssetDownloadLibrary.LOADED;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async downloadAsset(): Promise<void>
|
||||||
|
{
|
||||||
|
if(!this._assets || (this._state === AvatarAssetDownloadLibrary.LOADING)) return;
|
||||||
|
|
||||||
|
if(this.checkIfAssetLoaded()) return;
|
||||||
|
|
||||||
|
this._state = AvatarAssetDownloadLibrary.LOADING;
|
||||||
|
|
||||||
|
await this._assets.downloadAsset(this._downloadUrl);
|
||||||
|
|
||||||
|
this._state = AvatarAssetDownloadLibrary.LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get libraryName(): string
|
||||||
|
{
|
||||||
|
return this._libraryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isLoaded(): boolean
|
||||||
|
{
|
||||||
|
return (this._state === AvatarAssetDownloadLibrary.LOADED);
|
||||||
|
}
|
||||||
|
}
|
154
src/app/avatar/AvatarAssetDownloadManager.ts
Normal file
154
src/app/avatar/AvatarAssetDownloadManager.ts
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { AdvancedMap, IAssetManager } from '../../core';
|
||||||
|
import { Application } from '../Application';
|
||||||
|
import { AvatarAssetDownloadLibrary } from './AvatarAssetDownloadLibrary';
|
||||||
|
import { AvatarStructure } from './AvatarStructure';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
|
||||||
|
export class AvatarAssetDownloadManager
|
||||||
|
{
|
||||||
|
private _assets: IAssetManager;
|
||||||
|
private _structure: AvatarStructure;
|
||||||
|
|
||||||
|
private _missingMandatoryLibs: string[];
|
||||||
|
private _figureMap: AdvancedMap<string, AvatarAssetDownloadLibrary[]>;
|
||||||
|
private _libraryNames: string[];
|
||||||
|
|
||||||
|
constructor(assets: IAssetManager, structure: AvatarStructure)
|
||||||
|
{
|
||||||
|
this._assets = assets;
|
||||||
|
this._structure = structure;
|
||||||
|
|
||||||
|
this._missingMandatoryLibs = Application.instance.getConfiguration<string[]>('avatar.mandatory.libraries');
|
||||||
|
this._figureMap = new AdvancedMap();
|
||||||
|
this._libraryNames = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async loadFigureMap(): Promise<void>
|
||||||
|
{
|
||||||
|
const url = Application.instance.getConfiguration<string>('avatar.figuremap.url');
|
||||||
|
|
||||||
|
const data = await fetch(url);
|
||||||
|
const json = await data.json();
|
||||||
|
|
||||||
|
this.processFigureMap(json.libraries);
|
||||||
|
|
||||||
|
await this.processMissingLibraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
private processFigureMap(data: any): void
|
||||||
|
{
|
||||||
|
if(!data) return;
|
||||||
|
|
||||||
|
const avatarAssetUrl = Application.instance.getConfiguration<string>('avatar.asset.url');
|
||||||
|
|
||||||
|
for(const library of data)
|
||||||
|
{
|
||||||
|
if(!library) continue;
|
||||||
|
|
||||||
|
const id = (library.id as string);
|
||||||
|
const revision = (library.revision || '');
|
||||||
|
|
||||||
|
if(this._libraryNames.indexOf(id) >= 0) continue;
|
||||||
|
|
||||||
|
this._libraryNames.push(id);
|
||||||
|
|
||||||
|
const downloadLibrary = new AvatarAssetDownloadLibrary(id, revision, this._assets, avatarAssetUrl);
|
||||||
|
|
||||||
|
for(const part of library.parts)
|
||||||
|
{
|
||||||
|
const id = (part.id as string);
|
||||||
|
const type = (part.type as string);
|
||||||
|
const partString = (type + ':' + id);
|
||||||
|
|
||||||
|
let existing = this._figureMap.getValue(partString);
|
||||||
|
|
||||||
|
if(!existing) existing = [];
|
||||||
|
|
||||||
|
existing.push(downloadLibrary);
|
||||||
|
|
||||||
|
this._figureMap.add(partString, existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async processMissingLibraries(): Promise<void>
|
||||||
|
{
|
||||||
|
const missingLibraries = this._missingMandatoryLibs.slice();
|
||||||
|
|
||||||
|
for(const library of missingLibraries)
|
||||||
|
{
|
||||||
|
if(!library) continue;
|
||||||
|
|
||||||
|
const libraries = this._figureMap.getValue(library);
|
||||||
|
|
||||||
|
if(libraries) for(const library of libraries) (library && await this.downloadLibrary(library));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public isAvatarFigureContainerReady(container: IAvatarFigureContainer): boolean
|
||||||
|
{
|
||||||
|
const pendingLibraries = this.getAvatarFigurePendingLibraries(container);
|
||||||
|
|
||||||
|
return !pendingLibraries.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAvatarFigurePendingLibraries(container: IAvatarFigureContainer): AvatarAssetDownloadLibrary[]
|
||||||
|
{
|
||||||
|
const pendingLibraries: AvatarAssetDownloadLibrary[] = [];
|
||||||
|
|
||||||
|
if(!container || !this._structure) return pendingLibraries;
|
||||||
|
|
||||||
|
const figureData = this._structure.figureData;
|
||||||
|
|
||||||
|
if(!figureData) return pendingLibraries;
|
||||||
|
|
||||||
|
const setKeys = container.getPartTypeIds();
|
||||||
|
|
||||||
|
for(const key of setKeys)
|
||||||
|
{
|
||||||
|
const set = figureData.getSetType(key);
|
||||||
|
|
||||||
|
if(!set) continue;
|
||||||
|
|
||||||
|
const figurePartSet = set.getPartSet(container.getPartSetId(key));
|
||||||
|
|
||||||
|
if(!figurePartSet) continue;
|
||||||
|
|
||||||
|
for(const part of figurePartSet.parts)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
const name = (part.type + ':' + part.id);
|
||||||
|
const existing = this._figureMap.getValue(name);
|
||||||
|
|
||||||
|
if(existing === undefined) continue;
|
||||||
|
|
||||||
|
for(const library of existing)
|
||||||
|
{
|
||||||
|
if(!library || library.isLoaded) continue;
|
||||||
|
|
||||||
|
if(pendingLibraries.indexOf(library) >= 0) continue;
|
||||||
|
|
||||||
|
pendingLibraries.push(library);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pendingLibraries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async downloadAvatarFigure(container: IAvatarFigureContainer): Promise<void>
|
||||||
|
{
|
||||||
|
const pendingLibraries = this.getAvatarFigurePendingLibraries(container);
|
||||||
|
|
||||||
|
for(const library of pendingLibraries) (library && await this.downloadLibrary(library));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async downloadLibrary(library: AvatarAssetDownloadLibrary): Promise<void>
|
||||||
|
{
|
||||||
|
if(!library || library.isLoaded) return;
|
||||||
|
|
||||||
|
await library.downloadAsset();
|
||||||
|
}
|
||||||
|
}
|
117
src/app/avatar/AvatarFigureContainer.ts
Normal file
117
src/app/avatar/AvatarFigureContainer.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { AdvancedMap } from '../../core';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
|
||||||
|
export class AvatarFigureContainer implements IAvatarFigureContainer
|
||||||
|
{
|
||||||
|
private _parts: AdvancedMap<string, AdvancedMap<string, any>>;
|
||||||
|
|
||||||
|
constructor(figure: string)
|
||||||
|
{
|
||||||
|
this._parts = new AdvancedMap();
|
||||||
|
|
||||||
|
this.parseFigure(figure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartTypeIds(): string[]
|
||||||
|
{
|
||||||
|
return this.partSets().getKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasPartType(k: string): boolean
|
||||||
|
{
|
||||||
|
return !!this.partSets().getValue(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartSetId(k: string): number
|
||||||
|
{
|
||||||
|
const existing = this.partSets().getValue(k);
|
||||||
|
|
||||||
|
if(!existing) return 0;
|
||||||
|
|
||||||
|
return existing.getValue('setid');
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartColorIds(k: string): number[]
|
||||||
|
{
|
||||||
|
const existing = this.partSets().getValue(k);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing.getValue('colorids');
|
||||||
|
}
|
||||||
|
|
||||||
|
public updatePart(setType: string, partSetId: number, colorIds: number[]): void
|
||||||
|
{
|
||||||
|
const set: AdvancedMap<string, any> = new AdvancedMap();
|
||||||
|
|
||||||
|
set.add('type', setType);
|
||||||
|
set.add('setid', partSetId);
|
||||||
|
set.add('colorids', colorIds);
|
||||||
|
|
||||||
|
const existingSets = this.partSets();
|
||||||
|
|
||||||
|
existingSets.remove(setType);
|
||||||
|
existingSets.add(setType, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removePart(k: string): void
|
||||||
|
{
|
||||||
|
this.partSets().remove(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigureString(): string
|
||||||
|
{
|
||||||
|
const parts: string[] = [];
|
||||||
|
|
||||||
|
for(const key of this.partSets().getKeys())
|
||||||
|
{
|
||||||
|
if(!key) continue;
|
||||||
|
|
||||||
|
let setParts = [];
|
||||||
|
|
||||||
|
setParts.push(key);
|
||||||
|
setParts.push(this.getPartSetId(key));
|
||||||
|
|
||||||
|
setParts = setParts.concat(this.getPartColorIds(key));
|
||||||
|
|
||||||
|
parts.push(setParts.join('-'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
private partSets(): AdvancedMap<string, AdvancedMap<string, any>>
|
||||||
|
{
|
||||||
|
if(!this._parts) this._parts = new AdvancedMap();
|
||||||
|
|
||||||
|
return this._parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFigure(figure: string): void
|
||||||
|
{
|
||||||
|
if(!figure) figure = '';
|
||||||
|
|
||||||
|
for(const part of figure.split('.'))
|
||||||
|
{
|
||||||
|
const pieces = part.split('-');
|
||||||
|
|
||||||
|
if(pieces.length >= 2)
|
||||||
|
{
|
||||||
|
const type = pieces[0];
|
||||||
|
const setId = parseInt(pieces[1]);
|
||||||
|
const colors = [];
|
||||||
|
|
||||||
|
let index = 2;
|
||||||
|
|
||||||
|
while(index < pieces.length)
|
||||||
|
{
|
||||||
|
colors.push(parseInt(pieces[index]));
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updatePart(type, setId, colors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
741
src/app/avatar/AvatarImage.ts
Normal file
741
src/app/avatar/AvatarImage.ts
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
import { Canvas, createCanvas } from 'canvas';
|
||||||
|
import { IGraphicAsset } from '../../core';
|
||||||
|
import { ActiveActionData, IActionDefinition, IActiveActionData } from './actions';
|
||||||
|
import { AssetAliasCollection } from './alias';
|
||||||
|
import { IAnimationLayerData, IAvatarDataContainer, ISpriteDataContainer } from './animation';
|
||||||
|
import { AvatarFigureContainer } from './AvatarFigureContainer';
|
||||||
|
import { AvatarStructure } from './AvatarStructure';
|
||||||
|
import { AvatarImageCache } from './cache';
|
||||||
|
import { EffectAssetDownloadManager } from './EffectAssetDownloadManager';
|
||||||
|
import { AvatarAction, AvatarDirectionAngle, AvatarScaleType, AvatarSetType } from './enum';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
import { IAvatarImage } from './IAvatarImage';
|
||||||
|
import { IPartColor } from './structure';
|
||||||
|
|
||||||
|
export class AvatarImage implements IAvatarImage
|
||||||
|
{
|
||||||
|
private static CHANNELS_EQUAL: string = 'CHANNELS_EQUAL';
|
||||||
|
private static CHANNELS_UNIQUE: string = 'CHANNELS_UNIQUE';
|
||||||
|
private static CHANNELS_RED: string = 'CHANNELS_RED';
|
||||||
|
private static CHANNELS_GREEN: string = 'CHANNELS_GREEN';
|
||||||
|
private static CHANNELS_BLUE: string = 'CHANNELS_BLUE';
|
||||||
|
private static CHANNELS_DESATURATED: string = 'CHANNELS_DESATURATED';
|
||||||
|
private static DEFAULT_ACTION: string = 'Default';
|
||||||
|
private static DEFAULT_DIRECTION: number = 2;
|
||||||
|
private static DEFAULT_AVATAR_SET: string = AvatarSetType.FULL;
|
||||||
|
|
||||||
|
protected _structure: AvatarStructure;
|
||||||
|
protected _scale: string;
|
||||||
|
protected _mainDirection: number;
|
||||||
|
protected _headDirection: number;
|
||||||
|
protected _mainAction: IActiveActionData;
|
||||||
|
protected _disposed: boolean;
|
||||||
|
protected _canvasOffsets: number[];
|
||||||
|
protected _assets: AssetAliasCollection;
|
||||||
|
protected _cache: AvatarImageCache;
|
||||||
|
protected _figure: AvatarFigureContainer;
|
||||||
|
protected _avatarSpriteData: IAvatarDataContainer;
|
||||||
|
protected _actions: ActiveActionData[];
|
||||||
|
|
||||||
|
private _defaultAction: IActiveActionData;
|
||||||
|
private _frameCounter: number = 0;
|
||||||
|
private _directionOffset: number = 0;
|
||||||
|
private _sprites: ISpriteDataContainer[];
|
||||||
|
private _isAnimating: boolean = false;
|
||||||
|
private _animationHasResetOnToggle: boolean = false;
|
||||||
|
private _actionsSorted: boolean = false;
|
||||||
|
private _sortedActions: IActiveActionData[];
|
||||||
|
private _lastActionsString: string;
|
||||||
|
private _currentActionsString: string;
|
||||||
|
private _effectIdInUse: number = -1;
|
||||||
|
private _animationFrameCount: number;
|
||||||
|
private _cachedBodyParts: string[];
|
||||||
|
private _cachedBodyPartsDirection: number = -1;
|
||||||
|
private _cachedBodyPartsGeometryType: string = null;
|
||||||
|
private _cachedBodyPartsAvatarSet: string = null;
|
||||||
|
private _effectManager: EffectAssetDownloadManager;
|
||||||
|
|
||||||
|
constructor(k: AvatarStructure, _arg_2: AssetAliasCollection, _arg_3: AvatarFigureContainer, _arg_4: string, _arg_5: EffectAssetDownloadManager)
|
||||||
|
{
|
||||||
|
this._canvasOffsets = [];
|
||||||
|
this._actions = [];
|
||||||
|
this._cachedBodyParts = [];
|
||||||
|
this._disposed = false;
|
||||||
|
this._effectManager = _arg_5;
|
||||||
|
this._structure = k;
|
||||||
|
this._assets = _arg_2;
|
||||||
|
this._scale = _arg_4;
|
||||||
|
if(this._scale == null)
|
||||||
|
{
|
||||||
|
this._scale = AvatarScaleType.LARGE;
|
||||||
|
}
|
||||||
|
if(_arg_3 == null)
|
||||||
|
{
|
||||||
|
_arg_3 = new AvatarFigureContainer('hr-893-45.hd-180-2.ch-210-66.lg-270-82.sh-300-91.wa-2007-.ri-1-');
|
||||||
|
}
|
||||||
|
this._figure = _arg_3;
|
||||||
|
this._cache = new AvatarImageCache(this._structure, this, this._assets, this._scale);
|
||||||
|
this.setDirection(AvatarImage.DEFAULT_AVATAR_SET, AvatarImage.DEFAULT_DIRECTION);
|
||||||
|
this._actions = [];
|
||||||
|
this._defaultAction = new ActiveActionData(AvatarAction.POSTURE_STAND);
|
||||||
|
this._defaultAction.definition = this._structure.getActionDefinition(AvatarImage.DEFAULT_ACTION);
|
||||||
|
this.resetActions();
|
||||||
|
this._animationFrameCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async dispose(): Promise<void>
|
||||||
|
{
|
||||||
|
if(this._disposed) return;
|
||||||
|
|
||||||
|
this._structure = null;
|
||||||
|
this._assets = null;
|
||||||
|
this._mainAction = null;
|
||||||
|
this._figure = null;
|
||||||
|
this._avatarSpriteData = null;
|
||||||
|
this._actions = null;
|
||||||
|
|
||||||
|
if(this._cache)
|
||||||
|
{
|
||||||
|
this._cache.dispose();
|
||||||
|
this._cache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._canvasOffsets = null;
|
||||||
|
this._disposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get disposed(): boolean
|
||||||
|
{
|
||||||
|
return this._disposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigure(): IAvatarFigureContainer
|
||||||
|
{
|
||||||
|
return this._figure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getScale(): string
|
||||||
|
{
|
||||||
|
return this._scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartColor(k: string): IPartColor
|
||||||
|
{
|
||||||
|
return this._structure.getPartColor(this._figure, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDirection(k: string, _arg_2: number): void
|
||||||
|
{
|
||||||
|
_arg_2 = (_arg_2 + this._directionOffset);
|
||||||
|
|
||||||
|
if(_arg_2 < AvatarDirectionAngle.MIN_DIRECTION)
|
||||||
|
{
|
||||||
|
_arg_2 = (AvatarDirectionAngle.MAX_DIRECTION + (_arg_2 + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_arg_2 > AvatarDirectionAngle.MAX_DIRECTION)
|
||||||
|
{
|
||||||
|
_arg_2 = (_arg_2 - (AvatarDirectionAngle.MAX_DIRECTION + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._structure.isMainAvatarSet(k))
|
||||||
|
{
|
||||||
|
this._mainDirection = _arg_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((k === AvatarSetType.HEAD) || (k === AvatarSetType.FULL))
|
||||||
|
{
|
||||||
|
if((k === AvatarSetType.HEAD) && (this.isHeadTurnPreventedByAction()))
|
||||||
|
{
|
||||||
|
_arg_2 = this._mainDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._headDirection = _arg_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cache.setDirection(k, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDirectionAngle(k: string, _arg_2: number): void
|
||||||
|
{
|
||||||
|
this.setDirection(k, Math.floor(_arg_2 / 45));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSprites(): ISpriteDataContainer[]
|
||||||
|
{
|
||||||
|
return this._sprites;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCanvasOffsets(): number[]
|
||||||
|
{
|
||||||
|
return this._canvasOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLayerData(k: ISpriteDataContainer): IAnimationLayerData
|
||||||
|
{
|
||||||
|
return this._structure.getBodyPartData(k.animation.id, this._frameCounter, k.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateAnimationByFrames(k: number = 1): void
|
||||||
|
{
|
||||||
|
this._frameCounter += k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetAnimationFrameCounter(): void
|
||||||
|
{
|
||||||
|
this._frameCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFullImageCacheKey(): string
|
||||||
|
{
|
||||||
|
if(((this._sortedActions.length == 1) && (this._mainDirection == this._headDirection)))
|
||||||
|
{
|
||||||
|
return (this._mainDirection + this._currentActionsString) + (this._frameCounter % 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._sortedActions.length == 2)
|
||||||
|
{
|
||||||
|
for(const k of this._sortedActions)
|
||||||
|
{
|
||||||
|
if(((k.actionType == 'fx') && ((((k.actionParameter == '33') || (k.actionParameter == '34')) || (k.actionParameter == '35')) || (k.actionParameter == '36'))))
|
||||||
|
{
|
||||||
|
return (this._mainDirection + this._currentActionsString) + 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(((k.actionType == 'fx') && ((k.actionParameter == '38') || (k.actionParameter == '39'))))
|
||||||
|
{
|
||||||
|
return (((this._mainDirection + '_') + this._headDirection) + this._currentActionsString) + (this._frameCounter % 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((k.actionType === 'dance') && ((k.actionParameter === '1') || (k.actionParameter === '2') || (k.actionParameter === '3') || (k.actionParameter === '4')))
|
||||||
|
{
|
||||||
|
let frame = (this._frameCounter % 8);
|
||||||
|
|
||||||
|
if((k.actionParameter === '3')) frame = (this._frameCounter % 10);
|
||||||
|
|
||||||
|
if((k.actionParameter === '4')) frame = (this._frameCounter % 16);
|
||||||
|
|
||||||
|
return (((this._mainDirection + k.actionType) + k.actionParameter) + frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBodyParts(k: string, _arg_2: string, _arg_3: number): string[]
|
||||||
|
{
|
||||||
|
if((((!(_arg_3 == this._cachedBodyPartsDirection)) || (!(_arg_2 == this._cachedBodyPartsGeometryType))) || (!(k == this._cachedBodyPartsAvatarSet))))
|
||||||
|
{
|
||||||
|
this._cachedBodyPartsDirection = _arg_3;
|
||||||
|
this._cachedBodyPartsGeometryType = _arg_2;
|
||||||
|
this._cachedBodyPartsAvatarSet = k;
|
||||||
|
this._cachedBodyParts = this._structure.getBodyParts(k, _arg_2, _arg_3);
|
||||||
|
}
|
||||||
|
return this._cachedBodyParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAvatarPartsForCamera(k: string): void
|
||||||
|
{
|
||||||
|
let _local_4: string;
|
||||||
|
if(this._mainAction == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const _local_2 = this._structure.getCanvas(this._scale, this._mainAction.definition.geometryType);
|
||||||
|
if(_local_2 == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const _local_3 = this.getBodyParts(k, this._mainAction.definition.geometryType, this._mainDirection);
|
||||||
|
let _local_6 = (_local_3.length - 1);
|
||||||
|
while(_local_6 >= 0)
|
||||||
|
{
|
||||||
|
_local_4 = _local_3[_local_6];
|
||||||
|
const _local_5 = this._cache.getImageContainer(_local_4, this._frameCounter);
|
||||||
|
_local_6--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getImage(setType: string, hightlight: boolean, scale: number = 1): Promise<Canvas>
|
||||||
|
{
|
||||||
|
if(!this._mainAction) return null;
|
||||||
|
|
||||||
|
if(!this._actionsSorted) await this.endActionAppends();
|
||||||
|
|
||||||
|
const avatarCanvas = this._structure.getCanvas(this._scale, this._mainAction.definition.geometryType);
|
||||||
|
|
||||||
|
if(!avatarCanvas) return null;
|
||||||
|
|
||||||
|
const bodyParts = this.getBodyParts(setType, this._mainAction.definition.geometryType, this._mainDirection);
|
||||||
|
|
||||||
|
const canvas = createCanvas(avatarCanvas.width, avatarCanvas.height);
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
let partCount = (bodyParts.length - 1);
|
||||||
|
|
||||||
|
while(partCount >= 0)
|
||||||
|
{
|
||||||
|
const set = bodyParts[partCount];
|
||||||
|
const part = this._cache.getImageContainer(set, this._frameCounter);
|
||||||
|
|
||||||
|
if(part)
|
||||||
|
{
|
||||||
|
const partCacheContainer = part.image;
|
||||||
|
|
||||||
|
if(!partCacheContainer) return null;
|
||||||
|
|
||||||
|
const point = part.regPoint.clone();
|
||||||
|
|
||||||
|
if(point)
|
||||||
|
{
|
||||||
|
point.x += avatarCanvas.offset.x;
|
||||||
|
point.y += avatarCanvas.offset.y;
|
||||||
|
|
||||||
|
point.x += avatarCanvas.regPoint.x;
|
||||||
|
point.y += avatarCanvas.regPoint.y;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.scale(scale, 1);
|
||||||
|
ctx.drawImage(part.image, point.x, point.y, part.image.width, part.image.height);
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
partCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if(this._avatarSpriteData && this._avatarSpriteData.paletteIsGrayscale) this.convertToGrayscale(container);
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public applyPalette(texture: RenderTexture, reds: number[] = [], greens: number[] = [], blues: number[] = []): RenderTexture
|
||||||
|
// {
|
||||||
|
// const textureCanvas = Nitro.instance.renderer.extract.canvas(texture);
|
||||||
|
// const textureCtx = textureCanvas.getContext('2d');
|
||||||
|
// const textureImageData = textureCtx.getImageData(0, 0, textureCanvas.width, textureCanvas.height);
|
||||||
|
// const data = textureImageData.data;
|
||||||
|
|
||||||
|
// for(const i = 0; i < data.length; i += 4)
|
||||||
|
// {
|
||||||
|
// let paletteColor = this._palette[data[ i + 1 ]];
|
||||||
|
|
||||||
|
// if(paletteColor === undefined) paletteColor = [ 0, 0, 0 ];
|
||||||
|
|
||||||
|
// data[ i ] = paletteColor[0];
|
||||||
|
// data[ i + 1 ] = paletteColor[1];
|
||||||
|
// data[ i + 2 ] = paletteColor[2];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// textureCtx.putImageData(textureImageData, 0, 0);
|
||||||
|
|
||||||
|
// return Texture.from(textureCanvas);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public getAsset(k: string): IGraphicAsset
|
||||||
|
{
|
||||||
|
return this._assets.getAsset(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirection(): number
|
||||||
|
{
|
||||||
|
return this._mainDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public initActionAppends(): void
|
||||||
|
{
|
||||||
|
this._actions = [];
|
||||||
|
this._actionsSorted = false;
|
||||||
|
this._currentActionsString = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public async endActionAppends(): Promise<void>
|
||||||
|
{
|
||||||
|
let k:ActiveActionData;
|
||||||
|
|
||||||
|
if(!this.sortActions()) return;
|
||||||
|
|
||||||
|
for(const k of this._sortedActions)
|
||||||
|
{
|
||||||
|
if(k.actionType === AvatarAction.EFFECT)
|
||||||
|
{
|
||||||
|
if(!this._effectManager.isAvatarEffectReady(parseInt(k.actionParameter))) await this._effectManager.downloadAvatarEffect(parseInt(k.actionParameter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetActions();
|
||||||
|
this.setActionsToParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
public appendAction(k: string, ..._args: any[]): boolean
|
||||||
|
{
|
||||||
|
let _local_3 = '';
|
||||||
|
|
||||||
|
this._actionsSorted = false;
|
||||||
|
|
||||||
|
if(_args && (_args.length > 0)) _local_3 = _args[0];
|
||||||
|
|
||||||
|
if((_local_3 !== undefined) && (_local_3 !== null)) _local_3 = _local_3.toString();
|
||||||
|
|
||||||
|
switch(k)
|
||||||
|
{
|
||||||
|
case AvatarAction.POSTURE:
|
||||||
|
switch(_local_3)
|
||||||
|
{
|
||||||
|
case AvatarAction.POSTURE_LAY:
|
||||||
|
case AvatarAction.POSTURE_WALK:
|
||||||
|
case AvatarAction.POSTURE_STAND:
|
||||||
|
case AvatarAction.POSTURE_SWIM:
|
||||||
|
case AvatarAction.POSTURE_FLOAT:
|
||||||
|
case AvatarAction.POSTURE_SIT:
|
||||||
|
case AvatarAction.SNOWWAR_RUN:
|
||||||
|
case AvatarAction.SNOWWAR_DIE_FRONT:
|
||||||
|
case AvatarAction.SNOWWAR_DIE_BACK:
|
||||||
|
case AvatarAction.SNOWWAR_PICK:
|
||||||
|
case AvatarAction.SNOWWAR_THROW:
|
||||||
|
if((_local_3 === AvatarAction.POSTURE_LAY) || (_local_3 === AvatarAction.POSTURE_LAY) || (_local_3 === AvatarAction.POSTURE_LAY))
|
||||||
|
{
|
||||||
|
if(_local_3 === AvatarAction.POSTURE_LAY)
|
||||||
|
{
|
||||||
|
if(this._mainDirection == 0)
|
||||||
|
{
|
||||||
|
this.setDirection(AvatarSetType.FULL, 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.setDirection(AvatarSetType.FULL, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addActionData(_local_3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AvatarAction.GESTURE:
|
||||||
|
switch(_local_3)
|
||||||
|
{
|
||||||
|
case AvatarAction.GESTURE_AGGRAVATED:
|
||||||
|
case AvatarAction.GESTURE_SAD:
|
||||||
|
case AvatarAction.GESTURE_SMILE:
|
||||||
|
case AvatarAction.GESTURE_SURPRISED:
|
||||||
|
this.addActionData(_local_3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AvatarAction.EFFECT:
|
||||||
|
case AvatarAction.DANCE:
|
||||||
|
case AvatarAction.TALK:
|
||||||
|
case AvatarAction.EXPRESSION_WAVE:
|
||||||
|
case AvatarAction.SLEEP:
|
||||||
|
case AvatarAction.SIGN:
|
||||||
|
case AvatarAction.EXPRESSION_RESPECT:
|
||||||
|
case AvatarAction.EXPRESSION_BLOW_A_KISS:
|
||||||
|
case AvatarAction.EXPRESSION_LAUGH:
|
||||||
|
case AvatarAction.EXPRESSION_CRY:
|
||||||
|
case AvatarAction.EXPRESSION_IDLE:
|
||||||
|
case AvatarAction.EXPRESSION_SNOWBOARD_OLLIE:
|
||||||
|
case AvatarAction.EXPRESSION_SNOWBORD_360:
|
||||||
|
case AvatarAction.EXPRESSION_RIDE_JUMP:
|
||||||
|
this.addActionData(k, _local_3);
|
||||||
|
break;
|
||||||
|
case AvatarAction.CARRY_OBJECT:
|
||||||
|
case AvatarAction.USE_OBJECT: {
|
||||||
|
const _local_4 = this._structure.getActionDefinitionWithState(k);
|
||||||
|
if(_local_4) _local_3 = _local_4.getParameterValue(_local_3);
|
||||||
|
this.addActionData(k, _local_3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected addActionData(k: string, _arg_2: string=''): void
|
||||||
|
{
|
||||||
|
let _local_3:ActiveActionData;
|
||||||
|
if(!this._actions) this._actions = [];
|
||||||
|
|
||||||
|
let _local_4 = 0;
|
||||||
|
while(_local_4 < this._actions.length)
|
||||||
|
{
|
||||||
|
_local_3 = this._actions[_local_4];
|
||||||
|
if(((_local_3.actionType == k) && (_local_3.actionParameter == _arg_2)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_local_4++;
|
||||||
|
}
|
||||||
|
this._actions.push(new ActiveActionData(k, _arg_2, this._frameCounter));
|
||||||
|
}
|
||||||
|
|
||||||
|
public isAnimating(): boolean
|
||||||
|
{
|
||||||
|
return (this._isAnimating) || (this._animationFrameCount > 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetActions(): boolean
|
||||||
|
{
|
||||||
|
this._animationHasResetOnToggle = false;
|
||||||
|
this._isAnimating = false;
|
||||||
|
this._sprites = [];
|
||||||
|
this._avatarSpriteData = null;
|
||||||
|
this._directionOffset = 0;
|
||||||
|
this._structure.removeDynamicItems(this);
|
||||||
|
this._mainAction = this._defaultAction;
|
||||||
|
this._mainAction.definition = this._defaultAction.definition;
|
||||||
|
this.resetBodyPartCache(this._defaultAction);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isHeadTurnPreventedByAction(): boolean
|
||||||
|
{
|
||||||
|
let _local_2: IActionDefinition;
|
||||||
|
let _local_3: ActiveActionData;
|
||||||
|
let k: boolean;
|
||||||
|
if(this._sortedActions == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(const _local_3 of this._sortedActions)
|
||||||
|
{
|
||||||
|
_local_2 = this._structure.getActionDefinitionWithState(_local_3.actionType);
|
||||||
|
if(((!(_local_2 == null)) && (_local_2.getPreventHeadTurn(_local_3.actionParameter))))
|
||||||
|
{
|
||||||
|
k = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sortActions(): boolean
|
||||||
|
{
|
||||||
|
let _local_2: boolean;
|
||||||
|
let _local_3: boolean;
|
||||||
|
let _local_4:ActiveActionData;
|
||||||
|
let _local_5: number;
|
||||||
|
let k: boolean;
|
||||||
|
|
||||||
|
this._currentActionsString = '';
|
||||||
|
this._sortedActions = this._structure.sortActions(this._actions);
|
||||||
|
this._animationFrameCount = this._structure.maxFrames(this._sortedActions);
|
||||||
|
|
||||||
|
if(!this._sortedActions)
|
||||||
|
{
|
||||||
|
this._canvasOffsets = [ 0, 0, 0 ];
|
||||||
|
|
||||||
|
if(this._lastActionsString !== '')
|
||||||
|
{
|
||||||
|
k = true;
|
||||||
|
|
||||||
|
this._lastActionsString = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._canvasOffsets = this._structure.getCanvasOffsets(this._sortedActions, this._scale, this._mainDirection);
|
||||||
|
|
||||||
|
for(const _local_4 of this._sortedActions)
|
||||||
|
{
|
||||||
|
this._currentActionsString = (this._currentActionsString + (_local_4.actionType + _local_4.actionParameter));
|
||||||
|
|
||||||
|
if(_local_4.actionType === AvatarAction.EFFECT)
|
||||||
|
{
|
||||||
|
const _local_5 = parseInt(_local_4.actionParameter);
|
||||||
|
|
||||||
|
if(this._effectIdInUse !== _local_5) _local_2 = true;
|
||||||
|
|
||||||
|
this._effectIdInUse = _local_5;
|
||||||
|
|
||||||
|
_local_3 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_local_3)
|
||||||
|
{
|
||||||
|
if(this._effectIdInUse > -1) _local_2 = true;
|
||||||
|
|
||||||
|
this._effectIdInUse = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_2) this._cache.disposeInactiveActions(0);
|
||||||
|
|
||||||
|
if(this._lastActionsString != this._currentActionsString)
|
||||||
|
{
|
||||||
|
k = true;
|
||||||
|
|
||||||
|
this._lastActionsString = this._currentActionsString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._actionsSorted = true;
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
private setActionsToParts(): void
|
||||||
|
{
|
||||||
|
if(!this._sortedActions == null) return;
|
||||||
|
|
||||||
|
const _local_3: number = Date.now();
|
||||||
|
const _local_4: string[] = [];
|
||||||
|
|
||||||
|
for(const k of this._sortedActions) _local_4.push(k.actionType);
|
||||||
|
|
||||||
|
for(const k of this._sortedActions)
|
||||||
|
{
|
||||||
|
if((k && k.definition) && k.definition.isAnimation)
|
||||||
|
{
|
||||||
|
const _local_2 = this._structure.getAnimation(((k.definition.state + '.') + k.actionParameter));
|
||||||
|
|
||||||
|
if(_local_2 && _local_2.hasOverriddenActions())
|
||||||
|
{
|
||||||
|
const _local_5 = _local_2.overriddenActionNames();
|
||||||
|
|
||||||
|
if(_local_5)
|
||||||
|
{
|
||||||
|
for(const _local_6 of _local_5)
|
||||||
|
{
|
||||||
|
if(_local_4.indexOf(_local_6) >= 0) k.overridingAction = _local_2.overridingAction(_local_6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_2 && _local_2.resetOnToggle)
|
||||||
|
{
|
||||||
|
this._animationHasResetOnToggle = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const k of this._sortedActions)
|
||||||
|
{
|
||||||
|
if(!((!(k)) || (!(k.definition))))
|
||||||
|
{
|
||||||
|
if(k.definition.isAnimation && (k.actionParameter === '')) k.actionParameter = '1';
|
||||||
|
|
||||||
|
this.setActionToParts(k, _local_3);
|
||||||
|
|
||||||
|
if(k.definition.isAnimation)
|
||||||
|
{
|
||||||
|
this._isAnimating = k.definition.isAnimated(k.actionParameter);
|
||||||
|
|
||||||
|
const _local_2 = this._structure.getAnimation(((k.definition.state + '.') + k.actionParameter));
|
||||||
|
|
||||||
|
if(_local_2)
|
||||||
|
{
|
||||||
|
this._sprites = this._sprites.concat(_local_2.spriteData);
|
||||||
|
|
||||||
|
if(_local_2.hasDirectionData()) this._directionOffset = _local_2.directionData.offset;
|
||||||
|
|
||||||
|
if(_local_2.hasAvatarData()) this._avatarSpriteData = _local_2.avatarData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setActionToParts(k: IActiveActionData, _arg_2: number): void
|
||||||
|
{
|
||||||
|
if(((k == null) || (k.definition == null)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(k.definition.assetPartDefinition == '')
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(k.definition.isMain)
|
||||||
|
{
|
||||||
|
this._mainAction = k;
|
||||||
|
this._cache.setGeometryType(k.definition.geometryType);
|
||||||
|
}
|
||||||
|
this._cache.setAction(k, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private resetBodyPartCache(k: IActiveActionData): void
|
||||||
|
{
|
||||||
|
if(!k) return;
|
||||||
|
|
||||||
|
if(k.definition.assetPartDefinition === '') return;
|
||||||
|
|
||||||
|
if(k.definition.isMain)
|
||||||
|
{
|
||||||
|
this._mainAction = k;
|
||||||
|
this._cache.setGeometryType(k.definition.geometryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cache.resetBodyPartCache(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get avatarSpriteData(): IAvatarDataContainer
|
||||||
|
{
|
||||||
|
return this._avatarSpriteData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private convertToGrayscale(container: Canvas, channel: string = 'CHANNELS_EQUAL'): Canvas
|
||||||
|
// {
|
||||||
|
// let _local_3 = 0.33;
|
||||||
|
// let _local_4 = 0.33;
|
||||||
|
// let _local_5 = 0.33;
|
||||||
|
// const _local_6 = 1;
|
||||||
|
|
||||||
|
// switch(channel)
|
||||||
|
// {
|
||||||
|
// case AvatarImage.CHANNELS_UNIQUE:
|
||||||
|
// _local_3 = 0.3;
|
||||||
|
// _local_4 = 0.59;
|
||||||
|
// _local_5 = 0.11;
|
||||||
|
// break;
|
||||||
|
// case AvatarImage.CHANNELS_RED:
|
||||||
|
// _local_3 = 1;
|
||||||
|
// _local_4 = 0;
|
||||||
|
// _local_5 = 0;
|
||||||
|
// break;
|
||||||
|
// case AvatarImage.CHANNELS_GREEN:
|
||||||
|
// _local_3 = 0;
|
||||||
|
// _local_4 = 1;
|
||||||
|
// _local_5 = 0;
|
||||||
|
// break;
|
||||||
|
// case AvatarImage.CHANNELS_BLUE:
|
||||||
|
// _local_3 = 0;
|
||||||
|
// _local_4 = 0;
|
||||||
|
// _local_5 = 1;
|
||||||
|
// break;
|
||||||
|
// case AvatarImage.CHANNELS_DESATURATED:
|
||||||
|
// _local_3 = 0.3086;
|
||||||
|
// _local_4 = 0.6094;
|
||||||
|
// _local_5 = 0.082;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const colorFilter = new ColorMatrixFilter();
|
||||||
|
|
||||||
|
// colorFilter.matrix = [_local_3, _local_4, _local_5, 0, 0, _local_3, _local_4, _local_5, 0, 0, _local_3, _local_4, _local_5, 0, 0, 0, 0, 0, 1, 0];
|
||||||
|
|
||||||
|
// container.filters = [ colorFilter ];
|
||||||
|
|
||||||
|
// return container;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public isPlaceholder(): boolean
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public forceActionUpdate(): void
|
||||||
|
{
|
||||||
|
this._lastActionsString = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public get animationHasResetOnToggle(): boolean
|
||||||
|
{
|
||||||
|
return this._animationHasResetOnToggle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get mainAction(): string
|
||||||
|
{
|
||||||
|
return this._mainAction.actionType;
|
||||||
|
}
|
||||||
|
}
|
74
src/app/avatar/AvatarImageBodyPartContainer.ts
Normal file
74
src/app/avatar/AvatarImageBodyPartContainer.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { Canvas } from 'canvas';
|
||||||
|
import { Point } from '../../core';
|
||||||
|
|
||||||
|
export class AvatarImageBodyPartContainer
|
||||||
|
{
|
||||||
|
private _image: Canvas;
|
||||||
|
private _regPoint: Point;
|
||||||
|
private _offset: Point;
|
||||||
|
private _isCacheable: boolean;
|
||||||
|
|
||||||
|
constructor(image: Canvas, regPoint: Point, isCacheable: boolean)
|
||||||
|
{
|
||||||
|
this._image = image;
|
||||||
|
this._regPoint = regPoint;
|
||||||
|
this._offset = new Point(0, 0);
|
||||||
|
this._isCacheable = isCacheable;
|
||||||
|
|
||||||
|
this.cleanPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._image = null;
|
||||||
|
this._regPoint = null;
|
||||||
|
this._offset = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private cleanPoints(): void
|
||||||
|
{
|
||||||
|
// this._regPoint.x = this._regPoint.x;
|
||||||
|
// this._regPoint.y = this._regPoint.y;
|
||||||
|
// this._offset.x = this._offset.x;
|
||||||
|
// this._offset.y = this._offset.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setRegPoint(k: Point): void
|
||||||
|
{
|
||||||
|
this._regPoint = k;
|
||||||
|
|
||||||
|
this.cleanPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get image(): Canvas
|
||||||
|
{
|
||||||
|
return this._image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set image(k: Canvas)
|
||||||
|
{
|
||||||
|
this._image = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get regPoint(): Point
|
||||||
|
{
|
||||||
|
const clone = this._regPoint.clone();
|
||||||
|
|
||||||
|
clone.x += this._offset.x;
|
||||||
|
clone.y += this._offset.y;
|
||||||
|
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set offset(k: Point)
|
||||||
|
{
|
||||||
|
this._offset = k;
|
||||||
|
|
||||||
|
this.cleanPoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isCacheable(): boolean
|
||||||
|
{
|
||||||
|
return this._isCacheable;
|
||||||
|
}
|
||||||
|
}
|
134
src/app/avatar/AvatarImagePartContainer.ts
Normal file
134
src/app/avatar/AvatarImagePartContainer.ts
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { IActionDefinition } from './actions/IActionDefinition';
|
||||||
|
import { AvatarAnimationFrame } from './structure/animation/AvatarAnimationFrame';
|
||||||
|
import { IPartColor } from './structure/figure/IPartColor';
|
||||||
|
|
||||||
|
export class AvatarImagePartContainer
|
||||||
|
{
|
||||||
|
private _bodyPartId: string;
|
||||||
|
private _partType: string;
|
||||||
|
private _flippedPartType: string;
|
||||||
|
private _partId: string;
|
||||||
|
private _color: IPartColor;
|
||||||
|
private _frames: AvatarAnimationFrame[];
|
||||||
|
private _action: IActionDefinition;
|
||||||
|
private _isColorable: boolean;
|
||||||
|
private _isBlendable: boolean;
|
||||||
|
private _paletteMapId: number;
|
||||||
|
|
||||||
|
constructor(k: string, _arg_2: string, _arg_3: string, _arg_4: IPartColor, _arg_5: AvatarAnimationFrame[], _arg_6: IActionDefinition, _arg_7: boolean, _arg_8: number, _arg_9: string = '', _arg_10: boolean = false, _arg_11: number = 1)
|
||||||
|
{
|
||||||
|
this._bodyPartId = k;
|
||||||
|
this._partType = _arg_2;
|
||||||
|
this._partId = _arg_3;
|
||||||
|
this._color = _arg_4;
|
||||||
|
this._frames = _arg_5;
|
||||||
|
this._action = _arg_6;
|
||||||
|
this._isColorable = _arg_7;
|
||||||
|
this._paletteMapId = _arg_8;
|
||||||
|
this._flippedPartType = _arg_9;
|
||||||
|
this._isBlendable = _arg_10;
|
||||||
|
|
||||||
|
if(this._partType === 'ey') this._isColorable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFrameIndex(k: number): number
|
||||||
|
{
|
||||||
|
if(!this._frames || !this._frames.length) return 0;
|
||||||
|
|
||||||
|
const frameNumber = (k % this._frames.length);
|
||||||
|
|
||||||
|
if(this._frames[frameNumber] instanceof AvatarAnimationFrame)
|
||||||
|
{
|
||||||
|
return this._frames[frameNumber].number;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frameNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFrameDefinition(k: number): AvatarAnimationFrame
|
||||||
|
{
|
||||||
|
const frameNumber = (k % this._frames.length);
|
||||||
|
|
||||||
|
if(this._frames && (this._frames.length > frameNumber))
|
||||||
|
{
|
||||||
|
if(this._frames[frameNumber] instanceof AvatarAnimationFrame)
|
||||||
|
{
|
||||||
|
return this._frames[frameNumber];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCacheableKey(k: number): string
|
||||||
|
{
|
||||||
|
const frameNumber = (k % this._frames.length);
|
||||||
|
|
||||||
|
if(this._frames && (this._frames.length > frameNumber))
|
||||||
|
{
|
||||||
|
if(this._frames[frameNumber] instanceof AvatarAnimationFrame)
|
||||||
|
{
|
||||||
|
const frame = this._frames[frameNumber];
|
||||||
|
|
||||||
|
return (this.partId + ':' + frame.assetPartDefinition + ':' + frame.number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.partId + ':' + frameNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get bodyPartId(): string
|
||||||
|
{
|
||||||
|
return this._bodyPartId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get partType(): string
|
||||||
|
{
|
||||||
|
return this._partType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get partId(): string
|
||||||
|
{
|
||||||
|
return this._partId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get color(): IPartColor
|
||||||
|
{
|
||||||
|
return this._color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get action(): IActionDefinition
|
||||||
|
{
|
||||||
|
return this._action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isColorable(): boolean
|
||||||
|
{
|
||||||
|
return this._isColorable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set isColorable(k: boolean)
|
||||||
|
{
|
||||||
|
this._isColorable = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get paletteMapId(): number
|
||||||
|
{
|
||||||
|
return this._paletteMapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get flippedPartType(): string
|
||||||
|
{
|
||||||
|
return this._flippedPartType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isBlendable(): boolean
|
||||||
|
{
|
||||||
|
return this._isBlendable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string
|
||||||
|
{
|
||||||
|
return [ this._bodyPartId, this._partType, this._partId ].join(':');
|
||||||
|
}
|
||||||
|
}
|
310
src/app/avatar/AvatarRenderManager.ts
Normal file
310
src/app/avatar/AvatarRenderManager.ts
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { IAssetManager, IGraphicAsset, NitroManager } from '../../core';
|
||||||
|
import { Application } from '../Application';
|
||||||
|
import { AssetAliasCollection } from './alias';
|
||||||
|
import { AvatarAssetDownloadManager } from './AvatarAssetDownloadManager';
|
||||||
|
import { AvatarFigureContainer } from './AvatarFigureContainer';
|
||||||
|
import { AvatarImage } from './AvatarImage';
|
||||||
|
import { AvatarStructure } from './AvatarStructure';
|
||||||
|
import { HabboAvatarAnimations, HabboAvatarGeometry, HabboAvatarPartSets } from './data';
|
||||||
|
import { EffectAssetDownloadManager } from './EffectAssetDownloadManager';
|
||||||
|
import { AvatarSetType } from './enum';
|
||||||
|
import { FigureDataContainer } from './FigureDataContainer';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
import { IAvatarImage } from './IAvatarImage';
|
||||||
|
import { IAvatarRenderManager } from './IAvatarRenderManager';
|
||||||
|
import { IFigureData } from './interfaces';
|
||||||
|
import { IFigurePartSet, IStructureData } from './structure';
|
||||||
|
|
||||||
|
export class AvatarRenderManager extends NitroManager implements IAvatarRenderManager
|
||||||
|
{
|
||||||
|
private static DEFAULT_FIGURE: string = 'hd-99999-99999';
|
||||||
|
|
||||||
|
private _aliasCollection: AssetAliasCollection;
|
||||||
|
|
||||||
|
private _assets: IAssetManager;
|
||||||
|
private _structure: AvatarStructure;
|
||||||
|
private _avatarAssetDownloadManager: AvatarAssetDownloadManager;
|
||||||
|
private _effectAssetDownloadManager: EffectAssetDownloadManager;
|
||||||
|
private _placeHolderFigure: AvatarFigureContainer;
|
||||||
|
|
||||||
|
constructor(assets: IAssetManager)
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._assets = assets;
|
||||||
|
this._structure = null;
|
||||||
|
this._avatarAssetDownloadManager = null;
|
||||||
|
this._effectAssetDownloadManager = null;
|
||||||
|
this._placeHolderFigure = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onInit(): Promise<void>
|
||||||
|
{
|
||||||
|
this._structure = new AvatarStructure(this);
|
||||||
|
|
||||||
|
this._structure.initGeometry(HabboAvatarGeometry.geometry);
|
||||||
|
this._structure.initPartSets(HabboAvatarPartSets.partSets);
|
||||||
|
this._structure.initAnimation(HabboAvatarAnimations.animations);
|
||||||
|
await this.loadActions();
|
||||||
|
this.loadFigureData();
|
||||||
|
|
||||||
|
this._aliasCollection = new AssetAliasCollection(this, this._assets);
|
||||||
|
|
||||||
|
this._aliasCollection.init();
|
||||||
|
|
||||||
|
if(!this._avatarAssetDownloadManager)
|
||||||
|
{
|
||||||
|
this._avatarAssetDownloadManager = new AvatarAssetDownloadManager(this._assets, this._structure);
|
||||||
|
|
||||||
|
await this._avatarAssetDownloadManager.loadFigureMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this._effectAssetDownloadManager)
|
||||||
|
{
|
||||||
|
this._effectAssetDownloadManager = new EffectAssetDownloadManager(this._assets, this._structure);
|
||||||
|
|
||||||
|
await this._effectAssetDownloadManager.loadEffectMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadActions(): Promise<void>
|
||||||
|
{
|
||||||
|
this._structure.initActions({
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"id": "Default",
|
||||||
|
"state": "std",
|
||||||
|
"precedence": 1000,
|
||||||
|
"main": true,
|
||||||
|
"isDefault": true,
|
||||||
|
"geometryType": "vertical",
|
||||||
|
"activePartSet": "figure",
|
||||||
|
"assetPartDefinition": "std"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const url = Application.instance.getConfiguration<string>('avatar.actions.url');
|
||||||
|
|
||||||
|
const data = await fetch(url);
|
||||||
|
|
||||||
|
this._structure.updateActions(await data.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadFigureData(): Promise<void>
|
||||||
|
{
|
||||||
|
const defaultFigureData = Application.instance.getConfiguration<IFigureData>('avatar.default.figuredata');
|
||||||
|
|
||||||
|
if(this._structure) this._structure.initFigureData(defaultFigureData);
|
||||||
|
|
||||||
|
const url = Application.instance.getConfiguration<string>('avatar.figuredata.url');
|
||||||
|
|
||||||
|
const data = await fetch(url);
|
||||||
|
|
||||||
|
this._structure.figureData.appendJSON(await data.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
public createFigureContainer(figure: string): IAvatarFigureContainer
|
||||||
|
{
|
||||||
|
return new AvatarFigureContainer(figure);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isFigureContainerReady(container: IAvatarFigureContainer): boolean
|
||||||
|
{
|
||||||
|
if(!this._avatarAssetDownloadManager) return false;
|
||||||
|
|
||||||
|
return this._avatarAssetDownloadManager.isAvatarFigureContainerReady(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createAvatarImage(figure: string, size: string, gender: string): Promise<IAvatarImage>
|
||||||
|
{
|
||||||
|
if(!this._structure || !this._avatarAssetDownloadManager) return null;
|
||||||
|
|
||||||
|
const figureContainer = new AvatarFigureContainer(figure);
|
||||||
|
|
||||||
|
if(gender) this.validateAvatarFigure(figureContainer, gender);
|
||||||
|
|
||||||
|
if(!this._avatarAssetDownloadManager.isAvatarFigureContainerReady(figureContainer))
|
||||||
|
{
|
||||||
|
await this._avatarAssetDownloadManager.downloadAvatarFigure(figureContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this._placeHolderFigure) this._placeHolderFigure = new AvatarFigureContainer(AvatarRenderManager.DEFAULT_FIGURE);
|
||||||
|
|
||||||
|
return new AvatarImage(this._structure, this._aliasCollection, figureContainer, size, this._effectAssetDownloadManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async downloadAvatarFigure(container: IAvatarFigureContainer): Promise<void>
|
||||||
|
{
|
||||||
|
if(!this._avatarAssetDownloadManager) return;
|
||||||
|
|
||||||
|
await this._avatarAssetDownloadManager.downloadAvatarFigure(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateAvatarFigure(container: AvatarFigureContainer, gender: string): boolean
|
||||||
|
{
|
||||||
|
let isValid = false;
|
||||||
|
|
||||||
|
const typeIds = this._structure.getMandatorySetTypeIds(gender, 2);
|
||||||
|
|
||||||
|
if(typeIds)
|
||||||
|
{
|
||||||
|
const figureData = this._structure.figureData;
|
||||||
|
|
||||||
|
for(const id of typeIds)
|
||||||
|
{
|
||||||
|
if(!container.hasPartType(id))
|
||||||
|
{
|
||||||
|
const figurePartSet = this._structure.getDefaultPartSet(id, gender);
|
||||||
|
|
||||||
|
if(figurePartSet)
|
||||||
|
{
|
||||||
|
container.updatePart(id, figurePartSet.id, [0]);
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const setType = figureData.getSetType(id);
|
||||||
|
|
||||||
|
if(setType)
|
||||||
|
{
|
||||||
|
const figurePartSet = setType.getPartSet(container.getPartSetId(id));
|
||||||
|
|
||||||
|
if(!figurePartSet)
|
||||||
|
{
|
||||||
|
const partSet = this._structure.getDefaultPartSet(id, gender);
|
||||||
|
|
||||||
|
if(partSet)
|
||||||
|
{
|
||||||
|
container.updatePart(id, partSet.id, [0]);
|
||||||
|
|
||||||
|
isValid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !(isValid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigureClubLevel(container: IAvatarFigureContainer, gender: string, searchParts: string[]): number
|
||||||
|
{
|
||||||
|
if(!this._structure) return 0;
|
||||||
|
|
||||||
|
const figureData = this._structure.figureData;
|
||||||
|
const parts = Array.from(container.getPartTypeIds());
|
||||||
|
|
||||||
|
let clubLevel = 0;
|
||||||
|
|
||||||
|
for(const part of parts)
|
||||||
|
{
|
||||||
|
const set = figureData.getSetType(part);
|
||||||
|
const setId = container.getPartSetId(part);
|
||||||
|
const partSet = set.getPartSet(setId);
|
||||||
|
|
||||||
|
if(partSet)
|
||||||
|
{
|
||||||
|
clubLevel = Math.max(partSet.clubLevel, clubLevel);
|
||||||
|
|
||||||
|
const palette = figureData.getPalette(set.paletteID);
|
||||||
|
const colors = container.getPartColorIds(part);
|
||||||
|
|
||||||
|
for(const colorId of colors)
|
||||||
|
{
|
||||||
|
const color = palette.getColor(colorId);
|
||||||
|
|
||||||
|
clubLevel = Math.max(color.clubLevel, clubLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!searchParts) searchParts = this._structure.getBodyPartsUnordered(AvatarSetType.FULL);
|
||||||
|
|
||||||
|
for(const part of searchParts)
|
||||||
|
{
|
||||||
|
const set = figureData.getSetType(part);
|
||||||
|
|
||||||
|
if(parts.indexOf(part) === -1) clubLevel = Math.max(set.optionalFromClubLevel(gender), clubLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return clubLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValidFigureSetForGender(setId: number, gender: string): boolean
|
||||||
|
{
|
||||||
|
const structure = this.structureData;
|
||||||
|
const partSet = structure.getFigurePartSet(setId);
|
||||||
|
|
||||||
|
return !!(partSet && ((partSet.gender.toUpperCase() === 'U') || (partSet.gender.toUpperCase() === gender.toUpperCase())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigureStringWithFigureIds(k: string, _arg_2: string, _arg_3: number[]): string
|
||||||
|
{
|
||||||
|
const container = new FigureDataContainer();
|
||||||
|
|
||||||
|
container.loadAvatarData(k, _arg_2);
|
||||||
|
|
||||||
|
const partSets: IFigurePartSet[] = this.resolveFigureSets(_arg_3);
|
||||||
|
|
||||||
|
for(const partSet of partSets)
|
||||||
|
{
|
||||||
|
container.savePartData(partSet.type, partSet.id, container.getColourIds(partSet.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
return container.getFigureString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private resolveFigureSets(k: number[]): IFigurePartSet[]
|
||||||
|
{
|
||||||
|
const structure = this.structureData;
|
||||||
|
const partSets: IFigurePartSet[] = [];
|
||||||
|
|
||||||
|
for(const _local_4 of k)
|
||||||
|
{
|
||||||
|
const partSet = structure.getFigurePartSet(_local_4);
|
||||||
|
|
||||||
|
if(partSet) partSets.push(partSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMandatoryAvatarPartSetIds(k: string, _arg_2: number): string[]
|
||||||
|
{
|
||||||
|
if(!this._structure) return null;
|
||||||
|
|
||||||
|
return this._structure.getMandatorySetTypeIds(k, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAssetByName(name: string): IGraphicAsset
|
||||||
|
{
|
||||||
|
return this._aliasCollection.getAsset(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get assets(): IAssetManager
|
||||||
|
{
|
||||||
|
return this._assets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get structure(): AvatarStructure
|
||||||
|
{
|
||||||
|
return this._structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get structureData(): IStructureData
|
||||||
|
{
|
||||||
|
if(this._structure) return this._structure.figureData;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get downloadManager(): AvatarAssetDownloadManager
|
||||||
|
{
|
||||||
|
return this._avatarAssetDownloadManager;
|
||||||
|
}
|
||||||
|
}
|
630
src/app/avatar/AvatarStructure.ts
Normal file
630
src/app/avatar/AvatarStructure.ts
Normal file
@ -0,0 +1,630 @@
|
|||||||
|
import { AdvancedMap, IAssetAnimation, IAssetManager, Point } from '../../core';
|
||||||
|
import { ActionDefinition, AvatarActionManager, IActionDefinition, IActiveActionData } from './actions';
|
||||||
|
import { Animation, AnimationManager, AvatarAnimationLayerData } from './animation';
|
||||||
|
import { AvatarImagePartContainer } from './AvatarImagePartContainer';
|
||||||
|
import { AvatarRenderManager } from './AvatarRenderManager';
|
||||||
|
import { AvatarDirectionAngle } from './enum';
|
||||||
|
import { AvatarModelGeometry } from './geometry';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
import { IAvatarImage } from './IAvatarImage';
|
||||||
|
import { IAvatarRenderManager } from './IAvatarRenderManager';
|
||||||
|
import { IFigureData } from './interfaces';
|
||||||
|
import { AnimationAction, AvatarAnimationData, AvatarAnimationFrame, AvatarCanvas, FigureSetData, IFigurePartSet, IPartColor, IStructureData, PartSetsData } from './structure';
|
||||||
|
|
||||||
|
export class AvatarStructure
|
||||||
|
{
|
||||||
|
private _renderManager: AvatarRenderManager;
|
||||||
|
private _geometry: AvatarModelGeometry;
|
||||||
|
private _figureData: FigureSetData;
|
||||||
|
private _partSetsData: PartSetsData;
|
||||||
|
private _animationData: AvatarAnimationData;
|
||||||
|
private _animationManager: AnimationManager;
|
||||||
|
private _mandatorySetTypeIds: { [index: string]: { [index: number]: string[] } };
|
||||||
|
private _actionManager: AvatarActionManager;
|
||||||
|
private _defaultAction: IActionDefinition;
|
||||||
|
|
||||||
|
constructor(renderManager: AvatarRenderManager)
|
||||||
|
{
|
||||||
|
this._renderManager = renderManager;
|
||||||
|
this._geometry = null;
|
||||||
|
this._figureData = new FigureSetData();
|
||||||
|
this._partSetsData = new PartSetsData();
|
||||||
|
this._animationData = new AvatarAnimationData();
|
||||||
|
this._animationManager = new AnimationManager();
|
||||||
|
this._mandatorySetTypeIds = {};
|
||||||
|
this._actionManager = null;
|
||||||
|
this._defaultAction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._renderManager = null;
|
||||||
|
this._figureData = null;
|
||||||
|
this._partSetsData = null;
|
||||||
|
this._animationData = null;
|
||||||
|
this._mandatorySetTypeIds = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public initGeometry(k: any): void
|
||||||
|
{
|
||||||
|
if(!k) return;
|
||||||
|
|
||||||
|
this._geometry = new AvatarModelGeometry(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public initActions(actions: any): void
|
||||||
|
{
|
||||||
|
this._actionManager = new AvatarActionManager(actions);
|
||||||
|
this._defaultAction = this._actionManager.getDefaultAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateActions(data: any): void
|
||||||
|
{
|
||||||
|
this._actionManager.updateActions(data);
|
||||||
|
|
||||||
|
this._defaultAction = this._actionManager.getDefaultAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public initPartSets(k: any): boolean
|
||||||
|
{
|
||||||
|
if(!k) return false;
|
||||||
|
|
||||||
|
if(this._partSetsData.parse(k))
|
||||||
|
{
|
||||||
|
this._partSetsData.getPartDefinition('ri').appendToFigure = true;
|
||||||
|
this._partSetsData.getPartDefinition('li').appendToFigure = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public initAnimation(k: any): boolean
|
||||||
|
{
|
||||||
|
if(!k) return false;
|
||||||
|
|
||||||
|
return this._animationData.parse(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public initFigureData(k: IFigureData): boolean
|
||||||
|
{
|
||||||
|
if(!k) return false;
|
||||||
|
|
||||||
|
return this._figureData.parse(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public injectFigureData(data: IFigureData): void
|
||||||
|
{
|
||||||
|
this._figureData.injectJSON(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerAnimations(k: IAssetManager, _arg_2: string = 'fx', _arg_3: number = 200): void
|
||||||
|
{
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while(index < _arg_3)
|
||||||
|
{
|
||||||
|
const collection = k.getCollection((_arg_2 + index));
|
||||||
|
|
||||||
|
if(collection)
|
||||||
|
{
|
||||||
|
const animationData = collection.data;
|
||||||
|
|
||||||
|
this._animationManager.registerAnimation(this, animationData.animations);
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerAnimation(data: { [index: string]: IAssetAnimation }): void
|
||||||
|
{
|
||||||
|
this._animationManager.registerAnimation(this, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartColor(k: IAvatarFigureContainer, _arg_2: string, _arg_3: number = 0): IPartColor
|
||||||
|
{
|
||||||
|
const _local_4 = k.getPartColorIds(_arg_2);
|
||||||
|
|
||||||
|
if((!(_local_4)) || (_local_4.length < _arg_3)) return null;
|
||||||
|
|
||||||
|
const _local_5 = this._figureData.getSetType(_arg_2);
|
||||||
|
|
||||||
|
if(_local_5 == null) return null;
|
||||||
|
|
||||||
|
const _local_6 = this._figureData.getPalette(_local_5.paletteID);
|
||||||
|
|
||||||
|
if(!_local_6) return null;
|
||||||
|
|
||||||
|
return _local_6.getColor(_local_4[_arg_3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPartData(animation: string, frameCount: number, spriteId: string): AvatarAnimationLayerData
|
||||||
|
{
|
||||||
|
return this._animationManager.getLayerData(animation, frameCount, spriteId) as AvatarAnimationLayerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAnimation(k: string): Animation
|
||||||
|
{
|
||||||
|
return this._animationManager.getAnimation(k) as Animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActionDefinition(k: string): ActionDefinition
|
||||||
|
{
|
||||||
|
return this._actionManager.getActionDefinition(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActionDefinitionWithState(k: string): ActionDefinition
|
||||||
|
{
|
||||||
|
return this._actionManager.getActionDefinitionWithState(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isMainAvatarSet(k: string): boolean
|
||||||
|
{
|
||||||
|
return this._geometry.isMainAvatarSet(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sortActions(k: IActiveActionData[]): IActiveActionData[]
|
||||||
|
{
|
||||||
|
return this._actionManager.sortActions(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public maxFrames(k: IActiveActionData[]): number
|
||||||
|
{
|
||||||
|
let _local_2 = 0;
|
||||||
|
|
||||||
|
for(const _local_3 of k)
|
||||||
|
{
|
||||||
|
_local_2 = Math.max(_local_2, this._animationData.getFrameCount(_local_3.definition));
|
||||||
|
}
|
||||||
|
return _local_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMandatorySetTypeIds(k: string, _arg_2: number): string[]
|
||||||
|
{
|
||||||
|
if(!this._mandatorySetTypeIds[k])
|
||||||
|
{
|
||||||
|
this._mandatorySetTypeIds[k] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._mandatorySetTypeIds[k][_arg_2])
|
||||||
|
{
|
||||||
|
return this._mandatorySetTypeIds[k][_arg_2];
|
||||||
|
}
|
||||||
|
|
||||||
|
this._mandatorySetTypeIds[k][_arg_2] = this._figureData.getMandatorySetTypeIds(k, _arg_2);
|
||||||
|
|
||||||
|
return this._mandatorySetTypeIds[k][_arg_2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDefaultPartSet(k: string, _arg_2: string): IFigurePartSet
|
||||||
|
{
|
||||||
|
return this._figureData.getDefaultPartSet(k, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCanvasOffsets(k: IActiveActionData[], _arg_2: string, _arg_3: number): number[]
|
||||||
|
{
|
||||||
|
return this._actionManager.getCanvasOffsets(k, _arg_2, _arg_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCanvas(k: string, _arg_2: string): AvatarCanvas
|
||||||
|
{
|
||||||
|
return this._geometry.getCanvas(k, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeDynamicItems(k: IAvatarImage): void
|
||||||
|
{
|
||||||
|
this._geometry.removeDynamicItems(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActiveBodyPartIds(k: IActiveActionData, _arg_2: IAvatarImage): string[]
|
||||||
|
{
|
||||||
|
let _local_3: string[] = [];
|
||||||
|
|
||||||
|
const _local_4: string[] = [];
|
||||||
|
const _local_5 = k.definition.geometryType;
|
||||||
|
|
||||||
|
if(k.definition.isAnimation)
|
||||||
|
{
|
||||||
|
const _local_7 = ((k.definition.state + '.') + k.actionParameter);
|
||||||
|
const _local_8 = this._animationManager.getAnimation(_local_7);
|
||||||
|
|
||||||
|
if(_local_8)
|
||||||
|
{
|
||||||
|
_local_3 = _local_8.getAnimatedBodyPartIds(0, k.overridingAction);
|
||||||
|
|
||||||
|
if(_local_8.hasAddData())
|
||||||
|
{
|
||||||
|
const _local_11 = {
|
||||||
|
id: '',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
z: 0,
|
||||||
|
radius: 0.01,
|
||||||
|
nx: 0,
|
||||||
|
ny: 0,
|
||||||
|
nz: -1,
|
||||||
|
double: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
const _local_12 = {
|
||||||
|
setType: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
for(const _local_13 of _local_8.addData)
|
||||||
|
{
|
||||||
|
const _local_6 = this._geometry.getBodyPart(_local_5, _local_13.align);
|
||||||
|
|
||||||
|
if(_local_6)
|
||||||
|
{
|
||||||
|
_local_11.id = _local_13.id;
|
||||||
|
_local_6.addPart(_local_11, _arg_2);
|
||||||
|
|
||||||
|
_local_12.setType = _local_13.id;
|
||||||
|
|
||||||
|
const _local_10 = this._partSetsData.addPartDefinition(_local_12);
|
||||||
|
_local_10.appendToFigure = true;
|
||||||
|
|
||||||
|
if(_local_13.base === '') _local_10.staticId = 1;
|
||||||
|
|
||||||
|
if(_local_4.indexOf(_local_6.id) === -1) _local_4.push(_local_6.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const _local_9 of _local_3)
|
||||||
|
{
|
||||||
|
const _local_6 = this._geometry.getBodyPart(_local_5, _local_9);
|
||||||
|
|
||||||
|
if(_local_6 && (_local_4.indexOf(_local_6.id) === -1)) _local_4.push(_local_6.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_3 = this._partSetsData.getActiveParts(k.definition);
|
||||||
|
|
||||||
|
for(const _local_14 of _local_3)
|
||||||
|
{
|
||||||
|
const _local_6 = this._geometry.getBodyPartOfItem(_local_5, _local_14, _arg_2);
|
||||||
|
|
||||||
|
if(_local_6 && (_local_4.indexOf(_local_6.id) === -1)) _local_4.push(_local_6.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _local_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPartsUnordered(k: string): string[]
|
||||||
|
{
|
||||||
|
return this._geometry.getBodyPartIdsInAvatarSet(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyParts(k: string, _arg_2: string, _arg_3: number): string[]
|
||||||
|
{
|
||||||
|
const _local_4 = AvatarDirectionAngle.DIRECTION_TO_ANGLE[_arg_3];
|
||||||
|
|
||||||
|
return this._geometry.getBodyPartsAtAngle(k, _local_4, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFrameBodyPartOffset(k:IActiveActionData, _arg_2: number, _arg_3: number, _arg_4: string): Point
|
||||||
|
{
|
||||||
|
const _local_5 = this._animationData.getAction(k.definition);
|
||||||
|
|
||||||
|
if(_local_5) return _local_5.getFrameBodyPartOffset(_arg_2, _arg_3, _arg_4);
|
||||||
|
|
||||||
|
return AnimationAction.DEFAULT_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParts(k: string, _arg_2:IAvatarFigureContainer, _arg_3:IActiveActionData, _arg_4: string, _arg_5: number, removes: string[], _arg_7: IAvatarImage, _arg_8: AdvancedMap<string, string> = null): AvatarImagePartContainer[]
|
||||||
|
{
|
||||||
|
const _local_10: Animation = null;
|
||||||
|
let _local_34: IActionDefinition = null;
|
||||||
|
|
||||||
|
let _local_20: AvatarAnimationFrame[] = [];
|
||||||
|
let _local_36:IPartColor = null;
|
||||||
|
|
||||||
|
if(!_arg_3 == null) return [];
|
||||||
|
|
||||||
|
const _local_9 = this._partSetsData.getActiveParts(_arg_3.definition);
|
||||||
|
const _local_11: AvatarImagePartContainer[] = [];
|
||||||
|
let _local_14: any[] = [ 0 ];
|
||||||
|
const _local_15 = this._animationData.getAction(_arg_3.definition);
|
||||||
|
|
||||||
|
if(_arg_3.definition.isAnimation)
|
||||||
|
{
|
||||||
|
const _local_24 = ((_arg_3.definition.state + '.') + _arg_3.actionParameter);
|
||||||
|
const _local_10 = this._animationManager.getAnimation(_local_24);
|
||||||
|
|
||||||
|
if(_local_10)
|
||||||
|
{
|
||||||
|
_local_14 = this.getPopulatedArray(_local_10.frameCount(_arg_3.overridingAction));
|
||||||
|
|
||||||
|
for(const _local_25 of _local_10.getAnimatedBodyPartIds(0, _arg_3.overridingAction))
|
||||||
|
{
|
||||||
|
if(_local_25 === k)
|
||||||
|
{
|
||||||
|
const _local_26 = this._geometry.getBodyPart(_arg_4, _local_25);
|
||||||
|
|
||||||
|
if(_local_26)
|
||||||
|
{
|
||||||
|
for(const _local_27 of _local_26.getDynamicParts(_arg_7))
|
||||||
|
{
|
||||||
|
_local_9.push(_local_27.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _local_16 = this._geometry.getParts(_arg_4, k, _arg_5, _local_9, _arg_7);
|
||||||
|
const _local_21 = _arg_2.getPartTypeIds();
|
||||||
|
|
||||||
|
for(const _local_17 of _local_21)
|
||||||
|
{
|
||||||
|
if(_arg_8)
|
||||||
|
{
|
||||||
|
if(_arg_8.getValue(_local_17)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _local_28 = _arg_2.getPartSetId(_local_17);
|
||||||
|
const _local_29 = _arg_2.getPartColorIds(_local_17);
|
||||||
|
const _local_30 = this._figureData.getSetType(_local_17);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(_local_30)
|
||||||
|
{
|
||||||
|
const _local_31 = this._figureData.getPalette(_local_30.paletteID);
|
||||||
|
|
||||||
|
if(_local_31)
|
||||||
|
{
|
||||||
|
const _local_32 = _local_30.getPartSet(_local_28);
|
||||||
|
|
||||||
|
if(_local_32)
|
||||||
|
{
|
||||||
|
removes = removes.concat(_local_32.hiddenLayers);
|
||||||
|
|
||||||
|
for(const _local_33 of _local_32.parts)
|
||||||
|
{
|
||||||
|
if(_local_16.indexOf(_local_33.type) > -1)
|
||||||
|
{
|
||||||
|
if(_local_15)
|
||||||
|
{
|
||||||
|
const _local_19 = _local_15.getPart(_local_33.type);
|
||||||
|
|
||||||
|
if(_local_19)
|
||||||
|
{
|
||||||
|
_local_20 = _local_19.frames;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_20 = _local_14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_20 = _local_14;
|
||||||
|
}
|
||||||
|
|
||||||
|
_local_34 = _arg_3.definition;
|
||||||
|
|
||||||
|
if(_local_9.indexOf(_local_33.type) === -1) _local_34 = this._defaultAction;
|
||||||
|
|
||||||
|
const _local_13 = this._partSetsData.getPartDefinition(_local_33.type);
|
||||||
|
|
||||||
|
let _local_35 = (!_local_13) ? _local_33.type : _local_13.flippedSetType;
|
||||||
|
|
||||||
|
if(!_local_35 || (_local_35 === '')) _local_35 = _local_33.type;
|
||||||
|
|
||||||
|
if(_local_29 && (_local_29.length > (_local_33.colorLayerIndex - 1)))
|
||||||
|
{
|
||||||
|
_local_36 = _local_31.getColor(_local_29[(_local_33.colorLayerIndex - 1)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const _local_37 = (_local_33.colorLayerIndex > 0);
|
||||||
|
const _local_18 = new AvatarImagePartContainer(k, _local_33.type, _local_33.id.toString(), _local_36, _local_20, _local_34, _local_37, _local_33.paletteMap, _local_35);
|
||||||
|
|
||||||
|
_local_11.push(_local_18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const _local_22: AvatarImagePartContainer[] = [];
|
||||||
|
|
||||||
|
for(const _local_12 of _local_16)
|
||||||
|
{
|
||||||
|
let _local_39: IPartColor = null;
|
||||||
|
let _local_38 = false;
|
||||||
|
|
||||||
|
const _local_40 = ((_arg_8) && (_arg_8.getValue(_local_12)));
|
||||||
|
|
||||||
|
for(const _local_23 of _local_11)
|
||||||
|
{
|
||||||
|
if(_local_23.partType === _local_12)
|
||||||
|
{
|
||||||
|
if(_local_40)
|
||||||
|
{
|
||||||
|
_local_39 = _local_23.color;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_38 = true;
|
||||||
|
|
||||||
|
if(removes.indexOf(_local_12) === -1) _local_22.push(_local_23);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!_local_38)
|
||||||
|
{
|
||||||
|
if(_local_40)
|
||||||
|
{
|
||||||
|
const _local_41 = _arg_8.getValue(_local_12);
|
||||||
|
|
||||||
|
let _local_42 = 0;
|
||||||
|
let _local_43 = 0;
|
||||||
|
|
||||||
|
while(_local_43 < _local_41.length)
|
||||||
|
{
|
||||||
|
_local_42 = (_local_42 + _local_41.charCodeAt(_local_43));
|
||||||
|
_local_43++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_15)
|
||||||
|
{
|
||||||
|
const _local_19 = _local_15.getPart(_local_12);
|
||||||
|
|
||||||
|
if(_local_19)
|
||||||
|
{
|
||||||
|
_local_20 = _local_19.frames;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_20 = _local_14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_20 = _local_14;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _local_18 = new AvatarImagePartContainer(k, _local_12, _local_41, _local_39, _local_20, _arg_3.definition, (!(_local_39 == null)), -1, _local_12, false, 1);
|
||||||
|
|
||||||
|
_local_22.push(_local_18);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_local_9.indexOf(_local_12) > -1)
|
||||||
|
{
|
||||||
|
const _local_44 = this._geometry.getBodyPartOfItem(_arg_4, _local_12, _arg_7);
|
||||||
|
|
||||||
|
if(k !== _local_44.id)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const _local_13 = this._partSetsData.getPartDefinition(_local_12);
|
||||||
|
|
||||||
|
let _local_45 = false;
|
||||||
|
let _local_46 = 1;
|
||||||
|
|
||||||
|
if(_local_13.appendToFigure)
|
||||||
|
{
|
||||||
|
let _local_47 = '1';
|
||||||
|
|
||||||
|
if(_arg_3.actionParameter !== '')
|
||||||
|
{
|
||||||
|
_local_47 = _arg_3.actionParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_13.hasStaticId())
|
||||||
|
{
|
||||||
|
_local_47 = _local_13.staticId.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_10 != null)
|
||||||
|
{
|
||||||
|
const _local_48 = _local_10.getAddData(_local_12);
|
||||||
|
|
||||||
|
if(_local_48)
|
||||||
|
{
|
||||||
|
_local_45 = _local_48.isBlended;
|
||||||
|
_local_46 = _local_48.blend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_15)
|
||||||
|
{
|
||||||
|
const _local_19 = _local_15.getPart(_local_12);
|
||||||
|
|
||||||
|
if(_local_19)
|
||||||
|
{
|
||||||
|
_local_20 = _local_19.frames;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_20 = _local_14;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_20 = _local_14;
|
||||||
|
}
|
||||||
|
|
||||||
|
const _local_18 = new AvatarImagePartContainer(k, _local_12, _local_47, null, _local_20, _arg_3.definition, false, -1, _local_12, _local_45, _local_46);
|
||||||
|
|
||||||
|
_local_22.push(_local_18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _local_22;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPopulatedArray(k: number): number[]
|
||||||
|
{
|
||||||
|
const _local_2: number[] = [];
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while(index < k)
|
||||||
|
{
|
||||||
|
_local_2.push(index);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _local_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getItemIds(): string[]
|
||||||
|
{
|
||||||
|
if(this._actionManager)
|
||||||
|
{
|
||||||
|
const k = this._actionManager.getActionDefinition('CarryItem').params;
|
||||||
|
|
||||||
|
const _local_2 = [];
|
||||||
|
|
||||||
|
for(const _local_3 of k.getValues()) _local_2.push(_local_3);
|
||||||
|
|
||||||
|
return _local_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public get renderManager(): IAvatarRenderManager
|
||||||
|
{
|
||||||
|
return this._renderManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get figureData(): IStructureData
|
||||||
|
{
|
||||||
|
return this._figureData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get partData(): PartSetsData
|
||||||
|
{
|
||||||
|
return this._partSetsData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get animationManager(): AnimationManager
|
||||||
|
{
|
||||||
|
return this._animationManager;
|
||||||
|
}
|
||||||
|
}
|
78
src/app/avatar/EffectAssetDownloadLibrary.ts
Normal file
78
src/app/avatar/EffectAssetDownloadLibrary.ts
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { IAssetAnimation, IAssetManager } from '../../core';
|
||||||
|
|
||||||
|
export class EffectAssetDownloadLibrary
|
||||||
|
{
|
||||||
|
private static NOT_LOADED: number = 0;
|
||||||
|
private static LOADING: number = 1;
|
||||||
|
private static LOADED: number = 2;
|
||||||
|
|
||||||
|
private _state: number;
|
||||||
|
private _libraryName: string;
|
||||||
|
private _revision: string;
|
||||||
|
private _downloadUrl: string;
|
||||||
|
private _assets: IAssetManager;
|
||||||
|
private _animation: { [index: string]: IAssetAnimation };
|
||||||
|
|
||||||
|
constructor(id: string, revision: string, assets: IAssetManager, assetUrl: string)
|
||||||
|
{
|
||||||
|
this._state = EffectAssetDownloadLibrary.NOT_LOADED;
|
||||||
|
this._libraryName = id;
|
||||||
|
this._revision = revision;
|
||||||
|
this._downloadUrl = assetUrl;
|
||||||
|
this._assets = assets;
|
||||||
|
this._animation = null;
|
||||||
|
|
||||||
|
this._downloadUrl = this._downloadUrl.replace(/%libname%/gi, this._libraryName);
|
||||||
|
this._downloadUrl = this._downloadUrl.replace(/%revision%/gi, this._revision);
|
||||||
|
|
||||||
|
this.checkIfAssetLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
private checkIfAssetLoaded(): boolean
|
||||||
|
{
|
||||||
|
if(this._state === EffectAssetDownloadLibrary.LOADED) return true;
|
||||||
|
|
||||||
|
const asset = this._assets.getCollection(this._libraryName);
|
||||||
|
|
||||||
|
if(asset)
|
||||||
|
{
|
||||||
|
this._state = EffectAssetDownloadLibrary.LOADED;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async downloadAsset(): Promise<void>
|
||||||
|
{
|
||||||
|
if(!this._assets || (this._state === EffectAssetDownloadLibrary.LOADING)) return;
|
||||||
|
|
||||||
|
if(this.checkIfAssetLoaded()) return;
|
||||||
|
|
||||||
|
this._state = EffectAssetDownloadLibrary.LOADING;
|
||||||
|
|
||||||
|
await this._assets.downloadAsset(this._downloadUrl);
|
||||||
|
|
||||||
|
const collection = this._assets.getCollection(this._libraryName);
|
||||||
|
|
||||||
|
if(collection) this._animation = collection.data.animations;
|
||||||
|
|
||||||
|
this._state = EffectAssetDownloadLibrary.LOADED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get libraryName(): string
|
||||||
|
{
|
||||||
|
return this._libraryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get animation(): { [index: string]: IAssetAnimation }
|
||||||
|
{
|
||||||
|
return this._animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isLoaded(): boolean
|
||||||
|
{
|
||||||
|
return (this._state === EffectAssetDownloadLibrary.LOADED);
|
||||||
|
}
|
||||||
|
}
|
123
src/app/avatar/EffectAssetDownloadManager.ts
Normal file
123
src/app/avatar/EffectAssetDownloadManager.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import fetch from 'node-fetch';
|
||||||
|
import { AdvancedMap, IAssetManager } from '../../core';
|
||||||
|
import { Application } from '../Application';
|
||||||
|
import { AvatarStructure } from './AvatarStructure';
|
||||||
|
import { EffectAssetDownloadLibrary } from './EffectAssetDownloadLibrary';
|
||||||
|
|
||||||
|
export class EffectAssetDownloadManager
|
||||||
|
{
|
||||||
|
private _assets: IAssetManager;
|
||||||
|
private _structure: AvatarStructure;
|
||||||
|
|
||||||
|
private _missingMandatoryLibs: string[];
|
||||||
|
private _effectMap: AdvancedMap<string, EffectAssetDownloadLibrary[]>;
|
||||||
|
private _libraryNames: string[];
|
||||||
|
|
||||||
|
constructor(assets: IAssetManager, structure: AvatarStructure)
|
||||||
|
{
|
||||||
|
this._assets = assets;
|
||||||
|
this._structure = structure;
|
||||||
|
|
||||||
|
this._missingMandatoryLibs = Application.instance.getConfiguration<string[]>('avatar.mandatory.effect.libraries');
|
||||||
|
this._effectMap = new AdvancedMap();
|
||||||
|
this._libraryNames = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async loadEffectMap(): Promise<void>
|
||||||
|
{
|
||||||
|
const url = Application.instance.getConfiguration<string>('avatar.effectmap.url');
|
||||||
|
|
||||||
|
const data = await fetch(url);
|
||||||
|
const json = await data.json();
|
||||||
|
|
||||||
|
this.processEffectMap(json.effects);
|
||||||
|
|
||||||
|
await this.processMissingLibraries();
|
||||||
|
}
|
||||||
|
|
||||||
|
private processEffectMap(data: any): void
|
||||||
|
{
|
||||||
|
if(!data) return;
|
||||||
|
|
||||||
|
const avatarEffectAssetUrl = Application.instance.getConfiguration<string>('avatar.asset.effect.url');
|
||||||
|
|
||||||
|
for(const effect of data)
|
||||||
|
{
|
||||||
|
if(!effect) continue;
|
||||||
|
|
||||||
|
const id = (effect.id as string);
|
||||||
|
const lib = (effect.lib as string);
|
||||||
|
const revision = (effect.revision || '');
|
||||||
|
|
||||||
|
if(this._libraryNames.indexOf(lib) >= 0) continue;
|
||||||
|
|
||||||
|
this._libraryNames.push(lib);
|
||||||
|
|
||||||
|
const downloadLibrary = new EffectAssetDownloadLibrary(lib, revision, this._assets, avatarEffectAssetUrl);
|
||||||
|
|
||||||
|
let existing = this._effectMap.getValue(id);
|
||||||
|
|
||||||
|
if(!existing) existing = [];
|
||||||
|
|
||||||
|
existing.push(downloadLibrary);
|
||||||
|
|
||||||
|
this._effectMap.add(id, existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async downloadAvatarEffect(id: number): Promise<void>
|
||||||
|
{
|
||||||
|
const pendingLibraries = this.getAvatarEffectPendingLibraries(id);
|
||||||
|
|
||||||
|
for(const library of pendingLibraries) (library && await this.downloadLibrary(library));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async processMissingLibraries(): Promise<void>
|
||||||
|
{
|
||||||
|
const missingLibraries = this._missingMandatoryLibs.slice();
|
||||||
|
|
||||||
|
for(const library of missingLibraries)
|
||||||
|
{
|
||||||
|
if(!library) continue;
|
||||||
|
|
||||||
|
const libraries = this._effectMap.getValue(library);
|
||||||
|
|
||||||
|
if(libraries) for(const library of libraries) (library && await this.downloadLibrary(library));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public isAvatarEffectReady(effect: number): boolean
|
||||||
|
{
|
||||||
|
const pendingLibraries = this.getAvatarEffectPendingLibraries(effect);
|
||||||
|
|
||||||
|
return !pendingLibraries.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getAvatarEffectPendingLibraries(id: number): EffectAssetDownloadLibrary[]
|
||||||
|
{
|
||||||
|
const pendingLibraries: EffectAssetDownloadLibrary[] = [];
|
||||||
|
|
||||||
|
if(!this._structure) return pendingLibraries;
|
||||||
|
|
||||||
|
const libraries = this._effectMap.getValue(id.toString());
|
||||||
|
|
||||||
|
if(libraries)
|
||||||
|
{
|
||||||
|
for(const library of libraries)
|
||||||
|
{
|
||||||
|
if(!library || library.isLoaded) continue;
|
||||||
|
|
||||||
|
if(pendingLibraries.indexOf(library) === -1) pendingLibraries.push(library);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pendingLibraries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async downloadLibrary(library: EffectAssetDownloadLibrary): Promise<void>
|
||||||
|
{
|
||||||
|
if(!library || library.isLoaded) return;
|
||||||
|
|
||||||
|
await library.downloadAsset();
|
||||||
|
}
|
||||||
|
}
|
244
src/app/avatar/FigureDataContainer.ts
Normal file
244
src/app/avatar/FigureDataContainer.ts
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
import { AdvancedMap } from '../../core';
|
||||||
|
|
||||||
|
export class FigureDataContainer
|
||||||
|
{
|
||||||
|
private static MALE: string = 'M';
|
||||||
|
private static FEMALE: string = 'F';
|
||||||
|
private static UNISEX: string = 'U';
|
||||||
|
private static SCALE: string = 'h';
|
||||||
|
private static STD: string = 'std';
|
||||||
|
private static DEFAULT_FRAME: string = '0';
|
||||||
|
private static HD: string = 'hd';
|
||||||
|
private static HAIR: string = 'hr';
|
||||||
|
private static HAT: string = 'ha';
|
||||||
|
private static HEAD_ACCESSORIES: string = 'he';
|
||||||
|
private static EYE_ACCESSORIES: string = 'ea';
|
||||||
|
private static FACE_ACCESSORIES: string = 'fa';
|
||||||
|
private static JACKET: string = 'cc';
|
||||||
|
private static SHIRT: string = 'ch';
|
||||||
|
private static CHEST_ACCESSORIES: string = 'ca';
|
||||||
|
private static CHEST_PRINTS: string = 'cp';
|
||||||
|
private static TROUSERS: string = 'lg';
|
||||||
|
private static SHOES: string = 'sh';
|
||||||
|
private static TROUSER_ACCESSORIES: string = 'wa';
|
||||||
|
private static BLOCKED_FX_TYPES: number[] = [28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 68];
|
||||||
|
|
||||||
|
private _data: AdvancedMap<string, number>;
|
||||||
|
private _colors: AdvancedMap<string, number[]>;
|
||||||
|
private _gender: string = 'M';
|
||||||
|
private _isDisposed: boolean;
|
||||||
|
private _avatarEffectType: number = -1;
|
||||||
|
|
||||||
|
public loadAvatarData(k: string, _arg_2: string): void
|
||||||
|
{
|
||||||
|
this._data = new AdvancedMap();
|
||||||
|
this._colors = new AdvancedMap();
|
||||||
|
this._gender = _arg_2;
|
||||||
|
|
||||||
|
this.parseFigureString(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._data = null;
|
||||||
|
this._colors = null;
|
||||||
|
this._isDisposed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get disposed(): boolean
|
||||||
|
{
|
||||||
|
return this._isDisposed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFigureString(k: string): void
|
||||||
|
{
|
||||||
|
if(!k) return;
|
||||||
|
|
||||||
|
for(const set of k.split('.'))
|
||||||
|
{
|
||||||
|
const _local_3 = set.split('-');
|
||||||
|
|
||||||
|
if(_local_3.length > 0)
|
||||||
|
{
|
||||||
|
const part = _local_3[0];
|
||||||
|
const setId = parseInt(_local_3[1]);
|
||||||
|
const colors: number[] = [];
|
||||||
|
|
||||||
|
let i = 2;
|
||||||
|
|
||||||
|
while(i < _local_3.length)
|
||||||
|
{
|
||||||
|
colors.push(parseInt(_local_3[i]));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!colors.length) colors.push(0);
|
||||||
|
|
||||||
|
this.savePartSetId(part, setId, false);
|
||||||
|
this.savePartSetColourId(part, colors, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasSetType(k: string): boolean
|
||||||
|
{
|
||||||
|
return !!this._data.getValue(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartSetId(k: string): number
|
||||||
|
{
|
||||||
|
if(this.hasSetType(k)) return this._data.getValue(k);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getColourIds(k: string): number[]
|
||||||
|
{
|
||||||
|
if(this._colors.getValue(k)) return this._colors.getValue(k);
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigureString(): string
|
||||||
|
{
|
||||||
|
let figure = '';
|
||||||
|
|
||||||
|
const sets: string[] = [];
|
||||||
|
|
||||||
|
for(const key of this._data.getKeys())
|
||||||
|
{
|
||||||
|
const value = this._data.getValue(key);
|
||||||
|
let set = ((key + '-') + value);
|
||||||
|
|
||||||
|
const colors = this._colors.getValue(key);
|
||||||
|
|
||||||
|
if(colors) for(const color of colors) set = (set + ('-' + color));
|
||||||
|
|
||||||
|
sets.push(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while(i < sets.length)
|
||||||
|
{
|
||||||
|
figure = (figure + sets[i]);
|
||||||
|
|
||||||
|
if(i < (sets.length - 1)) figure = (figure + '.');
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return figure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public savePartData(k: string, _arg_2: number, _arg_3: number[], _arg_4: boolean = false): void
|
||||||
|
{
|
||||||
|
this.savePartSetId(k, _arg_2, _arg_4);
|
||||||
|
this.savePartSetColourId(k, _arg_3, _arg_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
private savePartSetId(k: string, _arg_2: number, _arg_3: boolean = true): void
|
||||||
|
{
|
||||||
|
switch(k)
|
||||||
|
{
|
||||||
|
case FigureDataContainer.HD:
|
||||||
|
case FigureDataContainer.HAIR:
|
||||||
|
case FigureDataContainer.HAT:
|
||||||
|
case FigureDataContainer.HEAD_ACCESSORIES:
|
||||||
|
case FigureDataContainer.EYE_ACCESSORIES:
|
||||||
|
case FigureDataContainer.FACE_ACCESSORIES:
|
||||||
|
case FigureDataContainer.SHIRT:
|
||||||
|
case FigureDataContainer.JACKET:
|
||||||
|
case FigureDataContainer.CHEST_ACCESSORIES:
|
||||||
|
case FigureDataContainer.CHEST_PRINTS:
|
||||||
|
case FigureDataContainer.TROUSERS:
|
||||||
|
case FigureDataContainer.SHOES:
|
||||||
|
case FigureDataContainer.TROUSER_ACCESSORIES:
|
||||||
|
if(_arg_2 >= 0)
|
||||||
|
{
|
||||||
|
this._data.add(k, _arg_2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._data.remove(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public savePartSetColourId(k: string, _arg_2: number[], _arg_3: boolean = true): void
|
||||||
|
{
|
||||||
|
switch(k)
|
||||||
|
{
|
||||||
|
case FigureDataContainer.HD:
|
||||||
|
case FigureDataContainer.HAIR:
|
||||||
|
case FigureDataContainer.HAT:
|
||||||
|
case FigureDataContainer.HEAD_ACCESSORIES:
|
||||||
|
case FigureDataContainer.EYE_ACCESSORIES:
|
||||||
|
case FigureDataContainer.FACE_ACCESSORIES:
|
||||||
|
case FigureDataContainer.SHIRT:
|
||||||
|
case FigureDataContainer.JACKET:
|
||||||
|
case FigureDataContainer.CHEST_ACCESSORIES:
|
||||||
|
case FigureDataContainer.CHEST_PRINTS:
|
||||||
|
case FigureDataContainer.TROUSERS:
|
||||||
|
case FigureDataContainer.SHOES:
|
||||||
|
case FigureDataContainer.TROUSER_ACCESSORIES:
|
||||||
|
this._colors.add(k, _arg_2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigureStringWithFace(k: number): string
|
||||||
|
{
|
||||||
|
const partSets: string[] = [ FigureDataContainer.HD ];
|
||||||
|
|
||||||
|
let figure = '';
|
||||||
|
const sets: string[] = [];
|
||||||
|
|
||||||
|
for(const part of partSets)
|
||||||
|
{
|
||||||
|
const colors = this._colors.getValue(part);
|
||||||
|
|
||||||
|
if(colors)
|
||||||
|
{
|
||||||
|
let setId = this._data.getValue(part);
|
||||||
|
|
||||||
|
if(part === FigureDataContainer.HD) setId = k;
|
||||||
|
|
||||||
|
let set = ((part + '-') + setId);
|
||||||
|
|
||||||
|
if(setId >= 0)
|
||||||
|
{
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while(i < colors.length)
|
||||||
|
{
|
||||||
|
set = (set + ('-' + colors[i]));
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sets.push(set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while(i < sets.length)
|
||||||
|
{
|
||||||
|
figure = (figure + sets[i]);
|
||||||
|
|
||||||
|
if(i < (sets.length - 1)) figure = (figure + '.');
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return figure;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get gender(): string
|
||||||
|
{
|
||||||
|
return this._gender;
|
||||||
|
}
|
||||||
|
}
|
10
src/app/avatar/IAvatarFigureContainer.ts
Normal file
10
src/app/avatar/IAvatarFigureContainer.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export interface IAvatarFigureContainer
|
||||||
|
{
|
||||||
|
getPartTypeIds(): string[];
|
||||||
|
hasPartType(_arg_1: string): boolean;
|
||||||
|
getPartSetId(_arg_1: string): number;
|
||||||
|
getPartColorIds(_arg_1: string): number[];
|
||||||
|
updatePart(_arg_1: string, _arg_2: number, _arg_3: number[]): void;
|
||||||
|
removePart(_arg_1: string): void;
|
||||||
|
getFigureString(): string;
|
||||||
|
}
|
31
src/app/avatar/IAvatarImage.ts
Normal file
31
src/app/avatar/IAvatarImage.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { Canvas } from 'canvas';
|
||||||
|
import { IDisposable, IGraphicAsset } from '../../core';
|
||||||
|
import { IAnimationLayerData, IAvatarDataContainer, ISpriteDataContainer } from './animation';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
import { IPartColor } from './structure';
|
||||||
|
|
||||||
|
export interface IAvatarImage extends IDisposable
|
||||||
|
{
|
||||||
|
setDirection(_arg_1: string, _arg_2: number): void;
|
||||||
|
setDirectionAngle(_arg_1: string, _arg_2: number): void;
|
||||||
|
updateAnimationByFrames(_arg_1?: number): void;
|
||||||
|
getScale(): string;
|
||||||
|
getSprites(): ISpriteDataContainer[];
|
||||||
|
getLayerData(_arg_1: ISpriteDataContainer): IAnimationLayerData;
|
||||||
|
getImage(setType: string, hightlight: boolean, scale?: number, cache?: boolean): Promise<Canvas>;
|
||||||
|
getAsset(_arg_1: string): IGraphicAsset;
|
||||||
|
getDirection(): number;
|
||||||
|
getFigure(): IAvatarFigureContainer;
|
||||||
|
getPartColor(_arg_1: string): IPartColor;
|
||||||
|
isAnimating(): boolean;
|
||||||
|
getCanvasOffsets(): number[];
|
||||||
|
initActionAppends(): void;
|
||||||
|
endActionAppends(): void;
|
||||||
|
appendAction(_arg_1: string, ..._args: any[]): boolean;
|
||||||
|
avatarSpriteData: IAvatarDataContainer;
|
||||||
|
isPlaceholder(): boolean;
|
||||||
|
forceActionUpdate(): void;
|
||||||
|
animationHasResetOnToggle: boolean;
|
||||||
|
resetAnimationFrameCounter(): void;
|
||||||
|
mainAction: string;
|
||||||
|
}
|
23
src/app/avatar/IAvatarRenderManager.ts
Normal file
23
src/app/avatar/IAvatarRenderManager.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { IAssetManager, IGraphicAsset, INitroManager } from '../../core';
|
||||||
|
import { AvatarAssetDownloadManager } from './AvatarAssetDownloadManager';
|
||||||
|
import { AvatarStructure } from './AvatarStructure';
|
||||||
|
import { IAvatarFigureContainer } from './IAvatarFigureContainer';
|
||||||
|
import { IAvatarImage } from './IAvatarImage';
|
||||||
|
import { IStructureData } from './structure/IStructureData';
|
||||||
|
|
||||||
|
export interface IAvatarRenderManager extends INitroManager
|
||||||
|
{
|
||||||
|
createFigureContainer(figure: string): IAvatarFigureContainer;
|
||||||
|
isFigureContainerReady(container: IAvatarFigureContainer): boolean;
|
||||||
|
createAvatarImage(figure: string, size: string, gender: string): Promise<IAvatarImage>;
|
||||||
|
downloadAvatarFigure(container: IAvatarFigureContainer): void;
|
||||||
|
getFigureClubLevel(container: IAvatarFigureContainer, gender: string, searchParts: string[]): number;
|
||||||
|
isValidFigureSetForGender(setId: number, gender: string): boolean;
|
||||||
|
getFigureStringWithFigureIds(k: string, _arg_2: string, _arg_3: number[]): string;
|
||||||
|
getMandatoryAvatarPartSetIds(k: string, _arg_2: number): string[];
|
||||||
|
getAssetByName(name: string): IGraphicAsset;
|
||||||
|
assets: IAssetManager;
|
||||||
|
structure: AvatarStructure;
|
||||||
|
structureData: IStructureData;
|
||||||
|
downloadManager: AvatarAssetDownloadManager;
|
||||||
|
}
|
18
src/app/avatar/PlaceHolderAvatarImage.ts
Normal file
18
src/app/avatar/PlaceHolderAvatarImage.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { AssetAliasCollection } from './alias';
|
||||||
|
import { AvatarFigureContainer } from './AvatarFigureContainer';
|
||||||
|
import { AvatarImage } from './AvatarImage';
|
||||||
|
import { AvatarStructure } from './AvatarStructure';
|
||||||
|
import { EffectAssetDownloadManager } from './EffectAssetDownloadManager';
|
||||||
|
|
||||||
|
export class PlaceHolderAvatarImage extends AvatarImage
|
||||||
|
{
|
||||||
|
constructor(k: AvatarStructure, _arg_2: AssetAliasCollection, _arg_3: AvatarFigureContainer, _arg_4: string, _arg_5: EffectAssetDownloadManager)
|
||||||
|
{
|
||||||
|
super(k, _arg_2, _arg_3, _arg_4, _arg_5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isPlaceholder(): boolean
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
225
src/app/avatar/actions/ActionDefinition.ts
Normal file
225
src/app/avatar/actions/ActionDefinition.ts
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { ActionType } from './ActionType';
|
||||||
|
import { IActionDefinition } from './IActionDefinition';
|
||||||
|
|
||||||
|
export class ActionDefinition implements IActionDefinition
|
||||||
|
{
|
||||||
|
private _id: string;
|
||||||
|
private _state: string;
|
||||||
|
private _precedence: number;
|
||||||
|
private _activePartSet: string;
|
||||||
|
private _assetPartDefinition: string;
|
||||||
|
private _lay: string;
|
||||||
|
private _geometryType: string;
|
||||||
|
private _isMain: boolean;
|
||||||
|
private _isDefault: boolean;
|
||||||
|
private _isAnimation: boolean;
|
||||||
|
private _startFromFrameZero: boolean;
|
||||||
|
private _prevents: string[];
|
||||||
|
private _preventHeadTurn: boolean;
|
||||||
|
private _types: AdvancedMap<number, ActionType>;
|
||||||
|
private _params: AdvancedMap<string, string>;
|
||||||
|
private _defaultParameterValue: string;
|
||||||
|
private _canvasOffsets: AdvancedMap<string, AdvancedMap<number, number[]>>;
|
||||||
|
|
||||||
|
constructor(data: any)
|
||||||
|
{
|
||||||
|
this._id = data.id;
|
||||||
|
this._state = data.state;
|
||||||
|
this._precedence = data.precedence;
|
||||||
|
this._activePartSet = data.activePartSet;
|
||||||
|
this._assetPartDefinition = data.assetPartDefinition;
|
||||||
|
this._lay = data.lay;
|
||||||
|
this._geometryType = data.geometryType;
|
||||||
|
this._isMain = data.main || false;
|
||||||
|
this._isDefault = data.isDefault || false;
|
||||||
|
this._isAnimation = data.animation || false;
|
||||||
|
this._startFromFrameZero = data.startFromFrameZero || false;
|
||||||
|
this._prevents = data.prevents || [];
|
||||||
|
this._preventHeadTurn = data.preventHeadTurn || false;
|
||||||
|
this._types = new AdvancedMap();
|
||||||
|
this._params = new AdvancedMap();
|
||||||
|
this._defaultParameterValue = '';
|
||||||
|
this._canvasOffsets = null;
|
||||||
|
|
||||||
|
if(data.params && (data.params.length > 0))
|
||||||
|
{
|
||||||
|
for(const param of data.params)
|
||||||
|
{
|
||||||
|
if(!param) continue;
|
||||||
|
|
||||||
|
if(param.id === 'default') this._defaultParameterValue = param.value;
|
||||||
|
else this._params.add(param.id, param.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.types && (data.types.length > 0))
|
||||||
|
{
|
||||||
|
for(const type of data.types)
|
||||||
|
{
|
||||||
|
if(!type) continue;
|
||||||
|
|
||||||
|
const action = new ActionType(type);
|
||||||
|
|
||||||
|
this._types.add(action.id, action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setOffsets(k: string, _arg_2: number, _arg_3: number[]): void
|
||||||
|
{
|
||||||
|
if(!this._canvasOffsets) this._canvasOffsets = new AdvancedMap();
|
||||||
|
|
||||||
|
let existing = this._canvasOffsets.getValue(k);
|
||||||
|
|
||||||
|
if(!existing)
|
||||||
|
{
|
||||||
|
existing = new AdvancedMap();
|
||||||
|
|
||||||
|
this._canvasOffsets.add(k, existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.add(_arg_2, _arg_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOffsets(k: string, _arg_2: number): number[]
|
||||||
|
{
|
||||||
|
if(!this._canvasOffsets) return null;
|
||||||
|
|
||||||
|
const existing = this._canvasOffsets.getValue(k);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing.getValue(_arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getType(id: string): ActionType
|
||||||
|
{
|
||||||
|
if(!id) return null;
|
||||||
|
|
||||||
|
const existing = this._types.getValue(parseInt(id));
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParameterValue(id: string): string
|
||||||
|
{
|
||||||
|
if(!id) return '';
|
||||||
|
|
||||||
|
const existing = this._params.getValue(id);
|
||||||
|
|
||||||
|
if(!existing) return this._defaultParameterValue;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPrevents(type: string): string[]
|
||||||
|
{
|
||||||
|
return this._prevents.concat(this.getTypePrevents(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
private getTypePrevents(type: string): string[]
|
||||||
|
{
|
||||||
|
if(!type) return [];
|
||||||
|
|
||||||
|
const existing = this._types.getValue(parseInt(type));
|
||||||
|
|
||||||
|
if(!existing) return [];
|
||||||
|
|
||||||
|
return existing.prevents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPreventHeadTurn(k: string): boolean
|
||||||
|
{
|
||||||
|
if(!k) return this._preventHeadTurn;
|
||||||
|
|
||||||
|
const type = this.getType(k);
|
||||||
|
|
||||||
|
if(!type) return this._preventHeadTurn;
|
||||||
|
|
||||||
|
return type.preventHeadTurn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isAnimated(k: string): boolean
|
||||||
|
{
|
||||||
|
if(!k) return true;
|
||||||
|
|
||||||
|
const type = this.getType(k);
|
||||||
|
|
||||||
|
if(!type) return true;
|
||||||
|
|
||||||
|
return type.isAnimated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get state(): string
|
||||||
|
{
|
||||||
|
return this._state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get precedence(): number
|
||||||
|
{
|
||||||
|
return this._precedence;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get activePartSet(): string
|
||||||
|
{
|
||||||
|
return this._activePartSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get assetPartDefinition(): string
|
||||||
|
{
|
||||||
|
return this._assetPartDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get lay(): string
|
||||||
|
{
|
||||||
|
return this._lay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get geometryType(): string
|
||||||
|
{
|
||||||
|
return this._geometryType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isMain(): boolean
|
||||||
|
{
|
||||||
|
return this._isMain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isDefault(): boolean
|
||||||
|
{
|
||||||
|
return this._isDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isAnimation(): boolean
|
||||||
|
{
|
||||||
|
return this._isAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get startFromFrameZero(): boolean
|
||||||
|
{
|
||||||
|
return this._startFromFrameZero;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get prevents(): string[]
|
||||||
|
{
|
||||||
|
return this._prevents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get preventHeadTurn(): boolean
|
||||||
|
{
|
||||||
|
return this._preventHeadTurn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get params(): AdvancedMap<string, string>
|
||||||
|
{
|
||||||
|
return this._params;
|
||||||
|
}
|
||||||
|
}
|
44
src/app/avatar/actions/ActionType.ts
Normal file
44
src/app/avatar/actions/ActionType.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
export class ActionType
|
||||||
|
{
|
||||||
|
private _id: number;
|
||||||
|
private _value: number;
|
||||||
|
private _prevents: string[];
|
||||||
|
private _preventHeadTurn: boolean;
|
||||||
|
private _isAnimated: boolean;
|
||||||
|
|
||||||
|
constructor(data: any)
|
||||||
|
{
|
||||||
|
this._id = parseInt(data.id);
|
||||||
|
this._value = parseInt(data.id);
|
||||||
|
this._prevents = data.prevents || [];
|
||||||
|
this._preventHeadTurn = data.preventHeadTurn || false;
|
||||||
|
this._isAnimated = true;
|
||||||
|
|
||||||
|
if((data.animated !== undefined) && (data.animated === false)) this._isAnimated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get value(): number
|
||||||
|
{
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get prevents(): string[]
|
||||||
|
{
|
||||||
|
return this._prevents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get preventHeadTurn(): boolean
|
||||||
|
{
|
||||||
|
return this._preventHeadTurn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isAnimated(): boolean
|
||||||
|
{
|
||||||
|
return this._isAnimated;
|
||||||
|
}
|
||||||
|
}
|
74
src/app/avatar/actions/ActiveActionData.ts
Normal file
74
src/app/avatar/actions/ActiveActionData.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { IActionDefinition } from './IActionDefinition';
|
||||||
|
import { IActiveActionData } from './IActiveActionData';
|
||||||
|
|
||||||
|
export class ActiveActionData implements IActiveActionData
|
||||||
|
{
|
||||||
|
private _actionType: string;
|
||||||
|
private _actionParameter: string;
|
||||||
|
private _definition: IActionDefinition;
|
||||||
|
private _startFrame: number;
|
||||||
|
private _overridingAction: string;
|
||||||
|
|
||||||
|
constructor(action: string, parameter: string = '', startFrame: number = 0)
|
||||||
|
{
|
||||||
|
this._actionType = action || '';
|
||||||
|
this._actionParameter = parameter || '';
|
||||||
|
this._definition = null;
|
||||||
|
this._startFrame = startFrame || 0;
|
||||||
|
this._overridingAction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._actionType = null;
|
||||||
|
this._actionParameter = null;
|
||||||
|
this._definition = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
if(!this._definition) return '';
|
||||||
|
|
||||||
|
return this._definition.id + '_' + this._actionParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get actionType(): string
|
||||||
|
{
|
||||||
|
return this._actionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get actionParameter(): string
|
||||||
|
{
|
||||||
|
return this._actionParameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set actionParameter(parameter: string)
|
||||||
|
{
|
||||||
|
this._actionParameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get definition(): IActionDefinition
|
||||||
|
{
|
||||||
|
return this._definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set definition(definition: IActionDefinition)
|
||||||
|
{
|
||||||
|
this._definition = definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get startFrame(): number
|
||||||
|
{
|
||||||
|
return this._startFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get overridingAction(): string
|
||||||
|
{
|
||||||
|
return this._overridingAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set overridingAction(action: string)
|
||||||
|
{
|
||||||
|
this._overridingAction = action;
|
||||||
|
}
|
||||||
|
}
|
185
src/app/avatar/actions/AvatarActionManager.ts
Normal file
185
src/app/avatar/actions/AvatarActionManager.ts
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { ActionDefinition } from './ActionDefinition';
|
||||||
|
import { IActiveActionData } from './IActiveActionData';
|
||||||
|
|
||||||
|
export class AvatarActionManager
|
||||||
|
{
|
||||||
|
private _actions: AdvancedMap<string, ActionDefinition>;
|
||||||
|
private _defaultAction: ActionDefinition;
|
||||||
|
|
||||||
|
constructor(data: any)
|
||||||
|
{
|
||||||
|
this._actions = new AdvancedMap();
|
||||||
|
this._defaultAction = null;
|
||||||
|
|
||||||
|
this.updateActions(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateActions(data: any): void
|
||||||
|
{
|
||||||
|
if(!data) return;
|
||||||
|
|
||||||
|
for(const action of data.actions)
|
||||||
|
{
|
||||||
|
if(!action || !action.state) continue;
|
||||||
|
|
||||||
|
const definition = new ActionDefinition(action);
|
||||||
|
|
||||||
|
this._actions.add(definition.state, definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.actionOffsets) this.parseActionOffsets(data.actionOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseActionOffsets(offsets: any): void
|
||||||
|
{
|
||||||
|
if(!offsets || !offsets.length) return;
|
||||||
|
|
||||||
|
for(const offset of offsets)
|
||||||
|
{
|
||||||
|
const action = this._actions.getValue(offset.action);
|
||||||
|
|
||||||
|
if(!action) continue;
|
||||||
|
|
||||||
|
for(const canvasOffset of offset.offsets)
|
||||||
|
{
|
||||||
|
const size = (canvasOffset.size || '');
|
||||||
|
const direction = canvasOffset.direction;
|
||||||
|
|
||||||
|
if((size === '') || (direction === undefined)) continue;
|
||||||
|
|
||||||
|
const x = (canvasOffset.x || 0);
|
||||||
|
const y = (canvasOffset.y || 0);
|
||||||
|
const z = (canvasOffset.z || 0);
|
||||||
|
|
||||||
|
action.setOffsets(size, direction, [ x, y, z ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActionDefinition(id: string): ActionDefinition
|
||||||
|
{
|
||||||
|
if(!id) return null;
|
||||||
|
|
||||||
|
for(const action of this._actions.getValues())
|
||||||
|
{
|
||||||
|
if(!action || (action.id !== id)) continue;
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActionDefinitionWithState(state: string): ActionDefinition
|
||||||
|
{
|
||||||
|
const existing = this._actions.getValue(state);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDefaultAction(): ActionDefinition
|
||||||
|
{
|
||||||
|
if(this._defaultAction) return this._defaultAction;
|
||||||
|
|
||||||
|
for(const action of this._actions.getValues())
|
||||||
|
{
|
||||||
|
if(!action || !action.isDefault) continue;
|
||||||
|
|
||||||
|
this._defaultAction = action;
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCanvasOffsets(k: IActiveActionData[], _arg_2: string, _arg_3: number): number[]
|
||||||
|
{
|
||||||
|
let canvasOffsets: number[] = [];
|
||||||
|
|
||||||
|
for(const activeAction of k)
|
||||||
|
{
|
||||||
|
if(!activeAction) continue;
|
||||||
|
|
||||||
|
const action = this._actions.getValue(activeAction.actionType);
|
||||||
|
const offsets = action && action.getOffsets(_arg_2, _arg_3);
|
||||||
|
|
||||||
|
if(offsets) canvasOffsets = offsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvasOffsets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public sortActions(actions: IActiveActionData[]): IActiveActionData[]
|
||||||
|
{
|
||||||
|
if(!actions) return null;
|
||||||
|
|
||||||
|
actions = this.filterActions(actions);
|
||||||
|
|
||||||
|
const validatedActions: IActiveActionData[] = [];
|
||||||
|
|
||||||
|
for(const action of actions)
|
||||||
|
{
|
||||||
|
if(!action) continue;
|
||||||
|
|
||||||
|
const definition = this._actions.getValue(action.actionType);
|
||||||
|
|
||||||
|
if(!definition) continue;
|
||||||
|
|
||||||
|
action.definition = definition;
|
||||||
|
|
||||||
|
validatedActions.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
validatedActions.sort(this.sortByPrecedence);
|
||||||
|
|
||||||
|
return validatedActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterActions(actions: IActiveActionData[]): IActiveActionData[]
|
||||||
|
{
|
||||||
|
let preventions: string[] = [];
|
||||||
|
const activeActions: IActiveActionData[] = [];
|
||||||
|
|
||||||
|
for(const action of actions)
|
||||||
|
{
|
||||||
|
if(!action) continue;
|
||||||
|
|
||||||
|
const localAction = this._actions.getValue(action.actionType);
|
||||||
|
|
||||||
|
if(localAction) preventions = preventions.concat(localAction.getPrevents(action.actionParameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const action of actions)
|
||||||
|
{
|
||||||
|
if(!action) continue;
|
||||||
|
|
||||||
|
let actionType = action.actionType;
|
||||||
|
|
||||||
|
if(action.actionType === 'fx') actionType = (actionType + ('.' + action.actionParameter));
|
||||||
|
|
||||||
|
if(preventions.indexOf(actionType) >= 0) continue;
|
||||||
|
|
||||||
|
activeActions.push(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sortByPrecedence(actionOne: IActiveActionData, actionTwo: IActiveActionData): number
|
||||||
|
{
|
||||||
|
if(!actionOne || !actionTwo) return 0;
|
||||||
|
|
||||||
|
const precedenceOne = actionOne.definition.precedence;
|
||||||
|
const precedenceTwo = actionTwo.definition.precedence;
|
||||||
|
|
||||||
|
if(precedenceOne < precedenceTwo) return 1;
|
||||||
|
|
||||||
|
if(precedenceOne > precedenceTwo) return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
19
src/app/avatar/actions/IActionDefinition.ts
Normal file
19
src/app/avatar/actions/IActionDefinition.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
export interface IActionDefinition
|
||||||
|
{
|
||||||
|
id: string;
|
||||||
|
state: string;
|
||||||
|
precedence: number;
|
||||||
|
activePartSet: string;
|
||||||
|
isMain: boolean;
|
||||||
|
isDefault: boolean;
|
||||||
|
assetPartDefinition: string;
|
||||||
|
lay: string;
|
||||||
|
geometryType: string;
|
||||||
|
isAnimation: boolean;
|
||||||
|
startFromFrameZero: boolean;
|
||||||
|
isAnimated(_arg_1: string): boolean;
|
||||||
|
getPrevents(_arg_1: string): string[];
|
||||||
|
getPreventHeadTurn(_arg_1: string): boolean;
|
||||||
|
setOffsets(_arg_1: string, _arg_2: number, _arg_3: []): void;
|
||||||
|
getOffsets(_arg_1: string, _arg_2: number): number[];
|
||||||
|
}
|
11
src/app/avatar/actions/IActiveActionData.ts
Normal file
11
src/app/avatar/actions/IActiveActionData.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { IActionDefinition } from './IActionDefinition';
|
||||||
|
|
||||||
|
export interface IActiveActionData
|
||||||
|
{
|
||||||
|
id: string;
|
||||||
|
actionType: string;
|
||||||
|
actionParameter: string;
|
||||||
|
startFrame: number;
|
||||||
|
definition: IActionDefinition;
|
||||||
|
overridingAction: string;
|
||||||
|
}
|
6
src/app/avatar/actions/index.ts
Normal file
6
src/app/avatar/actions/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export * from './ActionDefinition';
|
||||||
|
export * from './ActionType';
|
||||||
|
export * from './ActiveActionData';
|
||||||
|
export * from './AvatarActionManager';
|
||||||
|
export * from './IActionDefinition';
|
||||||
|
export * from './IActiveActionData';
|
37
src/app/avatar/alias/AssetAlias.ts
Normal file
37
src/app/avatar/alias/AssetAlias.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { IAssetAlias } from '../../../core';
|
||||||
|
|
||||||
|
export class AssetAlias
|
||||||
|
{
|
||||||
|
private _name: string;
|
||||||
|
private _link: string;
|
||||||
|
private _flipH: boolean;
|
||||||
|
private _flipV: boolean;
|
||||||
|
|
||||||
|
constructor(name: string, alias: IAssetAlias)
|
||||||
|
{
|
||||||
|
this._name = name;
|
||||||
|
this._link = alias.link;
|
||||||
|
this._flipH = alias.flipH;
|
||||||
|
this._flipV = alias.flipV;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get name(): string
|
||||||
|
{
|
||||||
|
return this._name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get link(): string
|
||||||
|
{
|
||||||
|
return this._link;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get flipH(): boolean
|
||||||
|
{
|
||||||
|
return this._flipH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get flipV(): boolean
|
||||||
|
{
|
||||||
|
return this._flipV;
|
||||||
|
}
|
||||||
|
}
|
89
src/app/avatar/alias/AssetAliasCollection.ts
Normal file
89
src/app/avatar/alias/AssetAliasCollection.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { AdvancedMap, IAssetManager, IGraphicAsset } from '../../../core';
|
||||||
|
import { AvatarRenderManager } from '../AvatarRenderManager';
|
||||||
|
import { AssetAlias } from './AssetAlias';
|
||||||
|
|
||||||
|
export class AssetAliasCollection
|
||||||
|
{
|
||||||
|
private _assets: IAssetManager;
|
||||||
|
private _aliases: AdvancedMap<string, AssetAlias>;
|
||||||
|
private _avatarRenderManager: AvatarRenderManager;
|
||||||
|
private _missingAssetNames: string[];
|
||||||
|
|
||||||
|
constructor(renderManager: AvatarRenderManager, assetManager: IAssetManager)
|
||||||
|
{
|
||||||
|
this._avatarRenderManager = renderManager;
|
||||||
|
this._aliases = new AdvancedMap();
|
||||||
|
this._assets = assetManager;
|
||||||
|
this._missingAssetNames = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._assets = null;
|
||||||
|
this._aliases = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public reset(): void
|
||||||
|
{
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(): void
|
||||||
|
{
|
||||||
|
for(const collection of this._assets.collections.getValues())
|
||||||
|
{
|
||||||
|
if(!collection) continue;
|
||||||
|
|
||||||
|
const aliases = collection.data && collection.data.aliases;
|
||||||
|
|
||||||
|
if(!aliases) continue;
|
||||||
|
|
||||||
|
for(const name in aliases)
|
||||||
|
{
|
||||||
|
const alias = aliases[name];
|
||||||
|
|
||||||
|
if(!alias) continue;
|
||||||
|
|
||||||
|
this._aliases.add(name, new AssetAlias(name, alias));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasAlias(name: string): boolean
|
||||||
|
{
|
||||||
|
const alias = this._aliases.getValue(name);
|
||||||
|
|
||||||
|
if(alias) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAssetName(k: string): string
|
||||||
|
{
|
||||||
|
let linkName = k;
|
||||||
|
let tries = 5;
|
||||||
|
|
||||||
|
while(this.hasAlias(linkName) && (tries >= 0))
|
||||||
|
{
|
||||||
|
const alias = this._aliases.getValue(linkName);
|
||||||
|
|
||||||
|
linkName = alias.link;
|
||||||
|
tries--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return linkName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAsset(name: string): IGraphicAsset
|
||||||
|
{
|
||||||
|
if(!this._assets) return null;
|
||||||
|
|
||||||
|
name = this.getAssetName(name);
|
||||||
|
|
||||||
|
const asset = this._assets.getAsset(name);
|
||||||
|
|
||||||
|
if(!asset) return null;
|
||||||
|
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
}
|
2
src/app/avatar/alias/index.ts
Normal file
2
src/app/avatar/alias/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './AssetAlias';
|
||||||
|
export * from './AssetAliasCollection';
|
58
src/app/avatar/animation/AddDataContainer.ts
Normal file
58
src/app/avatar/animation/AddDataContainer.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { IAssetAnimationAdd } from '../../../core';
|
||||||
|
|
||||||
|
export class AddDataContainer
|
||||||
|
{
|
||||||
|
private _id: string;
|
||||||
|
private _align: string;
|
||||||
|
private _base: string;
|
||||||
|
private _ink: number;
|
||||||
|
private _blend: number;
|
||||||
|
|
||||||
|
constructor(animation: IAssetAnimationAdd)
|
||||||
|
{
|
||||||
|
this._id = (animation.id || '');
|
||||||
|
this._align = (animation.align || '');
|
||||||
|
this._base = (animation.base || '');
|
||||||
|
this._ink = (animation.ink || 0);
|
||||||
|
this._blend = 0;
|
||||||
|
|
||||||
|
const blend = animation.blend;
|
||||||
|
|
||||||
|
if(blend && (blend.length > 0))
|
||||||
|
{
|
||||||
|
this._blend = parseInt(blend);
|
||||||
|
|
||||||
|
if(this._blend > 1) this._blend = (this._blend / 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get align(): string
|
||||||
|
{
|
||||||
|
return this._align;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get base(): string
|
||||||
|
{
|
||||||
|
return this._base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get ink(): number
|
||||||
|
{
|
||||||
|
return this._ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get blend(): number
|
||||||
|
{
|
||||||
|
return this._blend;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isBlended(): boolean
|
||||||
|
{
|
||||||
|
return (this._blend !== 1);
|
||||||
|
}
|
||||||
|
}
|
312
src/app/avatar/animation/Animation.ts
Normal file
312
src/app/avatar/animation/Animation.ts
Normal file
@ -0,0 +1,312 @@
|
|||||||
|
import { AdvancedMap, IAssetAnimation, IAssetAnimationFrame } from '../../../core';
|
||||||
|
import { AvatarStructure } from '../AvatarStructure';
|
||||||
|
import { AddDataContainer } from './AddDataContainer';
|
||||||
|
import { AvatarAnimationLayerData } from './AvatarAnimationLayerData';
|
||||||
|
import { AvatarDataContainer } from './AvatarDataContainer';
|
||||||
|
import { DirectionDataContainer } from './DirectionDataContainer';
|
||||||
|
import { IAnimation } from './IAnimation';
|
||||||
|
import { SpriteDataContainer } from './SpriteDataContainer';
|
||||||
|
|
||||||
|
export class Animation implements IAnimation
|
||||||
|
{
|
||||||
|
private static EMPTY_ARRAY: any[] = [];
|
||||||
|
|
||||||
|
private _id: string;
|
||||||
|
private _description: string;
|
||||||
|
private _frames: AvatarAnimationLayerData[][];
|
||||||
|
private _spriteData: SpriteDataContainer[];
|
||||||
|
private _avatarData: AvatarDataContainer;
|
||||||
|
private _directionData: DirectionDataContainer;
|
||||||
|
private _removeData: string[];
|
||||||
|
private _addData: AddDataContainer[];
|
||||||
|
private _overriddenActions: AdvancedMap<string, string>;
|
||||||
|
private _overrideFrames: AdvancedMap<string, AvatarAnimationLayerData[][]>;
|
||||||
|
private _resetOnToggle: boolean;
|
||||||
|
|
||||||
|
constructor(structure: AvatarStructure, animation: IAssetAnimation)
|
||||||
|
{
|
||||||
|
this._id = animation.name;
|
||||||
|
this._description = this._id;
|
||||||
|
this._frames = [];
|
||||||
|
this._spriteData = null;
|
||||||
|
this._avatarData = null;
|
||||||
|
this._directionData = null;
|
||||||
|
this._removeData = null;
|
||||||
|
this._addData = null;
|
||||||
|
this._overriddenActions = null;
|
||||||
|
this._overrideFrames = null;
|
||||||
|
this._resetOnToggle = (animation.resetOnToggle || false);
|
||||||
|
|
||||||
|
if(animation.sprites && animation.sprites.length)
|
||||||
|
{
|
||||||
|
this._spriteData = [];
|
||||||
|
|
||||||
|
for(const sprite of animation.sprites) this._spriteData.push(new SpriteDataContainer(this, sprite));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(animation.avatars && animation.avatars.length) this._avatarData = new AvatarDataContainer(animation.avatars[0]);
|
||||||
|
|
||||||
|
if(animation.directions && animation.directions.length) this._directionData = new DirectionDataContainer(animation.directions[0]);
|
||||||
|
|
||||||
|
if(animation.removes && animation.removes.length)
|
||||||
|
{
|
||||||
|
this._removeData = [];
|
||||||
|
|
||||||
|
for(const remove of animation.removes) this._removeData.push(remove.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(animation.adds && animation.adds.length)
|
||||||
|
{
|
||||||
|
this._addData = [];
|
||||||
|
|
||||||
|
for(const add of animation.adds) this._addData.push(new AddDataContainer(add));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(animation.overrides && animation.overrides.length)
|
||||||
|
{
|
||||||
|
this._overrideFrames = new AdvancedMap();
|
||||||
|
this._overriddenActions = new AdvancedMap();
|
||||||
|
|
||||||
|
for(const override of animation.overrides)
|
||||||
|
{
|
||||||
|
const name = override.name;
|
||||||
|
const value = override.override;
|
||||||
|
|
||||||
|
this._overriddenActions.add(value, name);
|
||||||
|
|
||||||
|
const frames: AvatarAnimationLayerData[][] = [];
|
||||||
|
|
||||||
|
this.parseFrames(frames, override.frames, structure);
|
||||||
|
|
||||||
|
this._overrideFrames.add(name, frames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parseFrames(this._frames, animation.frames, structure);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFrames(frames: AvatarAnimationLayerData[][], animationFrame: IAssetAnimationFrame[], structure: AvatarStructure): void
|
||||||
|
{
|
||||||
|
if(!animationFrame || !animationFrame.length) return;
|
||||||
|
|
||||||
|
for(const frame of animationFrame)
|
||||||
|
{
|
||||||
|
let repeats = 1;
|
||||||
|
|
||||||
|
if(frame.repeats && (frame.repeats > 1)) repeats = frame.repeats;
|
||||||
|
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while(index < repeats)
|
||||||
|
{
|
||||||
|
const layers: AvatarAnimationLayerData[] = [];
|
||||||
|
|
||||||
|
if(frame.bodyparts && frame.bodyparts.length)
|
||||||
|
{
|
||||||
|
for(const bodyPart of frame.bodyparts)
|
||||||
|
{
|
||||||
|
const definition = structure.getActionDefinition(bodyPart.action);
|
||||||
|
const layer = new AvatarAnimationLayerData(bodyPart, AvatarAnimationLayerData.BODYPART, definition);
|
||||||
|
|
||||||
|
layers.push(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(frame.fxs && frame.fxs.length)
|
||||||
|
{
|
||||||
|
for(const fx of frame.fxs)
|
||||||
|
{
|
||||||
|
const definition = structure.getActionDefinition(fx.action);
|
||||||
|
const layer = new AvatarAnimationLayerData(fx, AvatarAnimationLayerData.FX, definition);
|
||||||
|
|
||||||
|
layers.push(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frames.push(layers);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public frameCount(frame: string = null): number
|
||||||
|
{
|
||||||
|
if(!frame) return this._frames.length;
|
||||||
|
|
||||||
|
if(this._overrideFrames)
|
||||||
|
{
|
||||||
|
const layerData = this._overrideFrames.getValue(frame);
|
||||||
|
|
||||||
|
if(layerData) return layerData.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasOverriddenActions(): boolean
|
||||||
|
{
|
||||||
|
if(!this._overriddenActions) return false;
|
||||||
|
|
||||||
|
return (this._overriddenActions.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public overriddenActionNames(): string[]
|
||||||
|
{
|
||||||
|
if(!this._overriddenActions) return null;
|
||||||
|
|
||||||
|
const keys: string[] = [];
|
||||||
|
|
||||||
|
for(const key of this._overriddenActions.getKeys()) keys.push(key);
|
||||||
|
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public overridingAction(action: string): string
|
||||||
|
{
|
||||||
|
if(!this._overriddenActions) return null;
|
||||||
|
|
||||||
|
return this._overriddenActions.getValue(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getFrame(frameCount: number, frame: string = null): AvatarAnimationLayerData[]
|
||||||
|
{
|
||||||
|
if(frameCount < 0) frameCount = 0;
|
||||||
|
|
||||||
|
let layers: AvatarAnimationLayerData[] = [];
|
||||||
|
|
||||||
|
if(!frame)
|
||||||
|
{
|
||||||
|
if(this._frames.length > 0)
|
||||||
|
{
|
||||||
|
layers = this._frames[(frameCount % this._frames.length)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const overrideLayers = this._overrideFrames.getValue(frame);
|
||||||
|
|
||||||
|
if(overrideLayers && (overrideLayers.length > 0))
|
||||||
|
{
|
||||||
|
layers = overrideLayers[(frameCount % overrideLayers.length)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAnimatedBodyPartIds(frameCount: number, frame: string = null): string[]
|
||||||
|
{
|
||||||
|
const partIds: string[] = [];
|
||||||
|
|
||||||
|
for(const layer of this.getFrame(frameCount, frame))
|
||||||
|
{
|
||||||
|
if(layer.type === AvatarAnimationLayerData.BODYPART)
|
||||||
|
{
|
||||||
|
partIds.push(layer.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(layer.type === AvatarAnimationLayerData.FX)
|
||||||
|
{
|
||||||
|
if(this._addData && this._addData.length)
|
||||||
|
{
|
||||||
|
for(const _local_5 of this._addData)
|
||||||
|
{
|
||||||
|
if(_local_5.id === layer.id) partIds.push(_local_5.align);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return partIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLayerData(frameCount: number, spriteId: string, frame: string = null): AvatarAnimationLayerData
|
||||||
|
{
|
||||||
|
for(const layer of this.getFrame(frameCount, frame))
|
||||||
|
{
|
||||||
|
if(layer.id === spriteId) return layer;
|
||||||
|
|
||||||
|
if(layer.type === AvatarAnimationLayerData.FX)
|
||||||
|
{
|
||||||
|
if(this._addData && this._addData.length)
|
||||||
|
{
|
||||||
|
for(const addData of this._addData)
|
||||||
|
{
|
||||||
|
if(((addData.align === spriteId) && (addData.id === layer.id))) return layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasAvatarData(): boolean
|
||||||
|
{
|
||||||
|
return (this._avatarData !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasDirectionData(): boolean
|
||||||
|
{
|
||||||
|
return (this._directionData !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasAddData(): boolean
|
||||||
|
{
|
||||||
|
return (this._addData !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAddData(id: string): AddDataContainer
|
||||||
|
{
|
||||||
|
if(this._addData)
|
||||||
|
{
|
||||||
|
for(const data of this._addData)
|
||||||
|
{
|
||||||
|
if(data.id === id) return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get spriteData(): SpriteDataContainer[]
|
||||||
|
{
|
||||||
|
return (this._spriteData || Animation.EMPTY_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get avatarData(): AvatarDataContainer
|
||||||
|
{
|
||||||
|
return this._avatarData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get directionData(): DirectionDataContainer
|
||||||
|
{
|
||||||
|
return this._directionData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get removeData(): string[]
|
||||||
|
{
|
||||||
|
return (this._removeData || Animation.EMPTY_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get addData(): AddDataContainer[]
|
||||||
|
{
|
||||||
|
return (this._addData || Animation.EMPTY_ARRAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string
|
||||||
|
{
|
||||||
|
return this._description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get resetOnToggle(): boolean
|
||||||
|
{
|
||||||
|
return this._resetOnToggle;
|
||||||
|
}
|
||||||
|
}
|
50
src/app/avatar/animation/AnimationManager.ts
Normal file
50
src/app/avatar/animation/AnimationManager.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import { AdvancedMap, IAssetAnimation } from '../../../core';
|
||||||
|
import { AvatarStructure } from '../AvatarStructure';
|
||||||
|
import { Animation } from './Animation';
|
||||||
|
import { IAnimation } from './IAnimation';
|
||||||
|
import { IAnimationLayerData } from './IAnimationLayerData';
|
||||||
|
import { IAnimationManager } from './IAnimationManager';
|
||||||
|
|
||||||
|
export class AnimationManager implements IAnimationManager
|
||||||
|
{
|
||||||
|
private _animations: AdvancedMap<string, Animation>;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._animations = new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerAnimation(structure: AvatarStructure, animations: { [index: string]: IAssetAnimation }): boolean
|
||||||
|
{
|
||||||
|
const animationData = animations[Object.keys(animations)[0]];
|
||||||
|
|
||||||
|
const animation = new Animation(structure, animationData);
|
||||||
|
|
||||||
|
this._animations.add(animationData.name, animation);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAnimation(animation: string): Animation
|
||||||
|
{
|
||||||
|
const existing = this._animations.getValue(animation);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLayerData(animation: string, frameCount: number, spriteId: string): IAnimationLayerData
|
||||||
|
{
|
||||||
|
const existing = this.getAnimation(animation);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing.getLayerData(frameCount, spriteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get animations(): AdvancedMap<string, IAnimation>
|
||||||
|
{
|
||||||
|
return this._animations;
|
||||||
|
}
|
||||||
|
}
|
110
src/app/avatar/animation/AvatarAnimationLayerData.ts
Normal file
110
src/app/avatar/animation/AvatarAnimationLayerData.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import { AdvancedMap, IAssetAnimationFramePart } from '../../../core';
|
||||||
|
import { ActiveActionData, IActionDefinition, IActiveActionData } from '../actions';
|
||||||
|
import { IAnimationLayerData } from './IAnimationLayerData';
|
||||||
|
|
||||||
|
export class AvatarAnimationLayerData implements IAnimationLayerData
|
||||||
|
{
|
||||||
|
public static BODYPART: string = 'bodypart';
|
||||||
|
public static FX: string = 'fx';
|
||||||
|
|
||||||
|
private _id: string;
|
||||||
|
private _action: IActiveActionData;
|
||||||
|
private _animationFrame: number;
|
||||||
|
private _dx: number;
|
||||||
|
private _dy: number;
|
||||||
|
private _dz: number;
|
||||||
|
private _directionOffset: number;
|
||||||
|
private _type: string;
|
||||||
|
private _base: string;
|
||||||
|
private _items: AdvancedMap<string, string>;
|
||||||
|
|
||||||
|
constructor(framePart: IAssetAnimationFramePart, type: string, definition: IActionDefinition)
|
||||||
|
{
|
||||||
|
this._id = framePart.id;
|
||||||
|
this._animationFrame = (framePart.frame || 0);
|
||||||
|
this._dx = (framePart.dx || 0);
|
||||||
|
this._dy = (framePart.dy || 0);
|
||||||
|
this._dz = (framePart.dz || 0);
|
||||||
|
this._directionOffset = (framePart.dd || 0);
|
||||||
|
this._type = type;
|
||||||
|
this._base = (framePart.base || '');
|
||||||
|
this._items = new AdvancedMap();
|
||||||
|
|
||||||
|
if(framePart.items) for(const partItem of framePart.items) this._items.add(partItem.id, partItem.base);
|
||||||
|
|
||||||
|
let base = '';
|
||||||
|
|
||||||
|
if(this._base !== '') base = this.baseAsInt().toString();
|
||||||
|
|
||||||
|
if(definition)
|
||||||
|
{
|
||||||
|
this._action = new ActiveActionData(definition.state, this.base);
|
||||||
|
this._action.definition = definition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get items(): AdvancedMap<string, string>
|
||||||
|
{
|
||||||
|
return this._items;
|
||||||
|
}
|
||||||
|
|
||||||
|
private baseAsInt(): number
|
||||||
|
{
|
||||||
|
let base = 0;
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while(index < this._base.length)
|
||||||
|
{
|
||||||
|
base = (base + this._base.charCodeAt(index));
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get animationFrame(): number
|
||||||
|
{
|
||||||
|
return this._animationFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get dx(): number
|
||||||
|
{
|
||||||
|
return this._dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get dy(): number
|
||||||
|
{
|
||||||
|
return this._dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get dz(): number
|
||||||
|
{
|
||||||
|
return this._dz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get dd(): number
|
||||||
|
{
|
||||||
|
return this._directionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get type(): string
|
||||||
|
{
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get base(): string
|
||||||
|
{
|
||||||
|
return this._base;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get action(): IActiveActionData
|
||||||
|
{
|
||||||
|
return this._action;
|
||||||
|
}
|
||||||
|
}
|
129
src/app/avatar/animation/AvatarDataContainer.ts
Normal file
129
src/app/avatar/animation/AvatarDataContainer.ts
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { AdvancedMap, IAssetAnimationAvatar } from '../../../core';
|
||||||
|
import { IAvatarDataContainer } from './IAvatarDataContainer';
|
||||||
|
|
||||||
|
export class AvatarDataContainer implements IAvatarDataContainer
|
||||||
|
{
|
||||||
|
private _ink: number;
|
||||||
|
private _foreGround: number;
|
||||||
|
private _backGround: number;
|
||||||
|
private _rgb: number;
|
||||||
|
private _r: number;
|
||||||
|
private _g: number;
|
||||||
|
private _b: number;
|
||||||
|
private _redMultiplier: number;
|
||||||
|
private _greenMultiplier: number;
|
||||||
|
private _blueMultiplier: number;
|
||||||
|
private _alphaMultiplier: number;
|
||||||
|
private _colorMap: AdvancedMap<string, number[]>;
|
||||||
|
private _paletteIsGrayscale: boolean;
|
||||||
|
|
||||||
|
constructor(animation: IAssetAnimationAvatar)
|
||||||
|
{
|
||||||
|
this._ink = animation.ink;
|
||||||
|
|
||||||
|
let foreground = animation.foreground;
|
||||||
|
let background = animation.background;
|
||||||
|
|
||||||
|
foreground = foreground.replace('#', '');
|
||||||
|
background = background.replace('#', '');
|
||||||
|
|
||||||
|
this._foreGround = parseInt(foreground, 16);
|
||||||
|
this._backGround = parseInt(background, 16);
|
||||||
|
this._rgb = parseInt(foreground, 16);
|
||||||
|
this._r = ((this._rgb >> 16) & 0xFF);
|
||||||
|
this._g = ((this._rgb >> 8) & 0xFF);
|
||||||
|
this._b = ((this._rgb >> 0) & 0xFF);
|
||||||
|
this._redMultiplier = ((this._r / 0xFF) * 1);
|
||||||
|
this._greenMultiplier = ((this._g / 0xFF) * 1);
|
||||||
|
this._blueMultiplier = ((this._b / 0xFF) * 1);
|
||||||
|
this._alphaMultiplier = 1;
|
||||||
|
this._paletteIsGrayscale = true;
|
||||||
|
|
||||||
|
if(this._ink === 37)
|
||||||
|
{
|
||||||
|
this._alphaMultiplier = 0.5;
|
||||||
|
this._paletteIsGrayscale = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._colorMap = this.generatePaletteMapForGrayscale(this._backGround, this._foreGround);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get ink(): number
|
||||||
|
{
|
||||||
|
return this._ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get reds(): number[]
|
||||||
|
{
|
||||||
|
return this._colorMap.getValue('reds');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get greens(): number[]
|
||||||
|
{
|
||||||
|
return this._colorMap.getValue('greens');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get blues(): number[]
|
||||||
|
{
|
||||||
|
return this._colorMap.getValue('blues');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get alphas(): number[]
|
||||||
|
{
|
||||||
|
return this._colorMap.getValue('alphas');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get paletteIsGrayscale(): boolean
|
||||||
|
{
|
||||||
|
return this._paletteIsGrayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
private generatePaletteMapForGrayscale(k: number, _arg_2: number): AdvancedMap<string, number[]>
|
||||||
|
{
|
||||||
|
const _local_3 = ((k >> 24) & 0xFF);
|
||||||
|
const _local_4 = ((k >> 16) & 0xFF);
|
||||||
|
const _local_5 = ((k >> 8) & 0xFF);
|
||||||
|
const _local_6 = ((k >> 0) & 0xFF);
|
||||||
|
const _local_7 = ((_arg_2 >> 24) & 0xFF);
|
||||||
|
const _local_8 = ((_arg_2 >> 16) & 0xFF);
|
||||||
|
const _local_9 = ((_arg_2 >> 8) & 0xFF);
|
||||||
|
const _local_10 = ((_arg_2 >> 0) & 0xFF);
|
||||||
|
const _local_11 = ((_local_7 - _local_3) / 0xFF);
|
||||||
|
const _local_12 = ((_local_8 - _local_4) / 0xFF);
|
||||||
|
const _local_13 = ((_local_9 - _local_5) / 0xFF);
|
||||||
|
const _local_14 = ((_local_10 - _local_6) / 0xFF);
|
||||||
|
const _local_15: AdvancedMap<string, number[]> = new AdvancedMap();
|
||||||
|
const reds: number[] = [];
|
||||||
|
const greens: number[] = [];
|
||||||
|
const blues: number[] = [];
|
||||||
|
const _local_19: number[] = [];
|
||||||
|
let _local_20 = _local_3;
|
||||||
|
let _local_21 = _local_4;
|
||||||
|
let _local_22 = _local_5;
|
||||||
|
let _local_23 = _local_6;
|
||||||
|
let _local_24 = 0;
|
||||||
|
while(_local_24 < 0x0100)
|
||||||
|
{
|
||||||
|
if((((_local_21 == _local_4) && (_local_22 == _local_5)) && (_local_23 == _local_6)))
|
||||||
|
{
|
||||||
|
_local_20 = 0;
|
||||||
|
}
|
||||||
|
_local_20 = (_local_20 + _local_11);
|
||||||
|
_local_21 = (_local_21 + _local_12);
|
||||||
|
_local_22 = (_local_22 + _local_13);
|
||||||
|
_local_23 = (_local_23 + _local_14);
|
||||||
|
_local_19.push((_local_20 << 24));
|
||||||
|
reds.push(((((_local_20 << 24) | (_local_21 << 16)) | (_local_22 << 8)) | _local_23));
|
||||||
|
greens.push(((((_local_20 << 24) | (_local_21 << 16)) | (_local_22 << 8)) | _local_23));
|
||||||
|
blues.push(((((_local_20 << 24) | (_local_21 << 16)) | (_local_22 << 8)) | _local_23));
|
||||||
|
_local_24++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_local_15.add('alphas', reds);
|
||||||
|
_local_15.add('reds', reds);
|
||||||
|
_local_15.add('greens', greens);
|
||||||
|
_local_15.add('blues', blues);
|
||||||
|
|
||||||
|
return _local_15;
|
||||||
|
}
|
||||||
|
}
|
16
src/app/avatar/animation/DirectionDataContainer.ts
Normal file
16
src/app/avatar/animation/DirectionDataContainer.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { IAssetAnimationDirection } from '../../../core';
|
||||||
|
|
||||||
|
export class DirectionDataContainer
|
||||||
|
{
|
||||||
|
private _offset: number;
|
||||||
|
|
||||||
|
constructor(direction: IAssetAnimationDirection)
|
||||||
|
{
|
||||||
|
this._offset = direction.offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offset(): number
|
||||||
|
{
|
||||||
|
return this._offset;
|
||||||
|
}
|
||||||
|
}
|
11
src/app/avatar/animation/IAnimation.ts
Normal file
11
src/app/avatar/animation/IAnimation.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
export interface IAnimation
|
||||||
|
{
|
||||||
|
hasAvatarData(): boolean;
|
||||||
|
hasDirectionData(): boolean;
|
||||||
|
hasAddData(): boolean;
|
||||||
|
id: string;
|
||||||
|
spriteData: any;
|
||||||
|
removeData: any;
|
||||||
|
addData: any;
|
||||||
|
resetOnToggle: boolean;
|
||||||
|
}
|
12
src/app/avatar/animation/IAnimationLayerData.ts
Normal file
12
src/app/avatar/animation/IAnimationLayerData.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { IActiveActionData } from '../actions';
|
||||||
|
|
||||||
|
export interface IAnimationLayerData
|
||||||
|
{
|
||||||
|
id: string;
|
||||||
|
action: IActiveActionData;
|
||||||
|
animationFrame: number;
|
||||||
|
dx: number;
|
||||||
|
dy: number;
|
||||||
|
dz: number;
|
||||||
|
dd: number;
|
||||||
|
}
|
10
src/app/avatar/animation/IAnimationManager.ts
Normal file
10
src/app/avatar/animation/IAnimationManager.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { IAnimation } from './IAnimation';
|
||||||
|
import { IAnimationLayerData } from './IAnimationLayerData';
|
||||||
|
|
||||||
|
export interface IAnimationManager
|
||||||
|
{
|
||||||
|
animations: AdvancedMap<any, any>;
|
||||||
|
getAnimation(animation: string): IAnimation;
|
||||||
|
getLayerData(animation: string, frameCount: number, spriteId: string): IAnimationLayerData;
|
||||||
|
}
|
9
src/app/avatar/animation/IAvatarDataContainer.ts
Normal file
9
src/app/avatar/animation/IAvatarDataContainer.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface IAvatarDataContainer
|
||||||
|
{
|
||||||
|
ink: number;
|
||||||
|
paletteIsGrayscale: boolean;
|
||||||
|
reds: number[];
|
||||||
|
greens: number[];
|
||||||
|
blues: number[];
|
||||||
|
alphas: number[];
|
||||||
|
}
|
14
src/app/avatar/animation/ISpriteDataContainer.ts
Normal file
14
src/app/avatar/animation/ISpriteDataContainer.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { IAnimation } from './IAnimation';
|
||||||
|
|
||||||
|
export interface ISpriteDataContainer
|
||||||
|
{
|
||||||
|
animation: IAnimation;
|
||||||
|
id: string;
|
||||||
|
ink: number;
|
||||||
|
member: string;
|
||||||
|
hasDirections: boolean;
|
||||||
|
hasStaticY: boolean;
|
||||||
|
getDirectionOffsetX(direction: number): number;
|
||||||
|
getDirectionOffsetY(direction: number): number;
|
||||||
|
getDirectionOffsetZ(direction: number): number;
|
||||||
|
}
|
96
src/app/avatar/animation/SpriteDataContainer.ts
Normal file
96
src/app/avatar/animation/SpriteDataContainer.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { IAssetAnimationSprite } from '../../../core';
|
||||||
|
import { IAnimation } from './IAnimation';
|
||||||
|
import { ISpriteDataContainer } from './ISpriteDataContainer';
|
||||||
|
|
||||||
|
export class SpriteDataContainer implements ISpriteDataContainer
|
||||||
|
{
|
||||||
|
private _animation: IAnimation;
|
||||||
|
private _id: string;
|
||||||
|
private _ink: number;
|
||||||
|
private _member: string;
|
||||||
|
private _hasDirections: boolean;
|
||||||
|
private _hasStaticY: boolean;
|
||||||
|
private _dx: number[];
|
||||||
|
private _dy: number[];
|
||||||
|
private _dz: number[];
|
||||||
|
|
||||||
|
constructor(animation: IAnimation, sprite: IAssetAnimationSprite)
|
||||||
|
{
|
||||||
|
this._animation = animation;
|
||||||
|
this._id = sprite.id;
|
||||||
|
this._ink = sprite.ink;
|
||||||
|
this._member = sprite.member;
|
||||||
|
this._hasStaticY = sprite.staticY ? true : false;
|
||||||
|
this._hasDirections = sprite.directions ? true : false;
|
||||||
|
this._dx = [];
|
||||||
|
this._dy = [];
|
||||||
|
this._dz = [];
|
||||||
|
|
||||||
|
const directions = sprite.directionList;
|
||||||
|
|
||||||
|
if(directions && directions.length)
|
||||||
|
{
|
||||||
|
for(const direction of directions)
|
||||||
|
{
|
||||||
|
const id = direction.id;
|
||||||
|
|
||||||
|
if(id === undefined) continue;
|
||||||
|
|
||||||
|
this._dx[id] = (direction.dx || 0);
|
||||||
|
this._dy[id] = (direction.dy || 0);
|
||||||
|
this._dz[id] = (direction.dz || 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirectionOffsetX(k: number): number
|
||||||
|
{
|
||||||
|
if(k < this._dx.length) return this._dx[k];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirectionOffsetY(k: number): number
|
||||||
|
{
|
||||||
|
if(k < this._dy.length) return this._dy[k];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirectionOffsetZ(k: number): number
|
||||||
|
{
|
||||||
|
if(k < this._dz.length) return this._dz[k];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get animation(): IAnimation
|
||||||
|
{
|
||||||
|
return this._animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get ink(): number
|
||||||
|
{
|
||||||
|
return this._ink;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get member(): string
|
||||||
|
{
|
||||||
|
return this._member;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hasDirections(): boolean
|
||||||
|
{
|
||||||
|
return this._hasDirections;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hasStaticY(): boolean
|
||||||
|
{
|
||||||
|
return this._hasStaticY;
|
||||||
|
}
|
||||||
|
}
|
12
src/app/avatar/animation/index.ts
Normal file
12
src/app/avatar/animation/index.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export * from './AddDataContainer';
|
||||||
|
export * from './Animation';
|
||||||
|
export * from './AnimationManager';
|
||||||
|
export * from './AvatarAnimationLayerData';
|
||||||
|
export * from './AvatarDataContainer';
|
||||||
|
export * from './DirectionDataContainer';
|
||||||
|
export * from './IAnimation';
|
||||||
|
export * from './IAnimationLayerData';
|
||||||
|
export * from './IAnimationManager';
|
||||||
|
export * from './IAvatarDataContainer';
|
||||||
|
export * from './ISpriteDataContainer';
|
||||||
|
export * from './SpriteDataContainer';
|
57
src/app/avatar/cache/AvatarImageActionCache.ts
vendored
Normal file
57
src/app/avatar/cache/AvatarImageActionCache.ts
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { AvatarImageDirectionCache } from './AvatarImageDirectionCache';
|
||||||
|
|
||||||
|
export class AvatarImageActionCache
|
||||||
|
{
|
||||||
|
private _cache: AdvancedMap<string, AvatarImageDirectionCache>;
|
||||||
|
private _lastAccessTime: number;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._cache = new AdvancedMap();
|
||||||
|
|
||||||
|
this.setLastAccessTime(Date.now());
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this.debugInfo('[dispose]');
|
||||||
|
|
||||||
|
if(!this._cache) return;
|
||||||
|
|
||||||
|
for(const direction of this._cache.getValues())
|
||||||
|
{
|
||||||
|
if(direction) direction.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cache.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirectionCache(k: number): AvatarImageDirectionCache
|
||||||
|
{
|
||||||
|
const existing = this._cache.getValue(k.toString());
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateDirectionCache(k: number, _arg_2: AvatarImageDirectionCache): void
|
||||||
|
{
|
||||||
|
this._cache.add(k.toString(), _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public setLastAccessTime(k: number): void
|
||||||
|
{
|
||||||
|
this._lastAccessTime = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getLastAccessTime(): number
|
||||||
|
{
|
||||||
|
return this._lastAccessTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private debugInfo(k: string): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
99
src/app/avatar/cache/AvatarImageBodyPartCache.ts
vendored
Normal file
99
src/app/avatar/cache/AvatarImageBodyPartCache.ts
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { IActiveActionData } from '../actions';
|
||||||
|
import { AvatarImageActionCache } from './AvatarImageActionCache';
|
||||||
|
|
||||||
|
export class AvatarImageBodyPartCache
|
||||||
|
{
|
||||||
|
private _cache: AdvancedMap<string, AvatarImageActionCache>;
|
||||||
|
private _currentAction: IActiveActionData;
|
||||||
|
private _currentDirection: number;
|
||||||
|
private _disposed: boolean;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._cache = new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAction(k: IActiveActionData, _arg_2: number): void
|
||||||
|
{
|
||||||
|
if(!this._currentAction) this._currentAction = k;
|
||||||
|
|
||||||
|
const _local_3 = this.getActionCache(this._currentAction);
|
||||||
|
|
||||||
|
if(_local_3) _local_3.setLastAccessTime(_arg_2);
|
||||||
|
|
||||||
|
this._currentAction = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
if(!this._disposed)
|
||||||
|
{
|
||||||
|
if(!this._cache) return;
|
||||||
|
|
||||||
|
this.disposeActions(0, 2147483647);
|
||||||
|
|
||||||
|
this._cache.reset();
|
||||||
|
|
||||||
|
this._cache = null;
|
||||||
|
this._disposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public disposeActions(k: number, _arg_2: number): void
|
||||||
|
{
|
||||||
|
if(!this._cache || this._disposed) return;
|
||||||
|
|
||||||
|
for(const key of this._cache.getKeys())
|
||||||
|
{
|
||||||
|
const cache = this._cache.getValue(key);
|
||||||
|
|
||||||
|
if(!cache) continue;
|
||||||
|
|
||||||
|
const _local_3 = cache.getLastAccessTime();
|
||||||
|
|
||||||
|
if((_arg_2 - _local_3) >= k)
|
||||||
|
{
|
||||||
|
cache.dispose();
|
||||||
|
|
||||||
|
this._cache.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAction():IActiveActionData
|
||||||
|
{
|
||||||
|
return this._currentAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDirection(k: number): void
|
||||||
|
{
|
||||||
|
this._currentDirection = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDirection(): number
|
||||||
|
{
|
||||||
|
return this._currentDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActionCache(k: IActiveActionData=null): AvatarImageActionCache
|
||||||
|
{
|
||||||
|
if(!this._currentAction) return null;
|
||||||
|
|
||||||
|
if(!k) k = this._currentAction;
|
||||||
|
|
||||||
|
if(k.overridingAction) return this._cache.getValue(k.overridingAction);
|
||||||
|
|
||||||
|
return this._cache.getValue(k.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateActionCache(k: IActiveActionData, _arg_2: AvatarImageActionCache): void
|
||||||
|
{
|
||||||
|
if(k.overridingAction) this._cache.add(k.overridingAction, _arg_2);
|
||||||
|
else this._cache.add(k.id, _arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private debugInfo(k: string): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
485
src/app/avatar/cache/AvatarImageCache.ts
vendored
Normal file
485
src/app/avatar/cache/AvatarImageCache.ts
vendored
Normal file
@ -0,0 +1,485 @@
|
|||||||
|
import { createCanvas } from 'canvas';
|
||||||
|
import { AdvancedMap, Point, Rectangle } from '../../../core';
|
||||||
|
import { IActiveActionData } from '../actions';
|
||||||
|
import { AssetAliasCollection } from '../alias';
|
||||||
|
import { AvatarAnimationLayerData } from '../animation';
|
||||||
|
import { AvatarImageBodyPartContainer } from '../AvatarImageBodyPartContainer';
|
||||||
|
import { AvatarImagePartContainer } from '../AvatarImagePartContainer';
|
||||||
|
import { AvatarStructure } from '../AvatarStructure';
|
||||||
|
import { AvatarDirectionAngle, AvatarFigurePartType, AvatarScaleType, GeometryType } from '../enum';
|
||||||
|
import { IAvatarImage } from '../IAvatarImage';
|
||||||
|
import { AvatarCanvas } from '../structure';
|
||||||
|
import { AvatarImageActionCache } from './AvatarImageActionCache';
|
||||||
|
import { AvatarImageBodyPartCache } from './AvatarImageBodyPartCache';
|
||||||
|
import { AvatarImageDirectionCache } from './AvatarImageDirectionCache';
|
||||||
|
import { ImageData } from './ImageData';
|
||||||
|
|
||||||
|
export class AvatarImageCache
|
||||||
|
{
|
||||||
|
private static DEFAULT_MAX_CACHE_STORAGE_TIME_MS: number = 60000;
|
||||||
|
|
||||||
|
private _structure: AvatarStructure;
|
||||||
|
private _avatar: IAvatarImage;
|
||||||
|
private _assets: AssetAliasCollection;
|
||||||
|
private _scale: string;
|
||||||
|
private _cache: AdvancedMap<string, AvatarImageBodyPartCache>;
|
||||||
|
private _canvas: AvatarCanvas;
|
||||||
|
private _disposed: boolean;
|
||||||
|
private _geometryType: string;
|
||||||
|
private _unionImages: ImageData[];
|
||||||
|
|
||||||
|
constructor(structure: AvatarStructure, avatarImage: IAvatarImage, aliasCollection: AssetAliasCollection, scale: string)
|
||||||
|
{
|
||||||
|
this._structure = structure;
|
||||||
|
this._avatar = avatarImage;
|
||||||
|
this._assets = aliasCollection;
|
||||||
|
this._scale = scale;
|
||||||
|
this._cache = new AdvancedMap();
|
||||||
|
this._canvas = null;
|
||||||
|
this._disposed = false;
|
||||||
|
this._unionImages = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
if(this._disposed) return;
|
||||||
|
|
||||||
|
this._structure = null;
|
||||||
|
this._avatar = null;
|
||||||
|
this._assets = null;
|
||||||
|
this._canvas = null;
|
||||||
|
this._disposed = true;
|
||||||
|
|
||||||
|
if(this._cache)
|
||||||
|
{
|
||||||
|
for(const cache of this._cache.getValues())
|
||||||
|
{
|
||||||
|
if(!cache) continue;
|
||||||
|
|
||||||
|
cache.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._cache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._unionImages)
|
||||||
|
{
|
||||||
|
for(const image of this._unionImages)
|
||||||
|
{
|
||||||
|
if(!image) continue;
|
||||||
|
|
||||||
|
image.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._unionImages = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public disposeInactiveActions(k: number = 60000): void
|
||||||
|
{
|
||||||
|
const time = Date.now();
|
||||||
|
|
||||||
|
if(this._cache)
|
||||||
|
{
|
||||||
|
for(const cache of this._cache.getValues())
|
||||||
|
{
|
||||||
|
if(!cache) continue;
|
||||||
|
|
||||||
|
cache.disposeActions(k, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetBodyPartCache(k: IActiveActionData): void
|
||||||
|
{
|
||||||
|
if(this._cache)
|
||||||
|
{
|
||||||
|
for(const cache of this._cache.getValues())
|
||||||
|
{
|
||||||
|
if(!cache) continue;
|
||||||
|
|
||||||
|
cache.setAction(k, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDirection(k: string, _arg_2: number): void
|
||||||
|
{
|
||||||
|
const parts = this._structure.getBodyPartsUnordered(k);
|
||||||
|
|
||||||
|
if(parts)
|
||||||
|
{
|
||||||
|
for(const part of parts)
|
||||||
|
{
|
||||||
|
const actionCache = this.getBodyPartCache(part);
|
||||||
|
|
||||||
|
if(!actionCache) continue;
|
||||||
|
|
||||||
|
actionCache.setDirection(_arg_2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setAction(k: IActiveActionData, _arg_2: number): void
|
||||||
|
{
|
||||||
|
const _local_3 = this._structure.getActiveBodyPartIds(k, this._avatar);
|
||||||
|
|
||||||
|
for(const _local_4 of _local_3)
|
||||||
|
{
|
||||||
|
const _local_5 = this.getBodyPartCache(_local_4);
|
||||||
|
|
||||||
|
if(_local_5) _local_5.setAction(k, _arg_2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setGeometryType(k: string): void
|
||||||
|
{
|
||||||
|
if(this._geometryType === k) return;
|
||||||
|
|
||||||
|
if((((this._geometryType === GeometryType.SITTING) && (k === GeometryType.VERTICAL)) || ((this._geometryType === GeometryType.VERTICAL) && (k === GeometryType.SITTING)) || ((this._geometryType === GeometryType.SNOWWARS_HORIZONTAL) && (k = GeometryType.SNOWWARS_HORIZONTAL))))
|
||||||
|
{
|
||||||
|
this._geometryType = k;
|
||||||
|
this._canvas = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.disposeInactiveActions(0);
|
||||||
|
|
||||||
|
this._geometryType = k;
|
||||||
|
this._canvas = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getImageContainer(k: string, frameNumber: number): AvatarImageBodyPartContainer
|
||||||
|
{
|
||||||
|
let _local_4 = this.getBodyPartCache(k);
|
||||||
|
|
||||||
|
if(!_local_4)
|
||||||
|
{
|
||||||
|
_local_4 = new AvatarImageBodyPartCache();
|
||||||
|
|
||||||
|
this._cache.add(k, _local_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _local_5 = _local_4.getDirection();
|
||||||
|
let _local_7 = _local_4.getAction();
|
||||||
|
let frameCount = frameNumber;
|
||||||
|
|
||||||
|
if(_local_7.definition.startFromFrameZero) frameCount -= _local_7.startFrame;
|
||||||
|
|
||||||
|
let _local_8 = _local_7;
|
||||||
|
let _local_9: string[] = [];
|
||||||
|
let _local_10: AdvancedMap<string, string> = new AdvancedMap();
|
||||||
|
const _local_11 = new Point();
|
||||||
|
|
||||||
|
if(!((!(_local_7)) || (!(_local_7.definition))))
|
||||||
|
{
|
||||||
|
if(_local_7.definition.isAnimation)
|
||||||
|
{
|
||||||
|
let _local_15 = _local_5;
|
||||||
|
|
||||||
|
const _local_16 = this._structure.getAnimation(((_local_7.definition.state + '.') + _local_7.actionParameter));
|
||||||
|
const _local_17 = (frameNumber - _local_7.startFrame);
|
||||||
|
|
||||||
|
if(_local_16)
|
||||||
|
{
|
||||||
|
const _local_18 = _local_16.getLayerData(_local_17, k, _local_7.overridingAction);
|
||||||
|
|
||||||
|
if(_local_18)
|
||||||
|
{
|
||||||
|
_local_15 = (_local_5 + _local_18.dd);
|
||||||
|
|
||||||
|
if(_local_18.dd < 0)
|
||||||
|
{
|
||||||
|
if(_local_15 < 0)
|
||||||
|
{
|
||||||
|
_local_15 = (8 + _local_15);
|
||||||
|
}
|
||||||
|
else if(_local_15 > 7) _local_15 = (8 - _local_15);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_local_15 < 0)
|
||||||
|
{
|
||||||
|
_local_15 = (_local_15 + 8);
|
||||||
|
}
|
||||||
|
else if(_local_15 > 7) _local_15 = (_local_15 - 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._scale === AvatarScaleType.LARGE)
|
||||||
|
{
|
||||||
|
_local_11.x = _local_18.dx;
|
||||||
|
_local_11.y = _local_18.dy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_local_11.x = (_local_18.dx / 2);
|
||||||
|
_local_11.y = (_local_18.dy / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
frameCount = _local_18.animationFrame;
|
||||||
|
|
||||||
|
if(_local_18.action)
|
||||||
|
{
|
||||||
|
_local_7 = _local_18.action;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_local_18.type === AvatarAnimationLayerData.BODYPART)
|
||||||
|
{
|
||||||
|
if(_local_18.action != null)
|
||||||
|
{
|
||||||
|
_local_8 = _local_18.action;
|
||||||
|
}
|
||||||
|
|
||||||
|
_local_5 = _local_15;
|
||||||
|
}
|
||||||
|
else if(_local_18.type === AvatarAnimationLayerData.FX) _local_5 = _local_15;
|
||||||
|
|
||||||
|
_local_10 = _local_18.items;
|
||||||
|
}
|
||||||
|
|
||||||
|
_local_9 = _local_16.removeData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _local_12 = _local_4.getActionCache(_local_8);
|
||||||
|
|
||||||
|
if(!_local_12)
|
||||||
|
{
|
||||||
|
_local_12 = new AvatarImageActionCache();
|
||||||
|
_local_4.updateActionCache(_local_8, _local_12);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _local_13 = _local_12.getDirectionCache(_local_5);
|
||||||
|
|
||||||
|
if(!_local_13)
|
||||||
|
{
|
||||||
|
const _local_19 = this._structure.getParts(k, this._avatar.getFigure(), _local_8, this._geometryType, _local_5, _local_9, this._avatar, _local_10);
|
||||||
|
|
||||||
|
_local_13 = new AvatarImageDirectionCache(_local_19);
|
||||||
|
|
||||||
|
_local_12.updateDirectionCache(_local_5, _local_13);
|
||||||
|
}
|
||||||
|
|
||||||
|
let _local_14 = _local_13.getImageContainer(frameCount);
|
||||||
|
|
||||||
|
if(!_local_14)
|
||||||
|
{
|
||||||
|
const _local_20 = _local_13.getPartList();
|
||||||
|
|
||||||
|
_local_14 = this.renderBodyPart(_local_5, _local_20, frameCount, _local_7);
|
||||||
|
|
||||||
|
if(_local_14)
|
||||||
|
{
|
||||||
|
if(_local_14.isCacheable) _local_13.updateImageContainer(_local_14, frameCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset = this._structure.getFrameBodyPartOffset(_local_8, _local_5, frameCount, k);
|
||||||
|
|
||||||
|
_local_11.x += offset.x;
|
||||||
|
_local_11.y += offset.y;
|
||||||
|
|
||||||
|
_local_14.offset = _local_11;
|
||||||
|
|
||||||
|
return _local_14;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPartCache(k: string): AvatarImageBodyPartCache
|
||||||
|
{
|
||||||
|
let existing = this._cache.getValue(k);
|
||||||
|
|
||||||
|
if(!existing)
|
||||||
|
{
|
||||||
|
existing = new AvatarImageBodyPartCache();
|
||||||
|
|
||||||
|
this._cache.add(k, existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderBodyPart(direction: number, containers: AvatarImagePartContainer[], frameCount: number, _arg_4: IActiveActionData): AvatarImageBodyPartContainer
|
||||||
|
{
|
||||||
|
if(!containers || !containers.length) return null;
|
||||||
|
|
||||||
|
if(!this._canvas)
|
||||||
|
{
|
||||||
|
this._canvas = this._structure.getCanvas(this._scale, this._geometryType);
|
||||||
|
|
||||||
|
if(!this._canvas) return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isFlipped = AvatarDirectionAngle.DIRECTION_IS_FLIPPED[direction] || false;
|
||||||
|
let assetPartDefinition = _arg_4.definition.assetPartDefinition;
|
||||||
|
let isCacheable = true;
|
||||||
|
let containerIndex = (containers.length - 1);
|
||||||
|
|
||||||
|
while(containerIndex >= 0)
|
||||||
|
{
|
||||||
|
const container = containers[containerIndex];
|
||||||
|
|
||||||
|
let color = 16777215;
|
||||||
|
|
||||||
|
if(!((direction == 7) && ((container.partType === 'fc') || (container.partType === 'ey'))))
|
||||||
|
{
|
||||||
|
if(!((container.partType === 'ri') && !container.partId))
|
||||||
|
{
|
||||||
|
const partId = container.partId;
|
||||||
|
const animationFrame = container.getFrameDefinition(frameCount);
|
||||||
|
|
||||||
|
let partType = container.partType;
|
||||||
|
let frameNumber = 0;
|
||||||
|
|
||||||
|
if(animationFrame)
|
||||||
|
{
|
||||||
|
frameNumber = animationFrame.number;
|
||||||
|
|
||||||
|
if((animationFrame.assetPartDefinition) && (animationFrame.assetPartDefinition !== '')) assetPartDefinition = animationFrame.assetPartDefinition;
|
||||||
|
}
|
||||||
|
else frameNumber = container.getFrameIndex(frameCount);
|
||||||
|
|
||||||
|
let assetDirection = direction;
|
||||||
|
let flipH = false;
|
||||||
|
|
||||||
|
if(isFlipped)
|
||||||
|
{
|
||||||
|
if(((assetPartDefinition === 'wav') && (((partType === AvatarFigurePartType.LEFT_HAND) || (partType === AvatarFigurePartType.LEFT_SLEEVE)) || (partType === AvatarFigurePartType.LEFT_COAT_SLEEVE))) || ((assetPartDefinition === 'drk') && (((partType === AvatarFigurePartType.RIGHT_HAND) || (partType === AvatarFigurePartType.RIGHT_SLEEVE)) || (partType === AvatarFigurePartType.RIGHT_COAT_SLEEVE))) || ((assetPartDefinition === 'blw') && (partType === AvatarFigurePartType.RIGHT_HAND)) || ((assetPartDefinition === 'sig') && (partType === AvatarFigurePartType.LEFT_HAND)) || ((assetPartDefinition === 'respect') && (partType === AvatarFigurePartType.LEFT_HAND)) || (partType === AvatarFigurePartType.RIGHT_HAND_ITEM) || (partType === AvatarFigurePartType.LEFT_HAND_ITEM) || (partType === AvatarFigurePartType.CHEST_PRINT))
|
||||||
|
{
|
||||||
|
flipH = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(direction === 4) assetDirection = 2;
|
||||||
|
else if(direction === 5) assetDirection = 1;
|
||||||
|
else if(direction === 6) assetDirection = 0;
|
||||||
|
|
||||||
|
if(container.flippedPartType !== partType) partType = container.flippedPartType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let assetName = (this._scale + '_' + assetPartDefinition + '_' + partType + '_' + partId + '_' + assetDirection + '_' + frameNumber);
|
||||||
|
let asset = this._assets.getAsset(assetName);
|
||||||
|
|
||||||
|
if(!asset)
|
||||||
|
{
|
||||||
|
assetName = (this._scale + '_std_' + partType + '_' + partId + '_' + assetDirection + '_0');
|
||||||
|
asset = this._assets.getAsset(assetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(asset)
|
||||||
|
{
|
||||||
|
const texture = asset.texture;
|
||||||
|
|
||||||
|
if(!texture)
|
||||||
|
{
|
||||||
|
isCacheable = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(container.isColorable && container.color) color = container.color.rgb;
|
||||||
|
|
||||||
|
const offset = new Point(-(asset.x), -(asset.y));
|
||||||
|
|
||||||
|
if(flipH) offset.x = (offset.x + ((this._scale === AvatarScaleType.LARGE) ? 65 : 31));
|
||||||
|
|
||||||
|
this._unionImages.push(new ImageData(texture, asset.rectangle, offset, flipH, color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
containerIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this._unionImages.length) return null;
|
||||||
|
|
||||||
|
const imageData = this.createUnionImage(this._unionImages, isFlipped);
|
||||||
|
const canvasOffset = ((this._scale === AvatarScaleType.LARGE) ? (this._canvas.height - 16) : (this._canvas.height - 8));
|
||||||
|
const offset = new Point(-(imageData.regPoint.x), (canvasOffset - imageData.regPoint.y));
|
||||||
|
|
||||||
|
if(isFlipped && (assetPartDefinition !== 'lay')) offset.x = (offset.x + ((this._scale === AvatarScaleType.LARGE) ? 67 : 31));
|
||||||
|
|
||||||
|
let imageIndex = (this._unionImages.length - 1);
|
||||||
|
|
||||||
|
while(imageIndex >= 0)
|
||||||
|
{
|
||||||
|
const _local_17 = this._unionImages.pop();
|
||||||
|
|
||||||
|
if(_local_17) _local_17.dispose();
|
||||||
|
|
||||||
|
imageIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AvatarImageBodyPartContainer(imageData.texture, offset, isCacheable);
|
||||||
|
}
|
||||||
|
|
||||||
|
private convertColorToHex(k: number): string
|
||||||
|
{
|
||||||
|
let _local_2: string = (k * 0xFF).toString(16);
|
||||||
|
if(_local_2.length < 2)
|
||||||
|
{
|
||||||
|
_local_2 = ('0' + _local_2);
|
||||||
|
}
|
||||||
|
return _local_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createUnionImage(imageDatas: ImageData[], isFlipped: boolean): ImageData
|
||||||
|
{
|
||||||
|
const bounds = new Rectangle();
|
||||||
|
|
||||||
|
for(const data of imageDatas) data && bounds.enlarge(data.offsetRect);
|
||||||
|
|
||||||
|
const point = new Point(-(bounds.x), -(bounds.y));
|
||||||
|
const canvas = createCanvas(bounds.width, bounds.height);
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
|
for(const data of imageDatas)
|
||||||
|
{
|
||||||
|
if(!data) continue;
|
||||||
|
|
||||||
|
const texture = data.texture;
|
||||||
|
const color = data.colorTransform;
|
||||||
|
const flipH = (!(isFlipped && data.flipH) && (isFlipped || data.flipH));
|
||||||
|
const regPoint = point.clone();
|
||||||
|
|
||||||
|
regPoint.x -= data.regPoint.x;
|
||||||
|
regPoint.y -= data.regPoint.y;
|
||||||
|
|
||||||
|
if(isFlipped) regPoint.x = (canvas.width - (regPoint.x + data.rect.width));
|
||||||
|
|
||||||
|
let scale = 1;
|
||||||
|
let tx = 0;
|
||||||
|
let ty = 0;
|
||||||
|
|
||||||
|
if(flipH)
|
||||||
|
{
|
||||||
|
scale = -1;
|
||||||
|
tx = ((data.rect.x + data.rect.width) + regPoint.x);
|
||||||
|
ty = (regPoint.y - data.rect.y);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scale = 1;
|
||||||
|
tx = (regPoint.x - data.rect.x);
|
||||||
|
ty = (regPoint.y - data.rect.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
//ctx.save();
|
||||||
|
ctx.scale(scale, 1);
|
||||||
|
//ctx.transform(scale, 1, 0, 0, tx, ty);
|
||||||
|
ctx.drawImage(texture, tx, ty, texture.width, texture.height);
|
||||||
|
//ctx.restore();
|
||||||
|
|
||||||
|
// set the color
|
||||||
|
//console.log(canvas.toDataURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImageData(canvas, new Rectangle(0, 0, canvas.width, canvas.height), point, isFlipped, null);
|
||||||
|
}
|
||||||
|
}
|
60
src/app/avatar/cache/AvatarImageDirectionCache.ts
vendored
Normal file
60
src/app/avatar/cache/AvatarImageDirectionCache.ts
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { AvatarImageBodyPartContainer } from '../AvatarImageBodyPartContainer';
|
||||||
|
import { AvatarImagePartContainer } from '../AvatarImagePartContainer';
|
||||||
|
|
||||||
|
export class AvatarImageDirectionCache
|
||||||
|
{
|
||||||
|
private _partList: AvatarImagePartContainer[];
|
||||||
|
private _images: AdvancedMap<string, AvatarImageBodyPartContainer>;
|
||||||
|
|
||||||
|
constructor(k: AvatarImagePartContainer[])
|
||||||
|
{
|
||||||
|
this._partList = k;
|
||||||
|
this._images = new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
for(const image of this._images.getValues()) image && image.dispose();
|
||||||
|
|
||||||
|
this._images = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartList(): AvatarImagePartContainer[]
|
||||||
|
{
|
||||||
|
return this._partList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getImageContainer(k: number): AvatarImageBodyPartContainer
|
||||||
|
{
|
||||||
|
const existing = this._images.getValue(this.getCacheKey(k));
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateImageContainer(k: AvatarImageBodyPartContainer, _arg_2: number): void
|
||||||
|
{
|
||||||
|
const name = this.getCacheKey(_arg_2);
|
||||||
|
|
||||||
|
const existing = this._images.getValue(name);
|
||||||
|
|
||||||
|
if(existing) existing.dispose();
|
||||||
|
|
||||||
|
this._images.add(name, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCacheKey(k: number): string
|
||||||
|
{
|
||||||
|
let name = '';
|
||||||
|
|
||||||
|
for(const part of this._partList) name += (part.getCacheableKey(k) + '/');
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private debugInfo(k: string): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
59
src/app/avatar/cache/ImageData.ts
vendored
Normal file
59
src/app/avatar/cache/ImageData.ts
vendored
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { Canvas } from 'canvas';
|
||||||
|
import { Point, Rectangle } from '../../../core';
|
||||||
|
|
||||||
|
export class ImageData
|
||||||
|
{
|
||||||
|
private _texture: Canvas;
|
||||||
|
private _rect: Rectangle;
|
||||||
|
private _regPoint: Point;
|
||||||
|
private _flipH: boolean;
|
||||||
|
private _colorTransform: number;
|
||||||
|
|
||||||
|
constructor(texture: Canvas, rectangle: Rectangle, _arg_3: Point, flipH: boolean, color: number)
|
||||||
|
{
|
||||||
|
this._texture = texture;
|
||||||
|
this._rect = rectangle;
|
||||||
|
this._regPoint = _arg_3;
|
||||||
|
this._flipH = flipH;
|
||||||
|
this._colorTransform = color;
|
||||||
|
|
||||||
|
if(flipH) this._regPoint.x = (-(this._regPoint.x) + rectangle.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
this._texture = null;
|
||||||
|
this._regPoint = null;
|
||||||
|
this._colorTransform = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get texture(): Canvas
|
||||||
|
{
|
||||||
|
return this._texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get rect(): Rectangle
|
||||||
|
{
|
||||||
|
return this._rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get regPoint(): Point
|
||||||
|
{
|
||||||
|
return this._regPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get flipH(): boolean
|
||||||
|
{
|
||||||
|
return this._flipH;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get colorTransform(): number
|
||||||
|
{
|
||||||
|
return this._colorTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offsetRect(): Rectangle
|
||||||
|
{
|
||||||
|
return new Rectangle(-(this._regPoint.x), -(this._regPoint.y), this._rect.width, this._rect.height);
|
||||||
|
}
|
||||||
|
}
|
5
src/app/avatar/cache/index.ts
vendored
Normal file
5
src/app/avatar/cache/index.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './AvatarImageActionCache';
|
||||||
|
export * from './AvatarImageBodyPartCache';
|
||||||
|
export * from './AvatarImageCache';
|
||||||
|
export * from './AvatarImageDirectionCache';
|
||||||
|
export * from './ImageData';
|
827
src/app/avatar/data/HabboAvatarAnimations.ts
Normal file
827
src/app/avatar/data/HabboAvatarAnimations.ts
Normal file
@ -0,0 +1,827 @@
|
|||||||
|
export const HabboAvatarAnimations = {
|
||||||
|
'animations': [
|
||||||
|
{
|
||||||
|
'id': 'Move',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'bd',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bds',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ss',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lg',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'sh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lhs',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rhs',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ch',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wlk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'Wave',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'lh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lhs',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ch',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 2,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 3,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'Talk',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'hd',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'spk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'spk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'spk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'spk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fa',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'spk'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'spk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'Sign',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'lh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'sig'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'li',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'sig'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'Respect',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'lh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'respect',
|
||||||
|
'repeats': 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'respect',
|
||||||
|
'repeats': 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav',
|
||||||
|
'repeats': 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav',
|
||||||
|
'repeats': 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'wav',
|
||||||
|
'repeats': 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'wav',
|
||||||
|
'repeats': 15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'Blow',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'rh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'blw',
|
||||||
|
'repeats': 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 1,
|
||||||
|
'assetPartDefinition': 'blw',
|
||||||
|
'repeats': 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'drk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'drk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ri',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ey',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'std',
|
||||||
|
'repeats': 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'eyb',
|
||||||
|
'repeats': 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'std',
|
||||||
|
'repeats': 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'blw',
|
||||||
|
'repeats': 10
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'Laugh',
|
||||||
|
'parts': [
|
||||||
|
{
|
||||||
|
'setType': 'rh',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'blw'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'drk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'drk'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ri',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ey',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'std',
|
||||||
|
'repeats': 2
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc',
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'number': 0,
|
||||||
|
'assetPartDefinition': 'sml'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'offsets': {
|
||||||
|
'frames': [
|
||||||
|
{
|
||||||
|
'id': 0,
|
||||||
|
'directions': [
|
||||||
|
{
|
||||||
|
'id': 0,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 1,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 2,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 3,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 4,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 5,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 6,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 7,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 1,
|
||||||
|
'directions': [
|
||||||
|
{
|
||||||
|
'id': 0,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 1,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 2,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 3,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 4,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 5,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 6,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 7,
|
||||||
|
'bodyParts': [
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'dx': 0,
|
||||||
|
'dy': 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
1830
src/app/avatar/data/HabboAvatarGeometry.ts
Normal file
1830
src/app/avatar/data/HabboAvatarGeometry.ts
Normal file
File diff suppressed because it is too large
Load Diff
418
src/app/avatar/data/HabboAvatarPartSets.ts
Normal file
418
src/app/avatar/data/HabboAvatarPartSets.ts
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
export const HabboAvatarPartSets = {
|
||||||
|
'partSets': {
|
||||||
|
'partSet': [
|
||||||
|
{
|
||||||
|
'setType': 'ri',
|
||||||
|
'flippedSetType': 'ri'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ri',
|
||||||
|
'flippedSetType': 'ri'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rh',
|
||||||
|
'flippedSetType': 'lh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rhs',
|
||||||
|
'flippedSetType': 'lhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs',
|
||||||
|
'swim': '0',
|
||||||
|
'flippedSetType': 'ls'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc',
|
||||||
|
'flippedSetType': 'lc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bds'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ss'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'sh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ch'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'cp'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'cc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hrb',
|
||||||
|
'removeSetType': 'hr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'li',
|
||||||
|
'flippedSetType': 'li'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lh',
|
||||||
|
'flippedSetType': 'rh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lhs',
|
||||||
|
'flippedSetType': 'rhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls',
|
||||||
|
'flippedSetType': 'rs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc',
|
||||||
|
'flippedSetType': 'rc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'wa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ea'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ca'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ha'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'he'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'activePartSets': [
|
||||||
|
{
|
||||||
|
'id': 'figure',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'rh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bds'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ss'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'sh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ch'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'cp'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'cc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'wa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hrb'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ea'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ca'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ha'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'he'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'head',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'hd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hrb'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ea'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ha'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'he'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'speak',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'hd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hrb'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fa'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ha'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'gesture',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'ey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'eye',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'ey'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'handRight',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'rh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ri'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'handRightAndHead',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'rh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ri'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ey'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'fc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'hd'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'handLeft',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'lh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'li'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'walk',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'bd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bds'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ss'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rhs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ls'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rs'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'rc'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'sh'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'sit',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'bd'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'bds'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'ss'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'lg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'sh'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'setType': 'cc'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'id': 'itemRight',
|
||||||
|
'activeParts': [
|
||||||
|
{
|
||||||
|
'setType': 'ri'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
3
src/app/avatar/data/index.ts
Normal file
3
src/app/avatar/data/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './HabboAvatarAnimations';
|
||||||
|
export * from './HabboAvatarGeometry';
|
||||||
|
export * from './HabboAvatarPartSets';
|
127
src/app/avatar/enum/AvatarAction.ts
Normal file
127
src/app/avatar/enum/AvatarAction.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
export class AvatarAction
|
||||||
|
{
|
||||||
|
public static CARRY_OBJECT = 'cri';
|
||||||
|
public static DANCE = 'dance';
|
||||||
|
public static EFFECT = 'fx';
|
||||||
|
public static EXPRESSION = 'expression';
|
||||||
|
public static EXPRESSION_BLOW_A_KISS = 'blow';
|
||||||
|
public static EXPRESSION_CRY = 'cry';
|
||||||
|
public static EXPRESSION_IDLE = 'idle';
|
||||||
|
public static EXPRESSION_LAUGH = 'laugh';
|
||||||
|
public static EXPRESSION_RESPECT = 'respect';
|
||||||
|
public static EXPRESSION_RIDE_JUMP = 'ridejump';
|
||||||
|
public static EXPRESSION_SNOWBOARD_OLLIE = 'sbollie';
|
||||||
|
public static EXPRESSION_SNOWBORD_360 = 'sb360';
|
||||||
|
public static EXPRESSION_WAVE = 'wave';
|
||||||
|
public static GESTURE = 'gest';
|
||||||
|
public static GESTURE_AGGRAVATED = 'agr';
|
||||||
|
public static GESTURE_SAD = 'sad';
|
||||||
|
public static GESTURE_SMILE = 'sml';
|
||||||
|
public static GESTURE_SURPRISED = 'srp';
|
||||||
|
public static GUIDE_STATUS = 'guide';
|
||||||
|
public static MUTED = 'muted';
|
||||||
|
public static PET_GESTURE_BLINK = 'eyb';
|
||||||
|
public static PET_GESTURE_CRAZY = 'crz';
|
||||||
|
public static PET_GESTURE_JOY = 'joy';
|
||||||
|
public static PET_GESTURE_MISERABLE = 'mis';
|
||||||
|
public static PET_GESTURE_PUZZLED = 'puz';
|
||||||
|
public static PET_GESTURE_TONGUE = 'tng';
|
||||||
|
public static PLAYING_GAME = 'playing_game';
|
||||||
|
public static POSTURE = 'posture';
|
||||||
|
public static POSTURE_FLOAT = 'float';
|
||||||
|
public static POSTURE_LAY = 'lay';
|
||||||
|
public static POSTURE_SIT = 'sit';
|
||||||
|
public static POSTURE_STAND = 'std';
|
||||||
|
public static POSTURE_SWIM = 'swim';
|
||||||
|
public static POSTURE_WALK = 'mv';
|
||||||
|
public static SIGN = 'sign';
|
||||||
|
public static SLEEP = 'sleep';
|
||||||
|
public static SNOWWAR_DIE_BACK = 'swdieback';
|
||||||
|
public static SNOWWAR_DIE_FRONT = 'swdiefront';
|
||||||
|
public static SNOWWAR_PICK = 'swpick';
|
||||||
|
public static SNOWWAR_RUN = 'swrun';
|
||||||
|
public static SNOWWAR_THROW = 'swthrow';
|
||||||
|
public static TALK = 'talk';
|
||||||
|
public static BLINK = 'blink';
|
||||||
|
public static TYPING = 'typing';
|
||||||
|
public static USE_OBJECT = 'usei';
|
||||||
|
public static VOTE = 'vote';
|
||||||
|
|
||||||
|
public static GESTURE_MAP = [ '', AvatarAction.GESTURE_SMILE, AvatarAction.GESTURE_AGGRAVATED, AvatarAction.GESTURE_SURPRISED, AvatarAction.GESTURE_SAD, AvatarAction.PET_GESTURE_JOY, AvatarAction.PET_GESTURE_CRAZY, AvatarAction.PET_GESTURE_TONGUE, AvatarAction.PET_GESTURE_BLINK, AvatarAction.PET_GESTURE_MISERABLE, AvatarAction.PET_GESTURE_PUZZLED ];
|
||||||
|
|
||||||
|
public static EXPRESSION_MAP = [ '', AvatarAction.EXPRESSION_WAVE, AvatarAction.EXPRESSION_BLOW_A_KISS, AvatarAction.EXPRESSION_LAUGH, AvatarAction.EXPRESSION_CRY, AvatarAction.EXPRESSION_IDLE, AvatarAction.DANCE, AvatarAction.EXPRESSION_RESPECT, AvatarAction.EXPRESSION_SNOWBOARD_OLLIE, AvatarAction.EXPRESSION_SNOWBORD_360, AvatarAction.EXPRESSION_RIDE_JUMP ];
|
||||||
|
|
||||||
|
public static getExpressionTimeout(expressionId: number): number
|
||||||
|
{
|
||||||
|
expressionId = parseInt(expressionId as any);
|
||||||
|
|
||||||
|
switch(expressionId)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return 5000;
|
||||||
|
case 2:
|
||||||
|
return 1400;
|
||||||
|
case 3:
|
||||||
|
return 2000;
|
||||||
|
case 4:
|
||||||
|
return 2000;
|
||||||
|
case 5:
|
||||||
|
return 0;
|
||||||
|
case 6:
|
||||||
|
return 700;
|
||||||
|
case 7:
|
||||||
|
return 2000;
|
||||||
|
case 8:
|
||||||
|
return 1500;
|
||||||
|
case 9:
|
||||||
|
return 1500;
|
||||||
|
case 10:
|
||||||
|
return 1500;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getExpressionId(expression: string): number
|
||||||
|
{
|
||||||
|
return AvatarAction.EXPRESSION_MAP.indexOf(expression);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getExpression(expressionId: number): string
|
||||||
|
{
|
||||||
|
if(expressionId > AvatarAction.EXPRESSION_MAP.length) return null;
|
||||||
|
|
||||||
|
return AvatarAction.EXPRESSION_MAP[expressionId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getGestureId(gesture: string): number
|
||||||
|
{
|
||||||
|
return AvatarAction.GESTURE_MAP.indexOf(gesture);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getGesture(gestureId: number): string
|
||||||
|
{
|
||||||
|
if(gestureId > AvatarAction.GESTURE_MAP.length) return null;
|
||||||
|
|
||||||
|
return AvatarAction.GESTURE_MAP[gestureId];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static idToAvatarActionState(id: string): string
|
||||||
|
{
|
||||||
|
if(id === 'Lay') return 'lay';
|
||||||
|
if(id === 'Float') return 'float';
|
||||||
|
if(id === 'Swim') return 'swim';
|
||||||
|
if(id === 'Sit') return 'sit';
|
||||||
|
if(id === 'Respect') return 'respect';
|
||||||
|
if(id === 'Wave') return 'wave';
|
||||||
|
if(id === 'Idle') return 'idle';
|
||||||
|
if(id === 'Dance') return 'dance';
|
||||||
|
if(id === 'UseItem') return 'usei';
|
||||||
|
if(id === 'CarryItem') return 'cri';
|
||||||
|
if(id === 'Talk') return 'talk';
|
||||||
|
if(id === 'Sleep') return 'Sleep';
|
||||||
|
if(id === 'Move') return 'mv';
|
||||||
|
|
||||||
|
return 'std';
|
||||||
|
}
|
||||||
|
}
|
7
src/app/avatar/enum/AvatarDirectionAngle.ts
Normal file
7
src/app/avatar/enum/AvatarDirectionAngle.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export class AvatarDirectionAngle
|
||||||
|
{
|
||||||
|
public static DIRECTION_TO_ANGLE: number[] = [45, 90, 135, 180, 225, 270, 315, 0];
|
||||||
|
public static DIRECTION_IS_FLIPPED: boolean[] = [false, false, false, false, true, true, true, false];
|
||||||
|
public static MIN_DIRECTION: number = 0;
|
||||||
|
public static MAX_DIRECTION: number = 7;
|
||||||
|
}
|
29
src/app/avatar/enum/AvatarFigurePartType.ts
Normal file
29
src/app/avatar/enum/AvatarFigurePartType.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export class AvatarFigurePartType
|
||||||
|
{
|
||||||
|
public static BODY: string = 'bd';
|
||||||
|
public static SHOES: string = 'sh';
|
||||||
|
public static LEGS: string = 'lg';
|
||||||
|
public static CHEST: string = 'ch';
|
||||||
|
public static WAIST_ACCESSORY: string = 'wa';
|
||||||
|
public static CHEST_ACCESSORY: string = 'ca';
|
||||||
|
public static HEAD: string = 'hd';
|
||||||
|
public static HAIR: string = 'hr';
|
||||||
|
public static FACE_ACCESSORY: string = 'fa';
|
||||||
|
public static EYE_ACCESSORY: string = 'ea';
|
||||||
|
public static HEAD_ACCESSORY: string = 'ha';
|
||||||
|
public static HEAD_ACCESSORY_EXTRA: string = 'he';
|
||||||
|
public static COAT_CHEST: string = 'cc';
|
||||||
|
public static CHEST_PRINT: string = 'cp';
|
||||||
|
public static LEFT_HAND_ITEM: string = 'li';
|
||||||
|
public static LEFT_HAND: string = 'lh';
|
||||||
|
public static LEFT_SLEEVE: string = 'ls';
|
||||||
|
public static RIGHT_HAND: string = 'rh';
|
||||||
|
public static RIGHT_SLEEVE: string = 'rs';
|
||||||
|
public static FACE: string = 'fc';
|
||||||
|
public static EYES: string = 'ey';
|
||||||
|
public static HAIR_BIG: string = 'hrb';
|
||||||
|
public static RIGHT_HAND_ITEM: string = 'ri';
|
||||||
|
public static LEFT_COAT_SLEEVE: string = 'lc';
|
||||||
|
public static RIGHT_COAT_SLEEVE: string = 'rc';
|
||||||
|
public static FIGURE_SETS: string[] = [ AvatarFigurePartType.SHOES, AvatarFigurePartType.LEGS, AvatarFigurePartType.CHEST, AvatarFigurePartType.WAIST_ACCESSORY, AvatarFigurePartType.CHEST_ACCESSORY, AvatarFigurePartType.HEAD, AvatarFigurePartType.HAIR, AvatarFigurePartType.FACE_ACCESSORY, AvatarFigurePartType.EYE_ACCESSORY, AvatarFigurePartType.HEAD_ACCESSORY, AvatarFigurePartType.HEAD_ACCESSORY_EXTRA, AvatarFigurePartType.COAT_CHEST, AvatarFigurePartType.CHEST_PRINT ];
|
||||||
|
}
|
5
src/app/avatar/enum/AvatarScaleType.ts
Normal file
5
src/app/avatar/enum/AvatarScaleType.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export class AvatarScaleType
|
||||||
|
{
|
||||||
|
public static LARGE: string = 'h';
|
||||||
|
public static SMALL: string = 'sh';
|
||||||
|
}
|
6
src/app/avatar/enum/AvatarSetType.ts
Normal file
6
src/app/avatar/enum/AvatarSetType.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export class AvatarSetType
|
||||||
|
{
|
||||||
|
public static FULL: string = 'full';
|
||||||
|
public static HEAD: string = 'head';
|
||||||
|
public static BODY: string = 'body';
|
||||||
|
}
|
8
src/app/avatar/enum/GeometryType.ts
Normal file
8
src/app/avatar/enum/GeometryType.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export class GeometryType
|
||||||
|
{
|
||||||
|
public static VERTICAL: string = 'vertical';
|
||||||
|
public static SITTING: string = 'sitting';
|
||||||
|
public static HORIZONTAL: string = 'horizontal';
|
||||||
|
public static SWIM: string = 'swim';
|
||||||
|
public static SNOWWARS_HORIZONTAL: string = 'swhorizontal';
|
||||||
|
}
|
7
src/app/avatar/enum/RenderMode.ts
Normal file
7
src/app/avatar/enum/RenderMode.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export class RenderMode
|
||||||
|
{
|
||||||
|
public static TOOL: string = 'tool';
|
||||||
|
public static COMPONENT: string = 'component';
|
||||||
|
public static ONLINE_TOOL: string = 'online_tool';
|
||||||
|
public static LOCAL_ONLY: string = 'local_only';
|
||||||
|
}
|
7
src/app/avatar/enum/index.ts
Normal file
7
src/app/avatar/enum/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export * from './AvatarAction';
|
||||||
|
export * from './AvatarDirectionAngle';
|
||||||
|
export * from './AvatarFigurePartType';
|
||||||
|
export * from './AvatarScaleType';
|
||||||
|
export * from './AvatarSetType';
|
||||||
|
export * from './GeometryType';
|
||||||
|
export * from './RenderMode';
|
288
src/app/avatar/geometry/AvatarModelGeometry.ts
Normal file
288
src/app/avatar/geometry/AvatarModelGeometry.ts
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { IAvatarImage } from '../IAvatarImage';
|
||||||
|
import { AvatarCanvas } from '../structure';
|
||||||
|
import { AvatarSet } from './AvatarSet';
|
||||||
|
import { GeometryBodyPart } from './GeometryBodyPart';
|
||||||
|
import { Matrix4x4 } from './Matrix4x4';
|
||||||
|
import { Vector3D } from './Vector3D';
|
||||||
|
|
||||||
|
export class AvatarModelGeometry
|
||||||
|
{
|
||||||
|
private _camera: Vector3D;
|
||||||
|
private _avatarSet: AvatarSet;
|
||||||
|
private _geometryTypes: AdvancedMap<string, AdvancedMap<string, GeometryBodyPart>>;
|
||||||
|
private _itemIdToBodyPartMap: AdvancedMap<string, AdvancedMap<string, GeometryBodyPart>>;
|
||||||
|
private _transformation: Matrix4x4;
|
||||||
|
private _canvases: AdvancedMap<string, AdvancedMap<string, AvatarCanvas>>;
|
||||||
|
|
||||||
|
constructor(k: any)
|
||||||
|
{
|
||||||
|
this._camera = new Vector3D(0, 0, 10);
|
||||||
|
this._avatarSet = new AvatarSet(k.avatarSets[0]);
|
||||||
|
this._geometryTypes = new AdvancedMap();
|
||||||
|
this._itemIdToBodyPartMap = new AdvancedMap();
|
||||||
|
this._transformation = new Matrix4x4();
|
||||||
|
this._canvases = new AdvancedMap();
|
||||||
|
|
||||||
|
const camera = k.camera;
|
||||||
|
|
||||||
|
if(camera)
|
||||||
|
{
|
||||||
|
this._camera.x = parseFloat(camera.x);
|
||||||
|
this._camera.y = parseFloat(camera.y);
|
||||||
|
this._camera.z = parseFloat(camera.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(k.canvases && (k.canvases.length > 0))
|
||||||
|
{
|
||||||
|
for(const canvas of k.canvases)
|
||||||
|
{
|
||||||
|
if(!canvas) continue;
|
||||||
|
|
||||||
|
const scale = canvas.scale;
|
||||||
|
const geometries: AdvancedMap<string, AvatarCanvas> = new AdvancedMap();
|
||||||
|
|
||||||
|
if(canvas.geometries && (canvas.geometries.length > 0))
|
||||||
|
{
|
||||||
|
for(const geometry of canvas.geometries)
|
||||||
|
{
|
||||||
|
if(!geometry) continue;
|
||||||
|
|
||||||
|
const avatarCanvas = new AvatarCanvas(geometry, scale);
|
||||||
|
|
||||||
|
geometries.add(avatarCanvas.id, avatarCanvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._canvases.add(scale, geometries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(k.types && (k.types.length > 0))
|
||||||
|
{
|
||||||
|
for(const type of k.types)
|
||||||
|
{
|
||||||
|
if(!type) continue;
|
||||||
|
|
||||||
|
const bodyParts: AdvancedMap<string, GeometryBodyPart> = new AdvancedMap();
|
||||||
|
const itemIds: AdvancedMap<string, GeometryBodyPart> = new AdvancedMap();
|
||||||
|
|
||||||
|
if(type.bodyParts && (type.bodyParts.length > 0))
|
||||||
|
{
|
||||||
|
for(const bodyPart of type.bodyParts)
|
||||||
|
{
|
||||||
|
if(!bodyPart) continue;
|
||||||
|
|
||||||
|
const geometryBodyPart = new GeometryBodyPart(bodyPart);
|
||||||
|
|
||||||
|
bodyParts.add(geometryBodyPart.id, geometryBodyPart);
|
||||||
|
|
||||||
|
for(const part of geometryBodyPart.getPartIds(null))
|
||||||
|
{
|
||||||
|
itemIds.add(part, geometryBodyPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._geometryTypes.add(type.id, bodyParts);
|
||||||
|
this._itemIdToBodyPartMap.add(type.id, itemIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeDynamicItems(k: IAvatarImage): void
|
||||||
|
{
|
||||||
|
for(const geometry of this._geometryTypes.getValues())
|
||||||
|
{
|
||||||
|
if(!geometry) continue;
|
||||||
|
|
||||||
|
for(const part of geometry.getValues())
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
part.removeDynamicParts(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPartIdsInAvatarSet(k: string): string[]
|
||||||
|
{
|
||||||
|
const avatarSet = this._avatarSet.findAvatarSet(k);
|
||||||
|
|
||||||
|
if(!avatarSet) return [];
|
||||||
|
|
||||||
|
return avatarSet.getBodyParts();
|
||||||
|
}
|
||||||
|
|
||||||
|
public isMainAvatarSet(k: string): boolean
|
||||||
|
{
|
||||||
|
const avatarSet = this._avatarSet.findAvatarSet(k);
|
||||||
|
|
||||||
|
if(!avatarSet) return false;
|
||||||
|
|
||||||
|
return avatarSet.isMain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCanvas(k: string, _arg_2: string): AvatarCanvas
|
||||||
|
{
|
||||||
|
const canvas = this._canvases.getValue(k);
|
||||||
|
|
||||||
|
if(!canvas) return null;
|
||||||
|
|
||||||
|
return (canvas.getValue(_arg_2) || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private typeExists(k: string): boolean
|
||||||
|
{
|
||||||
|
const existing = this._geometryTypes.getValue(k);
|
||||||
|
|
||||||
|
if(existing) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasBodyPart(k: string, _arg_2: string): boolean
|
||||||
|
{
|
||||||
|
if(this.typeExists(k))
|
||||||
|
{
|
||||||
|
const existing = this._geometryTypes.getValue(k);
|
||||||
|
|
||||||
|
if(existing && existing.getValue(_arg_2)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBodyPartIDs(k: string): string[]
|
||||||
|
{
|
||||||
|
const parts = this.getBodyPartsOfType(k);
|
||||||
|
|
||||||
|
const types = [];
|
||||||
|
|
||||||
|
if(parts)
|
||||||
|
{
|
||||||
|
for(const part of parts.getValues())
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
types.push(part.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBodyPartsOfType(k: string): AdvancedMap<string, GeometryBodyPart>
|
||||||
|
{
|
||||||
|
if(this.typeExists(k)) return this._geometryTypes.getValue(k);
|
||||||
|
|
||||||
|
return new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPart(k: string, _arg_2: string): GeometryBodyPart
|
||||||
|
{
|
||||||
|
return (this.getBodyPartsOfType(k).getValue(_arg_2) || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPartOfItem(k: string, _arg_2: string, _arg_3:IAvatarImage): GeometryBodyPart
|
||||||
|
{
|
||||||
|
const itemIds = this._itemIdToBodyPartMap.getValue(k);
|
||||||
|
|
||||||
|
if(itemIds)
|
||||||
|
{
|
||||||
|
const part = itemIds.getValue(_arg_2);
|
||||||
|
|
||||||
|
if(part) return part;
|
||||||
|
|
||||||
|
const parts = this.getBodyPartsOfType(k);
|
||||||
|
|
||||||
|
if(parts)
|
||||||
|
{
|
||||||
|
for(const part of parts.getValues())
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
if(part.hasPart(_arg_2, _arg_3)) return part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBodyPartsInAvatarSet(k: AdvancedMap<string, GeometryBodyPart>, _arg_2: string): GeometryBodyPart[]
|
||||||
|
{
|
||||||
|
const parts = this.getBodyPartIdsInAvatarSet(_arg_2);
|
||||||
|
const geometryParts = [];
|
||||||
|
|
||||||
|
for(const part of parts)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
const bodyPart = k.getValue(part);
|
||||||
|
|
||||||
|
if(bodyPart)
|
||||||
|
{
|
||||||
|
geometryParts.push(bodyPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return geometryParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyPartsAtAngle(k: string, _arg_2: number, _arg_3: string): string[]
|
||||||
|
{
|
||||||
|
if(!_arg_3) return [];
|
||||||
|
|
||||||
|
const geometryParts = this.getBodyPartsOfType(_arg_3);
|
||||||
|
const parts = this.getBodyPartsInAvatarSet(geometryParts, k);
|
||||||
|
const sets: [ number, GeometryBodyPart ][] = [];
|
||||||
|
const ids: string[] = [];
|
||||||
|
|
||||||
|
this._transformation = Matrix4x4.getYRotationMatrix(_arg_2);
|
||||||
|
|
||||||
|
for(const part of parts)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
part.applyTransform(this._transformation);
|
||||||
|
|
||||||
|
sets.push([ part.getDistance(this._camera), part ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sets.sort((a, b) =>
|
||||||
|
{
|
||||||
|
const partA = a[0];
|
||||||
|
const partB = b[0];
|
||||||
|
|
||||||
|
if(partA < partB) return -1;
|
||||||
|
|
||||||
|
if(partA > partB) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
for(const set of sets)
|
||||||
|
{
|
||||||
|
if(!set) continue;
|
||||||
|
|
||||||
|
ids.push(set[1].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParts(k: string, _arg_2: string, _arg_3: number, _arg_4: any[], _arg_5:IAvatarImage): string[]
|
||||||
|
{
|
||||||
|
if(this.hasBodyPart(k, _arg_2))
|
||||||
|
{
|
||||||
|
const part = this.getBodyPartsOfType(k).getValue(_arg_2);
|
||||||
|
|
||||||
|
this._transformation = Matrix4x4.getYRotationMatrix(_arg_3);
|
||||||
|
|
||||||
|
return part.getParts(this._transformation, this._camera, _arg_4, _arg_5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
94
src/app/avatar/geometry/AvatarSet.ts
Normal file
94
src/app/avatar/geometry/AvatarSet.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
|
||||||
|
export class AvatarSet
|
||||||
|
{
|
||||||
|
private _id: string;
|
||||||
|
private _isMain: boolean;
|
||||||
|
private _avatarSets: AdvancedMap<string, AvatarSet>;
|
||||||
|
private _bodyParts: string[];
|
||||||
|
private _allBodyParts: string[];
|
||||||
|
|
||||||
|
constructor(k: any)
|
||||||
|
{
|
||||||
|
this._id = k.id;
|
||||||
|
this._isMain = k.main || false;
|
||||||
|
this._avatarSets = new AdvancedMap();
|
||||||
|
this._bodyParts = [];
|
||||||
|
this._allBodyParts = [];
|
||||||
|
|
||||||
|
if(k.avatarSets && (k.avatarSets.length > 0))
|
||||||
|
{
|
||||||
|
for(const avatarSet of k.avatarSets)
|
||||||
|
{
|
||||||
|
if(!avatarSet) continue;
|
||||||
|
|
||||||
|
const set = new AvatarSet(avatarSet);
|
||||||
|
|
||||||
|
this._avatarSets.add(set.id, set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(k.bodyParts && (k.bodyParts.length > 0))
|
||||||
|
{
|
||||||
|
for(const bodyPart of k.bodyParts)
|
||||||
|
{
|
||||||
|
if(!bodyPart) continue;
|
||||||
|
|
||||||
|
this._bodyParts.push(bodyPart.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let bodyParts = this._bodyParts.concat();
|
||||||
|
|
||||||
|
for(const avatarSet of this._avatarSets.getValues())
|
||||||
|
{
|
||||||
|
if(!avatarSet) continue;
|
||||||
|
|
||||||
|
bodyParts = bodyParts.concat(avatarSet.getBodyParts());
|
||||||
|
}
|
||||||
|
|
||||||
|
this._allBodyParts = bodyParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public findAvatarSet(k: string): AvatarSet
|
||||||
|
{
|
||||||
|
if(k === this._id) return this;
|
||||||
|
|
||||||
|
for(const avatarSet of this._avatarSets.getValues())
|
||||||
|
{
|
||||||
|
if(!avatarSet) continue;
|
||||||
|
|
||||||
|
if(!avatarSet.findAvatarSet(k)) continue;
|
||||||
|
|
||||||
|
return avatarSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getBodyParts(): string[]
|
||||||
|
{
|
||||||
|
return this._allBodyParts.concat();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isMain(): boolean
|
||||||
|
{
|
||||||
|
if(this._isMain) return true;
|
||||||
|
|
||||||
|
for(const avatarSet of this._avatarSets.getValues())
|
||||||
|
{
|
||||||
|
if(!avatarSet) continue;
|
||||||
|
|
||||||
|
if(!avatarSet.isMain) continue;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
195
src/app/avatar/geometry/GeometryBodyPart.ts
Normal file
195
src/app/avatar/geometry/GeometryBodyPart.ts
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { IAvatarImage } from '../IAvatarImage';
|
||||||
|
import { GeometryItem } from './GeometryItem';
|
||||||
|
import { Matrix4x4 } from './Matrix4x4';
|
||||||
|
import { Node3D } from './Node3D';
|
||||||
|
import { Vector3D } from './Vector3D';
|
||||||
|
|
||||||
|
export class GeometryBodyPart extends Node3D
|
||||||
|
{
|
||||||
|
private _id: string;
|
||||||
|
private _radius: number;
|
||||||
|
private _parts: AdvancedMap<string, GeometryItem>;
|
||||||
|
private _dynamicParts: AdvancedMap<IAvatarImage, { [index: string]: GeometryItem }>;
|
||||||
|
|
||||||
|
constructor(k: any)
|
||||||
|
{
|
||||||
|
super(parseFloat(k.x), parseFloat(k.y), parseFloat(k.z));
|
||||||
|
|
||||||
|
this._id = k.id;
|
||||||
|
this._radius = parseFloat(k.radius);
|
||||||
|
this._parts = new AdvancedMap();
|
||||||
|
this._dynamicParts = new AdvancedMap();
|
||||||
|
|
||||||
|
if(k.items && (k.items.length > 0))
|
||||||
|
{
|
||||||
|
for(const item of k.items)
|
||||||
|
{
|
||||||
|
if(!item) continue;
|
||||||
|
|
||||||
|
const geometryItem = new GeometryItem(item);
|
||||||
|
|
||||||
|
this._parts.add(geometryItem.id, geometryItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDynamicParts(k: IAvatarImage): GeometryItem[]
|
||||||
|
{
|
||||||
|
const existing = this._dynamicParts.getValue(k);
|
||||||
|
const parts: GeometryItem[] = [];
|
||||||
|
|
||||||
|
if(existing)
|
||||||
|
{
|
||||||
|
for(const index in existing)
|
||||||
|
{
|
||||||
|
const item = existing[index];
|
||||||
|
|
||||||
|
if(!item) continue;
|
||||||
|
|
||||||
|
parts.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartIds(k: IAvatarImage): string[]
|
||||||
|
{
|
||||||
|
const ids: string[] = [];
|
||||||
|
|
||||||
|
for(const part of this._parts.getValues())
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
ids.push(part.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(k)
|
||||||
|
{
|
||||||
|
const existing = this._dynamicParts.getValue(k);
|
||||||
|
|
||||||
|
if(existing)
|
||||||
|
{
|
||||||
|
for(const index in existing)
|
||||||
|
{
|
||||||
|
const part = existing[index];
|
||||||
|
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
ids.push(part.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeDynamicParts(k: IAvatarImage): boolean
|
||||||
|
{
|
||||||
|
this._dynamicParts.remove(k);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addPart(k: any, _arg_2: IAvatarImage): boolean
|
||||||
|
{
|
||||||
|
if(this.hasPart(k.id, _arg_2)) return false;
|
||||||
|
|
||||||
|
let existing = this._dynamicParts.getValue(_arg_2);
|
||||||
|
|
||||||
|
if(!existing)
|
||||||
|
{
|
||||||
|
existing = {};
|
||||||
|
|
||||||
|
this._dynamicParts.add(_arg_2, existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing[k.id] = new GeometryItem(k, true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasPart(k: string, _arg_2: IAvatarImage): boolean
|
||||||
|
{
|
||||||
|
let existingPart = (this._parts.getValue(k) || null);
|
||||||
|
|
||||||
|
if(!existingPart && (this._dynamicParts.getValue(_arg_2) !== undefined))
|
||||||
|
{
|
||||||
|
existingPart = (this._dynamicParts.getValue(_arg_2)[k] || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (existingPart !== null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getParts(k: Matrix4x4, _arg_2: Vector3D, _arg_3: any[], _arg_4: IAvatarImage): string[]
|
||||||
|
{
|
||||||
|
const parts: [ number, GeometryItem ][] = [];
|
||||||
|
|
||||||
|
for(const part of this._parts.getValues())
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
part.applyTransform(k);
|
||||||
|
|
||||||
|
parts.push([ part.getDistance(_arg_2), part ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingDynamic = this._dynamicParts.getValue(_arg_4);
|
||||||
|
|
||||||
|
if(existingDynamic)
|
||||||
|
{
|
||||||
|
for(const index in existingDynamic)
|
||||||
|
{
|
||||||
|
const part = existingDynamic[index];
|
||||||
|
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
part.applyTransform(k);
|
||||||
|
|
||||||
|
parts.push([ part.getDistance(_arg_2), part ]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parts.sort((a, b) =>
|
||||||
|
{
|
||||||
|
const partA = a[0];
|
||||||
|
const partB = b[0];
|
||||||
|
|
||||||
|
if(partA < partB) return -1;
|
||||||
|
|
||||||
|
if(partA > partB) return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
const partIds: string[] = [];
|
||||||
|
|
||||||
|
for(const part of parts)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
partIds.push(part[1].id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDistance(k: Vector3D): number
|
||||||
|
{
|
||||||
|
const _local_2 = Math.abs(((k.z - this.transformedLocation.z) - this._radius));
|
||||||
|
const _local_3 = Math.abs(((k.z - this.transformedLocation.z) + this._radius));
|
||||||
|
|
||||||
|
return Math.min(_local_2, _local_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get radius(): number
|
||||||
|
{
|
||||||
|
return this._radius;
|
||||||
|
}
|
||||||
|
}
|
55
src/app/avatar/geometry/GeometryItem.ts
Normal file
55
src/app/avatar/geometry/GeometryItem.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { Node3D } from './Node3D';
|
||||||
|
import { Vector3D } from './Vector3D';
|
||||||
|
|
||||||
|
export class GeometryItem extends Node3D
|
||||||
|
{
|
||||||
|
private _id: string;
|
||||||
|
private _radius: number;
|
||||||
|
private _normal: Vector3D;
|
||||||
|
private _isDoubleSided: boolean;
|
||||||
|
private _isDynamic: boolean;
|
||||||
|
|
||||||
|
constructor(k: any, _arg_2: boolean = false)
|
||||||
|
{
|
||||||
|
super(parseFloat(k.x), parseFloat(k.y), parseFloat(k.z));
|
||||||
|
|
||||||
|
this._id = k.id;
|
||||||
|
this._radius = parseFloat(k.radius);
|
||||||
|
this._normal = new Vector3D(parseFloat(k.nx), parseFloat(k.ny), parseFloat(k.nz));
|
||||||
|
this._isDoubleSided = k.double || false;
|
||||||
|
this._isDynamic = _arg_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDistance(k: Vector3D): number
|
||||||
|
{
|
||||||
|
const _local_2 = Math.abs(((k.z - this.transformedLocation.z) - this._radius));
|
||||||
|
const _local_3 = Math.abs(((k.z - this.transformedLocation.z) + this._radius));
|
||||||
|
|
||||||
|
return Math.min(_local_2, _local_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get normal(): Vector3D
|
||||||
|
{
|
||||||
|
return this._normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isDoubleSided(): boolean
|
||||||
|
{
|
||||||
|
return this._isDoubleSided;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string
|
||||||
|
{
|
||||||
|
return ((((this._id + ': ') + this.location) + ' - ') + this.transformedLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isDynamic(): boolean
|
||||||
|
{
|
||||||
|
return this._isDynamic;
|
||||||
|
}
|
||||||
|
}
|
133
src/app/avatar/geometry/Matrix4x4.ts
Normal file
133
src/app/avatar/geometry/Matrix4x4.ts
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { Vector3D } from './Vector3D';
|
||||||
|
|
||||||
|
export class Matrix4x4
|
||||||
|
{
|
||||||
|
public static IDENTITY:Matrix4x4 = new Matrix4x4(1, 0, 0, 0, 1, 0, 0, 0, 1);
|
||||||
|
private static TOLERANS: number = 1E-18;
|
||||||
|
|
||||||
|
private _data: number[];
|
||||||
|
|
||||||
|
constructor(k: number = 0, _arg_2: number = 0, _arg_3: number = 0, _arg_4: number = 0, _arg_5: number = 0, _arg_6: number = 0, _arg_7: number = 0, _arg_8: number = 0, _arg_9: number = 0)
|
||||||
|
{
|
||||||
|
this._data = [k, _arg_2, _arg_3, _arg_4, _arg_5, _arg_6, _arg_7, _arg_8, _arg_9];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getXRotationMatrix(k: number): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = ((k * Math.PI) / 180);
|
||||||
|
const _local_3 = Math.cos(_local_2);
|
||||||
|
const _local_4 = Math.sin(_local_2);
|
||||||
|
|
||||||
|
return new Matrix4x4(1, 0, 0, 0, _local_3, -(_local_4), 0, _local_4, _local_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getYRotationMatrix(k: number): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = ((k * Math.PI) / 180);
|
||||||
|
const _local_3 = Math.cos(_local_2);
|
||||||
|
const _local_4 = Math.sin(_local_2);
|
||||||
|
|
||||||
|
return new Matrix4x4(_local_3, 0, _local_4, 0, 1, 0, -(_local_4), 0, _local_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getZRotationMatrix(k: number): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = ((k * Math.PI) / 180);
|
||||||
|
const _local_3 = Math.cos(_local_2);
|
||||||
|
const _local_4 = Math.sin(_local_2);
|
||||||
|
|
||||||
|
return new Matrix4x4(_local_3, -(_local_4), 0, _local_4, _local_3, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public identity(): Matrix4x4
|
||||||
|
{
|
||||||
|
this._data = [1, 0, 0, 0, 1, 0, 0, 0, 1];
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public vectorMultiplication(k: Vector3D): Vector3D
|
||||||
|
{
|
||||||
|
const _local_2 = (((k.x * this._data[0]) + (k.y * this._data[3])) + (k.z * this._data[6]));
|
||||||
|
const _local_3 = (((k.x * this._data[1]) + (k.y * this._data[4])) + (k.z * this._data[7]));
|
||||||
|
const _local_4 = (((k.x * this._data[2]) + (k.y * this._data[5])) + (k.z * this._data[8]));
|
||||||
|
|
||||||
|
return new Vector3D(_local_2, _local_3, _local_4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public multiply(k:Matrix4x4): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = (((this._data[0] * k.data[0]) + (this._data[1] * k.data[3])) + (this._data[2] * k.data[6]));
|
||||||
|
const _local_3 = (((this._data[0] * k.data[1]) + (this._data[1] * k.data[4])) + (this._data[2] * k.data[7]));
|
||||||
|
const _local_4 = (((this._data[0] * k.data[2]) + (this._data[1] * k.data[5])) + (this._data[2] * k.data[8]));
|
||||||
|
const _local_5 = (((this._data[3] * k.data[0]) + (this._data[4] * k.data[3])) + (this._data[5] * k.data[6]));
|
||||||
|
const _local_6 = (((this._data[3] * k.data[1]) + (this._data[4] * k.data[4])) + (this._data[5] * k.data[7]));
|
||||||
|
const _local_7 = (((this._data[3] * k.data[2]) + (this._data[4] * k.data[5])) + (this._data[5] * k.data[8]));
|
||||||
|
const _local_8 = (((this._data[6] * k.data[0]) + (this._data[7] * k.data[3])) + (this._data[8] * k.data[6]));
|
||||||
|
const _local_9 = (((this._data[6] * k.data[1]) + (this._data[7] * k.data[4])) + (this._data[8] * k.data[7]));
|
||||||
|
const _local_10 = (((this._data[6] * k.data[2]) + (this._data[7] * k.data[5])) + (this._data[8] * k.data[8]));
|
||||||
|
|
||||||
|
return new Matrix4x4(_local_2, _local_3, _local_4, _local_5, _local_6, _local_7, _local_8, _local_9, _local_10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public scalarMultiply(k: number): void
|
||||||
|
{
|
||||||
|
let index = 0;
|
||||||
|
|
||||||
|
while(index < this._data.length)
|
||||||
|
{
|
||||||
|
this._data[index] = (this._data[index] * k);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public rotateX(k: number): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = ((k * Math.PI) / 180);
|
||||||
|
const _local_3 = Math.cos(_local_2);
|
||||||
|
const _local_4 = Math.sin(_local_2);
|
||||||
|
const _local_5 = new Matrix4x4(1, 0, 0, 0, _local_3, -(_local_4), 0, _local_4, _local_3);
|
||||||
|
|
||||||
|
return _local_5.multiply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public rotateY(k: number): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = ((k * Math.PI) / 180);
|
||||||
|
const _local_3 = Math.cos(_local_2);
|
||||||
|
const _local_4 = Math.sin(_local_2);
|
||||||
|
const _local_5 = new Matrix4x4(_local_3, 0, _local_4, 0, 1, 0, -(_local_4), 0, _local_3);
|
||||||
|
|
||||||
|
return _local_5.multiply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public rotateZ(k: number): Matrix4x4
|
||||||
|
{
|
||||||
|
const _local_2 = ((k * Math.PI) / 180);
|
||||||
|
const _local_3 = Math.cos(_local_2);
|
||||||
|
const _local_4 = Math.sin(_local_2);
|
||||||
|
const _local_5 = new Matrix4x4(_local_3, -(_local_4), 0, _local_4, _local_3, 0, 0, 0, 1);
|
||||||
|
|
||||||
|
return _local_5.multiply(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public skew(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public transpose(): Matrix4x4
|
||||||
|
{
|
||||||
|
return new Matrix4x4(this._data[0], this._data[3], this._data[6], this._data[1], this._data[4], this._data[7], this._data[2], this._data[5], this._data[8]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public equals(k: Matrix4x4): boolean
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get data(): number[]
|
||||||
|
{
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
}
|
33
src/app/avatar/geometry/Node3D.ts
Normal file
33
src/app/avatar/geometry/Node3D.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Matrix4x4 } from './Matrix4x4';
|
||||||
|
import { Vector3D } from './Vector3D';
|
||||||
|
|
||||||
|
export class Node3D
|
||||||
|
{
|
||||||
|
private _location: Vector3D;
|
||||||
|
private _transformedLocation: Vector3D;
|
||||||
|
private _needsTransformation: boolean;
|
||||||
|
|
||||||
|
constructor(k: number, _arg_2: number, _arg_3: number)
|
||||||
|
{
|
||||||
|
this._location = new Vector3D(k, _arg_2, _arg_3);
|
||||||
|
this._transformedLocation = new Vector3D();
|
||||||
|
this._needsTransformation = false;
|
||||||
|
|
||||||
|
if(((!(k == 0)) || (!(_arg_2 == 0))) || (!(_arg_3 == 0))) this._needsTransformation = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get location(): Vector3D
|
||||||
|
{
|
||||||
|
return this._location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get transformedLocation(): Vector3D
|
||||||
|
{
|
||||||
|
return this._transformedLocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public applyTransform(k: Matrix4x4): void
|
||||||
|
{
|
||||||
|
if(this._needsTransformation) this._transformedLocation = k.vectorMultiplication(this._location);
|
||||||
|
}
|
||||||
|
}
|
120
src/app/avatar/geometry/Vector3D.ts
Normal file
120
src/app/avatar/geometry/Vector3D.ts
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
export class Vector3D
|
||||||
|
{
|
||||||
|
private _x: number;
|
||||||
|
private _y: number;
|
||||||
|
private _z: number;
|
||||||
|
|
||||||
|
constructor(k: number = 0, _arg_2: number = 0, _arg_3: number = 0)
|
||||||
|
{
|
||||||
|
this._x = k;
|
||||||
|
this._y = _arg_2;
|
||||||
|
this._z = _arg_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static dot(k: Vector3D, _arg_2: Vector3D): number
|
||||||
|
{
|
||||||
|
return ((k.x * _arg_2.x) + (k.y * _arg_2.y)) + (k.z * _arg_2.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static cross(k: Vector3D, _arg_2: Vector3D): Vector3D
|
||||||
|
{
|
||||||
|
const _local_3 = new Vector3D();
|
||||||
|
|
||||||
|
_local_3.x = ((k.y * _arg_2.z) - (k.z * _arg_2.y));
|
||||||
|
_local_3.y = ((k.z * _arg_2.x) - (k.x * _arg_2.z));
|
||||||
|
_local_3.z = ((k.x * _arg_2.y) - (k.y * _arg_2.x));
|
||||||
|
|
||||||
|
return _local_3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static subtract(k: Vector3D, _arg_2: Vector3D): Vector3D
|
||||||
|
{
|
||||||
|
return new Vector3D((k.x - _arg_2.x), (k.y - _arg_2.y), (k.z - _arg_2.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public dot(k: Vector3D): number
|
||||||
|
{
|
||||||
|
return ((this._x * k.x) + (this._y * k.y)) + (this._z * k.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public cross(k: Vector3D): Vector3D
|
||||||
|
{
|
||||||
|
const _local_2 = new Vector3D();
|
||||||
|
|
||||||
|
_local_2.x = ((this._y * k.z) - (this._z * k.y));
|
||||||
|
_local_2.y = ((this._z * k.x) - (this._x * k.z));
|
||||||
|
_local_2.z = ((this._x * k.y) - (this._y * k.x));
|
||||||
|
|
||||||
|
return _local_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public subtract(k: Vector3D): void
|
||||||
|
{
|
||||||
|
this._x = (this._x - k.x);
|
||||||
|
this._y = (this._y - k.y);
|
||||||
|
this._z = (this._z - k.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public add(k: Vector3D): void
|
||||||
|
{
|
||||||
|
this._x = (this._x + k.x);
|
||||||
|
this._y = (this._y + k.y);
|
||||||
|
this._z = (this._z + k.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public normalize(): void
|
||||||
|
{
|
||||||
|
const k = (1 / this.length());
|
||||||
|
|
||||||
|
this._x = (this._x * k);
|
||||||
|
this._y = (this._y * k);
|
||||||
|
this._z = (this._z * k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public scaleBy(value: number): void
|
||||||
|
{
|
||||||
|
this._x *= value;
|
||||||
|
this._y *= value;
|
||||||
|
this._z *= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public length(): number
|
||||||
|
{
|
||||||
|
return Math.sqrt((((this._x * this._x) + (this._y * this._y)) + (this._z * this._z)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string
|
||||||
|
{
|
||||||
|
return (((((('Vector3D: (' + this._x) + ',') + this._y) + ',') + this._z) + ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
public get x(): number
|
||||||
|
{
|
||||||
|
return this._x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set x(k: number)
|
||||||
|
{
|
||||||
|
this._x = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get y(): number
|
||||||
|
{
|
||||||
|
return this._y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set y(k: number)
|
||||||
|
{
|
||||||
|
this._y = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get z(): number
|
||||||
|
{
|
||||||
|
return this._z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set z(k: number)
|
||||||
|
{
|
||||||
|
this._z = k;
|
||||||
|
}
|
||||||
|
}
|
7
src/app/avatar/geometry/index.ts
Normal file
7
src/app/avatar/geometry/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export * from './AvatarModelGeometry';
|
||||||
|
export * from './AvatarSet';
|
||||||
|
export * from './GeometryBodyPart';
|
||||||
|
export * from './GeometryItem';
|
||||||
|
export * from './Matrix4x4';
|
||||||
|
export * from './Node3D';
|
||||||
|
export * from './Vector3D';
|
24
src/app/avatar/index.ts
Normal file
24
src/app/avatar/index.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
export * from './actions';
|
||||||
|
export * from './alias';
|
||||||
|
export * from './animation';
|
||||||
|
export * from './AvatarAssetDownloadLibrary';
|
||||||
|
export * from './AvatarAssetDownloadManager';
|
||||||
|
export * from './AvatarFigureContainer';
|
||||||
|
export * from './AvatarImage';
|
||||||
|
export * from './AvatarImageBodyPartContainer';
|
||||||
|
export * from './AvatarImagePartContainer';
|
||||||
|
export * from './AvatarRenderManager';
|
||||||
|
export * from './AvatarStructure';
|
||||||
|
export * from './cache';
|
||||||
|
export * from './data';
|
||||||
|
export * from './EffectAssetDownloadLibrary';
|
||||||
|
export * from './EffectAssetDownloadManager';
|
||||||
|
export * from './enum';
|
||||||
|
export * from './FigureDataContainer';
|
||||||
|
export * from './geometry';
|
||||||
|
export * from './IAvatarFigureContainer';
|
||||||
|
export * from './IAvatarImage';
|
||||||
|
export * from './IAvatarRenderManager';
|
||||||
|
export * from './interfaces';
|
||||||
|
export * from './PlaceHolderAvatarImage';
|
||||||
|
export * from './structure';
|
8
src/app/avatar/interfaces/figuredata/IFigureData.ts
Normal file
8
src/app/avatar/interfaces/figuredata/IFigureData.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { IFigureDataPalette } from './IFigureDataPalette';
|
||||||
|
import { IFigureDataSetType } from './IFigureDataSetType';
|
||||||
|
|
||||||
|
export interface IFigureData
|
||||||
|
{
|
||||||
|
palettes?: IFigureDataPalette[];
|
||||||
|
setTypes?: IFigureDataSetType[];
|
||||||
|
}
|
8
src/app/avatar/interfaces/figuredata/IFigureDataColor.ts
Normal file
8
src/app/avatar/interfaces/figuredata/IFigureDataColor.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface IFigureDataColor
|
||||||
|
{
|
||||||
|
id?: number;
|
||||||
|
index?: number;
|
||||||
|
club?: number;
|
||||||
|
selectable?: boolean;
|
||||||
|
hexCode?: string;
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
export interface IFigureDataHiddenLayer
|
||||||
|
{
|
||||||
|
partType?: string;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
import { IFigureDataColor } from './IFigureDataColor';
|
||||||
|
|
||||||
|
export interface IFigureDataPalette
|
||||||
|
{
|
||||||
|
id?: number;
|
||||||
|
colors?: IFigureDataColor[];
|
||||||
|
}
|
8
src/app/avatar/interfaces/figuredata/IFigureDataPart.ts
Normal file
8
src/app/avatar/interfaces/figuredata/IFigureDataPart.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface IFigureDataPart
|
||||||
|
{
|
||||||
|
id?: number;
|
||||||
|
type?: string;
|
||||||
|
colorable?: boolean;
|
||||||
|
index?: number;
|
||||||
|
colorindex?: number;
|
||||||
|
}
|
15
src/app/avatar/interfaces/figuredata/IFigureDataSet.ts
Normal file
15
src/app/avatar/interfaces/figuredata/IFigureDataSet.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { IFigureDataHiddenLayer } from './IFigureDataHiddenLayer';
|
||||||
|
import { IFigureDataPart } from './IFigureDataPart';
|
||||||
|
|
||||||
|
export interface IFigureDataSet
|
||||||
|
{
|
||||||
|
id?: number;
|
||||||
|
gender?: string;
|
||||||
|
club?: number;
|
||||||
|
colorable?: boolean;
|
||||||
|
selectable?: boolean;
|
||||||
|
preselectable?: boolean;
|
||||||
|
sellable?: boolean;
|
||||||
|
parts?: IFigureDataPart[];
|
||||||
|
hiddenLayers?: IFigureDataHiddenLayer[];
|
||||||
|
}
|
12
src/app/avatar/interfaces/figuredata/IFigureDataSetType.ts
Normal file
12
src/app/avatar/interfaces/figuredata/IFigureDataSetType.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { IFigureDataSet } from './IFigureDataSet';
|
||||||
|
|
||||||
|
export interface IFigureDataSetType
|
||||||
|
{
|
||||||
|
type?: string;
|
||||||
|
paletteId?: number;
|
||||||
|
mandatory_m_0?: boolean;
|
||||||
|
mandatory_f_0?: boolean;
|
||||||
|
mandatory_m_1?: boolean;
|
||||||
|
mandatory_f_1?: boolean;
|
||||||
|
sets?: IFigureDataSet[];
|
||||||
|
}
|
7
src/app/avatar/interfaces/figuredata/index.ts
Normal file
7
src/app/avatar/interfaces/figuredata/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export * from './IFigureData';
|
||||||
|
export * from './IFigureDataColor';
|
||||||
|
export * from './IFigureDataHiddenLayer';
|
||||||
|
export * from './IFigureDataPalette';
|
||||||
|
export * from './IFigureDataPart';
|
||||||
|
export * from './IFigureDataSet';
|
||||||
|
export * from './IFigureDataSetType';
|
1
src/app/avatar/interfaces/index.ts
Normal file
1
src/app/avatar/interfaces/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './figuredata';
|
59
src/app/avatar/structure/AvatarAnimationData.ts
Normal file
59
src/app/avatar/structure/AvatarAnimationData.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { IActionDefinition } from '../actions';
|
||||||
|
import { AnimationAction } from './animation';
|
||||||
|
import { IFigureSetData } from './IFigureSetData';
|
||||||
|
|
||||||
|
export class AvatarAnimationData implements IFigureSetData
|
||||||
|
{
|
||||||
|
private _actions: AdvancedMap<string, AnimationAction>;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._actions = new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(data: any): boolean
|
||||||
|
{
|
||||||
|
if(data && (data.length > 0))
|
||||||
|
{
|
||||||
|
for(const animation of data)
|
||||||
|
{
|
||||||
|
if(!animation) continue;
|
||||||
|
|
||||||
|
const newAnimation = new AnimationAction(animation);
|
||||||
|
|
||||||
|
this._actions.add(newAnimation.id, newAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public appendJSON(k: any): boolean
|
||||||
|
{
|
||||||
|
for(const _local_2 of k.action)
|
||||||
|
{
|
||||||
|
this._actions.add(_local_2.id, new AnimationAction(_local_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getAction(action: IActionDefinition): AnimationAction
|
||||||
|
{
|
||||||
|
const existing = this._actions.getValue(action.id);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFrameCount(k: IActionDefinition): number
|
||||||
|
{
|
||||||
|
const animationAction = this.getAction(k);
|
||||||
|
|
||||||
|
if(!animationAction) return 0;
|
||||||
|
|
||||||
|
return animationAction.frameCount;
|
||||||
|
}
|
||||||
|
}
|
47
src/app/avatar/structure/AvatarCanvas.ts
Normal file
47
src/app/avatar/structure/AvatarCanvas.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { Point } from '../../../core';
|
||||||
|
import { AvatarScaleType } from '../enum';
|
||||||
|
|
||||||
|
export class AvatarCanvas
|
||||||
|
{
|
||||||
|
private _id: string;
|
||||||
|
private _width: number;
|
||||||
|
private _height: number;
|
||||||
|
private _offset: Point;
|
||||||
|
private _regPoint: Point;
|
||||||
|
|
||||||
|
constructor(k: any, _arg_2: string)
|
||||||
|
{
|
||||||
|
this._id = k.id;
|
||||||
|
this._width = k.width;
|
||||||
|
this._height = k.height;
|
||||||
|
this._offset = new Point(k.dx, k.dy);
|
||||||
|
|
||||||
|
if(_arg_2 == AvatarScaleType.LARGE) this._regPoint = new Point(((this._width - 64) / 2), 0);
|
||||||
|
else this._regPoint = new Point(((this._width - 32) / 2), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get width(): number
|
||||||
|
{
|
||||||
|
return this._width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get height(): number
|
||||||
|
{
|
||||||
|
return this._height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get offset(): Point
|
||||||
|
{
|
||||||
|
return this._offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get regPoint(): Point
|
||||||
|
{
|
||||||
|
return this._regPoint;
|
||||||
|
}
|
||||||
|
}
|
132
src/app/avatar/structure/FigureSetData.ts
Normal file
132
src/app/avatar/structure/FigureSetData.ts
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { IFigureData } from '../interfaces';
|
||||||
|
import { IFigurePartSet, IPalette, ISetType, Palette, SetType } from './figure';
|
||||||
|
import { IFigureSetData } from './IFigureSetData';
|
||||||
|
import { IStructureData } from './IStructureData';
|
||||||
|
|
||||||
|
export class FigureSetData implements IFigureSetData, IStructureData
|
||||||
|
{
|
||||||
|
private _palettes: AdvancedMap<string, Palette>;
|
||||||
|
private _setTypes: AdvancedMap<string, SetType>;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._palettes = new AdvancedMap();
|
||||||
|
this._setTypes = new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(data: IFigureData): boolean
|
||||||
|
{
|
||||||
|
if(!data) return false;
|
||||||
|
|
||||||
|
for(const palette of data.palettes)
|
||||||
|
{
|
||||||
|
const newPalette = new Palette(palette);
|
||||||
|
|
||||||
|
if(!newPalette) continue;
|
||||||
|
|
||||||
|
this._palettes.add(newPalette.id.toString(), newPalette);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const set of data.setTypes)
|
||||||
|
{
|
||||||
|
const newSet = new SetType(set);
|
||||||
|
|
||||||
|
if(!newSet) continue;
|
||||||
|
|
||||||
|
this._setTypes.add(newSet.type, newSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public injectJSON(data: IFigureData): void
|
||||||
|
{
|
||||||
|
for(const setType of data.setTypes)
|
||||||
|
{
|
||||||
|
const existingSetType = this._setTypes.getValue(setType.type);
|
||||||
|
|
||||||
|
if(existingSetType) existingSetType.cleanUp(setType);
|
||||||
|
else this._setTypes.add(setType.type, new SetType(setType));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.appendJSON(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public appendJSON(data: IFigureData): boolean
|
||||||
|
{
|
||||||
|
if(!data) return false;
|
||||||
|
|
||||||
|
for(const palette of data.palettes)
|
||||||
|
{
|
||||||
|
const id = palette.id.toString();
|
||||||
|
const existingPalette = this._palettes.getValue(id);
|
||||||
|
|
||||||
|
if(!existingPalette) this._palettes.add(id, new Palette(palette));
|
||||||
|
else existingPalette.append(palette);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(const setType of data.setTypes)
|
||||||
|
{
|
||||||
|
const type = setType.type;
|
||||||
|
const existingSetType = this._setTypes.getValue(type);
|
||||||
|
|
||||||
|
if(!existingSetType) this._setTypes.add(type, new SetType(setType));
|
||||||
|
else existingSetType.append(setType);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getMandatorySetTypeIds(k: string, _arg_2: number): string[]
|
||||||
|
{
|
||||||
|
const types: string[] = [];
|
||||||
|
|
||||||
|
for(const set of this._setTypes.getValues())
|
||||||
|
{
|
||||||
|
if(!set || !set.isMandatory(k, _arg_2)) continue;
|
||||||
|
|
||||||
|
types.push(set.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDefaultPartSet(k: string, _arg_2: string): IFigurePartSet
|
||||||
|
{
|
||||||
|
const setType = this._setTypes.getValue(k);
|
||||||
|
|
||||||
|
if(!setType) return null;
|
||||||
|
|
||||||
|
return setType.getDefaultPartSet(_arg_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSetType(k: string): ISetType
|
||||||
|
{
|
||||||
|
return (this._setTypes.getValue(k) || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPalette(k: number): IPalette
|
||||||
|
{
|
||||||
|
return (this._palettes.getValue(k.toString()) || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFigurePartSet(k: number): IFigurePartSet
|
||||||
|
{
|
||||||
|
for(const set of this._setTypes.getValues())
|
||||||
|
{
|
||||||
|
const partSet = set.getPartSet(k);
|
||||||
|
|
||||||
|
if(!partSet) continue;
|
||||||
|
|
||||||
|
return partSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
7
src/app/avatar/structure/IFigureSetData.ts
Normal file
7
src/app/avatar/structure/IFigureSetData.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { IFigureData } from '../interfaces';
|
||||||
|
|
||||||
|
export interface IFigureSetData
|
||||||
|
{
|
||||||
|
parse(data: any): boolean;
|
||||||
|
appendJSON(data: IFigureData): boolean;
|
||||||
|
}
|
11
src/app/avatar/structure/IStructureData.ts
Normal file
11
src/app/avatar/structure/IStructureData.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { IFigureData } from '../interfaces';
|
||||||
|
import { IFigurePartSet, IPalette, ISetType } from './figure';
|
||||||
|
|
||||||
|
export interface IStructureData
|
||||||
|
{
|
||||||
|
parse(data: any): boolean;
|
||||||
|
appendJSON(k: IFigureData): boolean;
|
||||||
|
getSetType(_arg_1: string): ISetType;
|
||||||
|
getPalette(_arg_1: number): IPalette;
|
||||||
|
getFigurePartSet(_arg_1: number): IFigurePartSet;
|
||||||
|
}
|
119
src/app/avatar/structure/PartSetsData.ts
Normal file
119
src/app/avatar/structure/PartSetsData.ts
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
import { AdvancedMap } from '../../../core';
|
||||||
|
import { ActionDefinition, IActionDefinition } from '../actions';
|
||||||
|
import { IFigureSetData } from './IFigureSetData';
|
||||||
|
import { ActivePartSet, PartDefinition } from './parts';
|
||||||
|
|
||||||
|
export class PartSetsData implements IFigureSetData
|
||||||
|
{
|
||||||
|
private _parts: AdvancedMap<string, PartDefinition>;
|
||||||
|
private _activePartSets: AdvancedMap<string, ActivePartSet>;
|
||||||
|
|
||||||
|
constructor()
|
||||||
|
{
|
||||||
|
this._parts = new AdvancedMap();
|
||||||
|
this._activePartSets = new AdvancedMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public parse(data: any): boolean
|
||||||
|
{
|
||||||
|
if(data.partSet && (data.partSet.length > 0))
|
||||||
|
{
|
||||||
|
for(const part of data.partSet)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
this._parts.add(part.setType, new PartDefinition(part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.activePartSets && (data.activePartSets.length > 0))
|
||||||
|
{
|
||||||
|
for(const activePart of data.activePartSets)
|
||||||
|
{
|
||||||
|
if(!activePart) continue;
|
||||||
|
|
||||||
|
this._activePartSets.add(activePart.id, new ActivePartSet(activePart));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public appendJSON(data: any): boolean
|
||||||
|
{
|
||||||
|
if(data.partSet && (data.partSet.length > 0))
|
||||||
|
{
|
||||||
|
for(const part of data.partSet)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
this._parts.add(part.setType, new PartDefinition(part));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.activePartSets && (data.activePartSets.length > 0))
|
||||||
|
{
|
||||||
|
for(const activePart of data.activePartSets)
|
||||||
|
{
|
||||||
|
if(!activePart) continue;
|
||||||
|
|
||||||
|
this._activePartSets.add(activePart.id, new ActivePartSet(activePart));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActiveParts(k:IActionDefinition): string[]
|
||||||
|
{
|
||||||
|
const activePartSet = this._activePartSets.getValue(k.activePartSet);
|
||||||
|
|
||||||
|
if(!activePartSet) return [];
|
||||||
|
|
||||||
|
return activePartSet.parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPartDefinition(part: string): PartDefinition
|
||||||
|
{
|
||||||
|
const existing = this._parts.getValue(part);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addPartDefinition(k: any): PartDefinition
|
||||||
|
{
|
||||||
|
const _local_2 = k.setType as string;
|
||||||
|
|
||||||
|
let existing = this._parts.getValue(_local_2);
|
||||||
|
|
||||||
|
if(!existing)
|
||||||
|
{
|
||||||
|
existing = new PartDefinition(k);
|
||||||
|
|
||||||
|
this._parts.add(_local_2, existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getActivePartSet(k: ActionDefinition): ActivePartSet
|
||||||
|
{
|
||||||
|
const existing = this._activePartSets.getValue(k.activePartSet);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get parts(): AdvancedMap<string, PartDefinition>
|
||||||
|
{
|
||||||
|
return this._parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get activePartSets(): AdvancedMap<string, ActivePartSet>
|
||||||
|
{
|
||||||
|
return this._activePartSets;
|
||||||
|
}
|
||||||
|
}
|
138
src/app/avatar/structure/animation/AnimationAction.ts
Normal file
138
src/app/avatar/structure/animation/AnimationAction.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { AdvancedMap, Point } from '../../../../core';
|
||||||
|
import { AnimationActionPart } from './AnimationActionPart';
|
||||||
|
|
||||||
|
export class AnimationAction
|
||||||
|
{
|
||||||
|
public static DEFAULT_OFFSET: Point = new Point(0, 0);
|
||||||
|
|
||||||
|
private _id: string;
|
||||||
|
private _actionParts: AdvancedMap<string, AnimationActionPart>;
|
||||||
|
private _bodyPartOffsets: AdvancedMap<number, AdvancedMap<number, AdvancedMap<string, Point>>>;
|
||||||
|
private _frameCount: number;
|
||||||
|
private _frameIndexes: number[];
|
||||||
|
|
||||||
|
constructor(data: any)
|
||||||
|
{
|
||||||
|
this._id = data.id;
|
||||||
|
this._actionParts = new AdvancedMap();
|
||||||
|
this._bodyPartOffsets = new AdvancedMap();
|
||||||
|
this._frameCount = 0;
|
||||||
|
this._frameIndexes = [];
|
||||||
|
|
||||||
|
if(data.parts && (data.parts.length > 0))
|
||||||
|
{
|
||||||
|
for(const part of data.parts)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
const newPart = new AnimationActionPart(part);
|
||||||
|
|
||||||
|
this._actionParts.add(part.setType, newPart);
|
||||||
|
|
||||||
|
this._frameCount = Math.max(this._frameCount, newPart.frames.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.offsets && data.offsets.frames && (data.offsets.frames.length > 0))
|
||||||
|
{
|
||||||
|
for(const frame of data.offsets.frames)
|
||||||
|
{
|
||||||
|
if(!frame) continue;
|
||||||
|
|
||||||
|
const frameId = frame.id;
|
||||||
|
|
||||||
|
this._frameCount = Math.max(this._frameCount, frameId);
|
||||||
|
|
||||||
|
const directions: AdvancedMap<number, AdvancedMap<string, Point>> = new AdvancedMap();
|
||||||
|
|
||||||
|
this._bodyPartOffsets.add(frameId, directions);
|
||||||
|
|
||||||
|
if(frame.directions && (frame.directions.length > 0))
|
||||||
|
{
|
||||||
|
for(const direction of frame.directions)
|
||||||
|
{
|
||||||
|
if(!direction) continue;
|
||||||
|
|
||||||
|
const directionId = direction.id;
|
||||||
|
|
||||||
|
const offsets: AdvancedMap<string, Point> = new AdvancedMap();
|
||||||
|
|
||||||
|
directions.add(directionId, offsets);
|
||||||
|
|
||||||
|
if(direction.bodyParts && (direction.bodyParts.length > 0))
|
||||||
|
{
|
||||||
|
for(const part of direction.bodyParts)
|
||||||
|
{
|
||||||
|
if(!part) continue;
|
||||||
|
|
||||||
|
const partId = part.id;
|
||||||
|
|
||||||
|
let dx = 0;
|
||||||
|
let dy = 0;
|
||||||
|
|
||||||
|
if(part.dx !== undefined) dx = part.dx;
|
||||||
|
if(part.dy !== undefined) dy = part.dy;
|
||||||
|
|
||||||
|
offsets.add(partId, new Point(dx, dy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._frameIndexes.push(frameId);
|
||||||
|
|
||||||
|
if(frame.repeats !== undefined)
|
||||||
|
{
|
||||||
|
let repeats = frame.repeats || 0;
|
||||||
|
|
||||||
|
if(repeats > 1) while(--repeats > 0) this._frameIndexes.push(frameId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPart(type: string): AnimationActionPart
|
||||||
|
{
|
||||||
|
if(!type) return null;
|
||||||
|
|
||||||
|
const existing = this._actionParts.getValue(type);
|
||||||
|
|
||||||
|
if(!existing) return null;
|
||||||
|
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getFrameBodyPartOffset(frameId: number, frameCount: number, partId: string): Point
|
||||||
|
{
|
||||||
|
const frameIndex = (frameCount % this._frameIndexes.length);
|
||||||
|
const frameNumber = this._frameIndexes[frameIndex];
|
||||||
|
const offsets = this._bodyPartOffsets.getValue(frameNumber);
|
||||||
|
|
||||||
|
if(!offsets) return AnimationAction.DEFAULT_OFFSET;
|
||||||
|
|
||||||
|
const frameOffset = offsets.getValue(frameId);
|
||||||
|
|
||||||
|
if(!frameOffset) return AnimationAction.DEFAULT_OFFSET;
|
||||||
|
|
||||||
|
const offset = frameOffset.getValue(partId);
|
||||||
|
|
||||||
|
if(!offset) return AnimationAction.DEFAULT_OFFSET;
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): string
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get parts(): AdvancedMap<string, AnimationActionPart>
|
||||||
|
{
|
||||||
|
return this._actionParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get frameCount(): number
|
||||||
|
{
|
||||||
|
return this._frameCount;
|
||||||
|
}
|
||||||
|
}
|
30
src/app/avatar/structure/animation/AnimationActionPart.ts
Normal file
30
src/app/avatar/structure/animation/AnimationActionPart.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { AvatarAnimationFrame } from './AvatarAnimationFrame';
|
||||||
|
|
||||||
|
export class AnimationActionPart
|
||||||
|
{
|
||||||
|
private _frames: AvatarAnimationFrame[];
|
||||||
|
|
||||||
|
constructor(data: any)
|
||||||
|
{
|
||||||
|
this._frames = [];
|
||||||
|
|
||||||
|
if(data.frames && (data.frames.length > 0))
|
||||||
|
{
|
||||||
|
for(const frame of data.frames)
|
||||||
|
{
|
||||||
|
if(!frame) continue;
|
||||||
|
|
||||||
|
this._frames.push(new AvatarAnimationFrame(frame));
|
||||||
|
|
||||||
|
let repeats = frame.repeats || 0;
|
||||||
|
|
||||||
|
if(repeats > 1) while(--repeats > 0) this._frames.push(this._frames[(this._frames.length - 1)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get frames(): AvatarAnimationFrame[]
|
||||||
|
{
|
||||||
|
return this._frames;
|
||||||
|
}
|
||||||
|
}
|
21
src/app/avatar/structure/animation/AvatarAnimationFrame.ts
Normal file
21
src/app/avatar/structure/animation/AvatarAnimationFrame.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export class AvatarAnimationFrame
|
||||||
|
{
|
||||||
|
private _number: number;
|
||||||
|
private _assetPartDefinition: string;
|
||||||
|
|
||||||
|
constructor(data: any)
|
||||||
|
{
|
||||||
|
this._number = data.number;
|
||||||
|
this._assetPartDefinition = data.assetPartDefinition || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get number(): number
|
||||||
|
{
|
||||||
|
return this._number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get assetPartDefinition(): string
|
||||||
|
{
|
||||||
|
return this._assetPartDefinition;
|
||||||
|
}
|
||||||
|
}
|
3
src/app/avatar/structure/animation/index.ts
Normal file
3
src/app/avatar/structure/animation/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './AnimationAction';
|
||||||
|
export * from './AnimationActionPart';
|
||||||
|
export * from './AvatarAnimationFrame';
|
59
src/app/avatar/structure/figure/FigurePart.ts
Normal file
59
src/app/avatar/structure/figure/FigurePart.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { IFigureDataPart } from '../../interfaces';
|
||||||
|
import { IFigurePart } from './IFigurePart';
|
||||||
|
|
||||||
|
export class FigurePart implements IFigurePart
|
||||||
|
{
|
||||||
|
private _id: number;
|
||||||
|
private _type: string;
|
||||||
|
private _breed: number;
|
||||||
|
private _index: number;
|
||||||
|
private _colorLayerIndex: number;
|
||||||
|
private _paletteMapId: number;
|
||||||
|
|
||||||
|
constructor(data: IFigureDataPart)
|
||||||
|
{
|
||||||
|
if(!data) throw new Error('invalid_data');
|
||||||
|
|
||||||
|
this._id = data.id;
|
||||||
|
this._type = data.type;
|
||||||
|
this._index = data.index;
|
||||||
|
this._colorLayerIndex = data.colorindex;
|
||||||
|
this._paletteMapId = -1;
|
||||||
|
this._breed = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get type(): string
|
||||||
|
{
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get breed(): number
|
||||||
|
{
|
||||||
|
return this._breed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get index(): number
|
||||||
|
{
|
||||||
|
return this._index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get colorLayerIndex(): number
|
||||||
|
{
|
||||||
|
return this._colorLayerIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get paletteMap(): number
|
||||||
|
{
|
||||||
|
return this._paletteMapId;
|
||||||
|
}
|
||||||
|
}
|
143
src/app/avatar/structure/figure/FigurePartSet.ts
Normal file
143
src/app/avatar/structure/figure/FigurePartSet.ts
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { IFigureDataSet } from '../../interfaces';
|
||||||
|
import { FigurePart } from './FigurePart';
|
||||||
|
import { IFigurePart } from './IFigurePart';
|
||||||
|
import { IFigurePartSet } from './IFigurePartSet';
|
||||||
|
|
||||||
|
export class FigurePartSet implements IFigurePartSet
|
||||||
|
{
|
||||||
|
private _id: number;
|
||||||
|
private _type: string;
|
||||||
|
private _gender: string;
|
||||||
|
private _clubLevel: number;
|
||||||
|
private _isColorable: boolean;
|
||||||
|
private _isSelectable: boolean;
|
||||||
|
private _parts: IFigurePart[];
|
||||||
|
private _hiddenLayers: string[];
|
||||||
|
private _isPreSelectable: boolean;
|
||||||
|
private _isSellable: boolean;
|
||||||
|
|
||||||
|
constructor(type: string, data: IFigureDataSet)
|
||||||
|
{
|
||||||
|
if(!type || !data) throw new Error('invalid_data');
|
||||||
|
|
||||||
|
this._id = data.id;
|
||||||
|
this._type = type;
|
||||||
|
this._gender = data.gender;
|
||||||
|
this._clubLevel = data.club;
|
||||||
|
this._isColorable = data.colorable;
|
||||||
|
this._isSelectable = data.selectable;
|
||||||
|
this._parts = [];
|
||||||
|
this._hiddenLayers = [];
|
||||||
|
this._isPreSelectable = data.preselectable;
|
||||||
|
this._isSellable = data.sellable;
|
||||||
|
|
||||||
|
for(const part of data.parts)
|
||||||
|
{
|
||||||
|
const newPart = new FigurePart(part);
|
||||||
|
const partIndex = this.getPartIndex(newPart);
|
||||||
|
|
||||||
|
if(partIndex !== -1) this._parts.splice(partIndex, 0, newPart);
|
||||||
|
else this._parts.push(newPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.hiddenLayers)
|
||||||
|
{
|
||||||
|
for(const hiddenLayer of data.hiddenLayers) this._hiddenLayers.push(hiddenLayer.partType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void
|
||||||
|
{
|
||||||
|
for(const part of this._parts)
|
||||||
|
{
|
||||||
|
const figurePart = (part as FigurePart);
|
||||||
|
|
||||||
|
figurePart.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._parts = null;
|
||||||
|
this._hiddenLayers = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPartIndex(part: FigurePart): number
|
||||||
|
{
|
||||||
|
const totalParts = this._parts.length;
|
||||||
|
|
||||||
|
if(!totalParts) return -1;
|
||||||
|
|
||||||
|
for(let i = 0; i < totalParts; i++)
|
||||||
|
{
|
||||||
|
const existingPart = this._parts[i];
|
||||||
|
|
||||||
|
if(!existingPart) continue;
|
||||||
|
|
||||||
|
if(existingPart.type !== part.type || existingPart.index > part.index) continue;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getPart(k: string, _arg_2: number): IFigurePart
|
||||||
|
{
|
||||||
|
for(const part of this._parts)
|
||||||
|
{
|
||||||
|
if((part.type !== k) || (part.id !== _arg_2)) continue;
|
||||||
|
|
||||||
|
return part;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get type(): string
|
||||||
|
{
|
||||||
|
return this._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get gender(): string
|
||||||
|
{
|
||||||
|
return this._gender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get clubLevel(): number
|
||||||
|
{
|
||||||
|
return this._clubLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isColorable(): boolean
|
||||||
|
{
|
||||||
|
return this._isColorable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isSelectable(): boolean
|
||||||
|
{
|
||||||
|
return this._isSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get parts(): IFigurePart[]
|
||||||
|
{
|
||||||
|
return this._parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get hiddenLayers(): string[]
|
||||||
|
{
|
||||||
|
return this._hiddenLayers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPreSelectable(): boolean
|
||||||
|
{
|
||||||
|
return this._isPreSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isSellable(): boolean
|
||||||
|
{
|
||||||
|
return this._isSellable;
|
||||||
|
}
|
||||||
|
}
|
9
src/app/avatar/structure/figure/IFigurePart.ts
Normal file
9
src/app/avatar/structure/figure/IFigurePart.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export interface IFigurePart
|
||||||
|
{
|
||||||
|
id: number;
|
||||||
|
type: string;
|
||||||
|
breed: number;
|
||||||
|
index: number;
|
||||||
|
colorLayerIndex: number;
|
||||||
|
paletteMap: number;
|
||||||
|
}
|
16
src/app/avatar/structure/figure/IFigurePartSet.ts
Normal file
16
src/app/avatar/structure/figure/IFigurePartSet.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { IFigurePart } from './IFigurePart';
|
||||||
|
|
||||||
|
export interface IFigurePartSet
|
||||||
|
{
|
||||||
|
getPart(_arg_1: string, _arg_2: number): IFigurePart;
|
||||||
|
id: number;
|
||||||
|
type: string;
|
||||||
|
gender: string;
|
||||||
|
clubLevel: number;
|
||||||
|
isColorable: boolean;
|
||||||
|
isSelectable: boolean;
|
||||||
|
parts: IFigurePart[];
|
||||||
|
hiddenLayers: string[];
|
||||||
|
isPreSelectable: boolean;
|
||||||
|
isSellable: boolean;
|
||||||
|
}
|
9
src/app/avatar/structure/figure/IPalette.ts
Normal file
9
src/app/avatar/structure/figure/IPalette.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { AdvancedMap } from '../../../../core';
|
||||||
|
import { IPartColor } from './IPartColor';
|
||||||
|
|
||||||
|
export interface IPalette
|
||||||
|
{
|
||||||
|
getColor(id: number): IPartColor;
|
||||||
|
id: number;
|
||||||
|
colors: AdvancedMap<string, IPartColor>;
|
||||||
|
}
|
8
src/app/avatar/structure/figure/IPartColor.ts
Normal file
8
src/app/avatar/structure/figure/IPartColor.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export interface IPartColor
|
||||||
|
{
|
||||||
|
id: number;
|
||||||
|
index: number;
|
||||||
|
clubLevel: number;
|
||||||
|
isSelectable: boolean;
|
||||||
|
rgb: number;
|
||||||
|
}
|
12
src/app/avatar/structure/figure/ISetType.ts
Normal file
12
src/app/avatar/structure/figure/ISetType.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { AdvancedMap } from '../../../../core';
|
||||||
|
import { IFigurePartSet } from './IFigurePartSet';
|
||||||
|
|
||||||
|
export interface ISetType
|
||||||
|
{
|
||||||
|
getPartSet(_arg_1: number): IFigurePartSet;
|
||||||
|
isMandatory(_arg_1: string, _arg_2: number): boolean;
|
||||||
|
optionalFromClubLevel(_arg_1: string): number;
|
||||||
|
type: string;
|
||||||
|
paletteID: number;
|
||||||
|
partSets: AdvancedMap<string, IFigurePartSet>;
|
||||||
|
}
|
48
src/app/avatar/structure/figure/Palette.ts
Normal file
48
src/app/avatar/structure/figure/Palette.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { AdvancedMap } from '../../../../core';
|
||||||
|
import { IFigureDataPalette } from '../../interfaces';
|
||||||
|
import { IPalette } from './IPalette';
|
||||||
|
import { IPartColor } from './IPartColor';
|
||||||
|
import { PartColor } from './PartColor';
|
||||||
|
|
||||||
|
export class Palette implements IPalette
|
||||||
|
{
|
||||||
|
private _id: number;
|
||||||
|
private _colors: AdvancedMap<string, IPartColor>;
|
||||||
|
|
||||||
|
constructor(data: IFigureDataPalette)
|
||||||
|
{
|
||||||
|
if(!data) throw new Error('invalid_data');
|
||||||
|
|
||||||
|
this._id = data.id;
|
||||||
|
this._colors = new AdvancedMap();
|
||||||
|
|
||||||
|
this.append(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public append(data: IFigureDataPalette): void
|
||||||
|
{
|
||||||
|
for(const color of data.colors)
|
||||||
|
{
|
||||||
|
const newColor = new PartColor(color);
|
||||||
|
|
||||||
|
this._colors.add(color.id.toString(), newColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public getColor(id: number): IPartColor
|
||||||
|
{
|
||||||
|
if((id === undefined) || id < 0) return null;
|
||||||
|
|
||||||
|
return (this._colors.getValue(id.toString()) || null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get id(): number
|
||||||
|
{
|
||||||
|
return this._id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get colors(): AdvancedMap<string, IPartColor>
|
||||||
|
{
|
||||||
|
return this._colors;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user