This commit is contained in:
Bill 2021-02-17 00:14:07 -05:00
parent 13cc7f601d
commit 85b7471772
138 changed files with 9432 additions and 5238 deletions

16
.editorconfig Normal file
View 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

132
.eslintrc.json Normal file
View File

@ -0,0 +1,132 @@
{
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": [
"error",
4,
{
"SwitchCase": 1
}
],
"no-trailing-spaces": [
"error",
{
"skipBlankLines": false,
"ignoreComments": true
}
],
"linebreak-style": [
"off"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"brace-style": [
"error",
"allman"
],
"object-curly-spacing": [
"error",
"always"
],
"keyword-spacing": [
"error",
{
"overrides":
{
"if":
{
"after": false
},
"for":
{
"after": false
},
"while":
{
"after": false
},
"switch":
{
"after": false
}
}
}
],
"@typescript-eslint/no-explicit-any": [
"off"
],
"@typescript-eslint/explicit-module-boundary-types": [
"off",
{
"allowedNames": [
"getMessageArray"
]
}
],
"@typescript-eslint/ban-ts-comment": [
"off"
],
"@typescript-eslint/no-empty-function": [
"error",
{
"allow": [
"functions",
"arrowFunctions",
"generatorFunctions",
"methods",
"generatorMethods",
"constructors"
]
}
],
"@typescript-eslint/no-unused-vars": [
"off"
],
"@typescript-eslint/no-inferrable-types": [
"error",
{
"ignoreParameters": true,
"ignoreProperties": true
}
],
"@typescript-eslint/ban-types": [
"error",
{
"types":
{
"String": true,
"Boolean": true,
"Number": true,
"Symbol": true,
"{}": false,
"Object": false,
"object": false,
"Function": false
},
"extendDefaults": true
}
]
}
}

16
.vscode/settings.json vendored Normal file
View 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
}

5808
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,13 +4,12 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"start:dev": "ts-node-dev --respawn --transpile-only src/Main.ts"
},
"author": "",
"license": "ISC",
"dependencies": {
"@gizeta/swf-reader": "^1.0.0",
"@types/node": "^14.14.22",
"bytebuffer": "^5.0.1",
"concat-frames": "^1.0.3",
"free-tex-packer-core": "^0.3.2",
@ -19,11 +18,23 @@
"lodash": "^4.17.20",
"node-fetch": "^2.6.1",
"node-gzip": "^1.1.2",
"ora": "^5.3.0",
"png-stream": "^1.0.5",
"reflect-metadata": "^0.1.13",
"stream-to-array": "^2.3.0",
"tsyringe": "^4.4.0",
"xml2js": "^0.4.23"
},
"devDependencies": {}
"devDependencies": {
"@types/bytebuffer": "^5.0.42",
"@types/node": "^14.14.28",
"@types/node-fetch": "^2.5.8",
"@types/xml2js": "^0.4.8",
"@typescript-eslint/eslint-plugin": "^4.15.1",
"@typescript-eslint/parser": "^4.15.1",
"eslint": "^7.20.0",
"ts-node": "^9.1.1",
"ts-node-dev": "^1.1.1",
"typescript": "^4.1.5"
}
}

View File

@ -1,34 +1,47 @@
import "reflect-metadata";
import Configuration from "./config/Configuration";
import {container} from "tsyringe";
import FigureConverter from "./figure/FigureConverter";
import FurnitureConverter from "./furniture/FurnitureConverter";
import PetConverter from "./pet/PetConverter";
import EffectConverter from "./effect/EffectConverter";
import 'reflect-metadata';
import { container } from 'tsyringe';
import { BundleProvider } from './common/bundle/BundleProvider';
import { Configuration } from './common/config/Configuration';
import { FurnitureConverter } from './converters/furniture/FurnitureConverter';
import { PetConverter } from './converters/pet/PetConverter';
import { Mapper } from './mapping/mappers/asset/Mapper';
(async () => {
(async () =>
{
const config = container.resolve(Configuration);
await config.init();
if (config.getBoolean("convert.figure")) {
const figureConverter = container.resolve(FigureConverter);
await figureConverter.convertAsync();
}
const prohibitedSizes = (config.getValue('prohibited.sizes') || '').split(',');
const prohibitedSizesAsset = [];
if (config.getBoolean("convert.furniture")) {
for(const prohibitedSize of prohibitedSizes) prohibitedSizesAsset.push('_' + prohibitedSize + '_');
Mapper.PROHIBITED_SIZES = prohibitedSizes;
BundleProvider.PROHIBITED_SIZES = prohibitedSizesAsset;
// if(config.getBoolean('convert.figure'))
// {
// const figureConverter = container.resolve(FigureConverter);
// await figureConverter.convertAsync();
// }
if(config.getBoolean('convert.furniture'))
{
const furnitureConverter = container.resolve(FurnitureConverter);
await furnitureConverter.convertAsync();
}
if (config.getBoolean("convert.pet")) {
if(config.getBoolean('convert.pet'))
{
const petConverter = container.resolve(PetConverter);
await petConverter.convertAsync();
}
if (config.getBoolean("convert.effect")) {
const effectConverter = container.resolve(EffectConverter);
await effectConverter.convertAsync();
}
// if(config.getBoolean('convert.effect'))
// {
// const effectConverter = container.resolve(EffectConverter);
// await effectConverter.convertAsync();
// }
console.log('finished!');
})()
})();

View File

@ -1,113 +0,0 @@
import HabboAssetSWF from "../swf/HabboAssetSWF";
import BundleTypes from "./BundleTypes";
import SymbolClassTag from "../swf/tags/SymbolClassTag";
import ImageTag from "../swf/tags/ImageTag";
import {singleton} from "tsyringe";
const {packAsync} = require('free-tex-packer-core');
@singleton()
export default class BundleProvider {
public static imageSource: Map<string, string> = new Map<string, string>();
public async generateSpriteSheet(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string): Promise<BundleTypes | null> {
const tagList: Array<SymbolClassTag> = habboAssetSWF.symbolTags();
const names: Array<string> = new Array<string>();
const tags: Array<number> = new Array<number>();
for (const tag of tagList) {
names.push(...tag.names);
tags.push(...tag.tags);
}
const images: Array<{ path: string, contents: Buffer }> = new Array<{ path: string, contents: Buffer }>();
const imageTags: Array<ImageTag> = habboAssetSWF.imageTags();
for (const imageTag of imageTags) {
if (tags.includes(imageTag.characterID)) {
for (let i = 0; i < tags.length; i++) {
if (tags[i] == imageTag.characterID) {
if (
(names[i].includes("_64_") && type === "furniture") ||
(names[i].includes("_icon_") && type === "furniture") ||
(names[i].includes("_h_") && (type === "figure" || type === "effect")) ||
(names[i].includes("_64_") && type === "pet")) {
if (names[i] !== imageTag.className) {
BundleProvider.imageSource.set(names[i].substring(habboAssetSWF.getDocumentClass().length + 1), imageTag.className.substring(habboAssetSWF.getDocumentClass().length + 1));
if ((imageTag.className.includes("_32_") && type === "furniture") ||
(imageTag.className.includes("_sh_") && (type === "figure" || type === "effect")) ||
(imageTag.className.includes("_32_") && type === "pet")) {
images.push({
path: imageTag.className,
contents: imageTag.imgData
});
}
}
}
}
}
}
if ((imageTag.className.includes("_64_") && type === "furniture") ||
(imageTag.className.includes("_1_") && type === "furniture") ||
(imageTag.className.includes("_icon_") && type === "furniture") ||
(imageTag.className.includes("_h_") && (type === "figure" || type === "effect")) ||
(imageTag.className.includes("_64_") && type === "pet")) {
images.push({
path: imageTag.className,
contents: imageTag.imgData
});
}
}
if (images.length === 0) {
return null;
}
return await this.packImages(habboAssetSWF.getDocumentClass(), outputFolder + "/", images);
}
async packImages(documentClass: string, outputFolder: string, images: Array<{ path: string, contents: Buffer }>): Promise<BundleTypes | null> {
let options = {
textureName: documentClass,
width: 3072,
height: 2048,
fixedSize: false,
allowRotation: true,
detectIdentical: true,
allowTrim: true,
exporter: "Pixi"
};
const archiveType: BundleTypes = {} as any;
const imageData: {
name: string,
buffer: Buffer
} = {} as any;
try {
const files = await packAsync(images, options);
for (let item of files) {
if (item.name.endsWith(".json")) {
archiveType.spriteSheetType = JSON.parse(item.buffer.toString('utf8'));
} else {
imageData.buffer = item.buffer;
imageData.name = item.name;
}
}
if (archiveType.spriteSheetType === null) throw new Error("Failed to parse SpriteSheet. " + images[0].path);
} catch (error) {
console.log("Image Packing Error: ");
console.log(error);
}
if (archiveType.spriteSheetType !== null) {
archiveType.spriteSheetType.meta.image = imageData.name;
archiveType.imageData = imageData;
}
return archiveType;
}
}

View File

@ -1,63 +0,0 @@
export default interface BundleTypes {
spriteSheetType: SpriteSheetType,
imageData: {
name: string,
buffer: Buffer
}
}
export interface SpriteSheetType {
frames: SpriteSheetFrames,
meta: SpriteSheetMeta
}
export interface SpriteSheetFrames {
[key: string]: SpriteSheetFrame
}
export interface SpriteSheetFrame {
frame: SpriteSheetFrameDimensions,
rotated: boolean,
trimmed: boolean,
spriteSourceSize: SpriteSourceSize
sourceSize: SourceSize,
pivot: FramePivot
}
export interface FramePivot {
x: number,
y: number
}
export interface SourceSize {
w: number,
h: number
}
export interface SpriteSourceSize {
x: number,
y: number,
w: number,
h: number
}
export interface SpriteSheetFrameDimensions {
x: number,
y: number,
w: number,
h: number
}
export interface SpriteSheetMeta {
app: string,
version: string,
image: string,
format: string,
size: SpriteSheetSize,
scale: number
}
export interface SpriteSheetSize {
w: number,
h: number
}

View File

@ -0,0 +1,144 @@
import { packAsync } from 'free-tex-packer-core';
import { singleton } from 'tsyringe';
import { HabboAssetSWF } from '../../swf/HabboAssetSWF';
import { Configuration } from '../config/Configuration';
import { SpriteBundle } from './SpriteBundle';
@singleton()
export class BundleProvider
{
public static PROHIBITED_SIZES: string[] = [];
public static imageSource: Map<string, string> = new Map();
constructor(private readonly _configuration: Configuration)
{}
public async generateSpriteSheet(habboAssetSWF: HabboAssetSWF): Promise<SpriteBundle>
{
const tagList = habboAssetSWF.symbolTags();
const names: string[] = [];
const tags: number[] = [];
for(const tag of tagList)
{
names.push(...tag.names);
tags.push(...tag.tags);
}
const images: { path: string, contents: Buffer }[] = [];
const imageTags = habboAssetSWF.imageTags();
for(const imageTag of imageTags)
{
if(tags.includes(imageTag.characterID))
{
for(let i = 0; i < tags.length; i++)
{
if(tags[i] != imageTag.characterID) continue;
if(names[i] == imageTag.className) continue;
let isProhibited = false;
for(const size of BundleProvider.PROHIBITED_SIZES)
{
if(imageTag.className.indexOf(size) >= 0)
{
isProhibited = true;
break;
}
}
if(isProhibited) continue;
BundleProvider.imageSource.set(names[i].substring(habboAssetSWF.getDocumentClass().length + 1), imageTag.className.substring(habboAssetSWF.getDocumentClass().length + 1));
images.push({
path: imageTag.className,
contents: imageTag.imgData
});
}
}
let isProhibited = false;
for(const size of BundleProvider.PROHIBITED_SIZES)
{
if(imageTag.className.indexOf(size) >= 0)
{
isProhibited = true;
break;
}
}
if(isProhibited) continue;
images.push({
path: imageTag.className,
contents: imageTag.imgData
});
}
if(!images.length) return null;
return await this.packImages(habboAssetSWF.getDocumentClass(), images);
}
async packImages(documentClass: string, images: { path: string, contents: Buffer }[]): Promise<SpriteBundle>
{
try
{
const files = await packAsync(images, {
textureName: documentClass,
width: 3072,
height: 2048,
fixedSize: false,
allowRotation: true,
detectIdentical: true,
allowTrim: true,
//@ts-ignore
exporter: 'Pixi'
});
const bundle = new SpriteBundle();
for(const item of files)
{
if(item.name.endsWith('.json'))
{
bundle.spritesheet = JSON.parse(item.buffer.toString('utf8'));
delete bundle.spritesheet.meta.app;
delete bundle.spritesheet.meta.version;
}
else
{
bundle.imageData = {
name: item.name,
buffer: item.buffer
};
}
}
if(!bundle.spritesheet) throw new Error('Failed to parse SpriteSheet. ' + images[0].path);
if((bundle.spritesheet !== undefined) && (bundle.imageData !== undefined))
{
bundle.spritesheet.meta.image = bundle.imageData.name;
}
return bundle;
}
catch (error)
{
console.error('Image Packing Error', error);
}
return null;
}
}

View File

@ -0,0 +1,27 @@
import { ISpritesheetData } from '../../mapping/json';
export class SpriteBundle
{
private _spritesheet: ISpritesheetData;
private _imageData: { name: string, buffer: Buffer};
public get spritesheet(): ISpritesheetData
{
return this._spritesheet;
}
public set spritesheet(spritesheet: ISpritesheetData)
{
this._spritesheet = spritesheet;
}
public get imageData(): { name: string, buffer: Buffer}
{
return this._imageData;
}
public set imageData(imageData: { name: string, buffer: Buffer })
{
this._imageData = imageData;
}
}

View File

@ -0,0 +1,61 @@
import { singleton } from 'tsyringe';
import * as configuration from '../../configuration.json';
import { FileUtilities } from '../../utils/FileUtilities';
@singleton()
export class Configuration
{
private readonly _config: Map<string, string>;
constructor()
{
this._config = new Map<string, string>();
}
public async init(): Promise<void>
{
for(const key of Object.keys(configuration)) this._config.set(key, configuration[key]);
}
public async loadExternalVariables(): Promise<void>
{
const url = this.getValue('external_vars.url');
try
{
const content = await FileUtilities.readFileAsString(url);
const config: string[] = content.split('\n');
for(const configEntry of config)
{
const configEntrySplit = configEntry.split('=');
const configKey = configEntrySplit[0];
const configValue = configEntrySplit[1];
this._config.set(configKey, configValue);
}
}
catch (error)
{
console.log();
console.error(error);
}
}
public getBoolean(key: string): boolean
{
return this._config.get(key) === '1';
}
public getValue(key: string, value: string = ''): string
{
if(this._config.has(key))
{
// @ts-ignore
return this._config.get(key);
}
return value;
}
}

View File

@ -0,0 +1,102 @@
import { wrap } from 'bytebuffer';
import { parseStringPromise } from 'xml2js';
import { HabboAssetSWF } from '../../swf/HabboAssetSWF';
import { DefineBinaryDataTag } from '../../swf/tags/DefineBinaryDataTag';
export class SWFConverter
{
private static getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean): DefineBinaryDataTag
{
let binaryName = habboAssetSWF.getFullClassName(type, documentNameTwice);
let tag = habboAssetSWF.getBinaryTagByName(binaryName);
if(!tag)
{
binaryName = habboAssetSWF.getFullClassNameSnake(type, documentNameTwice, true);
tag = habboAssetSWF.getBinaryTagByName(binaryName);
}
return tag;
}
protected static getPalette(habboAssetSWF: HabboAssetSWF, paletteName: string): [ number, number, number ][]
{
const binaryData = SWFConverter.getBinaryData(habboAssetSWF, paletteName, false);
if(!binaryData || !binaryData.binaryDataBuffer) return null;
const byteBuffer = wrap(binaryData.binaryDataBuffer);
const paletteColors: [ number, number, number ][] = [];
try
{
let R = 0;
let G = 0;
let B = 0;
let counter = 1;
while((binaryData.binaryDataBuffer.length - byteBuffer.offset) > 0)
{
if(counter == 1) R = byteBuffer.readUint8();
else if(counter == 2) G = byteBuffer.readUint8();
else if(counter == 3)
{
B = byteBuffer.readUint8();
paletteColors.push([ R, G, B ]);
counter = 0;
}
counter++;
}
return paletteColors;
}
catch (err)
{
console.log(err);
}
return null;
}
protected static async getAssetsXML(habboAssetSWF: HabboAssetSWF): Promise<any>
{
const binaryData = SWFConverter.getBinaryData(habboAssetSWF, 'assets', true);
if(!binaryData) return null;
return await parseStringPromise(binaryData.binaryData);
}
protected static async getLogicXML(habboAssetSWF: HabboAssetSWF): Promise<any>
{
const binaryData = SWFConverter.getBinaryData(habboAssetSWF, 'logic', true);
if(!binaryData) return null;
return await parseStringPromise(binaryData.binaryData);
}
protected static async getIndexXML(habboAssetSWF: HabboAssetSWF): Promise<any>
{
const binaryData = SWFConverter.getBinaryData(habboAssetSWF, 'index', false);
if(!binaryData) return null;
return await parseStringPromise(binaryData.binaryData);
}
protected static async getVisualizationXML(habboAssetSWF: HabboAssetSWF): Promise<any>
{
const binaryData = SWFConverter.getBinaryData(habboAssetSWF, 'visualization', true);
if(!binaryData) return null;
return await parseStringPromise(binaryData.binaryData);
}
}

View File

@ -1,20 +0,0 @@
{
"output.folder.furniture": "/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/furniture-test/",
"output.folder.figure": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/figure-test/",
"output.folder.effect": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/effect-test/",
"output.folder.pet": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/pet-test/",
"furnidata.url": "http://assets.nitro.se/game/harmony/furnidata.xml",
"figuremap.url": "http://assets.nitro.se/game/gordon/figuremap.xml",
"effectmap.url": "http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/effectmap.xml",
"external_vars.url": "http://assets.nitro.se/game/gamedata/external_variables.txt",
"dynamic.download.url.furniture": "/home/user/WebstormProjects/sites/assets.nitro.se/game/harmony/hof_furni/%className%.swf",
"dynamic.download.url.figure": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf",
"dynamic.download.url.effect": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf",
"dynamic.download.url.pet": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf",
"convert.furniture": "1",
"convert.figure": "0",
"convert.effect": "0",
"convert.pet": "0",
"figure.rotation.enabled": "0",
"figure.skip.non-existing.asset.images": "0"
}

View File

@ -1,50 +0,0 @@
import {singleton} from "tsyringe";
const fs = require('fs/promises');
const fetch = require('node-fetch');
const config = require('../config.json');
@singleton()
export default class Configuration {
private readonly _config: Map<string, string>;
constructor() {
this._config = new Map<string, string>();
}
async init() {
for (const key of Object.keys(config)) {
this._config.set(key, config[key]);
}
}
public getBoolean(key: string): boolean {
return this._config.get(key) === "1";
}
public getValue(key: string, value: string = ""): string {
if (this._config.has(key)) {
// @ts-ignore
return this._config.get(key);
}
return value;
}
public async loadExternalVariables(): Promise<void> {
const url = this.getValue("external_vars.url");
const fetchData = await fetch(url);
const textData = await fetchData.text();
const config: string[] = textData.split("\n");
for (const configEntry of config) {
const configEntrySplit = configEntry.split("=");
const configKey = configEntrySplit[0];
const configValue = configEntrySplit[1];
this._config.set(configKey, configValue);
}
}
}

View File

@ -0,0 +1,19 @@
{
"output.folder.furniture": "/converted-assets/furniture/",
"output.folder.figure": "/converted-assets/figure/",
"output.folder.effect": "/converted-assets/effect/",
"output.folder.pet": "/converted-assets/pet/",
"furnidata.url": "/gamedata/json/furnidata",
"figuremap.url": "/gamedata/figuremap.xml",
"effectmap.url": "/gamedata/effectmap.xml",
"external_vars.url": "/gamedata/external_variables.txt",
"dynamic.download.url.furniture": "/dcr/hof_furni/%className%.swf",
"dynamic.download.url.figure": "/gordon/PRODUCTION/%className%.swf",
"dynamic.download.url.effect": "/gordon/PRODUCTION/%className%.swf",
"dynamic.download.url.pet": "/gordon/PRODUCTION/%className%.swf",
"convert.furniture": "1",
"convert.figure": "0",
"convert.effect": "0",
"convert.pet": "1",
"prohibited.sizes": "32,sh"
}

View File

@ -0,0 +1,130 @@
import { writeFile } from 'fs/promises';
import * as ora from 'ora';
import { singleton } from 'tsyringe';
import { BundleProvider } from '../../common/bundle/BundleProvider';
import { SpriteBundle } from '../../common/bundle/SpriteBundle';
import { Configuration } from '../../common/config/Configuration';
import { SWFConverter } from '../../common/converters/SWFConverter';
import { IAssetData } from '../../mapping/json';
import { AssetMapper, IndexMapper, LogicMapper, VisualizationMapper } from '../../mapping/mappers';
import { HabboAssetSWF } from '../../swf/HabboAssetSWF';
import File from '../../utils/File';
import Logger from '../../utils/Logger';
import NitroBundle from '../../utils/NitroBundle';
import { FurnitureDownloader } from './FurnitureDownloader';
@singleton()
export class FurnitureConverter extends SWFConverter
{
constructor(
private readonly _furniDownloader: FurnitureDownloader,
private readonly _configuration: Configuration,
private readonly _bundleProvider: BundleProvider,
private readonly _logger: Logger)
{
super();
}
public async convertAsync(): Promise<void>
{
const now = Date.now();
const spinner = ora('Preparing Furniture').start();
const outputFolder = new File(this._configuration.getValue('output.folder.furniture'));
if(!outputFolder.isDirectory())
{
spinner.text = `Creating Folder: ${ outputFolder.path }`;
spinner.render();
outputFolder.mkdirs();
}
await this._furniDownloader.download(async (habboAssetSwf: HabboAssetSWF) =>
{
spinner.text = 'Parsing Furniture: ' + habboAssetSwf.getDocumentClass();
spinner.render();
try
{
const spriteBundle = await this._bundleProvider.generateSpriteSheet(habboAssetSwf);
await this.fromHabboAsset(habboAssetSwf, outputFolder.path, 'furniture', spriteBundle);
}
catch (error)
{
console.log();
console.error(error);
}
});
spinner.succeed(`Furniture Finished in ${ Date.now() - now }ms`);
}
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, spriteBundle: SpriteBundle): Promise<void>
{
const assetData = await this.mapXML2JSON(habboAssetSWF, 'furniture');
if(!assetData) return;
const name = habboAssetSWF.getDocumentClass();
const path = outputFolder + '/' + name + '.nitro';
const nitroBundle = new NitroBundle();
nitroBundle.addFile((name + '.json'), Buffer.from(JSON.stringify(assetData)));
if(spriteBundle && (spriteBundle.spritesheet !== undefined))
{
if(spriteBundle.spritesheet && spriteBundle.imageData)
{
assetData.spritesheet = spriteBundle.spritesheet;
nitroBundle.addFile(spriteBundle.imageData.name, spriteBundle.imageData.buffer);
}
}
const buffer = await nitroBundle.toBufferAsync();
await writeFile(path, buffer);
}
private async mapXML2JSON(habboAssetSWF: HabboAssetSWF, assetType: string): Promise<IAssetData>
{
if(!habboAssetSWF) return null;
const assetData: IAssetData = {};
assetData.type = assetType;
try
{
const indexXML = await FurnitureConverter.getIndexXML(habboAssetSWF);
if(indexXML) IndexMapper.mapXML(indexXML, assetData);
const assetXML = await FurnitureConverter.getAssetsXML(habboAssetSWF);
if(assetXML) AssetMapper.mapXML(assetXML, assetData);
const logicXML = await FurnitureConverter.getLogicXML(habboAssetSWF);
if(logicXML) LogicMapper.mapXML(logicXML, assetData);
const visualizationXML = await FurnitureConverter.getVisualizationXML(habboAssetSWF);
if(visualizationXML) VisualizationMapper.mapXML(visualizationXML, assetData);
return assetData;
}
catch (error)
{
console.log();
console.error(error);
}
}
}

