diff --git a/config.ini b/config.ini index c659e84..68569d5 100644 --- a/config.ini +++ b/config.ini @@ -1,7 +1,7 @@ -output.folder.furniture=/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/endrit/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.effect=/home/user/WebstormProjects/sites/assets.nitro.se/game/effect/ -output.folder.pet=/home/user/WebstormProjects/sites/assets.nitro.se/game/pet/ +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/ furnidata.url=http://assets.nitro.se/game/gamedata/furnidata-entry.xml figuremap.url=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/figuremap.xml effectmap.url=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/effectmap.xml @@ -10,10 +10,9 @@ dynamic.download.url.furniture=/home/user/WebstormProjects/sites/assets.nitro.se 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.pet=http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf -convert.furniture=0 -convert.figure=1 +convert.furniture=1 +convert.figure=0 convert.effect=1 convert.pet=1 figure.rotation.enabled=0 -figure.skip.non-existing.asset.images=0 -convert.threads=4 \ No newline at end of file +figure.skip.non-existing.asset.images=0 \ No newline at end of file diff --git a/src/Main.ts b/src/Main.ts index 7db9bfd..675a1b1 100644 --- a/src/Main.ts +++ b/src/Main.ts @@ -47,7 +47,7 @@ import FurnitureConverter from "./converters/furniture/FurnitureConverter"; if (config.getBoolean("convert.furniture")) { const furnitureDownloader = new FurnitureDownloader(config); await furnitureDownloader.download(async function (habboAssetSwf: HabboAssetSWF, className: string) { - //console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass()); + console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass()); try { const assetOuputFolder = new File(outputFolderFurniture.path + "/" + className); @@ -68,8 +68,15 @@ import FurnitureConverter from "./converters/furniture/FurnitureConverter"; } }); - console.log(`Parsed ${count} furnitures`) + console.log(`Parsed ${++count} furnitures`) } console.log('finished!'); + + /* + + outputFolderFurniture.rmdir({ + recursive: true, + force: true + });*/ })() \ No newline at end of file diff --git a/src/converters/figure/FigureConverter.ts b/src/converters/figure/FigureConverter.ts index 53e203e..fa92eab 100644 --- a/src/converters/figure/FigureConverter.ts +++ b/src/converters/figure/FigureConverter.ts @@ -3,7 +3,7 @@ import {SpriteSheetType} from "../util/SpriteSheetTypes"; import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag"; import Configuration from "../../config/Configuration"; import FigureJsonMapper from "./FigureJsonMapper"; -import {FigureJson} from "./FigureType"; +import {FigureJson} from "./FigureJsonType"; import File from "../../utils/File"; const xml2js = require('xml2js'); @@ -50,7 +50,7 @@ export default class FigureConverter { const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro"; const assetOuputFolder = new File(path); if (assetOuputFolder.exists()) { - console.log("Furniture already exists or the directory is not empty!"); + console.log("Figure already exists or the directory is not empty!"); return; } diff --git a/src/converters/figure/FigureJsonMapper.ts b/src/converters/figure/FigureJsonMapper.ts index 94f2caa..386df10 100644 --- a/src/converters/figure/FigureJsonMapper.ts +++ b/src/converters/figure/FigureJsonMapper.ts @@ -1,8 +1,9 @@ import Configuration from "../../config/Configuration"; import HabboAssetSWF from "../../swf/HabboAssetSWF"; -import {FigureAsset, FigureAssets, FigureJson} from "./FigureType"; +import {FigureAsset, FigureAssets, FigureJson} from "./FigureJsonType"; import FigureDownloader from "../../downloaders/FigureDownloader"; import SpriteSheetConverter from "../util/SpriteSheetConverter"; +import {FigureXMLManifest} from "./FigureXMLTypes"; export default class FigureJsonMapper { @@ -29,54 +30,48 @@ export default class FigureJsonMapper { private mapManifestXML(habboAssetSWF: HabboAssetSWF, manifestXML: any): FigureAssets { const assets: any = {}; - const libraries = manifestXML.manifest.library; - for (const library of libraries) { - for (const assetObj of library.assets) { - for (const asset of assetObj.asset) { - const assetInfo = asset['$']; - const name = assetInfo.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 = asset.param[0]['$'].value.split(',')[0]; - figureAsset.y = asset.param[0]['$'].value.split(',')[1]; - - if (SpriteSheetConverter.imageSource.has(name)) { - figureAsset.source = SpriteSheetConverter.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 rotations = new ArrayList(); - rotations.add(rotation); - assetRotations.put(firstName, rotations); - } - } - } - }*/ - } else { - console.log("Image " + name + " did not decompile for some reason"); - } + 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 (SpriteSheetConverter.imageSource.has(name)) { + figureAsset.source = SpriteSheetConverter.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 rotations = new ArrayList(); + rotations.add(rotation); + assetRotations.put(firstName, rotations); + } + } + } + }*/ + } else { + console.log("Image " + name + " did not decompile for some reason"); + } } } diff --git a/src/converters/figure/FigureType.ts b/src/converters/figure/FigureJsonType.ts similarity index 100% rename from src/converters/figure/FigureType.ts rename to src/converters/figure/FigureJsonType.ts diff --git a/src/converters/figure/FigureXMLTypes.ts b/src/converters/figure/FigureXMLTypes.ts new file mode 100644 index 0000000..f79fe79 --- /dev/null +++ b/src/converters/figure/FigureXMLTypes.ts @@ -0,0 +1,59 @@ +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; + } +} \ No newline at end of file diff --git a/src/converters/furniture/FurniJsonMapper.ts b/src/converters/furniture/FurniJsonMapper.ts index ce47b74..5b9096e 100644 --- a/src/converters/furniture/FurniJsonMapper.ts +++ b/src/converters/furniture/FurniJsonMapper.ts @@ -1,186 +1,337 @@ import { Action, + Animation, + AnimationLayer, + AnimationLayers, + Animations, + Color, + ColorLayer, + ColorLayers, + Colors, Direction, Directions, + Frame, + Frames, + FrameSequence, + FrameSequences, FurniAsset, FurniAssets, - FurniJson, + FurniJson, Gesture, Gestures, Layer, + Offset, Posture, Postures, Visualization, VisualizationLayers } from "./FurniTypes"; import SpriteSheetConverter from "../util/SpriteSheetConverter"; +import {AssetsXML, IndexXML, LogicXML} from "./FurniXMLTypes"; +import { + AnimationLayerXML, + AnimationXML, + ColorXML, + LayerXML, + VisualizationDataXML, + VisualizationXML +} from "./VisualizationXMLTypes"; +import {log} from "util"; export default class FurniJsonMapper { private static readonly VISUALIZATION_DEFAULT_SIZE = 64; private static readonly VISUALIZATION_ICON_SIZE = 1; - public mapXML(assetsXML: any, indexXML: any, logicXML: any, visualizationXML: any): FurniJson { + public mapXML(assets: any, indexXML: any, logic: any, visualization: any): FurniJson { const furniJson: FurniJson = {} as any; - furniJson.assets = this.mapAssetsXML(assetsXML) as any; - - this.mapIndexXML(indexXML, furniJson); - this.mapLogicXML(logicXML, furniJson); - this.mapVisualizationXML(visualizationXML, furniJson); - //console.log(furniJson); + FurniJsonMapper.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: any): FurniAssets | null { + private static mapAssetsXML(assetsXML: AssetsXML, output: FurniJson) { const assets: FurniAssets = {} as any; - for (const asset of assetsXML.assets.asset) { - const attributes = asset['$']; - if (!attributes.name.includes("_32_")) { + for (const asset of assetsXML.assets) { + if (!asset.name.includes("_32_")) { const furniAsset: FurniAsset = {} as any; - if (attributes.source !== undefined) { - furniAsset.source = attributes.source; - if (SpriteSheetConverter.imageSource.has(attributes.source)) { - furniAsset.source = SpriteSheetConverter.imageSource.get(attributes.source) as string; + if (asset.source !== undefined) { + furniAsset.source = asset.source; + if (SpriteSheetConverter.imageSource.has(asset.source)) { + furniAsset.source = SpriteSheetConverter.imageSource.get(asset.source) as string; } } - if (SpriteSheetConverter.imageSource.has(attributes.name)) { - furniAsset.source = SpriteSheetConverter.imageSource.get(attributes.name) as string; + if (SpriteSheetConverter.imageSource.has(asset.name)) { + furniAsset.source = SpriteSheetConverter.imageSource.get(asset.name) as string; } - furniAsset.x = attributes.x; - furniAsset.y = attributes.y; - furniAsset.flipH = attributes.flipH === "1"; - assets[attributes.name] = furniAsset; + furniAsset.x = parseFloat(asset.x.toString()); + furniAsset.y = parseFloat(asset.y.toString()); + furniAsset.flipH = asset.flipH as any; + assets[asset.name] = furniAsset; } } - return Object.keys(assets).length > 0 ? assets : null; + + if (Object.keys(assets).length > 0) { + output.assets = assets; + } } - private mapIndexXML(indexXML: any, output: FurniJson) { - const attributes = indexXML.object['$']; - output.name = attributes.type; - output.logicType = attributes.logic; - output.visualizationType = attributes.visualization; + private static mapIndexXML(indexXML: IndexXML, output: FurniJson) { + output.name = indexXML.type; + output.logicType = indexXML.logic; + output.visualizationType = indexXML.visualization; } - private mapLogicXML(logicXML: any, output: FurniJson) { - const objectData = logicXML.objectData; - const attributes = objectData['$']; - - const model = objectData.model[0]; - const dimensions = model.dimensions[0]['$']; + private static mapLogicXML(logicXML: LogicXML, output: FurniJson) { output.dimensions = { - x: parseInt(dimensions.x), - y: parseInt(dimensions.y), - z: parseFloat(dimensions.z) + x: parseFloat(logicXML.model.dimensions.x.toString()), + y: parseFloat(logicXML.model.dimensions.y.toString()), + z: parseFloat(logicXML.model.dimensions.z.toString()) } const directions: Array = []; - if (model.directions === undefined) { + if (logicXML.model.directions.length === 0) { directions.push(0); } else { - for (const directionObj of model.directions) { - const direction = directionObj.direction; - for (const dir of direction) { - const dirAttributes = dir['$']; - directions.push(dirAttributes); - } + for (const direction of logicXML.model.directions) { + directions.push(parseFloat(direction.id.toString())); } } - if (model.action !== undefined) { + 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 mapVisualizationXML(visualizationXML: any, output: FurniJson) { - const visualizationsArray: Visualization[] = []; + private static mapVisualizationXML(visualizationData: VisualizationDataXML, output: FurniJson) { + const visualizationsArray: Array = new Array(); - const visualizationData = visualizationXML.visualizationData; - const attributes = visualizationData['$']; + 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 = parseFloat(visualization.angle.toString()); + visualizationJson.layerCount = parseFloat(visualization.layerCount.toString()); + visualizationJson.size = parseFloat(visualization.size.toString()); - const visualizations = visualizationData.graphics; - for (const visualizationArr of visualizations) { - for (const visualization of visualizationArr.visualization) { - const attributes = visualization['$']; + FurniJsonMapper.mapVisualizationLayerXML(visualization, visualizationJson); + FurniJsonMapper.mapVisualizationDirectionXML(visualization, visualizationJson); + FurniJsonMapper.mapVisualizationColorXML(visualization, visualizationJson); + FurniJsonMapper.mapVisualizationAnimationXML(visualization, visualizationJson); + FurniJsonMapper.mapVisualizationPostureXML(visualization, visualizationJson); + FurniJsonMapper.mapVisualizationGestureXML(visualization, visualizationJson); - if (attributes.size == FurniJsonMapper.VISUALIZATION_DEFAULT_SIZE || attributes.size == FurniJsonMapper.VISUALIZATION_ICON_SIZE) { - const visualizationType: Visualization = {} as any; - visualizationType.angle = attributes.angle; - visualizationType.layerCount = attributes.layerCount; - visualizationType.size = attributes.size; - - this.mapVisualizationLayersXML(visualization, visualizationType); - this.mapVisualizationDirectionXML(visualization, visualizationType); - - visualizationsArray.push(visualizationType); - } + visualizationsArray.push(visualizationJson); } } output.visualizations = visualizationsArray; } - private mapVisualizationColorXML(visualization: any, visualizationType: Visualization) { - if (visualization.colors !== undefined && visualization.colors.length > 0) { - + private static mapVisualizationLayerXML(visXML: VisualizationXML, output: Visualization) { + if (visXML.layers.length > 0) { + output.layers = FurniJsonMapper.mapVisualizationLayersXML(visXML.layers); } } - private mapVisualizationDirectionXML(visualization: any, visualizationType: Visualization) { - if (visualization.directions !== undefined && visualization.directions.length > 0) { + private static mapVisualizationLayersXML(layersXML: Array): VisualizationLayers { + const layers: VisualizationLayers = {}; + for (const layerXML of layersXML) { + const layer: Layer = {} as any; + layer.alpha = layerXML.alpha; + layer.ink = layerXML.ink; + layer.tag = layerXML.tag; + layer.x = parseFloat(layerXML.x.toString()); + layer.y = parseFloat(layerXML.y.toString()); + layer.z = parseFloat(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 directionParent of visualization.directions) { - for (const direction of directionParent.direction) { - const attributes = direction['$']; - const directionType: Direction = {} as any; - directionType.id = attributes.id; + for (const directionXML of visXML.directions) { + const direction: Direction = {} as any; + if (directionXML.layers.length > 0) { + direction.layers = FurniJsonMapper.mapVisualizationLayersXML(directionXML.layers); + } - if (direction.layers !== undefined && direction.layers.length > 0) { - directionType.layers = this.generateLayers(direction, visualizationType); - } + directions[directionXML.id] = direction; + } - directions[directionType.id] = directionType; + 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(directions).length > 0) visualizationType.directions = directions; - } - } - - private mapVisualizationLayersXML(visualization: any, visualizationType: Visualization) { - if (visualization.layers !== undefined && visualization.layers.length > 0) { - for (const layerEntry of visualization.layers) { - const layer = layerEntry.layer; - visualizationType.layers = this.generateLayers(layer, visualizationType); + if (Object.keys(colors).length > 0) { + output.colors = colors; } } } - private generateLayers(visualization: any, visualizationType: Visualization): VisualizationLayers { - const visualizationLayers: VisualizationLayers = {} as any; - for (const layerEntry of visualization.layers) { - const layer = layerEntry.layer; - const layerAttributes = layer['$']; + 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); - const layerType: Layer = { - id: layerAttributes.id, - alpha: layerAttributes.alpha, - ink: layerAttributes.ink, - tag: layerAttributes.tag, - x: layerAttributes.x, - y: layerAttributes.y, - z: layerAttributes.z, - } as any; - if (layerAttributes.ignoreMouse !== undefined) layerType.ignoreMouse = layerAttributes.ignoreMouse === '1'; - - visualizationLayers[layerAttributes.id] = layerType; + colorLayers[colorLayerXML.id] = colorLayer; } - return visualizationLayers; + 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; + animation.transitionTo = animationXML.transitionTo; + animation.transitionFrom = animationXML.transitionFrom; + 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; + animationLayer.frameRepeat = animationLayerXML.frameRepeat; + animationLayer.loopCount = animationLayerXML.loopCount; + animationLayer.random = animationLayerXML.random; + + 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; + frame.x = frameXML.x; + frame.y = frameXML.y; + frame.randomX = frameXML.randomX; + frame.randomY = frameXML.randomY; + if (frameXML.id === "NaN") { + frame.id = 0; + } else { + frame.id = parseInt(frameXML.id); + } + if (frameXML.offsets.length > 0) { + const offsets: Array = new Array(); + 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; + } + } } } \ No newline at end of file diff --git a/src/converters/furniture/FurniTypes.ts b/src/converters/furniture/FurniTypes.ts index acd2ca9..6706413 100644 --- a/src/converters/furniture/FurniTypes.ts +++ b/src/converters/furniture/FurniTypes.ts @@ -80,7 +80,6 @@ export interface FrameSequences { } export interface AnimationLayer { - id: number, loopCount: number, frameRepeat: number, random: number, @@ -97,7 +96,6 @@ export interface Animations { } export interface Animation { - id: number, transitionTo: number, transitionFrom: number, immediateChangeFrom: string, @@ -110,7 +108,6 @@ export interface ColorLayers { } export interface ColorLayer { - id: number, color: number } @@ -119,7 +116,6 @@ export interface Colors { } export interface Color { - id: number; layers: ColorLayers; } @@ -128,7 +124,6 @@ export interface Directions { } export interface Direction { - id: number; layers: VisualizationLayers; } @@ -137,7 +132,6 @@ export interface VisualizationLayers { } export interface Layer { - id: number, alpha: number, x: number, y: number, diff --git a/src/converters/furniture/FurniXMLTypes.ts b/src/converters/furniture/FurniXMLTypes.ts new file mode 100644 index 0000000..7f39fdf --- /dev/null +++ b/src/converters/furniture/FurniXMLTypes.ts @@ -0,0 +1,247 @@ +export class AssetsXML { + private readonly _assets: Array; + + constructor(assetsXML: any) { + this._assets = new Array(); + + for (const asset of assetsXML.assets.asset) { + this._assets.push(new AssetXML(asset)); + } + } + + get assets(): Array { + 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; + + constructor(modelXML: any) { + this._dimensions = new DimensionsXML(modelXML.dimensions[0]); + this._directions = new Array(); + + 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 { + 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; + } +} \ No newline at end of file diff --git a/src/converters/furniture/FurnitureConverter.ts b/src/converters/furniture/FurnitureConverter.ts index a5df835..878689d 100644 --- a/src/converters/furniture/FurnitureConverter.ts +++ b/src/converters/furniture/FurnitureConverter.ts @@ -4,11 +4,13 @@ import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag"; import Configuration from "../../config/Configuration"; import FurniJsonMapper from "./FurniJsonMapper"; import {FurniJson} from "./FurniTypes"; +import File from "../../utils/File"; const xml2js = require('xml2js'); const parser = new xml2js.Parser(/* options */); const fs = require('fs').promises; +const {gzip} = require('node-gzip'); export default class FurnitureConverter { @@ -78,8 +80,18 @@ export default class FurnitureConverter { const furnitureJson = await this.convertXML2JSON(habboAssetSWF); if (furnitureJson !== null) { furnitureJson.spritesheet = spriteSheetType; + furnitureJson.type = type; - await fs.writeFile(outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".json", JSON.stringify(furnitureJson)); + const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro"; + const assetOuputFolder = new File(path); + if (assetOuputFolder.exists()) { + console.log("Furniture already exists or the directory is not empty!"); + + return; + } + + const compressed = await gzip(JSON.stringify(furnitureJson)); + await fs.writeFile(path, compressed); } } } \ No newline at end of file diff --git a/src/converters/furniture/VisualizationXMLTypes.ts b/src/converters/furniture/VisualizationXMLTypes.ts new file mode 100644 index 0000000..0956cb1 --- /dev/null +++ b/src/converters/furniture/VisualizationXMLTypes.ts @@ -0,0 +1,517 @@ +export class VisualizationDataXML { + + private readonly _type: string; + private readonly _visualizations: Array; + + constructor(visualizationXML: any) { + this._type = visualizationXML.$.type; + this._visualizations = new Array(); + + 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 { + return this._visualizations; + } +} + +export class VisualizationXML { + + private readonly _size: number; + private readonly _layerCount: number; + private readonly _angle: number; + + private readonly _layers: Array; + private readonly _directions: Array; + private readonly _colors: Array; + private readonly _animations: Array; + private readonly _postures: Array; + private readonly _gestures: Array; + + constructor(visualizationXML: any) { + const attributes = visualizationXML.$; + this._size = attributes.size; + this._layerCount = attributes.layerCount; + this._angle = attributes.angle; + + this._layers = new Array(); + 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(); + 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(); + 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(); + 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(); + 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(); + 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 { + return this._layers; + } + + get directions(): Array { + return this._directions; + } + + get colors(): Array { + return this._colors; + } + + get animations(): Array { + return this._animations; + } + + get postures(): Array { + return this._postures; + } + + get gestures(): Array { + 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; + + constructor(directionXML: any) { + this._id = directionXML.$.id; + + this._layers = new Array(); + 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 { + return this._layers; + } +} + +export class ColorXML { + private readonly _id: number; + private readonly _layers: Array; + + constructor(colorXML: any) { + this._id = colorXML.$.id; + + this._layers = new Array(); + for (const colorLayer of colorXML.colorLayer) { + this._layers.push(new ColorLayerXML(colorLayer)); + } + } + + + get id(): number { + return this._id; + } + + get layers(): Array { + 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; + + 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(); + 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 { + 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; + + 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(); + 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 { + return this._frameSequences; + } +} + +export class FrameSequenceXML { + private readonly _loopCount: number; + private readonly _random: number; + + private readonly _frames: Array; + + constructor(frameSequenceXML: any) { + let attributes = frameSequenceXML.$; + if (attributes === undefined) attributes = {}; + + this._loopCount = attributes.loopCount; + this._random = attributes.random; + + this._frames = new Array(); + 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 { + 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; + + 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(); + 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 { + 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; + } +} \ No newline at end of file diff --git a/src/converters/util/SpriteSheetConverter.ts b/src/converters/util/SpriteSheetConverter.ts index d5b7af9..6869dd3 100644 --- a/src/converters/util/SpriteSheetConverter.ts +++ b/src/converters/util/SpriteSheetConverter.ts @@ -94,10 +94,11 @@ export default class SpriteSheetConverter { if (spriteSheetType === null) throw new Error("Failed to parse SpriteSheet. " + images[0].path); } catch (error) { - console.log("Error: " + error); + console.log("Image Packing Error: "); + console.log(error); } - if (spriteSheetType !== null) spriteSheetType.meta.imageb64 = base64; + if (spriteSheetType !== null) spriteSheetType.meta.image = base64; return spriteSheetType; } } \ No newline at end of file diff --git a/src/converters/util/SpriteSheetTypes.ts b/src/converters/util/SpriteSheetTypes.ts index 9b4277e..a076a57 100644 --- a/src/converters/util/SpriteSheetTypes.ts +++ b/src/converters/util/SpriteSheetTypes.ts @@ -43,7 +43,7 @@ export interface SpriteSheetFrameDimensions { export interface SpriteSheetMeta { app: string, version: string, - imageb64: string, + image: string, format: string, size: SpriteSheetSize, scale: number diff --git a/src/downloaders/FurnitureDownloader.ts b/src/downloaders/FurnitureDownloader.ts index 1479741..c7267c9 100644 --- a/src/downloaders/FurnitureDownloader.ts +++ b/src/downloaders/FurnitureDownloader.ts @@ -61,7 +61,7 @@ export default class FurnitureDownloader { } async extractFurniture(revision: string, className: string, callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise) { - if (className !== "rare_dragonlamp") return; + //if (className !== "rare_dragonlamp" && className !== "tiki_bflies" && className !== "room_wl15_ele") return; const url = this._config.getValue("dynamic.download.url.furniture").replace("%revision%", revision).replace("%className%", className); const file = new File(url); diff --git a/src/utils/File.ts b/src/utils/File.ts index f0bc5c3..de2275e 100644 --- a/src/utils/File.ts +++ b/src/utils/File.ts @@ -1,3 +1,5 @@ +import {RmDirOptions, RmOptions} from "fs"; + const fs = require("fs"); export default class File { @@ -30,4 +32,8 @@ export default class File { get path(): string { return this._path; } + + public rmdir(options: RmOptions): void { + return fs.rmSync(this._path, options); + } } \ No newline at end of file