mirror of
https://github.com/billsonnn/nitro-converter.git
synced 2024-11-26 17:30:52 +01:00
Effects are done
This commit is contained in:
parent
bb1381c6db
commit
d7cf4b5849
@ -1,5 +1,5 @@
|
|||||||
output.folder.furniture=/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/furniture/
|
output.folder.furniture=/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/furniture/
|
||||||
output.folder.figure=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/figure-new1/
|
output.folder.figure=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/figure/
|
||||||
output.folder.effect=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/effect/
|
output.folder.effect=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/effect/
|
||||||
output.folder.pet=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/pet/
|
output.folder.pet=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/pet/
|
||||||
furnidata.url=http://assets.nitro.se/game/gamedata/furnidata-entry.xml
|
furnidata.url=http://assets.nitro.se/game/gamedata/furnidata-entry.xml
|
||||||
@ -8,7 +8,7 @@ effectmap.url=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-8373861
|
|||||||
external_vars.url=http://assets.nitro.se/game/gamedata/external_variables.txt
|
external_vars.url=http://assets.nitro.se/game/gamedata/external_variables.txt
|
||||||
dynamic.download.url.furniture=/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/endrit/hof_furni/%className%.swf
|
dynamic.download.url.furniture=/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/endrit/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.figure=/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf
|
||||||
dynamic.download.url.effect=http://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=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf
|
dynamic.download.url.pet=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf
|
||||||
convert.furniture=1
|
convert.furniture=1
|
||||||
convert.figure=0
|
convert.figure=0
|
||||||
|
13
package-lock.json
generated
13
package-lock.json
generated
@ -99,6 +99,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
|
||||||
"integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs="
|
"integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs="
|
||||||
},
|
},
|
||||||
|
"bytebuffer": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz",
|
||||||
|
"integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=",
|
||||||
|
"requires": {
|
||||||
|
"long": "~3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"caseless": {
|
"caseless": {
|
||||||
"version": "0.12.0",
|
"version": "0.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||||
@ -383,6 +391,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
|
||||||
},
|
},
|
||||||
|
"long": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
|
||||||
|
"integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s="
|
||||||
|
},
|
||||||
"lzma-purejs": {
|
"lzma-purejs": {
|
||||||
"version": "0.9.3",
|
"version": "0.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/lzma-purejs/-/lzma-purejs-0.9.3.tgz",
|
"resolved": "https://registry.npmjs.org/lzma-purejs/-/lzma-purejs-0.9.3.tgz",
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^14.14.22",
|
"@types/node": "^14.14.22",
|
||||||
|
"bytebuffer": "^5.0.1",
|
||||||
"free-tex-packer-core": "^0.3.2",
|
"free-tex-packer-core": "^0.3.2",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
|
42
src/Main.ts
42
src/Main.ts
@ -6,6 +6,8 @@ import FigureConverter from "./converters/figure/FigureConverter";
|
|||||||
import File from "./utils/File";
|
import File from "./utils/File";
|
||||||
import FurnitureDownloader from "./downloaders/FurnitureDownloader";
|
import FurnitureDownloader from "./downloaders/FurnitureDownloader";
|
||||||
import FurnitureConverter from "./converters/furniture/FurnitureConverter";
|
import FurnitureConverter from "./converters/furniture/FurnitureConverter";
|
||||||
|
import EffectConverter from "./converters/effect/EffectConverter";
|
||||||
|
import EffectDownloader from "./downloaders/EffectDownloader";
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const config = new Configuration();
|
const config = new Configuration();
|
||||||
@ -21,9 +23,15 @@ import FurnitureConverter from "./converters/furniture/FurnitureConverter";
|
|||||||
outputFolderFurniture.mkdirs();
|
outputFolderFurniture.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const outputFolderEffect = new File(config.getValue("output.folder.effect"));
|
||||||
|
if (!outputFolderEffect.isDirectory()) {
|
||||||
|
outputFolderEffect.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
const spriteSheetConverter = new SpriteSheetConverter();
|
const spriteSheetConverter = new SpriteSheetConverter();
|
||||||
const figureConverter = new FigureConverter(config);
|
const figureConverter = new FigureConverter(config);
|
||||||
const furnitureConverter = new FurnitureConverter(config);
|
const furnitureConverter = new FurnitureConverter(config);
|
||||||
|
const effectConverter = new EffectConverter(config);
|
||||||
|
|
||||||
if (config.getBoolean("convert.figure")) {
|
if (config.getBoolean("convert.figure")) {
|
||||||
const figureDownloader = new FigureDownloader(config);
|
const figureDownloader = new FigureDownloader(config);
|
||||||
@ -38,29 +46,21 @@ import FurnitureConverter from "./converters/furniture/FurnitureConverter";
|
|||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Figure error: " + habboAssetSwf.getDocumentClass());
|
console.log("Figure error: " + habboAssetSwf.getDocumentClass());
|
||||||
|
console.log(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let count = 0;
|
|
||||||
|
|
||||||
if (config.getBoolean("convert.furniture")) {
|
if (config.getBoolean("convert.furniture")) {
|
||||||
|
let count = 0;
|
||||||
const furnitureDownloader = new FurnitureDownloader(config);
|
const furnitureDownloader = new FurnitureDownloader(config);
|
||||||
await furnitureDownloader.download(async function (habboAssetSwf: HabboAssetSWF, className: string) {
|
await furnitureDownloader.download(async function (habboAssetSwf: HabboAssetSWF, className: string) {
|
||||||
console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass());
|
console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const assetOuputFolder = new File(outputFolderFurniture.path + "/" + className);
|
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, outputFolderFurniture.path, "furniture");
|
||||||
if (!assetOuputFolder.isDirectory()) {
|
|
||||||
assetOuputFolder.mkdirs();
|
|
||||||
} else if (assetOuputFolder.list().length > 0) {
|
|
||||||
console.log("Furniture already exists or the directory is not empty!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, assetOuputFolder.path, "furniture");
|
|
||||||
if (spriteSheetType !== null) {
|
if (spriteSheetType !== null) {
|
||||||
await furnitureConverter.fromHabboAsset(habboAssetSwf, assetOuputFolder.path, "furniture", spriteSheetType);
|
await furnitureConverter.fromHabboAsset(habboAssetSwf, outputFolderFurniture.path, "furniture", spriteSheetType);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Furniture error: " + habboAssetSwf.getDocumentClass());
|
console.log("Furniture error: " + habboAssetSwf.getDocumentClass());
|
||||||
@ -71,10 +71,26 @@ import FurnitureConverter from "./converters/furniture/FurnitureConverter";
|
|||||||
console.log(`Parsed ${++count} furnitures`)
|
console.log(`Parsed ${++count} furnitures`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.getBoolean("convert.effect")) {
|
||||||
|
const effectDownloader = new EffectDownloader(config);
|
||||||
|
await effectDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
|
||||||
|
console.log("Attempt parsing figure: " + habboAssetSwf.getDocumentClass());
|
||||||
|
|
||||||
|
try {
|
||||||
|
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, outputFolderFurniture.path, "effect");
|
||||||
|
if (spriteSheetType !== null) {
|
||||||
|
await effectConverter.fromHabboAsset(habboAssetSwf, outputFolderEffect.path, "effect", spriteSheetType);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
console.log("Effect error: "+ habboAssetSwf.getDocumentClass());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
console.log('finished!');
|
console.log('finished!');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
outputFolderFurniture.rmdir({
|
outputFolderFurniture.rmdir({
|
||||||
recursive: true,
|
recursive: true,
|
||||||
force: true
|
force: true
|
||||||
|
9
src/converters/ArchiveType.ts
Normal file
9
src/converters/ArchiveType.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import {SpriteSheetType} from "./util/SpriteSheetTypes";
|
||||||
|
|
||||||
|
export default interface ArchiveType {
|
||||||
|
spriteSheetType: SpriteSheetType,
|
||||||
|
imageData: {
|
||||||
|
name: string,
|
||||||
|
buffer: Buffer
|
||||||
|
}
|
||||||
|
}
|
522
src/converters/effect/EffectAnimationXMLTypes.ts
Normal file
522
src/converters/effect/EffectAnimationXMLTypes.ts
Normal file
@ -0,0 +1,522 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
80
src/converters/effect/EffectConverter.ts
Normal file
80
src/converters/effect/EffectConverter.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
||||||
|
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
|
||||||
|
import ArchiveType from "../ArchiveType";
|
||||||
|
import File from "../../utils/File";
|
||||||
|
import NitroBundle from "../../utils/NitroBundle";
|
||||||
|
import {EffectJson} from "./EffectTypes";
|
||||||
|
import Configuration from "../../config/Configuration";
|
||||||
|
import EffectJsonMapper from "./EffectJsonMapper";
|
||||||
|
|
||||||
|
const xml2js = require('xml2js');
|
||||||
|
const parser = new xml2js.Parser(/* options */);
|
||||||
|
|
||||||
|
const fs = require('fs').promises;
|
||||||
|
|
||||||
|
export default class EffectConverter {
|
||||||
|
private readonly _effectJsonMapper: EffectJsonMapper;
|
||||||
|
|
||||||
|
constructor(config: Configuration) {
|
||||||
|
this._effectJsonMapper = new EffectJsonMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
|
||||||
|
const effectJson = await this.convertXML2JSON(habboAssetSWF);
|
||||||
|
if (effectJson !== null) {
|
||||||
|
effectJson.spritesheet = archiveType.spriteSheetType;
|
||||||
|
effectJson.type = type;
|
||||||
|
|
||||||
|
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
|
||||||
|
const assetOuputFolder = new File(path);
|
||||||
|
if (assetOuputFolder.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
338
src/converters/effect/EffectJsonMapper.ts
Normal file
338
src/converters/effect/EffectJsonMapper.ts
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
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 EffectDownloader from "../../downloaders/EffectDownloader";
|
||||||
|
import {ManifestXML} from "./EffectManifestXMLTypes";
|
||||||
|
import SpriteSheetConverter from "../util/SpriteSheetConverter";
|
||||||
|
import {
|
||||||
|
AnimationXML,
|
||||||
|
BodyPartXML
|
||||||
|
} from "./EffectAnimationXMLTypes";
|
||||||
|
|
||||||
|
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;
|
||||||
|
EffectJsonMapper.mapManifestXML(new ManifestXML(manifest), result);
|
||||||
|
EffectJsonMapper.mapAnimationXML(new AnimationXML(animation), result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static mapManifestXML(manifestXML: ManifestXML, output: EffectJson) {
|
||||||
|
const assets: AssetsJSON = {};
|
||||||
|
|
||||||
|
for (const assetXML of manifestXML.library.assets) {
|
||||||
|
if (assetXML.name.startsWith(this.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 (SpriteSheetConverter.imageSource.has(assetXML.name)) {
|
||||||
|
asset.source = SpriteSheetConverter.imageSource.get(assetXML.name) as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
assets[assetXML.name] = asset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output.assets = assets;
|
||||||
|
|
||||||
|
if (manifestXML.library.aliases.length > 0 || SpriteSheetConverter.imageSource.size > 0) {
|
||||||
|
const aliases: Aliases = {};
|
||||||
|
for (const aliasXML of manifestXML.library.aliases) {
|
||||||
|
if (aliasXML.name.startsWith(this.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;
|
||||||
|
}
|
||||||
|
}
|
142
src/converters/effect/EffectManifestXMLTypes.ts
Normal file
142
src/converters/effect/EffectManifestXMLTypes.ts
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
135
src/converters/effect/EffectTypes.ts
Normal file
135
src/converters/effect/EffectTypes.ts
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import {SpriteSheetType} from "../util/SpriteSheetTypes";
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
@ -1,16 +1,15 @@
|
|||||||
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
||||||
import {SpriteSheetType} from "../util/SpriteSheetTypes";
|
|
||||||
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
|
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
|
||||||
import Configuration from "../../config/Configuration";
|
import Configuration from "../../config/Configuration";
|
||||||
import FigureJsonMapper from "./FigureJsonMapper";
|
import FigureJsonMapper from "./FigureJsonMapper";
|
||||||
import {FigureJson} from "./FigureJsonType";
|
import {FigureJson} from "./FigureJsonType";
|
||||||
import File from "../../utils/File";
|
import File from "../../utils/File";
|
||||||
|
import ArchiveType from "../ArchiveType";
|
||||||
|
import NitroBundle from "../../utils/NitroBundle";
|
||||||
|
|
||||||
const xml2js = require('xml2js');
|
const xml2js = require('xml2js');
|
||||||
const parser = new xml2js.Parser(/* options */);
|
const parser = new xml2js.Parser(/* options */);
|
||||||
|
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const {gzip} = require('node-gzip');
|
|
||||||
|
|
||||||
export default class FigureConverter {
|
export default class FigureConverter {
|
||||||
|
|
||||||
@ -42,10 +41,10 @@ export default class FigureConverter {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, spriteSheetType: SpriteSheetType) {
|
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
|
||||||
const manifestJson = await this.convertXML2JSON(habboAssetSWF);
|
const manifestJson = await this.convertXML2JSON(habboAssetSWF);
|
||||||
if (manifestJson !== null) {
|
if (manifestJson !== null) {
|
||||||
manifestJson.spritesheet = spriteSheetType;
|
manifestJson.spritesheet = archiveType.spriteSheetType;
|
||||||
|
|
||||||
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
|
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
|
||||||
const assetOuputFolder = new File(path);
|
const assetOuputFolder = new File(path);
|
||||||
@ -55,8 +54,12 @@ export default class FigureConverter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const compressed = await gzip(JSON.stringify(manifestJson));
|
const nitroBundle = new NitroBundle();
|
||||||
await fs.writeFile(path, compressed);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,16 +1,16 @@
|
|||||||
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
||||||
import {SpriteSheetType} from "../util/SpriteSheetTypes";
|
|
||||||
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
|
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
|
||||||
import Configuration from "../../config/Configuration";
|
import Configuration from "../../config/Configuration";
|
||||||
import FurniJsonMapper from "./FurniJsonMapper";
|
import FurniJsonMapper from "./FurniJsonMapper";
|
||||||
import {FurniJson} from "./FurniTypes";
|
import {FurniJson} from "./FurniTypes";
|
||||||
import File from "../../utils/File";
|
import File from "../../utils/File";
|
||||||
|
import ArchiveType from "../ArchiveType";
|
||||||
|
import NitroBundle from "../../utils/NitroBundle";
|
||||||
|
|
||||||
const xml2js = require('xml2js');
|
const xml2js = require('xml2js');
|
||||||
const parser = new xml2js.Parser(/* options */);
|
const parser = new xml2js.Parser(/* options */);
|
||||||
|
|
||||||
const fs = require('fs').promises;
|
const fs = require('fs').promises;
|
||||||
const {gzip} = require('node-gzip');
|
|
||||||
|
|
||||||
export default class FurnitureConverter {
|
export default class FurnitureConverter {
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ export default class FurnitureConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static async getIndexXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
|
private static async getIndexXML(habboAssetSWF: HabboAssetSWF): Promise<any> {
|
||||||
const binaryData: DefineBinaryDataTag | null = FurnitureConverter.getBinaryData(habboAssetSWF, "index", true);
|
const binaryData: DefineBinaryDataTag | null = FurnitureConverter.getBinaryData(habboAssetSWF, "index", false);
|
||||||
if (binaryData !== null) {
|
if (binaryData !== null) {
|
||||||
return await parser.parseStringPromise(binaryData.binaryData);
|
return await parser.parseStringPromise(binaryData.binaryData);
|
||||||
}
|
}
|
||||||
@ -76,10 +76,10 @@ export default class FurnitureConverter {
|
|||||||
return this._furniJsonMapper.mapXML(assetXml, indexXml, logicXml, visualizationXml);
|
return this._furniJsonMapper.mapXML(assetXml, indexXml, logicXml, visualizationXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, spriteSheetType: SpriteSheetType) {
|
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
|
||||||
const furnitureJson = await this.convertXML2JSON(habboAssetSWF);
|
const furnitureJson = await this.convertXML2JSON(habboAssetSWF);
|
||||||
if (furnitureJson !== null) {
|
if (furnitureJson !== null) {
|
||||||
furnitureJson.spritesheet = spriteSheetType;
|
furnitureJson.spritesheet = archiveType.spriteSheetType;
|
||||||
furnitureJson.type = type;
|
furnitureJson.type = type;
|
||||||
|
|
||||||
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
|
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
|
||||||
@ -90,8 +90,12 @@ export default class FurnitureConverter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const compressed = await gzip(JSON.stringify(furnitureJson));
|
const nitroBundle = new NitroBundle();
|
||||||
await fs.writeFile(path, compressed);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,16 +1,14 @@
|
|||||||
import {SpriteSheetType} from "./SpriteSheetTypes";
|
|
||||||
|
|
||||||
const fs = require('fs').promises;
|
|
||||||
let {packAsync} = require("free-tex-packer-core");
|
let {packAsync} = require("free-tex-packer-core");
|
||||||
|
|
||||||
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
import HabboAssetSWF from "../../swf/HabboAssetSWF";
|
||||||
import SymbolClassTag from "../../swf/tags/SymbolClassTag";
|
import SymbolClassTag from "../../swf/tags/SymbolClassTag";
|
||||||
import ImageTag from "../../swf/tags/ImageTag";
|
import ImageTag from "../../swf/tags/ImageTag";
|
||||||
|
import ArchiveType from "../ArchiveType";
|
||||||
|
|
||||||
export default class SpriteSheetConverter {
|
export default class SpriteSheetConverter {
|
||||||
public static imageSource: Map<String, String> = new Map<String, String>();
|
public static imageSource: Map<string, string> = new Map<string, string>();
|
||||||
|
|
||||||
public async generateSpriteSheet(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string): Promise<SpriteSheetType | null> {
|
public async generateSpriteSheet(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string): Promise<ArchiveType | null> {
|
||||||
const tagList: Array<SymbolClassTag> = habboAssetSWF.symbolTags();
|
const tagList: Array<SymbolClassTag> = habboAssetSWF.symbolTags();
|
||||||
const names: Array<string> = new Array<string>();
|
const names: Array<string> = new Array<string>();
|
||||||
const tags: Array<number> = new Array<number>();
|
const tags: Array<number> = new Array<number>();
|
||||||
@ -19,7 +17,7 @@ export default class SpriteSheetConverter {
|
|||||||
tags.push(...tag.tags);
|
tags.push(...tag.tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
const images: Array<{ path: String, contents: Buffer }> = new Array<{ path: String, contents: Buffer }>();
|
const images: Array<{ path: string, contents: Buffer }> = new Array<{ path: string, contents: Buffer }>();
|
||||||
|
|
||||||
const imageTags: Array<ImageTag> = habboAssetSWF.imageTags();
|
const imageTags: Array<ImageTag> = habboAssetSWF.imageTags();
|
||||||
for (const imageTag of imageTags) {
|
for (const imageTag of imageTags) {
|
||||||
@ -67,7 +65,7 @@ export default class SpriteSheetConverter {
|
|||||||
return await this.packImages(habboAssetSWF.getDocumentClass(), outputFolder + "/", images);
|
return await this.packImages(habboAssetSWF.getDocumentClass(), outputFolder + "/", images);
|
||||||
}
|
}
|
||||||
|
|
||||||
async packImages(documentClass: string, outputFolder: string, images: Array<{ path: String, contents: Buffer }>): Promise<SpriteSheetType | null> {
|
async packImages(documentClass: string, outputFolder: string, images: Array<{ path: string, contents: Buffer }>): Promise<ArchiveType | null> {
|
||||||
let options = {
|
let options = {
|
||||||
textureName: documentClass,
|
textureName: documentClass,
|
||||||
width: 1024,
|
width: 1024,
|
||||||
@ -79,26 +77,33 @@ export default class SpriteSheetConverter {
|
|||||||
exporter: "Pixi"
|
exporter: "Pixi"
|
||||||
};
|
};
|
||||||
|
|
||||||
let spriteSheetType: SpriteSheetType | null = null;
|
const archiveType: ArchiveType = {} as any;
|
||||||
let base64 = "";
|
const imageData: {
|
||||||
|
name: string,
|
||||||
|
buffer: Buffer
|
||||||
|
} = {} as any;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const files = await packAsync(images, options);
|
const files = await packAsync(images, options);
|
||||||
for (let item of files) {
|
for (let item of files) {
|
||||||
if (item.name.endsWith(".json")) {
|
if (item.name.endsWith(".json")) {
|
||||||
spriteSheetType = JSON.parse(item.buffer.toString('utf8'));
|
archiveType.spriteSheetType = JSON.parse(item.buffer.toString('utf8'));
|
||||||
} else {
|
} else {
|
||||||
base64 = item.buffer.toString("base64");
|
imageData.buffer = item.buffer;
|
||||||
//await fs.writeFile(outputFolder + item.name, item.buffer);
|
imageData.name = item.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spriteSheetType === null) throw new Error("Failed to parse SpriteSheet. " + images[0].path);
|
if (archiveType.spriteSheetType === null) throw new Error("Failed to parse SpriteSheet. " + images[0].path);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Image Packing Error: ");
|
console.log("Image Packing Error: ");
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spriteSheetType !== null) spriteSheetType.meta.image = base64;
|
if (archiveType.spriteSheetType !== null) {
|
||||||
return spriteSheetType;
|
archiveType.spriteSheetType.meta.image = imageData.name;
|
||||||
|
archiveType.imageData = imageData;
|
||||||
|
}
|
||||||
|
return archiveType;
|
||||||
}
|
}
|
||||||
}
|
}
|
68
src/downloaders/EffectDownloader.ts
Normal file
68
src/downloaders/EffectDownloader.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import Configuration from "../config/Configuration";
|
||||||
|
import HabboAssetSWF from "../swf/HabboAssetSWF";
|
||||||
|
import File from "../utils/File";
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
export default class EffectDownloader {
|
||||||
|
private readonly _config: Configuration;
|
||||||
|
|
||||||
|
constructor(config: Configuration) {
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
//if (className !== 'Hoverboard' && className !== 'Staff' && className !== 'ZombieMask' && className !== 'ESredUntouchable') continue;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (!fs.existsSync(url)) {
|
||||||
|
console.log("SWF File does not exist: " + url);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const buffer: Buffer = await readFile(url);
|
||||||
|
const habboAssetSWF = new HabboAssetSWF(buffer);
|
||||||
|
await habboAssetSWF.setupAsync();
|
||||||
|
|
||||||
|
EffectDownloader.types.set(className, info.type);
|
||||||
|
await callback(habboAssetSWF);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(className);
|
||||||
|
console.log(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);
|
||||||
|
}
|
||||||
|
}
|
@ -19,7 +19,7 @@ export default class FigureDownloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static types: Map<String, String> = new Map<String, String>();
|
public static types: Map<string, string> = new Map<string, string>();
|
||||||
|
|
||||||
public async download(callback: (habboAssetSwf: HabboAssetSWF) => Promise<void>) {
|
public async download(callback: (habboAssetSwf: HabboAssetSWF) => Promise<void>) {
|
||||||
const outputFolderFigure = this._config.getValue("output.folder.figure");
|
const outputFolderFigure = this._config.getValue("output.folder.figure");
|
||||||
|
38
src/utils/NitroBundle.ts
Normal file
38
src/utils/NitroBundle.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
const ByteBuffer = require('bytebuffer');
|
||||||
|
const {gzip} = require('node-gzip');
|
||||||
|
|
||||||
|
export default class NitroBundle {
|
||||||
|
private readonly _files: Map<string, Buffer>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this._files = new Map<string, Buffer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
addFile(name: string, data: Buffer) {
|
||||||
|
this._files.set(name, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async toBufferAsync() {
|
||||||
|
const buffer = new ByteBuffer();
|
||||||
|
|
||||||
|
buffer.writeUInt16(this._files.size);
|
||||||
|
|
||||||
|
const iterator = this._files.entries();
|
||||||
|
let result: IteratorResult<[string, Buffer]> = iterator.next();
|
||||||
|
while (!result.done) {
|
||||||
|
const fileName = result.value[0];
|
||||||
|
const file = result.value[1];
|
||||||
|
|
||||||
|
buffer.writeUint16(fileName.length);
|
||||||
|
buffer.writeString(fileName);
|
||||||
|
|
||||||
|
const compressed = await gzip(file);
|
||||||
|
buffer.writeUint32(compressed.length);
|
||||||
|
buffer.append(compressed);
|
||||||
|
|
||||||
|
result = iterator.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.flip().toBuffer();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user