View File

@ -0,0 +1,146 @@
import { singleton } from 'tsyringe';
import { Configuration } from '../../common/config/Configuration';
import { IFurnitureData } from '../../mapping/json';
import { HabboAssetSWF } from '../../swf/HabboAssetSWF';
import File from '../../utils/File';
import { FileUtilities } from '../../utils/FileUtilities';
import Logger from '../../utils/Logger';
@singleton()
export class FurnitureDownloader
{
constructor(
private readonly _configuration: Configuration,
private readonly _logger: Logger)
{}
public async download(callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>): Promise<void>
{
try
{
let count = 0;
const furniData = await this.parseFurniData();
const classNames: string[] = [];
const outputFolder = new File(this._configuration.getValue('output.folder.furniture'));
if(!outputFolder.isDirectory()) outputFolder.mkdirs();
if(furniData.roomitemtypes !== undefined)
{
if(furniData.roomitemtypes.furnitype !== undefined)
{
for(const furniType of furniData.roomitemtypes.furnitype)
{
const className = furniType.classname.split('*')[0];
const revision = furniType.revision;
if(count === 3) return;
if(classNames.indexOf(className) >= 0) continue;
classNames.push(className);
try
{
await this.extractFurniture(revision, className, callback);
count ++;
}
catch(error)
{
console.log();
console.error(error);
}
}
}
}
if(furniData.wallitemtypes !== undefined)
{
if(furniData.wallitemtypes.furnitype !== undefined)
{
for(const furniType of furniData.wallitemtypes.furnitype)
{
const className = furniType.classname.split('*')[0];
const revision = furniType.revision;
if(classNames.indexOf(className) >= 0) continue;
classNames.push(className);
try
{
await this.extractFurniture(revision, className, callback);
}
catch(error)
{
console.log();
console.error(error);
}
}
}
}
}
catch (error)
{
console.log();
console.error(error);
}
}
public async parseFurniData(): Promise<IFurnitureData>
{
const url = this._configuration.getValue('furnidata.url');
if(!url || !url.length) return null;
try
{
const content = await FileUtilities.readFileAsString(url);
if(!content || !content.length) return null;
return (JSON.parse(content) as IFurnitureData);
}
catch(error)
{
console.log();
console.error(error);
}
}
public async extractFurniture(revision: number, className: string, callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>): Promise<void>
{
let url = this._configuration.getValue('dynamic.download.url.furniture');
if(!url || !url.length) return;
url = url.replace('%revision%', revision.toString());
url = url.replace('%className%', className);
try
{
const buffer = await FileUtilities.readFileAsBuffer(url);
if(!buffer) return;
const newHabboAssetSWF = new HabboAssetSWF(buffer);
await newHabboAssetSWF.setupAsync();
await callback(newHabboAssetSWF, className);
}
catch (error)
{
console.log();
console.error(error);
}
}
}

View File

@ -0,0 +1,145 @@
import { writeFile } from 'fs/promises';
import { singleton } from 'tsyringe';
import { BundleProvider } from '../../common/bundle/BundleProvider';
import { SpriteBundle } from '../../common/bundle/SpriteBundle';
import { Configuration } from '../../common/config/Configuration';
import { SWFConverter } from '../../common/converters/SWFConverter';
import { IAssetData } from '../../mapping/json';
import { AssetMapper, IndexMapper, LogicMapper, VisualizationMapper } from '../../mapping/mappers';
import { HabboAssetSWF } from '../../swf/HabboAssetSWF';
import File from '../../utils/File';
import Logger from '../../utils/Logger';
import NitroBundle from '../../utils/NitroBundle';
import { PetDownloader } from './PetDownloader';
@singleton()
export class PetConverter extends SWFConverter
{
constructor(
private readonly _petDownloader: PetDownloader,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider,
private readonly _logger: Logger)
{
super();
}
public async convertAsync(): Promise<void>
{
const outputFolder = new File(this._config.getValue('output.folder.pet'));
if(!outputFolder.isDirectory()) outputFolder.mkdirs();
await this._petDownloader.download(async (habboAssetSwf: HabboAssetSWF) =>
{
console.log('Parsing Pet: ' + habboAssetSwf.getDocumentClass());
try
{
const spriteBundle = await this._bundleProvider.generateSpriteSheet(habboAssetSwf);
await this.fromHabboAsset(habboAssetSwf, outputFolder.path, 'pet', spriteBundle);
}
catch (error)
{
console.log();
console.error(error);
}
});
}
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, spriteBundle: SpriteBundle): Promise<void>
{
try
{
const assetData = await this.mapXML2JSON(habboAssetSWF, 'pet');
if(!assetData) return;
if(spriteBundle && (spriteBundle.spritesheet !== undefined)) assetData.spritesheet = spriteBundle.spritesheet;
const name = habboAssetSWF.getDocumentClass();
const path = outputFolder + '/' + name + '.nitro';
const nitroBundle = new NitroBundle();
nitroBundle.addFile((name + '.json'), Buffer.from(JSON.stringify(assetData)));
if(spriteBundle.imageData !== undefined)
{
nitroBundle.addFile(spriteBundle.imageData.name, spriteBundle.imageData.buffer);
}
const buffer = await nitroBundle.toBufferAsync();
await writeFile(path, buffer);
}
catch(err)
{
this._logger.logErrorAsync(err);
}
}
private async mapXML2JSON(habboAssetSWF: HabboAssetSWF, assetType: string): Promise<IAssetData>
{
if(!habboAssetSWF) return null;
const assetData: IAssetData = {};
assetData.type = assetType;
try
{
const indexXML = await PetConverter.getIndexXML(habboAssetSWF);
if(indexXML) IndexMapper.mapXML(indexXML, assetData);
const assetXML = await PetConverter.getAssetsXML(habboAssetSWF);
if(assetXML)
{
AssetMapper.mapXML(assetXML, assetData);
if(assetData.palettes !== undefined)
{
for(const paletteId in assetData.palettes)
{
const palette = assetData.palettes[paletteId];
const paletteColors = PetConverter.getPalette(habboAssetSWF, palette.source);
if(!paletteColors)
{
delete assetData.palettes[paletteId];
continue;
}
const rgbs: [ number, number, number ][] = [];
for(const rgb of paletteColors) rgbs.push([ rgb[0], rgb[1], rgb[2] ]);
palette.rgb = rgbs;
}
}
}
const logicXML = await PetConverter.getLogicXML(habboAssetSWF);
if(logicXML) LogicMapper.mapXML(logicXML, assetData);
const visualizationXML = await PetConverter.getVisualizationXML(habboAssetSWF);
if(visualizationXML) VisualizationMapper.mapXML(visualizationXML, assetData);
return assetData;
}
catch (error)
{
console.log();
console.error(error);
}
}
}

View File

@ -0,0 +1,98 @@
import { singleton } from 'tsyringe';
import { Configuration } from '../../common/config/Configuration';
import { HabboAssetSWF } from '../../swf/HabboAssetSWF';
import { FileUtilities } from '../../utils/FileUtilities';
import Logger from '../../utils/Logger';
@singleton()
export class PetDownloader
{
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger)
{}
public async download(callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>): Promise<void>
{
try
{
const petTypes = await this.parsePetTypes();
const classNames: string[] = [];
for(const petType of petTypes)
{
if(classNames.indexOf(petType) >= 0) continue;
classNames.push(petType);
try
{
await this.extractPet(petType, callback);
}
catch(error)
{
console.log();
console.error(error);
}
}
}
catch (error)
{
console.log();
console.error(error);
}
}
public async parsePetTypes(): Promise<string[]>
{
try
{
await this._config.loadExternalVariables();
const petTypes: string[] = [];
const pets = this._config.getValue('pet.configuration');
if(pets)
{
const types = pets.split(',');
for(const type of types) petTypes.push(type);
}
return petTypes;
}
catch (error)
{
console.log();
console.error(error);
}
}
public async extractPet(className: string, callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>): Promise<void>
{
let url = this._config.getValue('dynamic.download.url.pet');
if(!url || !url.length) return;
url = url.replace('%className%', className);
try
{
const buffer = await FileUtilities.readFileAsBuffer(url);
const newHabboAssetSWF = new HabboAssetSWF(buffer);
await newHabboAssetSWF.setupAsync();
await callback(newHabboAssetSWF, className);
}
catch (error)
{
console.log();
console.error(error);
}
}
}

View File

@ -1,107 +0,0 @@
import HabboAssetSWF from "../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../swf/tags/DefineBinaryDataTag";
import {EffectJson} from "./mapper/EffectTypes";
import BundleTypes from "../bundle/BundleTypes";
import File from "../utils/File";
import NitroBundle from "../utils/NitroBundle";
import EffectDownloader from "./EffectDownloader";
import EffectJsonMapper from "./mapper/EffectJsonMapper";
import Configuration from "../config/Configuration";
import BundleProvider from "../bundle/BundleProvider";
import {singleton} from "tsyringe";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
@singleton()
export default class EffectConverter {
constructor(
private readonly _effectDownloader: EffectDownloader,
private readonly _effectJsonMapper: EffectJsonMapper,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider) {
}
private static getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
let binaryName: string = habboAssetSWF.getFullClassName(type, documentNameTwice);
let tag = habboAssetSWF.getBinaryTagByName(binaryName);
if (tag === null) {
binaryName = habboAssetSWF.getFullClassNameSnake(type, documentNameTwice, true);
tag = habboAssetSWF.getBinaryTagByName(binaryName);
}
return tag;
}
private static async getManifestXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
const binaryData: DefineBinaryDataTag | null = this.getBinaryData(habboAssetSWF, "manifest", false);
if (binaryData !== null) {
return await parser.parseStringPromise(binaryData.binaryData);
}
return null;
}
private static async getAnimationXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
const binaryData: DefineBinaryDataTag | null = this.getBinaryData(habboAssetSWF, "animation", false);
if (binaryData !== null) {
return await parser.parseStringPromise(binaryData.binaryData);
}
return null;
}
private async convertXML2JSON(habboAssetSWF: HabboAssetSWF): Promise<EffectJson | null> {
const manifestXML = await EffectConverter.getManifestXML(habboAssetSWF);
const animationXML = await EffectConverter.getAnimationXML(habboAssetSWF);
return this._effectJsonMapper.mapXML(habboAssetSWF, manifestXML, animationXML);
}
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: BundleTypes) {
const effectJson = await this.convertXML2JSON(habboAssetSWF);
if (effectJson !== null) {
effectJson.spritesheet = archiveType.spriteSheetType;
effectJson.type = type;
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
const assetOutputFolder = new File(path);
if (assetOutputFolder.exists()) {
console.log("Effect already exists or the directory is not empty!");
return;
}
const nitroBundle = new NitroBundle();
nitroBundle.addFile(habboAssetSWF.getDocumentClass() + ".json", Buffer.from(JSON.stringify(effectJson)));
nitroBundle.addFile(archiveType.imageData.name, archiveType.imageData.buffer);
const buffer = await nitroBundle.toBufferAsync();
await fs.writeFile(path, buffer);
}
}
public async convertAsync() {
const outputFolderEffect = new File(this._config.getValue("output.folder.effect"));
if (!outputFolderEffect.isDirectory()) {
outputFolderEffect.mkdirs();
}
const effectConverter = this;
await this._effectDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing effect: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await effectConverter._bundleProvider.generateSpriteSheet(habboAssetSwf, outputFolderEffect.path, "effect");
if (spriteSheetType !== null) {
await effectConverter.fromHabboAsset(habboAssetSwf, outputFolderEffect.path, "effect", spriteSheetType);
}
} catch (e) {
console.log(e);
console.log("Effect error: " + habboAssetSwf.getDocumentClass());
}
});
}
}

View File

