├── src ├── common │ ├── config │ │ ├── index.ts │ │ └── Configuration.ts │ ├── mapping │ │ ├── mappers │ │ │ ├── asset │ │ │ │ ├── Mapper.ts │ │ │ │ ├── index.ts │ │ │ │ ├── IndexMapper.ts │ │ │ │ ├── AssetMapper.ts │ │ │ │ └── ManifestMapper.ts │ │ │ ├── index.ts │ │ │ ├── EffectMapMapper.ts │ │ │ ├── FigureMapMapper.ts │ │ │ └── FurnitureDataMapper.ts │ │ ├── json │ │ │ ├── externaltexts │ │ │ │ ├── index.ts │ │ │ │ └── IExternalTexts.ts │ │ │ ├── asset │ │ │ │ ├── visualization │ │ │ │ │ ├── gestures │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── IAssetGesture.ts │ │ │ │ │ ├── postures │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── IAssetPosture.ts │ │ │ │ │ ├── color │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── IAssetColorLayer.ts │ │ │ │ │ │ └── IAssetColor.ts │ │ │ │ │ ├── animation │ │ │ │ │ │ ├── IAssetVisualAnimationSequenceFrameOffset.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── IAssetVisualAnimationSequence.ts │ │ │ │ │ │ ├── IAssetVisualAnimationLayer.ts │ │ │ │ │ │ ├── IAssetVisualAnimation.ts │ │ │ │ │ │ └── IAssetVisualAnimationSequenceFrame.ts │ │ │ │ │ ├── IAssetVisualizationDirection.ts │ │ │ │ │ ├── IAssetVisualizationLayer.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── IAssetVisualizationData.ts │ │ │ │ ├── logic │ │ │ │ │ ├── model │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── IAssetDimension.ts │ │ │ │ │ │ └── IAssetLogicModel.ts │ │ │ │ │ ├── IAssetLogicCustomVars.ts │ │ │ │ │ ├── ISoundSample.ts │ │ │ │ │ ├── particlesystem │ │ │ │ │ │ ├── IParticleSystemParticle.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── IParticleSystemSimulation.ts │ │ │ │ │ │ ├── IParticleSystem.ts │ │ │ │ │ │ └── IParticleSystemEmitter.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── IAssetLogicPlanetSystem.ts │ │ │ │ │ └── IAssetLogicData.ts │ │ │ │ ├── animation │ │ │ │ │ ├── IAssetAnimationRemove.ts │ │ │ │ │ ├── IAssetAnimationShadow.ts │ │ │ │ │ ├── IAssetAnimationDirection.ts │ │ │ │ │ ├── IAssetAnimationFramePartItem.ts │ │ │ │ │ ├── IAssetAnimationAvatar.ts │ │ │ │ │ ├── IAssetAnimationSpriteDirection.ts │ │ │ │ │ ├── IAssetAnimationAdd.ts │ │ │ │ │ ├── IAssetAnimationOverride.ts │ │ │ │ │ ├── IAssetAnimationFrame.ts │ │ │ │ │ ├── IAssetAnimationSprite.ts │ │ │ │ │ ├── IAssetAnimationFramePart.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── IAssetAnimation.ts │ │ │ │ ├── IAssetAlias.ts │ │ │ │ ├── spritesheet │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── ISpritesheetMeta.ts │ │ │ │ │ ├── ISpritesheetData.ts │ │ │ │ │ └── ISpritesheetFrame.ts │ │ │ │ ├── IAsset.ts │ │ │ │ ├── index.ts │ │ │ │ ├── IAssetPalette.ts │ │ │ │ └── IAssetData.ts │ │ │ ├── effectmap │ │ │ │ ├── index.ts │ │ │ │ ├── IEffectMap.ts │ │ │ │ └── IEffectMapLibrary.ts │ │ │ ├── productdata │ │ │ │ ├── index.ts │ │ │ │ ├── IProductType.ts │ │ │ │ └── IProductData.ts │ │ │ ├── furnituredata │ │ │ │ ├── index.ts │ │ │ │ ├── IFurnitureData.ts │ │ │ │ └── IFurnitureType.ts │ │ │ ├── figuredata │ │ │ │ ├── IFigureDataHiddenLayer.ts │ │ │ │ ├── IFigureDataColor.ts │ │ │ │ ├── IFigureDataPart.ts │ │ │ │ ├── IFigureDataPalette.ts │ │ │ │ ├── IFigureData.ts │ │ │ │ ├── index.ts │ │ │ │ ├── IFigureDataSetType.ts │ │ │ │ └── IFigureDataSet.ts │ │ │ ├── figuremap │ │ │ │ ├── IFigureMapLibraryPart.ts │ │ │ │ ├── index.ts │ │ │ │ ├── IFigureMap.ts │ │ │ │ └── IFigureMapLibrary.ts │ │ │ └── index.ts │ │ ├── xml │ │ │ ├── effectmap │ │ │ │ ├── index.ts │ │ │ │ ├── EffectMapXML.ts │ │ │ │ └── EffectMapEffectXML.ts │ │ │ ├── asset │ │ │ │ ├── visualization │ │ │ │ │ ├── color │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── ColorLayerXML.ts │ │ │ │ │ │ └── ColorXML.ts │ │ │ │ │ ├── animation │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── FrameOffsetXML.ts │ │ │ │ │ │ ├── FrameSequenceXML.ts │ │ │ │ │ │ ├── FrameXML.ts │ │ │ │ │ │ ├── AnimationLayerXML.ts │ │ │ │ │ │ └── AnimationXML.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── GestureXML.ts │ │ │ │ │ ├── PostureXML.ts │ │ │ │ │ ├── VisualDirectionXML.ts │ │ │ │ │ ├── VisualizationXML.ts │ │ │ │ │ └── LayerXML.ts │ │ │ │ ├── assets │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── AssetsXML.ts │ │ │ │ │ ├── AssetXML.ts │ │ │ │ │ └── PaletteXML.ts │ │ │ │ ├── logic │ │ │ │ │ ├── model │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── ModelDirectionXML.ts │ │ │ │ │ │ ├── ModelDimensionsXML.ts │ │ │ │ │ │ └── ModelXML.ts │ │ │ │ │ ├── particlesystem │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── ParticleSystemXML.ts │ │ │ │ │ │ ├── ParticleSystemParticleXML.ts │ │ │ │ │ │ ├── ParticleSystemSimulationXML.ts │ │ │ │ │ │ ├── ParticleSystemObjectXML.ts │ │ │ │ │ │ ├── PlanetSystemObjectXML.ts │ │ │ │ │ │ └── ParticleSystemEmitterXML.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── MaskXML.ts │ │ │ │ │ ├── CreditsXML.ts │ │ │ │ │ ├── PlanetSystemXML.ts │ │ │ │ │ ├── SoundSampleXML.ts │ │ │ │ │ ├── ActionXML.ts │ │ │ │ │ ├── CustomVarsXML.ts │ │ │ │ │ └── LogicXML.ts │ │ │ │ ├── index.ts │ │ │ │ ├── manifest │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── ManifestLibraryAssetParamXML.ts │ │ │ │ │ ├── ManifestXML.ts │ │ │ │ │ ├── ManifestLibraryAssetXML.ts │ │ │ │ │ ├── ManifestLibraryAliasXML.ts │ │ │ │ │ └── ManifestLibraryXML.ts │ │ │ │ ├── animation │ │ │ │ │ ├── RemoveXML.ts │ │ │ │ │ ├── ShadowXML.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── DirectionOffsetXML.ts │ │ │ │ │ ├── EffectFramePartItemXML.ts │ │ │ │ │ ├── AvatarXML.ts │ │ │ │ │ ├── DirectionXML.ts │ │ │ │ │ ├── OverrideXML.ts │ │ │ │ │ ├── AddXML.ts │ │ │ │ │ ├── EffectFrameXML.ts │ │ │ │ │ ├── SpriteXML.ts │ │ │ │ │ └── EffectFramePartXML.ts │ │ │ │ └── IndexXML.ts │ │ │ ├── furnituredata │ │ │ │ ├── index.ts │ │ │ │ ├── FurnitureDataXML.ts │ │ │ │ └── FurnitureTypeXML.ts │ │ │ ├── figuremap │ │ │ │ ├── index.ts │ │ │ │ ├── FigureLibraryPartXML.ts │ │ │ │ ├── FigureMapXML.ts │ │ │ │ └── FigureLibraryXML.ts │ │ │ ├── index.ts │ │ │ └── figuredata │ │ │ │ ├── index.ts │ │ │ │ ├── FigureDataHiddenLayerXML.ts │ │ │ │ ├── FigureDataPaletteXML.ts │ │ │ │ ├── FigureDataColorXML.ts │ │ │ │ ├── FigureDataPartXML.ts │ │ │ │ ├── FigureDataXML.ts │ │ │ │ ├── FigureDataSetTypeXML.ts │ │ │ │ └── FigureDataSetXML.ts │ │ └── index.ts │ ├── converters │ │ ├── index.ts │ │ ├── IConverter.ts │ │ └── ConverterResult.ts │ ├── bundle │ │ ├── index.ts │ │ ├── ImageBundle.ts │ │ ├── SpriteBundle.ts │ │ └── NitroBundle.ts │ ├── utils │ │ ├── index.ts │ │ ├── SlicedToArray.ts │ │ ├── BinaryReader.ts │ │ ├── FileUtilities.ts │ │ ├── CustomIterator.ts │ │ └── File.ts │ └── index.ts ├── swf │ ├── tags │ │ ├── ITag.ts │ │ ├── ISymbolClass.ts │ │ ├── index.ts │ │ ├── CharacterTag.ts │ │ ├── SymbolClassTag.ts │ │ ├── ImageTag.ts │ │ └── DefineBinaryDataTag.ts │ ├── common │ │ ├── ISWFTagAsset.ts │ │ ├── ISWFTagScene.ts │ │ ├── ISWFTagSymbol.ts │ │ ├── ISWFTagHeader.ts │ │ ├── ISWFTagLabel.ts │ │ ├── ISWFFileLength.ts │ │ ├── ISWFFrameSize.ts │ │ ├── ISWFTagSplitter.ts │ │ ├── ISWFFileAttributes.ts │ │ ├── index.ts │ │ ├── ISWF.ts │ │ └── ISWFTag.ts │ ├── ConcatSWFHeader.ts │ ├── ReadSWF.ts │ ├── RecognizeImageHeader.ts │ ├── index.ts │ ├── GenerateNitroBundleFromSwf.ts │ ├── ReadSWFBuffer.ts │ ├── SWFDownloader.ts │ ├── PackImages.ts │ ├── GenerateSpritesheet.ts │ ├── ReadImagesJPEG3or4.ts │ ├── UncompressSWF.ts │ ├── ReadImagesDefineBitsLossless.ts │ └── SWFTags.ts ├── converters │ ├── FigureDataConverter.ts │ ├── ExternalTextsConverter.ts │ ├── EffectMapConverter.ts │ ├── FigureMapConverter.ts │ ├── ProductDataConverter.ts │ └── FurnitureDataConverter.ts └── Main.ts ├── .editorconfig ├── .vscode └── settings.json ├── tsconfig.json ├── .gitignore ├── configuration.json.example ├── package.json └── .eslintrc.json /src/common/config/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Configuration'; 2 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/asset/Mapper.ts: -------------------------------------------------------------------------------- 1 | export class Mapper 2 | {} 3 | -------------------------------------------------------------------------------- /src/swf/tags/ITag.ts: -------------------------------------------------------------------------------- 1 | export interface ITag 2 | { 3 | code: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/externaltexts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IExternalTexts'; 2 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/gestures/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetGesture'; 2 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/postures/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetPosture'; 2 | -------------------------------------------------------------------------------- /src/common/converters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ConverterResult'; 2 | export * from './IConverter'; 3 | -------------------------------------------------------------------------------- /src/common/converters/IConverter.ts: -------------------------------------------------------------------------------- 1 | export interface IConverter 2 | { 3 | convertAsync(): Promise; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/effectmap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IEffectMap'; 2 | export * from './IEffectMapLibrary'; 3 | -------------------------------------------------------------------------------- /src/common/mapping/json/productdata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IProductData'; 2 | export * from './IProductType'; 3 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTagAsset.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFTagAsset 2 | { 3 | id: number; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/swf/tags/ISymbolClass.ts: -------------------------------------------------------------------------------- 1 | export interface ISymbolClass 2 | { 3 | id: number; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/furnituredata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IFurnitureData'; 2 | export * from './IFurnitureType'; 3 | -------------------------------------------------------------------------------- /src/common/mapping/xml/effectmap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './EffectMapEffectXML'; 2 | export * from './EffectMapXML'; 3 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTagScene.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFTagScene 2 | { 3 | offset: number; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTagSymbol.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFTagSymbol 2 | { 3 | id: number; 4 | name: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/color/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ColorLayerXML'; 2 | export * from './ColorXML'; 3 | -------------------------------------------------------------------------------- /src/common/mapping/xml/furnituredata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FurnitureDataXML'; 2 | export * from './FurnitureTypeXML'; 3 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTagHeader.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFTagHeader 2 | { 3 | code: number; 4 | length: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/bundle/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ImageBundle'; 2 | export * from './NitroBundle'; 3 | export * from './SpriteBundle'; 4 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetDimension'; 2 | export * from './IAssetLogicModel'; 3 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/color/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetColor'; 2 | export * from './IAssetColorLayer'; 3 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTagLabel.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFTagLabel 2 | { 3 | frameNum: number; 4 | frameLabel: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/IAssetLogicCustomVars.ts: -------------------------------------------------------------------------------- 1 | export interface ICustomVars 2 | { 3 | variables?: string[]; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/externaltexts/IExternalTexts.ts: -------------------------------------------------------------------------------- 1 | export interface IExternalTexts 2 | { 3 | [index: string]: string 4 | } 5 | -------------------------------------------------------------------------------- /src/swf/common/ISWFFileLength.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFFileLength 2 | { 3 | compressed: number; 4 | uncompressed: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationRemove.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationRemove 2 | { 3 | id?: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationShadow.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationShadow 2 | { 3 | id?: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/color/IAssetColorLayer.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetColorLayer 2 | { 3 | color?: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureDataHiddenLayer.ts: -------------------------------------------------------------------------------- 1 | export interface IFigureDataHiddenLayer 2 | { 3 | partType?: string; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/assets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AssetsXML'; 2 | export * from './AssetXML'; 3 | export * from './PaletteXML'; 4 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/ISoundSample.ts: -------------------------------------------------------------------------------- 1 | export interface ISoundSample 2 | { 3 | id?: number; 4 | noPitch?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationDirection.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationDirection 2 | { 3 | offset?: number; 4 | } 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuremap/IFigureMapLibraryPart.ts: -------------------------------------------------------------------------------- 1 | export interface IFigureMapLibraryPart 2 | { 3 | id?: number; 4 | type?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/IAssetAlias.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAlias 2 | { 3 | link?: string; 4 | flipH?: boolean; 5 | flipV?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuremap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IFigureMap'; 2 | export * from './IFigureMapLibrary'; 3 | export * from './IFigureMapLibraryPart'; 4 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuremap/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FigureLibraryPartXML'; 2 | export * from './FigureLibraryXML'; 3 | export * from './FigureMapXML'; 4 | -------------------------------------------------------------------------------- /src/swf/ConcatSWFHeader.ts: -------------------------------------------------------------------------------- 1 | export const ConcatSWFHeader = (buff: Buffer, swf: Buffer) => 2 | { 3 | return Buffer.concat([ swf.slice(0, 8), buff ]); 4 | }; 5 | -------------------------------------------------------------------------------- /src/swf/common/ISWFFrameSize.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFFrameSize 2 | { 3 | x: number; 4 | y: number; 5 | width: number; 6 | height: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/gestures/IAssetGesture.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetGesture 2 | { 3 | id?: string; 4 | animationId?: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/postures/IAssetPosture.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetPosture 2 | { 3 | id?: string; 4 | animationId?: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/model/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ModelDimensionsXML'; 2 | export * from './ModelDirectionXML'; 3 | export * from './ModelXML'; 4 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTagSplitter.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFTagSplitter 2 | { 3 | x: number; 4 | y: number; 5 | width: number; 6 | height: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/spritesheet/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ISpritesheetData'; 2 | export * from './ISpritesheetFrame'; 3 | export * from './ISpritesheetMeta'; 4 | -------------------------------------------------------------------------------- /src/common/mapping/json/productdata/IProductType.ts: -------------------------------------------------------------------------------- 1 | export interface IProductType 2 | { 3 | code: string; 4 | name: string; 5 | description: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationFramePartItem.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationFramePartItem 2 | { 3 | id?: string; 4 | base?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/model/IAssetDimension.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetDimension 2 | { 3 | x: number; 4 | y: number; 5 | z?: number; 6 | centerZ?: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/effectmap/IEffectMap.ts: -------------------------------------------------------------------------------- 1 | import { IEffectMapLibrary } from './IEffectMapLibrary'; 2 | 3 | export interface IEffectMap 4 | { 5 | effects?: IEffectMapLibrary[]; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/effectmap/IEffectMapLibrary.ts: -------------------------------------------------------------------------------- 1 | export interface IEffectMapLibrary 2 | { 3 | id?: string; 4 | lib?: string; 5 | type?: string; 6 | revision?: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuremap/IFigureMap.ts: -------------------------------------------------------------------------------- 1 | import { IFigureMapLibrary } from './IFigureMapLibrary'; 2 | 3 | export interface IFigureMap 4 | { 5 | libraries?: IFigureMapLibrary[]; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/xml/index.ts: -------------------------------------------------------------------------------- 1 | export * from './asset'; 2 | export * from './effectmap'; 3 | export * from './figuredata'; 4 | export * from './figuremap'; 5 | export * from './furnituredata'; 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationAvatar.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationAvatar 2 | { 3 | ink?: number; 4 | foreground?: string; 5 | background?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BinaryReader'; 2 | export * from './CustomIterator'; 3 | export * from './File'; 4 | export * from './FileUtilities'; 5 | export * from './SlicedToArray'; 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationSpriteDirection.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationSpriteDirection 2 | { 3 | id?: number; 4 | dx?: number; 5 | dy?: number; 6 | dz?: number; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationAdd.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetAnimationAdd 2 | { 3 | id?: string; 4 | align?: string; 5 | blend?: string; 6 | ink?: number; 7 | base?: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureDataColor.ts: -------------------------------------------------------------------------------- 1 | export interface IFigureDataColor 2 | { 3 | id?: number; 4 | index?: number; 5 | club?: number; 6 | selectable?: boolean; 7 | hexCode?: string; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureDataPart.ts: -------------------------------------------------------------------------------- 1 | export interface IFigureDataPart 2 | { 3 | id?: number; 4 | type?: string; 5 | colorable?: boolean; 6 | index?: number; 7 | colorindex?: number; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/productdata/IProductData.ts: -------------------------------------------------------------------------------- 1 | import { IProductType } from './IProductType'; 2 | 3 | export interface IProductData 4 | { 5 | productdata?: { 6 | product: IProductType[] 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './asset'; 2 | export * from './EffectMapMapper'; 3 | export * from './FigureDataMapper'; 4 | export * from './FigureMapMapper'; 5 | export * from './FurnitureDataMapper'; 6 | -------------------------------------------------------------------------------- /src/swf/common/ISWFFileAttributes.ts: -------------------------------------------------------------------------------- 1 | export interface ISWFFileAttributes 2 | { 3 | useNetwork: boolean, 4 | as3: boolean, 5 | hasMetaData: boolean, 6 | useGPU: boolean, 7 | useDirectBit: boolean 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/color/IAssetColor.ts: -------------------------------------------------------------------------------- 1 | import { IAssetColorLayer } from './IAssetColorLayer'; 2 | 3 | export interface IAssetColor 4 | { 5 | layers?: { [index: string]: IAssetColorLayer }; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureDataPalette.ts: -------------------------------------------------------------------------------- 1 | import { IFigureDataColor } from './IFigureDataColor'; 2 | 3 | export interface IFigureDataPalette 4 | { 5 | id?: number; 6 | colors?: IFigureDataColor[]; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/IAsset.ts: -------------------------------------------------------------------------------- 1 | export interface IAsset 2 | { 3 | source?: string; 4 | x?: number; 5 | y?: number; 6 | flipH?: boolean; 7 | flipV?: boolean; 8 | usesPalette?: boolean; 9 | } 10 | -------------------------------------------------------------------------------- /src/swf/tags/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CharacterTag'; 2 | export * from './DefineBinaryDataTag'; 3 | export * from './ImageTag'; 4 | export * from './ISymbolClass'; 5 | export * from './ITag'; 6 | export * from './SymbolClassTag'; 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/model/IAssetLogicModel.ts: -------------------------------------------------------------------------------- 1 | import { IAssetDimension } from './IAssetDimension'; 2 | 3 | export interface IAssetLogicModel 4 | { 5 | dimensions?: IAssetDimension; 6 | directions?: number[]; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/particlesystem/IParticleSystemParticle.ts: -------------------------------------------------------------------------------- 1 | export interface IParticleSystemParticle 2 | { 3 | isEmitter?: boolean; 4 | lifeTime?: number; 5 | fade?: boolean; 6 | frames?: string[]; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/particlesystem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IParticleSystem'; 2 | export * from './IParticleSystemEmitter'; 3 | export * from './IParticleSystemParticle'; 4 | export * from './IParticleSystemSimulation'; 5 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/animation/IAssetVisualAnimationSequenceFrameOffset.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetVisualAnimationSequenceFrameOffset 2 | { 3 | direction?: number; 4 | x?: number; 5 | y?: number; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/animation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnimationLayerXML'; 2 | export * from './AnimationXML'; 3 | export * from './FrameOffsetXML'; 4 | export * from './FrameSequenceXML'; 5 | export * from './FrameXML'; 6 | -------------------------------------------------------------------------------- /src/common/converters/ConverterResult.ts: -------------------------------------------------------------------------------- 1 | export class ConverterResult 2 | { 3 | public static OK: number = 1; 4 | public static BAD_ARGS: number = 2; 5 | public static FILE_EXISTS: number = 3; 6 | public static INVALID_SWF: number = 4; 7 | } 8 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/index.ts: -------------------------------------------------------------------------------- 1 | export * from './animation'; 2 | export * from './assets'; 3 | export * from './index'; 4 | export * from './IndexXML'; 5 | export * from './logic'; 6 | export * from './manifest'; 7 | export * from './visualization'; 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuremap/IFigureMapLibrary.ts: -------------------------------------------------------------------------------- 1 | import { IFigureMapLibraryPart } from './IFigureMapLibraryPart'; 2 | 3 | export interface IFigureMapLibrary 4 | { 5 | id?: string; 6 | revision?: number; 7 | parts?: IFigureMapLibraryPart[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/index.ts: -------------------------------------------------------------------------------- 1 | export * from './asset'; 2 | export * from './effectmap'; 3 | export * from './externaltexts'; 4 | export * from './figuredata'; 5 | export * from './figuremap'; 6 | export * from './furnituredata'; 7 | export * from './productdata'; 8 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/manifest/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ManifestLibraryAliasXML'; 2 | export * from './ManifestLibraryAssetParamXML'; 3 | export * from './ManifestLibraryAssetXML'; 4 | export * from './ManifestLibraryXML'; 5 | export * from './ManifestXML'; 6 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetLogicCustomVars'; 2 | export * from './IAssetLogicData'; 3 | export * from './IAssetLogicPlanetSystem'; 4 | export * from './ISoundSample'; 5 | export * from './model'; 6 | export * from './particlesystem'; 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/IAssetVisualizationDirection.ts: -------------------------------------------------------------------------------- 1 | import { IAssetVisualizationLayer } from './IAssetVisualizationLayer'; 2 | 3 | export interface IAssetVisualizationDirection 4 | { 5 | layers?: { [index: string]: IAssetVisualizationLayer }; 6 | } 7 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationOverride.ts: -------------------------------------------------------------------------------- 1 | import { IAssetAnimationFrame } from './IAssetAnimationFrame'; 2 | 3 | export interface IAssetAnimationOverride 4 | { 5 | name?: string; 6 | override?: string; 7 | frames?: IAssetAnimationFrame[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/IAssetVisualizationLayer.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetVisualizationLayer 2 | { 3 | x?: number; 4 | y?: number; 5 | z?: number; 6 | alpha?: number; 7 | ink?: string; 8 | tag?: string; 9 | ignoreMouse?: boolean; 10 | } -------------------------------------------------------------------------------- /src/common/mapping/mappers/asset/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AnimationMapper'; 2 | export * from './AssetMapper'; 3 | export * from './IndexMapper'; 4 | export * from './LogicMapper'; 5 | export * from './ManifestMapper'; 6 | export * from './Mapper'; 7 | export * from './VisualizationMapper'; 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/index.ts: -------------------------------------------------------------------------------- 1 | export * from './animation'; 2 | export * from './IAsset'; 3 | export * from './IAssetAlias'; 4 | export * from './IAssetData'; 5 | export * from './IAssetPalette'; 6 | export * from './logic'; 7 | export * from './spritesheet'; 8 | export * from './visualization'; 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/particlesystem/IParticleSystemSimulation.ts: -------------------------------------------------------------------------------- 1 | export interface IParticleSystemSimulation 2 | { 3 | force?: number; 4 | direction?: number; 5 | gravity?: number; 6 | airFriction?: number; 7 | shape?: string; 8 | energy?: number; 9 | } 10 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureData.ts: -------------------------------------------------------------------------------- 1 | import { IFigureDataPalette } from './IFigureDataPalette'; 2 | import { IFigureDataSetType } from './IFigureDataSetType'; 3 | 4 | export interface IFigureData 5 | { 6 | palettes?: IFigureDataPalette[]; 7 | setTypes?: IFigureDataSetType[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationFrame.ts: -------------------------------------------------------------------------------- 1 | import { IAssetAnimationFramePart } from './IAssetAnimationFramePart'; 2 | 3 | export interface IAssetAnimationFrame 4 | { 5 | repeats?: number; 6 | fxs?: IAssetAnimationFramePart[]; 7 | bodyparts?: IAssetAnimationFramePart[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/spritesheet/ISpritesheetMeta.ts: -------------------------------------------------------------------------------- 1 | export interface ISpritesheetMeta 2 | { 3 | app: string; 4 | version: string; 5 | image: string; 6 | format: string; 7 | size: { 8 | w: number; 9 | h: number; 10 | }; 11 | scale: string; 12 | } 13 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/spritesheet/ISpritesheetData.ts: -------------------------------------------------------------------------------- 1 | import { ISpritesheetFrame } from './ISpritesheetFrame'; 2 | import { ISpritesheetMeta } from './ISpritesheetMeta'; 3 | 4 | export interface ISpritesheetData 5 | { 6 | meta?: ISpritesheetMeta; 7 | frames?: { [index: string]: ISpritesheetFrame }; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './animation'; 2 | export * from './color'; 3 | export * from './gestures'; 4 | export * from './IAssetVisualizationData'; 5 | export * from './IAssetVisualizationDirection'; 6 | export * from './IAssetVisualizationLayer'; 7 | export * from './postures'; 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IFigureData'; 2 | export * from './IFigureDataColor'; 3 | export * from './IFigureDataHiddenLayer'; 4 | export * from './IFigureDataPalette'; 5 | export * from './IFigureDataPart'; 6 | export * from './IFigureDataSet'; 7 | export * from './IFigureDataSetType'; 8 | -------------------------------------------------------------------------------- /src/common/mapping/json/furnituredata/IFurnitureData.ts: -------------------------------------------------------------------------------- 1 | import { IFurnitureType } from './IFurnitureType'; 2 | 3 | export class IFurnitureData 4 | { 5 | roomitemtypes?: { 6 | furnitype: IFurnitureType[] 7 | }; 8 | wallitemtypes?: { 9 | furnitype: IFurnitureType[] 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/IAssetLogicPlanetSystem.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetLogicPlanetSystem 2 | { 3 | id?: number; 4 | name?: string; 5 | parent?: string; 6 | radius?: number; 7 | arcSpeed?: number; 8 | arcOffset?: number; 9 | blend?: number; 10 | height?: number; 11 | } 12 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/animation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetVisualAnimation'; 2 | export * from './IAssetVisualAnimationLayer'; 3 | export * from './IAssetVisualAnimationSequence'; 4 | export * from './IAssetVisualAnimationSequenceFrame'; 5 | export * from './IAssetVisualAnimationSequenceFrameOffset'; 6 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FigureDataColorXML'; 2 | export * from './FigureDataHiddenLayerXML'; 3 | export * from './FigureDataPaletteXML'; 4 | export * from './FigureDataPartXML'; 5 | export * from './FigureDataSetTypeXML'; 6 | export * from './FigureDataSetXML'; 7 | export * from './FigureDataXML'; 8 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ParticleSystemEmitterXML'; 2 | export * from './ParticleSystemObjectXML'; 3 | export * from './ParticleSystemParticleXML'; 4 | export * from './ParticleSystemSimulationXML'; 5 | export * from './ParticleSystemXML'; 6 | export * from './PlanetSystemObjectXML'; 7 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/index.ts: -------------------------------------------------------------------------------- 1 | export * from './animation'; 2 | export * from './color'; 3 | export * from './GestureXML'; 4 | export * from './LayerXML'; 5 | export * from './PostureXML'; 6 | export * from './VisualDirectionXML'; 7 | export * from './VisualizationDataXML'; 8 | export * from './VisualizationXML'; 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/IAssetPalette.ts: -------------------------------------------------------------------------------- 1 | export interface IAssetPalette 2 | { 3 | id?: number; 4 | source?: string; 5 | master?: boolean; 6 | tags?: string[]; 7 | breed?: number; 8 | colorTag?: number; 9 | color1?: string; 10 | color2?: string; 11 | rgb?: [ number, number, number ][]; 12 | } 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ActionXML'; 2 | export * from './CreditsXML'; 3 | export * from './CustomVarsXML'; 4 | export * from './LogicXML'; 5 | export * from './MaskXML'; 6 | export * from './model'; 7 | export * from './particlesystem'; 8 | export * from './PlanetSystemXML'; 9 | export * from './SoundSampleXML'; 10 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/model/ModelDirectionXML.ts: -------------------------------------------------------------------------------- 1 | export class ModelDirectionXML 2 | { 3 | private readonly _id: number; 4 | 5 | constructor(xml: any) 6 | { 7 | if(xml.id !== undefined) this._id = parseInt(xml.id); 8 | } 9 | 10 | public get id(): number 11 | { 12 | return this._id; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/particlesystem/IParticleSystem.ts: -------------------------------------------------------------------------------- 1 | import { IParticleSystemEmitter } from './IParticleSystemEmitter'; 2 | 3 | export interface IParticleSystem 4 | { 5 | size?: number; 6 | canvasId?: number; 7 | offsetY?: number; 8 | blend?: number; 9 | bgColor?: string; 10 | emitters?: IParticleSystemEmitter[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/animation/IAssetVisualAnimationSequence.ts: -------------------------------------------------------------------------------- 1 | import { IAssetVisualAnimationSequenceFrame } from './IAssetVisualAnimationSequenceFrame'; 2 | 3 | export interface IAssetVisualAnimationSequence 4 | { 5 | loopCount?: number; 6 | random?: number; 7 | frames?: { [index: string]: IAssetVisualAnimationSequenceFrame }; 8 | } 9 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureDataSetType.ts: -------------------------------------------------------------------------------- 1 | import { IFigureDataSet } from './IFigureDataSet'; 2 | 3 | export interface IFigureDataSetType 4 | { 5 | type?: string; 6 | paletteId?: number; 7 | mandatory_m_0?: boolean; 8 | mandatory_f_0?: boolean; 9 | mandatory_m_1?: boolean; 10 | mandatory_f_1?: boolean; 11 | sets?: IFigureDataSet[]; 12 | } 13 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/animation/IAssetVisualAnimationLayer.ts: -------------------------------------------------------------------------------- 1 | import { IAssetVisualAnimationSequence } from './IAssetVisualAnimationSequence'; 2 | 3 | export interface IAssetVisualAnimationLayer 4 | { 5 | loopCount?: number; 6 | frameRepeat?: number; 7 | random?: number; 8 | frameSequences?: { [index: string]: IAssetVisualAnimationSequence }; 9 | } 10 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationSprite.ts: -------------------------------------------------------------------------------- 1 | import { IAssetAnimationSpriteDirection } from './IAssetAnimationSpriteDirection'; 2 | 3 | export interface IAssetAnimationSprite 4 | { 5 | id?: string; 6 | member?: string; 7 | directions?: number; 8 | staticY?: number; 9 | ink?: number; 10 | directionList?: IAssetAnimationSpriteDirection[]; 11 | } 12 | -------------------------------------------------------------------------------- /src/swf/ReadSWF.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from 'fs/promises'; 2 | import { UncompressSWF } from './UncompressSWF'; 3 | 4 | export const ReadSWF = async (buffer: Buffer) => 5 | { 6 | if(Buffer.isBuffer(buffer)) return await UncompressSWF(buffer); 7 | 8 | buffer = await readFile(buffer); 9 | 10 | if(!buffer) return null; 11 | 12 | return await UncompressSWF(buffer); 13 | }; 14 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/animation/IAssetVisualAnimation.ts: -------------------------------------------------------------------------------- 1 | import { IAssetVisualAnimationLayer } from './IAssetVisualAnimationLayer'; 2 | 3 | export interface IAssetVisualAnimation 4 | { 5 | transitionTo?: number; 6 | transitionFrom?: number; 7 | immediateChangeFrom?: string; 8 | randomStart?: boolean; 9 | layers?: { [index: string]: IAssetVisualAnimationLayer }; 10 | } 11 | -------------------------------------------------------------------------------- /src/swf/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ISWF'; 2 | export * from './ISWFFileAttributes'; 3 | export * from './ISWFFileLength'; 4 | export * from './ISWFFrameSize'; 5 | export * from './ISWFTag'; 6 | export * from './ISWFTagAsset'; 7 | export * from './ISWFTagHeader'; 8 | export * from './ISWFTagLabel'; 9 | export * from './ISWFTagScene'; 10 | export * from './ISWFTagSplitter'; 11 | export * from './ISWFTagSymbol'; 12 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataHiddenLayerXML.ts: -------------------------------------------------------------------------------- 1 | export class FigureDataHiddenLayerXML 2 | { 3 | private _partType: string; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | this._partType = ((attributes && attributes.parttype) || ''); 10 | } 11 | 12 | public get partType(): string 13 | { 14 | return this._partType; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimationFramePart.ts: -------------------------------------------------------------------------------- 1 | import { IAssetAnimationFramePartItem } from './IAssetAnimationFramePartItem'; 2 | 3 | export interface IAssetAnimationFramePart 4 | { 5 | id?: string; 6 | frame?: number; 7 | base?: string; 8 | action?: string; 9 | dx?: number; 10 | dy?: number; 11 | dz?: number; 12 | dd?: number; 13 | items?: IAssetAnimationFramePartItem[]; 14 | } 15 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/animation/IAssetVisualAnimationSequenceFrame.ts: -------------------------------------------------------------------------------- 1 | import { IAssetVisualAnimationSequenceFrameOffset } from './IAssetVisualAnimationSequenceFrameOffset'; 2 | 3 | export interface IAssetVisualAnimationSequenceFrame 4 | { 5 | id?: number; 6 | x?: number; 7 | y?: number; 8 | randomX?: number; 9 | randomY?: number; 10 | offsets?: { [index: string]: IAssetVisualAnimationSequenceFrameOffset }; 11 | } 12 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/RemoveXML.ts: -------------------------------------------------------------------------------- 1 | export class RemoveXML 2 | { 3 | private readonly _id: string; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if(attributes !== undefined) 10 | { 11 | if(attributes.id !== undefined) this._id = attributes.id; 12 | } 13 | } 14 | 15 | public get id(): string 16 | { 17 | return this._id; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/ShadowXML.ts: -------------------------------------------------------------------------------- 1 | export class ShadowXML 2 | { 3 | private readonly _id: string; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if(attributes !== undefined) 10 | { 11 | if(attributes.id !== undefined) this._id = attributes.id; 12 | } 13 | } 14 | 15 | public get id(): string 16 | { 17 | return this._id; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/MaskXML.ts: -------------------------------------------------------------------------------- 1 | export class MaskXML 2 | { 3 | private readonly _type: string; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if(attributes !== undefined) 10 | { 11 | if(attributes.type !== undefined) this._type = attributes.type; 12 | } 13 | } 14 | 15 | public get type(): string 16 | { 17 | return this._type; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/CreditsXML.ts: -------------------------------------------------------------------------------- 1 | export class CreditsXML 2 | { 3 | private readonly _value: string; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if(attributes !== undefined) 10 | { 11 | if(attributes.value !== undefined) this._value = attributes.value; 12 | } 13 | } 14 | 15 | public get value(): string 16 | { 17 | return this._value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/manifest/ManifestLibraryAssetParamXML.ts: -------------------------------------------------------------------------------- 1 | export class ManifestLibraryAssetParamXML 2 | { 3 | private readonly _value: string; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if(attributes !== undefined) 10 | { 11 | this._value = attributes.value; 12 | } 13 | } 14 | 15 | public get value(): string 16 | { 17 | return this._value; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AddXML'; 2 | export * from './AvatarXML'; 3 | export * from './DirectionOffsetXML'; 4 | export * from './DirectionXML'; 5 | export * from './EffectAnimationXML'; 6 | export * from './EffectFramePartItemXML'; 7 | export * from './EffectFramePartXML'; 8 | export * from './EffectFrameXML'; 9 | export * from './OverrideXML'; 10 | export * from './RemoveXML'; 11 | export * from './ShadowXML'; 12 | export * from './SpriteXML'; 13 | -------------------------------------------------------------------------------- /src/common/mapping/json/figuredata/IFigureDataSet.ts: -------------------------------------------------------------------------------- 1 | import { IFigureDataHiddenLayer } from './IFigureDataHiddenLayer'; 2 | import { IFigureDataPart } from './IFigureDataPart'; 3 | 4 | export interface IFigureDataSet 5 | { 6 | id?: number; 7 | gender?: string; 8 | club?: number; 9 | colorable?: boolean; 10 | selectable?: boolean; 11 | preselectable?: boolean; 12 | sellable?: boolean; 13 | parts?: IFigureDataPart[]; 14 | hiddenLayers?: IFigureDataHiddenLayer[]; 15 | } 16 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/DirectionOffsetXML.ts: -------------------------------------------------------------------------------- 1 | export class DirectionOffsetXML 2 | { 3 | private readonly _offset: number; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if(attributes !== undefined) 10 | { 11 | if(attributes.offset !== undefined) this._offset = parseInt(attributes.offset); 12 | } 13 | } 14 | 15 | public get offset(): number 16 | { 17 | return this._offset; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/manifest/ManifestXML.ts: -------------------------------------------------------------------------------- 1 | import { ManifestLibraryXML } from './ManifestLibraryXML'; 2 | 3 | export class ManifestXML 4 | { 5 | private readonly _library: ManifestLibraryXML; 6 | 7 | constructor(xml: any) 8 | { 9 | if(xml.library !== undefined) 10 | { 11 | if(xml.library[0] !== undefined) this._library = new ManifestLibraryXML(xml.library[0]); 12 | } 13 | } 14 | 15 | public get library(): ManifestLibraryXML 16 | { 17 | return this._library; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/particlesystem/IParticleSystemEmitter.ts: -------------------------------------------------------------------------------- 1 | import { IParticleSystemParticle } from './IParticleSystemParticle'; 2 | import { IParticleSystemSimulation } from './IParticleSystemSimulation'; 3 | 4 | export interface IParticleSystemEmitter 5 | { 6 | id?: number; 7 | name?: string; 8 | spriteId?: number; 9 | maxNumParticles?: number; 10 | particlesPerFrame?: number; 11 | burstPulse?: number; 12 | fuseTime?: number; 13 | simulation?: IParticleSystemSimulation; 14 | particles?: IParticleSystemParticle[]; 15 | } 16 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/spritesheet/ISpritesheetFrame.ts: -------------------------------------------------------------------------------- 1 | export interface ISpritesheetFrame 2 | { 3 | frame: { 4 | x: number; 5 | y: number; 6 | w: number; 7 | h: number; 8 | }; 9 | rotated: boolean; 10 | trimmed: boolean; 11 | spriteSourceSize: { 12 | x: number; 13 | y: number; 14 | w: number; 15 | h: number; 16 | }; 17 | sourceSize: { 18 | w: number; 19 | h: number; 20 | }; 21 | pivot: { 22 | x: number; 23 | y: number; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/index.ts: -------------------------------------------------------------------------------- 1 | export * from './IAssetAnimation'; 2 | export * from './IAssetAnimationAdd'; 3 | export * from './IAssetAnimationAvatar'; 4 | export * from './IAssetAnimationDirection'; 5 | export * from './IAssetAnimationFrame'; 6 | export * from './IAssetAnimationFramePart'; 7 | export * from './IAssetAnimationFramePartItem'; 8 | export * from './IAssetAnimationOverride'; 9 | export * from './IAssetAnimationRemove'; 10 | export * from './IAssetAnimationShadow'; 11 | export * from './IAssetAnimationSprite'; 12 | export * from './IAssetAnimationSpriteDirection'; 13 | -------------------------------------------------------------------------------- /src/swf/common/ISWF.ts: -------------------------------------------------------------------------------- 1 | import { ISWFFileAttributes } from './ISWFFileAttributes'; 2 | import { ISWFFileLength } from './ISWFFileLength'; 3 | import { ISWFFrameSize } from './ISWFFrameSize'; 4 | import { ISWFTag } from './ISWFTag'; 5 | 6 | export interface ISWF 7 | { 8 | version?: number; 9 | fileLength?: ISWFFileLength; 10 | frameSize?: ISWFFrameSize; 11 | frameRate?: number; 12 | frameCount?: number; 13 | backgroundColor?: string; 14 | fileAttributes?: Partial; 15 | metadata?: string; 16 | protect?: string; 17 | tags?: Partial[]; 18 | } 19 | -------------------------------------------------------------------------------- /src/common/bundle/ImageBundle.ts: -------------------------------------------------------------------------------- 1 | export class ImageBundle 2 | { 3 | private _images: { path: string, contents: Buffer }[] = []; 4 | 5 | public dispose(): void 6 | { 7 | this._images = null; 8 | } 9 | 10 | public addImage(path: string, contents: Buffer): void 11 | { 12 | if(!path || !contents) return; 13 | 14 | for(const image of this._images) if(image.path === path) return; 15 | 16 | this._images.push({ path, contents }); 17 | } 18 | 19 | public get images(): { path: string, contents: Buffer }[] 20 | { 21 | return this._images; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/swf/tags/CharacterTag.ts: -------------------------------------------------------------------------------- 1 | export abstract class CharacterTag 2 | { 3 | private _className: string = ''; 4 | 5 | constructor( 6 | protected _characterId: number = 1 7 | ) 8 | {} 9 | 10 | public get className(): string 11 | { 12 | return this._className; 13 | } 14 | 15 | public set className(value: string) 16 | { 17 | this._className = value; 18 | } 19 | 20 | public get characterId(): number 21 | { 22 | return this._characterId; 23 | } 24 | 25 | public set characterId(value: number) 26 | { 27 | this._characterId = value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/PlanetSystemXML.ts: -------------------------------------------------------------------------------- 1 | import { PlanetSystemObjectXML } from './particlesystem/PlanetSystemObjectXML'; 2 | 3 | export class PlanetSystemXML 4 | { 5 | private readonly _objects: PlanetSystemObjectXML[]; 6 | 7 | constructor(xml: any) 8 | { 9 | if((xml.object !== undefined) && Array.isArray(xml.object)) 10 | { 11 | this._objects = []; 12 | 13 | for(const object of xml.object) this._objects.push(new PlanetSystemObjectXML(object)); 14 | } 15 | } 16 | 17 | public get objects(): PlanetSystemObjectXML[] 18 | { 19 | return this._objects; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuremap/FigureLibraryPartXML.ts: -------------------------------------------------------------------------------- 1 | export class FigureLibraryPartXML 2 | { 3 | private _id: number; 4 | private _type: string; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes) 11 | { 12 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 13 | if(attributes.type !== undefined) this._type = attributes.type; 14 | } 15 | } 16 | 17 | public get id(): number 18 | { 19 | return this._id; 20 | } 21 | 22 | public get type(): string 23 | { 24 | return this._type; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/common/mapping/xml/effectmap/EffectMapXML.ts: -------------------------------------------------------------------------------- 1 | import { EffectMapEffectXML } from './EffectMapEffectXML'; 2 | 3 | export class EffectMapXML 4 | { 5 | private _effect: EffectMapEffectXML[]; 6 | 7 | constructor(xml: any) 8 | { 9 | if(xml.effect !== undefined) 10 | { 11 | if(Array.isArray(xml.effect)) 12 | { 13 | this._effect = []; 14 | 15 | for(const library of xml.effect) this._effect.push(new EffectMapEffectXML(library)); 16 | } 17 | } 18 | } 19 | 20 | public get effects(): EffectMapEffectXML[] 21 | { 22 | return this._effect; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/swf/RecognizeImageHeader.ts: -------------------------------------------------------------------------------- 1 | const pngMagic = Buffer.from('0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A'.split(' ').map(Number)); 2 | const gifMagic = Buffer.from('0x47 0x49 0x46 0x38 0x39 0x61'.split(' ').map(Number)); 3 | const jpegMagic = Buffer.from('0xFF 0xD8'.split(' ').map(Number)); 4 | 5 | export const RecognizeImageHeader = (buffer: Buffer) => 6 | { 7 | if(pngMagic.equals(buffer.slice(0, pngMagic.length))) return 'png'; 8 | if(gifMagic.equals(buffer.slice(0, gifMagic.length))) return 'gif'; 9 | if(jpegMagic.equals(buffer.slice(0, jpegMagic.length))) return 'jpeg'; 10 | 11 | console.error('Unknown format:', buffer.slice(0, 8)); 12 | 13 | return null; 14 | }; 15 | -------------------------------------------------------------------------------- /src/swf/index.ts: -------------------------------------------------------------------------------- 1 | export * from './common'; 2 | export * from './ConcatSWFHeader'; 3 | export * from './GenerateNitroBundleFromSwf'; 4 | export * from './GenerateSpritesheet'; 5 | export * from './HabboAssetSWF'; 6 | export * from './PackImages'; 7 | export * from './ReadImagesDefineBitsLossless'; 8 | export * from './ReadImagesJPEG3or4'; 9 | export * from './ReadSWF'; 10 | export * from './ReadSWFBuffer'; 11 | export * from './ReadSWFTags'; 12 | export * from './RecognizeImageHeader'; 13 | export * from './SWFBuffer'; 14 | export * from './SWFDownloader'; 15 | export * from './SWFTags'; 16 | export * from './SWFUtilities'; 17 | export * from './tags'; 18 | export * from './UncompressSWF'; 19 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/EffectFramePartItemXML.ts: -------------------------------------------------------------------------------- 1 | export class EffectFramePartItemXML 2 | { 3 | private readonly _id: string; 4 | private readonly _base: string; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes !== undefined) 11 | { 12 | if(attributes.id !== undefined) this._id = attributes.id; 13 | if(attributes.base !== undefined) this._base = attributes.base; 14 | } 15 | } 16 | 17 | public get id(): string 18 | { 19 | return this._id; 20 | } 21 | 22 | public get base(): string 23 | { 24 | return this._base; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/ParticleSystemXML.ts: -------------------------------------------------------------------------------- 1 | import { ParticleSystemObjectXML } from './ParticleSystemObjectXML'; 2 | 3 | export class ParticleSystemXML 4 | { 5 | private readonly _objects: ParticleSystemObjectXML[]; 6 | 7 | constructor(xml: any) 8 | { 9 | if((xml.particlesystem !== undefined) && Array.isArray(xml.particlesystem)) 10 | { 11 | this._objects = []; 12 | 13 | for(const object of xml.particlesystem) this._objects.push(new ParticleSystemObjectXML(object)); 14 | } 15 | } 16 | 17 | public get objects(): ParticleSystemObjectXML[] 18 | { 19 | return this._objects; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/swf/GenerateNitroBundleFromSwf.ts: -------------------------------------------------------------------------------- 1 | import { GenerateSpriteSheet } from './GenerateSpritesheet'; 2 | import { HabboAssetSWF } from './HabboAssetSWF'; 3 | import { SWFUtilities } from './SWFUtilities'; 4 | 5 | export const GenerateNitroBundleFromSwf = async (habboAssetSWF: HabboAssetSWF, assetType: string = null) => 6 | { 7 | if(!habboAssetSWF) return null; 8 | 9 | const spriteBundle = await GenerateSpriteSheet(habboAssetSWF); 10 | const assetData = await SWFUtilities.mapXML2JSON(habboAssetSWF, assetType); 11 | 12 | if(assetData) assetData.name = habboAssetSWF.getDocumentClass(); 13 | 14 | return SWFUtilities.createNitroBundle(assetData.name, assetData, spriteBundle); 15 | }; 16 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/color/ColorLayerXML.ts: -------------------------------------------------------------------------------- 1 | export class ColorLayerXML 2 | { 3 | private readonly _id: number; 4 | private readonly _color: string; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes !== undefined) 11 | { 12 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 13 | if(attributes.color !== undefined) this._color = attributes.color; 14 | } 15 | } 16 | 17 | public get id(): number 18 | { 19 | return this._id; 20 | } 21 | 22 | public get color(): string 23 | { 24 | return this._color; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/SoundSampleXML.ts: -------------------------------------------------------------------------------- 1 | export class SoundSampleXML 2 | { 3 | private readonly _id: number; 4 | private readonly _noPitch: boolean; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes !== undefined) 11 | { 12 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 13 | if(attributes.nopitch !== undefined) this._noPitch = attributes.nopitch === 'true'; 14 | } 15 | } 16 | 17 | public get id(): number 18 | { 19 | return this._id; 20 | } 21 | 22 | get noPitch(): boolean 23 | { 24 | return this._noPitch; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/logic/IAssetLogicData.ts: -------------------------------------------------------------------------------- 1 | import { ICustomVars } from './IAssetLogicCustomVars'; 2 | import { IAssetLogicPlanetSystem } from './IAssetLogicPlanetSystem'; 3 | import { ISoundSample } from './ISoundSample'; 4 | import { IAssetLogicModel } from './model/IAssetLogicModel'; 5 | import { IParticleSystem } from './particlesystem'; 6 | 7 | export interface IAssetLogicData 8 | { 9 | model?: IAssetLogicModel; 10 | maskType?: string; 11 | credits?: string; 12 | soundSample?: ISoundSample; 13 | action?: { link?: string, startState?: number }; 14 | planetSystems?: IAssetLogicPlanetSystem[]; 15 | particleSystems?: IParticleSystem[]; 16 | customVars?: ICustomVars; 17 | } 18 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/ActionXML.ts: -------------------------------------------------------------------------------- 1 | export class ActionXML 2 | { 3 | private readonly _link: string; 4 | private readonly _startState: number; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes !== undefined) 11 | { 12 | if(attributes.link !== undefined) this._link = attributes.link; 13 | if(attributes.startState !== undefined) this._startState = parseInt(attributes.startState); 14 | } 15 | } 16 | 17 | public get link(): string 18 | { 19 | return this._link; 20 | } 21 | 22 | public get startState(): number 23 | { 24 | return this._startState; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules\\typescript\\lib", 3 | "typescript.preferences.importModuleSpecifier": "relative", 4 | "typescript.preferences.quoteStyle": "single", 5 | "typescript.format.placeOpenBraceOnNewLineForControlBlocks": true, 6 | "typescript.format.placeOpenBraceOnNewLineForFunctions": true, 7 | "editor.codeActionsOnSave": { 8 | "source.fixAll": true, 9 | "source.fixAll.sortJSON": false, 10 | "source.organizeImports": true, 11 | }, 12 | "emmet.showExpandedAbbreviation": "never", 13 | "git.ignoreLimitWarning": true, 14 | "files.eol": "\n", 15 | "files.insertFinalNewline": true, 16 | "files.trimFinalNewlines": true 17 | } 18 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/GestureXML.ts: -------------------------------------------------------------------------------- 1 | export class GestureXML 2 | { 3 | private readonly _id: string; 4 | private readonly _animationId: number; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes !== undefined) 11 | { 12 | if(attributes.id !== undefined) this._id = attributes.id; 13 | if(attributes.animationId !== undefined) this._animationId = parseInt(attributes.animationId); 14 | } 15 | } 16 | 17 | public get id(): string 18 | { 19 | return this._id; 20 | } 21 | 22 | public get animationId(): number 23 | { 24 | return this._animationId; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/PostureXML.ts: -------------------------------------------------------------------------------- 1 | export class PostureXML 2 | { 3 | private readonly _id: string; 4 | private readonly _animationId: number; 5 | 6 | constructor(xml: any) 7 | { 8 | const attributes = xml.$; 9 | 10 | if(attributes !== undefined) 11 | { 12 | if(attributes.id !== undefined) this._id = attributes.id; 13 | if(attributes.animationId !== undefined) this._animationId = parseInt(attributes.animationId); 14 | } 15 | } 16 | 17 | public get id(): string 18 | { 19 | return this._id; 20 | } 21 | 22 | public get animationId(): number 23 | { 24 | return this._animationId; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/common/bundle/SpriteBundle.ts: -------------------------------------------------------------------------------- 1 | import { ISpritesheetData } from '../mapping'; 2 | 3 | export class SpriteBundle 4 | { 5 | private _spritesheet: ISpritesheetData; 6 | private _imageData: { name: string, buffer: Buffer }; 7 | 8 | public get spritesheet(): ISpritesheetData 9 | { 10 | return this._spritesheet; 11 | } 12 | 13 | public set spritesheet(spritesheet: ISpritesheetData) 14 | { 15 | this._spritesheet = spritesheet; 16 | } 17 | 18 | public get imageData(): { name: string, buffer: Buffer} 19 | { 20 | return this._imageData; 21 | } 22 | 23 | public set imageData(imageData: { name: string, buffer: Buffer }) 24 | { 25 | this._imageData = imageData; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuremap/FigureMapXML.ts: -------------------------------------------------------------------------------- 1 | import { FigureLibraryXML } from './FigureLibraryXML'; 2 | 3 | export class FigureMapXML 4 | { 5 | private _librares: FigureLibraryXML[]; 6 | 7 | constructor(xml: any) 8 | { 9 | if(xml.lib !== undefined) 10 | { 11 | if(Array.isArray(xml.lib)) 12 | { 13 | this._librares = []; 14 | 15 | for(const lib in xml.lib) 16 | { 17 | const library = xml.lib[lib]; 18 | 19 | this._librares.push(new FigureLibraryXML(library)); 20 | } 21 | } 22 | } 23 | } 24 | 25 | public get libraries(): FigureLibraryXML[] 26 | { 27 | return this._librares; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/common/mapping/json/furnituredata/IFurnitureType.ts: -------------------------------------------------------------------------------- 1 | export interface IFurnitureType 2 | { 3 | id?: number; 4 | classname?: string; 5 | revision?: number; 6 | category?: string; 7 | defaultdir?: number; 8 | xdim?: number; 9 | ydim?: number; 10 | partcolors?: { color: string[] }; 11 | name?: string; 12 | description?: string; 13 | adurl?: string; 14 | offerid?: number; 15 | buyout?: boolean; 16 | rentofferid?: number; 17 | rentbuyout?: boolean; 18 | bc?: boolean; 19 | excludeddynamic?: boolean; 20 | customparams?: string; 21 | specialtype?: number; 22 | canstandon?: boolean; 23 | cansiton?: boolean; 24 | canlayon?: boolean; 25 | furniline?: string; 26 | environment?: string; 27 | rare?: boolean; 28 | } 29 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "declaration": false, 5 | "noImplicitAny": false, 6 | "noUnusedLocals": false, 7 | "removeComments": true, 8 | "noLib": false, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "resolveJsonModule": true, 12 | "target": "es6", 13 | "sourceMap": false, 14 | "allowJs": true, 15 | "esModuleInterop": true, 16 | "baseUrl": "./src", 17 | "outDir": "./dist" 18 | }, 19 | "include": [ 20 | "src/**/*", 21 | "node_modules/wrappy/swf" 22 | ], 23 | "exclude": [ 24 | "node_modules", 25 | "dist", 26 | "src/configuration.json" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/CustomVarsXML.ts: -------------------------------------------------------------------------------- 1 | export class CustomVarsXML 2 | { 3 | private readonly _variables: string[]; 4 | 5 | constructor(xml: any) 6 | { 7 | const attributes = xml.$; 8 | 9 | if((xml.variable !== undefined) && Array.isArray(xml.variable)) 10 | { 11 | this._variables = []; 12 | 13 | for(const variable of xml.variable) 14 | { 15 | const attributes = variable.$; 16 | 17 | if(attributes !== undefined) 18 | { 19 | if(attributes.name !== undefined) this._variables.push(attributes.name); 20 | } 21 | } 22 | } 23 | } 24 | 25 | public get variables(): string[] 26 | { 27 | return this._variables; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/swf/tags/SymbolClassTag.ts: -------------------------------------------------------------------------------- 1 | import { ISymbolClass } from './ISymbolClass'; 2 | import { ITag } from './ITag'; 3 | 4 | export class SymbolClassTag implements ITag 5 | { 6 | private readonly _tags: number[]; 7 | private readonly _names: string[]; 8 | 9 | constructor(tags: ISymbolClass[]) 10 | { 11 | this._tags = []; 12 | this._names = []; 13 | 14 | for(const symbolClass of tags) 15 | { 16 | this._tags.push(symbolClass.id); 17 | this._names.push(symbolClass.name); 18 | } 19 | } 20 | 21 | public get tags(): number[] 22 | { 23 | return this._tags; 24 | } 25 | 26 | public get names(): string[] 27 | { 28 | return this._names; 29 | } 30 | 31 | public get code(): number 32 | { 33 | return 76; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/asset/IndexMapper.ts: -------------------------------------------------------------------------------- 1 | import { IAssetData } from '../../json'; 2 | import { IndexXML } from '../../xml'; 3 | import { Mapper } from './Mapper'; 4 | 5 | export class IndexMapper extends Mapper 6 | { 7 | public static mapXML(index: any, output: IAssetData): void 8 | { 9 | if(!index || !output) return; 10 | 11 | IndexMapper.mapIndexXML(new IndexXML(index.object), output); 12 | } 13 | 14 | private static mapIndexXML(indexXML: IndexXML, output: IAssetData): void 15 | { 16 | if(!indexXML || !output) return; 17 | 18 | if(indexXML.type !== undefined) output.name = indexXML.type; 19 | if(indexXML.logic !== undefined) output.logicType = indexXML.logic; 20 | if(indexXML.visualization !== undefined) output.visualizationType = indexXML.visualization; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/IAssetData.ts: -------------------------------------------------------------------------------- 1 | import { IAssetAnimation } from './animation'; 2 | import { IAsset } from './IAsset'; 3 | import { IAssetAlias } from './IAssetAlias'; 4 | import { IAssetPalette } from './IAssetPalette'; 5 | import { IAssetLogicData } from './logic/IAssetLogicData'; 6 | import { ISpritesheetData } from './spritesheet'; 7 | import { IAssetVisualizationData } from './visualization'; 8 | 9 | export interface IAssetData { 10 | type?: string; 11 | name?: string; 12 | visualizationType?: string; 13 | logicType?: string; 14 | spritesheet?: ISpritesheetData; 15 | logic?: IAssetLogicData; 16 | assets?: { [index: string]: IAsset }; 17 | aliases?: { [index: string]: IAssetAlias }; 18 | animations?: { [index: string]: IAssetAnimation }; 19 | palettes?: { [index: string]: IAssetPalette }; 20 | visualizations?: IAssetVisualizationData[]; 21 | } 22 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/VisualDirectionXML.ts: -------------------------------------------------------------------------------- 1 | import { LayerXML } from './LayerXML'; 2 | 3 | export class VisualDirectionXML 4 | { 5 | private readonly _id: number; 6 | private readonly _layers: LayerXML[]; 7 | 8 | constructor(xml: any) 9 | { 10 | const attributes = xml.$; 11 | 12 | if(attributes !== undefined) 13 | { 14 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 15 | } 16 | 17 | if((xml.layer !== undefined) && Array.isArray(xml.layer)) 18 | { 19 | this._layers = []; 20 | 21 | for(const layer of xml.layer) this._layers.push(new LayerXML(layer)); 22 | } 23 | } 24 | 25 | public get id(): number 26 | { 27 | return this._id; 28 | } 29 | 30 | public get layers(): LayerXML[] 31 | { 32 | return this._layers; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/IndexXML.ts: -------------------------------------------------------------------------------- 1 | export class IndexXML 2 | { 3 | private readonly _type: string; 4 | private readonly _visualization: string; 5 | private readonly _logic: string; 6 | 7 | constructor(xml: any) 8 | { 9 | const attributes = xml.$; 10 | 11 | if(attributes !== undefined) 12 | { 13 | if(attributes.type !== undefined) this._type = attributes.type; 14 | if(attributes.visualization !== undefined) this._visualization = attributes.visualization; 15 | if(attributes.logic !== undefined) this._logic = attributes.logic; 16 | } 17 | } 18 | 19 | public get type(): string 20 | { 21 | return this._type; 22 | } 23 | 24 | public get visualization(): string 25 | { 26 | return this._visualization; 27 | } 28 | 29 | public get logic(): string 30 | { 31 | return this._logic; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/animation/FrameOffsetXML.ts: -------------------------------------------------------------------------------- 1 | export class FrameOffsetXML 2 | { 3 | private readonly _direction: number; 4 | private readonly _x: number; 5 | private readonly _y: number; 6 | 7 | constructor(xml: any) 8 | { 9 | const attributes = xml.$; 10 | 11 | if(attributes !== undefined) 12 | { 13 | if(attributes.direction !== undefined) this._direction = parseInt(attributes.direction); 14 | if(attributes.x !== undefined) this._x = parseInt(attributes.x); 15 | if(attributes.y !== undefined) this._y = parseInt(attributes.y); 16 | } 17 | } 18 | 19 | public get direction(): number 20 | { 21 | return this._direction; 22 | } 23 | 24 | public get x(): number 25 | { 26 | return this._x; 27 | } 28 | 29 | public get y(): number 30 | { 31 | return this._y; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/color/ColorXML.ts: -------------------------------------------------------------------------------- 1 | import { ColorLayerXML } from './ColorLayerXML'; 2 | 3 | export class ColorXML 4 | { 5 | private readonly _id: number; 6 | private readonly _layers: ColorLayerXML[]; 7 | 8 | constructor(xml: any) 9 | { 10 | const attributes = xml.$; 11 | 12 | if(attributes !== undefined) 13 | { 14 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 15 | } 16 | 17 | if((xml.colorLayer !== undefined) && Array.isArray(xml.colorLayer)) 18 | { 19 | this._layers = []; 20 | 21 | for(const colorLayer of xml.colorLayer) this._layers.push(new ColorLayerXML(colorLayer)); 22 | } 23 | } 24 | 25 | public get id(): number 26 | { 27 | return this._id; 28 | } 29 | 30 | public get layers(): ColorLayerXML[] 31 | { 32 | return this._layers; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/swf/ReadSWFBuffer.ts: -------------------------------------------------------------------------------- 1 | import { ISWF } from './common'; 2 | import { readSWFTags } from './ReadSWFTags'; 3 | import { SWFBuffer } from './SWFBuffer'; 4 | 5 | export const ReadSWFBuff = (swfBuffer: SWFBuffer, rawBuffer: Buffer) => 6 | { 7 | if(!swfBuffer || !rawBuffer) return null; 8 | 9 | swfBuffer.seek(3); 10 | 11 | if(swfBuffer.length < 9) 12 | { 13 | console.error('Buffer is to small, must be greater than 9 bytes.'); 14 | 15 | return null; 16 | } 17 | 18 | const swf: ISWF = { 19 | version: swfBuffer.readUInt8(), 20 | fileLength: { 21 | compressed: rawBuffer.length, 22 | uncompressed: swfBuffer.readUIntLE(32) 23 | }, 24 | frameSize: swfBuffer.readRect(), 25 | frameRate: (swfBuffer.readUIntLE(16) / 256), 26 | frameCount: swfBuffer.readUIntLE(16), 27 | }; 28 | 29 | swf.tags = readSWFTags(swfBuffer, swf); 30 | 31 | return swf; 32 | }; 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events*.json 15 | speed-measure-plugin*.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | .git 44 | *.log 45 | 46 | # System Files 47 | .DS_Store 48 | Thumbs.db 49 | 50 | *.zip 51 | *.as 52 | *.bin 53 | .env 54 | /assets 55 | 56 | # Nitro 57 | configuration.json 58 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/AvatarXML.ts: -------------------------------------------------------------------------------- 1 | export class AvatarXML 2 | { 3 | private readonly _ink: number; 4 | private readonly _foreground: string; 5 | private readonly _background: string; 6 | 7 | constructor(xml: any) 8 | { 9 | const attributes = xml.$; 10 | 11 | if(attributes !== undefined) 12 | { 13 | if(attributes.ink !== undefined) this._ink = parseInt(attributes.ink); 14 | if(attributes.foreground !== undefined) this._foreground = attributes.foreground; 15 | if(attributes.background !== undefined) this._background = attributes.background; 16 | } 17 | } 18 | 19 | public get ink(): number 20 | { 21 | return this._ink; 22 | } 23 | 24 | public get foreground(): string 25 | { 26 | return this._foreground; 27 | } 28 | 29 | public get background(): string 30 | { 31 | return this._background; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/swf/tags/ImageTag.ts: -------------------------------------------------------------------------------- 1 | import { CharacterTag } from './CharacterTag'; 2 | import { ITag } from './ITag'; 3 | 4 | export class ImageTag extends CharacterTag implements ITag 5 | { 6 | constructor( 7 | protected _characterId: number, 8 | private _code: number, 9 | private _imgType: string, 10 | private _imgData: Buffer, 11 | private _imgWidth: number = 0, 12 | private _imgHeight: number = 0 13 | ) 14 | { 15 | super(_characterId); 16 | } 17 | 18 | public get code(): number 19 | { 20 | return this._code; 21 | } 22 | 23 | public get imgType(): string 24 | { 25 | return this._imgType; 26 | } 27 | 28 | public get imgData(): Buffer 29 | { 30 | return this._imgData; 31 | } 32 | 33 | public get imgWidth(): number 34 | { 35 | return this._imgWidth; 36 | } 37 | 38 | public get imgHeight(): number 39 | { 40 | return this._imgHeight; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/visualization/IAssetVisualizationData.ts: -------------------------------------------------------------------------------- 1 | import { IAssetVisualAnimation } from './animation/IAssetVisualAnimation'; 2 | import { IAssetColor } from './color/IAssetColor'; 3 | import { IAssetGesture } from './gestures/IAssetGesture'; 4 | import { IAssetVisualizationDirection } from './IAssetVisualizationDirection'; 5 | import { IAssetVisualizationLayer } from './IAssetVisualizationLayer'; 6 | import { IAssetPosture } from './postures/IAssetPosture'; 7 | 8 | export interface IAssetVisualizationData 9 | { 10 | size?: number; 11 | layerCount?: number; 12 | angle?: number; 13 | layers?: { [index: string]: IAssetVisualizationLayer }; 14 | colors?: { [index: string]: IAssetColor }; 15 | directions?: { [index: string]: IAssetVisualizationDirection }; 16 | animations?: { [index: string]: IAssetVisualAnimation }; 17 | defaultPosture?: string; 18 | postures?: { defaultPosture?: string, postures?: IAssetPosture[] }; 19 | gestures?: IAssetGesture[]; 20 | } 21 | -------------------------------------------------------------------------------- /configuration.json.example: -------------------------------------------------------------------------------- 1 | { 2 | "flash.client.url": "", 3 | "furnidata.load.url": "", 4 | "productdata.load.url": "", 5 | "figuredata.load.url": "https://www.habbo.com/gamedata/figuredata/1", 6 | "figuremap.load.url": "${flash.client.url}figuremap.xml", 7 | "effectmap.load.url": "${flash.client.url}effectmap.xml", 8 | "dynamic.download.pet.url": "${flash.client.url}%className%.swf", 9 | "dynamic.download.figure.url": "${flash.client.url}%className%.swf", 10 | "dynamic.download.effect.url": "${flash.client.url}%className%.swf", 11 | "flash.dynamic.download.url": "", 12 | "dynamic.download.furniture.url": "${flash.dynamic.download.url}%revision%/%className%.swf", 13 | "external.variables.url": "https://www.habbo.com/gamedata/external_variables/1", 14 | "external.texts.url": "${external.texts.txt}", 15 | "convert.figure": "1", 16 | "convert.effect": "1", 17 | "convert.furniture": "1", 18 | "convert.furniture.floor.only": "0", 19 | "convert.furniture.wall.only": "0", 20 | "convert.pet": "1" 21 | } 22 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataPaletteXML.ts: -------------------------------------------------------------------------------- 1 | import { FigureDataColorXML } from './FigureDataColorXML'; 2 | 3 | export class FigureDataPaletteXML 4 | { 5 | private _id: number; 6 | private _colors: FigureDataColorXML[]; 7 | 8 | constructor(xml: any) 9 | { 10 | if(xml.color !== undefined) 11 | { 12 | if(Array.isArray(xml.color)) 13 | { 14 | this._colors = []; 15 | 16 | for(const col in xml.color) 17 | { 18 | const color = xml.color[col]; 19 | 20 | this._colors.push(new FigureDataColorXML(color)); 21 | } 22 | } 23 | } 24 | 25 | const attributes = xml.$; 26 | 27 | this._id = ((attributes && parseInt(attributes.id)) || 0); 28 | } 29 | 30 | public get id(): number 31 | { 32 | return this._id; 33 | } 34 | 35 | public get colors(): FigureDataColorXML[] 36 | { 37 | return this._colors; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/manifest/ManifestLibraryAssetXML.ts: -------------------------------------------------------------------------------- 1 | import { ManifestLibraryAssetParamXML } from './ManifestLibraryAssetParamXML'; 2 | 3 | export class ManifestLibraryAssetXML 4 | { 5 | private readonly _name: string; 6 | private readonly _mimeType: string; 7 | private readonly _param: ManifestLibraryAssetParamXML; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | if(attributes !== undefined) 14 | { 15 | if(attributes.name !== undefined) this._name = attributes.name; 16 | if(attributes.mimeType !== undefined) this._mimeType = attributes.mimeType; 17 | } 18 | 19 | if(xml.param !== undefined) 20 | { 21 | if(xml.param[0] !== undefined) this._param = new ManifestLibraryAssetParamXML(xml.param[0]); 22 | } 23 | } 24 | 25 | public get name(): string 26 | { 27 | return this._name; 28 | } 29 | 30 | public get param(): ManifestLibraryAssetParamXML 31 | { 32 | return this._param; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/common/mapping/json/asset/animation/IAssetAnimation.ts: -------------------------------------------------------------------------------- 1 | import { IAssetAnimationAdd } from './IAssetAnimationAdd'; 2 | import { IAssetAnimationAvatar } from './IAssetAnimationAvatar'; 3 | import { IAssetAnimationDirection } from './IAssetAnimationDirection'; 4 | import { IAssetAnimationFrame } from './IAssetAnimationFrame'; 5 | import { IAssetAnimationOverride } from './IAssetAnimationOverride'; 6 | import { IAssetAnimationRemove } from './IAssetAnimationRemove'; 7 | import { IAssetAnimationShadow } from './IAssetAnimationShadow'; 8 | import { IAssetAnimationSprite } from './IAssetAnimationSprite'; 9 | 10 | export interface IAssetAnimation 11 | { 12 | name?: string; 13 | desc?: string; 14 | resetOnToggle?: boolean; 15 | directions?: IAssetAnimationDirection[]; 16 | shadows?: IAssetAnimationShadow[]; 17 | adds?: IAssetAnimationAdd[]; 18 | removes?: IAssetAnimationRemove[]; 19 | sprites?: IAssetAnimationSprite[]; 20 | frames?: IAssetAnimationFrame[]; 21 | avatars?: IAssetAnimationAvatar[]; 22 | overrides?: IAssetAnimationOverride[]; 23 | } 24 | -------------------------------------------------------------------------------- /src/common/mapping/xml/effectmap/EffectMapEffectXML.ts: -------------------------------------------------------------------------------- 1 | 2 | export class EffectMapEffectXML 3 | { 4 | private _id: string; 5 | private _lib: string; 6 | private _type: string; 7 | private _revision: number; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | if(attributes) 14 | { 15 | if(attributes.id !== undefined) this._id = attributes.id; 16 | if(attributes.lib !== undefined) this._lib = attributes.lib; 17 | if(attributes.type !== undefined) this._type = attributes.type; 18 | if(attributes.revision !== undefined) this._revision = parseInt(attributes.revision); 19 | } 20 | } 21 | 22 | public get id(): string 23 | { 24 | return this._id; 25 | } 26 | 27 | public get lib(): string 28 | { 29 | return this._lib; 30 | } 31 | 32 | public get type(): string 33 | { 34 | return this._type; 35 | } 36 | 37 | public get revision(): number 38 | { 39 | return this._revision; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/DirectionXML.ts: -------------------------------------------------------------------------------- 1 | export class DirectionXML 2 | { 3 | private readonly _id: number; 4 | private readonly _dx: number; 5 | private readonly _dy: number; 6 | private readonly _dz: number; 7 | 8 | constructor(xml: any) 9 | { 10 | const attributes = xml.$; 11 | 12 | if(attributes !== undefined) 13 | { 14 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 15 | if(attributes.dx !== undefined) this._dx = parseInt(attributes.dx); 16 | if(attributes.dy !== undefined) this._dy = parseInt(attributes.dy); 17 | if(attributes.dz !== undefined) this._dz = parseInt(attributes.dz); 18 | } 19 | } 20 | 21 | public get id(): number 22 | { 23 | return this._id; 24 | } 25 | 26 | public get dx(): number 27 | { 28 | return this._dx; 29 | } 30 | 31 | public get dy(): number 32 | { 33 | return this._dy; 34 | } 35 | 36 | public get dz(): number 37 | { 38 | return this._dz; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/common/utils/SlicedToArray.ts: -------------------------------------------------------------------------------- 1 | export class SlicedToArray 2 | { 3 | public static slicedToArray(arr: any, i: any): any[] 4 | { 5 | if(Array.isArray(arr)) return arr; 6 | 7 | if(Symbol.iterator in Object(arr)) return this.sliceIterator(arr, i); 8 | 9 | throw new TypeError('Invalid attempt to destructure non-iterable instance'); 10 | } 11 | 12 | private static sliceIterator(arr: any, i: any): any[] 13 | { 14 | const _arr = []; 15 | 16 | let _i = null; 17 | let _s = null; 18 | let _n = true; 19 | 20 | try 21 | { 22 | for(_i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) 23 | { 24 | _arr.push(_s.value); 25 | 26 | if(i && _arr.length === i) break; 27 | } 28 | 29 | if(!_n && _i['return']) _i['return'](); 30 | } 31 | 32 | catch (err) 33 | { 34 | if(!_n && _i['return']) _i['return'](); 35 | 36 | throw err; 37 | } 38 | 39 | return _arr; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/assets/AssetsXML.ts: -------------------------------------------------------------------------------- 1 | import { AssetXML } from './AssetXML'; 2 | import { PaletteXML } from './PaletteXML'; 3 | 4 | export class AssetsXML 5 | { 6 | private readonly _assets: AssetXML[]; 7 | private readonly _palettes: PaletteXML[]; 8 | 9 | constructor(xml: any) 10 | { 11 | if(xml.asset !== undefined) 12 | { 13 | if(Array.isArray(xml.asset)) 14 | { 15 | this._assets = []; 16 | 17 | for(const asset of xml.asset) this._assets.push(new AssetXML(asset)); 18 | } 19 | } 20 | 21 | if(xml.palette !== undefined) 22 | { 23 | if(Array.isArray(xml.palette)) 24 | { 25 | this._palettes = []; 26 | 27 | for(const palette of xml.palette) this._palettes.push(new PaletteXML(palette)); 28 | } 29 | } 30 | } 31 | 32 | public get assets(): AssetXML[] 33 | { 34 | return this._assets; 35 | } 36 | 37 | public get palettes(): PaletteXML[] 38 | { 39 | return this._palettes; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/manifest/ManifestLibraryAliasXML.ts: -------------------------------------------------------------------------------- 1 | export class ManifestLibraryAliasXML 2 | { 3 | private _name: string; 4 | private _link: string; 5 | private _flipH: boolean; 6 | private _flipV: boolean; 7 | 8 | constructor(xml: any) 9 | { 10 | const attributes = xml.$; 11 | 12 | if(attributes !== undefined) 13 | { 14 | if(attributes.name !== undefined) this._name = attributes.name; 15 | if(attributes.link !== undefined) this._link = attributes.link; 16 | if(attributes.fliph !== undefined) this._flipH = (attributes.fliph === '1'); 17 | if(attributes.flipv !== undefined) this._flipV = (attributes.flipv === '1'); 18 | } 19 | } 20 | 21 | public get name(): string 22 | { 23 | return this._name; 24 | } 25 | 26 | public get link(): string 27 | { 28 | return this._link; 29 | } 30 | 31 | public get flipH(): boolean 32 | { 33 | return this._flipH; 34 | } 35 | 36 | public get flipV(): boolean 37 | { 38 | return this._flipV; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/model/ModelDimensionsXML.ts: -------------------------------------------------------------------------------- 1 | export class ModelDimensionsXML 2 | { 3 | private readonly _x: number; 4 | private readonly _y: number; 5 | private readonly _z: number; 6 | private readonly _centerZ: number; 7 | 8 | constructor(xml: any) 9 | { 10 | const attributes = xml.$; 11 | 12 | if(attributes !== undefined) 13 | { 14 | if(attributes.x !== undefined) this._x = parseFloat(attributes.x); 15 | if(attributes.y !== undefined) this._y = parseFloat(attributes.y); 16 | if(attributes.z !== undefined) this._z = parseFloat(attributes.z); 17 | if(attributes.centerZ !== undefined) this._centerZ = parseFloat(attributes.centerZ); 18 | } 19 | } 20 | 21 | public get x(): number 22 | { 23 | return this._x; 24 | } 25 | 26 | public get y(): number 27 | { 28 | return this._y; 29 | } 30 | 31 | public get z(): number 32 | { 33 | return this._z; 34 | } 35 | 36 | public get centerZ(): number 37 | { 38 | return this._centerZ; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/VisualizationXML.ts: -------------------------------------------------------------------------------- 1 | import { VisualizationDataXML } from './VisualizationDataXML'; 2 | 3 | export class VisualizationXML 4 | { 5 | private readonly _type: string; 6 | private readonly _visualizations: VisualizationDataXML[]; 7 | 8 | constructor(xml: any) 9 | { 10 | const attributes = xml.$; 11 | 12 | if(attributes !== undefined) 13 | { 14 | if(attributes.type !== undefined) this._type = attributes.type; 15 | } 16 | 17 | if((xml.graphics !== undefined) && Array.isArray(xml.graphics)) 18 | { 19 | this._visualizations = []; 20 | 21 | for(const graphic of xml.graphics) 22 | { 23 | if(Array.isArray(graphic.visualization)) for(const visualization of graphic.visualization) this._visualizations.push(new VisualizationDataXML(visualization)); 24 | } 25 | } 26 | } 27 | 28 | public get type(): string 29 | { 30 | return this._type; 31 | } 32 | 33 | public get visualizations(): VisualizationDataXML[] 34 | { 35 | return this._visualizations; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/animation/FrameSequenceXML.ts: -------------------------------------------------------------------------------- 1 | import { FrameXML } from './FrameXML'; 2 | 3 | export class FrameSequenceXML 4 | { 5 | private readonly _loopCount: number; 6 | private readonly _random: number; 7 | 8 | private readonly _frames: FrameXML[]; 9 | 10 | constructor(xml: any) 11 | { 12 | const attributes = xml.$; 13 | 14 | if(attributes !== undefined) 15 | { 16 | if(attributes.loopCount !== undefined) this._loopCount = parseInt(attributes.loopCount); 17 | if(attributes.random !== undefined) this._random = parseInt(attributes.random); 18 | } 19 | 20 | if((xml.frame !== undefined) && Array.isArray(xml.frame)) 21 | { 22 | this._frames = []; 23 | 24 | for(const frame of xml.frame) this._frames.push(new FrameXML(frame)); 25 | } 26 | } 27 | 28 | public get loopCount(): number 29 | { 30 | return this._loopCount; 31 | } 32 | 33 | public get random(): number 34 | { 35 | return this._random; 36 | } 37 | 38 | public get frames(): FrameXML[] 39 | { 40 | return this._frames; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataColorXML.ts: -------------------------------------------------------------------------------- 1 | export class FigureDataColorXML 2 | { 3 | private _id: number; 4 | private _index: number; 5 | private _club: number; 6 | private _selectable: boolean; 7 | private _hexCode: string; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | this._id = ((attributes && parseInt(attributes.id)) || 0); 14 | this._index = ((attributes && parseInt(attributes.index)) || 0); 15 | this._club = ((attributes && parseInt(attributes.club)) || 0); 16 | this._selectable = ((attributes && parseInt(attributes.selectable) === 1) || false); 17 | 18 | this._hexCode = ((xml && xml._) || ''); 19 | } 20 | 21 | public get id(): number 22 | { 23 | return this._id; 24 | } 25 | 26 | public get index(): number 27 | { 28 | return this._index; 29 | } 30 | 31 | public get club(): number 32 | { 33 | return this._club; 34 | } 35 | 36 | public get selectable(): boolean 37 | { 38 | return this._selectable; 39 | } 40 | 41 | public get hexCode(): string 42 | { 43 | return this._hexCode; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/OverrideXML.ts: -------------------------------------------------------------------------------- 1 | import { EffectFrameXML } from './EffectFrameXML'; 2 | 3 | export class OverrideXML 4 | { 5 | private readonly _name: string; 6 | private readonly _override: string; 7 | 8 | private readonly _frames: EffectFrameXML[]; 9 | 10 | constructor(xml: any) 11 | { 12 | const attributes = xml.$; 13 | 14 | if(attributes !== undefined) 15 | { 16 | if(attributes.name !== undefined) this._name = attributes.name; 17 | if(attributes.override !== undefined) this._override = attributes.override; 18 | } 19 | 20 | if(xml.frame !== undefined) 21 | { 22 | if(Array.isArray(xml.frame)) 23 | { 24 | this._frames = []; 25 | 26 | for(const frame of xml.frame) this._frames.push(new EffectFrameXML(frame)); 27 | } 28 | } 29 | } 30 | 31 | public get name(): string 32 | { 33 | return this._name; 34 | } 35 | 36 | public get override(): string 37 | { 38 | return this._override; 39 | } 40 | 41 | public get frames(): EffectFrameXML[] 42 | { 43 | return this._frames; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/swf/SWFDownloader.ts: -------------------------------------------------------------------------------- 1 | import { FileUtilities } from '../common'; 2 | import { HabboAssetSWF } from './HabboAssetSWF'; 3 | 4 | export class SWFDownloader 5 | { 6 | public static USES_REVISION: boolean = true; 7 | public static LOG_DOWNLOADS: boolean = true; 8 | 9 | public static getDownloadUrl(baseUrl: string, className: string, revision: string): string 10 | { 11 | let url = baseUrl; 12 | 13 | if(!url || !url.length) return null; 14 | 15 | if(SWFDownloader.USES_REVISION && (revision !== '-1')) url = url.replace('%revision%', revision.toString()); 16 | 17 | url = url.replace('%className%', className); 18 | 19 | return url; 20 | } 21 | 22 | public static async downloadFromUrl(url: string): Promise 23 | { 24 | return await this.extractSWF(url); 25 | } 26 | 27 | public static async extractSWF(url: string): Promise 28 | { 29 | const buffer = await FileUtilities.readFileAsBuffer(url); 30 | 31 | if(!buffer) return null; 32 | 33 | const habboAssetSWF = new HabboAssetSWF(buffer); 34 | 35 | await habboAssetSWF.setupAsync(); 36 | 37 | return habboAssetSWF; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/model/ModelXML.ts: -------------------------------------------------------------------------------- 1 | import { ModelDimensionsXML } from './ModelDimensionsXML'; 2 | import { ModelDirectionXML } from './ModelDirectionXML'; 3 | 4 | export class ModelXML 5 | { 6 | private readonly _dimensions: ModelDimensionsXML; 7 | private readonly _directions: ModelDirectionXML[]; 8 | 9 | constructor(xml: any) 10 | { 11 | if(xml.dimensions !== undefined) 12 | { 13 | if(xml.dimensions[0] !== undefined) this._dimensions = new ModelDimensionsXML(xml.dimensions[0]); 14 | } 15 | 16 | if((xml.directions !== undefined) && Array.isArray(xml.directions)) 17 | { 18 | this._directions = []; 19 | 20 | for(const directionParent of xml.directions) 21 | { 22 | if(Array.isArray(directionParent.direction)) for(const direction of directionParent.direction) this._directions.push(new ModelDirectionXML(direction.$)); 23 | } 24 | } 25 | } 26 | 27 | public get dimensions(): ModelDimensionsXML 28 | { 29 | return this._dimensions; 30 | } 31 | 32 | public get directions(): ModelDirectionXML[] 33 | { 34 | return this._directions; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataPartXML.ts: -------------------------------------------------------------------------------- 1 | export class FigureDataPartXML 2 | { 3 | private _id: number; 4 | private _type: string; 5 | private _colorable: boolean; 6 | private _index: number; 7 | private _colorindex: number; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | this._id = ((attributes && parseInt(attributes.id)) || 0); 14 | this._type = ((attributes && attributes.type) || ''); 15 | this._colorable = ((attributes && parseInt(attributes.colorable) === 1) || false); 16 | this._index = ((attributes && parseInt(attributes.index)) || 0); 17 | this._colorindex = ((attributes && parseInt(attributes.colorindex)) || 0); 18 | } 19 | 20 | public get id(): number 21 | { 22 | return this._id; 23 | } 24 | 25 | public get type(): string 26 | { 27 | return this._type; 28 | } 29 | 30 | public get colorable(): boolean 31 | { 32 | return this._colorable; 33 | } 34 | 35 | public get index(): number 36 | { 37 | return this._index; 38 | } 39 | 40 | public get colorIndex(): number 41 | { 42 | return this._colorindex; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/AddXML.ts: -------------------------------------------------------------------------------- 1 | export class AddXML 2 | { 3 | private readonly _id: string; 4 | private readonly _align: string; 5 | private readonly _blend: string; 6 | private readonly _ink: number; 7 | private readonly _base: string; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | if(attributes !== undefined) 14 | { 15 | if(attributes.id !== undefined) this._id = attributes.id; 16 | if(attributes.align !== undefined) this._align = attributes.align; 17 | if(attributes.blend !== undefined) this._blend = attributes.blend; 18 | if(attributes.ink !== undefined) this._ink = parseInt(attributes.ink); 19 | if(attributes.base !== undefined) this._base = attributes.base; 20 | } 21 | } 22 | 23 | public get id(): string 24 | { 25 | return this._id; 26 | } 27 | 28 | public get align(): string 29 | { 30 | return this._align; 31 | } 32 | 33 | public get blend(): string 34 | { 35 | return this._blend; 36 | } 37 | 38 | public get ink(): number 39 | { 40 | return this._ink; 41 | } 42 | 43 | public get base(): string 44 | { 45 | return this._base; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuremap/FigureLibraryXML.ts: -------------------------------------------------------------------------------- 1 | import { FigureLibraryPartXML } from './FigureLibraryPartXML'; 2 | 3 | export class FigureLibraryXML 4 | { 5 | private _id: string; 6 | private _revision: number; 7 | private _parts: FigureLibraryPartXML[]; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | if(attributes) 14 | { 15 | if(attributes.id !== undefined) this._id = attributes.id; 16 | if(attributes.revision !== undefined) this._revision = parseInt(attributes.revision); 17 | } 18 | 19 | if(xml.part !== undefined) 20 | { 21 | if(Array.isArray(xml.part)) 22 | { 23 | this._parts = []; 24 | 25 | for(const partId in xml.part) 26 | { 27 | const part = xml.part[partId]; 28 | 29 | this._parts.push(new FigureLibraryPartXML(part)); 30 | } 31 | } 32 | } 33 | } 34 | 35 | public get id(): string 36 | { 37 | return this._id; 38 | } 39 | 40 | public get revision(): number 41 | { 42 | return this._revision; 43 | } 44 | 45 | public get parts(): FigureLibraryPartXML[] 46 | { 47 | return this._parts; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/swf/tags/DefineBinaryDataTag.ts: -------------------------------------------------------------------------------- 1 | import { CharacterTag } from './CharacterTag'; 2 | import { ITag } from './ITag'; 3 | 4 | export class DefineBinaryDataTag extends CharacterTag implements ITag 5 | { 6 | private readonly _tag: number; 7 | private readonly _reserved: number; 8 | private readonly _binaryData: string; 9 | private readonly _binaryDataBuffer: Buffer; 10 | 11 | constructor(buffer: Buffer) 12 | { 13 | super(); 14 | 15 | this._tag = buffer.readUInt16LE(0); 16 | this._reserved = buffer.readUInt32LE(2); 17 | const start = 6; //short 2 + int 4 18 | const end = buffer.length; 19 | const binary = buffer.slice(start, end); 20 | 21 | this._binaryData = binary.toString('utf-8'); 22 | this._binaryDataBuffer = binary; 23 | 24 | this.characterId = this._tag; 25 | } 26 | 27 | public get code(): number 28 | { 29 | return 87; 30 | } 31 | 32 | public get tag(): number 33 | { 34 | return this._tag; 35 | } 36 | 37 | public get reserved(): number 38 | { 39 | return this._reserved; 40 | } 41 | 42 | public get binaryData(): string 43 | { 44 | return this._binaryData; 45 | } 46 | 47 | public get binaryDataBuffer(): Buffer 48 | { 49 | return this._binaryDataBuffer; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/ParticleSystemParticleXML.ts: -------------------------------------------------------------------------------- 1 | 2 | export class ParticleSystemParticleXML 3 | { 4 | private readonly _isEmitter: boolean; 5 | private readonly _lifeTime: number; 6 | private readonly _fade: boolean; 7 | private readonly _frames: string[]; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | if(attributes !== undefined) 14 | { 15 | if(attributes.is_emitter !== undefined) this._isEmitter = (attributes.is_emitter === 'true'); 16 | if(attributes.lifetime !== undefined) this._lifeTime = parseInt(attributes.lifetime); 17 | if(attributes.fade !== undefined) this._fade = (attributes.fade === 'true'); 18 | } 19 | 20 | if((xml.frame !== undefined) && Array.isArray(xml.frame)) 21 | { 22 | this._frames = []; 23 | 24 | for(const frame of xml.frame) this._frames.push(frame.$.name); 25 | } 26 | } 27 | 28 | public get isEmitter(): boolean 29 | { 30 | return this._isEmitter; 31 | } 32 | 33 | public get lifeTime(): number 34 | { 35 | return this._lifeTime; 36 | } 37 | 38 | public get fade(): boolean 39 | { 40 | return this._fade; 41 | } 42 | 43 | public get frames(): string[] 44 | { 45 | return this._frames; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/EffectFrameXML.ts: -------------------------------------------------------------------------------- 1 | import { EffectFramePartXML } from './EffectFramePartXML'; 2 | 3 | export class EffectFrameXML 4 | { 5 | private readonly _repeats: number; 6 | private readonly _fxs: EffectFramePartXML[]; 7 | private readonly _bodyParts: EffectFramePartXML[]; 8 | 9 | constructor(xml: any) 10 | { 11 | const attributes = xml.$; 12 | 13 | if(attributes !== undefined) 14 | { 15 | if(attributes.repeats !== undefined) this._repeats = parseInt(attributes.repeats); 16 | } 17 | 18 | if(xml.fx !== undefined) 19 | { 20 | if(Array.isArray(xml.fx)) 21 | { 22 | this._fxs = []; 23 | 24 | for(const fx of xml.fx) this._fxs.push(new EffectFramePartXML(fx)); 25 | } 26 | } 27 | 28 | if(xml.bodypart !== undefined) 29 | { 30 | if(Array.isArray(xml.bodypart)) 31 | { 32 | this._bodyParts = []; 33 | 34 | for(const bodypart of xml.bodypart) this._bodyParts.push(new EffectFramePartXML(bodypart)); 35 | } 36 | } 37 | } 38 | 39 | public get repeats(): number 40 | { 41 | return this._repeats; 42 | } 43 | 44 | public get fxs(): EffectFramePartXML[] 45 | { 46 | return this._fxs; 47 | } 48 | 49 | public get bodyParts(): EffectFramePartXML[] 50 | { 51 | return this._bodyParts; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/common/mapping/index.ts: -------------------------------------------------------------------------------- 1 | export * from './json'; 2 | export * from './json/asset'; 3 | export * from './json/asset/animation'; 4 | export * from './json/asset/logic'; 5 | export * from './json/asset/logic/model'; 6 | export * from './json/asset/logic/particlesystem'; 7 | export * from './json/asset/spritesheet'; 8 | export * from './json/asset/visualization'; 9 | export * from './json/asset/visualization/animation'; 10 | export * from './json/asset/visualization/color'; 11 | export * from './json/asset/visualization/gestures'; 12 | export * from './json/asset/visualization/postures'; 13 | export * from './json/effectmap'; 14 | export * from './json/externaltexts'; 15 | export * from './json/figuredata'; 16 | export * from './json/figuremap'; 17 | export * from './json/furnituredata'; 18 | export * from './json/productdata'; 19 | export * from './mappers'; 20 | export * from './mappers/asset'; 21 | export * from './xml'; 22 | export * from './xml/asset'; 23 | export * from './xml/asset/animation'; 24 | export * from './xml/asset/assets'; 25 | export * from './xml/asset/logic'; 26 | export * from './xml/asset/logic/model'; 27 | export * from './xml/asset/logic/particlesystem'; 28 | export * from './xml/asset/manifest'; 29 | export * from './xml/asset/visualization'; 30 | export * from './xml/asset/visualization/animation'; 31 | export * from './xml/asset/visualization/color'; 32 | export * from './xml/effectmap'; 33 | export * from './xml/figuredata'; 34 | export * from './xml/figuremap'; 35 | export * from './xml/furnituredata'; 36 | -------------------------------------------------------------------------------- /src/common/utils/BinaryReader.ts: -------------------------------------------------------------------------------- 1 | export class BinaryReader 2 | { 3 | private _position: number; 4 | private _dataView: DataView; 5 | 6 | constructor(buffer: ArrayBuffer) 7 | { 8 | this._position = 0; 9 | this._dataView = new DataView(buffer); 10 | } 11 | 12 | public readByte(): number 13 | { 14 | const byte = this._dataView.getInt8(this._position); 15 | 16 | this._position++; 17 | 18 | return byte; 19 | } 20 | 21 | public readBytes(length: number): BinaryReader 22 | { 23 | const buffer = new BinaryReader(this._dataView.buffer.slice(this._position, this._position + length)); 24 | 25 | this._position += length; 26 | 27 | return buffer; 28 | } 29 | 30 | public readShort(): number 31 | { 32 | const short = this._dataView.getInt16(this._position); 33 | 34 | this._position += 2; 35 | 36 | return short; 37 | } 38 | 39 | public readInt(): number 40 | { 41 | const int = this._dataView.getInt32(this._position); 42 | 43 | this._position += 4; 44 | 45 | return int; 46 | } 47 | 48 | public remaining(): number 49 | { 50 | return this._dataView.byteLength - this._position; 51 | } 52 | 53 | public toString(encoding?: string): string 54 | { 55 | return new TextDecoder().decode(this._dataView.buffer); 56 | } 57 | 58 | public toArrayBuffer(): ArrayBuffer 59 | { 60 | return this._dataView.buffer; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/swf/common/ISWFTag.ts: -------------------------------------------------------------------------------- 1 | import { ISWFTagAsset } from './ISWFTagAsset'; 2 | import { ISWFTagHeader } from './ISWFTagHeader'; 3 | import { ISWFTagLabel } from './ISWFTagLabel'; 4 | import { ISWFTagScene } from './ISWFTagScene'; 5 | import { ISWFTagSplitter } from './ISWFTagSplitter'; 6 | import { ISWFTagSymbol } from './ISWFTagSymbol'; 7 | 8 | export interface ISWFTag 9 | { 10 | header: ISWFTagHeader; 11 | useNetwork: boolean; 12 | as3: boolean; 13 | hasMetaData: boolean; 14 | useGPU: boolean; 15 | useDirectBit: boolean; 16 | metadata: string; 17 | RGB: [ number, number, number ]; 18 | sceneCount: number; 19 | scenes: ISWFTagScene[]; 20 | frameLabelCount: number; 21 | labels: ISWFTagLabel[]; 22 | name: string; 23 | anchor: number; 24 | SpriteID: number; 25 | FrameCount: number; 26 | ControlTags: Partial[]; 27 | count: number; 28 | assets: ISWFTagAsset[]; 29 | url: string; 30 | characterId: number; 31 | bitmapFormat: number; 32 | bitmapWidth: number; 33 | bitmapHeight: number; 34 | bitmapColorTableSize: number; 35 | zlibBitmapData: Buffer; 36 | deblockParam: number; 37 | imgData: Buffer; 38 | bitmapAlphaData: Buffer; 39 | jpegData: Buffer; 40 | data: Buffer; 41 | splitter: ISWFTagSplitter; 42 | depth: number; 43 | tabIndex: number; 44 | password: string; 45 | maxRecursionDepth: number; 46 | scriptTimeoutSeconds: number; 47 | numSymbols: number; 48 | symbols: ISWFTagSymbol[]; 49 | } 50 | -------------------------------------------------------------------------------- /src/swf/PackImages.ts: -------------------------------------------------------------------------------- 1 | import { packAsync } from 'free-tex-packer-core'; 2 | import { ImageBundle, SpriteBundle } from '../common'; 3 | 4 | export const PackImages = async (documentClass: string, imageBundle: ImageBundle, convertCase: boolean = false) => 5 | { 6 | const files = await packAsync(imageBundle.images, { 7 | textureName: (convertCase ? documentClass.substring(1) : documentClass), 8 | width: 10240, 9 | height: 4320, 10 | fixedSize: false, 11 | allowRotation: false, 12 | detectIdentical: true, 13 | allowTrim: true, 14 | //@ts-ignore 15 | exporter: 'Pixi' 16 | }); 17 | 18 | const bundle = new SpriteBundle(); 19 | 20 | for(const item of files) 21 | { 22 | if(item.name.endsWith('.json')) 23 | { 24 | bundle.spritesheet = JSON.parse(item.buffer.toString('utf8')); 25 | 26 | delete bundle.spritesheet.meta.app; 27 | delete bundle.spritesheet.meta.version; 28 | } 29 | else 30 | { 31 | bundle.imageData = { 32 | name: item.name, 33 | buffer: item.buffer 34 | }; 35 | 36 | if(convertCase) bundle.imageData.name = (documentClass.replace(/(?:^|\.?)([A-Z])/g, (x,y) => ('_' + y.toLowerCase().replace(/^_/, '')))).substring(1); 37 | } 38 | } 39 | 40 | if((bundle.spritesheet !== undefined) && (bundle.imageData !== undefined)) bundle.spritesheet.meta.image = bundle.imageData.name; 41 | 42 | return bundle; 43 | }; 44 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/EffectMapMapper.ts: -------------------------------------------------------------------------------- 1 | import { IEffectMap, IEffectMapLibrary } from '../json'; 2 | import { EffectMapEffectXML, EffectMapXML } from '../xml'; 3 | import { Mapper } from './asset'; 4 | 5 | export class EffectMapMapper extends Mapper 6 | { 7 | public static mapXML(xml: any, output: IEffectMap): void 8 | { 9 | if(!xml || !output) return; 10 | 11 | if(xml.map !== undefined) EffectMapMapper.mapEffectMapXML(new EffectMapXML(xml.map), output); 12 | } 13 | 14 | private static mapEffectMapXML(xml: EffectMapXML, output: IEffectMap): void 15 | { 16 | if(!xml || !output) return; 17 | 18 | if(xml.effects !== undefined) 19 | { 20 | if(xml.effects.length) 21 | { 22 | output.effects = []; 23 | 24 | EffectMapMapper.mapEffectMapLibrariesXML(xml.effects, output.effects); 25 | } 26 | } 27 | } 28 | 29 | private static mapEffectMapLibrariesXML(xml: EffectMapEffectXML[], output: IEffectMapLibrary[]): void 30 | { 31 | if(!xml || !xml.length || !output) return; 32 | 33 | for(const libraryXML of xml) 34 | { 35 | const library: IEffectMapLibrary = {}; 36 | 37 | if(libraryXML.id !== undefined) library.id = libraryXML.id; 38 | if(libraryXML.lib !== undefined) library.lib = libraryXML.lib; 39 | if(libraryXML.type !== undefined) library.type = libraryXML.type; 40 | if(libraryXML.revision !== undefined) library.revision = libraryXML.revision; 41 | 42 | output.push(library); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/common/mapping/xml/furnituredata/FurnitureDataXML.ts: -------------------------------------------------------------------------------- 1 | import { FurnitureTypeXML } from './FurnitureTypeXML'; 2 | 3 | export class FurnitureDataXML 4 | { 5 | private _floorItems: FurnitureTypeXML[]; 6 | private _wallItems: FurnitureTypeXML[]; 7 | 8 | constructor(xml: any) 9 | { 10 | if(!xml) return; 11 | 12 | if(xml.roomitemtypes !== undefined) 13 | { 14 | this._floorItems = []; 15 | 16 | for(const roomitemtype of xml.roomitemtypes) 17 | { 18 | const furniTypes = roomitemtype.furnitype; 19 | 20 | if(furniTypes !== undefined) 21 | { 22 | if(Array.isArray(furniTypes)) for(const furniType of furniTypes) this._floorItems.push(new FurnitureTypeXML('floor', furniType)); 23 | } 24 | } 25 | } 26 | 27 | if(xml.wallitemtypes !== undefined) 28 | { 29 | this._wallItems = []; 30 | 31 | for(const wallitemtype of xml.wallitemtypes) 32 | { 33 | const furniTypes = wallitemtype.furnitype; 34 | 35 | if(furniTypes !== undefined) 36 | { 37 | if(Array.isArray(furniTypes)) for(const furniType of furniTypes) this._wallItems.push(new FurnitureTypeXML('wall', furniType)); 38 | } 39 | } 40 | } 41 | } 42 | 43 | public get floorItems(): FurnitureTypeXML[] 44 | { 45 | return this._floorItems; 46 | } 47 | 48 | public get wallItems(): FurnitureTypeXML[] 49 | { 50 | return this._wallItems; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/ParticleSystemSimulationXML.ts: -------------------------------------------------------------------------------- 1 | 2 | export class ParticleSystemSimulationXML 3 | { 4 | private _force: number; 5 | private _direction: number; 6 | private _gravity: number; 7 | private _airFriction: number; 8 | private _shape: string; 9 | private _energy: number; 10 | 11 | constructor(xml: any) 12 | { 13 | const attributes = xml.$; 14 | 15 | if(attributes !== undefined) 16 | { 17 | if(attributes.force !== undefined) this._force = parseFloat(attributes.force); 18 | if(attributes.direction !== undefined) this._direction = parseFloat(attributes.direction); 19 | if(attributes.gravity !== undefined) this._gravity = parseFloat(attributes.gravity); 20 | if(attributes.airfriction !== undefined) this._airFriction = parseFloat(attributes.airfriction); 21 | if(attributes.shape !== undefined) this._shape = attributes.shape; 22 | if(attributes.energy !== undefined) this._energy = parseFloat(attributes.energy); 23 | } 24 | } 25 | 26 | public get force(): number 27 | { 28 | return this._force; 29 | } 30 | 31 | public get direction(): number 32 | { 33 | return this._direction; 34 | } 35 | 36 | public get gravity(): number 37 | { 38 | return this._gravity; 39 | } 40 | 41 | public get airFriction(): number 42 | { 43 | return this._airFriction; 44 | } 45 | 46 | public get shape(): string 47 | { 48 | return this._shape; 49 | } 50 | 51 | public get energy(): number 52 | { 53 | return this._energy; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataXML.ts: -------------------------------------------------------------------------------- 1 | import { FigureDataPaletteXML } from './FigureDataPaletteXML'; 2 | import { FigureDataSetTypeXML } from './FigureDataSetTypeXML'; 3 | 4 | export class FigureDataXML 5 | { 6 | private _colorPalettes: FigureDataPaletteXML[]; 7 | private _sets: FigureDataSetTypeXML[]; 8 | 9 | constructor(xml: any) 10 | { 11 | if(xml.colors !== undefined && xml.colors[0].palette !== undefined) 12 | { 13 | const paletteArr = xml.colors[0].palette; 14 | 15 | if(Array.isArray(paletteArr)) 16 | { 17 | this._colorPalettes = []; 18 | 19 | for(const pal in paletteArr) 20 | { 21 | const palette = paletteArr[pal]; 22 | 23 | this._colorPalettes.push(new FigureDataPaletteXML(palette)); 24 | } 25 | } 26 | } 27 | 28 | if(xml.sets !== undefined && xml.sets[0].settype !== undefined) 29 | { 30 | const setTypeArr = xml.sets[0].settype; 31 | 32 | if(Array.isArray(setTypeArr)) 33 | { 34 | this._sets = []; 35 | 36 | for(const set in setTypeArr) 37 | { 38 | const setType = setTypeArr[set]; 39 | 40 | this._sets.push(new FigureDataSetTypeXML(setType)); 41 | } 42 | } 43 | } 44 | } 45 | 46 | public get colorPalettes(): FigureDataPaletteXML[] 47 | { 48 | return this._colorPalettes; 49 | } 50 | 51 | public get sets(): FigureDataSetTypeXML[] 52 | { 53 | return this._sets; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/converters/FigureDataConverter.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs/promises'; 2 | import ora from 'ora'; 3 | import { singleton } from 'tsyringe'; 4 | import { parseStringPromise } from 'xml2js'; 5 | import { Configuration, FigureDataMapper, FileUtilities, IConverter, IFigureData } from '../common'; 6 | 7 | @singleton() 8 | export class FigureDataConverter implements IConverter 9 | { 10 | public figureData: IFigureData = null; 11 | 12 | constructor( 13 | private readonly _configuration: Configuration) 14 | {} 15 | 16 | public async convertAsync(): Promise 17 | { 18 | const now = Date.now(); 19 | const spinner = ora('Preparing FigureData').start(); 20 | const url = this._configuration.getValue('figuredata.load.url'); 21 | const content = await FileUtilities.readFileAsString(url); 22 | 23 | this.figureData = ((!content.startsWith('{')) ? await this.mapXML2JSON(await parseStringPromise(content.replace(/&/g,'&'))) : JSON.parse(content)); 24 | 25 | const directory = await FileUtilities.getDirectory('./assets/gamedata'); 26 | const path = directory.path + '/FigureData.json'; 27 | 28 | await writeFile(path, JSON.stringify(this.figureData), 'utf8'); 29 | 30 | spinner.succeed(`FigureData: Finished in ${ Date.now() - now }ms`); 31 | } 32 | 33 | private async mapXML2JSON(xml: any): Promise 34 | { 35 | if(!xml) return null; 36 | 37 | const output: IFigureData = {}; 38 | 39 | FigureDataMapper.mapXML(xml, output); 40 | 41 | return output; 42 | } 43 | 44 | public get converterType(): string 45 | { 46 | return 'FigureData'; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nitrots/nitro-converter", 3 | "description": "Serverside javascript library for bundling .nitro assets", 4 | "version": "1.0.0", 5 | "publishConfig": { 6 | "access": "public" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://git.krews.org/nitro/nitro-converter.git" 11 | }, 12 | "license": "GPL-3.0", 13 | "bugs": { 14 | "url": "https://git.krews.org/nitro/nitro-converter/issues" 15 | }, 16 | "homepage": "https://git.krews.org/nitro/nitro-converter", 17 | "scripts": { 18 | "build": "tsc", 19 | "start:dev": "ts-node-dev --respawn --transpile-only src/Main.ts", 20 | "start": "node ./dist/Main.js", 21 | "start:bundle": "yarn start --bundle", 22 | "start:extract": "yarn start --extract", 23 | "start:convert-swf": "yarn start --convert-swf" 24 | }, 25 | "dependencies": { 26 | "bytebuffer": "^5.0.1", 27 | "concat-frames": "^1.0.3", 28 | "free-tex-packer-core": "^0.3.4", 29 | "jpg-stream": "^1.1.2", 30 | "lzma-purejs": "^0.9.3", 31 | "node-fetch": "2.6.1", 32 | "ora": "5.3.0", 33 | "pako": "^2.0.4", 34 | "png-stream": "^1.0.5", 35 | "reflect-metadata": "^0.1.13", 36 | "stream-to-array": "^2.3.0", 37 | "tsyringe": "^4.7.0", 38 | "xml2js": "^0.4.23" 39 | }, 40 | "devDependencies": { 41 | "@types/bytebuffer": "^5.0.42", 42 | "@types/node": "^18.6.1", 43 | "@types/node-fetch": "^2.6.2", 44 | "@types/pako": "^2.0.0", 45 | "@types/stream-to-array": "^2.3.0", 46 | "@types/xml2js": "^0.4.11", 47 | "@typescript-eslint/eslint-plugin": "^5.31.0", 48 | "@typescript-eslint/parser": "^5.31.0", 49 | "eslint": "^8.20.0", 50 | "ts-node-dev": "^2.0.0", 51 | "typescript": "^4.3.5" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/assets/AssetXML.ts: -------------------------------------------------------------------------------- 1 | export class AssetXML 2 | { 3 | private readonly _name: string; 4 | private readonly _source: string; 5 | private readonly _x: number; 6 | private readonly _y: number; 7 | private readonly _flipH: boolean; 8 | private readonly _flipV: boolean; 9 | private readonly _usesPalette: boolean; 10 | 11 | constructor(asset: any) 12 | { 13 | const attributes = asset.$; 14 | 15 | if(attributes !== undefined) 16 | { 17 | if(attributes.name !== undefined) this._name = attributes.name; 18 | if(attributes.source !== undefined) this._source = attributes.source; 19 | if(attributes.x !== undefined) this._x = parseInt(attributes.x); 20 | if(attributes.x !== undefined) this._y = parseInt(attributes.y); 21 | if(attributes.flipH !== undefined) this._flipH = (attributes.flipH === '1'); 22 | if(attributes.flipV !== undefined) this._flipV = (attributes.flipV === '1'); 23 | if(attributes.usesPalette !== undefined) this._usesPalette = (attributes.usesPalette === '1'); 24 | } 25 | } 26 | 27 | public get name(): string 28 | { 29 | return this._name; 30 | } 31 | 32 | public get source(): string 33 | { 34 | return this._source; 35 | } 36 | 37 | public get x(): number 38 | { 39 | return this._x; 40 | } 41 | 42 | public get y(): number 43 | { 44 | return this._y; 45 | } 46 | 47 | public get flipH(): boolean 48 | { 49 | return this._flipH; 50 | } 51 | 52 | public get flipV(): boolean 53 | { 54 | return this._flipV; 55 | } 56 | 57 | public get usesPalette(): boolean 58 | { 59 | return this._usesPalette; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/converters/ExternalTextsConverter.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs/promises'; 2 | import ora from 'ora'; 3 | import { singleton } from 'tsyringe'; 4 | import { Configuration, FileUtilities, IConverter, IExternalTexts } from '../common'; 5 | 6 | @singleton() 7 | export class ExternalTextsConverter implements IConverter 8 | { 9 | public externalTexts: IExternalTexts = null; 10 | 11 | constructor( 12 | private readonly _configuration: Configuration) 13 | {} 14 | 15 | public async convertAsync(): Promise 16 | { 17 | const now = Date.now(); 18 | const spinner = ora('Preparing ExternalTexts').start(); 19 | const url = this._configuration.getValue('external.texts.url'); 20 | const content = await FileUtilities.readFileAsString(url); 21 | 22 | this.externalTexts = ((!content.startsWith('{')) ? await this.mapText2JSON(content) : JSON.parse(content)); 23 | 24 | const directory = await FileUtilities.getDirectory('./assets/gamedata'); 25 | const path = directory.path + '/ExternalTexts.json'; 26 | 27 | await writeFile(path, JSON.stringify(this.externalTexts), 'utf8'); 28 | 29 | spinner.succeed(`ExternalTexts: Finished in ${ Date.now() - now }ms`); 30 | } 31 | 32 | private async mapText2JSON(text: string): Promise 33 | { 34 | if(!text) return null; 35 | 36 | const output: IExternalTexts = {}; 37 | 38 | const parts = text.split(/\r?\n/); 39 | 40 | for(const part of parts) 41 | { 42 | const [ key, ...value ] = part.split('='); 43 | 44 | output[key] = value.join(); 45 | } 46 | 47 | return output; 48 | } 49 | 50 | public get converterType(): string 51 | { 52 | return 'ExternalTexts'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/common/utils/FileUtilities.ts: -------------------------------------------------------------------------------- 1 | import { readFile } from 'fs/promises'; 2 | import * as fetch from 'node-fetch'; 3 | import { File } from './File'; 4 | 5 | export class FileUtilities 6 | { 7 | public static async getDirectory(path: string): Promise 8 | { 9 | const folder = new File(path); 10 | 11 | await folder.createDirectory(); 12 | 13 | return folder; 14 | } 15 | 16 | public static async readFileAsBuffer(url: string): Promise 17 | { 18 | if(!url) return null; 19 | 20 | let content: Buffer = null; 21 | 22 | if(url.startsWith('//')) url = ('https:' + url); 23 | 24 | if(url.startsWith('http')) 25 | { 26 | const data = await fetch.default(url); 27 | const arrayBuffer = await data.arrayBuffer(); 28 | 29 | if(data.headers.get('Content-Type') !== 'application/x-shockwave-flash' && data.headers.get('Content-Type') !== 'application/octet-stream') return; 30 | 31 | if(arrayBuffer) content = Buffer.from(arrayBuffer); 32 | } 33 | else 34 | { 35 | content = await readFile(url); 36 | } 37 | 38 | return content; 39 | } 40 | 41 | public static async readFileAsString(url: string): Promise 42 | { 43 | if(!url) return null; 44 | 45 | let content = null; 46 | 47 | if(url.startsWith('//')) url = ('https:' + url); 48 | 49 | if(url.startsWith('http')) 50 | { 51 | const data = await fetch.default(url); 52 | if(data.status === 404) return null; 53 | 54 | if(data) content = await data.text(); 55 | } 56 | else 57 | { 58 | const data = await readFile(url); 59 | 60 | content = data.toString('utf-8'); 61 | } 62 | 63 | return content; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './bundle'; 2 | export * from './config'; 3 | export * from './converters'; 4 | export * from './mapping'; 5 | export * from './mapping/json'; 6 | export * from './mapping/json/asset'; 7 | export * from './mapping/json/asset/animation'; 8 | export * from './mapping/json/asset/logic'; 9 | export * from './mapping/json/asset/logic/model'; 10 | export * from './mapping/json/asset/logic/particlesystem'; 11 | export * from './mapping/json/asset/spritesheet'; 12 | export * from './mapping/json/asset/visualization'; 13 | export * from './mapping/json/asset/visualization/animation'; 14 | export * from './mapping/json/asset/visualization/color'; 15 | export * from './mapping/json/asset/visualization/gestures'; 16 | export * from './mapping/json/asset/visualization/postures'; 17 | export * from './mapping/json/effectmap'; 18 | export * from './mapping/json/externaltexts'; 19 | export * from './mapping/json/figuredata'; 20 | export * from './mapping/json/figuremap'; 21 | export * from './mapping/json/furnituredata'; 22 | export * from './mapping/json/productdata'; 23 | export * from './mapping/mappers'; 24 | export * from './mapping/mappers/asset'; 25 | export * from './mapping/xml'; 26 | export * from './mapping/xml/asset'; 27 | export * from './mapping/xml/asset/animation'; 28 | export * from './mapping/xml/asset/assets'; 29 | export * from './mapping/xml/asset/logic'; 30 | export * from './mapping/xml/asset/logic/model'; 31 | export * from './mapping/xml/asset/logic/particlesystem'; 32 | export * from './mapping/xml/asset/manifest'; 33 | export * from './mapping/xml/asset/visualization'; 34 | export * from './mapping/xml/asset/visualization/animation'; 35 | export * from './mapping/xml/asset/visualization/color'; 36 | export * from './mapping/xml/effectmap'; 37 | export * from './mapping/xml/figuredata'; 38 | export * from './mapping/xml/figuremap'; 39 | export * from './mapping/xml/furnituredata'; 40 | export * from './utils'; 41 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/SpriteXML.ts: -------------------------------------------------------------------------------- 1 | import { DirectionXML } from './DirectionXML'; 2 | 3 | export class SpriteXML 4 | { 5 | private readonly _id: string; 6 | private readonly _member: string; 7 | private readonly _directions: number; 8 | private readonly _staticY: number; 9 | private readonly _ink: number; 10 | 11 | private readonly _directionList: DirectionXML[]; 12 | 13 | constructor(xml: any) 14 | { 15 | const attributes = xml.$; 16 | 17 | if(attributes !== undefined) 18 | { 19 | if(attributes.id !== undefined) this._id = attributes.id; 20 | if(attributes.member !== undefined) this._member = attributes.member; 21 | if(attributes.directions !== undefined) this._directions = parseInt(attributes.directions); 22 | if(attributes.staticY !== undefined) this._staticY = parseInt(attributes.staticY); 23 | if(attributes.ink !== undefined) this._ink = parseInt(attributes.ink); 24 | } 25 | 26 | if(xml.direction !== undefined) 27 | { 28 | if(Array.isArray(xml.direction)) 29 | { 30 | this._directionList = []; 31 | 32 | for(const direction of xml.direction) this._directionList.push(new DirectionXML(direction)); 33 | } 34 | } 35 | } 36 | 37 | public get id(): string 38 | { 39 | return this._id; 40 | } 41 | 42 | public get member(): string 43 | { 44 | return this._member; 45 | } 46 | 47 | public get directions(): number 48 | { 49 | return this._directions; 50 | } 51 | 52 | public get staticY(): number 53 | { 54 | return this._staticY; 55 | } 56 | 57 | public get ink(): number 58 | { 59 | return this._ink; 60 | } 61 | 62 | public get directionList(): DirectionXML[] 63 | { 64 | return this._directionList; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/animation/FrameXML.ts: -------------------------------------------------------------------------------- 1 | import { FrameOffsetXML } from './FrameOffsetXML'; 2 | 3 | export class FrameXML 4 | { 5 | private readonly _id: string; 6 | private readonly _x: number; 7 | private readonly _y: number; 8 | private readonly _randomX: number; 9 | private readonly _randomY: number; 10 | 11 | private readonly _offsets: FrameOffsetXML[]; 12 | 13 | constructor(xml: any) 14 | { 15 | const attributes = xml.$; 16 | 17 | if(attributes !== undefined) 18 | { 19 | if(attributes.id !== undefined) this._id = attributes.id; 20 | if(attributes.x !== undefined) this._x = parseInt(attributes.x); 21 | if(attributes.y !== undefined) this._y = parseInt(attributes.y); 22 | if(attributes.randomX !== undefined) this._randomX = parseInt(attributes.randomX); 23 | if(attributes.randomY !== undefined) this._randomY = parseInt(attributes.randomY); 24 | } 25 | 26 | if((xml.offsets !== undefined) && Array.isArray(xml.offsets)) 27 | { 28 | this._offsets = []; 29 | 30 | for(const offsetParent of xml.offsets) 31 | { 32 | if(Array.isArray(offsetParent.offset)) for(const offset of offsetParent.offset) this._offsets.push(new FrameOffsetXML(offset)); 33 | } 34 | } 35 | } 36 | 37 | public get id(): string 38 | { 39 | return this._id; 40 | } 41 | 42 | public get x(): number 43 | { 44 | return this._x; 45 | } 46 | 47 | public get y(): number 48 | { 49 | return this._y; 50 | } 51 | 52 | public get randomX(): number 53 | { 54 | return this._randomX; 55 | } 56 | 57 | public get randomY(): number 58 | { 59 | return this._randomY; 60 | } 61 | 62 | public get offsets(): FrameOffsetXML[] 63 | { 64 | return this._offsets; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/converters/EffectMapConverter.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs/promises'; 2 | import ora from 'ora'; 3 | import { singleton } from 'tsyringe'; 4 | import { parseStringPromise } from 'xml2js'; 5 | import { Configuration, EffectMapMapper, FileUtilities, IConverter, IEffectMap } from '../common'; 6 | 7 | @singleton() 8 | export class EffectMapConverter implements IConverter 9 | { 10 | private _effectMap: IEffectMap = null; 11 | 12 | constructor( 13 | private readonly _configuration: Configuration) 14 | {} 15 | 16 | public async convertAsync(): Promise 17 | { 18 | const now = Date.now(); 19 | const spinner = ora('Preparing EffectMap').start(); 20 | const url = this._configuration.getValue('effectmap.load.url'); 21 | const content = await FileUtilities.readFileAsString(url); 22 | 23 | this._effectMap = ((!content.startsWith('{')) ? await this.mapXML2JSON(await parseStringPromise(content.replace(/&/g,'&'))) : JSON.parse(content)); 24 | 25 | const directory = await FileUtilities.getDirectory('./assets/gamedata'); 26 | const path = directory.path + '/EffectMap.json'; 27 | 28 | await writeFile(path, JSON.stringify(this._effectMap), 'utf8'); 29 | 30 | spinner.succeed(`EffectMap: Finished in ${ Date.now() - now }ms`); 31 | } 32 | 33 | private async mapXML2JSON(xml: any): Promise 34 | { 35 | if(!xml) return null; 36 | 37 | const output: IEffectMap = {}; 38 | 39 | EffectMapMapper.mapXML(xml, output); 40 | 41 | return output; 42 | } 43 | 44 | public async getClassNamesAndRevisions(): Promise<{ [index: string]: string }> 45 | { 46 | const entries: { [index: string]: string } = {}; 47 | 48 | if(this._effectMap.effects) 49 | { 50 | for(const library of this._effectMap.effects) entries[library.lib] = '-1'; 51 | } 52 | 53 | return entries; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/ParticleSystemObjectXML.ts: -------------------------------------------------------------------------------- 1 | import { ParticleSystemEmitterXML } from './ParticleSystemEmitterXML'; 2 | 3 | export class ParticleSystemObjectXML 4 | { 5 | private readonly _size: number; 6 | private readonly _canvasId: number; 7 | private readonly _offsetY: number; 8 | private readonly _blend: number; 9 | private readonly _bgColor: string; 10 | private readonly _emitters: ParticleSystemEmitterXML[]; 11 | 12 | constructor(xml: any) 13 | { 14 | const attributes = xml.$; 15 | 16 | if(attributes !== undefined) 17 | { 18 | if(attributes.size !== undefined) this._size = parseInt(attributes.size); 19 | if(attributes.canvas_id !== undefined) this._canvasId = parseInt(attributes.canvas_id); 20 | if(attributes.offset_y !== undefined) this._offsetY = parseFloat(attributes.offset_y); 21 | if(attributes.blend !== undefined) this._blend = parseFloat(attributes.blend); 22 | if(attributes.bgcolor !== undefined) this._bgColor = attributes.bgcolor; 23 | } 24 | 25 | if((xml.emitter !== undefined) && Array.isArray(xml.emitter)) 26 | { 27 | this._emitters = []; 28 | 29 | for(const emitter of xml.emitter) this._emitters.push(new ParticleSystemEmitterXML(emitter)); 30 | } 31 | } 32 | 33 | public get size(): number 34 | { 35 | return this._size; 36 | } 37 | 38 | public get canvasId(): number 39 | { 40 | return this._canvasId; 41 | } 42 | 43 | public get offsetY(): number 44 | { 45 | return this._offsetY; 46 | } 47 | 48 | public get blend(): number 49 | { 50 | return this._blend; 51 | } 52 | 53 | public get bgColor(): string 54 | { 55 | return this._bgColor; 56 | } 57 | 58 | public get emitters(): ParticleSystemEmitterXML[] 59 | { 60 | return this._emitters; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/LayerXML.ts: -------------------------------------------------------------------------------- 1 | export class LayerXML 2 | { 3 | private readonly _id: number; 4 | private readonly _alpha: number; 5 | private readonly _x: number; 6 | private readonly _y: number; 7 | private readonly _z: number; 8 | private readonly _ink: string; 9 | private readonly _tag: string; 10 | private readonly _ignoreMouse: boolean; 11 | 12 | constructor(xml: any) 13 | { 14 | const attributes = xml.$; 15 | 16 | if(attributes !== undefined) 17 | { 18 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 19 | if(attributes.alpha !== undefined) this._alpha = parseInt(attributes.alpha); 20 | if(attributes.x !== undefined) this._x = parseInt(attributes.x); 21 | if(attributes.y !== undefined) this._y = parseInt(attributes.y); 22 | if(attributes.z !== undefined) this._z = parseInt(attributes.z); 23 | if(attributes.ink !== undefined) this._ink = attributes.ink; 24 | if(attributes.tag !== undefined) this._tag = attributes.tag; 25 | 26 | if(attributes.ignoreMouse !== undefined) this._ignoreMouse = (attributes.ignoreMouse === '1'); 27 | } 28 | } 29 | 30 | public get id(): number 31 | { 32 | return this._id; 33 | } 34 | 35 | public get alpha(): number 36 | { 37 | return this._alpha; 38 | } 39 | 40 | public get x(): number 41 | { 42 | return this._x; 43 | } 44 | 45 | public get y(): number 46 | { 47 | return this._y; 48 | } 49 | 50 | public get z(): number 51 | { 52 | return this._z; 53 | } 54 | 55 | public get ink(): string 56 | { 57 | return this._ink; 58 | } 59 | 60 | public get tag(): string 61 | { 62 | return this._tag; 63 | } 64 | 65 | public get ignoreMouse(): boolean 66 | { 67 | return this._ignoreMouse; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/manifest/ManifestLibraryXML.ts: -------------------------------------------------------------------------------- 1 | import { ManifestLibraryAliasXML } from './ManifestLibraryAliasXML'; 2 | import { ManifestLibraryAssetXML } from './ManifestLibraryAssetXML'; 3 | 4 | export class ManifestLibraryXML 5 | { 6 | private readonly _name: string; 7 | private readonly _version: string; 8 | private readonly _assets: ManifestLibraryAssetXML[]; 9 | private readonly _aliases: ManifestLibraryAliasXML[]; 10 | 11 | constructor(xml: any) 12 | { 13 | const attributes = xml.$; 14 | 15 | if(attributes !== undefined) 16 | { 17 | if(attributes.name !== undefined) this._name = attributes.name; 18 | if(attributes.version !== undefined) this._version = attributes.version; 19 | } 20 | 21 | if((xml.assets !== undefined) && Array.isArray(xml.assets)) 22 | { 23 | this._assets = []; 24 | 25 | for(const assetParent of xml.assets) 26 | { 27 | if(Array.isArray(assetParent.asset)) for(const asset of assetParent.asset) this._assets.push(new ManifestLibraryAssetXML(asset)); 28 | } 29 | } 30 | 31 | if((xml.aliases !== undefined) && Array.isArray(xml.aliases)) 32 | { 33 | this._aliases = []; 34 | 35 | for(const aliasParent of xml.aliases) 36 | { 37 | if(Array.isArray(aliasParent.alias)) for(const alias of aliasParent.alias) this._aliases.push(new ManifestLibraryAliasXML(alias)); 38 | } 39 | } 40 | } 41 | 42 | public get name(): string 43 | { 44 | return this._name; 45 | } 46 | 47 | public get version(): string 48 | { 49 | return this._version; 50 | } 51 | 52 | public get assets(): ManifestLibraryAssetXML[] 53 | { 54 | return this._assets; 55 | } 56 | 57 | public get aliases(): ManifestLibraryAliasXML[] 58 | { 59 | return this._aliases; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/animation/AnimationLayerXML.ts: -------------------------------------------------------------------------------- 1 | import { FrameSequenceXML } from './FrameSequenceXML'; 2 | 3 | export class AnimationLayerXML 4 | { 5 | private readonly _id: number; 6 | private readonly _loopCount: number; 7 | private readonly _frameRepeat: number; 8 | private readonly _random: number; 9 | private readonly _randomStart: number; 10 | 11 | private readonly _frameSequences: FrameSequenceXML[]; 12 | 13 | constructor(xml: any) 14 | { 15 | const attributes = xml.$; 16 | 17 | if(attributes !== undefined) 18 | { 19 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 20 | if(attributes.loopCount !== undefined) this._loopCount = parseInt(attributes.loopCount); 21 | if(attributes.frameRepeat !== undefined) this._frameRepeat = parseInt(attributes.frameRepeat); 22 | if(attributes.random !== undefined) this._random = parseInt(attributes.random); 23 | if(attributes.randomStart !== undefined) this._randomStart = parseInt(attributes.randomStart); 24 | } 25 | 26 | if((xml.frameSequence !== undefined) && Array.isArray(xml.frameSequence)) 27 | { 28 | this._frameSequences = []; 29 | 30 | for(const frameSequence of xml.frameSequence) this._frameSequences.push(new FrameSequenceXML(frameSequence)); 31 | } 32 | } 33 | 34 | public get id(): number 35 | { 36 | return this._id; 37 | } 38 | 39 | public get loopCount(): number 40 | { 41 | return this._loopCount; 42 | } 43 | 44 | public get frameRepeat(): number 45 | { 46 | return this._frameRepeat; 47 | } 48 | 49 | public get random(): number 50 | { 51 | return this._random; 52 | } 53 | 54 | public get randomStart(): number 55 | { 56 | return this._randomStart; 57 | } 58 | 59 | public get frameSequences(): FrameSequenceXML[] 60 | { 61 | return this._frameSequences; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/assets/PaletteXML.ts: -------------------------------------------------------------------------------- 1 | export class PaletteXML 2 | { 3 | private readonly _id: number; 4 | private readonly _source: string; 5 | private readonly _master: boolean; 6 | private readonly _tags: string[]; 7 | private readonly _breed: number; 8 | private readonly _colorTag: number; 9 | private readonly _color1: string; 10 | private readonly _color2: string; 11 | 12 | constructor(xml: any) 13 | { 14 | const attributes = xml.$; 15 | 16 | if(attributes) 17 | { 18 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 19 | if(attributes.source !== undefined) this._source = attributes.source; 20 | if(attributes.master !== undefined) this._master = (attributes.master === 'true') ? true : false; 21 | if(attributes.tags !== undefined) this._tags = attributes.tags.split(','); 22 | if(attributes.breed !== undefined) this._breed = parseInt(attributes.breed); 23 | if(attributes.colortag !== undefined) this._colorTag = parseInt(attributes.colortag); 24 | if(attributes.color1 !== undefined) this._color1 = attributes.color1; 25 | if(attributes.color2 !== undefined) this._color2 = attributes.color2; 26 | } 27 | } 28 | 29 | public get id(): number 30 | { 31 | return this._id; 32 | } 33 | 34 | public get source(): string 35 | { 36 | return this._source; 37 | } 38 | 39 | public get master(): boolean 40 | { 41 | return this._master; 42 | } 43 | 44 | public get tags(): string[] 45 | { 46 | return this._tags; 47 | } 48 | 49 | public get breed(): number 50 | { 51 | return this._breed; 52 | } 53 | 54 | public get colorTag(): number 55 | { 56 | return this._colorTag; 57 | } 58 | 59 | public get color1(): string 60 | { 61 | return this._color1; 62 | } 63 | 64 | public get color2(): string 65 | { 66 | return this._color2; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/common/utils/CustomIterator.ts: -------------------------------------------------------------------------------- 1 | export class CustomIterator 2 | { 3 | private idx: number; 4 | private readonly top: number; 5 | private readonly keys: Array; 6 | private readonly arr: boolean; 7 | private readonly collection: Array; 8 | 9 | constructor(collection: Array) 10 | { 11 | if(this.dontIterate(collection)) 12 | { 13 | throw new Error('Oh you nasty man, I won\'t iterate over that (' + collection + ')!'); 14 | } 15 | 16 | this.arr = this.isArray(collection); 17 | this.idx = 0; 18 | this.top = 0; 19 | this.keys = []; 20 | if(this.arr) 21 | { 22 | this.top = collection.length; 23 | } 24 | else 25 | { 26 | for(const prop in collection) 27 | { 28 | this.keys.push(prop); 29 | } 30 | } 31 | 32 | this.collection = collection; 33 | } 34 | 35 | isArray(candidate: any) 36 | { 37 | return candidate && 38 | typeof candidate === 'object' && 39 | typeof candidate.length === 'number' && 40 | typeof candidate.splice === 'function' && 41 | // eslint-disable-next-line no-prototype-builtins 42 | !(candidate.propertyIsEnumerable('length')); 43 | } 44 | 45 | dontIterate(collection: any) 46 | { 47 | // put some checks chere for stuff that isn't iterable (yet) 48 | return (!collection || typeof collection === 'number' || typeof collection === 'boolean'); 49 | } 50 | 51 | public next(): TType 52 | { 53 | if(!this.hasNext()) 54 | { 55 | throw new Error('Oh you nasty man. I have no more elements.'); 56 | } 57 | const elem = this.arr ? this.collection[this.idx] : this.collection[this.keys[this.idx]]; 58 | ++this.idx; 59 | return elem; 60 | } 61 | 62 | public hasNext() 63 | { 64 | return this.arr ? this.idx <= this.top : this.idx <= this.keys.length; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/visualization/animation/AnimationXML.ts: -------------------------------------------------------------------------------- 1 | import { AnimationLayerXML } from './AnimationLayerXML'; 2 | 3 | export class AnimationXML 4 | { 5 | private readonly _id: number; 6 | private readonly _transitionTo: number; 7 | private readonly _transitionFrom: number; 8 | private readonly _immediateChangeFrom: string; 9 | private readonly _randomStart: boolean; 10 | private readonly _layers: AnimationLayerXML[]; 11 | 12 | constructor(xml: any) 13 | { 14 | const attributes = xml.$; 15 | 16 | if(attributes !== undefined) 17 | { 18 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 19 | if(attributes.transitionTo !== undefined) this._transitionTo = parseInt(attributes.transitionTo); 20 | if(attributes.transitionFrom !== undefined) this._transitionFrom = parseInt(attributes.transitionFrom); 21 | if(attributes.immediateChangeFrom !== undefined) this._immediateChangeFrom = attributes.immediateChangeFrom; 22 | if(attributes.randomStart !== undefined) this._randomStart = (attributes.randomStart === '1'); 23 | } 24 | 25 | if((xml.animationLayer !== undefined) && Array.isArray(xml.animationLayer)) 26 | { 27 | this._layers = []; 28 | 29 | for(const animationLayer of xml.animationLayer) this._layers.push(new AnimationLayerXML(animationLayer)); 30 | } 31 | } 32 | 33 | public get id(): number 34 | { 35 | return this._id; 36 | } 37 | 38 | public get transitionTo(): number 39 | { 40 | return this._transitionTo; 41 | } 42 | 43 | public get transitionFrom(): number 44 | { 45 | return this._transitionFrom; 46 | } 47 | 48 | public get immediateChangeFrom(): string 49 | { 50 | return this._immediateChangeFrom; 51 | } 52 | 53 | public get randomStart(): boolean 54 | { 55 | return this._randomStart; 56 | } 57 | 58 | public get layers(): AnimationLayerXML[] 59 | { 60 | return this._layers; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/PlanetSystemObjectXML.ts: -------------------------------------------------------------------------------- 1 | export class PlanetSystemObjectXML 2 | { 3 | private readonly _id: number; 4 | private readonly _name: string; 5 | private readonly _parent: string; 6 | private readonly _radius: number; 7 | private readonly _arcSpeed: number; 8 | private readonly _arcOffset: number; 9 | private readonly _blend: number; 10 | private readonly _height: number; 11 | 12 | constructor(xml: any) 13 | { 14 | const attributes = xml.$; 15 | 16 | if(attributes !== undefined) 17 | { 18 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 19 | if(attributes.name !== undefined) this._name = attributes.name; 20 | if(attributes.parent !== undefined) this._parent = attributes.parent; 21 | if(attributes.radius !== undefined) this._radius = parseFloat(attributes.radius); 22 | if(attributes.arcspeed !== undefined) this._arcSpeed = parseFloat(attributes.arcspeed); 23 | if(attributes.arcoffset !== undefined) this._arcOffset = parseFloat(attributes.arcoffset); 24 | if(attributes.blend !== undefined) this._blend = parseFloat(attributes.blend); 25 | if(attributes.height !== undefined) this._height = parseFloat(attributes.height); 26 | } 27 | } 28 | 29 | public get id(): number 30 | { 31 | return this._id; 32 | } 33 | 34 | public get name(): string 35 | { 36 | return this._name; 37 | } 38 | 39 | public get parent(): string 40 | { 41 | return this._parent; 42 | } 43 | 44 | public get radius(): number 45 | { 46 | return this._radius; 47 | } 48 | 49 | public get arcSpeed(): number 50 | { 51 | return this._arcSpeed; 52 | } 53 | 54 | public get arcOffset(): number 55 | { 56 | return this._arcOffset; 57 | } 58 | 59 | public get blend(): number 60 | { 61 | return this._blend; 62 | } 63 | 64 | public get height(): number 65 | { 66 | return this._height; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/swf/GenerateSpritesheet.ts: -------------------------------------------------------------------------------- 1 | import { ImageBundle } from '../common'; 2 | import { HabboAssetSWF } from './HabboAssetSWF'; 3 | import { PackImages } from './PackImages'; 4 | 5 | export const IMAGE_SOURCES: Map = new Map(); 6 | 7 | export const GenerateSpriteSheet = async (habboAssetSWF: HabboAssetSWF, convertCase: boolean = false) => 8 | { 9 | const tagList = habboAssetSWF.symbolTags(); 10 | const names: string[] = []; 11 | const tags: number[] = []; 12 | 13 | let documentClass = habboAssetSWF.getDocumentClass(); 14 | 15 | if(convertCase) documentClass = (documentClass.replace(/(?:^|\.?)([A-Z])/g, (x,y) => ('_' + y.toLowerCase().replace(/^_/, '')))); 16 | 17 | for(const tag of tagList) 18 | { 19 | names.push(...tag.names); 20 | tags.push(...tag.tags); 21 | } 22 | 23 | const imageBundle = new ImageBundle(); 24 | 25 | const imageTags = habboAssetSWF.imageTags(); 26 | 27 | for(const imageTag of imageTags) 28 | { 29 | if(tags.includes(imageTag.characterId)) 30 | { 31 | for(let i = 0; i < tags.length; i++) 32 | { 33 | if(tags[i] != imageTag.characterId) continue; 34 | 35 | if(names[i] == imageTag.className) continue; 36 | 37 | if(imageTag.className.startsWith('sh_')) continue; 38 | 39 | if(imageTag.className.indexOf('_32_') >= 0) continue; 40 | 41 | IMAGE_SOURCES.set(names[i].substring(documentClass.length + 1), imageTag.className.substring(documentClass.length + 1)); 42 | } 43 | } 44 | 45 | if(imageTag.className.startsWith('sh_')) continue; 46 | 47 | if(imageTag.className.indexOf('_32_') >= 0) continue; 48 | 49 | let className = imageTag.className; 50 | 51 | if(convertCase) className = ((className.replace(/(?:^|\.?)([A-Z])/g, (x,y) => ('_' + y.toLowerCase().replace(/^_/, '')))).substring(1)); 52 | 53 | imageBundle.addImage(className, imageTag.imgData); 54 | } 55 | 56 | if(!imageBundle.images.length) return null; 57 | 58 | return await PackImages(documentClass, imageBundle, convertCase); 59 | }; 60 | -------------------------------------------------------------------------------- /src/converters/FigureMapConverter.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs/promises'; 2 | import ora from 'ora'; 3 | import { singleton } from 'tsyringe'; 4 | import { parseStringPromise } from 'xml2js'; 5 | import { Configuration, FigureMapMapper, FileUtilities, IConverter, IFigureMap } from '../common'; 6 | 7 | @singleton() 8 | export class FigureMapConverter implements IConverter 9 | { 10 | private _figureMap: IFigureMap = null; 11 | 12 | constructor( 13 | private readonly _configuration: Configuration) 14 | {} 15 | 16 | public async convertAsync(): Promise 17 | { 18 | const now = Date.now(); 19 | const spinner = ora('Preparing FigureMap').start(); 20 | const url = this._configuration.getValue('figuremap.load.url'); 21 | const content = await FileUtilities.readFileAsString(url); 22 | 23 | this._figureMap = ((!content.startsWith('{')) ? await this.mapXML2JSON(await parseStringPromise(content.replace(/&/g,'&'))) : JSON.parse(content)); 24 | 25 | const directory = await FileUtilities.getDirectory('./assets/gamedata'); 26 | const path = directory.path + '/FigureMap.json'; 27 | 28 | await writeFile(path, JSON.stringify(this._figureMap), 'utf8'); 29 | 30 | spinner.succeed(`FigureMap: Finished in ${ Date.now() - now }ms`); 31 | } 32 | 33 | private async mapXML2JSON(xml: any): Promise 34 | { 35 | if(!xml) return null; 36 | 37 | const output: IFigureMap = {}; 38 | 39 | FigureMapMapper.mapXML(xml, output); 40 | 41 | return output; 42 | } 43 | 44 | public async getClassNamesAndRevisions(): Promise<{ [index: string]: string }> 45 | { 46 | const entries: { [index: string]: string } = {}; 47 | 48 | if(this._figureMap.libraries) 49 | { 50 | for(const library of this._figureMap.libraries) 51 | { 52 | const className = library.id.split('*')[0]; 53 | 54 | if(className === 'hh_human_fx' || className === 'hh_pets') continue; 55 | 56 | entries[className] = '-1'; 57 | } 58 | } 59 | 60 | return entries; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataSetTypeXML.ts: -------------------------------------------------------------------------------- 1 | import { FigureDataSetXML } from './FigureDataSetXML'; 2 | 3 | export class FigureDataSetTypeXML 4 | { 5 | private _type: string; 6 | private _paletteId: number; 7 | private _mandatory_m_0: boolean; 8 | private _mandatory_f_0: boolean; 9 | private _mandatory_m_1: boolean; 10 | private _mandatory_f_1: boolean; 11 | private _sets: FigureDataSetXML[]; 12 | 13 | constructor(xml: any) 14 | { 15 | const attributes = xml.$; 16 | 17 | this._type = ((attributes && attributes.type) || ''); 18 | this._paletteId = ((attributes && parseInt(attributes.paletteid)) || 1); 19 | this._mandatory_m_0 = ((attributes && parseInt(attributes.mand_m_0) == 1) || false); 20 | this._mandatory_f_0 = ((attributes && parseInt(attributes.mand_f_0) == 1) || false); 21 | this._mandatory_m_1 = ((attributes && parseInt(attributes.mand_m_1) == 1) || false); 22 | this._mandatory_f_1 = ((attributes && parseInt(attributes.mand_f_1) == 1) || false); 23 | 24 | if(xml.set !== undefined) 25 | { 26 | if(Array.isArray(xml.set)) 27 | { 28 | this._sets = []; 29 | 30 | for(const index in xml.set) 31 | { 32 | const set = xml.set[index]; 33 | 34 | this._sets.push(new FigureDataSetXML(set)); 35 | } 36 | } 37 | } 38 | } 39 | 40 | public get type(): string 41 | { 42 | return this._type; 43 | } 44 | 45 | public get paletteId(): number 46 | { 47 | return this._paletteId; 48 | } 49 | 50 | public get mandatoryM0(): boolean 51 | { 52 | return this._mandatory_m_0; 53 | } 54 | 55 | public get mandatoryM1(): boolean 56 | { 57 | return this._mandatory_m_1; 58 | } 59 | 60 | public get mandatoryF0(): boolean 61 | { 62 | return this._mandatory_f_0; 63 | } 64 | 65 | public get mandatoryF1(): boolean 66 | { 67 | return this._mandatory_f_1; 68 | } 69 | 70 | public get sets(): FigureDataSetXML[] 71 | { 72 | return this._sets; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/common/bundle/NitroBundle.ts: -------------------------------------------------------------------------------- 1 | import ByteBuffer from 'bytebuffer'; 2 | import { Data, deflate, inflate } from 'pako'; 3 | import { BinaryReader } from '../utils'; 4 | 5 | export class NitroBundle 6 | { 7 | private readonly _files: Map; 8 | 9 | constructor() 10 | { 11 | this._files = new Map(); 12 | } 13 | 14 | public static from(buffer: ArrayBuffer): NitroBundle 15 | { 16 | const nitroBundle = new NitroBundle(); 17 | const binaryReader = new BinaryReader(buffer); 18 | 19 | let fileCount = binaryReader.readShort(); 20 | 21 | while(fileCount > 0) 22 | { 23 | const fileNameLength = binaryReader.readShort(); 24 | const fileName = binaryReader.readBytes(fileNameLength).toString(); 25 | const fileLength = binaryReader.readInt(); 26 | const buffer = binaryReader.readBytes(fileLength); 27 | const decompressed = inflate((buffer.toArrayBuffer() as Data)); 28 | 29 | nitroBundle.addFile(fileName, Buffer.from(decompressed.buffer)); 30 | 31 | fileCount--; 32 | } 33 | 34 | return nitroBundle; 35 | } 36 | 37 | public addFile(name: string, data: Buffer): void 38 | { 39 | this._files.set(name, data); 40 | } 41 | 42 | public async toBufferAsync(): Promise 43 | { 44 | const buffer = new ByteBuffer(); 45 | 46 | buffer.writeUint16(this._files.size); 47 | 48 | for(const file of this._files.entries()) 49 | { 50 | const fileName = file[0]; 51 | const fileBuffer = file[1]; 52 | 53 | buffer.writeUint16(fileName.length); 54 | buffer.writeString(fileName); 55 | 56 | const compressed = deflate(fileBuffer); 57 | buffer.writeUint32(compressed.length); 58 | buffer.append(compressed); 59 | } 60 | 61 | buffer.flip(); 62 | 63 | return buffer.toBuffer(); 64 | } 65 | 66 | public get files(): Map 67 | { 68 | return this._files; 69 | } 70 | 71 | public get totalFiles(): number 72 | { 73 | return this._files.size; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/common/utils/File.ts: -------------------------------------------------------------------------------- 1 | import { existsSync } from 'fs'; 2 | import { lstat, mkdir, readdir, readFile, writeFile } from 'fs/promises'; 3 | 4 | export class File 5 | { 6 | constructor(private readonly _path: string) 7 | {} 8 | 9 | public async createDirectory(): Promise 10 | { 11 | try 12 | { 13 | await mkdir(this._path, { recursive: true }); 14 | 15 | return true; 16 | } 17 | 18 | catch (error) 19 | { 20 | if(error.code && (error.code === 'EEXISTS')) return true; 21 | 22 | console.error(error); 23 | 24 | return false; 25 | } 26 | } 27 | 28 | public exists(): boolean 29 | { 30 | if(existsSync(this._path)) return true; 31 | 32 | return false; 33 | } 34 | 35 | public async getFileList(): Promise 36 | { 37 | try 38 | { 39 | return await readdir(this._path); 40 | } 41 | 42 | catch (error) 43 | { 44 | console.error(error); 45 | 46 | return null; 47 | } 48 | } 49 | 50 | public async isDirectory(): Promise 51 | { 52 | try 53 | { 54 | return (await lstat(this._path)).isDirectory(); 55 | } 56 | 57 | catch (error) 58 | { 59 | console.error(error); 60 | 61 | return false; 62 | } 63 | } 64 | 65 | public async getContentsAsBuffer(): Promise 66 | { 67 | try 68 | { 69 | return await readFile(this._path); 70 | } 71 | 72 | catch (error) 73 | { 74 | console.error(error); 75 | 76 | return null; 77 | } 78 | } 79 | 80 | public async writeData(data: string | Uint8Array): Promise 81 | { 82 | try 83 | { 84 | await writeFile(this._path, data); 85 | 86 | return true; 87 | } 88 | 89 | catch (error) 90 | { 91 | console.error(error); 92 | 93 | return false; 94 | } 95 | } 96 | 97 | public get path(): string 98 | { 99 | return this._path; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/FigureMapMapper.ts: -------------------------------------------------------------------------------- 1 | import { IFigureMap, IFigureMapLibrary, IFigureMapLibraryPart } from '../json'; 2 | import { FigureLibraryPartXML, FigureLibraryXML, FigureMapXML } from '../xml'; 3 | import { Mapper } from './asset'; 4 | 5 | export class FigureMapMapper extends Mapper 6 | { 7 | public static mapXML(xml: any, output: IFigureMap): void 8 | { 9 | if(!xml || !output) return; 10 | 11 | if(xml.map !== undefined) FigureMapMapper.mapFigureMapXML(new FigureMapXML(xml.map), output); 12 | } 13 | 14 | private static mapFigureMapXML(xml: FigureMapXML, output: IFigureMap): void 15 | { 16 | if(!xml || !output) return; 17 | 18 | if(xml.libraries !== undefined) 19 | { 20 | if(xml.libraries.length) 21 | { 22 | output.libraries = []; 23 | 24 | FigureMapMapper.mapFigureMapLibrariesXML(xml.libraries, output.libraries); 25 | } 26 | } 27 | } 28 | 29 | private static mapFigureMapLibrariesXML(xml: FigureLibraryXML[], output: IFigureMapLibrary[]): void 30 | { 31 | if(!xml || !xml.length || !output) return; 32 | 33 | for(const libraryXML of xml) 34 | { 35 | const library: IFigureMapLibrary = {}; 36 | 37 | if(libraryXML.id !== undefined) library.id = libraryXML.id; 38 | if(libraryXML.revision !== undefined) library.revision = libraryXML.revision; 39 | 40 | if(libraryXML.parts !== undefined) 41 | { 42 | if(libraryXML.parts.length) 43 | { 44 | library.parts = []; 45 | 46 | FigureMapMapper.mapFigureMapLibraryPartsXML(libraryXML.parts, library.parts); 47 | } 48 | } 49 | 50 | output.push(library); 51 | } 52 | } 53 | 54 | private static mapFigureMapLibraryPartsXML(xml: FigureLibraryPartXML[], output: IFigureMapLibraryPart[]): void 55 | { 56 | if(!xml || !xml.length || !output) return; 57 | 58 | for(const libraryPartXML of xml) 59 | { 60 | const libraryPart: IFigureMapLibraryPart = {}; 61 | 62 | if(libraryPartXML.id !== undefined) libraryPart.id = libraryPartXML.id; 63 | if(libraryPartXML.type !== undefined) libraryPart.type = libraryPartXML.type; 64 | 65 | output.push(libraryPart); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Main.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { container } from 'tsyringe'; 3 | import { FileUtilities } from './common'; 4 | import { Configuration } from './common/config/Configuration'; 5 | import { IConverter } from './common/converters/IConverter'; 6 | import { ConverterUtilities } from './converters/ConverterUtilities'; 7 | import { EffectMapConverter } from './converters/EffectMapConverter'; 8 | import { ExternalTextsConverter } from './converters/ExternalTextsConverter'; 9 | import { FigureDataConverter } from './converters/FigureDataConverter'; 10 | import { FigureMapConverter } from './converters/FigureMapConverter'; 11 | import { FurnitureDataConverter } from './converters/FurnitureDataConverter'; 12 | import { ProductDataConverter } from './converters/ProductDataConverter'; 13 | 14 | (async () => 15 | { 16 | try 17 | { 18 | const configurationContent = await FileUtilities.readFileAsString('./configuration.json'); 19 | const config = container.resolve(Configuration); 20 | 21 | await config.init(JSON.parse(configurationContent)); 22 | 23 | const converters = [ 24 | FurnitureDataConverter, 25 | FigureDataConverter, 26 | ProductDataConverter, 27 | ExternalTextsConverter, 28 | EffectMapConverter, 29 | FigureMapConverter 30 | ]; 31 | 32 | const bundle = (process.argv.indexOf('--bundle') >= 0); 33 | const extract = (process.argv.indexOf('--extract') >= 0); 34 | const convertSwf = (process.argv.indexOf('--convert-swf') >= 0); 35 | const skip = (bundle || extract || convertSwf); 36 | 37 | if (skip) 38 | { 39 | const extractor = container.resolve(ConverterUtilities); 40 | 41 | bundle && await extractor.bundleExtractedFromFolder(); 42 | extract && await extractor.extractNitroFromFolder(); 43 | convertSwf && await extractor.convertSwfFromFolder(); 44 | 45 | process.exit(); 46 | } 47 | 48 | for (const converterClass of converters) 49 | { 50 | const converter = (container.resolve(converterClass) as IConverter); 51 | 52 | await converter.convertAsync(); 53 | } 54 | 55 | const utilities = container.resolve(ConverterUtilities); 56 | 57 | await utilities.downloadSwfTypes(); 58 | 59 | process.exit(); 60 | } 61 | 62 | catch (e) 63 | { 64 | console.error(e); 65 | } 66 | })(); 67 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/animation/EffectFramePartXML.ts: -------------------------------------------------------------------------------- 1 | import { EffectFramePartItemXML } from './EffectFramePartItemXML'; 2 | 3 | export class EffectFramePartXML 4 | { 5 | private readonly _id: string; 6 | private readonly _frame: number; 7 | private readonly _base: string; 8 | private readonly _action: string; 9 | private readonly _dx: number; 10 | private readonly _dy: number; 11 | private readonly _dz: number; 12 | private readonly _dd: number; 13 | 14 | private readonly _items: EffectFramePartItemXML[]; 15 | 16 | constructor(xml: any) 17 | { 18 | const attributes = xml.$; 19 | 20 | if(attributes !== undefined) 21 | { 22 | if(attributes.id !== undefined) this._id = attributes.id; 23 | if(attributes.frame !== undefined) this._frame = parseInt(attributes.frame); 24 | if(attributes.base !== undefined) this._base = attributes.base; 25 | if(attributes.action !== undefined) this._action = attributes.action; 26 | if(attributes.dx !== undefined) this._dx = parseInt(attributes.dx); 27 | if(attributes.dy !== undefined) this._dy = parseInt(attributes.dy); 28 | if(attributes.dz !== undefined) this._dz = parseInt(attributes.dz); 29 | if(attributes.dd !== undefined) this._dd = parseInt(attributes.dd); 30 | } 31 | 32 | if(xml.item !== undefined) 33 | { 34 | if(Array.isArray(xml.item)) 35 | { 36 | this._items = []; 37 | 38 | for(const item of xml.item) this._items.push(new EffectFramePartItemXML(item)); 39 | } 40 | } 41 | } 42 | 43 | public get id(): string 44 | { 45 | return this._id; 46 | } 47 | 48 | public get frame(): number 49 | { 50 | return this._frame; 51 | } 52 | 53 | public get base(): string 54 | { 55 | return this._base; 56 | } 57 | 58 | public get action(): string 59 | { 60 | return this._action; 61 | } 62 | 63 | public get dx(): number 64 | { 65 | return this._dx; 66 | } 67 | 68 | public get dy(): number 69 | { 70 | return this._dy; 71 | } 72 | 73 | public get dz(): number 74 | { 75 | return this._dz; 76 | } 77 | 78 | public get dd(): number 79 | { 80 | return this._dd; 81 | } 82 | 83 | public get items(): EffectFramePartItemXML[] 84 | { 85 | return this._items; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/converters/ProductDataConverter.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs/promises'; 2 | import ora from 'ora'; 3 | import { singleton } from 'tsyringe'; 4 | import { Configuration, FileUtilities, IConverter, IProductData } from '../common'; 5 | 6 | @singleton() 7 | export class ProductDataConverter implements IConverter 8 | { 9 | public productData: IProductData = null; 10 | 11 | constructor( 12 | private readonly _configuration: Configuration) 13 | {} 14 | 15 | public async convertAsync(args: string[] = []): Promise 16 | { 17 | const now = Date.now(); 18 | const spinner = ora('Preparing ProductData').start(); 19 | const url = this._configuration.getValue('productdata.load.url'); 20 | const content = await FileUtilities.readFileAsString(url); 21 | 22 | this.productData = ((!content.startsWith('{')) ? await this.mapText2JSON(content) : JSON.parse(content)); 23 | 24 | const directory = await FileUtilities.getDirectory('./assets/gamedata'); 25 | const path = directory.path + '/ProductData.json'; 26 | 27 | await writeFile(path, JSON.stringify(this.productData), 'utf8'); 28 | 29 | spinner.succeed(`ProductData: Finished in ${ Date.now() - now }ms`); 30 | } 31 | 32 | private async mapText2JSON(text: string): Promise 33 | { 34 | if(!text) return null; 35 | 36 | const output: IProductData = { 37 | productdata: { 38 | product: [] 39 | } 40 | }; 41 | 42 | text = text.replace(/"{1,}/g, ''); 43 | 44 | const parts = text.split(/\n\r{1,}|\n{1,}|\r{1,}/mg); 45 | 46 | for(const part of parts) 47 | { 48 | const set = part.match(/\[+?((.)*?)\]/g); 49 | 50 | if(set) 51 | { 52 | for(const entry of set) 53 | { 54 | let value = entry.replace(/\[{1,}/mg, ''); 55 | value = entry.replace(/\]{1,}/mg, ''); 56 | 57 | value = value.replace('[[', ''); 58 | value = value.replace('[', ''); 59 | 60 | const pieces = value.split(','); 61 | const code = pieces.shift(); 62 | const name = pieces.shift(); 63 | const description = pieces.join(','); 64 | 65 | output.productdata.product.push({ code, name, description }); 66 | } 67 | } 68 | } 69 | 70 | return output; 71 | } 72 | 73 | public get converterType(): string 74 | { 75 | return 'ProductData'; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/swf/ReadImagesJPEG3or4.ts: -------------------------------------------------------------------------------- 1 | import * as concatFrames from 'concat-frames'; 2 | import decoder from 'jpg-stream/decoder'; 3 | import encoder from 'png-stream/encoder'; 4 | import { PassThrough } from 'stream'; 5 | import streamToArray from 'stream-to-array'; 6 | import { promisify } from 'util'; 7 | import { unzip } from 'zlib'; 8 | import { SlicedToArray } from '../common'; 9 | import { ISWFTag } from './common'; 10 | import { RecognizeImageHeader } from './RecognizeImageHeader'; 11 | 12 | export const ReadImagesJPEG3or4 = async (code: number, tag: Partial) => 13 | { 14 | const { characterId, imgData, bitmapAlphaData } = tag; 15 | const imgType = RecognizeImageHeader(imgData); 16 | 17 | if(imgType !== 'jpeg') return { code, characterId, imgType, imgData }; 18 | 19 | const pngEncoder = new encoder(undefined, undefined, { colorSpace: 'rgba' }); 20 | const alphaBufPre = await promisify(unzip)(bitmapAlphaData); 21 | 22 | let alphaBuffer: Buffer = null; 23 | 24 | if(alphaBufPre.length > 0) alphaBuffer = alphaBufPre; 25 | 26 | const bufferStream = new PassThrough(); 27 | 28 | bufferStream.end(imgData); 29 | 30 | bufferStream 31 | .pipe(new decoder()) 32 | .pipe(concatFrames.default((data: any) => 33 | { 34 | const _ref2 = SlicedToArray.slicedToArray(data, 1); 35 | const frame = _ref2[0]; 36 | 37 | const input = frame.pixels; 38 | const pCount = frame.width * frame.height; 39 | const output = Buffer.alloc(pCount * 4); 40 | 41 | if(alphaBuffer !== null && alphaBuffer.length !== pCount) 42 | { 43 | console.error('expect alphaBuf to have size ' + pCount + ' while getting ' + alphaBuffer.length); 44 | } 45 | 46 | const getAlphaBuffer = (i: any) => 47 | { 48 | if(!alphaBuffer) return 0xFF; 49 | 50 | return alphaBuffer[i]; 51 | }; 52 | 53 | for(let i = 0; i < pCount; ++i) 54 | { 55 | output[4 * i] = input[3 * i]; 56 | output[4 * i + 1] = input[3 * i + 1]; 57 | output[4 * i + 2] = input[3 * i + 2]; 58 | output[4 * i + 3] = getAlphaBuffer(i); 59 | } 60 | 61 | pngEncoder.format.width = frame.width; 62 | pngEncoder.format.height = frame.height; 63 | pngEncoder.end(output); 64 | })); 65 | 66 | const parts = await streamToArray(pngEncoder); 67 | const buffers = parts.map(part => Buffer.isBuffer(part) ? part : Buffer.from(part)); 68 | 69 | bufferStream.end(); 70 | 71 | return { 72 | code: code, 73 | characterId: characterId, 74 | imgType: 'png', 75 | imgData: Buffer.concat(buffers) 76 | }; 77 | }; 78 | -------------------------------------------------------------------------------- /src/swf/UncompressSWF.ts: -------------------------------------------------------------------------------- 1 | import * as lzma from 'lzma-purejs'; 2 | import { Stream } from 'stream'; 3 | import { promisify } from 'util'; 4 | import { unzip } from 'zlib'; 5 | import { ReadSWFBuff } from './ReadSWFBuffer'; 6 | import { SWFBuffer } from './SWFBuffer'; 7 | 8 | export const UncompressSWF = async (rawBuffer: Buffer) => 9 | { 10 | if(!Buffer.isBuffer(rawBuffer)) return null; 11 | 12 | let compressedBuffer = rawBuffer.slice(8); 13 | 14 | switch(rawBuffer[0]) 15 | { 16 | case 0x43: { // zlib compressed 17 | const buffer = await (promisify(unzip)(compressedBuffer)); 18 | 19 | if(!Buffer.isBuffer(buffer)) return null; 20 | 21 | return ReadSWFBuff(new SWFBuffer(buffer), rawBuffer); 22 | } 23 | case 0x46: // uncompressed 24 | return ReadSWFBuff(new SWFBuffer(rawBuffer), rawBuffer); 25 | case 0x5a: { // LZMA compressed 26 | const lzmaProperties = compressedBuffer.slice(4, 9); 27 | compressedBuffer = compressedBuffer.slice(9); 28 | 29 | const inputStream = new Stream(); 30 | 31 | let inputPos = 0; 32 | 33 | //@ts-ignore 34 | inputStream.readByte = () => 35 | { 36 | return inputPos >= compressedBuffer.length ? -1 : compressedBuffer[inputPos++]; 37 | }; 38 | 39 | const outputStream = new Stream(); 40 | 41 | let outputBuffer = Buffer.alloc(16384); 42 | let outputPos = 0; 43 | 44 | //@ts-ignore 45 | outputStream.writeByte = (_byte: number) => 46 | { 47 | if(outputPos >= outputBuffer.length) 48 | { 49 | const newBuffer = Buffer.alloc(outputBuffer.length * 2); 50 | 51 | outputBuffer.copy(newBuffer); 52 | outputBuffer = newBuffer; 53 | } 54 | 55 | outputBuffer[outputPos++] = _byte; 56 | 57 | return true; 58 | }; 59 | 60 | //@ts-ignore 61 | outputStream.getBuffer = () => 62 | { 63 | // trim buffer 64 | if(outputPos !== outputBuffer.length) 65 | { 66 | const newBuffer = Buffer.alloc(outputPos); 67 | outputBuffer.copy(newBuffer, 0, 0, outputPos); 68 | outputBuffer = newBuffer; 69 | } 70 | 71 | return outputBuffer; 72 | }; 73 | 74 | lzma.decompress(lzmaProperties, inputStream, outputStream, -1); 75 | 76 | //@ts-ignore 77 | const buffer = Buffer.concat([ rawBuffer.slice(0, 8), outputStream.getBuffer() ]); 78 | 79 | if(!Buffer.isBuffer(buffer)) return null; 80 | 81 | return ReadSWFBuff(new SWFBuffer(buffer), rawBuffer); 82 | } 83 | } 84 | 85 | return null; 86 | }; 87 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/particlesystem/ParticleSystemEmitterXML.ts: -------------------------------------------------------------------------------- 1 | import { ParticleSystemParticleXML } from './ParticleSystemParticleXML'; 2 | import { ParticleSystemSimulationXML } from './ParticleSystemSimulationXML'; 3 | 4 | export class ParticleSystemEmitterXML 5 | { 6 | private _id: number; 7 | private _name: string; 8 | private _spriteId: number; 9 | private _maxNumParticles: number; 10 | private _particlesPerFrame: number; 11 | private _burstPulse: number = 1; 12 | private _fuseTime: number; 13 | private _simulation: ParticleSystemSimulationXML; 14 | private _particles: ParticleSystemParticleXML[]; 15 | 16 | constructor(xml: any) 17 | { 18 | const attributes = xml.$; 19 | 20 | if(attributes !== undefined) 21 | { 22 | if(attributes.id !== undefined) this._id = parseInt(attributes.id); 23 | if(attributes.name !== undefined) this._name = attributes.name; 24 | if(attributes.sprite_id !== undefined) this._spriteId = parseInt(attributes.sprite_id); 25 | if(attributes.max_num_particles !== undefined) this._maxNumParticles = parseInt(attributes.max_num_particles); 26 | if(attributes.particles_per_frame !== undefined) this._particlesPerFrame = parseInt(attributes.particles_per_frame); 27 | if(attributes.burst_pulse !== undefined) this._burstPulse = parseInt(attributes.burst_pulse); 28 | if(attributes.fuse_time !== undefined) this._fuseTime = parseInt(attributes.fuse_time); 29 | } 30 | 31 | if(xml.simulation !== undefined) 32 | { 33 | if(xml.simulation[0] !== undefined) this._simulation = new ParticleSystemSimulationXML(xml.simulation[0]); 34 | } 35 | 36 | if((xml.particles !== undefined) && (xml.particles[0] !== undefined) && Array.isArray(xml.particles[0].particle)) 37 | { 38 | this._particles = []; 39 | 40 | for(const particle of xml.particles[0].particle) this._particles.push(new ParticleSystemParticleXML(particle)); 41 | } 42 | } 43 | 44 | public get id(): number 45 | { 46 | return this._id; 47 | } 48 | 49 | public get name(): string 50 | { 51 | return this._name; 52 | } 53 | 54 | public get spriteId(): number 55 | { 56 | return this._spriteId; 57 | } 58 | 59 | public get maxNumParticles(): number 60 | { 61 | return this._maxNumParticles; 62 | } 63 | 64 | public get particlesPerFrame(): number 65 | { 66 | return this._particlesPerFrame; 67 | } 68 | 69 | public get burstPulse(): number 70 | { 71 | return this._burstPulse; 72 | } 73 | 74 | public get fuseTime(): number 75 | { 76 | return this._fuseTime; 77 | } 78 | 79 | public get simulation(): ParticleSystemSimulationXML 80 | { 81 | return this._simulation; 82 | } 83 | 84 | public get particles(): ParticleSystemParticleXML[] 85 | { 86 | return this._particles; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/swf/ReadImagesDefineBitsLossless.ts: -------------------------------------------------------------------------------- 1 | import encoder from 'png-stream/encoder'; 2 | import streamToArray from 'stream-to-array'; 3 | import { promisify } from 'util'; 4 | import { unzip } from 'zlib'; 5 | import { ISWFTag } from './common'; 6 | 7 | export const ReadImagesDefineBitsLossless = async (tag: Partial) => 8 | { 9 | const { characterId, bitmapFormat, bitmapWidth, bitmapHeight, bitmapColorTableSize, zlibBitmapData } = tag; 10 | 11 | const pngEncoder = new encoder(bitmapWidth, bitmapHeight, { colorSpace: 'rgba' }); 12 | const dataBuf = await promisify(unzip)(zlibBitmapData); 13 | 14 | if(!dataBuf) return null; 15 | const output = Buffer.alloc(bitmapWidth * bitmapHeight * 4); 16 | 17 | let index = 0; 18 | let ptr = 0; 19 | 20 | switch(bitmapFormat) 21 | { 22 | case 5: { 23 | for(let y = 0; y < bitmapHeight; ++y) 24 | { 25 | for(let x = 0; x < bitmapWidth; ++x) 26 | { 27 | const alpha = dataBuf[ptr]; 28 | output[index] = dataBuf[ptr + 1] * (255 / alpha); 29 | output[index + 1] = dataBuf[ptr + 2] * (255 / alpha); 30 | output[index + 2] = dataBuf[ptr + 3] * (255 / alpha); 31 | output[index + 3] = alpha; 32 | index += 4; 33 | ptr += 4; 34 | } 35 | } 36 | 37 | break; 38 | } 39 | case 3: { 40 | // 8-bit colormapped image 41 | const colorMap = []; 42 | 43 | for(let i = 0; i < bitmapColorTableSize + 1; ++i) 44 | { 45 | colorMap.push([dataBuf[ptr], dataBuf[ptr + 1], dataBuf[ptr + 2], dataBuf[ptr + 3]]); 46 | 47 | ptr += 4; 48 | } 49 | 50 | for(let _y2 = 0; _y2 < bitmapHeight; ++_y2) 51 | { 52 | for(let _x2 = 0; _x2 < bitmapWidth; ++_x2) 53 | { 54 | const idx = dataBuf[ptr]; 55 | const color = idx < colorMap.length ? colorMap[idx] : [0, 0, 0, 0]; 56 | output[index] = color[0]; 57 | output[index + 1] = color[1]; 58 | output[index + 2] = color[2]; 59 | output[index + 3] = color[3]; 60 | ptr += 1; 61 | index += 4; 62 | } 63 | 64 | // skip padding 65 | ptr += (4 - bitmapWidth % 4) % 4; 66 | } 67 | 68 | break; 69 | } 70 | default: 71 | // reject(new Error('unhandled bitmapFormat: ' + bitmapFormat)); 72 | break; 73 | } 74 | 75 | pngEncoder.end(output); 76 | 77 | const parts = await streamToArray(pngEncoder); 78 | 79 | const buffers = parts.map(part => Buffer.isBuffer(part) ? part : Buffer.from(part)); 80 | 81 | return { 82 | code: 36, 83 | characterId: characterId, 84 | imgType: 'png', 85 | imgData: Buffer.concat(buffers), 86 | bitmapWidth: bitmapWidth, 87 | bitmapHeight: bitmapHeight 88 | }; 89 | }; 90 | -------------------------------------------------------------------------------- /src/converters/FurnitureDataConverter.ts: -------------------------------------------------------------------------------- 1 | import { writeFile } from 'fs/promises'; 2 | import ora from 'ora'; 3 | import { singleton } from 'tsyringe'; 4 | import { parseStringPromise } from 'xml2js'; 5 | import { Configuration, FileUtilities, FurnitureDataMapper, IConverter, IFurnitureData } from '../common'; 6 | 7 | @singleton() 8 | export class FurnitureDataConverter implements IConverter 9 | { 10 | public furnitureData: IFurnitureData = null; 11 | 12 | constructor( 13 | private readonly _configuration: Configuration) 14 | {} 15 | 16 | public async convertAsync(): Promise 17 | { 18 | const now = Date.now(); 19 | const spinner = ora('Preparing FurnitureData').start(); 20 | const url = this._configuration.getValue('furnidata.load.url'); 21 | const content = await FileUtilities.readFileAsString(url); 22 | 23 | this.furnitureData = ((!content.startsWith('{')) ? await this.mapXML2JSON(await parseStringPromise(content.replace(/&/g,'&'))) : JSON.parse(content)); 24 | 25 | const directory = await FileUtilities.getDirectory('./assets/gamedata'); 26 | const path = directory.path + '/FurnitureData.json'; 27 | 28 | await writeFile(path, JSON.stringify(this.furnitureData), 'utf8'); 29 | 30 | spinner.succeed(`FurnitureData: Finished in ${ Date.now() - now }ms`); 31 | } 32 | 33 | private async mapXML2JSON(xml: any): Promise 34 | { 35 | if(!xml) return null; 36 | 37 | const output: IFurnitureData = {}; 38 | 39 | FurnitureDataMapper.mapXML(xml, output); 40 | 41 | return output; 42 | } 43 | 44 | public async getClassNamesAndRevisions(floorOnly: boolean = false, wallOnly: boolean = false): Promise<{ [index: string]: string }> 45 | { 46 | if(!this.furnitureData) return null; 47 | 48 | const both = (!floorOnly && !wallOnly); 49 | const entries: { [index: string]: string } = {}; 50 | 51 | if((both || floorOnly) && this.furnitureData.roomitemtypes) 52 | { 53 | if(this.furnitureData.roomitemtypes.furnitype) 54 | { 55 | for(const furniType of this.furnitureData.roomitemtypes.furnitype) 56 | { 57 | const className = furniType.classname.split('*')[0]; 58 | const revision = furniType.revision; 59 | 60 | entries[className] = revision.toString(); 61 | } 62 | } 63 | } 64 | 65 | if((both || wallOnly) && this.furnitureData.wallitemtypes) 66 | { 67 | if(this.furnitureData.wallitemtypes.furnitype) 68 | { 69 | for(const furniType of this.furnitureData.wallitemtypes.furnitype) 70 | { 71 | const className = furniType.classname.split('*')[0]; 72 | const revision = furniType.revision; 73 | 74 | entries[className] = revision.toString(); 75 | } 76 | } 77 | } 78 | 79 | return entries; 80 | } 81 | 82 | public get converterType(): string 83 | { 84 | return 'FurnitureData'; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/common/mapping/xml/figuredata/FigureDataSetXML.ts: -------------------------------------------------------------------------------- 1 | import { FigureDataHiddenLayerXML } from './FigureDataHiddenLayerXML'; 2 | import { FigureDataPartXML } from './FigureDataPartXML'; 3 | 4 | export class FigureDataSetXML 5 | { 6 | private _id: number; 7 | private _gender: string; 8 | private _club: number; 9 | private _colorable: boolean; 10 | private _selectable: boolean; 11 | private _preselectable: boolean; 12 | private _sellable: boolean; 13 | private _parts: FigureDataPartXML[]; 14 | private _hiddenLayers: FigureDataHiddenLayerXML[]; 15 | 16 | constructor(xml: any) 17 | { 18 | const attributes = xml.$; 19 | 20 | this._id = ((attributes && parseInt(attributes.id)) || 0); 21 | this._gender = ((attributes && attributes.gender) || ''); 22 | this._club = ((attributes && parseInt(attributes.club)) || 0); 23 | this._colorable = ((attributes && parseInt(attributes.colorable) === 1) || false); 24 | this._selectable = ((attributes && parseInt(attributes.selectable) === 1) || false); 25 | this._preselectable = ((attributes && parseInt(attributes.preselectable) === 1) || false); 26 | this._sellable = ((attributes && parseInt(attributes.sellable) === 1) || false); 27 | 28 | if(xml.part !== undefined) 29 | { 30 | if(Array.isArray(xml.part)) 31 | { 32 | this._parts = []; 33 | 34 | for(const index in xml.part) 35 | { 36 | const part = xml.part[index]; 37 | 38 | this._parts.push(new FigureDataPartXML(part)); 39 | } 40 | } 41 | } 42 | 43 | if(xml.hiddenlayers !== undefined) 44 | { 45 | this._hiddenLayers = []; 46 | 47 | for(const hiddenLayer of xml.hiddenlayers) 48 | { 49 | const layers = hiddenLayer.layer; 50 | 51 | if(layers !== undefined) 52 | { 53 | if(Array.isArray(layers)) for(const layer of layers) this._hiddenLayers.push(new FigureDataHiddenLayerXML(layer)); 54 | } 55 | } 56 | } 57 | } 58 | 59 | public get id(): number 60 | { 61 | return this._id; 62 | } 63 | 64 | public get gender(): string 65 | { 66 | return this._gender; 67 | } 68 | 69 | public get club(): number 70 | { 71 | return this._club; 72 | } 73 | 74 | public get colorable(): boolean 75 | { 76 | return this._colorable; 77 | } 78 | 79 | public get selectable(): boolean 80 | { 81 | return this._selectable; 82 | } 83 | 84 | public get preselectable(): boolean 85 | { 86 | return this._preselectable; 87 | } 88 | 89 | public get sellable(): boolean 90 | { 91 | return this._sellable; 92 | } 93 | 94 | public get parts(): FigureDataPartXML[] 95 | { 96 | return this._parts; 97 | } 98 | 99 | public get hiddenLayers(): FigureDataHiddenLayerXML[] 100 | { 101 | return this._hiddenLayers; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/swf/SWFTags.ts: -------------------------------------------------------------------------------- 1 | export class SWFTags 2 | { 3 | public static End: number = 0; 4 | public static ShowFrame: number = 1; 5 | public static DefineShape: number = 2; 6 | public static PlaceObject: number = 4; 7 | public static RemoveObject: number = 5; 8 | public static DefineBits: number = 6; 9 | public static DefineButton: number = 7; 10 | public static JPEGTables: number = 8; 11 | public static SetBackgroundColor: number = 9; 12 | public static DefineFont: number = 10; 13 | public static DefineText: number = 11; 14 | public static DoAction: number = 12; 15 | public static DefineFontInfo: number = 13; 16 | public static DefineSound: number = 14; 17 | public static StartSound: number = 15; 18 | public static DefineButtonSound: number = 17; 19 | public static SoundStreamHead: number = 18; 20 | public static SoundStreamBlock: number = 19; 21 | public static DefineBitsLossless: number = 20; 22 | public static DefineBitsJPEG2: number = 21; 23 | public static DefineShape2: number = 22; 24 | public static DefineButtonCxform: number = 23; 25 | public static Protect: number = 24; 26 | public static PlaceObject2: number = 26; 27 | public static RemoveObject2: number = 28; 28 | public static DefineShape3: number = 32; 29 | public static DefineText2: number = 33; 30 | public static DefineButton2: number = 34; 31 | public static DefineBitsJPEG3: number = 35; 32 | public static DefineBitsLossless2: number = 36; 33 | public static DefineEditText: number = 37; 34 | public static DefineSprite: number = 39; 35 | public static SerialNumber: number = 41; 36 | public static FrameLabel: number = 43; 37 | public static SoundStreamHead2: number = 45; 38 | public static DefineMorphShape: number = 46; 39 | public static DefineFont2: number = 48; 40 | public static ExportAssets: number = 56; 41 | public static ImportAssets: number = 57; 42 | public static EnableDebugger: number = 58; 43 | public static DoInitAction: number = 59; 44 | public static DefineVideoStream: number = 60; 45 | public static VideoFrame: number = 61; 46 | public static DefineFontInfo2: number = 62; 47 | public static EnableDebugger2: number = 64; 48 | public static ScriptLimits: number = 65; 49 | public static SetTabIndex: number = 66; 50 | public static FileAttributes: number = 69; 51 | public static PlaceObject3: number = 70; 52 | public static ImportAssets2: number = 71; 53 | public static DefineFontAlignZones: number = 73; 54 | public static CSMTextSettings: number = 74; 55 | public static DefineFont3: number = 75; 56 | public static SymbolClass: number = 76; 57 | public static Metadata: number = 77; 58 | public static DefineScalingGrid: number = 78; 59 | public static DoABC: number = 82; 60 | public static DefineShape4: number = 83; 61 | public static DefineMorphShape2: number = 84; 62 | public static DefineSceneAndFrameLabelData: number = 86; 63 | public static DefineBinaryData: number = 87; 64 | public static DefineFontName: number = 88; 65 | public static StartSound2: number = 89; 66 | public static DefineBitsJPEG4: number = 90; 67 | public static DefineFont4: number = 91; 68 | } 69 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/FurnitureDataMapper.ts: -------------------------------------------------------------------------------- 1 | import { IFurnitureData, IFurnitureType } from '../json'; 2 | import { FurnitureDataXML, FurnitureTypeXML } from '../xml'; 3 | import { Mapper } from './asset'; 4 | 5 | export class FurnitureDataMapper extends Mapper 6 | { 7 | public static mapXML(xml: any, output: IFurnitureData): void 8 | { 9 | if(!xml || !output) return; 10 | 11 | if(xml.furnidata !== undefined) FurnitureDataMapper.mapFurnitureDataXML(new FurnitureDataXML(xml.furnidata), output); 12 | } 13 | 14 | private static mapFurnitureDataXML(xml: FurnitureDataXML, output: IFurnitureData): void 15 | { 16 | if(!xml || !output) return; 17 | 18 | if(xml.floorItems !== undefined) 19 | { 20 | if(xml.floorItems.length) 21 | { 22 | output.roomitemtypes = { 23 | furnitype: [] 24 | }; 25 | 26 | FurnitureDataMapper.mapFurnitureTypesXML(xml.floorItems, output.roomitemtypes.furnitype, 'floor'); 27 | } 28 | } 29 | 30 | if(xml.wallItems !== undefined) 31 | { 32 | if(xml.wallItems.length) 33 | { 34 | output.wallitemtypes = { 35 | furnitype: [] 36 | }; 37 | 38 | FurnitureDataMapper.mapFurnitureTypesXML(xml.wallItems, output.wallitemtypes.furnitype, 'wall'); 39 | } 40 | } 41 | } 42 | 43 | private static mapFurnitureTypesXML(xml: FurnitureTypeXML[], output: IFurnitureType[], type: string): void 44 | { 45 | if(!xml || !xml.length || !output) return; 46 | 47 | for(const typeXML of xml) 48 | { 49 | const furnitureType: IFurnitureType = {}; 50 | 51 | furnitureType.id = typeXML.id; 52 | furnitureType.classname = typeXML.classname; 53 | furnitureType.revision = typeXML.revision; 54 | furnitureType.category = typeXML.category; 55 | 56 | if(type === 'floor') 57 | { 58 | furnitureType.defaultdir = typeXML.defaultdir; 59 | furnitureType.xdim = typeXML.xdim; 60 | furnitureType.ydim = typeXML.ydim; 61 | furnitureType.partcolors = typeXML.partcolors; 62 | } 63 | 64 | furnitureType.name = typeXML.name; 65 | furnitureType.description = typeXML.description; 66 | furnitureType.adurl = typeXML.adurl; 67 | furnitureType.offerid = typeXML.offerid; 68 | furnitureType.buyout = typeXML.buyout; 69 | furnitureType.rentofferid = typeXML.rentofferid; 70 | furnitureType.rentbuyout = typeXML.rentbuyout; 71 | furnitureType.bc = typeXML.bc; 72 | furnitureType.excludeddynamic = typeXML.excludeddynamic; 73 | furnitureType.customparams = typeXML.customparams; 74 | furnitureType.specialtype = typeXML.specialtype; 75 | 76 | if(type === 'floor') 77 | { 78 | furnitureType.canstandon = typeXML.canstandon; 79 | furnitureType.cansiton = typeXML.cansiton; 80 | furnitureType.canlayon = typeXML.canlayon; 81 | } 82 | 83 | furnitureType.furniline = typeXML.furniline; 84 | furnitureType.environment = typeXML.environment; 85 | furnitureType.rare = typeXML.rare; 86 | 87 | output.push(furnitureType); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/common/mapping/xml/asset/logic/LogicXML.ts: -------------------------------------------------------------------------------- 1 | import { ActionXML } from './ActionXML'; 2 | import { CreditsXML } from './CreditsXML'; 3 | import { CustomVarsXML } from './CustomVarsXML'; 4 | import { MaskXML } from './MaskXML'; 5 | import { ModelXML } from './model'; 6 | import { ParticleSystemXML } from './particlesystem'; 7 | import { PlanetSystemXML } from './PlanetSystemXML'; 8 | import { SoundSampleXML } from './SoundSampleXML'; 9 | 10 | export class LogicXML 11 | { 12 | private readonly _type: string; 13 | private readonly _model: ModelXML; 14 | private readonly _action: ActionXML; 15 | private readonly _mask: MaskXML; 16 | private readonly _credits: CreditsXML; 17 | private readonly _soundSample: SoundSampleXML; 18 | private readonly _planetSystem: PlanetSystemXML; 19 | private readonly _particleSystem: ParticleSystemXML; 20 | private readonly _customVars: CustomVarsXML; 21 | 22 | constructor(xml: any) 23 | { 24 | const attributes = xml.$; 25 | 26 | if(attributes !== undefined) 27 | { 28 | if(attributes.type !== undefined) this._type = attributes.type; 29 | } 30 | 31 | if(xml.model !== undefined) 32 | { 33 | if(xml.model[0] !== undefined) this._model = new ModelXML(xml.model[0]); 34 | } 35 | 36 | if(xml.action !== undefined) 37 | { 38 | if(xml.action[0] !== undefined) this._action = new ActionXML(xml.action[0]); 39 | } 40 | 41 | if(xml.mask !== undefined) 42 | { 43 | if(xml.mask[0] !== undefined) this._mask = new MaskXML(xml.mask[0]); 44 | } 45 | 46 | if(xml.credits !== undefined) 47 | { 48 | if(xml.credits[0] !== undefined) this._credits = new CreditsXML(xml.credits[0]); 49 | } 50 | 51 | if(xml.sound !== undefined) 52 | { 53 | if(xml.sound[0] !== undefined) this._soundSample = new SoundSampleXML(xml.sound[0].sample[0]); 54 | } 55 | 56 | if(xml.planetsystem !== undefined) 57 | { 58 | if(xml.planetsystem[0] !== undefined) this._planetSystem = new PlanetSystemXML(xml.planetsystem[0]); 59 | } 60 | 61 | if(xml.particlesystems !== undefined) 62 | { 63 | if(xml.particlesystems[0] !== undefined) this._particleSystem = new ParticleSystemXML(xml.particlesystems[0]); 64 | } 65 | 66 | if(xml.customvars !== undefined) 67 | { 68 | if(xml.customvars[0] !== undefined) this._customVars = new CustomVarsXML(xml.customvars[0]); 69 | } 70 | } 71 | 72 | public get type(): string 73 | { 74 | return this._type; 75 | } 76 | 77 | public get model(): ModelXML 78 | { 79 | return this._model; 80 | } 81 | 82 | public get action(): ActionXML 83 | { 84 | return this._action; 85 | } 86 | 87 | public get mask(): MaskXML 88 | { 89 | return this._mask; 90 | } 91 | 92 | public get credits(): CreditsXML 93 | { 94 | return this._credits; 95 | } 96 | 97 | public get soundSample(): SoundSampleXML 98 | { 99 | return this._soundSample; 100 | } 101 | 102 | public get planetSystem(): PlanetSystemXML 103 | { 104 | return this._planetSystem; 105 | } 106 | 107 | public get particleSystem(): ParticleSystemXML 108 | { 109 | return this._particleSystem; 110 | } 111 | 112 | public get customVars(): CustomVarsXML 113 | { 114 | return this._customVars; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/asset/AssetMapper.ts: -------------------------------------------------------------------------------- 1 | import { IMAGE_SOURCES } from '../../../../swf'; 2 | import { IAsset, IAssetData, IAssetPalette } from '../../json'; 3 | import { AssetsXML, AssetXML, PaletteXML } from '../../xml'; 4 | import { Mapper } from './Mapper'; 5 | 6 | export class AssetMapper extends Mapper 7 | { 8 | public static mapXML(assets: any, output: IAssetData): void 9 | { 10 | if(!assets || !output) return; 11 | 12 | AssetMapper.mapAssetsXML(new AssetsXML(assets.assets), output); 13 | } 14 | 15 | private static mapAssetsXML(xml: AssetsXML, output: IAssetData): void 16 | { 17 | if(!xml || !output) return; 18 | 19 | if(xml.assets !== undefined) 20 | { 21 | if(xml.assets.length) 22 | { 23 | output.assets = {}; 24 | 25 | AssetMapper.mapAssetsAssetXML(xml.assets, output.assets); 26 | } 27 | } 28 | 29 | if(xml.palettes !== undefined) 30 | { 31 | if(xml.palettes.length) 32 | { 33 | output.palettes = {}; 34 | 35 | AssetMapper.mapAssetsPaletteXML(xml.palettes, output.palettes); 36 | } 37 | } 38 | } 39 | 40 | private static mapAssetsAssetXML(xml: AssetXML[], output: { [index: string]: IAsset }): void 41 | { 42 | if(!xml || !xml.length || !output) return; 43 | 44 | for(const assetXML of xml) 45 | { 46 | const asset: IAsset = {}; 47 | 48 | if(assetXML.name !== undefined) 49 | { 50 | if(assetXML.name.startsWith('sh_')) continue; 51 | 52 | if(assetXML.name.indexOf('_32_') >= 0) continue; 53 | 54 | if(assetXML.source !== undefined) 55 | { 56 | asset.source = assetXML.source; 57 | 58 | if(IMAGE_SOURCES.has(assetXML.source)) asset.source = IMAGE_SOURCES.get(assetXML.source) as string; 59 | } 60 | 61 | if(assetXML.name !== undefined) 62 | { 63 | if(IMAGE_SOURCES.has(assetXML.name)) asset.source = IMAGE_SOURCES.get(assetXML.name) as string; 64 | } 65 | 66 | if(assetXML.x !== undefined) asset.x = assetXML.x; 67 | if(assetXML.y !== undefined) asset.y = assetXML.y; 68 | if(assetXML.flipH !== undefined) asset.flipH = assetXML.flipH; 69 | if(assetXML.flipV !== undefined) asset.flipV = assetXML.flipV; 70 | if(assetXML.usesPalette !== undefined) asset.usesPalette = assetXML.usesPalette; 71 | 72 | output[assetXML.name] = asset; 73 | } 74 | } 75 | } 76 | 77 | private static mapAssetsPaletteXML(xml: PaletteXML[], output: { [index: string]: IAssetPalette }): void 78 | { 79 | if(!xml || !xml.length || !output) return; 80 | 81 | for(const paletteXML of xml) 82 | { 83 | const palette: IAssetPalette = {}; 84 | 85 | if(paletteXML.id !== undefined) palette.id = paletteXML.id; 86 | if(paletteXML.source !== undefined) palette.source = paletteXML.source; 87 | if(paletteXML.master !== undefined) palette.master = paletteXML.master; 88 | if(paletteXML.tags !== undefined) palette.tags = paletteXML.tags; 89 | if(paletteXML.breed !== undefined) palette.breed = paletteXML.breed; 90 | if(paletteXML.colorTag !== undefined) palette.colorTag = paletteXML.colorTag; 91 | if(paletteXML.color1 !== undefined) palette.color1 = paletteXML.color1; 92 | if(paletteXML.color2 !== undefined) palette.color2 = paletteXML.color2; 93 | 94 | output[paletteXML.id.toString()] = palette; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": [ 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "ecmaVersion": 12, 14 | "sourceType": "module" 15 | }, 16 | "plugins": [ 17 | "@typescript-eslint" 18 | ], 19 | "rules": { 20 | "indent": [ 21 | "error", 22 | 4, 23 | { 24 | "SwitchCase": 1 25 | } 26 | ], 27 | "no-trailing-spaces": [ 28 | "error", 29 | { 30 | "skipBlankLines": false, 31 | "ignoreComments": true 32 | } 33 | ], 34 | "linebreak-style": [ 35 | "off" 36 | ], 37 | "quotes": [ 38 | "error", 39 | "single" 40 | ], 41 | "semi": [ 42 | "error", 43 | "always" 44 | ], 45 | "brace-style": [ 46 | "error", 47 | "allman" 48 | ], 49 | "object-curly-spacing": [ 50 | "error", 51 | "always" 52 | ], 53 | "keyword-spacing": [ 54 | "error", 55 | { 56 | "overrides": 57 | { 58 | "if": 59 | { 60 | "after": false 61 | }, 62 | "for": 63 | { 64 | "after": false 65 | }, 66 | "while": 67 | { 68 | "after": false 69 | }, 70 | "switch": 71 | { 72 | "after": false 73 | } 74 | } 75 | } 76 | ], 77 | "@typescript-eslint/no-explicit-any": [ 78 | "off" 79 | ], 80 | "@typescript-eslint/explicit-module-boundary-types": [ 81 | "off", 82 | { 83 | "allowedNames": [ 84 | "getMessageArray" 85 | ] 86 | } 87 | ], 88 | "@typescript-eslint/ban-ts-comment": [ 89 | "off" 90 | ], 91 | "@typescript-eslint/no-empty-function": [ 92 | "error", 93 | { 94 | "allow": [ 95 | "functions", 96 | "arrowFunctions", 97 | "generatorFunctions", 98 | "methods", 99 | "generatorMethods", 100 | "constructors" 101 | ] 102 | } 103 | ], 104 | "@typescript-eslint/no-unused-vars": [ 105 | "off" 106 | ], 107 | "@typescript-eslint/no-inferrable-types": [ 108 | "error", 109 | { 110 | "ignoreParameters": true, 111 | "ignoreProperties": true 112 | } 113 | ], 114 | "@typescript-eslint/ban-types": [ 115 | "error", 116 | { 117 | "types": 118 | { 119 | "String": true, 120 | "Boolean": true, 121 | "Number": true, 122 | "Symbol": true, 123 | "{}": false, 124 | "Object": false, 125 | "object": false, 126 | "Function": false 127 | }, 128 | "extendDefaults": true 129 | } 130 | ] 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/common/config/Configuration.ts: -------------------------------------------------------------------------------- 1 | import { singleton } from 'tsyringe'; 2 | import { FileUtilities } from '../utils'; 3 | 4 | @singleton() 5 | export class Configuration 6 | { 7 | private readonly _config: Map; 8 | 9 | constructor() 10 | { 11 | this._config = new Map(); 12 | } 13 | 14 | public async init(configuration: Object): Promise 15 | { 16 | this.parseConfiguration(configuration); 17 | 18 | await this.loadExternalVariables(); 19 | 20 | this.parseConfiguration(configuration); 21 | } 22 | 23 | public async loadExternalVariables(): Promise 24 | { 25 | const url = this.getValue('external.variables.url'); 26 | 27 | try 28 | { 29 | const content = await FileUtilities.readFileAsString(url); 30 | 31 | this.parseExternalVariables(content); 32 | } 33 | 34 | catch (error) 35 | { 36 | console.log(); 37 | console.error(error); 38 | } 39 | } 40 | 41 | private parseConfiguration(content: Object): boolean 42 | { 43 | if (!content) return false; 44 | 45 | try 46 | { 47 | const regex = new RegExp(/\${(.*?)}/g); 48 | 49 | for (const key of Object.keys(content)) 50 | { 51 | if (this._config.get(key)) 52 | { 53 | if (!content[key].length) continue; 54 | } 55 | 56 | this._config.set(key, this.interpolate(content[key], regex)); 57 | } 58 | 59 | return true; 60 | } 61 | 62 | catch (e) 63 | { 64 | console.log(); 65 | console.error(e); 66 | 67 | return false; 68 | } 69 | } 70 | 71 | private parseExternalVariables(content: string): boolean 72 | { 73 | if (!content || (content === '')) return false; 74 | 75 | try 76 | { 77 | const regex = new RegExp(/\${(.*?)}/g); 78 | const lines: string[] = content.split('\n'); 79 | 80 | for (const line of lines) 81 | { 82 | const [key, value] = line.split('='); 83 | 84 | if (key.startsWith('landing.view')) continue; 85 | 86 | this._config.set(key, this.interpolate((value || ''), regex)); 87 | } 88 | 89 | return true; 90 | } 91 | 92 | catch (e) 93 | { 94 | console.log(); 95 | console.error(e); 96 | 97 | return false; 98 | } 99 | } 100 | 101 | public interpolate(value: string, regex: RegExp = null): string 102 | { 103 | if (!value || (typeof value === 'object')) return value; 104 | if (!regex) regex = new RegExp(/\${(.*?)}/g); 105 | 106 | const pieces = value.match(regex); 107 | 108 | if (pieces && pieces.length) 109 | { 110 | for (const piece of pieces) 111 | { 112 | const existing = this._config.get(this.removeInterpolateKey(piece)); 113 | 114 | if (existing) (value = value.replace(piece, existing)); 115 | } 116 | } 117 | 118 | return value; 119 | } 120 | 121 | private removeInterpolateKey(value: string): string 122 | { 123 | return value.replace('${', '').replace('}', ''); 124 | } 125 | 126 | public getValue(key: string, value: string = ''): string 127 | { 128 | if (this._config.has(key)) return this._config.get(key); 129 | 130 | return value; 131 | } 132 | 133 | public setValue(key: string, value: string): void 134 | { 135 | this._config.set(key, value); 136 | } 137 | 138 | public getBoolean(key: string): boolean 139 | { 140 | const value = this.getValue(key); 141 | 142 | return ((value === 'true') || (value === '1')); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/common/mapping/mappers/asset/ManifestMapper.ts: -------------------------------------------------------------------------------- 1 | import { IMAGE_SOURCES } from '../../../../swf'; 2 | import { IAsset, IAssetAlias, IAssetData } from '../../json'; 3 | import { ManifestLibraryAliasXML, ManifestLibraryAssetParamXML, ManifestLibraryAssetXML, ManifestLibraryXML, ManifestXML } from '../../xml'; 4 | import { Mapper } from './Mapper'; 5 | 6 | export class ManifestMapper extends Mapper 7 | { 8 | public static mapXML(manifest: any, output: IAssetData): void 9 | { 10 | if(!manifest || !output) return; 11 | 12 | ManifestMapper.mapManifestXML(new ManifestXML(manifest.manifest), output); 13 | } 14 | 15 | private static mapManifestXML(xml: ManifestXML, output: IAssetData): void 16 | { 17 | if(!xml || !output) return; 18 | 19 | if(xml.library !== undefined) ManifestMapper.mapManifestLibraryXML(xml.library, output); 20 | } 21 | 22 | private static mapManifestLibraryXML(xml: ManifestLibraryXML, output: IAssetData): void 23 | { 24 | if(!xml || !output) return; 25 | 26 | if(xml.assets !== undefined) 27 | { 28 | if(xml.assets.length) 29 | { 30 | output.assets = {}; 31 | 32 | ManifestMapper.mapManifestLibraryAssetXML(xml.assets, output.assets); 33 | } 34 | } 35 | 36 | if(xml.aliases !== undefined) 37 | { 38 | if(xml.aliases.length) 39 | { 40 | output.aliases = {}; 41 | 42 | ManifestMapper.mapManifestLibraryAliasXML(xml.aliases, output.aliases); 43 | } 44 | } 45 | } 46 | 47 | private static mapManifestLibraryAssetXML(xml: ManifestLibraryAssetXML[], output: { [index: string]: IAsset }): void 48 | { 49 | if(!xml || !xml.length || !output) return; 50 | 51 | for(const libraryAssetXML of xml) 52 | { 53 | const asset: IAsset = {}; 54 | 55 | if(libraryAssetXML.name !== undefined) 56 | { 57 | if(libraryAssetXML.name.startsWith('sh_')) continue; 58 | 59 | if(libraryAssetXML.name.indexOf('_32_') >= 0) continue; 60 | 61 | if(libraryAssetXML.param !== undefined) ManifestMapper.mapManifestLibraryAssetParamXML(libraryAssetXML.param, asset); 62 | 63 | if(IMAGE_SOURCES.has(libraryAssetXML.name)) asset.source = IMAGE_SOURCES.get(libraryAssetXML.name); 64 | 65 | output[libraryAssetXML.name] = asset; 66 | } 67 | } 68 | } 69 | 70 | private static mapManifestLibraryAssetParamXML(xml: ManifestLibraryAssetParamXML, output: IAsset): void 71 | { 72 | if(!xml || !output) return; 73 | 74 | if(xml.value !== undefined) 75 | { 76 | const split = xml.value.split(','); 77 | 78 | output.x = parseInt(split[0]); 79 | output.y = parseInt(split[1]); 80 | } 81 | } 82 | 83 | private static mapManifestLibraryAliasXML(xml: ManifestLibraryAliasXML[], output: { [index: string]: IAssetAlias }): void 84 | { 85 | if(!xml || !xml.length || !output) return; 86 | 87 | for(const libraryAliasXML of xml) 88 | { 89 | const alias: IAssetAlias = {}; 90 | 91 | if(libraryAliasXML.name !== undefined) 92 | { 93 | if(libraryAliasXML.link !== undefined) 94 | { 95 | if(libraryAliasXML.link.startsWith('sh_')) continue; 96 | 97 | if(libraryAliasXML.link.indexOf('_32_') >= 0) continue; 98 | 99 | alias.link = libraryAliasXML.link; 100 | } 101 | 102 | if(libraryAliasXML.flipH !== undefined) alias.flipH = libraryAliasXML.flipH; 103 | if(libraryAliasXML.flipH !== undefined) alias.flipV = libraryAliasXML.flipV; 104 | 105 | output[libraryAliasXML.name] = alias; 106 | } 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/common/mapping/xml/furnituredata/FurnitureTypeXML.ts: -------------------------------------------------------------------------------- 1 | export class FurnitureTypeXML 2 | { 3 | public furniType: string; 4 | 5 | public id: number; 6 | public classname: string; 7 | public revision: number; 8 | public category: string; 9 | public defaultdir: number; 10 | public xdim: number; 11 | public ydim: number; 12 | public partcolors: { color: string[] }; 13 | public name: string; 14 | public description: string; 15 | public adurl: string; 16 | public offerid: number; 17 | public buyout: boolean; 18 | public rentofferid: number; 19 | public rentbuyout: boolean; 20 | public bc: boolean; 21 | public excludeddynamic: boolean; 22 | public customparams: string; 23 | public specialtype: number; 24 | public canstandon: boolean; 25 | public cansiton: boolean; 26 | public canlayon: boolean; 27 | public furniline: string; 28 | public environment: string; 29 | public rare: boolean; 30 | 31 | constructor(type: string, xml: any) 32 | { 33 | this.furniType = type; 34 | 35 | const attributes = xml.$; 36 | 37 | this.id = ((attributes && parseInt(attributes.id)) || 0); 38 | this.classname = ((attributes && attributes.classname) || ''); 39 | this.revision = ((xml.revision && xml.revision[0] && parseInt(xml.revision[0])) || 0); 40 | this.category = ((xml.category && xml.category[0]) || 'unknown'); 41 | 42 | if(this.furniType === 'floor') 43 | { 44 | this.defaultdir = ((xml.defaultdir && parseInt(xml.defaultdir[0])) || 0); 45 | this.xdim = ((xml.xdim && parseInt(xml.xdim[0])) || 0); 46 | this.ydim = ((xml.ydim && parseInt(xml.ydim[0])) || 0); 47 | 48 | const colors: string[] = []; 49 | 50 | if(xml.partcolors) 51 | { 52 | for(const key in xml.partcolors) 53 | { 54 | const colorData = xml.partcolors[key].color; 55 | 56 | if(colorData) 57 | { 58 | for(const color of colorData) 59 | { 60 | let code = color; 61 | 62 | if(code.charAt(0) !== '#') code = ('#' + code); 63 | 64 | colors.push(code); 65 | } 66 | } 67 | } 68 | } 69 | 70 | this.partcolors = { color: [ ...colors ] }; 71 | } 72 | 73 | this.name = ((xml.name && xml.name[0]) || ''); 74 | this.description = ((xml.description && xml.description[0]) || ''); 75 | this.adurl = (xml.adurl && xml.adurl[0] || ''); 76 | this.offerid = ((xml.offerid && parseInt(xml.offerid[0])) || 0); 77 | this.buyout = ((xml.buyout && parseInt(xml.buyout[0]) === 1) || false); 78 | this.rentofferid = ((xml.rentofferid && parseInt(xml.rentofferid[0])) || 0); 79 | this.rentbuyout = ((xml.rentbuyout && parseInt(xml.rentbuyout[0]) === 1) || false); 80 | this.bc = ((xml.bc && parseInt(xml.bc[0]) === 1) || false); 81 | this.excludeddynamic = ((xml.excludeddynamic && parseInt(xml.excludeddynamic[0]) === 1) || false); 82 | this.customparams = ((xml.customparams && xml.customparams[0]) || ''); 83 | this.specialtype = ((xml.specialtype && parseInt(xml.specialtype[0])) || 0); 84 | 85 | if(this.furniType === 'floor') 86 | { 87 | this.canstandon = ((xml.canstandon && parseInt(xml.canstandon[0]) === 1) || false); 88 | this.cansiton = ((xml.cansiton && parseInt(xml.cansiton[0]) === 1) || false); 89 | this.canlayon = ((xml.canlayon && parseInt(xml.canlayon[0]) === 1) || false); 90 | } 91 | 92 | this.furniline = ((xml.furniline && xml.furniline[0]) || ''); 93 | this.environment = ((xml.environment && xml.environment[0]) || ''); 94 | this.rare = ((xml.rare && parseInt(xml.rare[0]) === 1) || false); 95 | } 96 | } 97 | --------------------------------------------------------------------------------