@ -1,76 +0,0 @@
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fetch = require('node-fetch');
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
@singleton()
export default class EffectDownloader {
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
public static types: Map<string, string> = new Map<string, string>();
public async download(callback: (habboAssetSwf: HabboAssetSWF) => Promise<void>) {
const outputFolderEffect = this._config.getValue("output.folder.effect");
const figureMap = await this.parseEffectMap();
const map = figureMap.map;
for (const lib of map.effect) {
const info = lib['$'];
const className: string = info.lib;
const assetOutputFolder = new File(outputFolderEffect + "/" + className);
if (assetOutputFolder.exists()) {
continue;
}
if (!EffectDownloader.types.has(className)) {
const url = this._config.getValue("dynamic.download.url.effect").replace("%className%", className);
let buffer: Buffer | null = null;
if (url.includes("http")) {
const fetchData = await fetch(url);
if (fetchData.status === 404) {
console.log("SWF File does not exist: " + url);
continue;
}
const arrayBuffer = await fetchData.arrayBuffer();
buffer = Buffer.from(arrayBuffer);
} else {
const file = new File(url);
if (!file.exists()) {
console.log("SWF File does not exist: " + file.path);
continue;
}
}
try {
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(buffer !== null ? buffer : url);
await newHabboAssetSWF.setupAsync();
EffectDownloader.types.set(className, info.type);
await callback(newHabboAssetSWF);
} catch (e) {
await this._logger.logErrorAsync(`[${className}]` + e);
}
}
}
}
async parseEffectMap() {
const figureMapPath = this._config.getValue("effectmap.url");
const figureFetch = await fetch(figureMapPath);
const figureMap = await figureFetch.text();
return await parser.parseStringPromise(figureMap);
}
}

View File

@ -1,522 +0,0 @@
export class AnimationXML {
private readonly _name: string;
private readonly _desc: string;
private readonly _resetOnToggle: boolean | undefined;
private readonly _directions: Array<DirectionOffsetXML>;
private readonly _shadows: Array<ShadowXML>;
private readonly _adds: Array<AddXML>;
private readonly _removes: Array<RemoveXML>;
private readonly _sprites: Array<SpriteXML>;
private readonly _frames: Array<FrameXML>;
private readonly _avatars: Array<AvatarXML>;
private readonly _overrides: Array<OverrideXML>;
constructor(animationXML: any) {
const animation = animationXML.animation;
const attributes = animation.$;
this._name = attributes.name;
this._desc = attributes.desc;
if (attributes.resetOnToggle !== undefined) this._resetOnToggle = attributes.resetOnToggle === '1';
this._directions = new Array<DirectionOffsetXML>();
if (animation.direction !== undefined) {
for (const direction of animation.direction) {
this._directions.push(new DirectionOffsetXML(direction));
}
}
this._shadows = new Array<ShadowXML>();
if (animation.shadow !== undefined) {
for (const shadow of animation.shadow) {
this._shadows.push(new ShadowXML(shadow));
}
}
this._adds = new Array<AddXML>();
if (animation.add !== undefined) {
for (const add of animation.add) {
this._adds.push(new AddXML(add));
}
}
this._removes = new Array<RemoveXML>();
if (animation.remove !== undefined) {
for (const remove of animation.remove) {
this._removes.push(new RemoveXML(remove));
}
}
this._sprites = new Array<SpriteXML>();
if (animation.sprite !== undefined) {
for (const sprite of animation.sprite) {
this._sprites.push(new SpriteXML(sprite));
}
}
this._frames = new Array<FrameXML>();
if (animation.frame !== undefined) {
for (const frame of animation.frame) {
this._frames.push(new FrameXML(frame));
}
}
this._avatars = new Array<AvatarXML>();
if (animation.avatar !== undefined) {
for (const avatar of animation.avatar) {
this._avatars.push(new AvatarXML(avatar));
}
}
this._overrides = new Array<OverrideXML>();
if (animation.override !== undefined) {
for (const override of animation.override) {
this._overrides.push(new OverrideXML(override));
}
}
}
get name(): string {
return this._name;
}
get desc(): string {
return this._desc;
}
get resetOnToggle(): boolean | undefined {
return this._resetOnToggle;
}
get directions(): Array<DirectionOffsetXML> {
return this._directions;
}
get shadows(): Array<ShadowXML> {
return this._shadows;
}
get adds(): Array<AddXML> {
return this._adds;
}
get removes(): Array<RemoveXML> {
return this._removes;
}
get sprites(): Array<SpriteXML> {
return this._sprites;
}
get frames(): Array<FrameXML> {
return this._frames;
}
get avatars(): Array<AvatarXML> {
return this._avatars;
}
get overrides(): Array<OverrideXML> {
return this._overrides;
}
}
export class OverrideXML {
private readonly _name: string;
private readonly _override: string;
private readonly _frames: Array<FrameXML>;
constructor(overrideXML: any) {
const attributes = overrideXML.$;
this._name = attributes.name;
this._override = attributes.override;
this._frames = new Array<FrameXML>();
if (overrideXML.frame !== undefined) {
for (const frame of overrideXML.frame) {
this._frames.push(new FrameXML(frame));
}
}
}
get name(): string {
return this._name;
}
get override(): string {
return this._override;
}
get frames(): Array<FrameXML> {
return this._frames;
}
}
export class AvatarXML {
private readonly _ink: number;
private readonly _foreground: string;
private readonly _background: string;
constructor(avatarXML: any) {
const attributes = avatarXML.$;
this._ink = attributes.ink;
this._foreground = attributes.foreground;
this._background = attributes.background;
}
get ink(): number {
return this._ink;
}
get foreground(): string {
return this._foreground;
}
get background(): string {
return this._background;
}
}
export class SpriteXML {
private readonly _id: string;
private readonly _member: string;
private readonly _directions: number;
private readonly _staticY: number;
private readonly _ink: number;
private readonly _directionList: Array<DirectionXML>;
constructor(spriteXML: any) {
const attributes = spriteXML.$;
this._id = attributes.id;
this._member = attributes.member;
this._directions = attributes.directions;
this._staticY = attributes.staticY;
this._ink = attributes.ink;
this._directionList = new Array<DirectionXML>();
if (spriteXML.direction !== undefined) {
for (const direction of spriteXML.direction) {
this._directionList.push(new DirectionXML(direction));
}
}
}
get id(): string {
return this._id;
}
get member(): string {
return this._member;
}
get directions(): number {
return this._directions;
}
get staticY(): number {
return this._staticY;
}
get ink(): number {
return this._ink;
}
get directionList(): Array<DirectionXML> {
return this._directionList;
}
}
export class DirectionXML {
private readonly _id: number;
private readonly _dx: number;
private readonly _dy: number;
private readonly _dz: number;
constructor(directionXML: any) {
const attributes = directionXML.$;
this._id = attributes.id;
this._dx = attributes.dx;
this._dy = attributes.dy;
this._dz = attributes.dz;
}
get id(): number {
return this._id;
}
get dx(): number {
return this._dx;
}
get dy(): number {
return this._dy;
}
get dz(): number {
return this._dz;
}
}
export class RemoveXML {
private readonly _id: string;
constructor(removeXML: any) {
this._id = removeXML.$.id;
}
get id(): string {
return this._id;
}
}
export class AddXML {
private readonly _id: string;
private readonly _align: string;
private readonly _blend: string;
private readonly _ink: number;
private readonly _base: string;
constructor(addXML: any) {
const attributes = addXML.$;
this._id = attributes.id;
this._align = attributes.align;
this._blend = attributes.blend;
this._ink = attributes.ink;
this._base = attributes.base;
}
get id(): string {
return this._id;
}
get align(): string {
return this._align;
}
get blend(): string {
return this._blend;
}
get ink(): number {
return this._ink;
}
get base(): string {
return this._base;
}
}
export class FrameXML {
private readonly _repeats: number | undefined;
private readonly _fxs: Array<FxXML>;
private readonly _bodyParts: Array<BodyPartXML>;
constructor(frameXML: any) {
if (frameXML.$ !== undefined)
this._repeats = frameXML.$.repeats;
this._fxs = new Array<FxXML>();
if (frameXML.fx !== undefined) {
for (const fx of frameXML.fx) {
this._fxs.push(new FxXML(fx));
}
}
this._bodyParts = new Array<BodyPartXML>();
if (frameXML.bodypart !== undefined) {
for (const bodypart of frameXML.bodypart) {
this._bodyParts.push(new BodyPartXML(bodypart));
}
}
}
get repeats(): number | undefined {
return this._repeats;
}
get fxs(): Array<FxXML> {
return this._fxs;
}
get bodyParts(): Array<BodyPartXML> {
return this._bodyParts;
}
}
export class BodyPartXML {
private readonly _id: string;
private readonly _frame: number;
private readonly _dx: number;
private readonly _dy: number;
private readonly _dz: number;
private readonly _dd: number;
private readonly _action: string;
private readonly _base: string;
private readonly _items: Array<ItemXML>;
constructor(bodyPartXML: any) {
const attributes = bodyPartXML.$;
this._id = attributes.id;
this._frame = attributes.frame;
this._dx = attributes.dx;
this._dy = attributes.dy;
this._dz = attributes.dz;
this._dd = attributes.dd;
this._action = attributes.action;
this._base = attributes.base;
this._items = new Array<ItemXML>();
if (bodyPartXML.item !== undefined) {
for (const item of bodyPartXML.item) {
this._items.push(new ItemXML(item));
}
}
}
get id(): string {
return this._id;
}
get frame(): number {
return this._frame;
}
get dx(): number {
return this._dx;
}
get dy(): number {
return this._dy;
}
get dz(): number {
return this._dz;
}
get dd(): number {
return this._dd;
}
get action(): string {
return this._action;
}
get base(): string {
return this._base;
}
get items(): Array<ItemXML> {
return this._items;
}
}
export class ItemXML {
private readonly _id: string;
private readonly _base: string;
constructor(itemXML: any) {
const attributes = itemXML.$;
this._id = attributes.id;
this._base = attributes.base;
}
get id(): string {
return this._id;
}
get base(): string {
return this._base;
}
}
export class FxXML {
private readonly _id: string;
private readonly _repeats: number;
private readonly _frame: number;
private readonly _dx: number;
private readonly _dy: number;
private readonly _dz: number;
private readonly _dd: number;
private readonly _action: string;
constructor(fxXML: any) {
const attributes = fxXML.$;
this._id = attributes.id;
this._repeats = attributes.repeats;
this._frame = attributes.frame;
this._dx = attributes.dx;
this._dy = attributes.dy;
this._dz = attributes.dz;
this._dd = attributes.dd;
this._action = attributes.action;
}
get id(): string {
return this._id;
}
get repeats(): number {
return this._repeats;
}
get frame(): number {
return this._frame;
}
get dx(): number {
return this._dx;
}
get dy(): number {
return this._dy;
}
get dz(): number {
return this._dz;
}
get dd(): number {
return this._dd;
}
get action(): string {
return this._action;
}
}
export class ShadowXML {
private readonly _id: string;
constructor(shadowXML: any) {
this._id = shadowXML.$.id;
}
get id(): string {
return this._id;
}
}
export class DirectionOffsetXML {
private readonly _offset: number;
constructor(directionXML: any) {
this._offset = directionXML.$.offset;
}
get offset(): number {
return this._offset;
}
}

View File

@ -1,341 +0,0 @@
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import {
Add,
Alias,
Aliases,
Animation,
Animations,
AssetJSON,
AssetsJSON, Avatar,
Bodypart, Direction, DirectionOffset,
EffectJson,
Frame,
Fx, Item, Override, Remove, Shadow, Sprite
} from "./EffectTypes";
import {ManifestXML} from "./EffectManifestXMLTypes";
import {
AnimationXML,
BodyPartXML
} from "./EffectAnimationXMLTypes";
import {singleton} from "tsyringe";
import EffectDownloader from "../EffectDownloader";
import BundleProvider from "../../bundle/BundleProvider";
@singleton()
export default class EffectJsonMapper {
public static readonly MUST_START_WITH: string = "h_";
public mapXML(habboAssetSWF: HabboAssetSWF, manifest: any, animation: any): EffectJson {
const name = habboAssetSWF.getDocumentClass();
const result = {} as EffectJson;
result.name = name;
result.type = EffectDownloader.types.get(name) as string;
this.mapManifestXML(new ManifestXML(manifest), result);
EffectJsonMapper.mapAnimationXML(new AnimationXML(animation), result);
return result;
}
private mapManifestXML(manifestXML: ManifestXML, output: EffectJson) {
const assets: AssetsJSON = {};
for (const assetXML of manifestXML.library.assets) {
if (assetXML.name.startsWith(EffectJsonMapper.MUST_START_WITH)) {
const asset: AssetJSON = {} as any;
if (assetXML.param != undefined && assetXML.param.value !== undefined) {
asset.x = parseInt(assetXML.param.value.split(",")[0]);
asset.y = parseInt(assetXML.param.value.split(",")[1]);
}
if (BundleProvider.imageSource.has(assetXML.name)) {
asset.source = BundleProvider.imageSource.get(assetXML.name) as string;
}
assets[assetXML.name] = asset;
}
}
output.assets = assets;
if (manifestXML.library.aliases.length > 0 || BundleProvider.imageSource.size > 0) {
const aliases: Aliases = {};
for (const aliasXML of manifestXML.library.aliases) {
if (aliasXML.name.startsWith(EffectJsonMapper.MUST_START_WITH)) {
const alias: Alias = {} as any;
alias.link = aliasXML.link;
if (aliasXML.fliph !== undefined)
alias.fliph = parseInt(aliasXML.fliph.toString());
if (aliasXML.flipv !== undefined)
alias.flipv = parseInt(aliasXML.flipv.toString());
aliases[aliasXML.name] = alias;
}
}
output.aliases = aliases;
}
}
private static mapAnimationXML(animationXML: AnimationXML, output: EffectJson) {
const animations: Animations = {};
const animation: Animation = {} as any;
animation.name = animationXML.name;
animation.desc = animationXML.desc;
animation.resetOnToggle = animationXML.resetOnToggle as any;
const frames: Array<Frame> = new Array<Frame>();
const avatars: Array<Avatar> = new Array<Avatar>();
const directions: Array<DirectionOffset> = new Array<DirectionOffset>();
const shadows: Array<Shadow> = new Array<Shadow>();
const adds: Array<Add> = new Array<Add>();
const removes: Array<Remove> = new Array<Remove>();
const sprites: Array<Sprite> = new Array<Sprite>();
const overrides: Array<Override> = new Array<Override>();
if (animationXML.frames.length > 0) {
for (const frameXML of animationXML.frames) {
const fxs: Array<Fx> = new Array<Fx>();
const bodyparts: Array<Bodypart> = new Array<BodyPartXML>();
const frame: Frame = {} as any;
if (frameXML.fxs.length > 0) {
for (const fxXML of frameXML.fxs) {
const fx: Fx = {} as any;
fx.action = fxXML.action;
if (fxXML.dx !== undefined)
fx.dx = parseInt(fxXML.dx.toString());
if (fxXML.dy !== undefined)
fx.dy = parseInt(fxXML.dy.toString());
if (fxXML.dz !== undefined)
fx.dz = parseInt(fxXML.dz.toString());
if (fxXML.dd !== undefined)
fx.dd = parseInt(fxXML.dd.toString());
if (fxXML.frame !== undefined)
fx.frame = parseInt(fxXML.frame.toString());
fx.id = fxXML.id;
fxs.push(fx);
}
}
if (frameXML.bodyParts.length > 0) {
for (const bodypartXML of frameXML.bodyParts) {
const items: Array<Item> = new Array<Item>();
const bodypart: Bodypart = {} as any;
if (bodypartXML.items.length > 0) {
for (const itemXML of bodypartXML.items) {
const item: Item = {} as any;
item.id = itemXML.id;
item.base = itemXML.base;
items.push(item);
}
}
bodypart.action = bodypartXML.action;
if (bodypartXML.dx !== undefined)
bodypart.dx = parseInt(bodypartXML.dx.toString());
if (bodypartXML.dy !== undefined)
bodypart.dy = parseInt(bodypartXML.dy.toString());
if (bodypartXML.dz !== undefined)
bodypart.dz = parseInt(bodypartXML.dz.toString());
if (bodypartXML.dd !== undefined)
bodypart.dd = parseInt(bodypartXML.dd.toString());
if (bodypartXML.frame !== undefined)
bodypart.frame = parseInt(bodypartXML.frame.toString());
bodypart.id = bodypartXML.id;
bodypart.base = bodypartXML.base;
bodypart.items = items;
bodyparts.push(bodypart);
}
}
if (frameXML.repeats !== undefined) frame.repeats = parseInt(frameXML.repeats.toString());
frame.fxs = fxs;
frame.bodyparts = bodyparts;
frames.push(frame);
}
}
if (animationXML.avatars.length > 0) {
for (const avatarXML of animationXML.avatars) {
const avatar: Avatar = {} as any;
avatar.background = avatarXML.background;
avatar.foreground = avatarXML.foreground;
if (avatarXML.ink !== undefined)
avatar.ink = parseInt(avatarXML.ink.toString());
avatars.push(avatar);
}
}
if (animationXML.directions.length > 0) {
for (const directionXML of animationXML.directions) {
const direction: DirectionOffset = {} as any;
direction.offset = parseInt(directionXML.offset.toString());
directions.push(direction);
}
}
if (animationXML.shadows.length > 0) {
for (const shadowXML of animationXML.shadows) {
const shadow: Shadow = {} as any;
shadow.id = shadowXML.id;
shadows.push(shadow);
}
}
if (animationXML.adds.length > 0) {
for (const addXML of animationXML.adds) {
const add: Add = {} as any;
add.id = addXML.id;
add.align = addXML.align;
add.blend = addXML.blend;
if (addXML.ink !== undefined)
add.ink = parseInt(addXML.ink.toString());
add.base = addXML.base;
adds.push(add);
}
}
if (animationXML.removes.length > 0) {
for (const removeXML of animationXML.removes) {
const remove: Remove = {} as any;
remove.id = removeXML.id;
removes.push(remove);
}
}
if (animationXML.sprites.length > 0) {
for (const spriteXML of animationXML.sprites) {
const sprite: Sprite = {} as any;
const directions2: Array<Direction> = new Array<Direction>();
if (spriteXML.directionList.length > 0) {
for (const directionXML of spriteXML.directionList) {
const direction: Direction = {} as any;
direction.id = parseInt(directionXML.id.toString());
if (directionXML.dx !== undefined)
direction.dx = parseInt(directionXML.dx.toString());
if (directionXML.dy !== undefined)
direction.dy = parseInt(directionXML.dy.toString());
if (directionXML.dz !== undefined)
direction.dz = parseInt(directionXML.dz.toString());
directions2.push(direction);
}
}
sprite.directionList = directions2;
if (spriteXML.directions !== undefined)
sprite.directions = parseInt(spriteXML.directions.toString());
sprite.id = spriteXML.id;
if (spriteXML.ink !== undefined)
sprite.ink = parseInt(spriteXML.ink.toString());
if (spriteXML.member !== undefined)
sprite.member = spriteXML.member;
if (spriteXML.staticY !== undefined)
sprite.staticY = parseInt(spriteXML.staticY.toString());
sprites.push(sprite);
}
}
if (animationXML.overrides.length > 0) {
for (const overrideXML of animationXML.overrides) {
const override: Override = {} as any;
override.name = overrideXML.name;
override.override = overrideXML.override;
if (overrideXML.frames.length > 0) {
const overrideFrames: Array<Frame> = new Array<Frame>();
for (const frameXML of overrideXML.frames) {
const fxs: Array<Fx> = new Array<Fx>();
const bodyparts: Array<Bodypart> = new Array<Bodypart>();
const frame: Frame = {} as any;
if (frameXML.fxs.length > 0) {
for (const fxXML of frameXML.fxs) {
const fx: Fx = {} as any;
fx.action = fxXML.action;
if (fxXML.dx !== undefined)
fx.dx = parseInt(fxXML.dx.toString());
if (fxXML.dy !== undefined)
fx.dy = parseInt(fxXML.dy.toString());
if (fxXML.dz !== undefined)
fx.dz = parseInt(fxXML.dz.toString());
if (fxXML.dd !== undefined)
fx.dd = parseInt(fxXML.dd.toString());
if (fxXML.frame !== undefined)
fx.frame = parseInt(fxXML.frame.toString());
fx.id = fxXML.id;
fxs.push(fx);
}
}
if (frameXML.bodyParts.length > 0) {
for (const bodypartXML of frameXML.bodyParts) {
const items: Array<Item> = new Array<Item>();
const bodypart: Bodypart = {} as any;
if (bodypartXML.items.length > 0) {
for (const itemXML of bodypartXML.items) {
const item: Item = {} as any;
item.id = itemXML.id;
item.base = itemXML.base;
items.push(item);
}
}
bodypart.action = bodypartXML.action;
if (bodypartXML.dx !== undefined)
bodypart.dx = parseInt(bodypartXML.dx.toString());
if (bodypartXML.dy !== undefined)
bodypart.dy = parseInt(bodypartXML.dy.toString());
if (bodypartXML.dz !== undefined)
bodypart.dz = parseInt(bodypartXML.dz.toString());
if (bodypartXML.dd !== undefined)
bodypart.dd = parseInt(bodypartXML.dd.toString());
if (bodypartXML.frame !== undefined)
bodypart.frame = parseInt(bodypartXML.frame.toString());
bodypart.id = bodypartXML.id;
bodypart.base = bodypartXML.base;
bodypart.items = items;
bodyparts.push(bodypart);
}
}
frame.fxs = fxs;
frame.bodyparts = bodyparts;
overrideFrames.push(frame);
}
override.frames = overrideFrames;
overrides.push(override);
}
}
}
animation.frames = frames;
animation.shadows = shadows;
animation.adds = adds;
animation.directions = directions;
animation.avatars = avatars;
animation.removes = removes;
animation.sprites = sprites;
animation.overrides = overrides;
animations[output.name] = animation;
output.animations = animations;
}
}

View File

@ -1,142 +0,0 @@
export class ManifestXML {
private readonly _library: LibraryXML;
constructor(manifestXML: any) {
this._library = new LibraryXML(manifestXML.manifest.library[0]);
}
get library(): LibraryXML {
return this._library;
}
}
export class LibraryXML {
private readonly _name: string;
private readonly _version: string;
private readonly _assets: Array<AssetXML>;
private readonly _aliases: Array<AliasXML>;
constructor(libraryXML: any) {
const attributes = libraryXML.$;
this._name = attributes.id;
this._version = attributes.version;
this._assets = new Array<AssetXML>();
if (libraryXML.assets !== undefined) {
for (const assetParent of libraryXML.assets) {
for (const asset of assetParent.asset) {
this._assets.push(new AssetXML(asset));
}
}
}
this._aliases = new Array<AliasXML>();
if (libraryXML.aliases !== undefined && Array.isArray(libraryXML.aliases)) {
for (const aliasParent of libraryXML.aliases) {
if (Array.isArray(aliasParent.alias)) {
for (const alias of aliasParent.alias) {
this._aliases.push(new AliasXML(alias));
}
}
}
}
}
get name(): string {
return this._name;
}
get version(): string {
return this._version;
}
get assets(): Array<AssetXML> {
return this._assets;
}
get aliases(): Array<AliasXML> {
return this._aliases;
}
}
export class AliasXML {
private readonly _name: string;
private readonly _link: string;
private readonly _fliph: number;
private readonly _flipv: number;
constructor(aliasXML: any) {
const attributes = aliasXML.$;
this._name = attributes.name;
this._link = attributes.link;
this._fliph = attributes.fliph;
this._flipv = attributes.flipv;
}
get name(): string {
return this._name;
}
get link(): string {
return this._link;
}
get fliph(): number {
return this._fliph;
}
get flipv(): number {
return this._flipv;
}
}
export class AssetXML {
private readonly _name: string;
private readonly _mimeType: string;
private readonly _param: ParamXML | undefined;
constructor(assetXML: any) {
const attributes = assetXML.$;
this._name = attributes.name;
this._mimeType = attributes.mimeType;
if (assetXML.param !== undefined) {
for (const param of assetXML.param) {
this._param = new ParamXML(param);
}
}
}
get name(): string {
return this._name;
}
get mimeType(): string {
return this._mimeType;
}
get param(): ParamXML | undefined {
return this._param;
}
}
export class ParamXML {
private readonly _key: string;
private readonly _value: string;
constructor(paramXML: any) {
const attributes = paramXML.$;
this._key = attributes.key;
this._value = attributes.value;
}
get key(): string {
return this._key;
}
get value(): string {
return this._value;
}
}

View File

@ -1,135 +0,0 @@
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface EffectJson {
type: string,
name: string,
spritesheet: SpriteSheetType,
assets: AssetsJSON,
aliases: Aliases,
animations: Animations
}
export interface Animations {
[key: string]: Animation
}
export interface Animation {
name: string,
desc: string,
resetOnToggle: boolean,
directions: Array<DirectionOffset>,
shadows: Array<Shadow>,
adds: Array<Add>,
removes: Array<Remove>,
sprites: Array<Sprite>,
frames: Array<Frame>,
avatars: Array<Avatar>,
overrides: Array<Override>
}
export interface Override {
name: string,
override: string,
frames: Array<Frame>;
}
export interface Avatar {
ink: number,
foreground: string,
background: string
}
export interface Frame {
repeats: number,
fxs: Array<Fx>,
bodyparts: Array<Bodypart>
}
export interface Bodypart {
id: string,
frame: number,
dx: number,
dy: number,
dz: number,
dd: number,
action: string,
base: string,
items: Array<Item>
}
export interface Item {
id: string,
base: string
}
export interface Fx {
id: string,
frame: number,
dx: number,
dy: number,
dz: number,
dd: number,
action: string
}
export interface Sprite {
id: string,
member: string,
directions: number,
staticY: number,
ink: number,
directionList: Array<Direction>;
}
export interface Direction {
id: number,
dx: number,
dy: number,
dz: number,
}
export interface Remove {
id: string
}
export interface Add {
id: string,
align: string,
blend: string,
ink: number,
base: string
}
export interface Shadow {
id: string
}
export interface DirectionOffset {
offset: number
}
export interface Aliases {
[key: string]: Alias
}
export interface Alias {
link: string,
fliph: number,
flipv: number
}
export interface AssetsJSON {
[key: string]: AssetJSON;
}
export interface AssetJSON {
source: string,
x: number,
y: number,
}

View File

@ -1,97 +0,0 @@
import {singleton} from "tsyringe";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import FigureJsonMapper from "./mapper/FigureJsonMapper";
import Configuration from "../config/Configuration";
import {FigureJson} from "./mapper/FigureJsonType";
import DefineBinaryDataTag from "../swf/tags/DefineBinaryDataTag";
import BundleTypes from "../bundle/BundleTypes";
import File from "../utils/File";
import NitroBundle from "../utils/NitroBundle";
import BundleProvider from "../bundle/BundleProvider";
import FigureDownloader from "./FigureDownloader";
import Logger from "../utils/Logger";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
@singleton()
export default class FigureConverter {
constructor(
private readonly _figureDownloader: FigureDownloader,
private readonly _figureJsonMapper: FigureJsonMapper,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider,
private readonly _logger: Logger) {
}
private getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
let binaryName: string = habboAssetSWF.getFullClassName(type, documentNameTwice);
let tag = habboAssetSWF.getBinaryTagByName(binaryName);
if (tag === null) {
binaryName = habboAssetSWF.getFullClassNameSnake(type, documentNameTwice, true);
tag = habboAssetSWF.getBinaryTagByName(binaryName);
}
return tag;
}
private async convertXML2JSON(habboAssetSWF: HabboAssetSWF): Promise<FigureJson | null> {
const manifestXML: DefineBinaryDataTag | null = this.getBinaryData(habboAssetSWF, "manifest", false);
if (manifestXML !== null) {
const result = await parser.parseStringPromise(manifestXML.binaryData);
return this._figureJsonMapper.mapXML(habboAssetSWF, result);
}
return null;
}
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: BundleTypes) {
const manifestJson = await this.convertXML2JSON(habboAssetSWF);
if (manifestJson !== null) {
manifestJson.spritesheet = archiveType.spriteSheetType;
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
const assetOuputFolder = new File(path);
if (assetOuputFolder.exists()) {
console.log("Figure already exists or the directory is not empty!");
return;
}
const nitroBundle = new NitroBundle();
nitroBundle.addFile(habboAssetSWF.getDocumentClass() + ".json", Buffer.from(JSON.stringify(manifestJson)));
nitroBundle.addFile(archiveType.imageData.name, archiveType.imageData.buffer);
const buffer = await nitroBundle.toBufferAsync();
await fs.writeFile(path, buffer);
}
}
public async convertAsync() {
const outputFolderFigure = new File(this._config.getValue("output.folder.figure"));
if (!outputFolderFigure.isDirectory()) {
outputFolderFigure.mkdirs();
}
const figureConverter = this;
await this._figureDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing figure: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await figureConverter._bundleProvider.generateSpriteSheet(habboAssetSwf, outputFolderFigure.path, "figure");
if (spriteSheetType !== null)
await figureConverter.fromHabboAsset(habboAssetSwf, outputFolderFigure.path, "figure", spriteSheetType);
} catch (e) {
await figureConverter._logger.logErrorAsync("Figure error: " + habboAssetSwf.getDocumentClass() + e);
console.log("Figure error: " + habboAssetSwf.getDocumentClass());
console.log(e);
}
});
}
}

View File

@ -1,81 +0,0 @@
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fetch = require('node-fetch');
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
@singleton()
export default class FigureDownloader {
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
public static types: Map<string, string> = new Map<string, string>();
public async download(callback: (habboAssetSwf: HabboAssetSWF) => Promise<void>) {
const outputFolderFigure = this._config.getValue("output.folder.figure");
const figureMap = await this.parseFigureMap();
const map = figureMap.map;
for (const lib of map.lib) {
const info = lib['$'];
const className: string = info.id.split("\\*")[0];
if (className === "hh_human_fx" || className === "hh_pets") {
continue;
}
const assetOutputFolder = new File(outputFolderFigure + "/" + className);
if (assetOutputFolder.exists()) {
continue;
}
if (!FigureDownloader.types.has(className)) {
const url = this._config.getValue("dynamic.download.url.figure").replace("%className%", className);
let buffer: Buffer | null = null;
if (url.includes("http")) {
const fetchData = await fetch(url);
if (fetchData.status === 404) {
console.log("SWF File does not exist: " + url);
continue;
}
const arrayBuffer = await fetchData.arrayBuffer();
buffer = Buffer.from(arrayBuffer);
} else {
const file = new File(url);
if (!file.exists()) {
console.log("SWF File does not exist: " + file.path);
continue;
}
}
try {
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(buffer !== null ? buffer : url);
await newHabboAssetSWF.setupAsync();
FigureDownloader.types.set(className, lib.part[0]['$'].type);
await callback(newHabboAssetSWF);
} catch (e) {
await this._logger.logErrorAsync("[" + className + "]" + e);
}
}
}
}
async parseFigureMap() {
const figureMapPath = this._config.getValue("figuremap.url");
const figureFetch = await fetch(figureMapPath);
const figureMap = await figureFetch.text();
return await parser.parseStringPromise(figureMap);
}
}

View File

@ -1,81 +0,0 @@
import Configuration from "../../config/Configuration";
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import {FigureAsset, FigureAssets, FigureJson} from "./FigureJsonType";
import {FigureXMLManifest} from "./FigureXMLTypes";
import FigureDownloader from "../FigureDownloader";
import {singleton} from "tsyringe";
import BundleProvider from "../../bundle/BundleProvider";
@singleton()
export default class FigureJsonMapper {
private static MUST_START_WITH: string = "h_";
constructor(
private readonly _config: Configuration
) {
}
public mapXML(habboAssetSWF: HabboAssetSWF, manifestXML: any): FigureJson {
const name = habboAssetSWF.getDocumentClass();
return {
name: name,
type: FigureDownloader.types.get(name) as string,
assets: this.mapManifestXML(habboAssetSWF, manifestXML),
spritesheet: null as any
};
}
private mapManifestXML(habboAssetSWF: HabboAssetSWF, manifestXML: any): FigureAssets {
const assets: any = {};
const figureXMLManifest: FigureXMLManifest = new FigureXMLManifest(manifestXML.manifest);
for (const asset of figureXMLManifest.library.assets) {
const name = asset.name;
if (name.startsWith(FigureJsonMapper.MUST_START_WITH)) {
let hasImage = false;
for (const imageTag of habboAssetSWF.imageTags()) {
if (imageTag.className.includes(name)) {
hasImage = true;
}
}
if (hasImage || !this._config.getBoolean("figure.skip.non-existing.asset.images")) {
const figureAsset: FigureAsset = {} as any;
figureAsset.name = name;
figureAsset.x = parseFloat(asset.param.value.split(',')[0]);
figureAsset.y = parseFloat(asset.param.value.split(',')[1]);
if (BundleProvider.imageSource.has(name)) {
figureAsset.source = BundleProvider.imageSource.get(name) as string;
}
assets[name] = figureAsset;
/*FigureJSON.Asset asset = new FigureJSON.Asset();
if (FFConverter.getConfig().getBoolean("figure.rotation.enabled")) {
String[] names = assetXML.getName().split("_");
if (this.isInteger(names[4])) {
String firstName = names[0] + "_" + names[1] + "_" + names[2] + "_" + names[3] + "_%ROTATION%_" + names[5];
Integer rotation = Integer.parseInt(names[4]);
if (rotation >= 0 && rotation < 8) {
if (assetRotations.containsKey(firstName)) {
assetRotations.get(firstName).add(rotation);
} else {
List<Integer> rotations = new ArrayList<Integer>();
rotations.add(rotation);
assetRotations.put(firstName, rotations);
}
}
}
}*/
} else {
console.log("Image " + name + " did not decompile for some reason");
}
}
}
return assets;
}
}

View File

@ -1,20 +0,0 @@
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface FigureJson {
type: string,
name: string,
spritesheet: SpriteSheetType,
assets: FigureAssets
}
export interface FigureAssets {
[key: string]: FigureAsset
}
export interface FigureAsset {
name: string,
source: string,
x: number,
y: number,
flipH: boolean
}

View File

@ -1,59 +0,0 @@
export class FigureXMLManifest {
private readonly _library: FigureXMLLibrary;
constructor(manifestXML: any) {
this._library = new FigureXMLLibrary(manifestXML.library[0]);
}
get library(): FigureXMLLibrary {
return this._library;
}
}
export class FigureXMLLibrary {
private readonly _assets: FigureXMLAsset[];
constructor(libraryXML: any) {
this._assets = [];
for (const assetObj of libraryXML.assets) {
for (const asset of assetObj.asset) {
this._assets.push(new FigureXMLAsset(asset));
}
}
}
get assets(): FigureXMLAsset[] {
return this._assets;
}
}
export class FigureXMLAsset {
private readonly _name: string;
private readonly _param: FigureXMLParam;
constructor(assetXML: any) {
this._name = assetXML.$.name;
this._param = new FigureXMLParam(assetXML.param[0]);
}
get name(): string {
return this._name;
}
get param(): FigureXMLParam {
return this._param;
}
}
export class FigureXMLParam {
private readonly _value: string;
constructor(paramXML: any) {
this._value = paramXML.$.value;
}
get value(): string {
return this._value;
}
}

View File

@ -1,129 +0,0 @@
import FurniJsonMapper from "./mapper/FurniJsonMapper";
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../swf/tags/DefineBinaryDataTag";
import {FurniJson} from "./mapper/FurniTypes";
import BundleTypes from "../bundle/BundleTypes";
import File from "../utils/File";
import NitroBundle from "../utils/NitroBundle";
import BundleProvider from "../bundle/BundleProvider";
import FurnitureDownloader from "./FurnitureDownloader";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
@singleton()
export default class FurnitureConverter {
constructor(
private readonly _furniDownloader: FurnitureDownloader,
private readonly _furniJsonMapper: FurniJsonMapper,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider,
private readonly _logger: Logger) {
}
private static getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
let binaryName: string = habboAssetSWF.getFullClassName(type, documentNameTwice);
let tag = habboAssetSWF.getBinaryTagByName(binaryName);
if (tag === null) {
binaryName = habboAssetSWF.getFullClassNameSnake(type, documentNameTwice, true);
tag = habboAssetSWF.getBinaryTagByName(binaryName);
}
return tag;
}
private static async getAssetsXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
const binaryData: DefineBinaryDataTag | null = FurnitureConverter.getBinaryData(habboAssetSWF, "assets", true);
if (binaryData !== null) {
return await parser.parseStringPromise(binaryData.binaryData);
}
return null;
}
private static async getLogicXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
const binaryData: DefineBinaryDataTag | null = FurnitureConverter.getBinaryData(habboAssetSWF, "logic", true);
if (binaryData !== null) {
return await parser.parseStringPromise(binaryData.binaryData);
}
return null;
}
private static async getIndexXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
const binaryData: DefineBinaryDataTag | null = FurnitureConverter.getBinaryData(habboAssetSWF, "index", false);
if (binaryData !== null) {
return await parser.parseStringPromise(binaryData.binaryData);
}
return null;
}
private static async getVisualizationXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
const binaryData: DefineBinaryDataTag | null = FurnitureConverter.getBinaryData(habboAssetSWF, "visualization", true);
if (binaryData !== null) {
return await parser.parseStringPromise(binaryData.binaryData);
}
return null;
}
private async convertXML2JSON(habboAssetSWF: HabboAssetSWF): Promise<FurniJson | null> {
const assetXml = await FurnitureConverter.getAssetsXML(habboAssetSWF);
const logicXml = await FurnitureConverter.getLogicXML(habboAssetSWF);
const indexXml = await FurnitureConverter.getIndexXML(habboAssetSWF);
const visualizationXml = await FurnitureConverter.getVisualizationXML(habboAssetSWF);
return this._furniJsonMapper.mapXML(assetXml, indexXml, logicXml, visualizationXml);
}
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: BundleTypes) {
const furnitureJson = await this.convertXML2JSON(habboAssetSWF);
if (furnitureJson !== null) {
furnitureJson.spritesheet = archiveType.spriteSheetType;
furnitureJson.type = type;
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
const assetOutputFolder = new File(path);
if (assetOutputFolder.exists()) {
console.log("Furniture already exists or the directory is not empty!");
return;
}
const nitroBundle = new NitroBundle();
nitroBundle.addFile(habboAssetSWF.getDocumentClass() + ".json", Buffer.from(JSON.stringify(furnitureJson)));
nitroBundle.addFile(archiveType.imageData.name, archiveType.imageData.buffer);
const buffer = await nitroBundle.toBufferAsync();
await fs.writeFile(path, buffer);
}
}
public async convertAsync() {
const outputFolderFurniture = new File(this._config.getValue("output.folder.furniture"));
if (!outputFolderFurniture.isDirectory()) {
outputFolderFurniture.mkdirs();
}
const furnitureConverter = this;
await this._furniDownloader.download(async function (habboAssetSwf: HabboAssetSWF, className: string) {
console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await furnitureConverter._bundleProvider.generateSpriteSheet(habboAssetSwf, outputFolderFurniture.path, "furniture");
if (spriteSheetType !== null) {
await furnitureConverter.fromHabboAsset(habboAssetSwf, outputFolderFurniture.path, "furniture", spriteSheetType);
}
} catch (e) {
await furnitureConverter._logger.logErrorAsync("Furniture error: " + habboAssetSwf.getDocumentClass() + " " + e);
}
});
}
}

View File

@ -1,116 +0,0 @@
import HabboAssetSWF from "../swf/HabboAssetSWF";
import Configuration from "../config/Configuration";
import {type} from "os";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fs = require("fs");
const fetch = require('node-fetch');
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const util = require('util');
const readFile = util.promisify(fs.readFile);
@singleton()
export default class FurnitureDownloader {
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
public async download(callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>) {
const outputFolderFurniture = new File(this._config.getValue("output.folder.furniture"));
const furniDataObj = await this.parseFurniData();
const furniData = furniDataObj.furnidata;
const roomitemtypes = furniData.roomitemtypes;
const wallitemtypes = furniData.wallitemtypes;
const classNames: Array<string> = new Array<string>();
for (const roomItem of roomitemtypes) {
for (const furnitype of roomItem.furnitype) {
const attributes = furnitype['$'];
const className = attributes.classname.split("\*")[0];
const revision = furnitype.revision[0];
if (classNames.includes(className)) continue;
else classNames.push(className);
const assetOuputFolder = new File(outputFolderFurniture.path + "/" + className);
if (assetOuputFolder.isDirectory()) {
continue;
}
await this.extractFurniture(revision, className, callback);
}
}
for (const wallItem of wallitemtypes) {
for (const furnitype of wallItem.furnitype) {
const attributes = furnitype['$'];
const className = attributes.classname.split("\*")[0];
const revision = furnitype.revision[0];
if (classNames.includes(className)) continue;
else classNames.push(className);
const assetOuputFolder = new File(outputFolderFurniture + "/" + className);
if (assetOuputFolder.isDirectory()) {
continue;
}
await this.extractFurniture(revision, className, callback);
}
}
}
async extractFurniture(revision: string, className: string, callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>) {
//if (/*className !== 'present_wrap' && */className !== 'holo_dragon') return;
const url = this._config.getValue("dynamic.download.url.furniture").replace("%revision%", revision).replace("%className%", className);
let buffer: Buffer | null = null;
if (url.includes("http")) {
const fetchData = await fetch(url);
if (fetchData.status === 404) {
console.log("SWF File does not exist: " + url);
return;
}
const arrayBuffer = await fetchData.arrayBuffer();
buffer = Buffer.from(arrayBuffer);
} else {
const file = new File(url);
if (!file.exists()) {
console.log("SWF File does not exist: " + file.path);
return;
}
}
try {
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(buffer !== null ? buffer : url);
await newHabboAssetSWF.setupAsync();
await callback(newHabboAssetSWF, className);
} catch (e) {
await this._logger.logErrorAsync(`Error with furniture: ${url} \n ${e}`);
}
}
async parseFurniData() {
const furniDataFetch = this._config.getValue("furnidata.url");
if (furniDataFetch.includes("http")) {
const furniFetch = await fetch(furniDataFetch);
const furniData = await furniFetch.text();
return await parser.parseStringPromise(furniData);
} else {
const content = await readFile(furniDataFetch);
return await parser.parseStringPromise(content);
}
}
}

View File

@ -1,360 +0,0 @@
import {
Action,
Animation,
AnimationLayer,
AnimationLayers,
Animations,
Color,
ColorLayer,
ColorLayers,
Colors,
Direction,
Directions,
Frame,
Frames,
FrameSequence,
FrameSequences,
FurniAsset,
FurniAssets,
FurniJson, Gesture, Gestures,
Layer,
Offset, Posture, Postures,
Visualization,
VisualizationLayers
} from "./FurniTypes";
import {AssetsXML, IndexXML, LogicXML} from "./FurniXMLTypes";
import {
AnimationLayerXML,
AnimationXML,
ColorXML,
LayerXML,
VisualizationDataXML,
VisualizationXML
} from "./VisualizationXMLTypes";
import BundleProvider from "../../bundle/BundleProvider";
import {singleton} from "tsyringe";
@singleton()
export default class FurniJsonMapper {
private static readonly VISUALIZATION_DEFAULT_SIZE = 64;
private static readonly VISUALIZATION_ICON_SIZE = 1;
public mapXML(assets: any, indexXML: any, logic: any, visualization: any): FurniJson {
const furniJson: FurniJson = {} as any;
this.mapAssetsXML(new AssetsXML(assets), furniJson);
FurniJsonMapper.mapIndexXML(new IndexXML(indexXML.object), furniJson);
FurniJsonMapper.mapLogicXML(new LogicXML(logic.objectData), furniJson);
FurniJsonMapper.mapVisualizationXML(new VisualizationDataXML(visualization.visualizationData), furniJson);
return furniJson;
}
private mapAssetsXML(assetsXML: AssetsXML, output: FurniJson) {
const assets: FurniAssets = {} as any;
for (const asset of assetsXML.assets) {
if (!asset.name.includes("_32_")) {
const furniAsset: FurniAsset = {} as any;
if (asset.source !== undefined) {
furniAsset.source = asset.source;
if (BundleProvider.imageSource.has(asset.source)) {
furniAsset.source = BundleProvider.imageSource.get(asset.source) as string;
}
}
if (BundleProvider.imageSource.has(asset.name)) {
furniAsset.source = BundleProvider.imageSource.get(asset.name) as string;
}
if (asset.x !== undefined)
furniAsset.x = parseInt(asset.x.toString());
if (asset.y !== undefined)
furniAsset.y = parseInt(asset.y.toString());
furniAsset.flipH = asset.flipH as any;
assets[asset.name] = furniAsset;
}
}
if (Object.keys(assets).length > 0) {
output.assets = assets;
}
}
private static mapIndexXML(indexXML: IndexXML, output: FurniJson) {
output.name = indexXML.type;
output.logicType = indexXML.logic;
output.visualizationType = indexXML.visualization;
}
private static mapLogicXML(logicXML: LogicXML, output: FurniJson) {
output.dimensions = {
x: parseInt(logicXML.model.dimensions.x.toString()),
y: parseInt(logicXML.model.dimensions.y.toString()),
z: parseInt(logicXML.model.dimensions.z.toString())
}
const directions: Array<number> = [];
if (logicXML.model.directions.length === 0) {
directions.push(0);
} else {
for (const direction of logicXML.model.directions) {
directions.push(parseInt(direction.id.toString()));
}
}
if (logicXML.action !== undefined) {
const action: Action = {} as any;
if (logicXML.action.link !== undefined) action.link = logicXML.action.link;
if (logicXML.action.startState !== undefined) action.startState = logicXML.action.startState;
output.action = action;
}
if (logicXML.mask !== undefined) {
output.maskType = logicXML.mask.type;
}
if (logicXML.credits !== undefined) {
output.credits = logicXML.credits.value;
}
output.directions = directions;
}
private static mapVisualizationXML(visualizationData: VisualizationDataXML, output: FurniJson) {
const visualizationsArray: Array<Visualization> = new Array<Visualization>();
for (const visualization of visualizationData.visualizations) {
if (visualization.size == FurniJsonMapper.VISUALIZATION_DEFAULT_SIZE || visualization.size == FurniJsonMapper.VISUALIZATION_ICON_SIZE) {
const visualizationJson: Visualization = {} as any;
visualizationJson.angle = parseInt(visualization.angle.toString());
visualizationJson.layerCount = parseInt(visualization.layerCount.toString());
visualizationJson.size = parseInt(visualization.size.toString());
FurniJsonMapper.mapVisualizationLayerXML(visualization, visualizationJson);
FurniJsonMapper.mapVisualizationDirectionXML(visualization, visualizationJson);
FurniJsonMapper.mapVisualizationColorXML(visualization, visualizationJson);
FurniJsonMapper.mapVisualizationAnimationXML(visualization, visualizationJson);
FurniJsonMapper.mapVisualizationPostureXML(visualization, visualizationJson);
FurniJsonMapper.mapVisualizationGestureXML(visualization, visualizationJson);
visualizationsArray.push(visualizationJson);
}
}
output.visualizations = visualizationsArray;
}
private static mapVisualizationLayerXML(visXML: VisualizationXML, output: Visualization) {
if (visXML.layers.length > 0) {
output.layers = FurniJsonMapper.mapVisualizationLayersXML(visXML.layers);
}
}
private static mapVisualizationLayersXML(layersXML: Array<LayerXML>): VisualizationLayers {
const layers: VisualizationLayers = {};
for (const layerXML of layersXML) {
const layer: Layer = {} as any;
if (layerXML.alpha !== undefined)
layer.alpha = parseInt(layerXML.alpha.toString());
layer.ink = layerXML.ink;
layer.tag = layerXML.tag;
if (layerXML.x !== undefined)
layer.x = parseInt(layerXML.x.toString());
if (layerXML.y !== undefined)
layer.y = parseInt(layerXML.y.toString());
if (layerXML.z !== undefined)
layer.z = parseInt(layerXML.z.toString());
layer.ignoreMouse = layerXML.ignoreMouse as any;
layers[layerXML.id] = layer;
}
return layers;
}
private static mapVisualizationDirectionXML(visXML: VisualizationXML, output: Visualization) {
if (visXML.directions.length > 0) {
const directions: Directions = {} as any;
for (const directionXML of visXML.directions) {
const direction: Direction = {} as any;
if (directionXML.layers.length > 0) {
direction.layers = FurniJsonMapper.mapVisualizationLayersXML(directionXML.layers);
}
directions[directionXML.id] = direction;
}
if (Object.keys(directions).length > 0) {
output.directions = directions;
}
}
}
private static mapVisualizationColorXML(visXML: VisualizationXML, output: Visualization) {
if (visXML.colors.length > 0) {
const colors: Colors = {};
for (const colorXML of visXML.colors) {
if (colorXML.layers.length > 0) {
const color: Color = {} as any;
color.layers = FurniJsonMapper.mapVisualizationColorLayerXML(colorXML);
colors[colorXML.id] = color;
}
}
if (Object.keys(colors).length > 0) {
output.colors = colors;
}
}
}
private static mapVisualizationColorLayerXML(colorXML: ColorXML): ColorLayers {
const colorLayers: ColorLayers = {};
for (const colorLayerXML of colorXML.layers) {
const colorLayer: ColorLayer = {} as any;
colorLayer.color = parseInt(colorLayerXML.color, 16);
colorLayers[colorLayerXML.id] = colorLayer;
}
return colorLayers;
}
private static mapVisualizationAnimationXML(visXML: VisualizationXML, output: Visualization) {
if (visXML.animations.length > 0) {
const animations: Animations = {};
for (const animationXML of visXML.animations) {
if (animationXML.layers.length > 0) {
const animation: Animation = {} as any;
if (animationXML.transitionTo !== undefined)
animation.transitionTo = parseInt(animationXML.transitionTo.toString());
if (animationXML.transitionFrom !== undefined)
animation.transitionFrom = parseInt(animationXML.transitionFrom.toString());
animation.immediateChangeFrom = animationXML.immediateChangeFrom;
animation.layers = FurniJsonMapper.mapVisualizationAnimationLayerXML(animationXML);
animations[animationXML.id] = animation;
}
}
if (Object.keys(animations).length > 0) {
output.animations = animations;
}
}
}
private static mapVisualizationAnimationLayerXML(animationXML: AnimationXML): AnimationLayers {
const animationLayers: AnimationLayers = {};
for (const animationLayerXML of animationXML.layers) {
const animationLayer: AnimationLayer = {} as any;
if (animationLayerXML.frameRepeat !== undefined)
animationLayer.frameRepeat = parseInt(animationLayerXML.frameRepeat.toString());
if (animationLayerXML.loopCount !== undefined)
animationLayer.loopCount = parseInt(animationLayerXML.loopCount.toString());
if (animationLayerXML.random !== undefined)
animationLayer.random = parseInt(animationLayerXML.random.toString());
if (animationLayerXML.frameSequences.length > 0) {
animationLayer.frameSequences = FurniJsonMapper.mapVisualizationFrameSequenceXML(animationLayerXML);
animationLayers[animationLayerXML.id] = animationLayer;
}
}
return animationLayers;
}
private static mapVisualizationFrameSequenceXML(animationLayerXML: AnimationLayerXML): FrameSequences {
const frameSequences: FrameSequences = {};
let frameSequenceCount = 0;
for (const frameSequenceXML of animationLayerXML.frameSequences) {
const frameSequence: FrameSequence = {} as any;
if (frameSequenceXML.frames.length > 0) {
let frameId = 0;
const frames: Frames = {};
for (const frameXML of frameSequenceXML.frames) {
const frame: Frame = {} as any;
if (frameXML.x !== undefined)
frame.x = parseInt(frameXML.x.toString());
if (frameXML.y !== undefined)
frame.y = parseInt(frameXML.y.toString());
if (frameXML.randomX !== undefined)
frame.randomX = parseInt(frameXML.randomX.toString());
if (frameXML.randomY !== undefined)
frame.randomY = parseInt(frameXML.randomY.toString());
if (frameXML.id === "NaN") {
frame.id = 0;
} else {
frame.id = parseInt(frameXML.id);
}
if (frameXML.offsets.length > 0) {
const offsets: Array<Offset> = new Array<Offset>();
for (const offsetXML of frameXML.offsets) {
const offset: Offset = {} as any;
offset.direction = offsetXML.direction;
offset.x = offsetXML.x;
offset.y = offsetXML.y;
offsets.push(offset);
}
frame.offsets = offsets;
}
frames[frameId] = frame;
frameId++;
}
frameSequence.loopCount = frameSequenceXML.loopCount;
frameSequence.random = frameSequenceXML.random;
frameSequence.frames = frames;
frameSequences[frameSequenceCount] = frameSequence;
}
frameSequenceCount++;
}
return frameSequences;
}
private static mapVisualizationPostureXML(visXML: VisualizationXML, output: Visualization) {
if (visXML.postures.length > 0) {
const postures: Postures = {};
for (const postureXML of visXML.postures) {
const posture: Posture = {} as any;
posture.id = postureXML.id;
posture.animationId = postureXML.animationId;
postures[postureXML.id] = posture;
}
if (Object.keys(postures).length > 0) {
output.postures = postures;
}
}
}
private static mapVisualizationGestureXML(visXML: VisualizationXML, output: Visualization) {
if (visXML.gestures.length > 0) {
const gestures: Gestures = {};
for (const gestureXML of visXML.gestures) {
const gesture: Gesture = {} as any;
gesture.id = gestureXML.id;
gesture.animationId = gestureXML.animationId;
gestures[gestureXML.id] = gesture;
}
if (Object.keys(gestures).length > 0) {
output.gestures = gestures;
}
}
}
}

View File

@ -1,164 +0,0 @@
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface FurniJson {
type: string,
name: string,
visualizationType: string,
logicType: string,
maskType: string,
credits: string,
spritesheet: SpriteSheetType,
dimensions: Dimensions,
action: Action;
directions: number[],
assets: FurniAssets,
visualizations: Visualization[]
}
export interface Visualization {
layerCount: number,
angle: number,
size: number,
layers: VisualizationLayers,
directions: Directions,
colors: Colors,
animations: Animations,
postures: Postures;
gestures: Gestures
}
export interface Gestures {
[key: string]: Gesture
}
export interface Gesture {
id: string,
animationId: number
}
export interface Postures {
[key: string]: Posture
}
export interface Posture {
id: string,
animationId: number
}
export interface Offset {
direction: number,
x: number,
y: number
}
export interface Frame {
id: number,
x: number,
y: number,
randomX: number,
randomY: number,
offsets: Offset[]
}
export interface Frames {
[key: number]: Frame
}
export interface FrameSequence {
loopCount: number,
random: number,
frames: Frames
}
export interface FrameSequences {
[key: number]: FrameSequence
}
export interface AnimationLayer {
loopCount: number,
frameRepeat: number,
random: number,
frameSequences: FrameSequences
}
export interface AnimationLayers {
[key: number]: AnimationLayer
}
export interface Animations {
[key: number]: Animation
}
export interface Animation {
transitionTo: number,
transitionFrom: number,
immediateChangeFrom: string,
layers: AnimationLayers;
}
export interface ColorLayers {
[key: number]: ColorLayer
}
export interface ColorLayer {
color: number
}
export interface Colors {
[key: number]: Color
}
export interface Color {
layers: ColorLayers;
}
export interface Directions {
[key: number]: Direction
}
export interface Direction {
layers: VisualizationLayers;
}
export interface VisualizationLayers {
[key: number]: Layer
}
export interface Layer {
alpha: number,
x: number,
y: number,
z: number,
ink: string,
tag: string,
ignoreMouse: boolean
}
export interface Action {
link: string,
startState: number
}
export interface Dimensions {
x: number,
y: number,
z: number
}
export interface FurniAssets {
[key: string]: FurniAsset
}
export interface FurniAsset {
source: string,
x: number,
y: number,
flipH: boolean
}

View File

@ -1,247 +0,0 @@
export class AssetsXML {
private readonly _assets: Array<AssetXML>;
constructor(assetsXML: any) {
this._assets = new Array<AssetXML>();
for (const asset of assetsXML.assets.asset) {
this._assets.push(new AssetXML(asset));
}
}
get assets(): Array<AssetXML> {
return this._assets;
}
}
export class AssetXML {
private readonly _name: string;
private readonly _source: string | undefined;
private readonly _x: number;
private readonly _y: number;
private readonly _flipH: boolean | undefined;
private readonly _usesPalette: number | undefined;
constructor(asset: any) {
const attributes = asset.$;
this._name = attributes.name;
if (attributes.source !== undefined)
this._source = attributes.source;
this._x = attributes.x;
this._y = attributes.y;
if (attributes.flipH !== undefined)
this._flipH = attributes.flipH === '1';
if (attributes.usesPalette !== undefined)
this._usesPalette = attributes.usesPalette;
}
get name(): string {
return this._name;
}
get source(): string | undefined {
return this._source;
}
get x(): number {
return this._x;
}
get y(): number {
return this._y;
}
get flipH(): boolean | undefined {
return this._flipH;
}
get usesPalette(): number | undefined {
return this._usesPalette;
}
}
export class IndexXML {
private readonly _type: string;
private readonly _visualization: string;
private readonly _logic: string;
constructor(indexXML: any) {
const attributes = indexXML.$;
this._type = attributes.type;
this._visualization = attributes.visualization;
this._logic = attributes.logic;
}
get type(): string {
return this._type;
}
get visualization(): string {
return this._visualization;
}
get logic(): string {
return this._logic;
}
}
export class LogicXML {
private readonly _type: string;
private readonly _model: ModelXML;
private readonly _action: ActionXML | undefined;
private readonly _mask: MaskXML | undefined;
private readonly _credits: CreditsXML | undefined;
constructor(logicXML: any) {
const attributes = logicXML.$;
this._type = attributes.type;
this._model = new ModelXML(logicXML.model[0]);
if (logicXML.action !== undefined)
this._action = new ActionXML(logicXML.action[0]);
if (logicXML.mask !== undefined)
this._mask = new MaskXML(logicXML.mask[0]);
if (logicXML.credits !== undefined)
this._credits = new CreditsXML(logicXML.credits[0]);
}
get type(): string {
return this._type;
}
get model(): ModelXML {
return this._model;
}
get action(): ActionXML | undefined {
return this._action;
}
get mask(): MaskXML | undefined {
return this._mask;
}
get credits(): CreditsXML | undefined {
return this._credits;
}
}
export class ModelXML {
private readonly _dimensions: DimensionsXML;
private readonly _directions: Array<DirectionXML>;
constructor(modelXML: any) {
this._dimensions = new DimensionsXML(modelXML.dimensions[0]);
this._directions = new Array<DirectionXML>();
if (Array.isArray(modelXML.directions)) {
for (const directionParent of modelXML.directions) {
if (Array.isArray(directionParent.direction)) {
for (const direction of directionParent.direction) {
this._directions.push(new DirectionXML(direction.$));
}
} else {
console.log(directionParent.direction);
}
}
}
}
get dimensions(): DimensionsXML {
return this._dimensions;
}
get directions(): Array<DirectionXML> {
return this._directions;
}
}
export class DimensionsXML {
private readonly _x: number;
private readonly _y: number;
private readonly _z: number;
constructor(dimensionsXML: any) {
const attributes = dimensionsXML.$;
this._x = attributes.x;
this._y = attributes.y;
this._z = attributes.z;
}
get x(): number {
return this._x;
}
get y(): number {
return this._y;
}
get z(): number {
return this._z;
}
}
export class DirectionXML {
private readonly _id: number;
constructor(directionXML: any) {
this._id = directionXML.id;
}
get id(): number {
return this._id;
}
}
export class ActionXML {
private readonly _link: string;
private readonly _startState: number;
constructor(actionXML: any) {
const attributes = actionXML.$;
this._link = attributes.link;
this._startState = attributes.startState;
}
get link(): string {
return this._link;
}
get startState(): number {
return this._startState;
}
}
export class MaskXML {
private readonly _type: string;
constructor(maskXML: any) {
this._type = maskXML.$.type;
}
get type(): string {
return this._type;
}
}
export class CreditsXML {
private readonly _value: string;
constructor(creditsXML: any) {
this._value = creditsXML.$.value;
}
get value(): string {
return this._value;
}
}

View File

@ -1,517 +0,0 @@
export class VisualizationDataXML {
private readonly _type: string;
private readonly _visualizations: Array<VisualizationXML>;
constructor(visualizationXML: any) {
this._type = visualizationXML.$.type;
this._visualizations = new Array<VisualizationXML>();
if (Array.isArray(visualizationXML.graphics)) {
for (const graphic of visualizationXML.graphics) {
for (const visualization of graphic.visualization) {
this._visualizations.push(new VisualizationXML(visualization));
}
}
}
}
get type(): string {
return this._type;
}
get visualizations(): Array<VisualizationXML> {
return this._visualizations;
}
}
export class VisualizationXML {
private readonly _size: number;
private readonly _layerCount: number;
private readonly _angle: number;
private readonly _layers: Array<LayerXML>;
private readonly _directions: Array<DirectionXML>;
private readonly _colors: Array<ColorXML>;
private readonly _animations: Array<AnimationXML>;
private readonly _postures: Array<PostureXML>;
private readonly _gestures: Array<GestureXML>;
constructor(visualizationXML: any) {
const attributes = visualizationXML.$;
this._size = attributes.size;
this._layerCount = attributes.layerCount;
this._angle = attributes.angle;
this._layers = new Array<LayerXML>();
if (visualizationXML.layers !== undefined)
for (const layerParent of visualizationXML.layers) {
if (Array.isArray(layerParent.layer)) {
for (const layer of layerParent.layer) {
this._layers.push(new LayerXML(layer));
}
}
}
this._directions = new Array<DirectionXML>();
if (visualizationXML.directions !== undefined) {
for (const directionParent of visualizationXML.directions) {
if (Array.isArray(directionParent.direction)) {
for (const direction of directionParent.direction) {
this._directions.push(new DirectionXML(direction));
}
}
}
}
this._colors = new Array<ColorXML>();
if (visualizationXML.colors !== undefined) {
for (const colorParent of visualizationXML.colors) {
if (Array.isArray(colorParent.color)) {
for (const color of colorParent.color) {
this._colors.push(new ColorXML(color));
}
}
}
}
this._animations = new Array<AnimationXML>();
if (visualizationXML.animations !== undefined) {
for (const animationParent of visualizationXML.animations) {
if (Array.isArray(animationParent.animation)) {
for (const animation of animationParent.animation) {
this._animations.push(new AnimationXML(animation));
}
}
}
}
this._postures = new Array<PostureXML>();
if (visualizationXML.postures !== undefined) {
for (const postureParent of visualizationXML.postures) {
if (Array.isArray(postureParent.posture)) {
for (const posture of postureParent.posture) {
this._postures.push(new PostureXML(posture));
}
}
}
}
this._gestures = new Array<GestureXML>();
if (visualizationXML.gestures !== undefined) {
for (const gestureParent of visualizationXML.gestures) {
if (Array.isArray(gestureParent.gesture)) {
for (const gesture of gestureParent.gesture) {
this._gestures.push(new GestureXML(gesture));
}
}
}
}
}
get size(): number {
return this._size;
}
get layerCount(): number {
return this._layerCount;
}
get angle(): number {
return this._angle;
}
get layers(): Array<LayerXML> {
return this._layers;
}
get directions(): Array<DirectionXML> {
return this._directions;
}
get colors(): Array<ColorXML> {
return this._colors;
}
get animations(): Array<AnimationXML> {
return this._animations;
}
get postures(): Array<PostureXML> {
return this._postures;
}
get gestures(): Array<GestureXML> {
return this._gestures;
}
}
export class LayerXML {
private readonly _id: number;
private readonly _alpha: number;
private readonly _x: number;
private readonly _y: number;
private readonly _z: number;
private readonly _ink: string;
private readonly _tag: string;
private readonly _ignoreMouse: boolean | undefined;
constructor(layerXML: any) {
const attributes = layerXML.$;
this._id = attributes.id;
this._alpha = attributes.alpha;
this._x = attributes.x;
this._y = attributes.y;
this._z = attributes.z;
this._ink = attributes.ink;
this._tag = attributes.tag;
if (attributes.ignoreMouse !== undefined) {
this._ignoreMouse = attributes.ignoreMouse === '1';
}
}
get id(): number {
return this._id;
}
get alpha(): number {
return this._alpha;
}
get x(): number {
return this._x;
}
get y(): number {
return this._y;
}
get z(): number {
return this._z;
}
get ink(): string {
return this._ink;
}
get tag(): string {
return this._tag;
}
get ignoreMouse(): boolean | undefined {
return this._ignoreMouse;
}
}
export class DirectionXML {
private readonly _id: number;
private readonly _layers: Array<LayerXML>;
constructor(directionXML: any) {
this._id = directionXML.$.id;
this._layers = new Array<LayerXML>();
if (directionXML.layer !== undefined) {
for (const layer of directionXML.layer) {
this._layers.push(new LayerXML(layer));
}
}
}
get id(): number {
return this._id;
}
get layers(): Array<LayerXML> {
return this._layers;
}
}
export class ColorXML {
private readonly _id: number;
private readonly _layers: Array<ColorLayerXML>;
constructor(colorXML: any) {
this._id = colorXML.$.id;
this._layers = new Array<ColorLayerXML>();
for (const colorLayer of colorXML.colorLayer) {
this._layers.push(new ColorLayerXML(colorLayer));
}
}
get id(): number {
return this._id;
}
get layers(): Array<ColorLayerXML> {
return this._layers;
}
}
export class ColorLayerXML {
private readonly _id: number;
private readonly _color: string;
constructor(colorLayerXML: any) {
const attributes = colorLayerXML.$;
this._id = attributes.id;
this._color = attributes.color;
}
get id(): number {
return this._id;
}
get color(): string {
return this._color;
}
}
export class AnimationXML {
private readonly _id: number;
private readonly _transitionTo: number;
private readonly _transitionFrom: number;
private readonly _immediateChangeFrom: string;
private readonly _layers: Array<AnimationLayerXML>;
constructor(animationXML: any) {
const attributes = animationXML.$;
this._id = attributes.id;
this._transitionTo = attributes.transitionTo;
this._transitionFrom = attributes.transitionFrom;
this._immediateChangeFrom = attributes.immediateChangeFrom;
this._layers = new Array<AnimationLayerXML>();
if (animationXML.animationLayer !== undefined) {
for (const animationLayer of animationXML.animationLayer) {
this._layers.push(new AnimationLayerXML(animationLayer))
}
}
}
get id(): number {
return this._id;
}
get transitionTo(): number {
return this._transitionTo;
}
get transitionFrom(): number {
return this._transitionFrom;
}
get immediateChangeFrom(): string {
return this._immediateChangeFrom;
}
get layers(): Array<AnimationLayerXML> {
return this._layers;
}
}
export class AnimationLayerXML {
private readonly _id: number;
private readonly _loopCount: number;
private readonly _frameRepeat: number;
private readonly _random: number;
private readonly _randomStart: number;
private readonly _frameSequences: Array<FrameSequenceXML>;
constructor(animationLayerXML: any) {
const attributes = animationLayerXML.$;
this._id = attributes.id;
this._loopCount = attributes.loopCount;
this._frameRepeat = attributes.frameRepeat;
this._random = attributes.random;
this._randomStart = attributes.randomStart;
this._frameSequences = new Array<FrameSequenceXML>();
if (animationLayerXML.frameSequence !== undefined) {
for (const frameSequence of animationLayerXML.frameSequence) {
this._frameSequences.push(new FrameSequenceXML(frameSequence));
}
}
}
get id(): number {
return this._id;
}
get loopCount(): number {
return this._loopCount;
}
get frameRepeat(): number {
return this._frameRepeat;
}
get random(): number {
return this._random;
}
get randomStart(): number {
return this._randomStart;
}
get frameSequences(): Array<FrameSequenceXML> {
return this._frameSequences;
}
}
export class FrameSequenceXML {
private readonly _loopCount: number;
private readonly _random: number;
private readonly _frames: Array<FrameXML>;
constructor(frameSequenceXML: any) {
let attributes = frameSequenceXML.$;
if (attributes === undefined) attributes = {};
this._loopCount = attributes.loopCount;
this._random = attributes.random;
this._frames = new Array<FrameXML>();
if (frameSequenceXML.frame !== undefined) {
for (const frame of frameSequenceXML.frame) {
this._frames.push(new FrameXML(frame));
}
}
}
get loopCount(): number {
return this._loopCount;
}
get random(): number {
return this._random;
}
get frames(): Array<FrameXML> {
return this._frames;
}
}
export class FrameXML {
private readonly _id: string;
private readonly _x: number;
private readonly _y: number;
private readonly _randomX: number;
private readonly _randomY: number;
private readonly _offsets: Array<OffsetXML>;
constructor(frameXML: any) {
const attributes = frameXML.$;
this._id = attributes.id;
this._x = attributes.x;
this._y = attributes.y;
this._randomX = attributes.randomX;
this._randomY = attributes.randomY;
this._offsets = new Array<OffsetXML>();
if (frameXML.offsets !== undefined) {
for (const offsetParent of frameXML.offsets) {
for (const offset of offsetParent.offset) {
this._offsets.push(new OffsetXML(offset));
}
}
}
}
get id(): string {
return this._id;
}
get x(): number {
return this._x;
}
get y(): number {
return this._y;
}
get randomX(): number {
return this._randomX;
}
get randomY(): number {
return this._randomY;
}
get offsets(): Array<OffsetXML> {
return this._offsets;
}
}
export class OffsetXML {
private readonly _direction: number;
private readonly _x: number;
private readonly _y: number;
constructor(offsetXML: any) {
const attributes = offsetXML.$;
this._direction = attributes.direction;
this._x = attributes.x;
this._y = attributes.y;
}
get direction(): number {
return this._direction;
}
get x(): number {
return this._x;
}
get y(): number {
return this._y;
}
}
export class PostureXML {
private readonly _id: string;
private readonly _animationId: number;
constructor(postureXML: any) {
const attributes = postureXML.$;
this._id = attributes.id;
this._animationId = attributes.animationId;
}
get id(): string {
return this._id;
}
get animationId(): number {
return this._animationId;
}
}
export class GestureXML {
private readonly _id: string;
private readonly _animationId: number;
constructor(gestureXML: any) {
const attributes = gestureXML.$;
this._id = attributes.id;
this._animationId = attributes.animationId;
}
get id(): string {
return this._id;
}
get animationId(): number {
return this._animationId;
}
}

View File

@ -0,0 +1,9 @@
export interface IAsset
{
source?: string;
x?: number;
y?: number;
flipH?: boolean;
flipV?: boolean;
usesPalette?: boolean;
}

View File

@ -0,0 +1,6 @@
export interface IAssetAlias
{
link: string;
fliph: number;
flipv: number;
}

View File

@ -0,0 +1,23 @@
import { IAsset } from './IAsset';
import { IAssetAlias } from './IAssetAlias';
import { IAssetDimension } from './IAssetDimension';
import { IAssetPalette } from './IAssetPalette';
import { ISpritesheetData } from './spritesheet';
import { IAssetVisualizationData } from './visualization';
export interface IAssetData {
type?: string;
name?: string;
visualizationType?: string;
logicType?: string;
maskType?: string;
credits?: string;
action?: { link?: string, startState?: number };
spritesheet?: ISpritesheetData;
dimensions?: IAssetDimension;
directions?: number[];
assets?: { [index: string]: IAsset };
aliases?: { [index: string]: IAssetAlias };
palettes?: { [index: string]: IAssetPalette };
visualizations?: IAssetVisualizationData[];
}

View File

@ -0,0 +1,6 @@
export interface IAssetDimension
{
x: number;
y: number;
z?: number;
}

View File

@ -0,0 +1,8 @@
export interface IAssetPalette
{
id?: number;
source?: string;
color1?: string;
color2?: string;
rgb?: [ number, number, number ][];
}

View File

@ -0,0 +1,7 @@
export * from './IAsset';
export * from './IAssetAlias';
export * from './IAssetData';
export * from './IAssetDimension';
export * from './IAssetPalette';
export * from './spritesheet';
export * from './visualization';

View File

@ -0,0 +1,8 @@
import { ISpritesheetFrame } from './ISpritesheetFrame';
import { ISpritesheetMeta } from './ISpritesheetMeta';
export interface ISpritesheetData
{
meta?: ISpritesheetMeta;
frames?: { [index: string]: ISpritesheetFrame };
}

View File

@ -0,0 +1,25 @@
export interface ISpritesheetFrame
{
frame: {
x: number;
y: number;
w: number;
h: number;
};
rotated: boolean;
trimmed: boolean;
spriteSourceSize: {
x: number;
y: number;
w: number;
h: number;
};
sourceSize: {
w: number;
h: number;
};
pivot: {
x: number;
y: number;
};
}

View File

@ -0,0 +1,12 @@
export interface ISpritesheetMeta
{
app: string;
version: string;
image: string;
format: string;
size: {
w: number;
h: number;
};
scale: string;
}

View File

@ -0,0 +1,3 @@
export * from './ISpritesheetData';
export * from './ISpritesheetFrame';
export * from './ISpritesheetMeta';

View File

@ -0,0 +1,19 @@
import { IAssetAnimation } from './animation/IAssetAnimation';
import { IAssetColor } from './color/IAssetColor';
import { IAssetGesture } from './gestures/IAssetGesture';
import { IAssetVisualizationDirection } from './IAssetVisualizationDirection';
import { IAssetVisualizationLayer } from './IAssetVisualizationLayer';
import { IAssetPosture } from './postures/IAssetPosture';
export interface IAssetVisualizationData
{
size?: number;
layerCount?: number;
angle?: number;
layers?: { [index: string]: IAssetVisualizationLayer };
colors?: { [index: string]: IAssetColor };
directions?: { [index: string]: IAssetVisualizationDirection };
animations?: { [index: string]: IAssetAnimation };
postures?: { [index: string]: IAssetPosture };
gestures?: { [index: string]: IAssetGesture };
}

View File

@ -0,0 +1,6 @@
import { IAssetVisualizationLayer } from './IAssetVisualizationLayer';
export interface IAssetVisualizationDirection
{
layers?: { [index: string]: IAssetVisualizationLayer };
}

View File

@ -0,0 +1,10 @@
export interface IAssetVisualizationLayer
{
x?: number;
y?: number;
z?: number;
alpha?: number;
ink?: string;
tag?: string;
ignoreMouse?: boolean;
}

View File

@ -0,0 +1,9 @@
import { IAssetAnimationLayer } from './IAssetAnimationLayer';
export interface IAssetAnimation
{
transitionTo?: number;
transitionFrom?: number;
immediateChangeFrom?: string;
layers?: { [index: string]: IAssetAnimationLayer };
}

View File

@ -0,0 +1,9 @@
import { IAssetAnimationSequence } from './IAssetAnimationSequence';
export interface IAssetAnimationLayer
{
loopCount?: number;
frameRepeat?: number;
random?: number;
frameSequences?: { [index: string]: IAssetAnimationSequence };
}

View File

@ -0,0 +1,8 @@
import { IAssetAnimationSequenceFrame } from './IAssetAnimationSequenceFrame';
export interface IAssetAnimationSequence
{
loopCount?: number;
random?: number;
frames?: { [index: string]: IAssetAnimationSequenceFrame };
}

View File

@ -0,0 +1,11 @@
import { IAssetAnimationSequenceFrameOffset } from './IAssetAnimationSequenceFrameOffset';
export interface IAssetAnimationSequenceFrame
{
id?: number;
x?: number;
y?: number;
randomX?: number;
randomY?: number;
offsets?: { [index: string]: IAssetAnimationSequenceFrameOffset };
}

View File

@ -0,0 +1,6 @@
export interface IAssetAnimationSequenceFrameOffset
{
direction?: number;
x?: number;
y?: number;
}

View File

@ -0,0 +1,5 @@
export * from './IAssetAnimation';
export * from './IAssetAnimationLayer';
export * from './IAssetAnimationSequence';
export * from './IAssetAnimationSequenceFrame';
export * from './IAssetAnimationSequenceFrameOffset';

View File

@ -0,0 +1,6 @@
import { IAssetColorLayer } from './IAssetColorLayer';
export interface IAssetColor
{
layers?: { [index: string]: IAssetColorLayer };
}

View File

@ -0,0 +1,4 @@
export interface IAssetColorLayer
{
color?: number;
}

View File

@ -0,0 +1,2 @@
export * from './IAssetColor';
export * from './IAssetColorLayer';

View File

@ -0,0 +1,5 @@
export interface IAssetGesture
{
id?: string;
animationId?: number;
}

View File

@ -0,0 +1 @@
export * from './IAssetGesture';

View File

@ -0,0 +1,7 @@
export * from './animation';
export * from './color';
export * from './gestures';
export * from './IAssetVisualizationData';
export * from './IAssetVisualizationDirection';
export * from './IAssetVisualizationLayer';
export * from './postures';

View File

@ -0,0 +1,5 @@
export interface IAssetPosture
{
id?: string;
animationId?: number;
}

View File

@ -0,0 +1 @@
export * from './IAssetPosture';

View File

@ -0,0 +1,6 @@
import { IFigureMapLibrary } from './IFigureMapLibrary';
export interface IFigureMap
{
libraries: IFigureMapLibrary[];
}

View File

@ -0,0 +1,8 @@
import { IFigureMapLibraryPart } from './IFigureMapLibraryPart';
export interface IFigureMapLibrary
{
id: string;
revision: number;
parts: IFigureMapLibraryPart[];
}

View File

@ -0,0 +1,5 @@
export interface IFigureMapLibraryPart
{
id: number;
type: string;
}

View File

@ -0,0 +1,3 @@
export * from './IFigureMap';
export * from './IFigureMapLibrary';
export * from './IFigureMapLibraryPart';

View File

@ -0,0 +1,11 @@
import { IFurnitureType } from './IFurnitureType';
export class IFurnitureData
{
roomitemtypes: {
furnitype: IFurnitureType[]
};
wallitemtypes: {
furnitype: IFurnitureType[]
};
}

View File

@ -0,0 +1,28 @@
export interface IFurnitureType
{
id: number;
classname: string;
revision: number;
category: string;
defaultdir: number;
xdim: number;
ydim: number;
partcolors: { color: string[] };
name: string;
description: string;
adurl: string;
offerid: number;
buyout: boolean;
rentofferid: number;
rentbuyout: boolean;
bc: boolean;
excludeddynamic: boolean;
customparams: string;
specialtype: number;
canstandon: boolean;
cansiton: boolean;
canlayon: boolean;
furniline: string;
environment: string;
rare: boolean;
}

View File

@ -0,0 +1,2 @@
export * from './IFurnitureData';
export * from './IFurnitureType';

View File

@ -0,0 +1,3 @@
export * from './asset';
export * from './figuremap';
export * from './furnidata';

View File

@ -0,0 +1,102 @@
import { BundleProvider } from '../../../common/bundle/BundleProvider';
import { IAsset, IAssetData, IAssetPalette } from '../../json';
import { AssetsXML, AssetXML, PaletteXML } from '../../xml';
import { Mapper } from './Mapper';
export class AssetMapper extends Mapper
{
public static mapXML(assets: any, output: IAssetData): void
{
if(!assets || !output) return;
AssetMapper.mapAssetsXML(new AssetsXML(assets), output);
}
private static mapAssetsXML(xml: AssetsXML, output: IAssetData): void
{
if(!xml) return;
if(xml.assets !== undefined)
{
output.assets = {};
AssetMapper.mapAssetsAssetXML(xml.assets, output.assets);
}
if(xml.palettes !== undefined)
{
output.palettes = {};
AssetMapper.mapAssetsPaletteXML(xml.palettes, output.palettes);
}
}
private static mapAssetsAssetXML(xml: AssetXML[], output: { [index: string]: IAsset }): void
{
if(!xml || !xml.length) return;
for(const assetXML of xml)
{
const asset: IAsset = {};
if(assetXML.name !== undefined)
{
let isProhibited = false;
for(const size of AssetMapper.PROHIBITED_SIZES)
{
if(assetXML.name.indexOf(('_' + size + '_')) >= 0)
{
isProhibited = true;
break;
}
}
if(isProhibited) continue;
}
if(assetXML.source !== undefined)
{
asset.source = assetXML.source;
if(BundleProvider.imageSource.has(assetXML.source))
{
asset.source = BundleProvider.imageSource.get(assetXML.source) as string;
}
}
if(assetXML.name !== undefined)
{
if(BundleProvider.imageSource.has(assetXML.name))
{
asset.source = BundleProvider.imageSource.get(assetXML.name) as string;
}
}
if(assetXML.x !== undefined) asset.x = assetXML.x;
if(assetXML.y !== undefined) asset.y = assetXML.y;
if(assetXML.flipH !== undefined) asset.flipH = assetXML.flipH;
if(assetXML.flipV !== undefined) asset.flipV = assetXML.flipV;
output[assetXML.name] = asset;
}
}
private static mapAssetsPaletteXML(xml: PaletteXML[], output: { [index: string]: IAssetPalette }): void
{
if(!xml || !xml.length) return;
for(const paletteXML of xml)
{
const palette: IAssetPalette = {};
if(paletteXML.id !== undefined) palette.id = paletteXML.id;
if(paletteXML.source !== undefined) palette.source = paletteXML.source;
if(paletteXML.color1 !== undefined) palette.color1 = paletteXML.color1;
if(paletteXML.color2 !== undefined) palette.color2 = paletteXML.color2;
output[paletteXML.id.toString()] = palette;
}
}
}

View File

@ -0,0 +1,22 @@
import { IAssetData } from '../../json';
import { IndexXML } from '../../xml';
import { Mapper } from './Mapper';
export class IndexMapper extends Mapper
{
public static mapXML(index: any, output: IAssetData): void
{
if(!index || !output) return;
IndexMapper.mapIndexXML(new IndexXML(index.object), output);
}
private static mapIndexXML(indexXML: IndexXML, output: IAssetData): void
{
if(!indexXML) return;
if(indexXML.type !== undefined) output.name = indexXML.type;
if(indexXML.logic !== undefined) output.logicType = indexXML.logic;
if(indexXML.visualization !== undefined) output.visualizationType = indexXML.visualization;
}
}

View File

@ -0,0 +1,67 @@
import { IAssetData } from '../../json';
import { LogicXML } from '../../xml';
import { Mapper } from './Mapper';
export class LogicMapper extends Mapper
{
public static mapXML(logic: any, output: IAssetData): void
{
if(!logic || !output) return;
LogicMapper.mapLogicXML(new LogicXML(logic.objectData), output);
}
private static mapLogicXML(xml: LogicXML, output: IAssetData): void
{
if(!xml) return;
if(xml.model !== undefined)
{
if(xml.model.dimensions !== undefined)
{
output.dimensions = {
x: xml.model.dimensions.x,
y: xml.model.dimensions.y,
z: xml.model.dimensions.z
};
}
if(xml.model.directions !== undefined)
{
const directions: number[] = [];
if(!xml.model.directions.length)
{
directions.push(0);
}
else
{
for(const direction of xml.model.directions) directions.push(parseInt(direction.id.toString()));
}
output.directions = directions;
}
}
if(xml.action !== undefined)
{
if(xml.action.link !== undefined)
{
if(!output.action) output.action = {};
output.action.link = xml.action.link;
}
if(xml.action.startState !== undefined)
{
if(!output.action) output.action = {};
output.action.startState = xml.action.startState;
}
}
if(xml.mask !== undefined) output.maskType = xml.mask.type;
if(xml.credits !== undefined) output.credits = xml.credits.value;
}
}

View File

@ -0,0 +1,4 @@
export class Mapper
{
public static PROHIBITED_SIZES: string[] = [];
}

View File

@ -0,0 +1,359 @@
import { IAssetAnimation, IAssetAnimationLayer, IAssetAnimationSequence, IAssetAnimationSequenceFrame, IAssetAnimationSequenceFrameOffset, IAssetColor, IAssetColorLayer, IAssetData, IAssetGesture, IAssetPosture, IAssetVisualizationData, IAssetVisualizationDirection, IAssetVisualizationLayer } from '../../json';
import { AnimationLayerXML, AnimationXML, ColorLayerXML, ColorXML, FrameOffsetXML, FrameSequenceXML, FrameXML, GestureXML, LayerXML, PostureXML, VisualDirectionXML, VisualizationDataXML, VisualizationXML } from '../../xml';
import { Mapper } from './Mapper';
export class VisualizationMapper extends Mapper
{
public static mapXML(visualization: any, output: IAssetData): void
{
if(!visualization || !output) return;
VisualizationMapper.mapVisualizationXML(new VisualizationXML(visualization.visualizationData), output);
}
private static mapVisualizationXML(xml: VisualizationXML, output: IAssetData): void
{
if(!xml) return;
if(xml.visualizations !== undefined)
{
output.visualizations = [];
VisualizationMapper.mapVisualizationDataXML(xml.visualizations, output.visualizations);
}
}
private static mapVisualizationDataXML(xml: VisualizationDataXML[], output: IAssetVisualizationData[]): void
{
if(!xml || !xml.length) return;
for(const visualizationDataXML of xml)
{
if(visualizationDataXML.size !== undefined)
{
let isProhibited = false;
for(const size of VisualizationMapper.PROHIBITED_SIZES)
{
if(visualizationDataXML.size === parseInt(size))
{
isProhibited = true;
break;
}
}
if(isProhibited) continue;
}
const visualizationData: IAssetVisualizationData = {};
if(visualizationDataXML.angle !== undefined) visualizationData.angle = visualizationDataXML.angle;
if(visualizationDataXML.layerCount !== undefined) visualizationData.layerCount = visualizationDataXML.layerCount;
if(visualizationDataXML.size !== undefined) visualizationData.size = visualizationDataXML.size;
if(visualizationDataXML.layers !== undefined)
{
if(visualizationDataXML.layers.length)
{
visualizationData.layers = {};
VisualizationMapper.mapVisualizationLayerXML(visualizationDataXML.layers, visualizationData.layers);
}
}
if(visualizationDataXML.directions !== undefined)
{
if(visualizationDataXML.directions.length)
{
visualizationData.directions = {};
VisualizationMapper.mapVisualizationDirectionXML(visualizationDataXML.directions, visualizationData.directions);
}
}
if(visualizationDataXML.colors !== undefined)
{
if(visualizationDataXML.colors.length)
{
visualizationData.colors = {};
VisualizationMapper.mapVisualizationColorXML(visualizationDataXML.colors, visualizationData.colors);
}
}
if(visualizationDataXML.animations !== undefined)
{
if(visualizationDataXML.animations.length)
{
visualizationData.animations = {};
VisualizationMapper.mapVisualizationAnimationXML(visualizationDataXML.animations, visualizationData.animations);
}
}
if(visualizationDataXML.postures !== undefined)
{
if(visualizationDataXML.postures.length)
{
visualizationData.postures = {};
VisualizationMapper.mapVisualizationPostureXML(visualizationDataXML.postures, visualizationData.postures);
}
}
if(visualizationDataXML.gestures !== undefined)
{
if(visualizationDataXML.gestures.length)
{
visualizationData.gestures = {};
VisualizationMapper.mapVisualizationGestureXML(visualizationDataXML.gestures, visualizationData.gestures);
}
}
output.push(visualizationData);
}
}
private static mapVisualizationLayerXML(xml: LayerXML[], output: { [index: string]: IAssetVisualizationLayer }): void
{
if(!xml || !xml.length) return;
for(const layerXML of xml)
{
const layer: IAssetVisualizationLayer = {};
if(layerXML.x !== undefined) layer.x = layerXML.x;
if(layerXML.y !== undefined) layer.y = layerXML.y;
if(layerXML.z !== undefined) layer.z = layerXML.z;
if(layerXML.alpha !== undefined) layer.alpha = layerXML.alpha;
if(layerXML.ink !== undefined) layer.ink = layerXML.ink;
if(layerXML.tag !== undefined) layer.tag = layerXML.tag;
if(layerXML.ignoreMouse !== undefined) layer.ignoreMouse = layerXML.ignoreMouse;
output[layerXML.id.toString()] = layer;
}
}
private static mapVisualizationDirectionXML(xml: VisualDirectionXML[], output: { [index: string]: IAssetVisualizationDirection }): void
{
if(!xml || !xml.length) return;
for(const directionXML of xml)
{
const direction: IAssetVisualizationDirection = {};
if(directionXML.layers !== undefined)
{
if(directionXML.layers.length)
{
direction.layers = {};
VisualizationMapper.mapVisualizationLayerXML(directionXML.layers, direction.layers);
}
}
output[directionXML.id.toString()] = direction;
}
}
private static mapVisualizationColorXML(xml: ColorXML[], output: { [index: string]: IAssetColor }): void
{
if(!xml || !xml.length) return;
for(const colorXML of xml)
{
const color: IAssetColor = {};
if(colorXML.layers !== undefined)
{
if(colorXML.layers.length)
{
color.layers = {};
VisualizationMapper.mapVisualizationColorLayerXML(colorXML.layers, color.layers);
}
}
output[colorXML.id.toString()] = color;
}
}
private static mapVisualizationColorLayerXML(xml: ColorLayerXML[], output: { [index: string]: IAssetColorLayer }): void
{
if(!xml || !xml.length) return;
for(const colorLayerXML of xml)
{
const colorLayer: IAssetColorLayer = {};
if(colorLayerXML.color !== undefined) colorLayer.color = parseInt(colorLayerXML.color, 16);
output[colorLayerXML.id.toString()] = colorLayer;
}
}
private static mapVisualizationAnimationXML(xml: AnimationXML[], output: { [index: string]: IAssetAnimation }): void
{
if(!xml || !xml.length) return;
for(const animationXML of xml)
{
const animation: IAssetAnimation = {};
if(animationXML.transitionTo !== undefined) animation.transitionTo = animationXML.transitionTo;
if(animationXML.transitionFrom !== undefined) animation.transitionFrom = animationXML.transitionFrom;
if(animationXML.immediateChangeFrom !== undefined) animation.immediateChangeFrom = animationXML.immediateChangeFrom;
if(animationXML.layers !== undefined)
{
if(animationXML.layers.length)
{
animation.layers = {};
VisualizationMapper.mapVisualizationAnimationLayerXML(animationXML.layers, animation.layers);
}
}
output[animationXML.id.toString()] = animation;
}
}
private static mapVisualizationAnimationLayerXML(xml: AnimationLayerXML[], output: { [index: string]: IAssetAnimationLayer }): void
{
if(!xml || !xml.length) return;
for(const animationLayerXML of xml)
{
const animationLayer: IAssetAnimationLayer = {};
if(animationLayerXML.frameRepeat !== undefined) animationLayer.frameRepeat = animationLayerXML.frameRepeat;
if(animationLayerXML.loopCount !== undefined) animationLayer.loopCount = animationLayerXML.loopCount;
if(animationLayerXML.random !== undefined) animationLayer.random = animationLayerXML.random;
if(animationLayerXML.frameSequences !== undefined)
{
if(animationLayerXML.frameSequences.length)
{
animationLayer.frameSequences = {};
VisualizationMapper.mapVisualizationFrameSequenceXML(animationLayerXML.frameSequences, animationLayer.frameSequences);
}
}
output[animationLayerXML.id.toString()] = animationLayer;
}
}
private static mapVisualizationFrameSequenceXML(xml: FrameSequenceXML[], output: { [index: string]: IAssetAnimationSequence }): void
{
if(!xml || !xml.length) return;
let i = 0;
for(const frameSequenceXML of xml)
{
const frameSequence: IAssetAnimationSequence = {};
if(frameSequenceXML.loopCount !== undefined) frameSequence.loopCount = frameSequenceXML.loopCount;
if(frameSequenceXML.random !== undefined) frameSequence.random = frameSequenceXML.random;
if(frameSequenceXML.frames !== undefined)
{
if(frameSequenceXML.frames.length)
{
frameSequence.frames = {};
VisualizationMapper.mapVisualizationFrameSequenceFrameXML(frameSequenceXML.frames, frameSequence.frames);
}
}
output[i.toString()] = frameSequence;
i++;
}
}
private static mapVisualizationFrameSequenceFrameXML(xml: FrameXML[], output: { [index: string]: IAssetAnimationSequenceFrame }): void
{
if(!xml || !xml.length) return;
let i = 0;
for(const frameXML of xml)
{
const frame: IAssetAnimationSequenceFrame = {};
if((frameXML.id === undefined) || (frameXML.id === 'NaN')) frame.id = 0;
else frame.id = parseInt(frameXML.id);
if(frameXML.x !== undefined) frame.x = frameXML.x;
if(frameXML.y !== undefined) frame.y = frameXML.y;
if(frameXML.randomX !== undefined) frame.randomX = frameXML.randomX;
if(frameXML.randomY !== undefined) frame.randomY = frameXML.randomY;
if(frameXML.offsets !== undefined)
{
if(frameXML.offsets.length)
{
frame.offsets = {};
VisualizationMapper.mapVisualizationFrameSequenceFrameOffsetXML(frameXML.offsets, frame.offsets);
}
}
output[i.toString()] = frame;
i++;
}
}
private static mapVisualizationFrameSequenceFrameOffsetXML(xml: FrameOffsetXML[], output: { [index: string]: IAssetAnimationSequenceFrameOffset }): void
{
if(!xml || !xml.length) return;
let i = 0;
for(const offsetXML of xml)
{
const offset: IAssetAnimationSequenceFrameOffset = {};
if(offsetXML.direction !== undefined) offset.direction = offsetXML.direction;
if(offsetXML.x !== undefined) offset.x = offsetXML.x;
if(offsetXML.y !== undefined) offset.y = offsetXML.y;
output[i.toString()] = offset;
}
}
private static mapVisualizationPostureXML(xml: PostureXML[], output: { [index: string]: IAssetPosture }): void
{
if(!xml || !xml.length) return;
for(const postureXML of xml)
{
const posture: IAssetPosture = {};
if(postureXML.id !== undefined) posture.id = postureXML.id;
if(postureXML.animationId !== undefined) posture.animationId = postureXML.animationId;
output[postureXML.id] = posture;
}
}
private static mapVisualizationGestureXML(xml: GestureXML[], output: { [index: string]: IAssetGesture }): void
{
if(!xml || !xml.length) return;
for(const gestureXML of xml)
{
const gesture: IAssetGesture = {};
if(gestureXML.id !== undefined) gesture.id = gestureXML.id;
if(gestureXML.animationId !== undefined) gesture.animationId = gestureXML.animationId;
output[gestureXML.id] = gesture;
}
}
}

View File

@ -0,0 +1,4 @@
export * from './AssetMapper';
export * from './IndexMapper';
export * from './LogicMapper';
export * from './VisualizationMapper';

View File

@ -0,0 +1 @@
export * from './asset';

View File

@ -0,0 +1,33 @@
export class IndexXML
{
private readonly _type: string;
private readonly _visualization: string;
private readonly _logic: string;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.type !== undefined) this._type = attributes.type;
if(attributes.visualization !== undefined) this._visualization = attributes.visualization;
if(attributes.logic !== undefined) this._logic = attributes.logic;
}
}
public get type(): string
{
return this._type;
}
public get visualization(): string
{
return this._visualization;
}
public get logic(): string
{
return this._logic;
}
}

View File

@ -0,0 +1,61 @@
export class AssetXML
{
private readonly _name: string;
private readonly _source: string;
private readonly _x: number;
private readonly _y: number;
private readonly _flipH: boolean;
private readonly _flipV: boolean;
private readonly _usesPalette: number;
constructor(asset: any)
{
const attributes = asset.$;
if(attributes !== undefined)
{
if(attributes.name !== undefined) this._name = attributes.name;
if(attributes.source !== undefined) this._source = attributes.source;
if(attributes.x !== undefined) this._x = parseInt(attributes.x);
if(attributes.x !== undefined) this._y = parseInt(attributes.y);
if(attributes.flipH !== undefined) this._flipH = (attributes.flipH === '1');
if(attributes.flipV !== undefined) this._flipV = (attributes.flipV === '1');
if(attributes.usesPalette !== undefined) this._usesPalette = parseInt(attributes.usesPalette);
}
}
public get name(): string
{
return this._name;
}
public get source(): string
{
return this._source;
}
public get x(): number
{
return this._x;
}
public get y(): number
{
return this._y;
}
public get flipH(): boolean
{
return this._flipH;
}
public get flipV(): boolean
{
return this._flipV;
}
public get usesPalette(): number
{
return this._usesPalette;
}
}

View File

@ -0,0 +1,35 @@
import { AssetXML } from './AssetXML';
import { PaletteXML } from './PaletteXML';
export class AssetsXML
{
private readonly _assets: AssetXML[];
private readonly _palettes: PaletteXML[];
constructor(xml: any)
{
if(xml.assets !== undefined)
{
this._assets = [];
if(xml.assets.asset !== undefined) for(const asset of xml.assets.asset) this._assets.push(new AssetXML(asset));
if(xml.assets.palette !== undefined)
{
this._palettes = [];
for(const palette of xml.assets.palette) this._palettes.push(new PaletteXML(palette));
}
}
}
public get assets(): AssetXML[]
{
return this._assets;
}
public get palettes(): PaletteXML[]
{
return this._palettes;
}
}

View File

@ -0,0 +1,40 @@
export class PaletteXML
{
private readonly _id: number;
private readonly _source: string;
private readonly _color1: string;
private readonly _color2: string;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes)
{
if(attributes.id !== undefined) this._id = parseInt(attributes.id);
if(attributes.source !== undefined) this._source = attributes.source;
if(attributes.color1 !== undefined) this._color1 = attributes.color1;
if(attributes.color2 !== undefined) this._color2 = attributes.color2;
}
}
public get id(): number
{
return this._id;
}
public get source(): string
{
return this._source;
}
public get color1(): string
{
return this._color1;
}
public get color2(): string
{
return this._color2;
}
}

View File

@ -0,0 +1,3 @@
export * from './AssetsXML';
export * from './AssetXML';
export * from './PaletteXML';

View File

@ -0,0 +1,5 @@
export * from './assets';
export * from './index';
export * from './IndexXML';
export * from './logic';
export * from './visualization';

View File

@ -0,0 +1,26 @@
export class ActionXML
{
private readonly _link: string;
private readonly _startState: number;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.link !== undefined) this._link = attributes.link;
if(attributes.startState !== undefined) this._startState = parseInt(attributes.startState);
}
}
public get link(): string
{
return this._link;
}
public get startState(): number
{
return this._startState;
}
}

View File

@ -0,0 +1,19 @@
export class CreditsXML
{
private readonly _value: string;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.value !== undefined) this._value = attributes.value;
}
}
public get value(): string
{
return this._value;
}
}

View File

@ -0,0 +1,68 @@
import { ActionXML } from './ActionXML';
import { CreditsXML } from './CreditsXML';
import { MaskXML } from './MaskXML';
import { ModelXML } from './model/ModelXML';
export class LogicXML
{
private readonly _type: string;
private readonly _model: ModelXML;
private readonly _action: ActionXML;
private readonly _mask: MaskXML;
private readonly _credits: CreditsXML;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.type !== undefined) this._type = attributes.type;
}
if(xml.model !== undefined)
{
if(xml.model[0] !== undefined) this._model = new ModelXML(xml.model[0]);
}
if(xml.action !== undefined)
{
if(xml.action[0] !== undefined) this._action = new ActionXML(xml.action[0]);
}
if(xml.mask !== undefined)
{
if(xml.mask[0] !== undefined) this._mask = new MaskXML(xml.mask[0]);
}
if(xml.credits !== undefined)
{
if(xml.credits[0] !== undefined) this._credits = new CreditsXML(xml.credits[0]);
}
}
public get type(): string
{
return this._type;
}
public get model(): ModelXML
{
return this._model;
}
public get action(): ActionXML | undefined
{
return this._action;
}
public get mask(): MaskXML | undefined
{
return this._mask;
}
public get credits(): CreditsXML | undefined
{
return this._credits;
}
}

View File

@ -0,0 +1,19 @@
export class MaskXML
{
private readonly _type: string;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.type !== undefined) this._type = attributes.type;
}
}
public get type(): string
{
return this._type;
}
}

View File

@ -0,0 +1,5 @@
export * from './ActionXML';
export * from './CreditsXML';
export * from './LogicXML';
export * from './MaskXML';
export * from './model';

View File

@ -0,0 +1,33 @@
export class DimensionsXML
{
private readonly _x: number;
private readonly _y: number;
private readonly _z: number;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.x !== undefined) this._x = parseInt(attributes.x);
if(attributes.y !== undefined) this._y = parseInt(attributes.y);
if(attributes.z !== undefined) this._z = parseInt(attributes.z);
}
}
public get x(): number
{
return this._x;
}
public get y(): number
{
return this._y;
}
public get z(): number
{
return this._z;
}
}

View File

@ -0,0 +1,14 @@
export class ModelDirectionXML
{
private readonly _id: number;
constructor(xml: any)
{
if(xml.id !== undefined) this._id = parseInt(xml.id);
}
public get id(): number
{
return this._id;
}
}

View File

@ -0,0 +1,39 @@
import { DimensionsXML } from './DimensionsXML';
import { ModelDirectionXML } from './ModelDirectionXML';
export class ModelXML
{
private readonly _dimensions: DimensionsXML;
private readonly _directions: ModelDirectionXML[];
constructor(xml: any)
{
if(xml.dimensions !== undefined)
{
if(xml.dimensions[0] !== undefined) this._dimensions = new DimensionsXML(xml.dimensions[0]);
}
if(xml.directions !== undefined)
{
this._directions = [];
if(Array.isArray(xml.directions))
{
for(const directionParent of xml.directions)
{
if(Array.isArray(directionParent.direction)) for(const direction of directionParent.direction) this._directions.push(new ModelDirectionXML(direction.$));
}
}
}
}
public get dimensions(): DimensionsXML
{
return this._dimensions;
}
public get directions(): ModelDirectionXML[]
{
return this._directions;
}
}

View File

@ -0,0 +1,2 @@
export * from './DimensionsXML';
export * from './ModelDirectionXML';

View File

@ -0,0 +1,26 @@
export class GestureXML
{
private readonly _id: string;
private readonly _animationId: number;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.id !== undefined) this._id = attributes.id;
if(attributes.animationId !== undefined) this._animationId = parseInt(attributes.animationId);
}
}
public get id(): string
{
return this._id;
}
public get animationId(): number
{
return this._animationId;
}
}

View File

@ -0,0 +1,69 @@
export class LayerXML
{
private readonly _id: number;
private readonly _alpha: number;
private readonly _x: number;
private readonly _y: number;
private readonly _z: number;
private readonly _ink: string;
private readonly _tag: string;
private readonly _ignoreMouse: boolean;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.id !== undefined) this._id = parseInt(attributes.id);
if(attributes.alpha !== undefined) this._alpha = parseInt(attributes.alpha);
if(attributes.x !== undefined) this._x = parseInt(attributes.x);
if(attributes.y !== undefined) this._y = parseInt(attributes.y);
if(attributes.z !== undefined) this._z = parseInt(attributes.z);
if(attributes.ink !== undefined) this._ink = attributes.ink;
if(attributes.tag !== undefined) this._tag = attributes.tag;
if(attributes.ignoreMouse !== undefined) this._ignoreMouse = (attributes.ignoreMouse === '1');
}
}
public get id(): number
{
return this._id;
}
public get alpha(): number
{
return this._alpha;
}
public get x(): number
{
return this._x;
}
public get y(): number
{
return this._y;
}
public get z(): number
{
return this._z;
}
public get ink(): string
{
return this._ink;
}
public get tag(): string
{
return this._tag;
}
public get ignoreMouse(): boolean
{
return this._ignoreMouse;
}
}

View File

@ -0,0 +1,26 @@
export class PostureXML
{
private readonly _id: string;
private readonly _animationId: number;
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.id !== undefined) this._id = attributes.id;
if(attributes.animationId !== undefined) this._animationId = parseInt(attributes.animationId);
}
}
public get id(): string
{
return this._id;
}
public get animationId(): number
{
return this._animationId;
}
}

View File

@ -0,0 +1,34 @@
import { LayerXML } from './LayerXML';
export class VisualDirectionXML
{
private readonly _id: number;
private readonly _layers: LayerXML[];
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.id !== undefined) this._id = parseInt(attributes.id);
}
if(xml.layer !== undefined)
{
this._layers = [];
for(const layer of xml.layer) this._layers.push(new LayerXML(layer));
}
}
public get id(): number
{
return this._id;
}
public get layers(): LayerXML[]
{
return this._layers;
}
}

View File

@ -0,0 +1,155 @@
import { AnimationXML } from './animation/AnimationXML';
import { ColorXML } from './color/ColorXML';
import { GestureXML } from './GestureXML';
import { LayerXML } from './LayerXML';
import { PostureXML } from './PostureXML';
import { VisualDirectionXML } from './VisualDirectionXML';
export class VisualizationDataXML
{
private readonly _size: number;
private readonly _layerCount: number;
private readonly _angle: number;
private readonly _layers: LayerXML[]
private readonly _directions: VisualDirectionXML[];
private readonly _colors: ColorXML[];
private readonly _animations: AnimationXML[];
private readonly _postures: PostureXML[];
private readonly _gestures: GestureXML[];
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.size !== undefined) this._size = parseInt(attributes.size);
if(attributes.layerCount !== undefined) this._layerCount = parseInt(attributes.layerCount);
if(attributes.angle !== undefined) this._angle = parseInt(attributes.angle);
}
if(xml.layers !== undefined)
{
this._layers = [];
for(const layerParent of xml.layers)
{
if(Array.isArray(layerParent.layer))
{
for(const layer of layerParent.layer) this._layers.push(new LayerXML(layer));
}
}
}
if(xml.directions !== undefined)
{
this._directions = [];
for(const directionParent of xml.directions)
{
if(Array.isArray(directionParent.direction))
{
for(const direction of directionParent.direction) this._directions.push(new VisualDirectionXML(direction));
}
}
}
if(xml.colors !== undefined)
{
this._colors = [];
for(const colorParent of xml.colors)
{
if(Array.isArray(colorParent.color))
{
for(const color of colorParent.color) this._colors.push(new ColorXML(color));
}
}
}
if(xml.animations !== undefined)
{
this._animations = [];
for(const animationParent of xml.animations)
{
if(Array.isArray(animationParent.animation))
{
for(const animation of animationParent.animation) this._animations.push(new AnimationXML(animation));
}
}
}
if((xml.postures !== undefined) && xml.postures.length)
{
this._postures = [];
for(const postureParent of xml.postures)
{
if(Array.isArray(postureParent.posture))
{
for(const posture of postureParent.posture) this._postures.push(new PostureXML(posture));
}
}
}
if(xml.gestures !== undefined)
{
this._gestures = [];
for(const gestureParent of xml.gestures)
{
if(Array.isArray(gestureParent.gesture))
{
for(const gesture of gestureParent.gesture) this._gestures.push(new GestureXML(gesture));
}
}
}
}
public get size(): number
{
return this._size;
}
public get layerCount(): number
{
return this._layerCount;
}
public get angle(): number
{
return this._angle;
}
public get layers(): LayerXML[]
{
return this._layers;
}
public get directions(): VisualDirectionXML[]
{
return this._directions;
}
public get colors(): ColorXML[]
{
return this._colors;
}
public get animations(): AnimationXML[]
{
return this._animations;
}
public get postures(): PostureXML[]
{
return this._postures;
}
public get gestures(): GestureXML[]
{
return this._gestures;
}
}

View File

@ -0,0 +1,37 @@
import { VisualizationDataXML } from './VisualizationDataXML';
export class VisualizationXML
{
private readonly _type: string;
private readonly _visualizations: VisualizationDataXML[];
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.type !== undefined) this._type = attributes.type;
}
if(xml.graphics !== undefined)
{
this._visualizations = [];
if(Array.isArray(xml.graphics))
{
for(const graphic of xml.graphics) for(const visualization of graphic.visualization) this._visualizations.push(new VisualizationDataXML(visualization));
}
}
}
public get type(): string
{
return this._type;
}
public get visualizations(): VisualizationDataXML[]
{
return this._visualizations;
}
}

View File

@ -0,0 +1,63 @@
import { FrameSequenceXML } from './FrameSequenceXML';
export class AnimationLayerXML
{
private readonly _id: number;
private readonly _loopCount: number;
private readonly _frameRepeat: number;
private readonly _random: number;
private readonly _randomStart: number;
private readonly _frameSequences: FrameSequenceXML[];
constructor(xml: any)
{
const attributes = xml.$;
if(attributes !== undefined)
{
if(attributes.id !== undefined) this._id = parseInt(attributes.id);
if(attributes.loopCount !== undefined) this._loopCount = parseInt(attributes.loopCount);
if(attributes.frameRepeat !== undefined) this._frameRepeat = parseInt(attributes.frameRepeat);
if(attributes.random !== undefined) this._random = parseInt(attributes.random);
if(attributes.randomStart !== undefined) this._randomStart = parseInt(attributes.randomStart);
}
if(xml.frameSequence !== undefined)
{
this._frameSequences = [];
for(const frameSequence of xml.frameSequence) this._frameSequences.push(new FrameSequenceXML(frameSequence));
}
}
public get id(): number
{
return this._id;
}
public get loopCount(): number
{
return this._loopCount;
}
public get frameRepeat(): number
{
return this._frameRepeat;
}
public get random(): number
{
return this._random;
}
public get randomStart(): number
{
return this._randomStart;
}
public get frameSequences(): FrameSequenceXML[]
{
return this._frameSequences;
}
}

Some files were not shown because too many files have changed in this diff Show More