From a314dc2abe30db20a7f4ac452cd2996e801ba81a Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 2 Sep 2021 13:31:56 -0400 Subject: [PATCH] First commit --- .editorconfig | 16 + .env | 1 + .gitignore | 51 + .vscode/settings.json | 16 + package-lock.json | 1373 +++++++++++++ package.json | 38 + src/app/Application.ts | 63 + src/app/IApplication.ts | 9 + src/app/avatar/AvatarAssetDownloadLibrary.ts | 67 + src/app/avatar/AvatarAssetDownloadManager.ts | 154 ++ src/app/avatar/AvatarFigureContainer.ts | 117 ++ src/app/avatar/AvatarImage.ts | 741 +++++++ .../avatar/AvatarImageBodyPartContainer.ts | 74 + src/app/avatar/AvatarImagePartContainer.ts | 134 ++ src/app/avatar/AvatarRenderManager.ts | 310 +++ src/app/avatar/AvatarStructure.ts | 630 ++++++ src/app/avatar/EffectAssetDownloadLibrary.ts | 78 + src/app/avatar/EffectAssetDownloadManager.ts | 123 ++ src/app/avatar/FigureDataContainer.ts | 244 +++ src/app/avatar/IAvatarFigureContainer.ts | 10 + src/app/avatar/IAvatarImage.ts | 31 + src/app/avatar/IAvatarRenderManager.ts | 23 + src/app/avatar/PlaceHolderAvatarImage.ts | 18 + src/app/avatar/actions/ActionDefinition.ts | 225 ++ src/app/avatar/actions/ActionType.ts | 44 + src/app/avatar/actions/ActiveActionData.ts | 74 + src/app/avatar/actions/AvatarActionManager.ts | 185 ++ src/app/avatar/actions/IActionDefinition.ts | 19 + src/app/avatar/actions/IActiveActionData.ts | 11 + src/app/avatar/actions/index.ts | 6 + src/app/avatar/alias/AssetAlias.ts | 37 + src/app/avatar/alias/AssetAliasCollection.ts | 89 + src/app/avatar/alias/index.ts | 2 + src/app/avatar/animation/AddDataContainer.ts | 58 + src/app/avatar/animation/Animation.ts | 312 +++ src/app/avatar/animation/AnimationManager.ts | 50 + .../animation/AvatarAnimationLayerData.ts | 110 + .../avatar/animation/AvatarDataContainer.ts | 129 ++ .../animation/DirectionDataContainer.ts | 16 + src/app/avatar/animation/IAnimation.ts | 11 + .../avatar/animation/IAnimationLayerData.ts | 12 + src/app/avatar/animation/IAnimationManager.ts | 10 + .../avatar/animation/IAvatarDataContainer.ts | 9 + .../avatar/animation/ISpriteDataContainer.ts | 14 + .../avatar/animation/SpriteDataContainer.ts | 96 + src/app/avatar/animation/index.ts | 12 + .../avatar/cache/AvatarImageActionCache.ts | 57 + .../avatar/cache/AvatarImageBodyPartCache.ts | 99 + src/app/avatar/cache/AvatarImageCache.ts | 485 +++++ .../avatar/cache/AvatarImageDirectionCache.ts | 60 + src/app/avatar/cache/ImageData.ts | 59 + src/app/avatar/cache/index.ts | 5 + src/app/avatar/data/HabboAvatarAnimations.ts | 827 ++++++++ src/app/avatar/data/HabboAvatarGeometry.ts | 1830 +++++++++++++++++ src/app/avatar/data/HabboAvatarPartSets.ts | 418 ++++ src/app/avatar/data/index.ts | 3 + src/app/avatar/enum/AvatarAction.ts | 127 ++ src/app/avatar/enum/AvatarDirectionAngle.ts | 7 + src/app/avatar/enum/AvatarFigurePartType.ts | 29 + src/app/avatar/enum/AvatarScaleType.ts | 5 + src/app/avatar/enum/AvatarSetType.ts | 6 + src/app/avatar/enum/GeometryType.ts | 8 + src/app/avatar/enum/RenderMode.ts | 7 + src/app/avatar/enum/index.ts | 7 + .../avatar/geometry/AvatarModelGeometry.ts | 288 +++ src/app/avatar/geometry/AvatarSet.ts | 94 + src/app/avatar/geometry/GeometryBodyPart.ts | 195 ++ src/app/avatar/geometry/GeometryItem.ts | 55 + src/app/avatar/geometry/Matrix4x4.ts | 133 ++ src/app/avatar/geometry/Node3D.ts | 33 + src/app/avatar/geometry/Vector3D.ts | 120 ++ src/app/avatar/geometry/index.ts | 7 + src/app/avatar/index.ts | 24 + .../interfaces/figuredata/IFigureData.ts | 8 + .../interfaces/figuredata/IFigureDataColor.ts | 8 + .../figuredata/IFigureDataHiddenLayer.ts | 4 + .../figuredata/IFigureDataPalette.ts | 7 + .../interfaces/figuredata/IFigureDataPart.ts | 8 + .../interfaces/figuredata/IFigureDataSet.ts | 15 + .../figuredata/IFigureDataSetType.ts | 12 + src/app/avatar/interfaces/figuredata/index.ts | 7 + src/app/avatar/interfaces/index.ts | 1 + .../avatar/structure/AvatarAnimationData.ts | 59 + src/app/avatar/structure/AvatarCanvas.ts | 47 + src/app/avatar/structure/FigureSetData.ts | 132 ++ src/app/avatar/structure/IFigureSetData.ts | 7 + src/app/avatar/structure/IStructureData.ts | 11 + src/app/avatar/structure/PartSetsData.ts | 119 ++ .../structure/animation/AnimationAction.ts | 138 ++ .../animation/AnimationActionPart.ts | 30 + .../animation/AvatarAnimationFrame.ts | 21 + src/app/avatar/structure/animation/index.ts | 3 + src/app/avatar/structure/figure/FigurePart.ts | 59 + .../avatar/structure/figure/FigurePartSet.ts | 143 ++ .../avatar/structure/figure/IFigurePart.ts | 9 + .../avatar/structure/figure/IFigurePartSet.ts | 16 + src/app/avatar/structure/figure/IPalette.ts | 9 + src/app/avatar/structure/figure/IPartColor.ts | 8 + src/app/avatar/structure/figure/ISetType.ts | 12 + src/app/avatar/structure/figure/Palette.ts | 48 + src/app/avatar/structure/figure/PartColor.ts | 47 + src/app/avatar/structure/figure/SetType.ts | 106 + src/app/avatar/structure/figure/index.ts | 10 + src/app/avatar/structure/index.ts | 9 + .../avatar/structure/parts/ActivePartSet.ts | 26 + .../avatar/structure/parts/PartDefinition.ts | 64 + src/app/avatar/structure/parts/index.ts | 2 + src/app/index.ts | 3 + src/core/INitroCore.ts | 9 + src/core/NitroCore.ts | 42 + src/core/asset/AssetManager.ts | 119 ++ src/core/asset/IAssetManager.ts | 16 + src/core/asset/NitroBundle.ts | 77 + src/core/asset/index.ts | 5 + src/core/asset/interfaces/IAsset.ts | 9 + src/core/asset/interfaces/IAssetAlias.ts | 6 + src/core/asset/interfaces/IAssetData.ts | 21 + src/core/asset/interfaces/IAssetPalette.ts | 12 + .../interfaces/animation/IAssetAnimation.ts | 23 + .../animation/IAssetAnimationAdd.ts | 8 + .../animation/IAssetAnimationAvatar.ts | 6 + .../animation/IAssetAnimationDirection.ts | 4 + .../animation/IAssetAnimationFrame.ts | 8 + .../animation/IAssetAnimationFramePart.ts | 14 + .../animation/IAssetAnimationFramePartItem.ts | 5 + .../animation/IAssetAnimationOverride.ts | 8 + .../animation/IAssetAnimationRemove.ts | 4 + .../animation/IAssetAnimationShadow.ts | 4 + .../animation/IAssetAnimationSprite.ts | 11 + .../IAssetAnimationSpriteDirection.ts | 7 + src/core/asset/interfaces/animation/index.ts | 12 + src/core/asset/interfaces/index.ts | 8 + .../interfaces/logic/IAssetLogicCustomVars.ts | 4 + .../asset/interfaces/logic/IAssetLogicData.ts | 17 + .../logic/IAssetLogicPlanetSystem.ts | 11 + .../asset/interfaces/logic/ISoundSample.ts | 5 + src/core/asset/interfaces/logic/index.ts | 6 + .../interfaces/logic/model/IAssetDimension.ts | 6 + .../logic/model/IAssetLogicModel.ts | 7 + .../asset/interfaces/logic/model/index.ts | 2 + .../logic/particlesystem/IParticleSystem.ts | 11 + .../particlesystem/IParticleSystemEmitter.ts | 15 + .../particlesystem/IParticleSystemParticle.ts | 7 + .../IParticleSystemSimulation.ts | 9 + .../interfaces/logic/particlesystem/index.ts | 4 + .../spritesheet/ISpritesheetData.ts | 8 + .../spritesheet/ISpritesheetFrame.ts | 25 + .../spritesheet/ISpritesheetMeta.ts | 12 + .../asset/interfaces/spritesheet/index.ts | 3 + .../visualization/IAssetVisualizationData.ts | 20 + .../IAssetVisualizationDirection.ts | 6 + .../visualization/IAssetVisualizationLayer.ts | 10 + .../animation/IAssetVisualAnimation.ts | 10 + .../animation/IAssetVisualAnimationLayer.ts | 9 + .../IAssetVisualAnimationSequence.ts | 8 + .../IAssetVisualAnimationSequenceFrame.ts | 11 + ...AssetVisualAnimationSequenceFrameOffset.ts | 6 + .../visualization/animation/index.ts | 5 + .../visualization/color/IAssetColor.ts | 6 + .../visualization/color/IAssetColorLayer.ts | 4 + .../interfaces/visualization/color/index.ts | 2 + .../visualization/gestures/IAssetGesture.ts | 5 + .../visualization/gestures/index.ts | 1 + .../asset/interfaces/visualization/index.ts | 7 + .../visualization/postures/IAssetPosture.ts | 5 + .../visualization/postures/index.ts | 1 + src/core/asset/utils/GraphicAsset.ts | 141 ++ .../asset/utils/GraphicAssetCollection.ts | 314 +++ src/core/asset/utils/GraphicAssetPalette.ts | 59 + src/core/asset/utils/IGraphicAsset.ts | 19 + .../asset/utils/IGraphicAssetCollection.ts | 17 + src/core/asset/utils/index.ts | 5 + src/core/common/INitroManager.ts | 10 + src/core/common/NitroManager.ts | 53 + src/core/common/disposable/Disposable.ts | 40 + src/core/common/disposable/IDisposable.ts | 5 + src/core/common/disposable/index.ts | 2 + src/core/common/index.ts | 3 + .../configuration/ConfigurationManager.ts | 113 + .../configuration/IConfigurationManager.ts | 8 + src/core/configuration/index.ts | 2 + src/core/index.ts | 7 + src/core/logger/INitroLogger.ts | 8 + src/core/logger/NitroLogger.ts | 79 + src/core/logger/index.ts | 2 + src/core/utils/AdvancedMap.ts | 157 ++ src/core/utils/BinaryReader.ts | 47 + src/core/utils/File.ts | 43 + src/core/utils/FileUtilities.ts | 75 + src/core/utils/Point.ts | 36 + src/core/utils/Rectangle.ts | 125 ++ src/core/utils/index.ts | 6 + src/main.ts | 24 + 193 files changed, 14154 insertions(+) create mode 100644 .editorconfig create mode 100644 .env create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/app/Application.ts create mode 100644 src/app/IApplication.ts create mode 100644 src/app/avatar/AvatarAssetDownloadLibrary.ts create mode 100644 src/app/avatar/AvatarAssetDownloadManager.ts create mode 100644 src/app/avatar/AvatarFigureContainer.ts create mode 100644 src/app/avatar/AvatarImage.ts create mode 100644 src/app/avatar/AvatarImageBodyPartContainer.ts create mode 100644 src/app/avatar/AvatarImagePartContainer.ts create mode 100644 src/app/avatar/AvatarRenderManager.ts create mode 100644 src/app/avatar/AvatarStructure.ts create mode 100644 src/app/avatar/EffectAssetDownloadLibrary.ts create mode 100644 src/app/avatar/EffectAssetDownloadManager.ts create mode 100644 src/app/avatar/FigureDataContainer.ts create mode 100644 src/app/avatar/IAvatarFigureContainer.ts create mode 100644 src/app/avatar/IAvatarImage.ts create mode 100644 src/app/avatar/IAvatarRenderManager.ts create mode 100644 src/app/avatar/PlaceHolderAvatarImage.ts create mode 100644 src/app/avatar/actions/ActionDefinition.ts create mode 100644 src/app/avatar/actions/ActionType.ts create mode 100644 src/app/avatar/actions/ActiveActionData.ts create mode 100644 src/app/avatar/actions/AvatarActionManager.ts create mode 100644 src/app/avatar/actions/IActionDefinition.ts create mode 100644 src/app/avatar/actions/IActiveActionData.ts create mode 100644 src/app/avatar/actions/index.ts create mode 100644 src/app/avatar/alias/AssetAlias.ts create mode 100644 src/app/avatar/alias/AssetAliasCollection.ts create mode 100644 src/app/avatar/alias/index.ts create mode 100644 src/app/avatar/animation/AddDataContainer.ts create mode 100644 src/app/avatar/animation/Animation.ts create mode 100644 src/app/avatar/animation/AnimationManager.ts create mode 100644 src/app/avatar/animation/AvatarAnimationLayerData.ts create mode 100644 src/app/avatar/animation/AvatarDataContainer.ts create mode 100644 src/app/avatar/animation/DirectionDataContainer.ts create mode 100644 src/app/avatar/animation/IAnimation.ts create mode 100644 src/app/avatar/animation/IAnimationLayerData.ts create mode 100644 src/app/avatar/animation/IAnimationManager.ts create mode 100644 src/app/avatar/animation/IAvatarDataContainer.ts create mode 100644 src/app/avatar/animation/ISpriteDataContainer.ts create mode 100644 src/app/avatar/animation/SpriteDataContainer.ts create mode 100644 src/app/avatar/animation/index.ts create mode 100644 src/app/avatar/cache/AvatarImageActionCache.ts create mode 100644 src/app/avatar/cache/AvatarImageBodyPartCache.ts create mode 100644 src/app/avatar/cache/AvatarImageCache.ts create mode 100644 src/app/avatar/cache/AvatarImageDirectionCache.ts create mode 100644 src/app/avatar/cache/ImageData.ts create mode 100644 src/app/avatar/cache/index.ts create mode 100644 src/app/avatar/data/HabboAvatarAnimations.ts create mode 100644 src/app/avatar/data/HabboAvatarGeometry.ts create mode 100644 src/app/avatar/data/HabboAvatarPartSets.ts create mode 100644 src/app/avatar/data/index.ts create mode 100644 src/app/avatar/enum/AvatarAction.ts create mode 100644 src/app/avatar/enum/AvatarDirectionAngle.ts create mode 100644 src/app/avatar/enum/AvatarFigurePartType.ts create mode 100644 src/app/avatar/enum/AvatarScaleType.ts create mode 100644 src/app/avatar/enum/AvatarSetType.ts create mode 100644 src/app/avatar/enum/GeometryType.ts create mode 100644 src/app/avatar/enum/RenderMode.ts create mode 100644 src/app/avatar/enum/index.ts create mode 100644 src/app/avatar/geometry/AvatarModelGeometry.ts create mode 100644 src/app/avatar/geometry/AvatarSet.ts create mode 100644 src/app/avatar/geometry/GeometryBodyPart.ts create mode 100644 src/app/avatar/geometry/GeometryItem.ts create mode 100644 src/app/avatar/geometry/Matrix4x4.ts create mode 100644 src/app/avatar/geometry/Node3D.ts create mode 100644 src/app/avatar/geometry/Vector3D.ts create mode 100644 src/app/avatar/geometry/index.ts create mode 100644 src/app/avatar/index.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureData.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureDataColor.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureDataHiddenLayer.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureDataPalette.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureDataPart.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureDataSet.ts create mode 100644 src/app/avatar/interfaces/figuredata/IFigureDataSetType.ts create mode 100644 src/app/avatar/interfaces/figuredata/index.ts create mode 100644 src/app/avatar/interfaces/index.ts create mode 100644 src/app/avatar/structure/AvatarAnimationData.ts create mode 100644 src/app/avatar/structure/AvatarCanvas.ts create mode 100644 src/app/avatar/structure/FigureSetData.ts create mode 100644 src/app/avatar/structure/IFigureSetData.ts create mode 100644 src/app/avatar/structure/IStructureData.ts create mode 100644 src/app/avatar/structure/PartSetsData.ts create mode 100644 src/app/avatar/structure/animation/AnimationAction.ts create mode 100644 src/app/avatar/structure/animation/AnimationActionPart.ts create mode 100644 src/app/avatar/structure/animation/AvatarAnimationFrame.ts create mode 100644 src/app/avatar/structure/animation/index.ts create mode 100644 src/app/avatar/structure/figure/FigurePart.ts create mode 100644 src/app/avatar/structure/figure/FigurePartSet.ts create mode 100644 src/app/avatar/structure/figure/IFigurePart.ts create mode 100644 src/app/avatar/structure/figure/IFigurePartSet.ts create mode 100644 src/app/avatar/structure/figure/IPalette.ts create mode 100644 src/app/avatar/structure/figure/IPartColor.ts create mode 100644 src/app/avatar/structure/figure/ISetType.ts create mode 100644 src/app/avatar/structure/figure/Palette.ts create mode 100644 src/app/avatar/structure/figure/PartColor.ts create mode 100644 src/app/avatar/structure/figure/SetType.ts create mode 100644 src/app/avatar/structure/figure/index.ts create mode 100644 src/app/avatar/structure/index.ts create mode 100644 src/app/avatar/structure/parts/ActivePartSet.ts create mode 100644 src/app/avatar/structure/parts/PartDefinition.ts create mode 100644 src/app/avatar/structure/parts/index.ts create mode 100644 src/app/index.ts create mode 100644 src/core/INitroCore.ts create mode 100644 src/core/NitroCore.ts create mode 100644 src/core/asset/AssetManager.ts create mode 100644 src/core/asset/IAssetManager.ts create mode 100644 src/core/asset/NitroBundle.ts create mode 100644 src/core/asset/index.ts create mode 100644 src/core/asset/interfaces/IAsset.ts create mode 100644 src/core/asset/interfaces/IAssetAlias.ts create mode 100644 src/core/asset/interfaces/IAssetData.ts create mode 100644 src/core/asset/interfaces/IAssetPalette.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimation.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationAdd.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationAvatar.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationDirection.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationFrame.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationFramePart.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationFramePartItem.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationOverride.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationRemove.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationShadow.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationSprite.ts create mode 100644 src/core/asset/interfaces/animation/IAssetAnimationSpriteDirection.ts create mode 100644 src/core/asset/interfaces/animation/index.ts create mode 100644 src/core/asset/interfaces/index.ts create mode 100644 src/core/asset/interfaces/logic/IAssetLogicCustomVars.ts create mode 100644 src/core/asset/interfaces/logic/IAssetLogicData.ts create mode 100644 src/core/asset/interfaces/logic/IAssetLogicPlanetSystem.ts create mode 100644 src/core/asset/interfaces/logic/ISoundSample.ts create mode 100644 src/core/asset/interfaces/logic/index.ts create mode 100644 src/core/asset/interfaces/logic/model/IAssetDimension.ts create mode 100644 src/core/asset/interfaces/logic/model/IAssetLogicModel.ts create mode 100644 src/core/asset/interfaces/logic/model/index.ts create mode 100644 src/core/asset/interfaces/logic/particlesystem/IParticleSystem.ts create mode 100644 src/core/asset/interfaces/logic/particlesystem/IParticleSystemEmitter.ts create mode 100644 src/core/asset/interfaces/logic/particlesystem/IParticleSystemParticle.ts create mode 100644 src/core/asset/interfaces/logic/particlesystem/IParticleSystemSimulation.ts create mode 100644 src/core/asset/interfaces/logic/particlesystem/index.ts create mode 100644 src/core/asset/interfaces/spritesheet/ISpritesheetData.ts create mode 100644 src/core/asset/interfaces/spritesheet/ISpritesheetFrame.ts create mode 100644 src/core/asset/interfaces/spritesheet/ISpritesheetMeta.ts create mode 100644 src/core/asset/interfaces/spritesheet/index.ts create mode 100644 src/core/asset/interfaces/visualization/IAssetVisualizationData.ts create mode 100644 src/core/asset/interfaces/visualization/IAssetVisualizationDirection.ts create mode 100644 src/core/asset/interfaces/visualization/IAssetVisualizationLayer.ts create mode 100644 src/core/asset/interfaces/visualization/animation/IAssetVisualAnimation.ts create mode 100644 src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationLayer.ts create mode 100644 src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequence.ts create mode 100644 src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrame.ts create mode 100644 src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrameOffset.ts create mode 100644 src/core/asset/interfaces/visualization/animation/index.ts create mode 100644 src/core/asset/interfaces/visualization/color/IAssetColor.ts create mode 100644 src/core/asset/interfaces/visualization/color/IAssetColorLayer.ts create mode 100644 src/core/asset/interfaces/visualization/color/index.ts create mode 100644 src/core/asset/interfaces/visualization/gestures/IAssetGesture.ts create mode 100644 src/core/asset/interfaces/visualization/gestures/index.ts create mode 100644 src/core/asset/interfaces/visualization/index.ts create mode 100644 src/core/asset/interfaces/visualization/postures/IAssetPosture.ts create mode 100644 src/core/asset/interfaces/visualization/postures/index.ts create mode 100644 src/core/asset/utils/GraphicAsset.ts create mode 100644 src/core/asset/utils/GraphicAssetCollection.ts create mode 100644 src/core/asset/utils/GraphicAssetPalette.ts create mode 100644 src/core/asset/utils/IGraphicAsset.ts create mode 100644 src/core/asset/utils/IGraphicAssetCollection.ts create mode 100644 src/core/asset/utils/index.ts create mode 100644 src/core/common/INitroManager.ts create mode 100644 src/core/common/NitroManager.ts create mode 100644 src/core/common/disposable/Disposable.ts create mode 100644 src/core/common/disposable/IDisposable.ts create mode 100644 src/core/common/disposable/index.ts create mode 100644 src/core/common/index.ts create mode 100644 src/core/configuration/ConfigurationManager.ts create mode 100644 src/core/configuration/IConfigurationManager.ts create mode 100644 src/core/configuration/index.ts create mode 100644 src/core/index.ts create mode 100644 src/core/logger/INitroLogger.ts create mode 100644 src/core/logger/NitroLogger.ts create mode 100644 src/core/logger/index.ts create mode 100644 src/core/utils/AdvancedMap.ts create mode 100644 src/core/utils/BinaryReader.ts create mode 100644 src/core/utils/File.ts create mode 100644 src/core/utils/FileUtilities.ts create mode 100644 src/core/utils/Point.ts create mode 100644 src/core/utils/Rectangle.ts create mode 100644 src/core/utils/index.ts create mode 100644 src/main.ts diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0792692 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.env b/.env new file mode 100644 index 0000000..464c1e1 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +CONFIG_URL=http://client.nitrots.co:3000/renderer-config.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1413af9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc +# Only exists if Bazel was run +/bazel-out + +# dependencies +/node_modules + +# profiling files +chrome-profiler-events*.json +speed-measure-plugin*.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings +.git + +# System Files +.DS_Store +Thumbs.db + +*.zip +*.as +*.bin diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7b328b8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib", + "typescript.preferences.importModuleSpecifier": "relative", + "typescript.preferences.quoteStyle": "single", + "typescript.format.placeOpenBraceOnNewLineForControlBlocks": true, + "typescript.format.placeOpenBraceOnNewLineForFunctions": true, + "editor.codeActionsOnSave": { + "source.fixAll": true, + "source.organizeImports": true, + }, + "emmet.showExpandedAbbreviation": "never", + "git.ignoreLimitWarning": true, + "files.eol": "\n", + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5b7b207 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1373 @@ +{ + "name": "nitro-imager", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@mapbox/node-pre-gyp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", + "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==", + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.1", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "rimraf": "^3.0.2", + "semver": "^7.3.4", + "tar": "^6.1.0" + } + }, + "@types/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bytebuffer": { + "version": "5.0.42", + "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.42.tgz", + "integrity": "sha512-lEgKojWUAc/MG2t649oZS5AfYFP2xRNPoDuwDBlBMjHXd8MaGPgFgtCXUK7inZdBOygmVf10qxc1Us8GXC96aw==", + "dev": true, + "requires": { + "@types/long": "*", + "@types/node": "*" + } + }, + "@types/chalk": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", + "integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==", + "dev": true, + "requires": { + "chalk": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", + "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/long": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.1.tgz", + "integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==", + "dev": true + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/node": { + "version": "14.17.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.12.tgz", + "integrity": "sha512-vhUqgjJR1qxwTWV5Ps5txuy2XMdf7Fw+OrdChRboy8BmWUPkckOhphaohzFG6b8DW7CrxaBMdrdJ47SYFq1okw==", + "dev": true + }, + "@types/node-fetch": { + "version": "2.5.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz", + "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "@types/pako": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.2.tgz", + "integrity": "sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "bytebuffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz", + "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=", + "requires": { + "long": "~3" + } + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "canvas": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.8.0.tgz", + "integrity": "sha512-gLTi17X8WY9Cf5GZ2Yns8T5lfBOcGgFehDFb+JQwDqdOoBOcECS9ZWMEAqMSVcMYwXD659J8NyzjRY/2aE+C2Q==", + "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.14.0", + "simple-get": "^3.0.3" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "requires": { + "mimic-response": "^2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dotenv": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz", + "integrity": "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==" + }, + "dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE=", + "dev": true, + "requires": { + "xtend": "^4.0.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "requires": { + "agent-base": "6", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz", + "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "long": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.49.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz", + "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==" + }, + "mime-types": { + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz", + "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==", + "requires": { + "mime-db": "1.49.0" + } + }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "requires": { + "yallist": "^4.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "node-fetch": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "pako": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz", + "integrity": "sha512-v8tweI900AUkZN6heMU/4Uy4cXRc2AYNRggVmTR+dEncawDJgCdLMximOVA2p4qO57WMynangsfGRb5WD6L1Bg==" + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-node": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", + "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.17", + "yn": "3.1.1" + } + }, + "ts-node-dev": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", + "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", + "dev": true, + "requires": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.5", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^9.0.0", + "tsconfig": "^7.0.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "requires": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typescript": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", + "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..24d8358 --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "nitro-imager", + "version": "1.0.0", + "description": "", + "main": "index.js", + "dependencies": { + "bytebuffer": "^5.0.1", + "canvas": "^2.8.0", + "chalk": "^4.1.2", + "dotenv": "^10.0.0", + "express": "^4.17.1", + "node-fetch": "^2.6.1", + "pako": "^2.0.4" + }, + "devDependencies": { + "@types/bytebuffer": "^5.0.42", + "@types/chalk": "^2.2.0", + "@types/express": "^4.17.13", + "@types/node": "^14.17.12", + "@types/node-fetch": "^2.5.12", + "@types/pako": "^1.0.2", + "ts-node-dev": "^1.1.8", + "typescript": "^4.4.2" + }, + "scripts": { + "start:dev": "ts-node-dev --respawn --transpile-only ./src/main.ts" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/billsonnn/nitro-imager.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/billsonnn/nitro-imager/issues" + }, + "homepage": "https://github.com/billsonnn/nitro-imager#readme" +} diff --git a/src/app/Application.ts b/src/app/Application.ts new file mode 100644 index 0000000..1047452 --- /dev/null +++ b/src/app/Application.ts @@ -0,0 +1,63 @@ +import { INitroCore, NitroManager } from '../core'; +import { AvatarRenderManager, AvatarScaleType, AvatarSetType, IAvatarRenderManager } from './avatar'; +import { IApplication } from './IApplication'; + +export class Application extends NitroManager implements IApplication +{ + private static INSTANCE: IApplication = null; + + private _core: INitroCore; + private _avatar: IAvatarRenderManager; + + constructor(core: INitroCore) + { + super(); + + Application.INSTANCE = this; + + this._core = core; + this._avatar = new AvatarRenderManager(core.asset); + } + + protected async onInit(): Promise + { + if(this._core) await this._core.init(); + + if(this._avatar) await this._avatar.init(); + + const image = await this._avatar.createAvatarImage('hd-207-14.lg-3216-1408.cc-3007-86-88.ha-3054-1408-1408.he-3079-64.ea-1402-0.ch-230-72.hr-110-40', AvatarScaleType.LARGE, 'M'); + + //image.setDirection(AvatarSetType.FULL, 2); + const canvas = await image.getImage(AvatarSetType.FULL, false); + console.log(canvas.toDataURL()); + + this.logger.log(`Initialized`); + } + + protected async onDispose(): Promise + { + if(this._avatar) await this._avatar.dispose(); + + if(this._core) await this._core.dispose(); + } + + public getConfiguration(key: string, value: T = null): T + { + return this._core.configuration.getValue(key, value); + } + + public get core(): INitroCore + { + return this._core; + } + + public get avatar(): IAvatarRenderManager + { + return this._avatar; + } + + public static get instance(): IApplication + { + return this.INSTANCE; + } +} diff --git a/src/app/IApplication.ts b/src/app/IApplication.ts new file mode 100644 index 0000000..8a44642 --- /dev/null +++ b/src/app/IApplication.ts @@ -0,0 +1,9 @@ +import { INitroCore, INitroManager } from '../core'; +import { IAvatarRenderManager } from './avatar'; + +export interface IApplication extends INitroManager +{ + getConfiguration(key: string, value?: T): T; + core: INitroCore; + avatar: IAvatarRenderManager; +} diff --git a/src/app/avatar/AvatarAssetDownloadLibrary.ts b/src/app/avatar/AvatarAssetDownloadLibrary.ts new file mode 100644 index 0000000..a9a0ba4 --- /dev/null +++ b/src/app/avatar/AvatarAssetDownloadLibrary.ts @@ -0,0 +1,67 @@ +import { IAssetManager } from '../../core'; + +export class AvatarAssetDownloadLibrary +{ + private static NOT_LOADED: number = 0; + private static LOADING: number = 1; + private static LOADED: number = 2; + + private _state: number; + private _libraryName: string; + private _revision: string; + private _downloadUrl: string; + private _assets: IAssetManager; + + constructor(id: string, revision: string, assets: IAssetManager, assetUrl: string) + { + this._state = AvatarAssetDownloadLibrary.NOT_LOADED; + this._libraryName = id; + this._revision = revision; + this._downloadUrl = assetUrl; + this._assets = assets; + + this._downloadUrl = this._downloadUrl.replace(/%libname%/gi, this._libraryName); + this._downloadUrl = this._downloadUrl.replace(/%revision%/gi, this._revision); + + this.checkIfAssetLoaded(); + } + + private checkIfAssetLoaded(): boolean + { + if(this._state === AvatarAssetDownloadLibrary.LOADED) return true; + + const asset = this._assets.getCollection(this._libraryName); + + if(asset) + { + this._state = AvatarAssetDownloadLibrary.LOADED; + + return true; + } + + return false; + } + + public async downloadAsset(): Promise + { + if(!this._assets || (this._state === AvatarAssetDownloadLibrary.LOADING)) return; + + if(this.checkIfAssetLoaded()) return; + + this._state = AvatarAssetDownloadLibrary.LOADING; + + await this._assets.downloadAsset(this._downloadUrl); + + this._state = AvatarAssetDownloadLibrary.LOADED; + } + + public get libraryName(): string + { + return this._libraryName; + } + + public get isLoaded(): boolean + { + return (this._state === AvatarAssetDownloadLibrary.LOADED); + } +} diff --git a/src/app/avatar/AvatarAssetDownloadManager.ts b/src/app/avatar/AvatarAssetDownloadManager.ts new file mode 100644 index 0000000..5ae50db --- /dev/null +++ b/src/app/avatar/AvatarAssetDownloadManager.ts @@ -0,0 +1,154 @@ +import fetch from 'node-fetch'; +import { AdvancedMap, IAssetManager } from '../../core'; +import { Application } from '../Application'; +import { AvatarAssetDownloadLibrary } from './AvatarAssetDownloadLibrary'; +import { AvatarStructure } from './AvatarStructure'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; + +export class AvatarAssetDownloadManager +{ + private _assets: IAssetManager; + private _structure: AvatarStructure; + + private _missingMandatoryLibs: string[]; + private _figureMap: AdvancedMap; + private _libraryNames: string[]; + + constructor(assets: IAssetManager, structure: AvatarStructure) + { + this._assets = assets; + this._structure = structure; + + this._missingMandatoryLibs = Application.instance.getConfiguration('avatar.mandatory.libraries'); + this._figureMap = new AdvancedMap(); + this._libraryNames = []; + } + + public async loadFigureMap(): Promise + { + const url = Application.instance.getConfiguration('avatar.figuremap.url'); + + const data = await fetch(url); + const json = await data.json(); + + this.processFigureMap(json.libraries); + + await this.processMissingLibraries(); + } + + private processFigureMap(data: any): void + { + if(!data) return; + + const avatarAssetUrl = Application.instance.getConfiguration('avatar.asset.url'); + + for(const library of data) + { + if(!library) continue; + + const id = (library.id as string); + const revision = (library.revision || ''); + + if(this._libraryNames.indexOf(id) >= 0) continue; + + this._libraryNames.push(id); + + const downloadLibrary = new AvatarAssetDownloadLibrary(id, revision, this._assets, avatarAssetUrl); + + for(const part of library.parts) + { + const id = (part.id as string); + const type = (part.type as string); + const partString = (type + ':' + id); + + let existing = this._figureMap.getValue(partString); + + if(!existing) existing = []; + + existing.push(downloadLibrary); + + this._figureMap.add(partString, existing); + } + } + } + + public async processMissingLibraries(): Promise + { + const missingLibraries = this._missingMandatoryLibs.slice(); + + for(const library of missingLibraries) + { + if(!library) continue; + + const libraries = this._figureMap.getValue(library); + + if(libraries) for(const library of libraries) (library && await this.downloadLibrary(library)); + } + } + + public isAvatarFigureContainerReady(container: IAvatarFigureContainer): boolean + { + const pendingLibraries = this.getAvatarFigurePendingLibraries(container); + + return !pendingLibraries.length; + } + + private getAvatarFigurePendingLibraries(container: IAvatarFigureContainer): AvatarAssetDownloadLibrary[] + { + const pendingLibraries: AvatarAssetDownloadLibrary[] = []; + + if(!container || !this._structure) return pendingLibraries; + + const figureData = this._structure.figureData; + + if(!figureData) return pendingLibraries; + + const setKeys = container.getPartTypeIds(); + + for(const key of setKeys) + { + const set = figureData.getSetType(key); + + if(!set) continue; + + const figurePartSet = set.getPartSet(container.getPartSetId(key)); + + if(!figurePartSet) continue; + + for(const part of figurePartSet.parts) + { + if(!part) continue; + + const name = (part.type + ':' + part.id); + const existing = this._figureMap.getValue(name); + + if(existing === undefined) continue; + + for(const library of existing) + { + if(!library || library.isLoaded) continue; + + if(pendingLibraries.indexOf(library) >= 0) continue; + + pendingLibraries.push(library); + } + } + } + + return pendingLibraries; + } + + public async downloadAvatarFigure(container: IAvatarFigureContainer): Promise + { + const pendingLibraries = this.getAvatarFigurePendingLibraries(container); + + for(const library of pendingLibraries) (library && await this.downloadLibrary(library)); + } + + private async downloadLibrary(library: AvatarAssetDownloadLibrary): Promise + { + if(!library || library.isLoaded) return; + + await library.downloadAsset(); + } +} diff --git a/src/app/avatar/AvatarFigureContainer.ts b/src/app/avatar/AvatarFigureContainer.ts new file mode 100644 index 0000000..da458eb --- /dev/null +++ b/src/app/avatar/AvatarFigureContainer.ts @@ -0,0 +1,117 @@ +import { AdvancedMap } from '../../core'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; + +export class AvatarFigureContainer implements IAvatarFigureContainer +{ + private _parts: AdvancedMap>; + + constructor(figure: string) + { + this._parts = new AdvancedMap(); + + this.parseFigure(figure); + } + + public getPartTypeIds(): string[] + { + return this.partSets().getKeys(); + } + + public hasPartType(k: string): boolean + { + return !!this.partSets().getValue(k); + } + + public getPartSetId(k: string): number + { + const existing = this.partSets().getValue(k); + + if(!existing) return 0; + + return existing.getValue('setid'); + } + + public getPartColorIds(k: string): number[] + { + const existing = this.partSets().getValue(k); + + if(!existing) return null; + + return existing.getValue('colorids'); + } + + public updatePart(setType: string, partSetId: number, colorIds: number[]): void + { + const set: AdvancedMap = new AdvancedMap(); + + set.add('type', setType); + set.add('setid', partSetId); + set.add('colorids', colorIds); + + const existingSets = this.partSets(); + + existingSets.remove(setType); + existingSets.add(setType, set); + } + + public removePart(k: string): void + { + this.partSets().remove(k); + } + + public getFigureString(): string + { + const parts: string[] = []; + + for(const key of this.partSets().getKeys()) + { + if(!key) continue; + + let setParts = []; + + setParts.push(key); + setParts.push(this.getPartSetId(key)); + + setParts = setParts.concat(this.getPartColorIds(key)); + + parts.push(setParts.join('-')); + } + + return parts.join('.'); + } + + private partSets(): AdvancedMap> + { + if(!this._parts) this._parts = new AdvancedMap(); + + return this._parts; + } + + private parseFigure(figure: string): void + { + if(!figure) figure = ''; + + for(const part of figure.split('.')) + { + const pieces = part.split('-'); + + if(pieces.length >= 2) + { + const type = pieces[0]; + const setId = parseInt(pieces[1]); + const colors = []; + + let index = 2; + + while(index < pieces.length) + { + colors.push(parseInt(pieces[index])); + + index++; + } + + this.updatePart(type, setId, colors); + } + } + } +} diff --git a/src/app/avatar/AvatarImage.ts b/src/app/avatar/AvatarImage.ts new file mode 100644 index 0000000..c77ff56 --- /dev/null +++ b/src/app/avatar/AvatarImage.ts @@ -0,0 +1,741 @@ +import { Canvas, createCanvas } from 'canvas'; +import { IGraphicAsset } from '../../core'; +import { ActiveActionData, IActionDefinition, IActiveActionData } from './actions'; +import { AssetAliasCollection } from './alias'; +import { IAnimationLayerData, IAvatarDataContainer, ISpriteDataContainer } from './animation'; +import { AvatarFigureContainer } from './AvatarFigureContainer'; +import { AvatarStructure } from './AvatarStructure'; +import { AvatarImageCache } from './cache'; +import { EffectAssetDownloadManager } from './EffectAssetDownloadManager'; +import { AvatarAction, AvatarDirectionAngle, AvatarScaleType, AvatarSetType } from './enum'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; +import { IAvatarImage } from './IAvatarImage'; +import { IPartColor } from './structure'; + +export class AvatarImage implements IAvatarImage +{ + private static CHANNELS_EQUAL: string = 'CHANNELS_EQUAL'; + private static CHANNELS_UNIQUE: string = 'CHANNELS_UNIQUE'; + private static CHANNELS_RED: string = 'CHANNELS_RED'; + private static CHANNELS_GREEN: string = 'CHANNELS_GREEN'; + private static CHANNELS_BLUE: string = 'CHANNELS_BLUE'; + private static CHANNELS_DESATURATED: string = 'CHANNELS_DESATURATED'; + private static DEFAULT_ACTION: string = 'Default'; + private static DEFAULT_DIRECTION: number = 2; + private static DEFAULT_AVATAR_SET: string = AvatarSetType.FULL; + + protected _structure: AvatarStructure; + protected _scale: string; + protected _mainDirection: number; + protected _headDirection: number; + protected _mainAction: IActiveActionData; + protected _disposed: boolean; + protected _canvasOffsets: number[]; + protected _assets: AssetAliasCollection; + protected _cache: AvatarImageCache; + protected _figure: AvatarFigureContainer; + protected _avatarSpriteData: IAvatarDataContainer; + protected _actions: ActiveActionData[]; + + private _defaultAction: IActiveActionData; + private _frameCounter: number = 0; + private _directionOffset: number = 0; + private _sprites: ISpriteDataContainer[]; + private _isAnimating: boolean = false; + private _animationHasResetOnToggle: boolean = false; + private _actionsSorted: boolean = false; + private _sortedActions: IActiveActionData[]; + private _lastActionsString: string; + private _currentActionsString: string; + private _effectIdInUse: number = -1; + private _animationFrameCount: number; + private _cachedBodyParts: string[]; + private _cachedBodyPartsDirection: number = -1; + private _cachedBodyPartsGeometryType: string = null; + private _cachedBodyPartsAvatarSet: string = null; + private _effectManager: EffectAssetDownloadManager; + + constructor(k: AvatarStructure, _arg_2: AssetAliasCollection, _arg_3: AvatarFigureContainer, _arg_4: string, _arg_5: EffectAssetDownloadManager) + { + this._canvasOffsets = []; + this._actions = []; + this._cachedBodyParts = []; + this._disposed = false; + this._effectManager = _arg_5; + this._structure = k; + this._assets = _arg_2; + this._scale = _arg_4; + if(this._scale == null) + { + this._scale = AvatarScaleType.LARGE; + } + if(_arg_3 == null) + { + _arg_3 = new AvatarFigureContainer('hr-893-45.hd-180-2.ch-210-66.lg-270-82.sh-300-91.wa-2007-.ri-1-'); + } + this._figure = _arg_3; + this._cache = new AvatarImageCache(this._structure, this, this._assets, this._scale); + this.setDirection(AvatarImage.DEFAULT_AVATAR_SET, AvatarImage.DEFAULT_DIRECTION); + this._actions = []; + this._defaultAction = new ActiveActionData(AvatarAction.POSTURE_STAND); + this._defaultAction.definition = this._structure.getActionDefinition(AvatarImage.DEFAULT_ACTION); + this.resetActions(); + this._animationFrameCount = 0; + } + + public async dispose(): Promise + { + if(this._disposed) return; + + this._structure = null; + this._assets = null; + this._mainAction = null; + this._figure = null; + this._avatarSpriteData = null; + this._actions = null; + + if(this._cache) + { + this._cache.dispose(); + this._cache = null; + } + + this._canvasOffsets = null; + this._disposed = true; + } + + public get disposed(): boolean + { + return this._disposed; + } + + public getFigure(): IAvatarFigureContainer + { + return this._figure; + } + + public getScale(): string + { + return this._scale; + } + + public getPartColor(k: string): IPartColor + { + return this._structure.getPartColor(this._figure, k); + } + + public setDirection(k: string, _arg_2: number): void + { + _arg_2 = (_arg_2 + this._directionOffset); + + if(_arg_2 < AvatarDirectionAngle.MIN_DIRECTION) + { + _arg_2 = (AvatarDirectionAngle.MAX_DIRECTION + (_arg_2 + 1)); + } + + if(_arg_2 > AvatarDirectionAngle.MAX_DIRECTION) + { + _arg_2 = (_arg_2 - (AvatarDirectionAngle.MAX_DIRECTION + 1)); + } + + if(this._structure.isMainAvatarSet(k)) + { + this._mainDirection = _arg_2; + } + + if((k === AvatarSetType.HEAD) || (k === AvatarSetType.FULL)) + { + if((k === AvatarSetType.HEAD) && (this.isHeadTurnPreventedByAction())) + { + _arg_2 = this._mainDirection; + } + + this._headDirection = _arg_2; + } + + this._cache.setDirection(k, _arg_2); + } + + public setDirectionAngle(k: string, _arg_2: number): void + { + this.setDirection(k, Math.floor(_arg_2 / 45)); + } + + public getSprites(): ISpriteDataContainer[] + { + return this._sprites; + } + + public getCanvasOffsets(): number[] + { + return this._canvasOffsets; + } + + public getLayerData(k: ISpriteDataContainer): IAnimationLayerData + { + return this._structure.getBodyPartData(k.animation.id, this._frameCounter, k.id); + } + + public updateAnimationByFrames(k: number = 1): void + { + this._frameCounter += k; + } + + public resetAnimationFrameCounter(): void + { + this._frameCounter = 0; + } + + private getFullImageCacheKey(): string + { + if(((this._sortedActions.length == 1) && (this._mainDirection == this._headDirection))) + { + return (this._mainDirection + this._currentActionsString) + (this._frameCounter % 4); + } + + if(this._sortedActions.length == 2) + { + for(const k of this._sortedActions) + { + if(((k.actionType == 'fx') && ((((k.actionParameter == '33') || (k.actionParameter == '34')) || (k.actionParameter == '35')) || (k.actionParameter == '36')))) + { + return (this._mainDirection + this._currentActionsString) + 0; + } + + if(((k.actionType == 'fx') && ((k.actionParameter == '38') || (k.actionParameter == '39')))) + { + return (((this._mainDirection + '_') + this._headDirection) + this._currentActionsString) + (this._frameCounter % 11); + } + + if((k.actionType === 'dance') && ((k.actionParameter === '1') || (k.actionParameter === '2') || (k.actionParameter === '3') || (k.actionParameter === '4'))) + { + let frame = (this._frameCounter % 8); + + if((k.actionParameter === '3')) frame = (this._frameCounter % 10); + + if((k.actionParameter === '4')) frame = (this._frameCounter % 16); + + return (((this._mainDirection + k.actionType) + k.actionParameter) + frame); + } + } + } + + return null; + } + + private getBodyParts(k: string, _arg_2: string, _arg_3: number): string[] + { + if((((!(_arg_3 == this._cachedBodyPartsDirection)) || (!(_arg_2 == this._cachedBodyPartsGeometryType))) || (!(k == this._cachedBodyPartsAvatarSet)))) + { + this._cachedBodyPartsDirection = _arg_3; + this._cachedBodyPartsGeometryType = _arg_2; + this._cachedBodyPartsAvatarSet = k; + this._cachedBodyParts = this._structure.getBodyParts(k, _arg_2, _arg_3); + } + return this._cachedBodyParts; + } + + public getAvatarPartsForCamera(k: string): void + { + let _local_4: string; + if(this._mainAction == null) + { + return; + } + const _local_2 = this._structure.getCanvas(this._scale, this._mainAction.definition.geometryType); + if(_local_2 == null) + { + return; + } + const _local_3 = this.getBodyParts(k, this._mainAction.definition.geometryType, this._mainDirection); + let _local_6 = (_local_3.length - 1); + while(_local_6 >= 0) + { + _local_4 = _local_3[_local_6]; + const _local_5 = this._cache.getImageContainer(_local_4, this._frameCounter); + _local_6--; + } + } + + public async getImage(setType: string, hightlight: boolean, scale: number = 1): Promise + { + if(!this._mainAction) return null; + + if(!this._actionsSorted) await this.endActionAppends(); + + const avatarCanvas = this._structure.getCanvas(this._scale, this._mainAction.definition.geometryType); + + if(!avatarCanvas) return null; + + const bodyParts = this.getBodyParts(setType, this._mainAction.definition.geometryType, this._mainDirection); + + const canvas = createCanvas(avatarCanvas.width, avatarCanvas.height); + const ctx = canvas.getContext('2d'); + + let partCount = (bodyParts.length - 1); + + while(partCount >= 0) + { + const set = bodyParts[partCount]; + const part = this._cache.getImageContainer(set, this._frameCounter); + + if(part) + { + const partCacheContainer = part.image; + + if(!partCacheContainer) return null; + + const point = part.regPoint.clone(); + + if(point) + { + point.x += avatarCanvas.offset.x; + point.y += avatarCanvas.offset.y; + + point.x += avatarCanvas.regPoint.x; + point.y += avatarCanvas.regPoint.y; + + ctx.save(); + ctx.scale(scale, 1); + ctx.drawImage(part.image, point.x, point.y, part.image.width, part.image.height); + ctx.restore(); + } + } + + partCount--; + } + + //if(this._avatarSpriteData && this._avatarSpriteData.paletteIsGrayscale) this.convertToGrayscale(container); + + return canvas; + } + + // public applyPalette(texture: RenderTexture, reds: number[] = [], greens: number[] = [], blues: number[] = []): RenderTexture + // { + // const textureCanvas = Nitro.instance.renderer.extract.canvas(texture); + // const textureCtx = textureCanvas.getContext('2d'); + // const textureImageData = textureCtx.getImageData(0, 0, textureCanvas.width, textureCanvas.height); + // const data = textureImageData.data; + + // for(const i = 0; i < data.length; i += 4) + // { + // let paletteColor = this._palette[data[ i + 1 ]]; + + // if(paletteColor === undefined) paletteColor = [ 0, 0, 0 ]; + + // data[ i ] = paletteColor[0]; + // data[ i + 1 ] = paletteColor[1]; + // data[ i + 2 ] = paletteColor[2]; + // } + + // textureCtx.putImageData(textureImageData, 0, 0); + + // return Texture.from(textureCanvas); + // } + + public getAsset(k: string): IGraphicAsset + { + return this._assets.getAsset(k); + } + + public getDirection(): number + { + return this._mainDirection; + } + + public initActionAppends(): void + { + this._actions = []; + this._actionsSorted = false; + this._currentActionsString = ''; + } + + public async endActionAppends(): Promise + { + let k:ActiveActionData; + + if(!this.sortActions()) return; + + for(const k of this._sortedActions) + { + if(k.actionType === AvatarAction.EFFECT) + { + if(!this._effectManager.isAvatarEffectReady(parseInt(k.actionParameter))) await this._effectManager.downloadAvatarEffect(parseInt(k.actionParameter)); + } + } + + this.resetActions(); + this.setActionsToParts(); + } + + public appendAction(k: string, ..._args: any[]): boolean + { + let _local_3 = ''; + + this._actionsSorted = false; + + if(_args && (_args.length > 0)) _local_3 = _args[0]; + + if((_local_3 !== undefined) && (_local_3 !== null)) _local_3 = _local_3.toString(); + + switch(k) + { + case AvatarAction.POSTURE: + switch(_local_3) + { + case AvatarAction.POSTURE_LAY: + case AvatarAction.POSTURE_WALK: + case AvatarAction.POSTURE_STAND: + case AvatarAction.POSTURE_SWIM: + case AvatarAction.POSTURE_FLOAT: + case AvatarAction.POSTURE_SIT: + case AvatarAction.SNOWWAR_RUN: + case AvatarAction.SNOWWAR_DIE_FRONT: + case AvatarAction.SNOWWAR_DIE_BACK: + case AvatarAction.SNOWWAR_PICK: + case AvatarAction.SNOWWAR_THROW: + if((_local_3 === AvatarAction.POSTURE_LAY) || (_local_3 === AvatarAction.POSTURE_LAY) || (_local_3 === AvatarAction.POSTURE_LAY)) + { + if(_local_3 === AvatarAction.POSTURE_LAY) + { + if(this._mainDirection == 0) + { + this.setDirection(AvatarSetType.FULL, 4); + } + else + { + this.setDirection(AvatarSetType.FULL, 2); + } + } + } + + this.addActionData(_local_3); + break; + } + break; + case AvatarAction.GESTURE: + switch(_local_3) + { + case AvatarAction.GESTURE_AGGRAVATED: + case AvatarAction.GESTURE_SAD: + case AvatarAction.GESTURE_SMILE: + case AvatarAction.GESTURE_SURPRISED: + this.addActionData(_local_3); + break; + } + break; + case AvatarAction.EFFECT: + case AvatarAction.DANCE: + case AvatarAction.TALK: + case AvatarAction.EXPRESSION_WAVE: + case AvatarAction.SLEEP: + case AvatarAction.SIGN: + case AvatarAction.EXPRESSION_RESPECT: + case AvatarAction.EXPRESSION_BLOW_A_KISS: + case AvatarAction.EXPRESSION_LAUGH: + case AvatarAction.EXPRESSION_CRY: + case AvatarAction.EXPRESSION_IDLE: + case AvatarAction.EXPRESSION_SNOWBOARD_OLLIE: + case AvatarAction.EXPRESSION_SNOWBORD_360: + case AvatarAction.EXPRESSION_RIDE_JUMP: + this.addActionData(k, _local_3); + break; + case AvatarAction.CARRY_OBJECT: + case AvatarAction.USE_OBJECT: { + const _local_4 = this._structure.getActionDefinitionWithState(k); + if(_local_4) _local_3 = _local_4.getParameterValue(_local_3); + this.addActionData(k, _local_3); + break; + } + } + + return true; + } + + protected addActionData(k: string, _arg_2: string=''): void + { + let _local_3:ActiveActionData; + if(!this._actions) this._actions = []; + + let _local_4 = 0; + while(_local_4 < this._actions.length) + { + _local_3 = this._actions[_local_4]; + if(((_local_3.actionType == k) && (_local_3.actionParameter == _arg_2))) + { + return; + } + _local_4++; + } + this._actions.push(new ActiveActionData(k, _arg_2, this._frameCounter)); + } + + public isAnimating(): boolean + { + return (this._isAnimating) || (this._animationFrameCount > 1); + } + + private resetActions(): boolean + { + this._animationHasResetOnToggle = false; + this._isAnimating = false; + this._sprites = []; + this._avatarSpriteData = null; + this._directionOffset = 0; + this._structure.removeDynamicItems(this); + this._mainAction = this._defaultAction; + this._mainAction.definition = this._defaultAction.definition; + this.resetBodyPartCache(this._defaultAction); + return true; + } + + private isHeadTurnPreventedByAction(): boolean + { + let _local_2: IActionDefinition; + let _local_3: ActiveActionData; + let k: boolean; + if(this._sortedActions == null) + { + return false; + } + for(const _local_3 of this._sortedActions) + { + _local_2 = this._structure.getActionDefinitionWithState(_local_3.actionType); + if(((!(_local_2 == null)) && (_local_2.getPreventHeadTurn(_local_3.actionParameter)))) + { + k = true; + } + } + return k; + } + + private sortActions(): boolean + { + let _local_2: boolean; + let _local_3: boolean; + let _local_4:ActiveActionData; + let _local_5: number; + let k: boolean; + + this._currentActionsString = ''; + this._sortedActions = this._structure.sortActions(this._actions); + this._animationFrameCount = this._structure.maxFrames(this._sortedActions); + + if(!this._sortedActions) + { + this._canvasOffsets = [ 0, 0, 0 ]; + + if(this._lastActionsString !== '') + { + k = true; + + this._lastActionsString = ''; + } + } + else + { + this._canvasOffsets = this._structure.getCanvasOffsets(this._sortedActions, this._scale, this._mainDirection); + + for(const _local_4 of this._sortedActions) + { + this._currentActionsString = (this._currentActionsString + (_local_4.actionType + _local_4.actionParameter)); + + if(_local_4.actionType === AvatarAction.EFFECT) + { + const _local_5 = parseInt(_local_4.actionParameter); + + if(this._effectIdInUse !== _local_5) _local_2 = true; + + this._effectIdInUse = _local_5; + + _local_3 = true; + } + } + + if(!_local_3) + { + if(this._effectIdInUse > -1) _local_2 = true; + + this._effectIdInUse = -1; + } + + if(_local_2) this._cache.disposeInactiveActions(0); + + if(this._lastActionsString != this._currentActionsString) + { + k = true; + + this._lastActionsString = this._currentActionsString; + } + } + + this._actionsSorted = true; + + return k; + } + + private setActionsToParts(): void + { + if(!this._sortedActions == null) return; + + const _local_3: number = Date.now(); + const _local_4: string[] = []; + + for(const k of this._sortedActions) _local_4.push(k.actionType); + + for(const k of this._sortedActions) + { + if((k && k.definition) && k.definition.isAnimation) + { + const _local_2 = this._structure.getAnimation(((k.definition.state + '.') + k.actionParameter)); + + if(_local_2 && _local_2.hasOverriddenActions()) + { + const _local_5 = _local_2.overriddenActionNames(); + + if(_local_5) + { + for(const _local_6 of _local_5) + { + if(_local_4.indexOf(_local_6) >= 0) k.overridingAction = _local_2.overridingAction(_local_6); + } + } + } + + if(_local_2 && _local_2.resetOnToggle) + { + this._animationHasResetOnToggle = true; + } + } + } + + for(const k of this._sortedActions) + { + if(!((!(k)) || (!(k.definition)))) + { + if(k.definition.isAnimation && (k.actionParameter === '')) k.actionParameter = '1'; + + this.setActionToParts(k, _local_3); + + if(k.definition.isAnimation) + { + this._isAnimating = k.definition.isAnimated(k.actionParameter); + + const _local_2 = this._structure.getAnimation(((k.definition.state + '.') + k.actionParameter)); + + if(_local_2) + { + this._sprites = this._sprites.concat(_local_2.spriteData); + + if(_local_2.hasDirectionData()) this._directionOffset = _local_2.directionData.offset; + + if(_local_2.hasAvatarData()) this._avatarSpriteData = _local_2.avatarData; + } + } + } + } + } + + private setActionToParts(k: IActiveActionData, _arg_2: number): void + { + if(((k == null) || (k.definition == null))) + { + return; + } + if(k.definition.assetPartDefinition == '') + { + return; + } + if(k.definition.isMain) + { + this._mainAction = k; + this._cache.setGeometryType(k.definition.geometryType); + } + this._cache.setAction(k, _arg_2); + } + + private resetBodyPartCache(k: IActiveActionData): void + { + if(!k) return; + + if(k.definition.assetPartDefinition === '') return; + + if(k.definition.isMain) + { + this._mainAction = k; + this._cache.setGeometryType(k.definition.geometryType); + } + + this._cache.resetBodyPartCache(k); + } + + public get avatarSpriteData(): IAvatarDataContainer + { + return this._avatarSpriteData; + } + + // private convertToGrayscale(container: Canvas, channel: string = 'CHANNELS_EQUAL'): Canvas + // { + // let _local_3 = 0.33; + // let _local_4 = 0.33; + // let _local_5 = 0.33; + // const _local_6 = 1; + + // switch(channel) + // { + // case AvatarImage.CHANNELS_UNIQUE: + // _local_3 = 0.3; + // _local_4 = 0.59; + // _local_5 = 0.11; + // break; + // case AvatarImage.CHANNELS_RED: + // _local_3 = 1; + // _local_4 = 0; + // _local_5 = 0; + // break; + // case AvatarImage.CHANNELS_GREEN: + // _local_3 = 0; + // _local_4 = 1; + // _local_5 = 0; + // break; + // case AvatarImage.CHANNELS_BLUE: + // _local_3 = 0; + // _local_4 = 0; + // _local_5 = 1; + // break; + // case AvatarImage.CHANNELS_DESATURATED: + // _local_3 = 0.3086; + // _local_4 = 0.6094; + // _local_5 = 0.082; + // break; + // } + + // const colorFilter = new ColorMatrixFilter(); + + // colorFilter.matrix = [_local_3, _local_4, _local_5, 0, 0, _local_3, _local_4, _local_5, 0, 0, _local_3, _local_4, _local_5, 0, 0, 0, 0, 0, 1, 0]; + + // container.filters = [ colorFilter ]; + + // return container; + // } + + public isPlaceholder(): boolean + { + return false; + } + + public forceActionUpdate(): void + { + this._lastActionsString = ''; + } + + public get animationHasResetOnToggle(): boolean + { + return this._animationHasResetOnToggle; + } + + public get mainAction(): string + { + return this._mainAction.actionType; + } +} diff --git a/src/app/avatar/AvatarImageBodyPartContainer.ts b/src/app/avatar/AvatarImageBodyPartContainer.ts new file mode 100644 index 0000000..dcf46d1 --- /dev/null +++ b/src/app/avatar/AvatarImageBodyPartContainer.ts @@ -0,0 +1,74 @@ +import { Canvas } from 'canvas'; +import { Point } from '../../core'; + +export class AvatarImageBodyPartContainer +{ + private _image: Canvas; + private _regPoint: Point; + private _offset: Point; + private _isCacheable: boolean; + + constructor(image: Canvas, regPoint: Point, isCacheable: boolean) + { + this._image = image; + this._regPoint = regPoint; + this._offset = new Point(0, 0); + this._isCacheable = isCacheable; + + this.cleanPoints(); + } + + public dispose(): void + { + this._image = null; + this._regPoint = null; + this._offset = null; + } + + private cleanPoints(): void + { + // this._regPoint.x = this._regPoint.x; + // this._regPoint.y = this._regPoint.y; + // this._offset.x = this._offset.x; + // this._offset.y = this._offset.y; + } + + public setRegPoint(k: Point): void + { + this._regPoint = k; + + this.cleanPoints(); + } + + public get image(): Canvas + { + return this._image; + } + + public set image(k: Canvas) + { + this._image = k; + } + + public get regPoint(): Point + { + const clone = this._regPoint.clone(); + + clone.x += this._offset.x; + clone.y += this._offset.y; + + return clone; + } + + public set offset(k: Point) + { + this._offset = k; + + this.cleanPoints(); + } + + public get isCacheable(): boolean + { + return this._isCacheable; + } +} diff --git a/src/app/avatar/AvatarImagePartContainer.ts b/src/app/avatar/AvatarImagePartContainer.ts new file mode 100644 index 0000000..ce7af9e --- /dev/null +++ b/src/app/avatar/AvatarImagePartContainer.ts @@ -0,0 +1,134 @@ +import { IActionDefinition } from './actions/IActionDefinition'; +import { AvatarAnimationFrame } from './structure/animation/AvatarAnimationFrame'; +import { IPartColor } from './structure/figure/IPartColor'; + +export class AvatarImagePartContainer +{ + private _bodyPartId: string; + private _partType: string; + private _flippedPartType: string; + private _partId: string; + private _color: IPartColor; + private _frames: AvatarAnimationFrame[]; + private _action: IActionDefinition; + private _isColorable: boolean; + private _isBlendable: boolean; + private _paletteMapId: number; + + constructor(k: string, _arg_2: string, _arg_3: string, _arg_4: IPartColor, _arg_5: AvatarAnimationFrame[], _arg_6: IActionDefinition, _arg_7: boolean, _arg_8: number, _arg_9: string = '', _arg_10: boolean = false, _arg_11: number = 1) + { + this._bodyPartId = k; + this._partType = _arg_2; + this._partId = _arg_3; + this._color = _arg_4; + this._frames = _arg_5; + this._action = _arg_6; + this._isColorable = _arg_7; + this._paletteMapId = _arg_8; + this._flippedPartType = _arg_9; + this._isBlendable = _arg_10; + + if(this._partType === 'ey') this._isColorable = false; + } + + public getFrameIndex(k: number): number + { + if(!this._frames || !this._frames.length) return 0; + + const frameNumber = (k % this._frames.length); + + if(this._frames[frameNumber] instanceof AvatarAnimationFrame) + { + return this._frames[frameNumber].number; + } + + return frameNumber; + } + + public getFrameDefinition(k: number): AvatarAnimationFrame + { + const frameNumber = (k % this._frames.length); + + if(this._frames && (this._frames.length > frameNumber)) + { + if(this._frames[frameNumber] instanceof AvatarAnimationFrame) + { + return this._frames[frameNumber]; + } + } + + return null; + } + + public getCacheableKey(k: number): string + { + const frameNumber = (k % this._frames.length); + + if(this._frames && (this._frames.length > frameNumber)) + { + if(this._frames[frameNumber] instanceof AvatarAnimationFrame) + { + const frame = this._frames[frameNumber]; + + return (this.partId + ':' + frame.assetPartDefinition + ':' + frame.number); + } + } + + return (this.partId + ':' + frameNumber); + } + + public get bodyPartId(): string + { + return this._bodyPartId; + } + + public get partType(): string + { + return this._partType; + } + + public get partId(): string + { + return this._partId; + } + + public get color(): IPartColor + { + return this._color; + } + + public get action(): IActionDefinition + { + return this._action; + } + + public get isColorable(): boolean + { + return this._isColorable; + } + + public set isColorable(k: boolean) + { + this._isColorable = k; + } + + public get paletteMapId(): number + { + return this._paletteMapId; + } + + public get flippedPartType(): string + { + return this._flippedPartType; + } + + public get isBlendable(): boolean + { + return this._isBlendable; + } + + public toString(): string + { + return [ this._bodyPartId, this._partType, this._partId ].join(':'); + } +} diff --git a/src/app/avatar/AvatarRenderManager.ts b/src/app/avatar/AvatarRenderManager.ts new file mode 100644 index 0000000..a0e458d --- /dev/null +++ b/src/app/avatar/AvatarRenderManager.ts @@ -0,0 +1,310 @@ +import fetch from 'node-fetch'; +import { IAssetManager, IGraphicAsset, NitroManager } from '../../core'; +import { Application } from '../Application'; +import { AssetAliasCollection } from './alias'; +import { AvatarAssetDownloadManager } from './AvatarAssetDownloadManager'; +import { AvatarFigureContainer } from './AvatarFigureContainer'; +import { AvatarImage } from './AvatarImage'; +import { AvatarStructure } from './AvatarStructure'; +import { HabboAvatarAnimations, HabboAvatarGeometry, HabboAvatarPartSets } from './data'; +import { EffectAssetDownloadManager } from './EffectAssetDownloadManager'; +import { AvatarSetType } from './enum'; +import { FigureDataContainer } from './FigureDataContainer'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; +import { IAvatarImage } from './IAvatarImage'; +import { IAvatarRenderManager } from './IAvatarRenderManager'; +import { IFigureData } from './interfaces'; +import { IFigurePartSet, IStructureData } from './structure'; + +export class AvatarRenderManager extends NitroManager implements IAvatarRenderManager +{ + private static DEFAULT_FIGURE: string = 'hd-99999-99999'; + + private _aliasCollection: AssetAliasCollection; + + private _assets: IAssetManager; + private _structure: AvatarStructure; + private _avatarAssetDownloadManager: AvatarAssetDownloadManager; + private _effectAssetDownloadManager: EffectAssetDownloadManager; + private _placeHolderFigure: AvatarFigureContainer; + + constructor(assets: IAssetManager) + { + super(); + + this._assets = assets; + this._structure = null; + this._avatarAssetDownloadManager = null; + this._effectAssetDownloadManager = null; + this._placeHolderFigure = null; + } + + public async onInit(): Promise + { + this._structure = new AvatarStructure(this); + + this._structure.initGeometry(HabboAvatarGeometry.geometry); + this._structure.initPartSets(HabboAvatarPartSets.partSets); + this._structure.initAnimation(HabboAvatarAnimations.animations); + await this.loadActions(); + this.loadFigureData(); + + this._aliasCollection = new AssetAliasCollection(this, this._assets); + + this._aliasCollection.init(); + + if(!this._avatarAssetDownloadManager) + { + this._avatarAssetDownloadManager = new AvatarAssetDownloadManager(this._assets, this._structure); + + await this._avatarAssetDownloadManager.loadFigureMap(); + } + + if(!this._effectAssetDownloadManager) + { + this._effectAssetDownloadManager = new EffectAssetDownloadManager(this._assets, this._structure); + + await this._effectAssetDownloadManager.loadEffectMap(); + } + } + + private async loadActions(): Promise + { + this._structure.initActions({ + "actions": [ + { + "id": "Default", + "state": "std", + "precedence": 1000, + "main": true, + "isDefault": true, + "geometryType": "vertical", + "activePartSet": "figure", + "assetPartDefinition": "std" + } + ] + }); + + const url = Application.instance.getConfiguration('avatar.actions.url'); + + const data = await fetch(url); + + this._structure.updateActions(await data.json()); + } + + private async loadFigureData(): Promise + { + const defaultFigureData = Application.instance.getConfiguration('avatar.default.figuredata'); + + if(this._structure) this._structure.initFigureData(defaultFigureData); + + const url = Application.instance.getConfiguration('avatar.figuredata.url'); + + const data = await fetch(url); + + this._structure.figureData.appendJSON(await data.json()); + } + + public createFigureContainer(figure: string): IAvatarFigureContainer + { + return new AvatarFigureContainer(figure); + } + + public isFigureContainerReady(container: IAvatarFigureContainer): boolean + { + if(!this._avatarAssetDownloadManager) return false; + + return this._avatarAssetDownloadManager.isAvatarFigureContainerReady(container); + } + + public async createAvatarImage(figure: string, size: string, gender: string): Promise + { + if(!this._structure || !this._avatarAssetDownloadManager) return null; + + const figureContainer = new AvatarFigureContainer(figure); + + if(gender) this.validateAvatarFigure(figureContainer, gender); + + if(!this._avatarAssetDownloadManager.isAvatarFigureContainerReady(figureContainer)) + { + await this._avatarAssetDownloadManager.downloadAvatarFigure(figureContainer); + } + + if(!this._placeHolderFigure) this._placeHolderFigure = new AvatarFigureContainer(AvatarRenderManager.DEFAULT_FIGURE); + + return new AvatarImage(this._structure, this._aliasCollection, figureContainer, size, this._effectAssetDownloadManager); + } + + public async downloadAvatarFigure(container: IAvatarFigureContainer): Promise + { + if(!this._avatarAssetDownloadManager) return; + + await this._avatarAssetDownloadManager.downloadAvatarFigure(container); + } + + private validateAvatarFigure(container: AvatarFigureContainer, gender: string): boolean + { + let isValid = false; + + const typeIds = this._structure.getMandatorySetTypeIds(gender, 2); + + if(typeIds) + { + const figureData = this._structure.figureData; + + for(const id of typeIds) + { + if(!container.hasPartType(id)) + { + const figurePartSet = this._structure.getDefaultPartSet(id, gender); + + if(figurePartSet) + { + container.updatePart(id, figurePartSet.id, [0]); + + isValid = true; + } + } + else + { + const setType = figureData.getSetType(id); + + if(setType) + { + const figurePartSet = setType.getPartSet(container.getPartSetId(id)); + + if(!figurePartSet) + { + const partSet = this._structure.getDefaultPartSet(id, gender); + + if(partSet) + { + container.updatePart(id, partSet.id, [0]); + + isValid = true; + } + } + } + } + } + } + + return !(isValid); + } + + public getFigureClubLevel(container: IAvatarFigureContainer, gender: string, searchParts: string[]): number + { + if(!this._structure) return 0; + + const figureData = this._structure.figureData; + const parts = Array.from(container.getPartTypeIds()); + + let clubLevel = 0; + + for(const part of parts) + { + const set = figureData.getSetType(part); + const setId = container.getPartSetId(part); + const partSet = set.getPartSet(setId); + + if(partSet) + { + clubLevel = Math.max(partSet.clubLevel, clubLevel); + + const palette = figureData.getPalette(set.paletteID); + const colors = container.getPartColorIds(part); + + for(const colorId of colors) + { + const color = palette.getColor(colorId); + + clubLevel = Math.max(color.clubLevel, clubLevel); + } + } + } + + if(!searchParts) searchParts = this._structure.getBodyPartsUnordered(AvatarSetType.FULL); + + for(const part of searchParts) + { + const set = figureData.getSetType(part); + + if(parts.indexOf(part) === -1) clubLevel = Math.max(set.optionalFromClubLevel(gender), clubLevel); + } + + return clubLevel; + } + + public isValidFigureSetForGender(setId: number, gender: string): boolean + { + const structure = this.structureData; + const partSet = structure.getFigurePartSet(setId); + + return !!(partSet && ((partSet.gender.toUpperCase() === 'U') || (partSet.gender.toUpperCase() === gender.toUpperCase()))); + } + + public getFigureStringWithFigureIds(k: string, _arg_2: string, _arg_3: number[]): string + { + const container = new FigureDataContainer(); + + container.loadAvatarData(k, _arg_2); + + const partSets: IFigurePartSet[] = this.resolveFigureSets(_arg_3); + + for(const partSet of partSets) + { + container.savePartData(partSet.type, partSet.id, container.getColourIds(partSet.type)); + } + + return container.getFigureString(); + } + + private resolveFigureSets(k: number[]): IFigurePartSet[] + { + const structure = this.structureData; + const partSets: IFigurePartSet[] = []; + + for(const _local_4 of k) + { + const partSet = structure.getFigurePartSet(_local_4); + + if(partSet) partSets.push(partSet); + } + + return partSets; + } + + public getMandatoryAvatarPartSetIds(k: string, _arg_2: number): string[] + { + if(!this._structure) return null; + + return this._structure.getMandatorySetTypeIds(k, _arg_2); + } + + public getAssetByName(name: string): IGraphicAsset + { + return this._aliasCollection.getAsset(name); + } + + public get assets(): IAssetManager + { + return this._assets; + } + + public get structure(): AvatarStructure + { + return this._structure; + } + + public get structureData(): IStructureData + { + if(this._structure) return this._structure.figureData; + + return null; + } + + public get downloadManager(): AvatarAssetDownloadManager + { + return this._avatarAssetDownloadManager; + } +} diff --git a/src/app/avatar/AvatarStructure.ts b/src/app/avatar/AvatarStructure.ts new file mode 100644 index 0000000..5a8acbb --- /dev/null +++ b/src/app/avatar/AvatarStructure.ts @@ -0,0 +1,630 @@ +import { AdvancedMap, IAssetAnimation, IAssetManager, Point } from '../../core'; +import { ActionDefinition, AvatarActionManager, IActionDefinition, IActiveActionData } from './actions'; +import { Animation, AnimationManager, AvatarAnimationLayerData } from './animation'; +import { AvatarImagePartContainer } from './AvatarImagePartContainer'; +import { AvatarRenderManager } from './AvatarRenderManager'; +import { AvatarDirectionAngle } from './enum'; +import { AvatarModelGeometry } from './geometry'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; +import { IAvatarImage } from './IAvatarImage'; +import { IAvatarRenderManager } from './IAvatarRenderManager'; +import { IFigureData } from './interfaces'; +import { AnimationAction, AvatarAnimationData, AvatarAnimationFrame, AvatarCanvas, FigureSetData, IFigurePartSet, IPartColor, IStructureData, PartSetsData } from './structure'; + +export class AvatarStructure +{ + private _renderManager: AvatarRenderManager; + private _geometry: AvatarModelGeometry; + private _figureData: FigureSetData; + private _partSetsData: PartSetsData; + private _animationData: AvatarAnimationData; + private _animationManager: AnimationManager; + private _mandatorySetTypeIds: { [index: string]: { [index: number]: string[] } }; + private _actionManager: AvatarActionManager; + private _defaultAction: IActionDefinition; + + constructor(renderManager: AvatarRenderManager) + { + this._renderManager = renderManager; + this._geometry = null; + this._figureData = new FigureSetData(); + this._partSetsData = new PartSetsData(); + this._animationData = new AvatarAnimationData(); + this._animationManager = new AnimationManager(); + this._mandatorySetTypeIds = {}; + this._actionManager = null; + this._defaultAction = null; + } + + public init(): void + { + + } + + public dispose(): void + { + this._renderManager = null; + this._figureData = null; + this._partSetsData = null; + this._animationData = null; + this._mandatorySetTypeIds = null; + } + + public initGeometry(k: any): void + { + if(!k) return; + + this._geometry = new AvatarModelGeometry(k); + } + + public initActions(actions: any): void + { + this._actionManager = new AvatarActionManager(actions); + this._defaultAction = this._actionManager.getDefaultAction(); + } + + public updateActions(data: any): void + { + this._actionManager.updateActions(data); + + this._defaultAction = this._actionManager.getDefaultAction(); + } + + public initPartSets(k: any): boolean + { + if(!k) return false; + + if(this._partSetsData.parse(k)) + { + this._partSetsData.getPartDefinition('ri').appendToFigure = true; + this._partSetsData.getPartDefinition('li').appendToFigure = true; + + return true; + } + + return false; + } + + public initAnimation(k: any): boolean + { + if(!k) return false; + + return this._animationData.parse(k); + } + + public initFigureData(k: IFigureData): boolean + { + if(!k) return false; + + return this._figureData.parse(k); + } + + public injectFigureData(data: IFigureData): void + { + this._figureData.injectJSON(data); + } + + public registerAnimations(k: IAssetManager, _arg_2: string = 'fx', _arg_3: number = 200): void + { + let index = 0; + + while(index < _arg_3) + { + const collection = k.getCollection((_arg_2 + index)); + + if(collection) + { + const animationData = collection.data; + + this._animationManager.registerAnimation(this, animationData.animations); + } + + index++; + } + } + + public registerAnimation(data: { [index: string]: IAssetAnimation }): void + { + this._animationManager.registerAnimation(this, data); + } + + public getPartColor(k: IAvatarFigureContainer, _arg_2: string, _arg_3: number = 0): IPartColor + { + const _local_4 = k.getPartColorIds(_arg_2); + + if((!(_local_4)) || (_local_4.length < _arg_3)) return null; + + const _local_5 = this._figureData.getSetType(_arg_2); + + if(_local_5 == null) return null; + + const _local_6 = this._figureData.getPalette(_local_5.paletteID); + + if(!_local_6) return null; + + return _local_6.getColor(_local_4[_arg_3]); + } + + public getBodyPartData(animation: string, frameCount: number, spriteId: string): AvatarAnimationLayerData + { + return this._animationManager.getLayerData(animation, frameCount, spriteId) as AvatarAnimationLayerData; + } + + public getAnimation(k: string): Animation + { + return this._animationManager.getAnimation(k) as Animation; + } + + public getActionDefinition(k: string): ActionDefinition + { + return this._actionManager.getActionDefinition(k); + } + + public getActionDefinitionWithState(k: string): ActionDefinition + { + return this._actionManager.getActionDefinitionWithState(k); + } + + public isMainAvatarSet(k: string): boolean + { + return this._geometry.isMainAvatarSet(k); + } + + public sortActions(k: IActiveActionData[]): IActiveActionData[] + { + return this._actionManager.sortActions(k); + } + + public maxFrames(k: IActiveActionData[]): number + { + let _local_2 = 0; + + for(const _local_3 of k) + { + _local_2 = Math.max(_local_2, this._animationData.getFrameCount(_local_3.definition)); + } + return _local_2; + } + + public getMandatorySetTypeIds(k: string, _arg_2: number): string[] + { + if(!this._mandatorySetTypeIds[k]) + { + this._mandatorySetTypeIds[k] = []; + } + + if(this._mandatorySetTypeIds[k][_arg_2]) + { + return this._mandatorySetTypeIds[k][_arg_2]; + } + + this._mandatorySetTypeIds[k][_arg_2] = this._figureData.getMandatorySetTypeIds(k, _arg_2); + + return this._mandatorySetTypeIds[k][_arg_2]; + } + + public getDefaultPartSet(k: string, _arg_2: string): IFigurePartSet + { + return this._figureData.getDefaultPartSet(k, _arg_2); + } + + public getCanvasOffsets(k: IActiveActionData[], _arg_2: string, _arg_3: number): number[] + { + return this._actionManager.getCanvasOffsets(k, _arg_2, _arg_3); + } + + public getCanvas(k: string, _arg_2: string): AvatarCanvas + { + return this._geometry.getCanvas(k, _arg_2); + } + + public removeDynamicItems(k: IAvatarImage): void + { + this._geometry.removeDynamicItems(k); + } + + public getActiveBodyPartIds(k: IActiveActionData, _arg_2: IAvatarImage): string[] + { + let _local_3: string[] = []; + + const _local_4: string[] = []; + const _local_5 = k.definition.geometryType; + + if(k.definition.isAnimation) + { + const _local_7 = ((k.definition.state + '.') + k.actionParameter); + const _local_8 = this._animationManager.getAnimation(_local_7); + + if(_local_8) + { + _local_3 = _local_8.getAnimatedBodyPartIds(0, k.overridingAction); + + if(_local_8.hasAddData()) + { + const _local_11 = { + id: '', + x: 0, + y: 0, + z: 0, + radius: 0.01, + nx: 0, + ny: 0, + nz: -1, + double: 1 + }; + + const _local_12 = { + setType: '' + }; + + for(const _local_13 of _local_8.addData) + { + const _local_6 = this._geometry.getBodyPart(_local_5, _local_13.align); + + if(_local_6) + { + _local_11.id = _local_13.id; + _local_6.addPart(_local_11, _arg_2); + + _local_12.setType = _local_13.id; + + const _local_10 = this._partSetsData.addPartDefinition(_local_12); + _local_10.appendToFigure = true; + + if(_local_13.base === '') _local_10.staticId = 1; + + if(_local_4.indexOf(_local_6.id) === -1) _local_4.push(_local_6.id); + } + } + } + } + + for(const _local_9 of _local_3) + { + const _local_6 = this._geometry.getBodyPart(_local_5, _local_9); + + if(_local_6 && (_local_4.indexOf(_local_6.id) === -1)) _local_4.push(_local_6.id); + } + } + else + { + _local_3 = this._partSetsData.getActiveParts(k.definition); + + for(const _local_14 of _local_3) + { + const _local_6 = this._geometry.getBodyPartOfItem(_local_5, _local_14, _arg_2); + + if(_local_6 && (_local_4.indexOf(_local_6.id) === -1)) _local_4.push(_local_6.id); + } + } + + return _local_4; + } + + public getBodyPartsUnordered(k: string): string[] + { + return this._geometry.getBodyPartIdsInAvatarSet(k); + } + + public getBodyParts(k: string, _arg_2: string, _arg_3: number): string[] + { + const _local_4 = AvatarDirectionAngle.DIRECTION_TO_ANGLE[_arg_3]; + + return this._geometry.getBodyPartsAtAngle(k, _local_4, _arg_2); + } + + public getFrameBodyPartOffset(k:IActiveActionData, _arg_2: number, _arg_3: number, _arg_4: string): Point + { + const _local_5 = this._animationData.getAction(k.definition); + + if(_local_5) return _local_5.getFrameBodyPartOffset(_arg_2, _arg_3, _arg_4); + + return AnimationAction.DEFAULT_OFFSET; + } + + public getParts(k: string, _arg_2:IAvatarFigureContainer, _arg_3:IActiveActionData, _arg_4: string, _arg_5: number, removes: string[], _arg_7: IAvatarImage, _arg_8: AdvancedMap = null): AvatarImagePartContainer[] + { + const _local_10: Animation = null; + let _local_34: IActionDefinition = null; + + let _local_20: AvatarAnimationFrame[] = []; + let _local_36:IPartColor = null; + + if(!_arg_3 == null) return []; + + const _local_9 = this._partSetsData.getActiveParts(_arg_3.definition); + const _local_11: AvatarImagePartContainer[] = []; + let _local_14: any[] = [ 0 ]; + const _local_15 = this._animationData.getAction(_arg_3.definition); + + if(_arg_3.definition.isAnimation) + { + const _local_24 = ((_arg_3.definition.state + '.') + _arg_3.actionParameter); + const _local_10 = this._animationManager.getAnimation(_local_24); + + if(_local_10) + { + _local_14 = this.getPopulatedArray(_local_10.frameCount(_arg_3.overridingAction)); + + for(const _local_25 of _local_10.getAnimatedBodyPartIds(0, _arg_3.overridingAction)) + { + if(_local_25 === k) + { + const _local_26 = this._geometry.getBodyPart(_arg_4, _local_25); + + if(_local_26) + { + for(const _local_27 of _local_26.getDynamicParts(_arg_7)) + { + _local_9.push(_local_27.id); + } + } + } + } + } + } + + const _local_16 = this._geometry.getParts(_arg_4, k, _arg_5, _local_9, _arg_7); + const _local_21 = _arg_2.getPartTypeIds(); + + for(const _local_17 of _local_21) + { + if(_arg_8) + { + if(_arg_8.getValue(_local_17)) continue; + } + + const _local_28 = _arg_2.getPartSetId(_local_17); + const _local_29 = _arg_2.getPartColorIds(_local_17); + const _local_30 = this._figureData.getSetType(_local_17); + + + + if(_local_30) + { + const _local_31 = this._figureData.getPalette(_local_30.paletteID); + + if(_local_31) + { + const _local_32 = _local_30.getPartSet(_local_28); + + if(_local_32) + { + removes = removes.concat(_local_32.hiddenLayers); + + for(const _local_33 of _local_32.parts) + { + if(_local_16.indexOf(_local_33.type) > -1) + { + if(_local_15) + { + const _local_19 = _local_15.getPart(_local_33.type); + + if(_local_19) + { + _local_20 = _local_19.frames; + } + else + { + _local_20 = _local_14; + } + } + else + { + _local_20 = _local_14; + } + + _local_34 = _arg_3.definition; + + if(_local_9.indexOf(_local_33.type) === -1) _local_34 = this._defaultAction; + + const _local_13 = this._partSetsData.getPartDefinition(_local_33.type); + + let _local_35 = (!_local_13) ? _local_33.type : _local_13.flippedSetType; + + if(!_local_35 || (_local_35 === '')) _local_35 = _local_33.type; + + if(_local_29 && (_local_29.length > (_local_33.colorLayerIndex - 1))) + { + _local_36 = _local_31.getColor(_local_29[(_local_33.colorLayerIndex - 1)]); + } + + const _local_37 = (_local_33.colorLayerIndex > 0); + const _local_18 = new AvatarImagePartContainer(k, _local_33.type, _local_33.id.toString(), _local_36, _local_20, _local_34, _local_37, _local_33.paletteMap, _local_35); + + _local_11.push(_local_18); + } + } + } + } + } + } + + const _local_22: AvatarImagePartContainer[] = []; + + for(const _local_12 of _local_16) + { + let _local_39: IPartColor = null; + let _local_38 = false; + + const _local_40 = ((_arg_8) && (_arg_8.getValue(_local_12))); + + for(const _local_23 of _local_11) + { + if(_local_23.partType === _local_12) + { + if(_local_40) + { + _local_39 = _local_23.color; + } + else + { + _local_38 = true; + + if(removes.indexOf(_local_12) === -1) _local_22.push(_local_23); + } + } + } + + if(!_local_38) + { + if(_local_40) + { + const _local_41 = _arg_8.getValue(_local_12); + + let _local_42 = 0; + let _local_43 = 0; + + while(_local_43 < _local_41.length) + { + _local_42 = (_local_42 + _local_41.charCodeAt(_local_43)); + _local_43++; + } + + if(_local_15) + { + const _local_19 = _local_15.getPart(_local_12); + + if(_local_19) + { + _local_20 = _local_19.frames; + } + else + { + _local_20 = _local_14; + } + } + else + { + _local_20 = _local_14; + } + + const _local_18 = new AvatarImagePartContainer(k, _local_12, _local_41, _local_39, _local_20, _arg_3.definition, (!(_local_39 == null)), -1, _local_12, false, 1); + + _local_22.push(_local_18); + } + else + { + if(_local_9.indexOf(_local_12) > -1) + { + const _local_44 = this._geometry.getBodyPartOfItem(_arg_4, _local_12, _arg_7); + + if(k !== _local_44.id) + { + // + } + else + { + const _local_13 = this._partSetsData.getPartDefinition(_local_12); + + let _local_45 = false; + let _local_46 = 1; + + if(_local_13.appendToFigure) + { + let _local_47 = '1'; + + if(_arg_3.actionParameter !== '') + { + _local_47 = _arg_3.actionParameter; + } + + if(_local_13.hasStaticId()) + { + _local_47 = _local_13.staticId.toString(); + } + + if(_local_10 != null) + { + const _local_48 = _local_10.getAddData(_local_12); + + if(_local_48) + { + _local_45 = _local_48.isBlended; + _local_46 = _local_48.blend; + } + } + + if(_local_15) + { + const _local_19 = _local_15.getPart(_local_12); + + if(_local_19) + { + _local_20 = _local_19.frames; + } + else + { + _local_20 = _local_14; + } + } + else + { + _local_20 = _local_14; + } + + const _local_18 = new AvatarImagePartContainer(k, _local_12, _local_47, null, _local_20, _arg_3.definition, false, -1, _local_12, _local_45, _local_46); + + _local_22.push(_local_18); + } + } + } + } + } + } + + return _local_22; + } + + private getPopulatedArray(k: number): number[] + { + const _local_2: number[] = []; + + let index = 0; + + while(index < k) + { + _local_2.push(index); + + index++; + } + + return _local_2; + } + + public getItemIds(): string[] + { + if(this._actionManager) + { + const k = this._actionManager.getActionDefinition('CarryItem').params; + + const _local_2 = []; + + for(const _local_3 of k.getValues()) _local_2.push(_local_3); + + return _local_2; + } + + return []; + } + + public get renderManager(): IAvatarRenderManager + { + return this._renderManager; + } + + public get figureData(): IStructureData + { + return this._figureData; + } + + public get partData(): PartSetsData + { + return this._partSetsData; + } + + public get animationManager(): AnimationManager + { + return this._animationManager; + } +} diff --git a/src/app/avatar/EffectAssetDownloadLibrary.ts b/src/app/avatar/EffectAssetDownloadLibrary.ts new file mode 100644 index 0000000..bfd16f9 --- /dev/null +++ b/src/app/avatar/EffectAssetDownloadLibrary.ts @@ -0,0 +1,78 @@ +import { IAssetAnimation, IAssetManager } from '../../core'; + +export class EffectAssetDownloadLibrary +{ + private static NOT_LOADED: number = 0; + private static LOADING: number = 1; + private static LOADED: number = 2; + + private _state: number; + private _libraryName: string; + private _revision: string; + private _downloadUrl: string; + private _assets: IAssetManager; + private _animation: { [index: string]: IAssetAnimation }; + + constructor(id: string, revision: string, assets: IAssetManager, assetUrl: string) + { + this._state = EffectAssetDownloadLibrary.NOT_LOADED; + this._libraryName = id; + this._revision = revision; + this._downloadUrl = assetUrl; + this._assets = assets; + this._animation = null; + + this._downloadUrl = this._downloadUrl.replace(/%libname%/gi, this._libraryName); + this._downloadUrl = this._downloadUrl.replace(/%revision%/gi, this._revision); + + this.checkIfAssetLoaded(); + } + + private checkIfAssetLoaded(): boolean + { + if(this._state === EffectAssetDownloadLibrary.LOADED) return true; + + const asset = this._assets.getCollection(this._libraryName); + + if(asset) + { + this._state = EffectAssetDownloadLibrary.LOADED; + + return true; + } + + return false; + } + + public async downloadAsset(): Promise + { + if(!this._assets || (this._state === EffectAssetDownloadLibrary.LOADING)) return; + + if(this.checkIfAssetLoaded()) return; + + this._state = EffectAssetDownloadLibrary.LOADING; + + await this._assets.downloadAsset(this._downloadUrl); + + const collection = this._assets.getCollection(this._libraryName); + + if(collection) this._animation = collection.data.animations; + + this._state = EffectAssetDownloadLibrary.LOADED; + } + + public get libraryName(): string + { + return this._libraryName; + } + + public get animation(): { [index: string]: IAssetAnimation } + { + return this._animation; + } + + public get isLoaded(): boolean + { + return (this._state === EffectAssetDownloadLibrary.LOADED); + } +} diff --git a/src/app/avatar/EffectAssetDownloadManager.ts b/src/app/avatar/EffectAssetDownloadManager.ts new file mode 100644 index 0000000..5360ac4 --- /dev/null +++ b/src/app/avatar/EffectAssetDownloadManager.ts @@ -0,0 +1,123 @@ +import fetch from 'node-fetch'; +import { AdvancedMap, IAssetManager } from '../../core'; +import { Application } from '../Application'; +import { AvatarStructure } from './AvatarStructure'; +import { EffectAssetDownloadLibrary } from './EffectAssetDownloadLibrary'; + +export class EffectAssetDownloadManager +{ + private _assets: IAssetManager; + private _structure: AvatarStructure; + + private _missingMandatoryLibs: string[]; + private _effectMap: AdvancedMap; + private _libraryNames: string[]; + + constructor(assets: IAssetManager, structure: AvatarStructure) + { + this._assets = assets; + this._structure = structure; + + this._missingMandatoryLibs = Application.instance.getConfiguration('avatar.mandatory.effect.libraries'); + this._effectMap = new AdvancedMap(); + this._libraryNames = []; + } + + public async loadEffectMap(): Promise + { + const url = Application.instance.getConfiguration('avatar.effectmap.url'); + + const data = await fetch(url); + const json = await data.json(); + + this.processEffectMap(json.effects); + + await this.processMissingLibraries(); + } + + private processEffectMap(data: any): void + { + if(!data) return; + + const avatarEffectAssetUrl = Application.instance.getConfiguration('avatar.asset.effect.url'); + + for(const effect of data) + { + if(!effect) continue; + + const id = (effect.id as string); + const lib = (effect.lib as string); + const revision = (effect.revision || ''); + + if(this._libraryNames.indexOf(lib) >= 0) continue; + + this._libraryNames.push(lib); + + const downloadLibrary = new EffectAssetDownloadLibrary(lib, revision, this._assets, avatarEffectAssetUrl); + + let existing = this._effectMap.getValue(id); + + if(!existing) existing = []; + + existing.push(downloadLibrary); + + this._effectMap.add(id, existing); + } + } + + public async downloadAvatarEffect(id: number): Promise + { + const pendingLibraries = this.getAvatarEffectPendingLibraries(id); + + for(const library of pendingLibraries) (library && await this.downloadLibrary(library)); + } + + public async processMissingLibraries(): Promise + { + const missingLibraries = this._missingMandatoryLibs.slice(); + + for(const library of missingLibraries) + { + if(!library) continue; + + const libraries = this._effectMap.getValue(library); + + if(libraries) for(const library of libraries) (library && await this.downloadLibrary(library)); + } + } + + public isAvatarEffectReady(effect: number): boolean + { + const pendingLibraries = this.getAvatarEffectPendingLibraries(effect); + + return !pendingLibraries.length; + } + + private getAvatarEffectPendingLibraries(id: number): EffectAssetDownloadLibrary[] + { + const pendingLibraries: EffectAssetDownloadLibrary[] = []; + + if(!this._structure) return pendingLibraries; + + const libraries = this._effectMap.getValue(id.toString()); + + if(libraries) + { + for(const library of libraries) + { + if(!library || library.isLoaded) continue; + + if(pendingLibraries.indexOf(library) === -1) pendingLibraries.push(library); + } + } + + return pendingLibraries; + } + + private async downloadLibrary(library: EffectAssetDownloadLibrary): Promise + { + if(!library || library.isLoaded) return; + + await library.downloadAsset(); + } +} diff --git a/src/app/avatar/FigureDataContainer.ts b/src/app/avatar/FigureDataContainer.ts new file mode 100644 index 0000000..387fefd --- /dev/null +++ b/src/app/avatar/FigureDataContainer.ts @@ -0,0 +1,244 @@ +import { AdvancedMap } from '../../core'; + +export class FigureDataContainer +{ + private static MALE: string = 'M'; + private static FEMALE: string = 'F'; + private static UNISEX: string = 'U'; + private static SCALE: string = 'h'; + private static STD: string = 'std'; + private static DEFAULT_FRAME: string = '0'; + private static HD: string = 'hd'; + private static HAIR: string = 'hr'; + private static HAT: string = 'ha'; + private static HEAD_ACCESSORIES: string = 'he'; + private static EYE_ACCESSORIES: string = 'ea'; + private static FACE_ACCESSORIES: string = 'fa'; + private static JACKET: string = 'cc'; + private static SHIRT: string = 'ch'; + private static CHEST_ACCESSORIES: string = 'ca'; + private static CHEST_PRINTS: string = 'cp'; + private static TROUSERS: string = 'lg'; + private static SHOES: string = 'sh'; + private static TROUSER_ACCESSORIES: string = 'wa'; + private static BLOCKED_FX_TYPES: number[] = [28, 29, 30, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 68]; + + private _data: AdvancedMap; + private _colors: AdvancedMap; + private _gender: string = 'M'; + private _isDisposed: boolean; + private _avatarEffectType: number = -1; + + public loadAvatarData(k: string, _arg_2: string): void + { + this._data = new AdvancedMap(); + this._colors = new AdvancedMap(); + this._gender = _arg_2; + + this.parseFigureString(k); + } + + public dispose(): void + { + this._data = null; + this._colors = null; + this._isDisposed = true; + } + + public get disposed(): boolean + { + return this._isDisposed; + } + + private parseFigureString(k: string): void + { + if(!k) return; + + for(const set of k.split('.')) + { + const _local_3 = set.split('-'); + + if(_local_3.length > 0) + { + const part = _local_3[0]; + const setId = parseInt(_local_3[1]); + const colors: number[] = []; + + let i = 2; + + while(i < _local_3.length) + { + colors.push(parseInt(_local_3[i])); + + i++; + } + + if(!colors.length) colors.push(0); + + this.savePartSetId(part, setId, false); + this.savePartSetColourId(part, colors, false); + } + } + } + + public hasSetType(k: string): boolean + { + return !!this._data.getValue(k); + } + + public getPartSetId(k: string): number + { + if(this.hasSetType(k)) return this._data.getValue(k); + + return -1; + } + + public getColourIds(k: string): number[] + { + if(this._colors.getValue(k)) return this._colors.getValue(k); + + return []; + } + + public getFigureString(): string + { + let figure = ''; + + const sets: string[] = []; + + for(const key of this._data.getKeys()) + { + const value = this._data.getValue(key); + let set = ((key + '-') + value); + + const colors = this._colors.getValue(key); + + if(colors) for(const color of colors) set = (set + ('-' + color)); + + sets.push(set); + } + + let i = 0; + + while(i < sets.length) + { + figure = (figure + sets[i]); + + if(i < (sets.length - 1)) figure = (figure + '.'); + + i++; + } + + return figure; + } + + public savePartData(k: string, _arg_2: number, _arg_3: number[], _arg_4: boolean = false): void + { + this.savePartSetId(k, _arg_2, _arg_4); + this.savePartSetColourId(k, _arg_3, _arg_4); + } + + private savePartSetId(k: string, _arg_2: number, _arg_3: boolean = true): void + { + switch(k) + { + case FigureDataContainer.HD: + case FigureDataContainer.HAIR: + case FigureDataContainer.HAT: + case FigureDataContainer.HEAD_ACCESSORIES: + case FigureDataContainer.EYE_ACCESSORIES: + case FigureDataContainer.FACE_ACCESSORIES: + case FigureDataContainer.SHIRT: + case FigureDataContainer.JACKET: + case FigureDataContainer.CHEST_ACCESSORIES: + case FigureDataContainer.CHEST_PRINTS: + case FigureDataContainer.TROUSERS: + case FigureDataContainer.SHOES: + case FigureDataContainer.TROUSER_ACCESSORIES: + if(_arg_2 >= 0) + { + this._data.add(k, _arg_2); + } + else + { + this._data.remove(k); + } + } + } + + public savePartSetColourId(k: string, _arg_2: number[], _arg_3: boolean = true): void + { + switch(k) + { + case FigureDataContainer.HD: + case FigureDataContainer.HAIR: + case FigureDataContainer.HAT: + case FigureDataContainer.HEAD_ACCESSORIES: + case FigureDataContainer.EYE_ACCESSORIES: + case FigureDataContainer.FACE_ACCESSORIES: + case FigureDataContainer.SHIRT: + case FigureDataContainer.JACKET: + case FigureDataContainer.CHEST_ACCESSORIES: + case FigureDataContainer.CHEST_PRINTS: + case FigureDataContainer.TROUSERS: + case FigureDataContainer.SHOES: + case FigureDataContainer.TROUSER_ACCESSORIES: + this._colors.add(k, _arg_2); + return; + } + } + + public getFigureStringWithFace(k: number): string + { + const partSets: string[] = [ FigureDataContainer.HD ]; + + let figure = ''; + const sets: string[] = []; + + for(const part of partSets) + { + const colors = this._colors.getValue(part); + + if(colors) + { + let setId = this._data.getValue(part); + + if(part === FigureDataContainer.HD) setId = k; + + let set = ((part + '-') + setId); + + if(setId >= 0) + { + let i = 0; + + while(i < colors.length) + { + set = (set + ('-' + colors[i])); + + i++; + } + } + + sets.push(set); + } + } + + let i = 0; + + while(i < sets.length) + { + figure = (figure + sets[i]); + + if(i < (sets.length - 1)) figure = (figure + '.'); + + i++; + } + + return figure; + } + + public get gender(): string + { + return this._gender; + } +} diff --git a/src/app/avatar/IAvatarFigureContainer.ts b/src/app/avatar/IAvatarFigureContainer.ts new file mode 100644 index 0000000..2703e78 --- /dev/null +++ b/src/app/avatar/IAvatarFigureContainer.ts @@ -0,0 +1,10 @@ +export interface IAvatarFigureContainer +{ + getPartTypeIds(): string[]; + hasPartType(_arg_1: string): boolean; + getPartSetId(_arg_1: string): number; + getPartColorIds(_arg_1: string): number[]; + updatePart(_arg_1: string, _arg_2: number, _arg_3: number[]): void; + removePart(_arg_1: string): void; + getFigureString(): string; +} diff --git a/src/app/avatar/IAvatarImage.ts b/src/app/avatar/IAvatarImage.ts new file mode 100644 index 0000000..4bf5cce --- /dev/null +++ b/src/app/avatar/IAvatarImage.ts @@ -0,0 +1,31 @@ +import { Canvas } from 'canvas'; +import { IDisposable, IGraphicAsset } from '../../core'; +import { IAnimationLayerData, IAvatarDataContainer, ISpriteDataContainer } from './animation'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; +import { IPartColor } from './structure'; + +export interface IAvatarImage extends IDisposable +{ + setDirection(_arg_1: string, _arg_2: number): void; + setDirectionAngle(_arg_1: string, _arg_2: number): void; + updateAnimationByFrames(_arg_1?: number): void; + getScale(): string; + getSprites(): ISpriteDataContainer[]; + getLayerData(_arg_1: ISpriteDataContainer): IAnimationLayerData; + getImage(setType: string, hightlight: boolean, scale?: number, cache?: boolean): Promise; + getAsset(_arg_1: string): IGraphicAsset; + getDirection(): number; + getFigure(): IAvatarFigureContainer; + getPartColor(_arg_1: string): IPartColor; + isAnimating(): boolean; + getCanvasOffsets(): number[]; + initActionAppends(): void; + endActionAppends(): void; + appendAction(_arg_1: string, ..._args: any[]): boolean; + avatarSpriteData: IAvatarDataContainer; + isPlaceholder(): boolean; + forceActionUpdate(): void; + animationHasResetOnToggle: boolean; + resetAnimationFrameCounter(): void; + mainAction: string; +} diff --git a/src/app/avatar/IAvatarRenderManager.ts b/src/app/avatar/IAvatarRenderManager.ts new file mode 100644 index 0000000..bf630cd --- /dev/null +++ b/src/app/avatar/IAvatarRenderManager.ts @@ -0,0 +1,23 @@ +import { IAssetManager, IGraphicAsset, INitroManager } from '../../core'; +import { AvatarAssetDownloadManager } from './AvatarAssetDownloadManager'; +import { AvatarStructure } from './AvatarStructure'; +import { IAvatarFigureContainer } from './IAvatarFigureContainer'; +import { IAvatarImage } from './IAvatarImage'; +import { IStructureData } from './structure/IStructureData'; + +export interface IAvatarRenderManager extends INitroManager +{ + createFigureContainer(figure: string): IAvatarFigureContainer; + isFigureContainerReady(container: IAvatarFigureContainer): boolean; + createAvatarImage(figure: string, size: string, gender: string): Promise; + downloadAvatarFigure(container: IAvatarFigureContainer): void; + getFigureClubLevel(container: IAvatarFigureContainer, gender: string, searchParts: string[]): number; + isValidFigureSetForGender(setId: number, gender: string): boolean; + getFigureStringWithFigureIds(k: string, _arg_2: string, _arg_3: number[]): string; + getMandatoryAvatarPartSetIds(k: string, _arg_2: number): string[]; + getAssetByName(name: string): IGraphicAsset; + assets: IAssetManager; + structure: AvatarStructure; + structureData: IStructureData; + downloadManager: AvatarAssetDownloadManager; +} diff --git a/src/app/avatar/PlaceHolderAvatarImage.ts b/src/app/avatar/PlaceHolderAvatarImage.ts new file mode 100644 index 0000000..d9d5144 --- /dev/null +++ b/src/app/avatar/PlaceHolderAvatarImage.ts @@ -0,0 +1,18 @@ +import { AssetAliasCollection } from './alias'; +import { AvatarFigureContainer } from './AvatarFigureContainer'; +import { AvatarImage } from './AvatarImage'; +import { AvatarStructure } from './AvatarStructure'; +import { EffectAssetDownloadManager } from './EffectAssetDownloadManager'; + +export class PlaceHolderAvatarImage extends AvatarImage +{ + constructor(k: AvatarStructure, _arg_2: AssetAliasCollection, _arg_3: AvatarFigureContainer, _arg_4: string, _arg_5: EffectAssetDownloadManager) + { + super(k, _arg_2, _arg_3, _arg_4, _arg_5); + } + + public isPlaceholder(): boolean + { + return true; + } +} diff --git a/src/app/avatar/actions/ActionDefinition.ts b/src/app/avatar/actions/ActionDefinition.ts new file mode 100644 index 0000000..1fc5748 --- /dev/null +++ b/src/app/avatar/actions/ActionDefinition.ts @@ -0,0 +1,225 @@ +import { AdvancedMap } from '../../../core'; +import { ActionType } from './ActionType'; +import { IActionDefinition } from './IActionDefinition'; + +export class ActionDefinition implements IActionDefinition +{ + private _id: string; + private _state: string; + private _precedence: number; + private _activePartSet: string; + private _assetPartDefinition: string; + private _lay: string; + private _geometryType: string; + private _isMain: boolean; + private _isDefault: boolean; + private _isAnimation: boolean; + private _startFromFrameZero: boolean; + private _prevents: string[]; + private _preventHeadTurn: boolean; + private _types: AdvancedMap; + private _params: AdvancedMap; + private _defaultParameterValue: string; + private _canvasOffsets: AdvancedMap>; + + constructor(data: any) + { + this._id = data.id; + this._state = data.state; + this._precedence = data.precedence; + this._activePartSet = data.activePartSet; + this._assetPartDefinition = data.assetPartDefinition; + this._lay = data.lay; + this._geometryType = data.geometryType; + this._isMain = data.main || false; + this._isDefault = data.isDefault || false; + this._isAnimation = data.animation || false; + this._startFromFrameZero = data.startFromFrameZero || false; + this._prevents = data.prevents || []; + this._preventHeadTurn = data.preventHeadTurn || false; + this._types = new AdvancedMap(); + this._params = new AdvancedMap(); + this._defaultParameterValue = ''; + this._canvasOffsets = null; + + if(data.params && (data.params.length > 0)) + { + for(const param of data.params) + { + if(!param) continue; + + if(param.id === 'default') this._defaultParameterValue = param.value; + else this._params.add(param.id, param.value); + } + } + + if(data.types && (data.types.length > 0)) + { + for(const type of data.types) + { + if(!type) continue; + + const action = new ActionType(type); + + this._types.add(action.id, action); + } + } + } + + public setOffsets(k: string, _arg_2: number, _arg_3: number[]): void + { + if(!this._canvasOffsets) this._canvasOffsets = new AdvancedMap(); + + let existing = this._canvasOffsets.getValue(k); + + if(!existing) + { + existing = new AdvancedMap(); + + this._canvasOffsets.add(k, existing); + } + + existing.add(_arg_2, _arg_3); + } + + public getOffsets(k: string, _arg_2: number): number[] + { + if(!this._canvasOffsets) return null; + + const existing = this._canvasOffsets.getValue(k); + + if(!existing) return null; + + return existing.getValue(_arg_2); + } + + public getType(id: string): ActionType + { + if(!id) return null; + + const existing = this._types.getValue(parseInt(id)); + + if(!existing) return null; + + return existing; + } + + public getParameterValue(id: string): string + { + if(!id) return ''; + + const existing = this._params.getValue(id); + + if(!existing) return this._defaultParameterValue; + + return existing; + } + + public getPrevents(type: string): string[] + { + return this._prevents.concat(this.getTypePrevents(type)); + } + + private getTypePrevents(type: string): string[] + { + if(!type) return []; + + const existing = this._types.getValue(parseInt(type)); + + if(!existing) return []; + + return existing.prevents; + } + + public getPreventHeadTurn(k: string): boolean + { + if(!k) return this._preventHeadTurn; + + const type = this.getType(k); + + if(!type) return this._preventHeadTurn; + + return type.preventHeadTurn; + } + + public isAnimated(k: string): boolean + { + if(!k) return true; + + const type = this.getType(k); + + if(!type) return true; + + return type.isAnimated; + } + + public get id(): string + { + return this._id; + } + + public get state(): string + { + return this._state; + } + + public get precedence(): number + { + return this._precedence; + } + + public get activePartSet(): string + { + return this._activePartSet; + } + + public get assetPartDefinition(): string + { + return this._assetPartDefinition; + } + + public get lay(): string + { + return this._lay; + } + + public get geometryType(): string + { + return this._geometryType; + } + + public get isMain(): boolean + { + return this._isMain; + } + + public get isDefault(): boolean + { + return this._isDefault; + } + + public get isAnimation(): boolean + { + return this._isAnimation; + } + + public get startFromFrameZero(): boolean + { + return this._startFromFrameZero; + } + + public get prevents(): string[] + { + return this._prevents; + } + + public get preventHeadTurn(): boolean + { + return this._preventHeadTurn; + } + + public get params(): AdvancedMap + { + return this._params; + } +} diff --git a/src/app/avatar/actions/ActionType.ts b/src/app/avatar/actions/ActionType.ts new file mode 100644 index 0000000..e90ec68 --- /dev/null +++ b/src/app/avatar/actions/ActionType.ts @@ -0,0 +1,44 @@ +export class ActionType +{ + private _id: number; + private _value: number; + private _prevents: string[]; + private _preventHeadTurn: boolean; + private _isAnimated: boolean; + + constructor(data: any) + { + this._id = parseInt(data.id); + this._value = parseInt(data.id); + this._prevents = data.prevents || []; + this._preventHeadTurn = data.preventHeadTurn || false; + this._isAnimated = true; + + if((data.animated !== undefined) && (data.animated === false)) this._isAnimated = false; + } + + public get id(): number + { + return this._id; + } + + public get value(): number + { + return this._value; + } + + public get prevents(): string[] + { + return this._prevents; + } + + public get preventHeadTurn(): boolean + { + return this._preventHeadTurn; + } + + public get isAnimated(): boolean + { + return this._isAnimated; + } +} diff --git a/src/app/avatar/actions/ActiveActionData.ts b/src/app/avatar/actions/ActiveActionData.ts new file mode 100644 index 0000000..8e25916 --- /dev/null +++ b/src/app/avatar/actions/ActiveActionData.ts @@ -0,0 +1,74 @@ +import { IActionDefinition } from './IActionDefinition'; +import { IActiveActionData } from './IActiveActionData'; + +export class ActiveActionData implements IActiveActionData +{ + private _actionType: string; + private _actionParameter: string; + private _definition: IActionDefinition; + private _startFrame: number; + private _overridingAction: string; + + constructor(action: string, parameter: string = '', startFrame: number = 0) + { + this._actionType = action || ''; + this._actionParameter = parameter || ''; + this._definition = null; + this._startFrame = startFrame || 0; + this._overridingAction = null; + } + + public dispose(): void + { + this._actionType = null; + this._actionParameter = null; + this._definition = null; + } + + public get id(): string + { + if(!this._definition) return ''; + + return this._definition.id + '_' + this._actionParameter; + } + + public get actionType(): string + { + return this._actionType; + } + + public get actionParameter(): string + { + return this._actionParameter; + } + + public set actionParameter(parameter: string) + { + this._actionParameter = parameter; + } + + public get definition(): IActionDefinition + { + return this._definition; + } + + public set definition(definition: IActionDefinition) + { + this._definition = definition; + } + + public get startFrame(): number + { + return this._startFrame; + } + + public get overridingAction(): string + { + return this._overridingAction; + } + + public set overridingAction(action: string) + { + this._overridingAction = action; + } +} diff --git a/src/app/avatar/actions/AvatarActionManager.ts b/src/app/avatar/actions/AvatarActionManager.ts new file mode 100644 index 0000000..6d48a03 --- /dev/null +++ b/src/app/avatar/actions/AvatarActionManager.ts @@ -0,0 +1,185 @@ +import { AdvancedMap } from '../../../core'; +import { ActionDefinition } from './ActionDefinition'; +import { IActiveActionData } from './IActiveActionData'; + +export class AvatarActionManager +{ + private _actions: AdvancedMap; + private _defaultAction: ActionDefinition; + + constructor(data: any) + { + this._actions = new AdvancedMap(); + this._defaultAction = null; + + this.updateActions(data); + } + + public updateActions(data: any): void + { + if(!data) return; + + for(const action of data.actions) + { + if(!action || !action.state) continue; + + const definition = new ActionDefinition(action); + + this._actions.add(definition.state, definition); + } + + if(data.actionOffsets) this.parseActionOffsets(data.actionOffsets); + } + + private parseActionOffsets(offsets: any): void + { + if(!offsets || !offsets.length) return; + + for(const offset of offsets) + { + const action = this._actions.getValue(offset.action); + + if(!action) continue; + + for(const canvasOffset of offset.offsets) + { + const size = (canvasOffset.size || ''); + const direction = canvasOffset.direction; + + if((size === '') || (direction === undefined)) continue; + + const x = (canvasOffset.x || 0); + const y = (canvasOffset.y || 0); + const z = (canvasOffset.z || 0); + + action.setOffsets(size, direction, [ x, y, z ]); + } + } + } + + public getActionDefinition(id: string): ActionDefinition + { + if(!id) return null; + + for(const action of this._actions.getValues()) + { + if(!action || (action.id !== id)) continue; + + return action; + } + + return null; + } + + public getActionDefinitionWithState(state: string): ActionDefinition + { + const existing = this._actions.getValue(state); + + if(!existing) return null; + + return existing; + } + + public getDefaultAction(): ActionDefinition + { + if(this._defaultAction) return this._defaultAction; + + for(const action of this._actions.getValues()) + { + if(!action || !action.isDefault) continue; + + this._defaultAction = action; + + return action; + } + + return null; + } + + public getCanvasOffsets(k: IActiveActionData[], _arg_2: string, _arg_3: number): number[] + { + let canvasOffsets: number[] = []; + + for(const activeAction of k) + { + if(!activeAction) continue; + + const action = this._actions.getValue(activeAction.actionType); + const offsets = action && action.getOffsets(_arg_2, _arg_3); + + if(offsets) canvasOffsets = offsets; + } + + return canvasOffsets; + } + + public sortActions(actions: IActiveActionData[]): IActiveActionData[] + { + if(!actions) return null; + + actions = this.filterActions(actions); + + const validatedActions: IActiveActionData[] = []; + + for(const action of actions) + { + if(!action) continue; + + const definition = this._actions.getValue(action.actionType); + + if(!definition) continue; + + action.definition = definition; + + validatedActions.push(action); + } + + validatedActions.sort(this.sortByPrecedence); + + return validatedActions; + } + + private filterActions(actions: IActiveActionData[]): IActiveActionData[] + { + let preventions: string[] = []; + const activeActions: IActiveActionData[] = []; + + for(const action of actions) + { + if(!action) continue; + + const localAction = this._actions.getValue(action.actionType); + + if(localAction) preventions = preventions.concat(localAction.getPrevents(action.actionParameter)); + } + + for(const action of actions) + { + if(!action) continue; + + let actionType = action.actionType; + + if(action.actionType === 'fx') actionType = (actionType + ('.' + action.actionParameter)); + + if(preventions.indexOf(actionType) >= 0) continue; + + activeActions.push(action); + } + + return activeActions; + } + + private sortByPrecedence(actionOne: IActiveActionData, actionTwo: IActiveActionData): number + { + if(!actionOne || !actionTwo) return 0; + + const precedenceOne = actionOne.definition.precedence; + const precedenceTwo = actionTwo.definition.precedence; + + if(precedenceOne < precedenceTwo) return 1; + + if(precedenceOne > precedenceTwo) return -1; + + return 0; + } +} diff --git a/src/app/avatar/actions/IActionDefinition.ts b/src/app/avatar/actions/IActionDefinition.ts new file mode 100644 index 0000000..9c0e5f1 --- /dev/null +++ b/src/app/avatar/actions/IActionDefinition.ts @@ -0,0 +1,19 @@ +export interface IActionDefinition +{ + id: string; + state: string; + precedence: number; + activePartSet: string; + isMain: boolean; + isDefault: boolean; + assetPartDefinition: string; + lay: string; + geometryType: string; + isAnimation: boolean; + startFromFrameZero: boolean; + isAnimated(_arg_1: string): boolean; + getPrevents(_arg_1: string): string[]; + getPreventHeadTurn(_arg_1: string): boolean; + setOffsets(_arg_1: string, _arg_2: number, _arg_3: []): void; + getOffsets(_arg_1: string, _arg_2: number): number[]; +} diff --git a/src/app/avatar/actions/IActiveActionData.ts b/src/app/avatar/actions/IActiveActionData.ts new file mode 100644 index 0000000..214c64f --- /dev/null +++ b/src/app/avatar/actions/IActiveActionData.ts @@ -0,0 +1,11 @@ +import { IActionDefinition } from './IActionDefinition'; + +export interface IActiveActionData +{ + id: string; + actionType: string; + actionParameter: string; + startFrame: number; + definition: IActionDefinition; + overridingAction: string; +} diff --git a/src/app/avatar/actions/index.ts b/src/app/avatar/actions/index.ts new file mode 100644 index 0000000..342a3f8 --- /dev/null +++ b/src/app/avatar/actions/index.ts @@ -0,0 +1,6 @@ +export * from './ActionDefinition'; +export * from './ActionType'; +export * from './ActiveActionData'; +export * from './AvatarActionManager'; +export * from './IActionDefinition'; +export * from './IActiveActionData'; diff --git a/src/app/avatar/alias/AssetAlias.ts b/src/app/avatar/alias/AssetAlias.ts new file mode 100644 index 0000000..e6564f7 --- /dev/null +++ b/src/app/avatar/alias/AssetAlias.ts @@ -0,0 +1,37 @@ +import { IAssetAlias } from '../../../core'; + +export class AssetAlias +{ + private _name: string; + private _link: string; + private _flipH: boolean; + private _flipV: boolean; + + constructor(name: string, alias: IAssetAlias) + { + this._name = name; + this._link = alias.link; + this._flipH = alias.flipH; + this._flipV = alias.flipV; + } + + public get name(): string + { + return this._name; + } + + public get link(): string + { + return this._link; + } + + public get flipH(): boolean + { + return this._flipH; + } + + public get flipV(): boolean + { + return this._flipV; + } +} diff --git a/src/app/avatar/alias/AssetAliasCollection.ts b/src/app/avatar/alias/AssetAliasCollection.ts new file mode 100644 index 0000000..f21feec --- /dev/null +++ b/src/app/avatar/alias/AssetAliasCollection.ts @@ -0,0 +1,89 @@ +import { AdvancedMap, IAssetManager, IGraphicAsset } from '../../../core'; +import { AvatarRenderManager } from '../AvatarRenderManager'; +import { AssetAlias } from './AssetAlias'; + +export class AssetAliasCollection +{ + private _assets: IAssetManager; + private _aliases: AdvancedMap; + private _avatarRenderManager: AvatarRenderManager; + private _missingAssetNames: string[]; + + constructor(renderManager: AvatarRenderManager, assetManager: IAssetManager) + { + this._avatarRenderManager = renderManager; + this._aliases = new AdvancedMap(); + this._assets = assetManager; + this._missingAssetNames = []; + } + + public dispose(): void + { + this._assets = null; + this._aliases = null; + } + + public reset(): void + { + this.init(); + } + + public init(): void + { + for(const collection of this._assets.collections.getValues()) + { + if(!collection) continue; + + const aliases = collection.data && collection.data.aliases; + + if(!aliases) continue; + + for(const name in aliases) + { + const alias = aliases[name]; + + if(!alias) continue; + + this._aliases.add(name, new AssetAlias(name, alias)); + } + } + } + + public hasAlias(name: string): boolean + { + const alias = this._aliases.getValue(name); + + if(alias) return true; + + return false; + } + + public getAssetName(k: string): string + { + let linkName = k; + let tries = 5; + + while(this.hasAlias(linkName) && (tries >= 0)) + { + const alias = this._aliases.getValue(linkName); + + linkName = alias.link; + tries--; + } + + return linkName; + } + + public getAsset(name: string): IGraphicAsset + { + if(!this._assets) return null; + + name = this.getAssetName(name); + + const asset = this._assets.getAsset(name); + + if(!asset) return null; + + return asset; + } +} diff --git a/src/app/avatar/alias/index.ts b/src/app/avatar/alias/index.ts new file mode 100644 index 0000000..7d9524c --- /dev/null +++ b/src/app/avatar/alias/index.ts @@ -0,0 +1,2 @@ +export * from './AssetAlias'; +export * from './AssetAliasCollection'; diff --git a/src/app/avatar/animation/AddDataContainer.ts b/src/app/avatar/animation/AddDataContainer.ts new file mode 100644 index 0000000..7dddd61 --- /dev/null +++ b/src/app/avatar/animation/AddDataContainer.ts @@ -0,0 +1,58 @@ +import { IAssetAnimationAdd } from '../../../core'; + +export class AddDataContainer +{ + private _id: string; + private _align: string; + private _base: string; + private _ink: number; + private _blend: number; + + constructor(animation: IAssetAnimationAdd) + { + this._id = (animation.id || ''); + this._align = (animation.align || ''); + this._base = (animation.base || ''); + this._ink = (animation.ink || 0); + this._blend = 0; + + const blend = animation.blend; + + if(blend && (blend.length > 0)) + { + this._blend = parseInt(blend); + + if(this._blend > 1) this._blend = (this._blend / 100); + } + } + + public get id(): string + { + return this._id; + } + + public get align(): string + { + return this._align; + } + + public get base(): string + { + return this._base; + } + + public get ink(): number + { + return this._ink; + } + + public get blend(): number + { + return this._blend; + } + + public get isBlended(): boolean + { + return (this._blend !== 1); + } +} diff --git a/src/app/avatar/animation/Animation.ts b/src/app/avatar/animation/Animation.ts new file mode 100644 index 0000000..8480e46 --- /dev/null +++ b/src/app/avatar/animation/Animation.ts @@ -0,0 +1,312 @@ +import { AdvancedMap, IAssetAnimation, IAssetAnimationFrame } from '../../../core'; +import { AvatarStructure } from '../AvatarStructure'; +import { AddDataContainer } from './AddDataContainer'; +import { AvatarAnimationLayerData } from './AvatarAnimationLayerData'; +import { AvatarDataContainer } from './AvatarDataContainer'; +import { DirectionDataContainer } from './DirectionDataContainer'; +import { IAnimation } from './IAnimation'; +import { SpriteDataContainer } from './SpriteDataContainer'; + +export class Animation implements IAnimation +{ + private static EMPTY_ARRAY: any[] = []; + + private _id: string; + private _description: string; + private _frames: AvatarAnimationLayerData[][]; + private _spriteData: SpriteDataContainer[]; + private _avatarData: AvatarDataContainer; + private _directionData: DirectionDataContainer; + private _removeData: string[]; + private _addData: AddDataContainer[]; + private _overriddenActions: AdvancedMap; + private _overrideFrames: AdvancedMap; + private _resetOnToggle: boolean; + + constructor(structure: AvatarStructure, animation: IAssetAnimation) + { + this._id = animation.name; + this._description = this._id; + this._frames = []; + this._spriteData = null; + this._avatarData = null; + this._directionData = null; + this._removeData = null; + this._addData = null; + this._overriddenActions = null; + this._overrideFrames = null; + this._resetOnToggle = (animation.resetOnToggle || false); + + if(animation.sprites && animation.sprites.length) + { + this._spriteData = []; + + for(const sprite of animation.sprites) this._spriteData.push(new SpriteDataContainer(this, sprite)); + } + + if(animation.avatars && animation.avatars.length) this._avatarData = new AvatarDataContainer(animation.avatars[0]); + + if(animation.directions && animation.directions.length) this._directionData = new DirectionDataContainer(animation.directions[0]); + + if(animation.removes && animation.removes.length) + { + this._removeData = []; + + for(const remove of animation.removes) this._removeData.push(remove.id); + } + + if(animation.adds && animation.adds.length) + { + this._addData = []; + + for(const add of animation.adds) this._addData.push(new AddDataContainer(add)); + } + + if(animation.overrides && animation.overrides.length) + { + this._overrideFrames = new AdvancedMap(); + this._overriddenActions = new AdvancedMap(); + + for(const override of animation.overrides) + { + const name = override.name; + const value = override.override; + + this._overriddenActions.add(value, name); + + const frames: AvatarAnimationLayerData[][] = []; + + this.parseFrames(frames, override.frames, structure); + + this._overrideFrames.add(name, frames); + } + } + + this.parseFrames(this._frames, animation.frames, structure); + } + + private parseFrames(frames: AvatarAnimationLayerData[][], animationFrame: IAssetAnimationFrame[], structure: AvatarStructure): void + { + if(!animationFrame || !animationFrame.length) return; + + for(const frame of animationFrame) + { + let repeats = 1; + + if(frame.repeats && (frame.repeats > 1)) repeats = frame.repeats; + + let index = 0; + + while(index < repeats) + { + const layers: AvatarAnimationLayerData[] = []; + + if(frame.bodyparts && frame.bodyparts.length) + { + for(const bodyPart of frame.bodyparts) + { + const definition = structure.getActionDefinition(bodyPart.action); + const layer = new AvatarAnimationLayerData(bodyPart, AvatarAnimationLayerData.BODYPART, definition); + + layers.push(layer); + } + } + + if(frame.fxs && frame.fxs.length) + { + for(const fx of frame.fxs) + { + const definition = structure.getActionDefinition(fx.action); + const layer = new AvatarAnimationLayerData(fx, AvatarAnimationLayerData.FX, definition); + + layers.push(layer); + } + } + + frames.push(layers); + + index++; + } + } + } + + public frameCount(frame: string = null): number + { + if(!frame) return this._frames.length; + + if(this._overrideFrames) + { + const layerData = this._overrideFrames.getValue(frame); + + if(layerData) return layerData.length; + } + + return 0; + } + + public hasOverriddenActions(): boolean + { + if(!this._overriddenActions) return false; + + return (this._overriddenActions.length > 0); + } + + public overriddenActionNames(): string[] + { + if(!this._overriddenActions) return null; + + const keys: string[] = []; + + for(const key of this._overriddenActions.getKeys()) keys.push(key); + + return keys; + } + + public overridingAction(action: string): string + { + if(!this._overriddenActions) return null; + + return this._overriddenActions.getValue(action); + } + + private getFrame(frameCount: number, frame: string = null): AvatarAnimationLayerData[] + { + if(frameCount < 0) frameCount = 0; + + let layers: AvatarAnimationLayerData[] = []; + + if(!frame) + { + if(this._frames.length > 0) + { + layers = this._frames[(frameCount % this._frames.length)]; + } + } + else + { + const overrideLayers = this._overrideFrames.getValue(frame); + + if(overrideLayers && (overrideLayers.length > 0)) + { + layers = overrideLayers[(frameCount % overrideLayers.length)]; + } + } + + return layers; + } + + public getAnimatedBodyPartIds(frameCount: number, frame: string = null): string[] + { + const partIds: string[] = []; + + for(const layer of this.getFrame(frameCount, frame)) + { + if(layer.type === AvatarAnimationLayerData.BODYPART) + { + partIds.push(layer.id); + } + + else if(layer.type === AvatarAnimationLayerData.FX) + { + if(this._addData && this._addData.length) + { + for(const _local_5 of this._addData) + { + if(_local_5.id === layer.id) partIds.push(_local_5.align); + } + } + } + } + + return partIds; + } + + public getLayerData(frameCount: number, spriteId: string, frame: string = null): AvatarAnimationLayerData + { + for(const layer of this.getFrame(frameCount, frame)) + { + if(layer.id === spriteId) return layer; + + if(layer.type === AvatarAnimationLayerData.FX) + { + if(this._addData && this._addData.length) + { + for(const addData of this._addData) + { + if(((addData.align === spriteId) && (addData.id === layer.id))) return layer; + } + } + } + } + + return null; + } + + public hasAvatarData(): boolean + { + return (this._avatarData !== null); + } + + public hasDirectionData(): boolean + { + return (this._directionData !== null); + } + + public hasAddData(): boolean + { + return (this._addData !== null); + } + + public getAddData(id: string): AddDataContainer + { + if(this._addData) + { + for(const data of this._addData) + { + if(data.id === id) return data; + } + } + + return null; + } + + public get id(): string + { + return this._id; + } + + public get spriteData(): SpriteDataContainer[] + { + return (this._spriteData || Animation.EMPTY_ARRAY); + } + + public get avatarData(): AvatarDataContainer + { + return this._avatarData; + } + + public get directionData(): DirectionDataContainer + { + return this._directionData; + } + + public get removeData(): string[] + { + return (this._removeData || Animation.EMPTY_ARRAY); + } + + public get addData(): AddDataContainer[] + { + return (this._addData || Animation.EMPTY_ARRAY); + } + + public toString(): string + { + return this._description; + } + + public get resetOnToggle(): boolean + { + return this._resetOnToggle; + } +} diff --git a/src/app/avatar/animation/AnimationManager.ts b/src/app/avatar/animation/AnimationManager.ts new file mode 100644 index 0000000..1e543f0 --- /dev/null +++ b/src/app/avatar/animation/AnimationManager.ts @@ -0,0 +1,50 @@ +import { AdvancedMap, IAssetAnimation } from '../../../core'; +import { AvatarStructure } from '../AvatarStructure'; +import { Animation } from './Animation'; +import { IAnimation } from './IAnimation'; +import { IAnimationLayerData } from './IAnimationLayerData'; +import { IAnimationManager } from './IAnimationManager'; + +export class AnimationManager implements IAnimationManager +{ + private _animations: AdvancedMap; + + constructor() + { + this._animations = new AdvancedMap(); + } + + public registerAnimation(structure: AvatarStructure, animations: { [index: string]: IAssetAnimation }): boolean + { + const animationData = animations[Object.keys(animations)[0]]; + + const animation = new Animation(structure, animationData); + + this._animations.add(animationData.name, animation); + + return true; + } + + public getAnimation(animation: string): Animation + { + const existing = this._animations.getValue(animation); + + if(!existing) return null; + + return existing; + } + + public getLayerData(animation: string, frameCount: number, spriteId: string): IAnimationLayerData + { + const existing = this.getAnimation(animation); + + if(!existing) return null; + + return existing.getLayerData(frameCount, spriteId); + } + + public get animations(): AdvancedMap + { + return this._animations; + } +} diff --git a/src/app/avatar/animation/AvatarAnimationLayerData.ts b/src/app/avatar/animation/AvatarAnimationLayerData.ts new file mode 100644 index 0000000..3c9526f --- /dev/null +++ b/src/app/avatar/animation/AvatarAnimationLayerData.ts @@ -0,0 +1,110 @@ +import { AdvancedMap, IAssetAnimationFramePart } from '../../../core'; +import { ActiveActionData, IActionDefinition, IActiveActionData } from '../actions'; +import { IAnimationLayerData } from './IAnimationLayerData'; + +export class AvatarAnimationLayerData implements IAnimationLayerData +{ + public static BODYPART: string = 'bodypart'; + public static FX: string = 'fx'; + + private _id: string; + private _action: IActiveActionData; + private _animationFrame: number; + private _dx: number; + private _dy: number; + private _dz: number; + private _directionOffset: number; + private _type: string; + private _base: string; + private _items: AdvancedMap; + + constructor(framePart: IAssetAnimationFramePart, type: string, definition: IActionDefinition) + { + this._id = framePart.id; + this._animationFrame = (framePart.frame || 0); + this._dx = (framePart.dx || 0); + this._dy = (framePart.dy || 0); + this._dz = (framePart.dz || 0); + this._directionOffset = (framePart.dd || 0); + this._type = type; + this._base = (framePart.base || ''); + this._items = new AdvancedMap(); + + if(framePart.items) for(const partItem of framePart.items) this._items.add(partItem.id, partItem.base); + + let base = ''; + + if(this._base !== '') base = this.baseAsInt().toString(); + + if(definition) + { + this._action = new ActiveActionData(definition.state, this.base); + this._action.definition = definition; + } + } + + public get items(): AdvancedMap + { + return this._items; + } + + private baseAsInt(): number + { + let base = 0; + let index = 0; + + while(index < this._base.length) + { + base = (base + this._base.charCodeAt(index)); + + index++; + } + + return base; + } + + public get id(): string + { + return this._id; + } + + public get animationFrame(): number + { + return this._animationFrame; + } + + public get dx(): number + { + return this._dx; + } + + public get dy(): number + { + return this._dy; + } + + public get dz(): number + { + return this._dz; + } + + public get dd(): number + { + return this._directionOffset; + } + + public get type(): string + { + return this._type; + } + + public get base(): string + { + return this._base; + } + + public get action(): IActiveActionData + { + return this._action; + } +} diff --git a/src/app/avatar/animation/AvatarDataContainer.ts b/src/app/avatar/animation/AvatarDataContainer.ts new file mode 100644 index 0000000..eaa49ef --- /dev/null +++ b/src/app/avatar/animation/AvatarDataContainer.ts @@ -0,0 +1,129 @@ +import { AdvancedMap, IAssetAnimationAvatar } from '../../../core'; +import { IAvatarDataContainer } from './IAvatarDataContainer'; + +export class AvatarDataContainer implements IAvatarDataContainer +{ + private _ink: number; + private _foreGround: number; + private _backGround: number; + private _rgb: number; + private _r: number; + private _g: number; + private _b: number; + private _redMultiplier: number; + private _greenMultiplier: number; + private _blueMultiplier: number; + private _alphaMultiplier: number; + private _colorMap: AdvancedMap; + private _paletteIsGrayscale: boolean; + + constructor(animation: IAssetAnimationAvatar) + { + this._ink = animation.ink; + + let foreground = animation.foreground; + let background = animation.background; + + foreground = foreground.replace('#', ''); + background = background.replace('#', ''); + + this._foreGround = parseInt(foreground, 16); + this._backGround = parseInt(background, 16); + this._rgb = parseInt(foreground, 16); + this._r = ((this._rgb >> 16) & 0xFF); + this._g = ((this._rgb >> 8) & 0xFF); + this._b = ((this._rgb >> 0) & 0xFF); + this._redMultiplier = ((this._r / 0xFF) * 1); + this._greenMultiplier = ((this._g / 0xFF) * 1); + this._blueMultiplier = ((this._b / 0xFF) * 1); + this._alphaMultiplier = 1; + this._paletteIsGrayscale = true; + + if(this._ink === 37) + { + this._alphaMultiplier = 0.5; + this._paletteIsGrayscale = false; + } + + this._colorMap = this.generatePaletteMapForGrayscale(this._backGround, this._foreGround); + } + + public get ink(): number + { + return this._ink; + } + + public get reds(): number[] + { + return this._colorMap.getValue('reds'); + } + + public get greens(): number[] + { + return this._colorMap.getValue('greens'); + } + + public get blues(): number[] + { + return this._colorMap.getValue('blues'); + } + + public get alphas(): number[] + { + return this._colorMap.getValue('alphas'); + } + + public get paletteIsGrayscale(): boolean + { + return this._paletteIsGrayscale; + } + + private generatePaletteMapForGrayscale(k: number, _arg_2: number): AdvancedMap + { + const _local_3 = ((k >> 24) & 0xFF); + const _local_4 = ((k >> 16) & 0xFF); + const _local_5 = ((k >> 8) & 0xFF); + const _local_6 = ((k >> 0) & 0xFF); + const _local_7 = ((_arg_2 >> 24) & 0xFF); + const _local_8 = ((_arg_2 >> 16) & 0xFF); + const _local_9 = ((_arg_2 >> 8) & 0xFF); + const _local_10 = ((_arg_2 >> 0) & 0xFF); + const _local_11 = ((_local_7 - _local_3) / 0xFF); + const _local_12 = ((_local_8 - _local_4) / 0xFF); + const _local_13 = ((_local_9 - _local_5) / 0xFF); + const _local_14 = ((_local_10 - _local_6) / 0xFF); + const _local_15: AdvancedMap = new AdvancedMap(); + const reds: number[] = []; + const greens: number[] = []; + const blues: number[] = []; + const _local_19: number[] = []; + let _local_20 = _local_3; + let _local_21 = _local_4; + let _local_22 = _local_5; + let _local_23 = _local_6; + let _local_24 = 0; + while(_local_24 < 0x0100) + { + if((((_local_21 == _local_4) && (_local_22 == _local_5)) && (_local_23 == _local_6))) + { + _local_20 = 0; + } + _local_20 = (_local_20 + _local_11); + _local_21 = (_local_21 + _local_12); + _local_22 = (_local_22 + _local_13); + _local_23 = (_local_23 + _local_14); + _local_19.push((_local_20 << 24)); + reds.push(((((_local_20 << 24) | (_local_21 << 16)) | (_local_22 << 8)) | _local_23)); + greens.push(((((_local_20 << 24) | (_local_21 << 16)) | (_local_22 << 8)) | _local_23)); + blues.push(((((_local_20 << 24) | (_local_21 << 16)) | (_local_22 << 8)) | _local_23)); + _local_24++; + } + + _local_15.add('alphas', reds); + _local_15.add('reds', reds); + _local_15.add('greens', greens); + _local_15.add('blues', blues); + + return _local_15; + } +} diff --git a/src/app/avatar/animation/DirectionDataContainer.ts b/src/app/avatar/animation/DirectionDataContainer.ts new file mode 100644 index 0000000..b22fb89 --- /dev/null +++ b/src/app/avatar/animation/DirectionDataContainer.ts @@ -0,0 +1,16 @@ +import { IAssetAnimationDirection } from '../../../core'; + +export class DirectionDataContainer +{ + private _offset: number; + + constructor(direction: IAssetAnimationDirection) + { + this._offset = direction.offset; + } + + public get offset(): number + { + return this._offset; + } +} diff --git a/src/app/avatar/animation/IAnimation.ts b/src/app/avatar/animation/IAnimation.ts new file mode 100644 index 0000000..2f53b72 --- /dev/null +++ b/src/app/avatar/animation/IAnimation.ts @@ -0,0 +1,11 @@ +export interface IAnimation +{ + hasAvatarData(): boolean; + hasDirectionData(): boolean; + hasAddData(): boolean; + id: string; + spriteData: any; + removeData: any; + addData: any; + resetOnToggle: boolean; +} diff --git a/src/app/avatar/animation/IAnimationLayerData.ts b/src/app/avatar/animation/IAnimationLayerData.ts new file mode 100644 index 0000000..8bf9e86 --- /dev/null +++ b/src/app/avatar/animation/IAnimationLayerData.ts @@ -0,0 +1,12 @@ +import { IActiveActionData } from '../actions'; + +export interface IAnimationLayerData +{ + id: string; + action: IActiveActionData; + animationFrame: number; + dx: number; + dy: number; + dz: number; + dd: number; +} diff --git a/src/app/avatar/animation/IAnimationManager.ts b/src/app/avatar/animation/IAnimationManager.ts new file mode 100644 index 0000000..0a4510d --- /dev/null +++ b/src/app/avatar/animation/IAnimationManager.ts @@ -0,0 +1,10 @@ +import { AdvancedMap } from '../../../core'; +import { IAnimation } from './IAnimation'; +import { IAnimationLayerData } from './IAnimationLayerData'; + +export interface IAnimationManager +{ + animations: AdvancedMap; + getAnimation(animation: string): IAnimation; + getLayerData(animation: string, frameCount: number, spriteId: string): IAnimationLayerData; +} diff --git a/src/app/avatar/animation/IAvatarDataContainer.ts b/src/app/avatar/animation/IAvatarDataContainer.ts new file mode 100644 index 0000000..27b197f --- /dev/null +++ b/src/app/avatar/animation/IAvatarDataContainer.ts @@ -0,0 +1,9 @@ +export interface IAvatarDataContainer +{ + ink: number; + paletteIsGrayscale: boolean; + reds: number[]; + greens: number[]; + blues: number[]; + alphas: number[]; +} diff --git a/src/app/avatar/animation/ISpriteDataContainer.ts b/src/app/avatar/animation/ISpriteDataContainer.ts new file mode 100644 index 0000000..ed953f6 --- /dev/null +++ b/src/app/avatar/animation/ISpriteDataContainer.ts @@ -0,0 +1,14 @@ +import { IAnimation } from './IAnimation'; + +export interface ISpriteDataContainer +{ + animation: IAnimation; + id: string; + ink: number; + member: string; + hasDirections: boolean; + hasStaticY: boolean; + getDirectionOffsetX(direction: number): number; + getDirectionOffsetY(direction: number): number; + getDirectionOffsetZ(direction: number): number; +} diff --git a/src/app/avatar/animation/SpriteDataContainer.ts b/src/app/avatar/animation/SpriteDataContainer.ts new file mode 100644 index 0000000..1f9db3d --- /dev/null +++ b/src/app/avatar/animation/SpriteDataContainer.ts @@ -0,0 +1,96 @@ +import { IAssetAnimationSprite } from '../../../core'; +import { IAnimation } from './IAnimation'; +import { ISpriteDataContainer } from './ISpriteDataContainer'; + +export class SpriteDataContainer implements ISpriteDataContainer +{ + private _animation: IAnimation; + private _id: string; + private _ink: number; + private _member: string; + private _hasDirections: boolean; + private _hasStaticY: boolean; + private _dx: number[]; + private _dy: number[]; + private _dz: number[]; + + constructor(animation: IAnimation, sprite: IAssetAnimationSprite) + { + this._animation = animation; + this._id = sprite.id; + this._ink = sprite.ink; + this._member = sprite.member; + this._hasStaticY = sprite.staticY ? true : false; + this._hasDirections = sprite.directions ? true : false; + this._dx = []; + this._dy = []; + this._dz = []; + + const directions = sprite.directionList; + + if(directions && directions.length) + { + for(const direction of directions) + { + const id = direction.id; + + if(id === undefined) continue; + + this._dx[id] = (direction.dx || 0); + this._dy[id] = (direction.dy || 0); + this._dz[id] = (direction.dz || 0); + } + } + } + + public getDirectionOffsetX(k: number): number + { + if(k < this._dx.length) return this._dx[k]; + + return 0; + } + + public getDirectionOffsetY(k: number): number + { + if(k < this._dy.length) return this._dy[k]; + + return 0; + } + + public getDirectionOffsetZ(k: number): number + { + if(k < this._dz.length) return this._dz[k]; + + return 0; + } + + public get animation(): IAnimation + { + return this._animation; + } + + public get id(): string + { + return this._id; + } + + public get ink(): number + { + return this._ink; + } + + public get member(): string + { + return this._member; + } + + public get hasDirections(): boolean + { + return this._hasDirections; + } + + public get hasStaticY(): boolean + { + return this._hasStaticY; + } +} diff --git a/src/app/avatar/animation/index.ts b/src/app/avatar/animation/index.ts new file mode 100644 index 0000000..fbaf45c --- /dev/null +++ b/src/app/avatar/animation/index.ts @@ -0,0 +1,12 @@ +export * from './AddDataContainer'; +export * from './Animation'; +export * from './AnimationManager'; +export * from './AvatarAnimationLayerData'; +export * from './AvatarDataContainer'; +export * from './DirectionDataContainer'; +export * from './IAnimation'; +export * from './IAnimationLayerData'; +export * from './IAnimationManager'; +export * from './IAvatarDataContainer'; +export * from './ISpriteDataContainer'; +export * from './SpriteDataContainer'; diff --git a/src/app/avatar/cache/AvatarImageActionCache.ts b/src/app/avatar/cache/AvatarImageActionCache.ts new file mode 100644 index 0000000..b65161b --- /dev/null +++ b/src/app/avatar/cache/AvatarImageActionCache.ts @@ -0,0 +1,57 @@ +import { AdvancedMap } from '../../../core'; +import { AvatarImageDirectionCache } from './AvatarImageDirectionCache'; + +export class AvatarImageActionCache +{ + private _cache: AdvancedMap; + private _lastAccessTime: number; + + constructor() + { + this._cache = new AdvancedMap(); + + this.setLastAccessTime(Date.now()); + } + + public dispose(): void + { + this.debugInfo('[dispose]'); + + if(!this._cache) return; + + for(const direction of this._cache.getValues()) + { + if(direction) direction.dispose(); + } + + this._cache.reset(); + } + + public getDirectionCache(k: number): AvatarImageDirectionCache + { + const existing = this._cache.getValue(k.toString()); + + if(!existing) return null; + + return existing; + } + + public updateDirectionCache(k: number, _arg_2: AvatarImageDirectionCache): void + { + this._cache.add(k.toString(), _arg_2); + } + + public setLastAccessTime(k: number): void + { + this._lastAccessTime = k; + } + + public getLastAccessTime(): number + { + return this._lastAccessTime; + } + + private debugInfo(k: string): void + { + } +} diff --git a/src/app/avatar/cache/AvatarImageBodyPartCache.ts b/src/app/avatar/cache/AvatarImageBodyPartCache.ts new file mode 100644 index 0000000..6640b78 --- /dev/null +++ b/src/app/avatar/cache/AvatarImageBodyPartCache.ts @@ -0,0 +1,99 @@ +import { AdvancedMap } from '../../../core'; +import { IActiveActionData } from '../actions'; +import { AvatarImageActionCache } from './AvatarImageActionCache'; + +export class AvatarImageBodyPartCache +{ + private _cache: AdvancedMap; + private _currentAction: IActiveActionData; + private _currentDirection: number; + private _disposed: boolean; + + constructor() + { + this._cache = new AdvancedMap(); + } + + public setAction(k: IActiveActionData, _arg_2: number): void + { + if(!this._currentAction) this._currentAction = k; + + const _local_3 = this.getActionCache(this._currentAction); + + if(_local_3) _local_3.setLastAccessTime(_arg_2); + + this._currentAction = k; + } + + public dispose(): void + { + if(!this._disposed) + { + if(!this._cache) return; + + this.disposeActions(0, 2147483647); + + this._cache.reset(); + + this._cache = null; + this._disposed = true; + } + } + + public disposeActions(k: number, _arg_2: number): void + { + if(!this._cache || this._disposed) return; + + for(const key of this._cache.getKeys()) + { + const cache = this._cache.getValue(key); + + if(!cache) continue; + + const _local_3 = cache.getLastAccessTime(); + + if((_arg_2 - _local_3) >= k) + { + cache.dispose(); + + this._cache.remove(key); + } + } + } + + public getAction():IActiveActionData + { + return this._currentAction; + } + + public setDirection(k: number): void + { + this._currentDirection = k; + } + + public getDirection(): number + { + return this._currentDirection; + } + + public getActionCache(k: IActiveActionData=null): AvatarImageActionCache + { + if(!this._currentAction) return null; + + if(!k) k = this._currentAction; + + if(k.overridingAction) return this._cache.getValue(k.overridingAction); + + return this._cache.getValue(k.id); + } + + public updateActionCache(k: IActiveActionData, _arg_2: AvatarImageActionCache): void + { + if(k.overridingAction) this._cache.add(k.overridingAction, _arg_2); + else this._cache.add(k.id, _arg_2); + } + + private debugInfo(k: string): void + { + } +} diff --git a/src/app/avatar/cache/AvatarImageCache.ts b/src/app/avatar/cache/AvatarImageCache.ts new file mode 100644 index 0000000..f35832b --- /dev/null +++ b/src/app/avatar/cache/AvatarImageCache.ts @@ -0,0 +1,485 @@ +import { createCanvas } from 'canvas'; +import { AdvancedMap, Point, Rectangle } from '../../../core'; +import { IActiveActionData } from '../actions'; +import { AssetAliasCollection } from '../alias'; +import { AvatarAnimationLayerData } from '../animation'; +import { AvatarImageBodyPartContainer } from '../AvatarImageBodyPartContainer'; +import { AvatarImagePartContainer } from '../AvatarImagePartContainer'; +import { AvatarStructure } from '../AvatarStructure'; +import { AvatarDirectionAngle, AvatarFigurePartType, AvatarScaleType, GeometryType } from '../enum'; +import { IAvatarImage } from '../IAvatarImage'; +import { AvatarCanvas } from '../structure'; +import { AvatarImageActionCache } from './AvatarImageActionCache'; +import { AvatarImageBodyPartCache } from './AvatarImageBodyPartCache'; +import { AvatarImageDirectionCache } from './AvatarImageDirectionCache'; +import { ImageData } from './ImageData'; + +export class AvatarImageCache +{ + private static DEFAULT_MAX_CACHE_STORAGE_TIME_MS: number = 60000; + + private _structure: AvatarStructure; + private _avatar: IAvatarImage; + private _assets: AssetAliasCollection; + private _scale: string; + private _cache: AdvancedMap; + private _canvas: AvatarCanvas; + private _disposed: boolean; + private _geometryType: string; + private _unionImages: ImageData[]; + + constructor(structure: AvatarStructure, avatarImage: IAvatarImage, aliasCollection: AssetAliasCollection, scale: string) + { + this._structure = structure; + this._avatar = avatarImage; + this._assets = aliasCollection; + this._scale = scale; + this._cache = new AdvancedMap(); + this._canvas = null; + this._disposed = false; + this._unionImages = []; + } + + public dispose(): void + { + if(this._disposed) return; + + this._structure = null; + this._avatar = null; + this._assets = null; + this._canvas = null; + this._disposed = true; + + if(this._cache) + { + for(const cache of this._cache.getValues()) + { + if(!cache) continue; + + cache.dispose(); + } + + this._cache = null; + } + + if(this._unionImages) + { + for(const image of this._unionImages) + { + if(!image) continue; + + image.dispose(); + } + + this._unionImages = []; + } + } + + public disposeInactiveActions(k: number = 60000): void + { + const time = Date.now(); + + if(this._cache) + { + for(const cache of this._cache.getValues()) + { + if(!cache) continue; + + cache.disposeActions(k, time); + } + } + } + + public resetBodyPartCache(k: IActiveActionData): void + { + if(this._cache) + { + for(const cache of this._cache.getValues()) + { + if(!cache) continue; + + cache.setAction(k, 0); + } + } + } + + public setDirection(k: string, _arg_2: number): void + { + const parts = this._structure.getBodyPartsUnordered(k); + + if(parts) + { + for(const part of parts) + { + const actionCache = this.getBodyPartCache(part); + + if(!actionCache) continue; + + actionCache.setDirection(_arg_2); + } + } + } + + public setAction(k: IActiveActionData, _arg_2: number): void + { + const _local_3 = this._structure.getActiveBodyPartIds(k, this._avatar); + + for(const _local_4 of _local_3) + { + const _local_5 = this.getBodyPartCache(_local_4); + + if(_local_5) _local_5.setAction(k, _arg_2); + } + } + + public setGeometryType(k: string): void + { + if(this._geometryType === k) return; + + if((((this._geometryType === GeometryType.SITTING) && (k === GeometryType.VERTICAL)) || ((this._geometryType === GeometryType.VERTICAL) && (k === GeometryType.SITTING)) || ((this._geometryType === GeometryType.SNOWWARS_HORIZONTAL) && (k = GeometryType.SNOWWARS_HORIZONTAL)))) + { + this._geometryType = k; + this._canvas = null; + + return; + } + + this.disposeInactiveActions(0); + + this._geometryType = k; + this._canvas = null; + } + + public getImageContainer(k: string, frameNumber: number): AvatarImageBodyPartContainer + { + let _local_4 = this.getBodyPartCache(k); + + if(!_local_4) + { + _local_4 = new AvatarImageBodyPartCache(); + + this._cache.add(k, _local_4); + } + + let _local_5 = _local_4.getDirection(); + let _local_7 = _local_4.getAction(); + let frameCount = frameNumber; + + if(_local_7.definition.startFromFrameZero) frameCount -= _local_7.startFrame; + + let _local_8 = _local_7; + let _local_9: string[] = []; + let _local_10: AdvancedMap = new AdvancedMap(); + const _local_11 = new Point(); + + if(!((!(_local_7)) || (!(_local_7.definition)))) + { + if(_local_7.definition.isAnimation) + { + let _local_15 = _local_5; + + const _local_16 = this._structure.getAnimation(((_local_7.definition.state + '.') + _local_7.actionParameter)); + const _local_17 = (frameNumber - _local_7.startFrame); + + if(_local_16) + { + const _local_18 = _local_16.getLayerData(_local_17, k, _local_7.overridingAction); + + if(_local_18) + { + _local_15 = (_local_5 + _local_18.dd); + + if(_local_18.dd < 0) + { + if(_local_15 < 0) + { + _local_15 = (8 + _local_15); + } + else if(_local_15 > 7) _local_15 = (8 - _local_15); + } + else + { + if(_local_15 < 0) + { + _local_15 = (_local_15 + 8); + } + else if(_local_15 > 7) _local_15 = (_local_15 - 8); + } + + if(this._scale === AvatarScaleType.LARGE) + { + _local_11.x = _local_18.dx; + _local_11.y = _local_18.dy; + } + else + { + _local_11.x = (_local_18.dx / 2); + _local_11.y = (_local_18.dy / 2); + } + + frameCount = _local_18.animationFrame; + + if(_local_18.action) + { + _local_7 = _local_18.action; + } + + if(_local_18.type === AvatarAnimationLayerData.BODYPART) + { + if(_local_18.action != null) + { + _local_8 = _local_18.action; + } + + _local_5 = _local_15; + } + else if(_local_18.type === AvatarAnimationLayerData.FX) _local_5 = _local_15; + + _local_10 = _local_18.items; + } + + _local_9 = _local_16.removeData; + } + } + } + + let _local_12 = _local_4.getActionCache(_local_8); + + if(!_local_12) + { + _local_12 = new AvatarImageActionCache(); + _local_4.updateActionCache(_local_8, _local_12); + } + + let _local_13 = _local_12.getDirectionCache(_local_5); + + if(!_local_13) + { + const _local_19 = this._structure.getParts(k, this._avatar.getFigure(), _local_8, this._geometryType, _local_5, _local_9, this._avatar, _local_10); + + _local_13 = new AvatarImageDirectionCache(_local_19); + + _local_12.updateDirectionCache(_local_5, _local_13); + } + + let _local_14 = _local_13.getImageContainer(frameCount); + + if(!_local_14) + { + const _local_20 = _local_13.getPartList(); + + _local_14 = this.renderBodyPart(_local_5, _local_20, frameCount, _local_7); + + if(_local_14) + { + if(_local_14.isCacheable) _local_13.updateImageContainer(_local_14, frameCount); + } + else + { + return null; + } + } + + const offset = this._structure.getFrameBodyPartOffset(_local_8, _local_5, frameCount, k); + + _local_11.x += offset.x; + _local_11.y += offset.y; + + _local_14.offset = _local_11; + + return _local_14; + } + + public getBodyPartCache(k: string): AvatarImageBodyPartCache + { + let existing = this._cache.getValue(k); + + if(!existing) + { + existing = new AvatarImageBodyPartCache(); + + this._cache.add(k, existing); + } + + return existing; + } + + private renderBodyPart(direction: number, containers: AvatarImagePartContainer[], frameCount: number, _arg_4: IActiveActionData): AvatarImageBodyPartContainer + { + if(!containers || !containers.length) return null; + + if(!this._canvas) + { + this._canvas = this._structure.getCanvas(this._scale, this._geometryType); + + if(!this._canvas) return null; + } + + const isFlipped = AvatarDirectionAngle.DIRECTION_IS_FLIPPED[direction] || false; + let assetPartDefinition = _arg_4.definition.assetPartDefinition; + let isCacheable = true; + let containerIndex = (containers.length - 1); + + while(containerIndex >= 0) + { + const container = containers[containerIndex]; + + let color = 16777215; + + if(!((direction == 7) && ((container.partType === 'fc') || (container.partType === 'ey')))) + { + if(!((container.partType === 'ri') && !container.partId)) + { + const partId = container.partId; + const animationFrame = container.getFrameDefinition(frameCount); + + let partType = container.partType; + let frameNumber = 0; + + if(animationFrame) + { + frameNumber = animationFrame.number; + + if((animationFrame.assetPartDefinition) && (animationFrame.assetPartDefinition !== '')) assetPartDefinition = animationFrame.assetPartDefinition; + } + else frameNumber = container.getFrameIndex(frameCount); + + let assetDirection = direction; + let flipH = false; + + if(isFlipped) + { + if(((assetPartDefinition === 'wav') && (((partType === AvatarFigurePartType.LEFT_HAND) || (partType === AvatarFigurePartType.LEFT_SLEEVE)) || (partType === AvatarFigurePartType.LEFT_COAT_SLEEVE))) || ((assetPartDefinition === 'drk') && (((partType === AvatarFigurePartType.RIGHT_HAND) || (partType === AvatarFigurePartType.RIGHT_SLEEVE)) || (partType === AvatarFigurePartType.RIGHT_COAT_SLEEVE))) || ((assetPartDefinition === 'blw') && (partType === AvatarFigurePartType.RIGHT_HAND)) || ((assetPartDefinition === 'sig') && (partType === AvatarFigurePartType.LEFT_HAND)) || ((assetPartDefinition === 'respect') && (partType === AvatarFigurePartType.LEFT_HAND)) || (partType === AvatarFigurePartType.RIGHT_HAND_ITEM) || (partType === AvatarFigurePartType.LEFT_HAND_ITEM) || (partType === AvatarFigurePartType.CHEST_PRINT)) + { + flipH = true; + } + else + { + if(direction === 4) assetDirection = 2; + else if(direction === 5) assetDirection = 1; + else if(direction === 6) assetDirection = 0; + + if(container.flippedPartType !== partType) partType = container.flippedPartType; + } + } + + let assetName = (this._scale + '_' + assetPartDefinition + '_' + partType + '_' + partId + '_' + assetDirection + '_' + frameNumber); + let asset = this._assets.getAsset(assetName); + + if(!asset) + { + assetName = (this._scale + '_std_' + partType + '_' + partId + '_' + assetDirection + '_0'); + asset = this._assets.getAsset(assetName); + } + + if(asset) + { + const texture = asset.texture; + + if(!texture) + { + isCacheable = false; + } + else + { + if(container.isColorable && container.color) color = container.color.rgb; + + const offset = new Point(-(asset.x), -(asset.y)); + + if(flipH) offset.x = (offset.x + ((this._scale === AvatarScaleType.LARGE) ? 65 : 31)); + + this._unionImages.push(new ImageData(texture, asset.rectangle, offset, flipH, color)); + } + } + } + } + + containerIndex--; + } + + if(!this._unionImages.length) return null; + + const imageData = this.createUnionImage(this._unionImages, isFlipped); + const canvasOffset = ((this._scale === AvatarScaleType.LARGE) ? (this._canvas.height - 16) : (this._canvas.height - 8)); + const offset = new Point(-(imageData.regPoint.x), (canvasOffset - imageData.regPoint.y)); + + if(isFlipped && (assetPartDefinition !== 'lay')) offset.x = (offset.x + ((this._scale === AvatarScaleType.LARGE) ? 67 : 31)); + + let imageIndex = (this._unionImages.length - 1); + + while(imageIndex >= 0) + { + const _local_17 = this._unionImages.pop(); + + if(_local_17) _local_17.dispose(); + + imageIndex--; + } + + return new AvatarImageBodyPartContainer(imageData.texture, offset, isCacheable); + } + + private convertColorToHex(k: number): string + { + let _local_2: string = (k * 0xFF).toString(16); + if(_local_2.length < 2) + { + _local_2 = ('0' + _local_2); + } + return _local_2; + } + + private createUnionImage(imageDatas: ImageData[], isFlipped: boolean): ImageData + { + const bounds = new Rectangle(); + + for(const data of imageDatas) data && bounds.enlarge(data.offsetRect); + + const point = new Point(-(bounds.x), -(bounds.y)); + const canvas = createCanvas(bounds.width, bounds.height); + const ctx = canvas.getContext('2d'); + + for(const data of imageDatas) + { + if(!data) continue; + + const texture = data.texture; + const color = data.colorTransform; + const flipH = (!(isFlipped && data.flipH) && (isFlipped || data.flipH)); + const regPoint = point.clone(); + + regPoint.x -= data.regPoint.x; + regPoint.y -= data.regPoint.y; + + if(isFlipped) regPoint.x = (canvas.width - (regPoint.x + data.rect.width)); + + let scale = 1; + let tx = 0; + let ty = 0; + + if(flipH) + { + scale = -1; + tx = ((data.rect.x + data.rect.width) + regPoint.x); + ty = (regPoint.y - data.rect.y); + } + else + { + scale = 1; + tx = (regPoint.x - data.rect.x); + ty = (regPoint.y - data.rect.y); + } + + //ctx.save(); + ctx.scale(scale, 1); + //ctx.transform(scale, 1, 0, 0, tx, ty); + ctx.drawImage(texture, tx, ty, texture.width, texture.height); + //ctx.restore(); + + // set the color + //console.log(canvas.toDataURL()); + } + + return new ImageData(canvas, new Rectangle(0, 0, canvas.width, canvas.height), point, isFlipped, null); + } +} diff --git a/src/app/avatar/cache/AvatarImageDirectionCache.ts b/src/app/avatar/cache/AvatarImageDirectionCache.ts new file mode 100644 index 0000000..081d2ad --- /dev/null +++ b/src/app/avatar/cache/AvatarImageDirectionCache.ts @@ -0,0 +1,60 @@ +import { AdvancedMap } from '../../../core'; +import { AvatarImageBodyPartContainer } from '../AvatarImageBodyPartContainer'; +import { AvatarImagePartContainer } from '../AvatarImagePartContainer'; + +export class AvatarImageDirectionCache +{ + private _partList: AvatarImagePartContainer[]; + private _images: AdvancedMap; + + constructor(k: AvatarImagePartContainer[]) + { + this._partList = k; + this._images = new AdvancedMap(); + } + + public dispose(): void + { + for(const image of this._images.getValues()) image && image.dispose(); + + this._images = null; + } + + public getPartList(): AvatarImagePartContainer[] + { + return this._partList; + } + + public getImageContainer(k: number): AvatarImageBodyPartContainer + { + const existing = this._images.getValue(this.getCacheKey(k)); + + if(!existing) return null; + + return existing; + } + + public updateImageContainer(k: AvatarImageBodyPartContainer, _arg_2: number): void + { + const name = this.getCacheKey(_arg_2); + + const existing = this._images.getValue(name); + + if(existing) existing.dispose(); + + this._images.add(name, k); + } + + private getCacheKey(k: number): string + { + let name = ''; + + for(const part of this._partList) name += (part.getCacheableKey(k) + '/'); + + return name; + } + + private debugInfo(k: string): void + { + } +} diff --git a/src/app/avatar/cache/ImageData.ts b/src/app/avatar/cache/ImageData.ts new file mode 100644 index 0000000..565bcef --- /dev/null +++ b/src/app/avatar/cache/ImageData.ts @@ -0,0 +1,59 @@ +import { Canvas } from 'canvas'; +import { Point, Rectangle } from '../../../core'; + +export class ImageData +{ + private _texture: Canvas; + private _rect: Rectangle; + private _regPoint: Point; + private _flipH: boolean; + private _colorTransform: number; + + constructor(texture: Canvas, rectangle: Rectangle, _arg_3: Point, flipH: boolean, color: number) + { + this._texture = texture; + this._rect = rectangle; + this._regPoint = _arg_3; + this._flipH = flipH; + this._colorTransform = color; + + if(flipH) this._regPoint.x = (-(this._regPoint.x) + rectangle.width); + } + + public dispose(): void + { + this._texture = null; + this._regPoint = null; + this._colorTransform = null; + } + + public get texture(): Canvas + { + return this._texture; + } + + public get rect(): Rectangle + { + return this._rect; + } + + public get regPoint(): Point + { + return this._regPoint; + } + + public get flipH(): boolean + { + return this._flipH; + } + + public get colorTransform(): number + { + return this._colorTransform; + } + + public get offsetRect(): Rectangle + { + return new Rectangle(-(this._regPoint.x), -(this._regPoint.y), this._rect.width, this._rect.height); + } +} diff --git a/src/app/avatar/cache/index.ts b/src/app/avatar/cache/index.ts new file mode 100644 index 0000000..d8d2e53 --- /dev/null +++ b/src/app/avatar/cache/index.ts @@ -0,0 +1,5 @@ +export * from './AvatarImageActionCache'; +export * from './AvatarImageBodyPartCache'; +export * from './AvatarImageCache'; +export * from './AvatarImageDirectionCache'; +export * from './ImageData'; diff --git a/src/app/avatar/data/HabboAvatarAnimations.ts b/src/app/avatar/data/HabboAvatarAnimations.ts new file mode 100644 index 0000000..f1fc2cc --- /dev/null +++ b/src/app/avatar/data/HabboAvatarAnimations.ts @@ -0,0 +1,827 @@ +export const HabboAvatarAnimations = { + 'animations': [ + { + 'id': 'Move', + 'parts': [ + { + 'setType': 'bd', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'bds', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'ss', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'lg', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'sh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'lh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'lhs', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'ls', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'lc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'rh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'rhs', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'rs', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'rc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + }, + { + 'setType': 'ch', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 1, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 2, + 'assetPartDefinition': 'wlk' + }, + { + 'number': 3, + 'assetPartDefinition': 'wlk' + } + ] + } + ] + }, + { + 'id': 'Wave', + 'parts': [ + { + 'setType': 'lh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + }, + { + 'number': 1, + 'assetPartDefinition': 'wav' + } + ] + }, + { + 'setType': 'lhs', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + }, + { + 'number': 1, + 'assetPartDefinition': 'wav' + } + ] + }, + { + 'setType': 'ls', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + }, + { + 'number': 1, + 'assetPartDefinition': 'wav' + } + ] + }, + { + 'setType': 'lc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + }, + { + 'number': 1, + 'assetPartDefinition': 'wav' + } + ] + }, + { + 'setType': 'ch', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + }, + { + 'number': 1, + 'assetPartDefinition': 'wav' + }, + { + 'number': 2, + 'assetPartDefinition': 'wav' + }, + { + 'number': 3, + 'assetPartDefinition': 'wav' + } + ] + } + ] + }, + { + 'id': 'Talk', + 'parts': [ + { + 'setType': 'hd', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'spk' + }, + { + 'number': 1, + 'assetPartDefinition': 'spk' + } + ] + }, + { + 'setType': 'fc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'spk' + }, + { + 'number': 1, + 'assetPartDefinition': 'spk' + } + ] + }, + { + 'setType': 'fa', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'spk' + }, + { + 'number': 1, + 'assetPartDefinition': 'spk' + } + ] + } + ] + }, + { + 'id': 'Sign', + 'parts': [ + { + 'setType': 'lh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'sig' + } + ] + }, + { + 'setType': 'li', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'sig' + } + ] + }, + { + 'setType': 'ls', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + } + ] + }, + { + 'setType': 'lc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav' + } + ] + } + ] + }, + { + 'id': 'Respect', + 'parts': [ + { + 'setType': 'lh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'respect', + 'repeats': 15 + }, + { + 'number': 1, + 'assetPartDefinition': 'respect', + 'repeats': 15 + } + ] + }, + { + 'setType': 'ls', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav', + 'repeats': 15 + }, + { + 'number': 1, + 'assetPartDefinition': 'wav', + 'repeats': 15 + } + ] + }, + { + 'setType': 'lc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'wav', + 'repeats': 15 + }, + { + 'number': 1, + 'assetPartDefinition': 'wav', + 'repeats': 15 + } + ] + } + ] + }, + { + 'id': 'Blow', + 'parts': [ + { + 'setType': 'rh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'blw', + 'repeats': 10 + }, + { + 'number': 1, + 'assetPartDefinition': 'blw', + 'repeats': 10 + } + ] + }, + { + 'setType': 'rs', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'drk' + } + ] + }, + { + 'setType': 'rc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'drk' + } + ] + }, + { + 'setType': 'ri', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': '' + } + ] + }, + { + 'setType': 'ey', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'std', + 'repeats': 10 + }, + { + 'number': 0, + 'assetPartDefinition': 'eyb', + 'repeats': 10 + } + ] + }, + { + 'setType': 'fc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'std', + 'repeats': 10 + }, + { + 'number': 0, + 'assetPartDefinition': 'blw', + 'repeats': 10 + } + ] + } + ] + }, + { + 'id': 'Laugh', + 'parts': [ + { + 'setType': 'rh', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'blw' + } + ] + }, + { + 'setType': 'rs', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'drk' + } + ] + }, + { + 'setType': 'rc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'drk' + } + ] + }, + { + 'setType': 'ri', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': '' + } + ] + }, + { + 'setType': 'ey', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'std', + 'repeats': 2 + } + ] + }, + { + 'setType': 'fc', + 'frames': [ + { + 'number': 0, + 'assetPartDefinition': 'sml' + } + ] + } + ], + 'offsets': { + 'frames': [ + { + 'id': 0, + 'directions': [ + { + 'id': 0, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 1, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 2, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 3, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 4, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 5, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 6, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + }, + { + 'id': 7, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 1 + } + ] + } + ] + }, + { + 'id': 1, + 'directions': [ + { + 'id': 0, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 1, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 2, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 3, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 4, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 5, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 6, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + }, + { + 'id': 7, + 'bodyParts': [ + { + 'id': 'head', + 'dx': 0, + 'dy': 0 + } + ] + } + ] + } + ] + } + } + ] +}; diff --git a/src/app/avatar/data/HabboAvatarGeometry.ts b/src/app/avatar/data/HabboAvatarGeometry.ts new file mode 100644 index 0000000..e6b9db0 --- /dev/null +++ b/src/app/avatar/data/HabboAvatarGeometry.ts @@ -0,0 +1,1830 @@ +export const HabboAvatarGeometry = { + 'geometry': { + 'direction': 0, + 'camera': { + 'x': 0, + 'y': 0, + 'z': 10 + }, + 'canvases': [ + { + 'scale': 'h', + 'geometries': [ + { + 'id': 'vertical', + 'width': 90, + 'height': 130, + 'dx': 0, + 'dy': 0 + }, + { + 'id': 'sitting', + 'width': 90, + 'height': 130, + 'dx': 0, + 'dy': 0 + }, + { + 'id': 'horizontal', + 'width': 128, + 'height': 80, + 'dx': 30, + 'dy': 0 + }, + { + 'id': 'swhorizontal', + 'width': 192, + 'height': 120, + 'dx': 0, + 'dy': -40 + } + ] + }, + { + 'scale': 'sh', + 'geometries': [ + { + 'id': 'vertical', + 'width': 45, + 'height': 72, + 'dx': 0, + 'dy': 0 + }, + { + 'id': 'sitting', + 'width': 45, + 'height': 72, + 'dx': 0, + 'dy': 0 + }, + { + 'id': 'horizontal', + 'width': 64, + 'height': 50, + 'dx': 15, + 'dy': -10 + }, + { + 'id': 'swhorizontal', + 'width': 96, + 'height': 70, + 'dx': 0, + 'dy': -20 + }, + { + 'id': 'swim', + 'width': 64, + 'height': 70, + 'dx': 25, + 'dy': 10 + } + ] + } + ], + 'avatarSets': [ + { + 'id': 'full', + 'avatarSets': [ + { + 'id': 'body', + 'main': true, + 'bodyParts': [ + { + 'id': 'top' + }, + { + 'id': 'bottom' + }, + { + 'id': 'behind' + }, + { + 'id': 'torso' + }, + { + 'id': 'leftitem' + }, + { + 'id': 'rightitem' + }, + { + 'id': 'leftarm' + }, + { + 'id': 'rightarm' + } + ] + }, + { + 'id': 'head', + 'bodyParts': [ + { + 'id': 'head' + } + ] + } + ] + } + ], + 'types': [ + { + 'id': 'vertical', + 'bodyParts': [ + { + 'id': 'top', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 2.0 + }, + { + 'id': 'bottom', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.001 + }, + { + 'id': 'behind', + 'x': 0, + 'y': 0, + 'z': 0.2, + 'radius': 0.3 + }, + { + 'id': 'torso', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.4, + 'items': [ + { + 'id': 'bd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'bds', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'ch', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'sh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lg', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ss', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cp', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.045, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'wa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ca', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'li', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'ri', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftarm', + 'x': -1, + 'y': 0, + 'z': -0.51, + 'radius': 0.5, + 'items': [ + { + 'id': 'lh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ls', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightarm', + 'x': 1, + 'y': 0, + 'z': -0.51, + 'radius': 0.5, + 'items': [ + { + 'id': 'rh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'head', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.5, + 'items': [ + { + 'id': 'hd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ey', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'hr', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'hrb', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ea', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ha', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.08, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'he', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.09, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + } + ] + }, + { + 'id': 'sitting', + 'bodyParts': [ + { + 'id': 'top', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 2.0 + }, + { + 'id': 'bottom', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.001 + }, + { + 'id': 'behind', + 'x': 0, + 'y': 0, + 'z': 0.2, + 'radius': 0.3 + }, + { + 'id': 'torso', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.4, + 'items': [ + { + 'id': 'bd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'bds', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'ch', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'sh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lg', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ss', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cp', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.045, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'wa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ca', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'li', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'ri', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftarm', + 'x': -1, + 'y': 0, + 'z': -0.51, + 'radius': 0.5, + 'items': [ + { + 'id': 'lh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ls', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightarm', + 'x': 1, + 'y': 0, + 'z': -0.51, + 'radius': 0.5, + 'items': [ + { + 'id': 'rh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'head', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.5, + 'items': [ + { + 'id': 'hd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ey', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'hr', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'hrb', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ea', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ha', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.08, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'he', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.09, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + } + ] + }, + { + 'id': 'horizontal', + 'bodyParts': [ + { + 'id': 'torso', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.4, + 'items': [ + { + 'id': 'bd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'bds', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'ch', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cp', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'sh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lg', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ss', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'wa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ca', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'li', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'ri', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftarm', + 'x': -1, + 'y': 0, + 'z': -0.51, + 'radius': 0.6, + 'items': [ + { + 'id': 'lh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ls', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightarm', + 'x': 1, + 'y': 0, + 'z': -0.51, + 'radius': 0.6, + 'items': [ + { + 'id': 'rh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'head', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.5, + 'items': [ + { + 'id': 'hd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ey', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'hr', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'hrb', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ea', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ha', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.08, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'he', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.09, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + } + ] + }, + { + 'id': 'swhorizontal', + 'bodyParts': [ + { + 'id': 'torso', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.4, + 'items': [ + { + 'id': 'bd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'bds', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'ch', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cp', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'sh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lg', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ss', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'wa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'cc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ca', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'li', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightitem', + 'x': 0, + 'y': 0, + 'z': -0.29, + 'radius': 0.3, + 'items': [ + { + 'id': 'ri', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'leftarm', + 'x': -1, + 'y': 0, + 'z': -0.51, + 'radius': 0.6, + 'items': [ + { + 'id': 'lh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ls', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'lc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'rightarm', + 'x': 1, + 'y': 0, + 'z': -0.51, + 'radius': 0.6, + 'items': [ + { + 'id': 'rh', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rhs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rs', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'rc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.025, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'head', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.5, + 'items': [ + { + 'id': 'hd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ey', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'hr', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'hrb', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ea', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ha', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.08, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'he', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.09, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + } + ] + }, + { + 'id': 'swim', + 'bodyParts': [ + { + 'id': 'torso', + 'x': 0, + 'y': 0, + 'z': 0.0, + 'radius': 0.4, + 'items': [ + { + 'id': 'bds', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'ss', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + }, + { + 'id': 'head', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.5, + 'items': [ + { + 'id': 'hd', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.01, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fc', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.02, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ey', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.03, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'hr', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.04, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'hrb', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.05, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': true + }, + { + 'id': 'fa', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.06, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ea', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.07, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'ha', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.08, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + }, + { + 'id': 'he', + 'x': 0, + 'y': 0, + 'z': 0, + 'radius': 0.09, + 'nx': 0, + 'ny': 0, + 'nz': -1, + 'double': false + } + ] + } + ] + } + ] + } +}; diff --git a/src/app/avatar/data/HabboAvatarPartSets.ts b/src/app/avatar/data/HabboAvatarPartSets.ts new file mode 100644 index 0000000..1bd4750 --- /dev/null +++ b/src/app/avatar/data/HabboAvatarPartSets.ts @@ -0,0 +1,418 @@ +export const HabboAvatarPartSets = { + 'partSets': { + 'partSet': [ + { + 'setType': 'ri', + 'flippedSetType': 'ri' + }, + { + 'setType': 'ri', + 'flippedSetType': 'ri' + }, + { + 'setType': 'rh', + 'flippedSetType': 'lh' + }, + { + 'setType': 'rhs', + 'flippedSetType': 'lhs' + }, + { + 'setType': 'rs', + 'swim': '0', + 'flippedSetType': 'ls' + }, + { + 'setType': 'rc', + 'flippedSetType': 'lc' + }, + { + 'setType': 'bd' + }, + { + 'setType': 'bds' + }, + { + 'setType': 'ss' + }, + { + 'setType': 'sh' + }, + { + 'setType': 'lg' + }, + { + 'setType': 'ch' + }, + { + 'setType': 'cp' + }, + { + 'setType': 'cc' + }, + { + 'setType': 'hd' + }, + { + 'setType': 'fc' + }, + { + 'setType': 'ey' + }, + { + 'setType': 'hr' + }, + { + 'setType': 'hrb', + 'removeSetType': 'hr' + }, + { + 'setType': 'li', + 'flippedSetType': 'li' + }, + { + 'setType': 'lh', + 'flippedSetType': 'rh' + }, + { + 'setType': 'lhs', + 'flippedSetType': 'rhs' + }, + { + 'setType': 'ls', + 'flippedSetType': 'rs' + }, + { + 'setType': 'lc', + 'flippedSetType': 'rc' + }, + { + 'setType': 'wa' + }, + { + 'setType': 'ea' + }, + { + 'setType': 'ca' + }, + { + 'setType': 'fa' + }, + { + 'setType': 'ha' + }, + { + 'setType': 'he' + } + ], + 'activePartSets': [ + { + 'id': 'figure', + 'activeParts': [ + { + 'setType': 'rh' + }, + { + 'setType': 'rh' + }, + { + 'setType': 'rhs' + }, + { + 'setType': 'rs' + }, + { + 'setType': 'rc' + }, + { + 'setType': 'bd' + }, + { + 'setType': 'bds' + }, + { + 'setType': 'ss' + }, + { + 'setType': 'sh' + }, + { + 'setType': 'lg' + }, + { + 'setType': 'ch' + }, + { + 'setType': 'cp' + }, + { + 'setType': 'cc' + }, + { + 'setType': 'wa' + }, + { + 'setType': 'hd' + }, + { + 'setType': 'fc' + }, + { + 'setType': 'ey' + }, + { + 'setType': 'hr' + }, + { + 'setType': 'hrb' + }, + { + 'setType': 'lh' + }, + { + 'setType': 'lhs' + }, + { + 'setType': 'ls' + }, + { + 'setType': 'lc' + }, + { + 'setType': 'ea' + }, + { + 'setType': 'ca' + }, + { + 'setType': 'fa' + }, + { + 'setType': 'ha' + }, + { + 'setType': 'he' + } + ] + }, + { + 'id': 'head', + 'activeParts': [ + { + 'setType': 'hd' + }, + { + 'setType': 'fc' + }, + { + 'setType': 'ey' + }, + { + 'setType': 'hr' + }, + { + 'setType': 'hrb' + }, + { + 'setType': 'ea' + }, + { + 'setType': 'fa' + }, + { + 'setType': 'ha' + }, + { + 'setType': 'he' + } + ] + }, + { + 'id': 'speak', + 'activeParts': [ + { + 'setType': 'hd' + }, + { + 'setType': 'hr' + }, + { + 'setType': 'hrb' + }, + { + 'setType': 'fc' + }, + { + 'setType': 'fa' + }, + { + 'setType': 'ha' + } + ] + }, + { + 'id': 'gesture', + 'activeParts': [ + { + 'setType': 'ey' + }, + { + 'setType': 'fc' + } + ] + }, + { + 'id': 'eye', + 'activeParts': [ + { + 'setType': 'ey' + } + ] + }, + { + 'id': 'handRight', + 'activeParts': [ + { + 'setType': 'rh' + }, + { + 'setType': 'rhs' + }, + { + 'setType': 'rs' + }, + { + 'setType': 'rc' + }, + { + 'setType': 'ri' + } + ] + }, + { + 'id': 'handRightAndHead', + 'activeParts': [ + { + 'setType': 'rh' + }, + { + 'setType': 'rhs' + }, + { + 'setType': 'rs' + }, + { + 'setType': 'rc' + }, + { + 'setType': 'ri' + }, + { + 'setType': 'ey' + }, + { + 'setType': 'fc' + }, + { + 'setType': 'hd' + } + ] + }, + { + 'id': 'handLeft', + 'activeParts': [ + { + 'setType': 'lh' + }, + { + 'setType': 'lhs' + }, + { + 'setType': 'ls' + }, + { + 'setType': 'lc' + }, + { + 'setType': 'li' + } + ] + }, + { + 'id': 'walk', + 'activeParts': [ + { + 'setType': 'bd' + }, + { + 'setType': 'bds' + }, + { + 'setType': 'ss' + }, + { + 'setType': 'lg' + }, + { + 'setType': 'lh' + }, + { + 'setType': 'lhs' + }, + { + 'setType': 'rh' + }, + { + 'setType': 'rhs' + }, + { + 'setType': 'ls' + }, + { + 'setType': 'lc' + }, + { + 'setType': 'rs' + }, + { + 'setType': 'rc' + }, + { + 'setType': 'sh' + } + ] + }, + { + 'id': 'sit', + 'activeParts': [ + { + 'setType': 'bd' + }, + { + 'setType': 'bds' + }, + { + 'setType': 'ss' + }, + { + 'setType': 'lg' + }, + { + 'setType': 'sh' + }, + { + 'setType': 'cc' + } + ] + }, + { + 'id': 'itemRight', + 'activeParts': [ + { + 'setType': 'ri' + } + ] + } + ] + } +}; diff --git a/src/app/avatar/data/index.ts b/src/app/avatar/data/index.ts new file mode 100644 index 0000000..a147605 --- /dev/null +++ b/src/app/avatar/data/index.ts @@ -0,0 +1,3 @@ +export * from './HabboAvatarAnimations'; +export * from './HabboAvatarGeometry'; +export * from './HabboAvatarPartSets'; diff --git a/src/app/avatar/enum/AvatarAction.ts b/src/app/avatar/enum/AvatarAction.ts new file mode 100644 index 0000000..2d7ac10 --- /dev/null +++ b/src/app/avatar/enum/AvatarAction.ts @@ -0,0 +1,127 @@ +export class AvatarAction +{ + public static CARRY_OBJECT = 'cri'; + public static DANCE = 'dance'; + public static EFFECT = 'fx'; + public static EXPRESSION = 'expression'; + public static EXPRESSION_BLOW_A_KISS = 'blow'; + public static EXPRESSION_CRY = 'cry'; + public static EXPRESSION_IDLE = 'idle'; + public static EXPRESSION_LAUGH = 'laugh'; + public static EXPRESSION_RESPECT = 'respect'; + public static EXPRESSION_RIDE_JUMP = 'ridejump'; + public static EXPRESSION_SNOWBOARD_OLLIE = 'sbollie'; + public static EXPRESSION_SNOWBORD_360 = 'sb360'; + public static EXPRESSION_WAVE = 'wave'; + public static GESTURE = 'gest'; + public static GESTURE_AGGRAVATED = 'agr'; + public static GESTURE_SAD = 'sad'; + public static GESTURE_SMILE = 'sml'; + public static GESTURE_SURPRISED = 'srp'; + public static GUIDE_STATUS = 'guide'; + public static MUTED = 'muted'; + public static PET_GESTURE_BLINK = 'eyb'; + public static PET_GESTURE_CRAZY = 'crz'; + public static PET_GESTURE_JOY = 'joy'; + public static PET_GESTURE_MISERABLE = 'mis'; + public static PET_GESTURE_PUZZLED = 'puz'; + public static PET_GESTURE_TONGUE = 'tng'; + public static PLAYING_GAME = 'playing_game'; + public static POSTURE = 'posture'; + public static POSTURE_FLOAT = 'float'; + public static POSTURE_LAY = 'lay'; + public static POSTURE_SIT = 'sit'; + public static POSTURE_STAND = 'std'; + public static POSTURE_SWIM = 'swim'; + public static POSTURE_WALK = 'mv'; + public static SIGN = 'sign'; + public static SLEEP = 'sleep'; + public static SNOWWAR_DIE_BACK = 'swdieback'; + public static SNOWWAR_DIE_FRONT = 'swdiefront'; + public static SNOWWAR_PICK = 'swpick'; + public static SNOWWAR_RUN = 'swrun'; + public static SNOWWAR_THROW = 'swthrow'; + public static TALK = 'talk'; + public static BLINK = 'blink'; + public static TYPING = 'typing'; + public static USE_OBJECT = 'usei'; + public static VOTE = 'vote'; + + public static GESTURE_MAP = [ '', AvatarAction.GESTURE_SMILE, AvatarAction.GESTURE_AGGRAVATED, AvatarAction.GESTURE_SURPRISED, AvatarAction.GESTURE_SAD, AvatarAction.PET_GESTURE_JOY, AvatarAction.PET_GESTURE_CRAZY, AvatarAction.PET_GESTURE_TONGUE, AvatarAction.PET_GESTURE_BLINK, AvatarAction.PET_GESTURE_MISERABLE, AvatarAction.PET_GESTURE_PUZZLED ]; + + public static EXPRESSION_MAP = [ '', AvatarAction.EXPRESSION_WAVE, AvatarAction.EXPRESSION_BLOW_A_KISS, AvatarAction.EXPRESSION_LAUGH, AvatarAction.EXPRESSION_CRY, AvatarAction.EXPRESSION_IDLE, AvatarAction.DANCE, AvatarAction.EXPRESSION_RESPECT, AvatarAction.EXPRESSION_SNOWBOARD_OLLIE, AvatarAction.EXPRESSION_SNOWBORD_360, AvatarAction.EXPRESSION_RIDE_JUMP ]; + + public static getExpressionTimeout(expressionId: number): number + { + expressionId = parseInt(expressionId as any); + + switch(expressionId) + { + case 1: + return 5000; + case 2: + return 1400; + case 3: + return 2000; + case 4: + return 2000; + case 5: + return 0; + case 6: + return 700; + case 7: + return 2000; + case 8: + return 1500; + case 9: + return 1500; + case 10: + return 1500; + default: + return 0; + } + } + + public static getExpressionId(expression: string): number + { + return AvatarAction.EXPRESSION_MAP.indexOf(expression); + } + + public static getExpression(expressionId: number): string + { + if(expressionId > AvatarAction.EXPRESSION_MAP.length) return null; + + return AvatarAction.EXPRESSION_MAP[expressionId]; + } + + public static getGestureId(gesture: string): number + { + return AvatarAction.GESTURE_MAP.indexOf(gesture); + } + + public static getGesture(gestureId: number): string + { + if(gestureId > AvatarAction.GESTURE_MAP.length) return null; + + return AvatarAction.GESTURE_MAP[gestureId]; + } + + public static idToAvatarActionState(id: string): string + { + if(id === 'Lay') return 'lay'; + if(id === 'Float') return 'float'; + if(id === 'Swim') return 'swim'; + if(id === 'Sit') return 'sit'; + if(id === 'Respect') return 'respect'; + if(id === 'Wave') return 'wave'; + if(id === 'Idle') return 'idle'; + if(id === 'Dance') return 'dance'; + if(id === 'UseItem') return 'usei'; + if(id === 'CarryItem') return 'cri'; + if(id === 'Talk') return 'talk'; + if(id === 'Sleep') return 'Sleep'; + if(id === 'Move') return 'mv'; + + return 'std'; + } +} diff --git a/src/app/avatar/enum/AvatarDirectionAngle.ts b/src/app/avatar/enum/AvatarDirectionAngle.ts new file mode 100644 index 0000000..83f9288 --- /dev/null +++ b/src/app/avatar/enum/AvatarDirectionAngle.ts @@ -0,0 +1,7 @@ +export class AvatarDirectionAngle +{ + public static DIRECTION_TO_ANGLE: number[] = [45, 90, 135, 180, 225, 270, 315, 0]; + public static DIRECTION_IS_FLIPPED: boolean[] = [false, false, false, false, true, true, true, false]; + public static MIN_DIRECTION: number = 0; + public static MAX_DIRECTION: number = 7; +} diff --git a/src/app/avatar/enum/AvatarFigurePartType.ts b/src/app/avatar/enum/AvatarFigurePartType.ts new file mode 100644 index 0000000..30bc564 --- /dev/null +++ b/src/app/avatar/enum/AvatarFigurePartType.ts @@ -0,0 +1,29 @@ +export class AvatarFigurePartType +{ + public static BODY: string = 'bd'; + public static SHOES: string = 'sh'; + public static LEGS: string = 'lg'; + public static CHEST: string = 'ch'; + public static WAIST_ACCESSORY: string = 'wa'; + public static CHEST_ACCESSORY: string = 'ca'; + public static HEAD: string = 'hd'; + public static HAIR: string = 'hr'; + public static FACE_ACCESSORY: string = 'fa'; + public static EYE_ACCESSORY: string = 'ea'; + public static HEAD_ACCESSORY: string = 'ha'; + public static HEAD_ACCESSORY_EXTRA: string = 'he'; + public static COAT_CHEST: string = 'cc'; + public static CHEST_PRINT: string = 'cp'; + public static LEFT_HAND_ITEM: string = 'li'; + public static LEFT_HAND: string = 'lh'; + public static LEFT_SLEEVE: string = 'ls'; + public static RIGHT_HAND: string = 'rh'; + public static RIGHT_SLEEVE: string = 'rs'; + public static FACE: string = 'fc'; + public static EYES: string = 'ey'; + public static HAIR_BIG: string = 'hrb'; + public static RIGHT_HAND_ITEM: string = 'ri'; + public static LEFT_COAT_SLEEVE: string = 'lc'; + public static RIGHT_COAT_SLEEVE: string = 'rc'; + public static FIGURE_SETS: string[] = [ AvatarFigurePartType.SHOES, AvatarFigurePartType.LEGS, AvatarFigurePartType.CHEST, AvatarFigurePartType.WAIST_ACCESSORY, AvatarFigurePartType.CHEST_ACCESSORY, AvatarFigurePartType.HEAD, AvatarFigurePartType.HAIR, AvatarFigurePartType.FACE_ACCESSORY, AvatarFigurePartType.EYE_ACCESSORY, AvatarFigurePartType.HEAD_ACCESSORY, AvatarFigurePartType.HEAD_ACCESSORY_EXTRA, AvatarFigurePartType.COAT_CHEST, AvatarFigurePartType.CHEST_PRINT ]; +} diff --git a/src/app/avatar/enum/AvatarScaleType.ts b/src/app/avatar/enum/AvatarScaleType.ts new file mode 100644 index 0000000..5933495 --- /dev/null +++ b/src/app/avatar/enum/AvatarScaleType.ts @@ -0,0 +1,5 @@ +export class AvatarScaleType +{ + public static LARGE: string = 'h'; + public static SMALL: string = 'sh'; +} \ No newline at end of file diff --git a/src/app/avatar/enum/AvatarSetType.ts b/src/app/avatar/enum/AvatarSetType.ts new file mode 100644 index 0000000..38df0af --- /dev/null +++ b/src/app/avatar/enum/AvatarSetType.ts @@ -0,0 +1,6 @@ +export class AvatarSetType +{ + public static FULL: string = 'full'; + public static HEAD: string = 'head'; + public static BODY: string = 'body'; +} \ No newline at end of file diff --git a/src/app/avatar/enum/GeometryType.ts b/src/app/avatar/enum/GeometryType.ts new file mode 100644 index 0000000..5e388fe --- /dev/null +++ b/src/app/avatar/enum/GeometryType.ts @@ -0,0 +1,8 @@ +export class GeometryType +{ + public static VERTICAL: string = 'vertical'; + public static SITTING: string = 'sitting'; + public static HORIZONTAL: string = 'horizontal'; + public static SWIM: string = 'swim'; + public static SNOWWARS_HORIZONTAL: string = 'swhorizontal'; +} diff --git a/src/app/avatar/enum/RenderMode.ts b/src/app/avatar/enum/RenderMode.ts new file mode 100644 index 0000000..68900f3 --- /dev/null +++ b/src/app/avatar/enum/RenderMode.ts @@ -0,0 +1,7 @@ +export class RenderMode +{ + public static TOOL: string = 'tool'; + public static COMPONENT: string = 'component'; + public static ONLINE_TOOL: string = 'online_tool'; + public static LOCAL_ONLY: string = 'local_only'; +} diff --git a/src/app/avatar/enum/index.ts b/src/app/avatar/enum/index.ts new file mode 100644 index 0000000..bd40612 --- /dev/null +++ b/src/app/avatar/enum/index.ts @@ -0,0 +1,7 @@ +export * from './AvatarAction'; +export * from './AvatarDirectionAngle'; +export * from './AvatarFigurePartType'; +export * from './AvatarScaleType'; +export * from './AvatarSetType'; +export * from './GeometryType'; +export * from './RenderMode'; diff --git a/src/app/avatar/geometry/AvatarModelGeometry.ts b/src/app/avatar/geometry/AvatarModelGeometry.ts new file mode 100644 index 0000000..c8542fa --- /dev/null +++ b/src/app/avatar/geometry/AvatarModelGeometry.ts @@ -0,0 +1,288 @@ +import { AdvancedMap } from '../../../core'; +import { IAvatarImage } from '../IAvatarImage'; +import { AvatarCanvas } from '../structure'; +import { AvatarSet } from './AvatarSet'; +import { GeometryBodyPart } from './GeometryBodyPart'; +import { Matrix4x4 } from './Matrix4x4'; +import { Vector3D } from './Vector3D'; + +export class AvatarModelGeometry +{ + private _camera: Vector3D; + private _avatarSet: AvatarSet; + private _geometryTypes: AdvancedMap>; + private _itemIdToBodyPartMap: AdvancedMap>; + private _transformation: Matrix4x4; + private _canvases: AdvancedMap>; + + constructor(k: any) + { + this._camera = new Vector3D(0, 0, 10); + this._avatarSet = new AvatarSet(k.avatarSets[0]); + this._geometryTypes = new AdvancedMap(); + this._itemIdToBodyPartMap = new AdvancedMap(); + this._transformation = new Matrix4x4(); + this._canvases = new AdvancedMap(); + + const camera = k.camera; + + if(camera) + { + this._camera.x = parseFloat(camera.x); + this._camera.y = parseFloat(camera.y); + this._camera.z = parseFloat(camera.z); + } + + if(k.canvases && (k.canvases.length > 0)) + { + for(const canvas of k.canvases) + { + if(!canvas) continue; + + const scale = canvas.scale; + const geometries: AdvancedMap = new AdvancedMap(); + + if(canvas.geometries && (canvas.geometries.length > 0)) + { + for(const geometry of canvas.geometries) + { + if(!geometry) continue; + + const avatarCanvas = new AvatarCanvas(geometry, scale); + + geometries.add(avatarCanvas.id, avatarCanvas); + } + } + + this._canvases.add(scale, geometries); + } + } + + if(k.types && (k.types.length > 0)) + { + for(const type of k.types) + { + if(!type) continue; + + const bodyParts: AdvancedMap = new AdvancedMap(); + const itemIds: AdvancedMap = new AdvancedMap(); + + if(type.bodyParts && (type.bodyParts.length > 0)) + { + for(const bodyPart of type.bodyParts) + { + if(!bodyPart) continue; + + const geometryBodyPart = new GeometryBodyPart(bodyPart); + + bodyParts.add(geometryBodyPart.id, geometryBodyPart); + + for(const part of geometryBodyPart.getPartIds(null)) + { + itemIds.add(part, geometryBodyPart); + } + } + } + + this._geometryTypes.add(type.id, bodyParts); + this._itemIdToBodyPartMap.add(type.id, itemIds); + } + } + } + + public removeDynamicItems(k: IAvatarImage): void + { + for(const geometry of this._geometryTypes.getValues()) + { + if(!geometry) continue; + + for(const part of geometry.getValues()) + { + if(!part) continue; + + part.removeDynamicParts(k); + } + } + } + + public getBodyPartIdsInAvatarSet(k: string): string[] + { + const avatarSet = this._avatarSet.findAvatarSet(k); + + if(!avatarSet) return []; + + return avatarSet.getBodyParts(); + } + + public isMainAvatarSet(k: string): boolean + { + const avatarSet = this._avatarSet.findAvatarSet(k); + + if(!avatarSet) return false; + + return avatarSet.isMain; + } + + public getCanvas(k: string, _arg_2: string): AvatarCanvas + { + const canvas = this._canvases.getValue(k); + + if(!canvas) return null; + + return (canvas.getValue(_arg_2) || null); + } + + private typeExists(k: string): boolean + { + const existing = this._geometryTypes.getValue(k); + + if(existing) return true; + + return false; + } + + private hasBodyPart(k: string, _arg_2: string): boolean + { + if(this.typeExists(k)) + { + const existing = this._geometryTypes.getValue(k); + + if(existing && existing.getValue(_arg_2)) return true; + } + + return false; + } + + private getBodyPartIDs(k: string): string[] + { + const parts = this.getBodyPartsOfType(k); + + const types = []; + + if(parts) + { + for(const part of parts.getValues()) + { + if(!part) continue; + + types.push(part.id); + } + } + + return types; + } + + private getBodyPartsOfType(k: string): AdvancedMap + { + if(this.typeExists(k)) return this._geometryTypes.getValue(k); + + return new AdvancedMap(); + } + + public getBodyPart(k: string, _arg_2: string): GeometryBodyPart + { + return (this.getBodyPartsOfType(k).getValue(_arg_2) || null); + } + + public getBodyPartOfItem(k: string, _arg_2: string, _arg_3:IAvatarImage): GeometryBodyPart + { + const itemIds = this._itemIdToBodyPartMap.getValue(k); + + if(itemIds) + { + const part = itemIds.getValue(_arg_2); + + if(part) return part; + + const parts = this.getBodyPartsOfType(k); + + if(parts) + { + for(const part of parts.getValues()) + { + if(!part) continue; + + if(part.hasPart(_arg_2, _arg_3)) return part; + } + } + } + + return null; + } + + private getBodyPartsInAvatarSet(k: AdvancedMap, _arg_2: string): GeometryBodyPart[] + { + const parts = this.getBodyPartIdsInAvatarSet(_arg_2); + const geometryParts = []; + + for(const part of parts) + { + if(!part) continue; + + const bodyPart = k.getValue(part); + + if(bodyPart) + { + geometryParts.push(bodyPart); + } + } + + return geometryParts; + } + + public getBodyPartsAtAngle(k: string, _arg_2: number, _arg_3: string): string[] + { + if(!_arg_3) return []; + + const geometryParts = this.getBodyPartsOfType(_arg_3); + const parts = this.getBodyPartsInAvatarSet(geometryParts, k); + const sets: [ number, GeometryBodyPart ][] = []; + const ids: string[] = []; + + this._transformation = Matrix4x4.getYRotationMatrix(_arg_2); + + for(const part of parts) + { + if(!part) continue; + + part.applyTransform(this._transformation); + + sets.push([ part.getDistance(this._camera), part ]); + } + + sets.sort((a, b) => + { + const partA = a[0]; + const partB = b[0]; + + if(partA < partB) return -1; + + if(partA > partB) return 1; + + return 0; + }); + + for(const set of sets) + { + if(!set) continue; + + ids.push(set[1].id); + } + + return ids; + } + + public getParts(k: string, _arg_2: string, _arg_3: number, _arg_4: any[], _arg_5:IAvatarImage): string[] + { + if(this.hasBodyPart(k, _arg_2)) + { + const part = this.getBodyPartsOfType(k).getValue(_arg_2); + + this._transformation = Matrix4x4.getYRotationMatrix(_arg_3); + + return part.getParts(this._transformation, this._camera, _arg_4, _arg_5); + } + + return []; + } +} diff --git a/src/app/avatar/geometry/AvatarSet.ts b/src/app/avatar/geometry/AvatarSet.ts new file mode 100644 index 0000000..1a77958 --- /dev/null +++ b/src/app/avatar/geometry/AvatarSet.ts @@ -0,0 +1,94 @@ +import { AdvancedMap } from '../../../core'; + +export class AvatarSet +{ + private _id: string; + private _isMain: boolean; + private _avatarSets: AdvancedMap; + private _bodyParts: string[]; + private _allBodyParts: string[]; + + constructor(k: any) + { + this._id = k.id; + this._isMain = k.main || false; + this._avatarSets = new AdvancedMap(); + this._bodyParts = []; + this._allBodyParts = []; + + if(k.avatarSets && (k.avatarSets.length > 0)) + { + for(const avatarSet of k.avatarSets) + { + if(!avatarSet) continue; + + const set = new AvatarSet(avatarSet); + + this._avatarSets.add(set.id, set); + } + } + + if(k.bodyParts && (k.bodyParts.length > 0)) + { + for(const bodyPart of k.bodyParts) + { + if(!bodyPart) continue; + + this._bodyParts.push(bodyPart.id); + } + } + + let bodyParts = this._bodyParts.concat(); + + for(const avatarSet of this._avatarSets.getValues()) + { + if(!avatarSet) continue; + + bodyParts = bodyParts.concat(avatarSet.getBodyParts()); + } + + this._allBodyParts = bodyParts; + } + + public findAvatarSet(k: string): AvatarSet + { + if(k === this._id) return this; + + for(const avatarSet of this._avatarSets.getValues()) + { + if(!avatarSet) continue; + + if(!avatarSet.findAvatarSet(k)) continue; + + return avatarSet; + } + + return null; + } + + public getBodyParts(): string[] + { + return this._allBodyParts.concat(); + } + + public get id(): string + { + return this._id; + } + + public get isMain(): boolean + { + if(this._isMain) return true; + + for(const avatarSet of this._avatarSets.getValues()) + { + if(!avatarSet) continue; + + if(!avatarSet.isMain) continue; + + return true; + } + + return false; + } +} diff --git a/src/app/avatar/geometry/GeometryBodyPart.ts b/src/app/avatar/geometry/GeometryBodyPart.ts new file mode 100644 index 0000000..8844a43 --- /dev/null +++ b/src/app/avatar/geometry/GeometryBodyPart.ts @@ -0,0 +1,195 @@ +import { AdvancedMap } from '../../../core'; +import { IAvatarImage } from '../IAvatarImage'; +import { GeometryItem } from './GeometryItem'; +import { Matrix4x4 } from './Matrix4x4'; +import { Node3D } from './Node3D'; +import { Vector3D } from './Vector3D'; + +export class GeometryBodyPart extends Node3D +{ + private _id: string; + private _radius: number; + private _parts: AdvancedMap; + private _dynamicParts: AdvancedMap; + + constructor(k: any) + { + super(parseFloat(k.x), parseFloat(k.y), parseFloat(k.z)); + + this._id = k.id; + this._radius = parseFloat(k.radius); + this._parts = new AdvancedMap(); + this._dynamicParts = new AdvancedMap(); + + if(k.items && (k.items.length > 0)) + { + for(const item of k.items) + { + if(!item) continue; + + const geometryItem = new GeometryItem(item); + + this._parts.add(geometryItem.id, geometryItem); + } + } + } + + public getDynamicParts(k: IAvatarImage): GeometryItem[] + { + const existing = this._dynamicParts.getValue(k); + const parts: GeometryItem[] = []; + + if(existing) + { + for(const index in existing) + { + const item = existing[index]; + + if(!item) continue; + + parts.push(item); + } + } + + return parts; + } + + public getPartIds(k: IAvatarImage): string[] + { + const ids: string[] = []; + + for(const part of this._parts.getValues()) + { + if(!part) continue; + + ids.push(part.id); + } + + if(k) + { + const existing = this._dynamicParts.getValue(k); + + if(existing) + { + for(const index in existing) + { + const part = existing[index]; + + if(!part) continue; + + ids.push(part.id); + } + } + } + + return ids; + } + + public removeDynamicParts(k: IAvatarImage): boolean + { + this._dynamicParts.remove(k); + + return true; + } + + public addPart(k: any, _arg_2: IAvatarImage): boolean + { + if(this.hasPart(k.id, _arg_2)) return false; + + let existing = this._dynamicParts.getValue(_arg_2); + + if(!existing) + { + existing = {}; + + this._dynamicParts.add(_arg_2, existing); + } + + existing[k.id] = new GeometryItem(k, true); + + return true; + } + + public hasPart(k: string, _arg_2: IAvatarImage): boolean + { + let existingPart = (this._parts.getValue(k) || null); + + if(!existingPart && (this._dynamicParts.getValue(_arg_2) !== undefined)) + { + existingPart = (this._dynamicParts.getValue(_arg_2)[k] || null); + } + + return (existingPart !== null); + } + + public getParts(k: Matrix4x4, _arg_2: Vector3D, _arg_3: any[], _arg_4: IAvatarImage): string[] + { + const parts: [ number, GeometryItem ][] = []; + + for(const part of this._parts.getValues()) + { + if(!part) continue; + + part.applyTransform(k); + + parts.push([ part.getDistance(_arg_2), part ]); + } + + const existingDynamic = this._dynamicParts.getValue(_arg_4); + + if(existingDynamic) + { + for(const index in existingDynamic) + { + const part = existingDynamic[index]; + + if(!part) continue; + + part.applyTransform(k); + + parts.push([ part.getDistance(_arg_2), part ]); + } + } + + parts.sort((a, b) => + { + const partA = a[0]; + const partB = b[0]; + + if(partA < partB) return -1; + + if(partA > partB) return 1; + + return 0; + }); + + const partIds: string[] = []; + + for(const part of parts) + { + if(!part) continue; + + partIds.push(part[1].id); + } + + return partIds; + } + + public getDistance(k: Vector3D): number + { + const _local_2 = Math.abs(((k.z - this.transformedLocation.z) - this._radius)); + const _local_3 = Math.abs(((k.z - this.transformedLocation.z) + this._radius)); + + return Math.min(_local_2, _local_3); + } + + public get id(): string + { + return this._id; + } + + public get radius(): number + { + return this._radius; + } +} diff --git a/src/app/avatar/geometry/GeometryItem.ts b/src/app/avatar/geometry/GeometryItem.ts new file mode 100644 index 0000000..189a406 --- /dev/null +++ b/src/app/avatar/geometry/GeometryItem.ts @@ -0,0 +1,55 @@ +import { Node3D } from './Node3D'; +import { Vector3D } from './Vector3D'; + +export class GeometryItem extends Node3D +{ + private _id: string; + private _radius: number; + private _normal: Vector3D; + private _isDoubleSided: boolean; + private _isDynamic: boolean; + + constructor(k: any, _arg_2: boolean = false) + { + super(parseFloat(k.x), parseFloat(k.y), parseFloat(k.z)); + + this._id = k.id; + this._radius = parseFloat(k.radius); + this._normal = new Vector3D(parseFloat(k.nx), parseFloat(k.ny), parseFloat(k.nz)); + this._isDoubleSided = k.double || false; + this._isDynamic = _arg_2; + } + + public getDistance(k: Vector3D): number + { + const _local_2 = Math.abs(((k.z - this.transformedLocation.z) - this._radius)); + const _local_3 = Math.abs(((k.z - this.transformedLocation.z) + this._radius)); + + return Math.min(_local_2, _local_3); + } + + public get id(): string + { + return this._id; + } + + public get normal(): Vector3D + { + return this._normal; + } + + public get isDoubleSided(): boolean + { + return this._isDoubleSided; + } + + public toString(): string + { + return ((((this._id + ': ') + this.location) + ' - ') + this.transformedLocation); + } + + public get isDynamic(): boolean + { + return this._isDynamic; + } +} diff --git a/src/app/avatar/geometry/Matrix4x4.ts b/src/app/avatar/geometry/Matrix4x4.ts new file mode 100644 index 0000000..d0914a2 --- /dev/null +++ b/src/app/avatar/geometry/Matrix4x4.ts @@ -0,0 +1,133 @@ +import { Vector3D } from './Vector3D'; + +export class Matrix4x4 +{ + public static IDENTITY:Matrix4x4 = new Matrix4x4(1, 0, 0, 0, 1, 0, 0, 0, 1); + private static TOLERANS: number = 1E-18; + + private _data: number[]; + + constructor(k: number = 0, _arg_2: number = 0, _arg_3: number = 0, _arg_4: number = 0, _arg_5: number = 0, _arg_6: number = 0, _arg_7: number = 0, _arg_8: number = 0, _arg_9: number = 0) + { + this._data = [k, _arg_2, _arg_3, _arg_4, _arg_5, _arg_6, _arg_7, _arg_8, _arg_9]; + } + + public static getXRotationMatrix(k: number): Matrix4x4 + { + const _local_2 = ((k * Math.PI) / 180); + const _local_3 = Math.cos(_local_2); + const _local_4 = Math.sin(_local_2); + + return new Matrix4x4(1, 0, 0, 0, _local_3, -(_local_4), 0, _local_4, _local_3); + } + + public static getYRotationMatrix(k: number): Matrix4x4 + { + const _local_2 = ((k * Math.PI) / 180); + const _local_3 = Math.cos(_local_2); + const _local_4 = Math.sin(_local_2); + + return new Matrix4x4(_local_3, 0, _local_4, 0, 1, 0, -(_local_4), 0, _local_3); + } + + public static getZRotationMatrix(k: number): Matrix4x4 + { + const _local_2 = ((k * Math.PI) / 180); + const _local_3 = Math.cos(_local_2); + const _local_4 = Math.sin(_local_2); + + return new Matrix4x4(_local_3, -(_local_4), 0, _local_4, _local_3, 0, 0, 0, 1); + } + + public identity(): Matrix4x4 + { + this._data = [1, 0, 0, 0, 1, 0, 0, 0, 1]; + + return this; + } + + public vectorMultiplication(k: Vector3D): Vector3D + { + const _local_2 = (((k.x * this._data[0]) + (k.y * this._data[3])) + (k.z * this._data[6])); + const _local_3 = (((k.x * this._data[1]) + (k.y * this._data[4])) + (k.z * this._data[7])); + const _local_4 = (((k.x * this._data[2]) + (k.y * this._data[5])) + (k.z * this._data[8])); + + return new Vector3D(_local_2, _local_3, _local_4); + } + + public multiply(k:Matrix4x4): Matrix4x4 + { + const _local_2 = (((this._data[0] * k.data[0]) + (this._data[1] * k.data[3])) + (this._data[2] * k.data[6])); + const _local_3 = (((this._data[0] * k.data[1]) + (this._data[1] * k.data[4])) + (this._data[2] * k.data[7])); + const _local_4 = (((this._data[0] * k.data[2]) + (this._data[1] * k.data[5])) + (this._data[2] * k.data[8])); + const _local_5 = (((this._data[3] * k.data[0]) + (this._data[4] * k.data[3])) + (this._data[5] * k.data[6])); + const _local_6 = (((this._data[3] * k.data[1]) + (this._data[4] * k.data[4])) + (this._data[5] * k.data[7])); + const _local_7 = (((this._data[3] * k.data[2]) + (this._data[4] * k.data[5])) + (this._data[5] * k.data[8])); + const _local_8 = (((this._data[6] * k.data[0]) + (this._data[7] * k.data[3])) + (this._data[8] * k.data[6])); + const _local_9 = (((this._data[6] * k.data[1]) + (this._data[7] * k.data[4])) + (this._data[8] * k.data[7])); + const _local_10 = (((this._data[6] * k.data[2]) + (this._data[7] * k.data[5])) + (this._data[8] * k.data[8])); + + return new Matrix4x4(_local_2, _local_3, _local_4, _local_5, _local_6, _local_7, _local_8, _local_9, _local_10); + } + + public scalarMultiply(k: number): void + { + let index = 0; + + while(index < this._data.length) + { + this._data[index] = (this._data[index] * k); + + index++; + } + } + + public rotateX(k: number): Matrix4x4 + { + const _local_2 = ((k * Math.PI) / 180); + const _local_3 = Math.cos(_local_2); + const _local_4 = Math.sin(_local_2); + const _local_5 = new Matrix4x4(1, 0, 0, 0, _local_3, -(_local_4), 0, _local_4, _local_3); + + return _local_5.multiply(this); + } + + public rotateY(k: number): Matrix4x4 + { + const _local_2 = ((k * Math.PI) / 180); + const _local_3 = Math.cos(_local_2); + const _local_4 = Math.sin(_local_2); + const _local_5 = new Matrix4x4(_local_3, 0, _local_4, 0, 1, 0, -(_local_4), 0, _local_3); + + return _local_5.multiply(this); + } + + public rotateZ(k: number): Matrix4x4 + { + const _local_2 = ((k * Math.PI) / 180); + const _local_3 = Math.cos(_local_2); + const _local_4 = Math.sin(_local_2); + const _local_5 = new Matrix4x4(_local_3, -(_local_4), 0, _local_4, _local_3, 0, 0, 0, 1); + + return _local_5.multiply(this); + } + + public skew(): void + { + } + + public transpose(): Matrix4x4 + { + return new Matrix4x4(this._data[0], this._data[3], this._data[6], this._data[1], this._data[4], this._data[7], this._data[2], this._data[5], this._data[8]); + } + + public equals(k: Matrix4x4): boolean + { + return false; + } + + public get data(): number[] + { + return this._data; + } +} diff --git a/src/app/avatar/geometry/Node3D.ts b/src/app/avatar/geometry/Node3D.ts new file mode 100644 index 0000000..7cbcf49 --- /dev/null +++ b/src/app/avatar/geometry/Node3D.ts @@ -0,0 +1,33 @@ +import { Matrix4x4 } from './Matrix4x4'; +import { Vector3D } from './Vector3D'; + +export class Node3D +{ + private _location: Vector3D; + private _transformedLocation: Vector3D; + private _needsTransformation: boolean; + + constructor(k: number, _arg_2: number, _arg_3: number) + { + this._location = new Vector3D(k, _arg_2, _arg_3); + this._transformedLocation = new Vector3D(); + this._needsTransformation = false; + + if(((!(k == 0)) || (!(_arg_2 == 0))) || (!(_arg_3 == 0))) this._needsTransformation = true; + } + + public get location(): Vector3D + { + return this._location; + } + + public get transformedLocation(): Vector3D + { + return this._transformedLocation; + } + + public applyTransform(k: Matrix4x4): void + { + if(this._needsTransformation) this._transformedLocation = k.vectorMultiplication(this._location); + } +} diff --git a/src/app/avatar/geometry/Vector3D.ts b/src/app/avatar/geometry/Vector3D.ts new file mode 100644 index 0000000..4afba81 --- /dev/null +++ b/src/app/avatar/geometry/Vector3D.ts @@ -0,0 +1,120 @@ +export class Vector3D +{ + private _x: number; + private _y: number; + private _z: number; + + constructor(k: number = 0, _arg_2: number = 0, _arg_3: number = 0) + { + this._x = k; + this._y = _arg_2; + this._z = _arg_3; + } + + public static dot(k: Vector3D, _arg_2: Vector3D): number + { + return ((k.x * _arg_2.x) + (k.y * _arg_2.y)) + (k.z * _arg_2.z); + } + + public static cross(k: Vector3D, _arg_2: Vector3D): Vector3D + { + const _local_3 = new Vector3D(); + + _local_3.x = ((k.y * _arg_2.z) - (k.z * _arg_2.y)); + _local_3.y = ((k.z * _arg_2.x) - (k.x * _arg_2.z)); + _local_3.z = ((k.x * _arg_2.y) - (k.y * _arg_2.x)); + + return _local_3; + } + + public static subtract(k: Vector3D, _arg_2: Vector3D): Vector3D + { + return new Vector3D((k.x - _arg_2.x), (k.y - _arg_2.y), (k.z - _arg_2.z)); + } + + public dot(k: Vector3D): number + { + return ((this._x * k.x) + (this._y * k.y)) + (this._z * k.z); + } + + public cross(k: Vector3D): Vector3D + { + const _local_2 = new Vector3D(); + + _local_2.x = ((this._y * k.z) - (this._z * k.y)); + _local_2.y = ((this._z * k.x) - (this._x * k.z)); + _local_2.z = ((this._x * k.y) - (this._y * k.x)); + + return _local_2; + } + + public subtract(k: Vector3D): void + { + this._x = (this._x - k.x); + this._y = (this._y - k.y); + this._z = (this._z - k.z); + } + + public add(k: Vector3D): void + { + this._x = (this._x + k.x); + this._y = (this._y + k.y); + this._z = (this._z + k.z); + } + + public normalize(): void + { + const k = (1 / this.length()); + + this._x = (this._x * k); + this._y = (this._y * k); + this._z = (this._z * k); + } + + public scaleBy(value: number): void + { + this._x *= value; + this._y *= value; + this._z *= value; + } + + public length(): number + { + return Math.sqrt((((this._x * this._x) + (this._y * this._y)) + (this._z * this._z))); + } + + public toString(): string + { + return (((((('Vector3D: (' + this._x) + ',') + this._y) + ',') + this._z) + ')'); + } + + public get x(): number + { + return this._x; + } + + public set x(k: number) + { + this._x = k; + } + + public get y(): number + { + return this._y; + } + + public set y(k: number) + { + this._y = k; + } + + public get z(): number + { + return this._z; + } + + public set z(k: number) + { + this._z = k; + } +} diff --git a/src/app/avatar/geometry/index.ts b/src/app/avatar/geometry/index.ts new file mode 100644 index 0000000..4e0b66d --- /dev/null +++ b/src/app/avatar/geometry/index.ts @@ -0,0 +1,7 @@ +export * from './AvatarModelGeometry'; +export * from './AvatarSet'; +export * from './GeometryBodyPart'; +export * from './GeometryItem'; +export * from './Matrix4x4'; +export * from './Node3D'; +export * from './Vector3D'; diff --git a/src/app/avatar/index.ts b/src/app/avatar/index.ts new file mode 100644 index 0000000..8894c69 --- /dev/null +++ b/src/app/avatar/index.ts @@ -0,0 +1,24 @@ +export * from './actions'; +export * from './alias'; +export * from './animation'; +export * from './AvatarAssetDownloadLibrary'; +export * from './AvatarAssetDownloadManager'; +export * from './AvatarFigureContainer'; +export * from './AvatarImage'; +export * from './AvatarImageBodyPartContainer'; +export * from './AvatarImagePartContainer'; +export * from './AvatarRenderManager'; +export * from './AvatarStructure'; +export * from './cache'; +export * from './data'; +export * from './EffectAssetDownloadLibrary'; +export * from './EffectAssetDownloadManager'; +export * from './enum'; +export * from './FigureDataContainer'; +export * from './geometry'; +export * from './IAvatarFigureContainer'; +export * from './IAvatarImage'; +export * from './IAvatarRenderManager'; +export * from './interfaces'; +export * from './PlaceHolderAvatarImage'; +export * from './structure'; diff --git a/src/app/avatar/interfaces/figuredata/IFigureData.ts b/src/app/avatar/interfaces/figuredata/IFigureData.ts new file mode 100644 index 0000000..86e7901 --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureData.ts @@ -0,0 +1,8 @@ +import { IFigureDataPalette } from './IFigureDataPalette'; +import { IFigureDataSetType } from './IFigureDataSetType'; + +export interface IFigureData +{ + palettes?: IFigureDataPalette[]; + setTypes?: IFigureDataSetType[]; +} diff --git a/src/app/avatar/interfaces/figuredata/IFigureDataColor.ts b/src/app/avatar/interfaces/figuredata/IFigureDataColor.ts new file mode 100644 index 0000000..535dead --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureDataColor.ts @@ -0,0 +1,8 @@ +export interface IFigureDataColor +{ + id?: number; + index?: number; + club?: number; + selectable?: boolean; + hexCode?: string; +} diff --git a/src/app/avatar/interfaces/figuredata/IFigureDataHiddenLayer.ts b/src/app/avatar/interfaces/figuredata/IFigureDataHiddenLayer.ts new file mode 100644 index 0000000..80f42e6 --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureDataHiddenLayer.ts @@ -0,0 +1,4 @@ +export interface IFigureDataHiddenLayer +{ + partType?: string; +} diff --git a/src/app/avatar/interfaces/figuredata/IFigureDataPalette.ts b/src/app/avatar/interfaces/figuredata/IFigureDataPalette.ts new file mode 100644 index 0000000..f83fa06 --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureDataPalette.ts @@ -0,0 +1,7 @@ +import { IFigureDataColor } from './IFigureDataColor'; + +export interface IFigureDataPalette +{ + id?: number; + colors?: IFigureDataColor[]; +} diff --git a/src/app/avatar/interfaces/figuredata/IFigureDataPart.ts b/src/app/avatar/interfaces/figuredata/IFigureDataPart.ts new file mode 100644 index 0000000..e57ef47 --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureDataPart.ts @@ -0,0 +1,8 @@ +export interface IFigureDataPart +{ + id?: number; + type?: string; + colorable?: boolean; + index?: number; + colorindex?: number; +} diff --git a/src/app/avatar/interfaces/figuredata/IFigureDataSet.ts b/src/app/avatar/interfaces/figuredata/IFigureDataSet.ts new file mode 100644 index 0000000..f3c89d9 --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureDataSet.ts @@ -0,0 +1,15 @@ +import { IFigureDataHiddenLayer } from './IFigureDataHiddenLayer'; +import { IFigureDataPart } from './IFigureDataPart'; + +export interface IFigureDataSet +{ + id?: number; + gender?: string; + club?: number; + colorable?: boolean; + selectable?: boolean; + preselectable?: boolean; + sellable?: boolean; + parts?: IFigureDataPart[]; + hiddenLayers?: IFigureDataHiddenLayer[]; +} diff --git a/src/app/avatar/interfaces/figuredata/IFigureDataSetType.ts b/src/app/avatar/interfaces/figuredata/IFigureDataSetType.ts new file mode 100644 index 0000000..d9a2d97 --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/IFigureDataSetType.ts @@ -0,0 +1,12 @@ +import { IFigureDataSet } from './IFigureDataSet'; + +export interface IFigureDataSetType +{ + type?: string; + paletteId?: number; + mandatory_m_0?: boolean; + mandatory_f_0?: boolean; + mandatory_m_1?: boolean; + mandatory_f_1?: boolean; + sets?: IFigureDataSet[]; +} diff --git a/src/app/avatar/interfaces/figuredata/index.ts b/src/app/avatar/interfaces/figuredata/index.ts new file mode 100644 index 0000000..579987b --- /dev/null +++ b/src/app/avatar/interfaces/figuredata/index.ts @@ -0,0 +1,7 @@ +export * from './IFigureData'; +export * from './IFigureDataColor'; +export * from './IFigureDataHiddenLayer'; +export * from './IFigureDataPalette'; +export * from './IFigureDataPart'; +export * from './IFigureDataSet'; +export * from './IFigureDataSetType'; diff --git a/src/app/avatar/interfaces/index.ts b/src/app/avatar/interfaces/index.ts new file mode 100644 index 0000000..c44ce3e --- /dev/null +++ b/src/app/avatar/interfaces/index.ts @@ -0,0 +1 @@ +export * from './figuredata'; diff --git a/src/app/avatar/structure/AvatarAnimationData.ts b/src/app/avatar/structure/AvatarAnimationData.ts new file mode 100644 index 0000000..f33ee74 --- /dev/null +++ b/src/app/avatar/structure/AvatarAnimationData.ts @@ -0,0 +1,59 @@ +import { AdvancedMap } from '../../../core'; +import { IActionDefinition } from '../actions'; +import { AnimationAction } from './animation'; +import { IFigureSetData } from './IFigureSetData'; + +export class AvatarAnimationData implements IFigureSetData +{ + private _actions: AdvancedMap; + + constructor() + { + this._actions = new AdvancedMap(); + } + + public parse(data: any): boolean + { + if(data && (data.length > 0)) + { + for(const animation of data) + { + if(!animation) continue; + + const newAnimation = new AnimationAction(animation); + + this._actions.add(newAnimation.id, newAnimation); + } + } + + return true; + } + + public appendJSON(k: any): boolean + { + for(const _local_2 of k.action) + { + this._actions.add(_local_2.id, new AnimationAction(_local_2)); + } + + return true; + } + + public getAction(action: IActionDefinition): AnimationAction + { + const existing = this._actions.getValue(action.id); + + if(!existing) return null; + + return existing; + } + + public getFrameCount(k: IActionDefinition): number + { + const animationAction = this.getAction(k); + + if(!animationAction) return 0; + + return animationAction.frameCount; + } +} diff --git a/src/app/avatar/structure/AvatarCanvas.ts b/src/app/avatar/structure/AvatarCanvas.ts new file mode 100644 index 0000000..75e1688 --- /dev/null +++ b/src/app/avatar/structure/AvatarCanvas.ts @@ -0,0 +1,47 @@ +import { Point } from '../../../core'; +import { AvatarScaleType } from '../enum'; + +export class AvatarCanvas +{ + private _id: string; + private _width: number; + private _height: number; + private _offset: Point; + private _regPoint: Point; + + constructor(k: any, _arg_2: string) + { + this._id = k.id; + this._width = k.width; + this._height = k.height; + this._offset = new Point(k.dx, k.dy); + + if(_arg_2 == AvatarScaleType.LARGE) this._regPoint = new Point(((this._width - 64) / 2), 0); + else this._regPoint = new Point(((this._width - 32) / 2), 0); + } + + public get width(): number + { + return this._width; + } + + public get height(): number + { + return this._height; + } + + public get offset(): Point + { + return this._offset; + } + + public get id(): string + { + return this._id; + } + + public get regPoint(): Point + { + return this._regPoint; + } +} diff --git a/src/app/avatar/structure/FigureSetData.ts b/src/app/avatar/structure/FigureSetData.ts new file mode 100644 index 0000000..7f4c183 --- /dev/null +++ b/src/app/avatar/structure/FigureSetData.ts @@ -0,0 +1,132 @@ +import { AdvancedMap } from '../../../core'; +import { IFigureData } from '../interfaces'; +import { IFigurePartSet, IPalette, ISetType, Palette, SetType } from './figure'; +import { IFigureSetData } from './IFigureSetData'; +import { IStructureData } from './IStructureData'; + +export class FigureSetData implements IFigureSetData, IStructureData +{ + private _palettes: AdvancedMap; + private _setTypes: AdvancedMap; + + constructor() + { + this._palettes = new AdvancedMap(); + this._setTypes = new AdvancedMap(); + } + + public dispose(): void + { + + } + + public parse(data: IFigureData): boolean + { + if(!data) return false; + + for(const palette of data.palettes) + { + const newPalette = new Palette(palette); + + if(!newPalette) continue; + + this._palettes.add(newPalette.id.toString(), newPalette); + } + + for(const set of data.setTypes) + { + const newSet = new SetType(set); + + if(!newSet) continue; + + this._setTypes.add(newSet.type, newSet); + } + + return true; + } + + public injectJSON(data: IFigureData): void + { + for(const setType of data.setTypes) + { + const existingSetType = this._setTypes.getValue(setType.type); + + if(existingSetType) existingSetType.cleanUp(setType); + else this._setTypes.add(setType.type, new SetType(setType)); + } + + this.appendJSON(data); + } + + public appendJSON(data: IFigureData): boolean + { + if(!data) return false; + + for(const palette of data.palettes) + { + const id = palette.id.toString(); + const existingPalette = this._palettes.getValue(id); + + if(!existingPalette) this._palettes.add(id, new Palette(palette)); + else existingPalette.append(palette); + } + + for(const setType of data.setTypes) + { + const type = setType.type; + const existingSetType = this._setTypes.getValue(type); + + if(!existingSetType) this._setTypes.add(type, new SetType(setType)); + else existingSetType.append(setType); + } + + return false; + } + + public getMandatorySetTypeIds(k: string, _arg_2: number): string[] + { + const types: string[] = []; + + for(const set of this._setTypes.getValues()) + { + if(!set || !set.isMandatory(k, _arg_2)) continue; + + types.push(set.type); + } + + return types; + } + + public getDefaultPartSet(k: string, _arg_2: string): IFigurePartSet + { + const setType = this._setTypes.getValue(k); + + if(!setType) return null; + + return setType.getDefaultPartSet(_arg_2); + } + + public getSetType(k: string): ISetType + { + return (this._setTypes.getValue(k) || null); + } + + public getPalette(k: number): IPalette + { + return (this._palettes.getValue(k.toString()) || null); + } + + public getFigurePartSet(k: number): IFigurePartSet + { + for(const set of this._setTypes.getValues()) + { + const partSet = set.getPartSet(k); + + if(!partSet) continue; + + return partSet; + } + + return null; + } +} diff --git a/src/app/avatar/structure/IFigureSetData.ts b/src/app/avatar/structure/IFigureSetData.ts new file mode 100644 index 0000000..fb747e1 --- /dev/null +++ b/src/app/avatar/structure/IFigureSetData.ts @@ -0,0 +1,7 @@ +import { IFigureData } from '../interfaces'; + +export interface IFigureSetData +{ + parse(data: any): boolean; + appendJSON(data: IFigureData): boolean; +} diff --git a/src/app/avatar/structure/IStructureData.ts b/src/app/avatar/structure/IStructureData.ts new file mode 100644 index 0000000..5a700c4 --- /dev/null +++ b/src/app/avatar/structure/IStructureData.ts @@ -0,0 +1,11 @@ +import { IFigureData } from '../interfaces'; +import { IFigurePartSet, IPalette, ISetType } from './figure'; + +export interface IStructureData +{ + parse(data: any): boolean; + appendJSON(k: IFigureData): boolean; + getSetType(_arg_1: string): ISetType; + getPalette(_arg_1: number): IPalette; + getFigurePartSet(_arg_1: number): IFigurePartSet; +} diff --git a/src/app/avatar/structure/PartSetsData.ts b/src/app/avatar/structure/PartSetsData.ts new file mode 100644 index 0000000..f9f7698 --- /dev/null +++ b/src/app/avatar/structure/PartSetsData.ts @@ -0,0 +1,119 @@ +import { AdvancedMap } from '../../../core'; +import { ActionDefinition, IActionDefinition } from '../actions'; +import { IFigureSetData } from './IFigureSetData'; +import { ActivePartSet, PartDefinition } from './parts'; + +export class PartSetsData implements IFigureSetData +{ + private _parts: AdvancedMap; + private _activePartSets: AdvancedMap; + + constructor() + { + this._parts = new AdvancedMap(); + this._activePartSets = new AdvancedMap(); + } + + public parse(data: any): boolean + { + if(data.partSet && (data.partSet.length > 0)) + { + for(const part of data.partSet) + { + if(!part) continue; + + this._parts.add(part.setType, new PartDefinition(part)); + } + } + + if(data.activePartSets && (data.activePartSets.length > 0)) + { + for(const activePart of data.activePartSets) + { + if(!activePart) continue; + + this._activePartSets.add(activePart.id, new ActivePartSet(activePart)); + } + } + + return true; + } + + public appendJSON(data: any): boolean + { + if(data.partSet && (data.partSet.length > 0)) + { + for(const part of data.partSet) + { + if(!part) continue; + + this._parts.add(part.setType, new PartDefinition(part)); + } + } + + if(data.activePartSets && (data.activePartSets.length > 0)) + { + for(const activePart of data.activePartSets) + { + if(!activePart) continue; + + this._activePartSets.add(activePart.id, new ActivePartSet(activePart)); + } + } + + return false; + } + + public getActiveParts(k:IActionDefinition): string[] + { + const activePartSet = this._activePartSets.getValue(k.activePartSet); + + if(!activePartSet) return []; + + return activePartSet.parts; + } + + public getPartDefinition(part: string): PartDefinition + { + const existing = this._parts.getValue(part); + + if(!existing) return null; + + return existing; + } + + public addPartDefinition(k: any): PartDefinition + { + const _local_2 = k.setType as string; + + let existing = this._parts.getValue(_local_2); + + if(!existing) + { + existing = new PartDefinition(k); + + this._parts.add(_local_2, existing); + } + + return existing; + } + + public getActivePartSet(k: ActionDefinition): ActivePartSet + { + const existing = this._activePartSets.getValue(k.activePartSet); + + if(!existing) return null; + + return existing; + } + + public get parts(): AdvancedMap + { + return this._parts; + } + + public get activePartSets(): AdvancedMap + { + return this._activePartSets; + } +} diff --git a/src/app/avatar/structure/animation/AnimationAction.ts b/src/app/avatar/structure/animation/AnimationAction.ts new file mode 100644 index 0000000..631aae7 --- /dev/null +++ b/src/app/avatar/structure/animation/AnimationAction.ts @@ -0,0 +1,138 @@ +import { AdvancedMap, Point } from '../../../../core'; +import { AnimationActionPart } from './AnimationActionPart'; + +export class AnimationAction +{ + public static DEFAULT_OFFSET: Point = new Point(0, 0); + + private _id: string; + private _actionParts: AdvancedMap; + private _bodyPartOffsets: AdvancedMap>>; + private _frameCount: number; + private _frameIndexes: number[]; + + constructor(data: any) + { + this._id = data.id; + this._actionParts = new AdvancedMap(); + this._bodyPartOffsets = new AdvancedMap(); + this._frameCount = 0; + this._frameIndexes = []; + + if(data.parts && (data.parts.length > 0)) + { + for(const part of data.parts) + { + if(!part) continue; + + const newPart = new AnimationActionPart(part); + + this._actionParts.add(part.setType, newPart); + + this._frameCount = Math.max(this._frameCount, newPart.frames.length); + } + } + + if(data.offsets && data.offsets.frames && (data.offsets.frames.length > 0)) + { + for(const frame of data.offsets.frames) + { + if(!frame) continue; + + const frameId = frame.id; + + this._frameCount = Math.max(this._frameCount, frameId); + + const directions: AdvancedMap> = new AdvancedMap(); + + this._bodyPartOffsets.add(frameId, directions); + + if(frame.directions && (frame.directions.length > 0)) + { + for(const direction of frame.directions) + { + if(!direction) continue; + + const directionId = direction.id; + + const offsets: AdvancedMap = new AdvancedMap(); + + directions.add(directionId, offsets); + + if(direction.bodyParts && (direction.bodyParts.length > 0)) + { + for(const part of direction.bodyParts) + { + if(!part) continue; + + const partId = part.id; + + let dx = 0; + let dy = 0; + + if(part.dx !== undefined) dx = part.dx; + if(part.dy !== undefined) dy = part.dy; + + offsets.add(partId, new Point(dx, dy)); + } + } + } + } + + this._frameIndexes.push(frameId); + + if(frame.repeats !== undefined) + { + let repeats = frame.repeats || 0; + + if(repeats > 1) while(--repeats > 0) this._frameIndexes.push(frameId); + } + } + } + } + + public getPart(type: string): AnimationActionPart + { + if(!type) return null; + + const existing = this._actionParts.getValue(type); + + if(!existing) return null; + + return existing; + } + + public getFrameBodyPartOffset(frameId: number, frameCount: number, partId: string): Point + { + const frameIndex = (frameCount % this._frameIndexes.length); + const frameNumber = this._frameIndexes[frameIndex]; + const offsets = this._bodyPartOffsets.getValue(frameNumber); + + if(!offsets) return AnimationAction.DEFAULT_OFFSET; + + const frameOffset = offsets.getValue(frameId); + + if(!frameOffset) return AnimationAction.DEFAULT_OFFSET; + + const offset = frameOffset.getValue(partId); + + if(!offset) return AnimationAction.DEFAULT_OFFSET; + + return offset; + } + + public get id(): string + { + return this._id; + } + + public get parts(): AdvancedMap + { + return this._actionParts; + } + + public get frameCount(): number + { + return this._frameCount; + } +} diff --git a/src/app/avatar/structure/animation/AnimationActionPart.ts b/src/app/avatar/structure/animation/AnimationActionPart.ts new file mode 100644 index 0000000..ea16687 --- /dev/null +++ b/src/app/avatar/structure/animation/AnimationActionPart.ts @@ -0,0 +1,30 @@ +import { AvatarAnimationFrame } from './AvatarAnimationFrame'; + +export class AnimationActionPart +{ + private _frames: AvatarAnimationFrame[]; + + constructor(data: any) + { + this._frames = []; + + if(data.frames && (data.frames.length > 0)) + { + for(const frame of data.frames) + { + if(!frame) continue; + + this._frames.push(new AvatarAnimationFrame(frame)); + + let repeats = frame.repeats || 0; + + if(repeats > 1) while(--repeats > 0) this._frames.push(this._frames[(this._frames.length - 1)]); + } + } + } + + public get frames(): AvatarAnimationFrame[] + { + return this._frames; + } +} diff --git a/src/app/avatar/structure/animation/AvatarAnimationFrame.ts b/src/app/avatar/structure/animation/AvatarAnimationFrame.ts new file mode 100644 index 0000000..3b9ec35 --- /dev/null +++ b/src/app/avatar/structure/animation/AvatarAnimationFrame.ts @@ -0,0 +1,21 @@ +export class AvatarAnimationFrame +{ + private _number: number; + private _assetPartDefinition: string; + + constructor(data: any) + { + this._number = data.number; + this._assetPartDefinition = data.assetPartDefinition || null; + } + + public get number(): number + { + return this._number; + } + + public get assetPartDefinition(): string + { + return this._assetPartDefinition; + } +} diff --git a/src/app/avatar/structure/animation/index.ts b/src/app/avatar/structure/animation/index.ts new file mode 100644 index 0000000..98af842 --- /dev/null +++ b/src/app/avatar/structure/animation/index.ts @@ -0,0 +1,3 @@ +export * from './AnimationAction'; +export * from './AnimationActionPart'; +export * from './AvatarAnimationFrame'; diff --git a/src/app/avatar/structure/figure/FigurePart.ts b/src/app/avatar/structure/figure/FigurePart.ts new file mode 100644 index 0000000..afc2258 --- /dev/null +++ b/src/app/avatar/structure/figure/FigurePart.ts @@ -0,0 +1,59 @@ +import { IFigureDataPart } from '../../interfaces'; +import { IFigurePart } from './IFigurePart'; + +export class FigurePart implements IFigurePart +{ + private _id: number; + private _type: string; + private _breed: number; + private _index: number; + private _colorLayerIndex: number; + private _paletteMapId: number; + + constructor(data: IFigureDataPart) + { + if(!data) throw new Error('invalid_data'); + + this._id = data.id; + this._type = data.type; + this._index = data.index; + this._colorLayerIndex = data.colorindex; + this._paletteMapId = -1; + this._breed = -1; + } + + public dispose(): void + { + + } + + public get id(): number + { + return this._id; + } + + public get type(): string + { + return this._type; + } + + public get breed(): number + { + return this._breed; + } + + public get index(): number + { + return this._index; + } + + public get colorLayerIndex(): number + { + return this._colorLayerIndex; + } + + public get paletteMap(): number + { + return this._paletteMapId; + } +} diff --git a/src/app/avatar/structure/figure/FigurePartSet.ts b/src/app/avatar/structure/figure/FigurePartSet.ts new file mode 100644 index 0000000..9bc5a7e --- /dev/null +++ b/src/app/avatar/structure/figure/FigurePartSet.ts @@ -0,0 +1,143 @@ +import { IFigureDataSet } from '../../interfaces'; +import { FigurePart } from './FigurePart'; +import { IFigurePart } from './IFigurePart'; +import { IFigurePartSet } from './IFigurePartSet'; + +export class FigurePartSet implements IFigurePartSet +{ + private _id: number; + private _type: string; + private _gender: string; + private _clubLevel: number; + private _isColorable: boolean; + private _isSelectable: boolean; + private _parts: IFigurePart[]; + private _hiddenLayers: string[]; + private _isPreSelectable: boolean; + private _isSellable: boolean; + + constructor(type: string, data: IFigureDataSet) + { + if(!type || !data) throw new Error('invalid_data'); + + this._id = data.id; + this._type = type; + this._gender = data.gender; + this._clubLevel = data.club; + this._isColorable = data.colorable; + this._isSelectable = data.selectable; + this._parts = []; + this._hiddenLayers = []; + this._isPreSelectable = data.preselectable; + this._isSellable = data.sellable; + + for(const part of data.parts) + { + const newPart = new FigurePart(part); + const partIndex = this.getPartIndex(newPart); + + if(partIndex !== -1) this._parts.splice(partIndex, 0, newPart); + else this._parts.push(newPart); + } + + if(data.hiddenLayers) + { + for(const hiddenLayer of data.hiddenLayers) this._hiddenLayers.push(hiddenLayer.partType); + } + } + + public dispose(): void + { + for(const part of this._parts) + { + const figurePart = (part as FigurePart); + + figurePart.dispose(); + } + + this._parts = null; + this._hiddenLayers = null; + } + + private getPartIndex(part: FigurePart): number + { + const totalParts = this._parts.length; + + if(!totalParts) return -1; + + for(let i = 0; i < totalParts; i++) + { + const existingPart = this._parts[i]; + + if(!existingPart) continue; + + if(existingPart.type !== part.type || existingPart.index > part.index) continue; + + return i; + } + + return -1; + } + + public getPart(k: string, _arg_2: number): IFigurePart + { + for(const part of this._parts) + { + if((part.type !== k) || (part.id !== _arg_2)) continue; + + return part; + } + + return null; + } + + public get id(): number + { + return this._id; + } + + public get type(): string + { + return this._type; + } + + public get gender(): string + { + return this._gender; + } + + public get clubLevel(): number + { + return this._clubLevel; + } + + public get isColorable(): boolean + { + return this._isColorable; + } + + public get isSelectable(): boolean + { + return this._isSelectable; + } + + public get parts(): IFigurePart[] + { + return this._parts; + } + + public get hiddenLayers(): string[] + { + return this._hiddenLayers; + } + + public get isPreSelectable(): boolean + { + return this._isPreSelectable; + } + + public get isSellable(): boolean + { + return this._isSellable; + } +} diff --git a/src/app/avatar/structure/figure/IFigurePart.ts b/src/app/avatar/structure/figure/IFigurePart.ts new file mode 100644 index 0000000..578725b --- /dev/null +++ b/src/app/avatar/structure/figure/IFigurePart.ts @@ -0,0 +1,9 @@ +export interface IFigurePart +{ + id: number; + type: string; + breed: number; + index: number; + colorLayerIndex: number; + paletteMap: number; +} diff --git a/src/app/avatar/structure/figure/IFigurePartSet.ts b/src/app/avatar/structure/figure/IFigurePartSet.ts new file mode 100644 index 0000000..7e1653e --- /dev/null +++ b/src/app/avatar/structure/figure/IFigurePartSet.ts @@ -0,0 +1,16 @@ +import { IFigurePart } from './IFigurePart'; + +export interface IFigurePartSet +{ + getPart(_arg_1: string, _arg_2: number): IFigurePart; + id: number; + type: string; + gender: string; + clubLevel: number; + isColorable: boolean; + isSelectable: boolean; + parts: IFigurePart[]; + hiddenLayers: string[]; + isPreSelectable: boolean; + isSellable: boolean; +} diff --git a/src/app/avatar/structure/figure/IPalette.ts b/src/app/avatar/structure/figure/IPalette.ts new file mode 100644 index 0000000..3c230ab --- /dev/null +++ b/src/app/avatar/structure/figure/IPalette.ts @@ -0,0 +1,9 @@ +import { AdvancedMap } from '../../../../core'; +import { IPartColor } from './IPartColor'; + +export interface IPalette +{ + getColor(id: number): IPartColor; + id: number; + colors: AdvancedMap; +} diff --git a/src/app/avatar/structure/figure/IPartColor.ts b/src/app/avatar/structure/figure/IPartColor.ts new file mode 100644 index 0000000..6978528 --- /dev/null +++ b/src/app/avatar/structure/figure/IPartColor.ts @@ -0,0 +1,8 @@ +export interface IPartColor +{ + id: number; + index: number; + clubLevel: number; + isSelectable: boolean; + rgb: number; +} diff --git a/src/app/avatar/structure/figure/ISetType.ts b/src/app/avatar/structure/figure/ISetType.ts new file mode 100644 index 0000000..0df7f93 --- /dev/null +++ b/src/app/avatar/structure/figure/ISetType.ts @@ -0,0 +1,12 @@ +import { AdvancedMap } from '../../../../core'; +import { IFigurePartSet } from './IFigurePartSet'; + +export interface ISetType +{ + getPartSet(_arg_1: number): IFigurePartSet; + isMandatory(_arg_1: string, _arg_2: number): boolean; + optionalFromClubLevel(_arg_1: string): number; + type: string; + paletteID: number; + partSets: AdvancedMap; +} diff --git a/src/app/avatar/structure/figure/Palette.ts b/src/app/avatar/structure/figure/Palette.ts new file mode 100644 index 0000000..42da5a8 --- /dev/null +++ b/src/app/avatar/structure/figure/Palette.ts @@ -0,0 +1,48 @@ +import { AdvancedMap } from '../../../../core'; +import { IFigureDataPalette } from '../../interfaces'; +import { IPalette } from './IPalette'; +import { IPartColor } from './IPartColor'; +import { PartColor } from './PartColor'; + +export class Palette implements IPalette +{ + private _id: number; + private _colors: AdvancedMap; + + constructor(data: IFigureDataPalette) + { + if(!data) throw new Error('invalid_data'); + + this._id = data.id; + this._colors = new AdvancedMap(); + + this.append(data); + } + + public append(data: IFigureDataPalette): void + { + for(const color of data.colors) + { + const newColor = new PartColor(color); + + this._colors.add(color.id.toString(), newColor); + } + } + + public getColor(id: number): IPartColor + { + if((id === undefined) || id < 0) return null; + + return (this._colors.getValue(id.toString()) || null); + } + + public get id(): number + { + return this._id; + } + + public get colors(): AdvancedMap + { + return this._colors; + } +} diff --git a/src/app/avatar/structure/figure/PartColor.ts b/src/app/avatar/structure/figure/PartColor.ts new file mode 100644 index 0000000..462a0e4 --- /dev/null +++ b/src/app/avatar/structure/figure/PartColor.ts @@ -0,0 +1,47 @@ +import { IFigureDataColor } from '../../interfaces'; +import { IPartColor } from './IPartColor'; + +export class PartColor implements IPartColor +{ + private _id: number; + private _index: number; + private _clubLevel: number; + private _isSelectable: boolean; + private _rgb: number; + + constructor(data: IFigureDataColor) + { + if(!data) throw new Error('invalid_data'); + + this._id = data.id; + this._index = data.index; + this._clubLevel = data.club; + this._isSelectable = data.selectable; + this._rgb = parseInt('0x' + data.hexCode, 16); + } + + public get id(): number + { + return this._id; + } + + public get index(): number + { + return this._index; + } + + public get clubLevel(): number + { + return this._clubLevel; + } + + public get isSelectable(): boolean + { + return this._isSelectable; + } + + public get rgb(): number + { + return this._rgb; + } +} diff --git a/src/app/avatar/structure/figure/SetType.ts b/src/app/avatar/structure/figure/SetType.ts new file mode 100644 index 0000000..ec870a9 --- /dev/null +++ b/src/app/avatar/structure/figure/SetType.ts @@ -0,0 +1,106 @@ +import { AdvancedMap } from '../../../../core'; +import { IFigureDataSetType } from '../../interfaces'; +import { FigurePartSet } from './FigurePartSet'; +import { IFigurePartSet } from './IFigurePartSet'; +import { ISetType } from './ISetType'; + +export class SetType implements ISetType +{ + private _type: string; + private _paletteId: number; + private _isMandatory: { [index: string]: boolean[] }; + private _partSets: AdvancedMap; + + constructor(data: IFigureDataSetType) + { + if(!data) throw new Error('invalid_data'); + + this._type = data.type; + this._paletteId = data.paletteId; + this._isMandatory = {}; + this._isMandatory['F'] = [ data.mandatory_f_0, data.mandatory_f_1 ]; + this._isMandatory['M'] = [ data.mandatory_m_0, data.mandatory_m_1 ]; + this._partSets = new AdvancedMap(); + + this.append(data); + } + + public dispose(): void + { + for(const set of this._partSets.getValues()) + { + const partSet = set as FigurePartSet; + + partSet.dispose(); + } + + this._partSets = null; + } + + public cleanUp(data: IFigureDataSetType): void + { + for(const set of data.sets) + { + const setId = set.id.toString(); + const partSet = (this._partSets.getValue(setId) as FigurePartSet); + + if(partSet) + { + partSet.dispose(); + + this._partSets.remove(setId); + } + } + } + + public append(setType: IFigureDataSetType): void + { + if(!setType || !setType.sets) return; + + for(const set of setType.sets) this._partSets.add(set.id.toString(), new FigurePartSet(this._type, set)); + } + + public getDefaultPartSet(gender: string): IFigurePartSet + { + for(const set of this._partSets.getValues()) + { + if(!set) continue; + + if((set.clubLevel === 0) && ((set.gender === gender) || (set.gender === 'U'))) return set; + } + + return null; + } + + public getPartSet(k: number): IFigurePartSet + { + return this._partSets.getValue(k.toString()); + } + + public get type(): string + { + return this._type; + } + + public get paletteID(): number + { + return this._paletteId; + } + + public isMandatory(k: string, _arg_2: number): boolean + { + return this._isMandatory[k.toUpperCase()][Math.min(_arg_2, 1)]; + } + + public optionalFromClubLevel(k: string): number + { + const _local_2 = this._isMandatory[k.toUpperCase()]; + + return _local_2.indexOf(false); + } + + public get partSets(): AdvancedMap + { + return this._partSets; + } +} diff --git a/src/app/avatar/structure/figure/index.ts b/src/app/avatar/structure/figure/index.ts new file mode 100644 index 0000000..d2b5f52 --- /dev/null +++ b/src/app/avatar/structure/figure/index.ts @@ -0,0 +1,10 @@ +export * from './FigurePart'; +export * from './FigurePartSet'; +export * from './IFigurePart'; +export * from './IFigurePartSet'; +export * from './IPalette'; +export * from './IPartColor'; +export * from './ISetType'; +export * from './Palette'; +export * from './PartColor'; +export * from './SetType'; diff --git a/src/app/avatar/structure/index.ts b/src/app/avatar/structure/index.ts new file mode 100644 index 0000000..493e0d2 --- /dev/null +++ b/src/app/avatar/structure/index.ts @@ -0,0 +1,9 @@ +export * from './animation'; +export * from './AvatarAnimationData'; +export * from './AvatarCanvas'; +export * from './figure'; +export * from './FigureSetData'; +export * from './IFigureSetData'; +export * from './IStructureData'; +export * from './parts'; +export * from './PartSetsData'; diff --git a/src/app/avatar/structure/parts/ActivePartSet.ts b/src/app/avatar/structure/parts/ActivePartSet.ts new file mode 100644 index 0000000..4244308 --- /dev/null +++ b/src/app/avatar/structure/parts/ActivePartSet.ts @@ -0,0 +1,26 @@ +export class ActivePartSet +{ + private _id: string; + private _parts: string[]; + + constructor(data: any) + { + this._id = data.id; + this._parts = []; + + if(data.activeParts && (data.activeParts.length > 0)) + { + for(const part of data.activeParts) + { + if(!part) continue; + + this._parts.push(part.setType); + } + } + } + + public get parts(): string[] + { + return this._parts; + } +} diff --git a/src/app/avatar/structure/parts/PartDefinition.ts b/src/app/avatar/structure/parts/PartDefinition.ts new file mode 100644 index 0000000..19caa8c --- /dev/null +++ b/src/app/avatar/structure/parts/PartDefinition.ts @@ -0,0 +1,64 @@ +export class PartDefinition +{ + private _setType: string; + private _flippedSetType: string; + private _removeSetType: string; + private _appendToFigure: boolean; + private _staticId: number; + + constructor(data: any) + { + if(!data) throw new Error('invalid_data'); + + this._setType = data.setType; + this._flippedSetType = data.flippedSetType || null; + this._removeSetType = data.removeSetType || null; + this._appendToFigure = false; + this._staticId = -1; + } + + public hasStaticId(): boolean + { + return this._staticId >= 0; + } + + public get staticId(): number + { + return this._staticId; + } + + public set staticId(k: number) + { + this._staticId = k; + } + + public get setType(): string + { + return this._setType; + } + + public get flippedSetType(): string + { + return this._flippedSetType; + } + + public set flippedSetType(type: string) + { + this._flippedSetType = type; + } + + public get removeSetType(): string + { + return this._removeSetType; + } + + public get appendToFigure(): boolean + { + return this._appendToFigure; + } + + public set appendToFigure(flag: boolean) + { + this._appendToFigure = flag; + } +} diff --git a/src/app/avatar/structure/parts/index.ts b/src/app/avatar/structure/parts/index.ts new file mode 100644 index 0000000..31faf62 --- /dev/null +++ b/src/app/avatar/structure/parts/index.ts @@ -0,0 +1,2 @@ +export * from './ActivePartSet'; +export * from './PartDefinition'; diff --git a/src/app/index.ts b/src/app/index.ts new file mode 100644 index 0000000..13f65e1 --- /dev/null +++ b/src/app/index.ts @@ -0,0 +1,3 @@ +export * from './Application'; +export * from './avatar'; +export * from './IApplication'; diff --git a/src/core/INitroCore.ts b/src/core/INitroCore.ts new file mode 100644 index 0000000..f359e11 --- /dev/null +++ b/src/core/INitroCore.ts @@ -0,0 +1,9 @@ +import { IAssetManager } from './asset'; +import { INitroManager } from './common'; +import { IConfigurationManager } from './configuration'; + +export interface INitroCore extends INitroManager +{ + configuration: IConfigurationManager; + asset: IAssetManager; +} diff --git a/src/core/NitroCore.ts b/src/core/NitroCore.ts new file mode 100644 index 0000000..369143c --- /dev/null +++ b/src/core/NitroCore.ts @@ -0,0 +1,42 @@ +import { AssetManager, IAssetManager } from './asset'; +import { NitroManager } from './common'; +import { ConfigurationManager, IConfigurationManager } from './configuration'; +import { INitroCore } from './INitroCore'; + +export class NitroCore extends NitroManager implements INitroCore +{ + private _configuration: IConfigurationManager; + private _asset: IAssetManager; + + constructor() + { + super(); + + this._configuration = new ConfigurationManager(); + this._asset = new AssetManager(); + } + + protected async onInit(): Promise + { + if(this._configuration) await this._configuration.init(); + + if(this._asset) await this._asset.init(); + } + + protected async onDispose(): Promise + { + if(this._asset) await this._asset.dispose(); + + if(this._configuration) await this._configuration.dispose(); + } + + public get configuration(): IConfigurationManager + { + return this._configuration; + } + + public get asset(): IAssetManager + { + return this._asset; + } +} diff --git a/src/core/asset/AssetManager.ts b/src/core/asset/AssetManager.ts new file mode 100644 index 0000000..35ad4f3 --- /dev/null +++ b/src/core/asset/AssetManager.ts @@ -0,0 +1,119 @@ +import { Canvas } from 'canvas'; +import { NitroManager } from '../common'; +import { AdvancedMap, FileUtilities } from '../utils'; +import { IAssetManager } from './IAssetManager'; +import { NitroBundle } from './NitroBundle'; +import { GraphicAssetCollection, IGraphicAsset, IGraphicAssetCollection } from './utils'; + +export class AssetManager extends NitroManager implements IAssetManager +{ + private _textures: AdvancedMap; + private _collections: AdvancedMap; + + constructor() + { + super(); + + this._textures = new AdvancedMap(); + this._collections = new AdvancedMap(); + } + + public getTexture(name: string): Canvas + { + if(!name) return null; + + const existing = this._textures.getValue(name); + + if(!existing) return null; + + return existing; + } + + public setTexture(name: string, texture: Canvas): void + { + if(!name || !texture) return; + + this._textures.add(name, texture); + } + + public getAsset(name: string): IGraphicAsset + { + if(!name) return null; + + for(const collection of this._collections.getValues()) + { + if(!collection) continue; + + const existing = collection.getAsset(name); + + if(!existing) continue; + + return existing; + } + + return null; + } + + public getCollection(name: string): IGraphicAssetCollection + { + if(!name) return null; + + const existing = this._collections.getValue(name); + + if(!existing) return null; + + return existing; + } + + public createCollectionFromNitroBundle(bundle: NitroBundle): IGraphicAssetCollection + { + const collection = new GraphicAssetCollection(bundle.jsonFile, bundle.baseTexture); + + if(collection) + { + for(const [ name, texture ] of collection.textures.getKeys()) + { + const texture = collection.textures.getValue(name); + + this.setTexture(name, texture); + } + + this._collections.add(collection.name, collection); + } + + return collection; + } + + public async downloadAsset(assetUrl: string): Promise + { + return await this.downloadAssets([ assetUrl ]); + } + + public async downloadAssets(assetUrls: string[]): Promise + { + if(!assetUrls || !assetUrls.length) return false; + + for(const url of assetUrls) + { + try + { + const buffer = await FileUtilities.readFileAsBuffer(url); + const bundle = await NitroBundle.from(buffer); + + this.createCollectionFromNitroBundle(bundle); + } + + catch(err) + { + + } + } + + return true; + } + + public get collections(): AdvancedMap + { + return this._collections; + } +} diff --git a/src/core/asset/IAssetManager.ts b/src/core/asset/IAssetManager.ts new file mode 100644 index 0000000..630d5d4 --- /dev/null +++ b/src/core/asset/IAssetManager.ts @@ -0,0 +1,16 @@ +import { Canvas } from 'canvas'; +import { INitroManager } from '../common'; +import { NitroBundle } from './NitroBundle'; +import { IGraphicAsset, IGraphicAssetCollection } from './utils'; + +export interface IAssetManager extends INitroManager +{ + getTexture(name: string): Canvas; + setTexture(name: string, texture: Canvas): void; + getAsset(name: string): IGraphicAsset; + getCollection(name: string): IGraphicAssetCollection; + createCollectionFromNitroBundle(bundle: NitroBundle): IGraphicAssetCollection; + downloadAssets(urls: string[]): Promise; + downloadAsset(url: string): Promise; + collections: AdvancedMap; +} diff --git a/src/core/asset/NitroBundle.ts b/src/core/asset/NitroBundle.ts new file mode 100644 index 0000000..35c0970 --- /dev/null +++ b/src/core/asset/NitroBundle.ts @@ -0,0 +1,77 @@ +import { wrap } from 'bytebuffer'; +import { Image, loadImage } from 'canvas'; +import { Data, inflate } from 'pako'; +import { IAssetData } from './interfaces'; + +export class NitroBundle +{ + private static TEXT_DECODER: TextDecoder = new TextDecoder('utf-8'); + + private _jsonFile: IAssetData = null; + private _baseTexture: Image = null; + + public static async from(buffer: ArrayBuffer): Promise + { + const bundle = new NitroBundle(); + + await bundle.parse(buffer); + + return bundle; + } + + private static arrayBufferToBase64(buffer: ArrayBuffer): string + { + let binary = ''; + + const bytes = new Uint8Array(buffer); + const len = bytes.byteLength; + + for(let i = 0; i < len; i++) (binary += String.fromCharCode(bytes[i])); + + const newBuffer = Buffer.from(binary.toString(), 'binary'); + + return newBuffer.toString('base64'); + } + + private async parse(arrayBuffer: ArrayBuffer): Promise + { + const binaryReader = wrap(arrayBuffer); + + let fileCount = binaryReader.readShort(); + + while(fileCount > 0) + { + const fileNameLength = binaryReader.readShort(); + const fileName = binaryReader.readString(fileNameLength); + const fileLength = binaryReader.readInt(); + const buffer = binaryReader.readBytes(fileLength); + + if(fileName.endsWith('.json')) + { + const decompressed = inflate((buffer.toArrayBuffer() as Data)); + + this._jsonFile = JSON.parse(NitroBundle.TEXT_DECODER.decode(decompressed)); + } + else + { + const decompressed = inflate((buffer.toArrayBuffer() as Data)); + const base64 = NitroBundle.arrayBufferToBase64(decompressed); + const baseTexture = await loadImage('data:image/png;base64,' + base64); + + this._baseTexture = baseTexture; + } + + fileCount--; + } + } + + public get jsonFile(): IAssetData + { + return this._jsonFile; + } + + public get baseTexture(): Image + { + return this._baseTexture; + } +} diff --git a/src/core/asset/index.ts b/src/core/asset/index.ts new file mode 100644 index 0000000..710adc8 --- /dev/null +++ b/src/core/asset/index.ts @@ -0,0 +1,5 @@ +export * from './AssetManager'; +export * from './IAssetManager'; +export * from './interfaces'; +export * from './NitroBundle'; +export * from './utils'; diff --git a/src/core/asset/interfaces/IAsset.ts b/src/core/asset/interfaces/IAsset.ts new file mode 100644 index 0000000..f4e4fb4 --- /dev/null +++ b/src/core/asset/interfaces/IAsset.ts @@ -0,0 +1,9 @@ +export interface IAsset +{ + source?: string; + x?: number; + y?: number; + flipH?: boolean; + flipV?: boolean; + usesPalette?: boolean; +} diff --git a/src/core/asset/interfaces/IAssetAlias.ts b/src/core/asset/interfaces/IAssetAlias.ts new file mode 100644 index 0000000..5c14027 --- /dev/null +++ b/src/core/asset/interfaces/IAssetAlias.ts @@ -0,0 +1,6 @@ +export interface IAssetAlias +{ + link?: string; + flipH?: boolean; + flipV?: boolean; +} diff --git a/src/core/asset/interfaces/IAssetData.ts b/src/core/asset/interfaces/IAssetData.ts new file mode 100644 index 0000000..ff4524c --- /dev/null +++ b/src/core/asset/interfaces/IAssetData.ts @@ -0,0 +1,21 @@ +import { IAssetAnimation } from './animation'; +import { IAsset } from './IAsset'; +import { IAssetAlias } from './IAssetAlias'; +import { IAssetPalette } from './IAssetPalette'; +import { IAssetLogicData } from './logic'; +import { ISpritesheetData } from './spritesheet'; +import { IAssetVisualizationData } from './visualization'; + +export interface IAssetData { + type?: string; + name?: string; + visualizationType?: string; + logicType?: string; + spritesheet?: ISpritesheetData; + logic?: IAssetLogicData; + assets?: { [index: string]: IAsset }; + aliases?: { [index: string]: IAssetAlias }; + animations?: { [index: string]: IAssetAnimation }; + palettes?: { [index: string]: IAssetPalette }; + visualizations?: IAssetVisualizationData[]; +} diff --git a/src/core/asset/interfaces/IAssetPalette.ts b/src/core/asset/interfaces/IAssetPalette.ts new file mode 100644 index 0000000..9b0384b --- /dev/null +++ b/src/core/asset/interfaces/IAssetPalette.ts @@ -0,0 +1,12 @@ +export interface IAssetPalette +{ + id?: number; + source?: string; + master?: boolean; + tags?: string[]; + breed?: number; + colorTag?: number; + color1?: string; + color2?: string; + rgb?: [ number, number, number ][]; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimation.ts b/src/core/asset/interfaces/animation/IAssetAnimation.ts new file mode 100644 index 0000000..b35e0eb --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimation.ts @@ -0,0 +1,23 @@ +import { IAssetAnimationAdd } from './IAssetAnimationAdd'; +import { IAssetAnimationAvatar } from './IAssetAnimationAvatar'; +import { IAssetAnimationDirection } from './IAssetAnimationDirection'; +import { IAssetAnimationFrame } from './IAssetAnimationFrame'; +import { IAssetAnimationOverride } from './IAssetAnimationOverride'; +import { IAssetAnimationRemove } from './IAssetAnimationRemove'; +import { IAssetAnimationShadow } from './IAssetAnimationShadow'; +import { IAssetAnimationSprite } from './IAssetAnimationSprite'; + +export interface IAssetAnimation +{ + name?: string; + desc?: string; + resetOnToggle?: boolean; + directions?: IAssetAnimationDirection[]; + shadows?: IAssetAnimationShadow[]; + adds?: IAssetAnimationAdd[]; + removes?: IAssetAnimationRemove[]; + sprites?: IAssetAnimationSprite[]; + frames?: IAssetAnimationFrame[]; + avatars?: IAssetAnimationAvatar[]; + overrides?: IAssetAnimationOverride[]; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationAdd.ts b/src/core/asset/interfaces/animation/IAssetAnimationAdd.ts new file mode 100644 index 0000000..3da37c6 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationAdd.ts @@ -0,0 +1,8 @@ +export interface IAssetAnimationAdd +{ + id?: string; + align?: string; + blend?: string; + ink?: number; + base?: string; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationAvatar.ts b/src/core/asset/interfaces/animation/IAssetAnimationAvatar.ts new file mode 100644 index 0000000..dcd030e --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationAvatar.ts @@ -0,0 +1,6 @@ +export interface IAssetAnimationAvatar +{ + ink?: number; + foreground?: string; + background?: string; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationDirection.ts b/src/core/asset/interfaces/animation/IAssetAnimationDirection.ts new file mode 100644 index 0000000..0c18eae --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationDirection.ts @@ -0,0 +1,4 @@ +export interface IAssetAnimationDirection +{ + offset?: number; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationFrame.ts b/src/core/asset/interfaces/animation/IAssetAnimationFrame.ts new file mode 100644 index 0000000..b8b88a0 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationFrame.ts @@ -0,0 +1,8 @@ +import { IAssetAnimationFramePart } from './IAssetAnimationFramePart'; + +export interface IAssetAnimationFrame +{ + repeats?: number; + fxs?: IAssetAnimationFramePart[]; + bodyparts?: IAssetAnimationFramePart[]; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationFramePart.ts b/src/core/asset/interfaces/animation/IAssetAnimationFramePart.ts new file mode 100644 index 0000000..ac8c093 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationFramePart.ts @@ -0,0 +1,14 @@ +import { IAssetAnimationFramePartItem } from './IAssetAnimationFramePartItem'; + +export interface IAssetAnimationFramePart +{ + id?: string; + frame?: number; + base?: string; + action?: string; + dx?: number; + dy?: number; + dz?: number; + dd?: number; + items?: IAssetAnimationFramePartItem[]; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationFramePartItem.ts b/src/core/asset/interfaces/animation/IAssetAnimationFramePartItem.ts new file mode 100644 index 0000000..45a7642 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationFramePartItem.ts @@ -0,0 +1,5 @@ +export interface IAssetAnimationFramePartItem +{ + id?: string; + base?: string; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationOverride.ts b/src/core/asset/interfaces/animation/IAssetAnimationOverride.ts new file mode 100644 index 0000000..3d56833 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationOverride.ts @@ -0,0 +1,8 @@ +import { IAssetAnimationFrame } from './IAssetAnimationFrame'; + +export interface IAssetAnimationOverride +{ + name?: string; + override?: string; + frames?: IAssetAnimationFrame[]; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationRemove.ts b/src/core/asset/interfaces/animation/IAssetAnimationRemove.ts new file mode 100644 index 0000000..ac65fb5 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationRemove.ts @@ -0,0 +1,4 @@ +export interface IAssetAnimationRemove +{ + id?: string; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationShadow.ts b/src/core/asset/interfaces/animation/IAssetAnimationShadow.ts new file mode 100644 index 0000000..dfe22a8 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationShadow.ts @@ -0,0 +1,4 @@ +export interface IAssetAnimationShadow +{ + id?: string; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationSprite.ts b/src/core/asset/interfaces/animation/IAssetAnimationSprite.ts new file mode 100644 index 0000000..afc7b05 --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationSprite.ts @@ -0,0 +1,11 @@ +import { IAssetAnimationSpriteDirection } from './IAssetAnimationSpriteDirection'; + +export interface IAssetAnimationSprite +{ + id?: string; + member?: string; + directions?: number; + staticY?: number; + ink?: number; + directionList?: IAssetAnimationSpriteDirection[]; +} diff --git a/src/core/asset/interfaces/animation/IAssetAnimationSpriteDirection.ts b/src/core/asset/interfaces/animation/IAssetAnimationSpriteDirection.ts new file mode 100644 index 0000000..746719d --- /dev/null +++ b/src/core/asset/interfaces/animation/IAssetAnimationSpriteDirection.ts @@ -0,0 +1,7 @@ +export interface IAssetAnimationSpriteDirection +{ + id?: number; + dx?: number; + dy?: number; + dz?: number; +} diff --git a/src/core/asset/interfaces/animation/index.ts b/src/core/asset/interfaces/animation/index.ts new file mode 100644 index 0000000..56543d0 --- /dev/null +++ b/src/core/asset/interfaces/animation/index.ts @@ -0,0 +1,12 @@ +export * from './IAssetAnimation'; +export * from './IAssetAnimationAdd'; +export * from './IAssetAnimationAvatar'; +export * from './IAssetAnimationDirection'; +export * from './IAssetAnimationFrame'; +export * from './IAssetAnimationFramePart'; +export * from './IAssetAnimationFramePartItem'; +export * from './IAssetAnimationOverride'; +export * from './IAssetAnimationRemove'; +export * from './IAssetAnimationShadow'; +export * from './IAssetAnimationSprite'; +export * from './IAssetAnimationSpriteDirection'; diff --git a/src/core/asset/interfaces/index.ts b/src/core/asset/interfaces/index.ts new file mode 100644 index 0000000..3d5fabb --- /dev/null +++ b/src/core/asset/interfaces/index.ts @@ -0,0 +1,8 @@ +export * from './animation'; +export * from './IAsset'; +export * from './IAssetAlias'; +export * from './IAssetData'; +export * from './IAssetPalette'; +export * from './logic'; +export * from './spritesheet'; +export * from './visualization'; diff --git a/src/core/asset/interfaces/logic/IAssetLogicCustomVars.ts b/src/core/asset/interfaces/logic/IAssetLogicCustomVars.ts new file mode 100644 index 0000000..1ebd4a8 --- /dev/null +++ b/src/core/asset/interfaces/logic/IAssetLogicCustomVars.ts @@ -0,0 +1,4 @@ +export interface ICustomVars +{ + variables?: string[]; +} diff --git a/src/core/asset/interfaces/logic/IAssetLogicData.ts b/src/core/asset/interfaces/logic/IAssetLogicData.ts new file mode 100644 index 0000000..acf484c --- /dev/null +++ b/src/core/asset/interfaces/logic/IAssetLogicData.ts @@ -0,0 +1,17 @@ +import { ICustomVars } from './IAssetLogicCustomVars'; +import { IAssetLogicPlanetSystem } from './IAssetLogicPlanetSystem'; +import { ISoundSample } from './ISoundSample'; +import { IAssetLogicModel } from './model/IAssetLogicModel'; +import { IParticleSystem } from './particlesystem'; + +export interface IAssetLogicData +{ + model?: IAssetLogicModel; + maskType?: string; + credits?: string; + soundSample?: ISoundSample; + action?: { link?: string, startState?: number }; + planetSystems?: IAssetLogicPlanetSystem[]; + particleSystems?: IParticleSystem[]; + customVars?: ICustomVars; +} diff --git a/src/core/asset/interfaces/logic/IAssetLogicPlanetSystem.ts b/src/core/asset/interfaces/logic/IAssetLogicPlanetSystem.ts new file mode 100644 index 0000000..47521bc --- /dev/null +++ b/src/core/asset/interfaces/logic/IAssetLogicPlanetSystem.ts @@ -0,0 +1,11 @@ +export interface IAssetLogicPlanetSystem +{ + id?: number; + name?: string; + parent?: string; + radius?: number; + arcSpeed?: number; + arcOffset?: number; + blend?: number; + height?: number; +} diff --git a/src/core/asset/interfaces/logic/ISoundSample.ts b/src/core/asset/interfaces/logic/ISoundSample.ts new file mode 100644 index 0000000..003f9f6 --- /dev/null +++ b/src/core/asset/interfaces/logic/ISoundSample.ts @@ -0,0 +1,5 @@ +export interface ISoundSample +{ + id?: number; + noPitch?: boolean; +} diff --git a/src/core/asset/interfaces/logic/index.ts b/src/core/asset/interfaces/logic/index.ts new file mode 100644 index 0000000..569907b --- /dev/null +++ b/src/core/asset/interfaces/logic/index.ts @@ -0,0 +1,6 @@ +export * from './IAssetLogicCustomVars'; +export * from './IAssetLogicData'; +export * from './IAssetLogicPlanetSystem'; +export * from './ISoundSample'; +export * from './model'; +export * from './particlesystem'; diff --git a/src/core/asset/interfaces/logic/model/IAssetDimension.ts b/src/core/asset/interfaces/logic/model/IAssetDimension.ts new file mode 100644 index 0000000..4a4629f --- /dev/null +++ b/src/core/asset/interfaces/logic/model/IAssetDimension.ts @@ -0,0 +1,6 @@ +export interface IAssetDimension +{ + x: number; + y: number; + z?: number; +} \ No newline at end of file diff --git a/src/core/asset/interfaces/logic/model/IAssetLogicModel.ts b/src/core/asset/interfaces/logic/model/IAssetLogicModel.ts new file mode 100644 index 0000000..eef3245 --- /dev/null +++ b/src/core/asset/interfaces/logic/model/IAssetLogicModel.ts @@ -0,0 +1,7 @@ +import { IAssetDimension } from './IAssetDimension'; + +export interface IAssetLogicModel +{ + dimensions?: IAssetDimension; + directions?: number[]; +} diff --git a/src/core/asset/interfaces/logic/model/index.ts b/src/core/asset/interfaces/logic/model/index.ts new file mode 100644 index 0000000..4d08a72 --- /dev/null +++ b/src/core/asset/interfaces/logic/model/index.ts @@ -0,0 +1,2 @@ +export * from './IAssetDimension'; +export * from './IAssetLogicModel'; diff --git a/src/core/asset/interfaces/logic/particlesystem/IParticleSystem.ts b/src/core/asset/interfaces/logic/particlesystem/IParticleSystem.ts new file mode 100644 index 0000000..871f5f3 --- /dev/null +++ b/src/core/asset/interfaces/logic/particlesystem/IParticleSystem.ts @@ -0,0 +1,11 @@ +import { IParticleSystemEmitter } from './IParticleSystemEmitter'; + +export interface IParticleSystem +{ + size?: number; + canvasId?: number; + offsetY?: number; + blend?: number; + bgColor?: string; + emitters?: IParticleSystemEmitter[]; +} diff --git a/src/core/asset/interfaces/logic/particlesystem/IParticleSystemEmitter.ts b/src/core/asset/interfaces/logic/particlesystem/IParticleSystemEmitter.ts new file mode 100644 index 0000000..fa175e2 --- /dev/null +++ b/src/core/asset/interfaces/logic/particlesystem/IParticleSystemEmitter.ts @@ -0,0 +1,15 @@ +import { IParticleSystemParticle } from './IParticleSystemParticle'; +import { IParticleSystemSimulation } from './IParticleSystemSimulation'; + +export interface IParticleSystemEmitter +{ + id?: number; + name?: string; + spriteId?: number; + maxNumParticles?: number; + particlesPerFrame?: number; + burstPulse?: number; + fuseTime?: number; + simulation?: IParticleSystemSimulation; + particles?: IParticleSystemParticle[]; +} diff --git a/src/core/asset/interfaces/logic/particlesystem/IParticleSystemParticle.ts b/src/core/asset/interfaces/logic/particlesystem/IParticleSystemParticle.ts new file mode 100644 index 0000000..99281fa --- /dev/null +++ b/src/core/asset/interfaces/logic/particlesystem/IParticleSystemParticle.ts @@ -0,0 +1,7 @@ +export interface IParticleSystemParticle +{ + isEmitter?: boolean; + lifeTime?: number; + fade?: boolean; + frames?: string[]; +} diff --git a/src/core/asset/interfaces/logic/particlesystem/IParticleSystemSimulation.ts b/src/core/asset/interfaces/logic/particlesystem/IParticleSystemSimulation.ts new file mode 100644 index 0000000..fef400c --- /dev/null +++ b/src/core/asset/interfaces/logic/particlesystem/IParticleSystemSimulation.ts @@ -0,0 +1,9 @@ +export interface IParticleSystemSimulation +{ + force?: number; + direction?: number; + gravity?: number; + airFriction?: number; + shape?: string; + energy?: number; +} diff --git a/src/core/asset/interfaces/logic/particlesystem/index.ts b/src/core/asset/interfaces/logic/particlesystem/index.ts new file mode 100644 index 0000000..428f6fc --- /dev/null +++ b/src/core/asset/interfaces/logic/particlesystem/index.ts @@ -0,0 +1,4 @@ +export * from './IParticleSystem'; +export * from './IParticleSystemEmitter'; +export * from './IParticleSystemParticle'; +export * from './IParticleSystemSimulation'; diff --git a/src/core/asset/interfaces/spritesheet/ISpritesheetData.ts b/src/core/asset/interfaces/spritesheet/ISpritesheetData.ts new file mode 100644 index 0000000..2c68634 --- /dev/null +++ b/src/core/asset/interfaces/spritesheet/ISpritesheetData.ts @@ -0,0 +1,8 @@ +import { ISpritesheetFrame } from './ISpritesheetFrame'; +import { ISpritesheetMeta } from './ISpritesheetMeta'; + +export interface ISpritesheetData +{ + meta: ISpritesheetMeta; + frames: ISpritesheetFrame[]; +} diff --git a/src/core/asset/interfaces/spritesheet/ISpritesheetFrame.ts b/src/core/asset/interfaces/spritesheet/ISpritesheetFrame.ts new file mode 100644 index 0000000..0833b50 --- /dev/null +++ b/src/core/asset/interfaces/spritesheet/ISpritesheetFrame.ts @@ -0,0 +1,25 @@ +export interface ISpritesheetFrame +{ + frame: { + x: number; + y: number; + w: number; + h: number; + }; + rotated: boolean; + trimmed: boolean; + spriteSourceSize: { + x: number; + y: number; + w: number; + h: number; + }; + sourceSize: { + w: number; + h: number; + }; + pivot: { + x: number; + y: number; + }; +} diff --git a/src/core/asset/interfaces/spritesheet/ISpritesheetMeta.ts b/src/core/asset/interfaces/spritesheet/ISpritesheetMeta.ts new file mode 100644 index 0000000..3a74f7b --- /dev/null +++ b/src/core/asset/interfaces/spritesheet/ISpritesheetMeta.ts @@ -0,0 +1,12 @@ +export interface ISpritesheetMeta +{ + app: string; + version: string; + image: string; + format: string; + size: { + w: number; + h: number; + }; + scale: string; +} diff --git a/src/core/asset/interfaces/spritesheet/index.ts b/src/core/asset/interfaces/spritesheet/index.ts new file mode 100644 index 0000000..9c94e8b --- /dev/null +++ b/src/core/asset/interfaces/spritesheet/index.ts @@ -0,0 +1,3 @@ +export * from './ISpritesheetData'; +export * from './ISpritesheetFrame'; +export * from './ISpritesheetMeta'; diff --git a/src/core/asset/interfaces/visualization/IAssetVisualizationData.ts b/src/core/asset/interfaces/visualization/IAssetVisualizationData.ts new file mode 100644 index 0000000..e17ecdc --- /dev/null +++ b/src/core/asset/interfaces/visualization/IAssetVisualizationData.ts @@ -0,0 +1,20 @@ +import { IAssetVisualAnimation } from './animation/IAssetVisualAnimation'; +import { IAssetColor } from './color/IAssetColor'; +import { IAssetGesture } from './gestures/IAssetGesture'; +import { IAssetVisualizationDirection } from './IAssetVisualizationDirection'; +import { IAssetVisualizationLayer } from './IAssetVisualizationLayer'; +import { IAssetPosture } from './postures/IAssetPosture'; + +export interface IAssetVisualizationData +{ + size?: number; + layerCount?: number; + angle?: number; + layers?: { [index: string]: IAssetVisualizationLayer }; + colors?: { [index: string]: IAssetColor }; + directions?: { [index: string]: IAssetVisualizationDirection }; + animations?: { [index: string]: IAssetVisualAnimation }; + defaultPosture?: string; + postures?: { defaultPosture?: string, postures?: IAssetPosture[] }; + gestures?: IAssetGesture[]; +} diff --git a/src/core/asset/interfaces/visualization/IAssetVisualizationDirection.ts b/src/core/asset/interfaces/visualization/IAssetVisualizationDirection.ts new file mode 100644 index 0000000..cc628f1 --- /dev/null +++ b/src/core/asset/interfaces/visualization/IAssetVisualizationDirection.ts @@ -0,0 +1,6 @@ +import { IAssetVisualizationLayer } from './IAssetVisualizationLayer'; + +export interface IAssetVisualizationDirection +{ + layers?: { [index: string]: IAssetVisualizationLayer }; +} diff --git a/src/core/asset/interfaces/visualization/IAssetVisualizationLayer.ts b/src/core/asset/interfaces/visualization/IAssetVisualizationLayer.ts new file mode 100644 index 0000000..61fcf56 --- /dev/null +++ b/src/core/asset/interfaces/visualization/IAssetVisualizationLayer.ts @@ -0,0 +1,10 @@ +export interface IAssetVisualizationLayer +{ + x?: number; + y?: number; + z?: number; + alpha?: number; + ink?: string; + tag?: string; + ignoreMouse?: boolean; +} \ No newline at end of file diff --git a/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimation.ts b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimation.ts new file mode 100644 index 0000000..4e71438 --- /dev/null +++ b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimation.ts @@ -0,0 +1,10 @@ +import { IAssetVisualAnimationLayer } from './IAssetVisualAnimationLayer'; + +export interface IAssetVisualAnimation +{ + transitionTo?: number; + transitionFrom?: number; + immediateChangeFrom?: string; + randomStart?: boolean; + layers?: { [index: string]: IAssetVisualAnimationLayer }; +} diff --git a/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationLayer.ts b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationLayer.ts new file mode 100644 index 0000000..2a274ea --- /dev/null +++ b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationLayer.ts @@ -0,0 +1,9 @@ +import { IAssetVisualAnimationSequence } from './IAssetVisualAnimationSequence'; + +export interface IAssetVisualAnimationLayer +{ + loopCount?: number; + frameRepeat?: number; + random?: number; + frameSequences?: { [index: string]: IAssetVisualAnimationSequence }; +} diff --git a/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequence.ts b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequence.ts new file mode 100644 index 0000000..bb25104 --- /dev/null +++ b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequence.ts @@ -0,0 +1,8 @@ +import { IAssetVisualAnimationSequenceFrame } from './IAssetVisualAnimationSequenceFrame'; + +export interface IAssetVisualAnimationSequence +{ + loopCount?: number; + random?: number; + frames?: { [index: string]: IAssetVisualAnimationSequenceFrame }; +} diff --git a/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrame.ts b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrame.ts new file mode 100644 index 0000000..196631e --- /dev/null +++ b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrame.ts @@ -0,0 +1,11 @@ +import { IAssetVisualAnimationSequenceFrameOffset } from './IAssetVisualAnimationSequenceFrameOffset'; + +export interface IAssetVisualAnimationSequenceFrame +{ + id?: number; + x?: number; + y?: number; + randomX?: number; + randomY?: number; + offsets?: { [index: string]: IAssetVisualAnimationSequenceFrameOffset }; +} diff --git a/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrameOffset.ts b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrameOffset.ts new file mode 100644 index 0000000..bc85461 --- /dev/null +++ b/src/core/asset/interfaces/visualization/animation/IAssetVisualAnimationSequenceFrameOffset.ts @@ -0,0 +1,6 @@ +export interface IAssetVisualAnimationSequenceFrameOffset +{ + direction?: number; + x?: number; + y?: number; +} diff --git a/src/core/asset/interfaces/visualization/animation/index.ts b/src/core/asset/interfaces/visualization/animation/index.ts new file mode 100644 index 0000000..19b332c --- /dev/null +++ b/src/core/asset/interfaces/visualization/animation/index.ts @@ -0,0 +1,5 @@ +export * from './IAssetVisualAnimation'; +export * from './IAssetVisualAnimationLayer'; +export * from './IAssetVisualAnimationSequence'; +export * from './IAssetVisualAnimationSequenceFrame'; +export * from './IAssetVisualAnimationSequenceFrameOffset'; diff --git a/src/core/asset/interfaces/visualization/color/IAssetColor.ts b/src/core/asset/interfaces/visualization/color/IAssetColor.ts new file mode 100644 index 0000000..29ebc75 --- /dev/null +++ b/src/core/asset/interfaces/visualization/color/IAssetColor.ts @@ -0,0 +1,6 @@ +import { IAssetColorLayer } from './IAssetColorLayer'; + +export interface IAssetColor +{ + layers?: { [index: string]: IAssetColorLayer }; +} diff --git a/src/core/asset/interfaces/visualization/color/IAssetColorLayer.ts b/src/core/asset/interfaces/visualization/color/IAssetColorLayer.ts new file mode 100644 index 0000000..7a1372e --- /dev/null +++ b/src/core/asset/interfaces/visualization/color/IAssetColorLayer.ts @@ -0,0 +1,4 @@ +export interface IAssetColorLayer +{ + color?: number; +} diff --git a/src/core/asset/interfaces/visualization/color/index.ts b/src/core/asset/interfaces/visualization/color/index.ts new file mode 100644 index 0000000..00aff50 --- /dev/null +++ b/src/core/asset/interfaces/visualization/color/index.ts @@ -0,0 +1,2 @@ +export * from './IAssetColor'; +export * from './IAssetColorLayer'; diff --git a/src/core/asset/interfaces/visualization/gestures/IAssetGesture.ts b/src/core/asset/interfaces/visualization/gestures/IAssetGesture.ts new file mode 100644 index 0000000..ddf3752 --- /dev/null +++ b/src/core/asset/interfaces/visualization/gestures/IAssetGesture.ts @@ -0,0 +1,5 @@ +export interface IAssetGesture +{ + id?: string; + animationId?: number; +} diff --git a/src/core/asset/interfaces/visualization/gestures/index.ts b/src/core/asset/interfaces/visualization/gestures/index.ts new file mode 100644 index 0000000..2c6e978 --- /dev/null +++ b/src/core/asset/interfaces/visualization/gestures/index.ts @@ -0,0 +1 @@ +export * from './IAssetGesture'; diff --git a/src/core/asset/interfaces/visualization/index.ts b/src/core/asset/interfaces/visualization/index.ts new file mode 100644 index 0000000..334bddc --- /dev/null +++ b/src/core/asset/interfaces/visualization/index.ts @@ -0,0 +1,7 @@ +export * from './animation'; +export * from './color'; +export * from './gestures'; +export * from './IAssetVisualizationData'; +export * from './IAssetVisualizationDirection'; +export * from './IAssetVisualizationLayer'; +export * from './postures'; diff --git a/src/core/asset/interfaces/visualization/postures/IAssetPosture.ts b/src/core/asset/interfaces/visualization/postures/IAssetPosture.ts new file mode 100644 index 0000000..3313851 --- /dev/null +++ b/src/core/asset/interfaces/visualization/postures/IAssetPosture.ts @@ -0,0 +1,5 @@ +export interface IAssetPosture +{ + id?: string; + animationId?: number; +} diff --git a/src/core/asset/interfaces/visualization/postures/index.ts b/src/core/asset/interfaces/visualization/postures/index.ts new file mode 100644 index 0000000..c24c1b9 --- /dev/null +++ b/src/core/asset/interfaces/visualization/postures/index.ts @@ -0,0 +1 @@ +export * from './IAssetPosture'; diff --git a/src/core/asset/utils/GraphicAsset.ts b/src/core/asset/utils/GraphicAsset.ts new file mode 100644 index 0000000..59b926e --- /dev/null +++ b/src/core/asset/utils/GraphicAsset.ts @@ -0,0 +1,141 @@ +import { Canvas } from 'canvas'; +import { Rectangle } from '../../utils'; +import { IGraphicAsset } from './IGraphicAsset'; + +export class GraphicAsset implements IGraphicAsset +{ + private static GRAPHIC_POOL: GraphicAsset[] = []; + + private _name: string; + private _source: string; + private _texture: Canvas; + private _usesPalette: boolean; + private _x: number; + private _y: number; + private _width: number; + private _height: number; + private _flipH: boolean; + private _flipV: boolean; + private _rectangle: Rectangle; + private _initialized: boolean; + + public static createAsset(name: string, source: string, texture: Canvas, x: number, y: number, flipH: boolean = false, flipV: boolean = false, usesPalette: boolean = false): GraphicAsset + { + const graphicAsset = (GraphicAsset.GRAPHIC_POOL.length ? GraphicAsset.GRAPHIC_POOL.pop() : new GraphicAsset()); + + graphicAsset._name = name; + graphicAsset._source = source || null; + + if(texture) + { + graphicAsset._texture = texture; + graphicAsset._initialized = false; + } + else + { + graphicAsset._texture = null; + graphicAsset._initialized = true; + } + + graphicAsset._usesPalette = usesPalette; + graphicAsset._x = x; + graphicAsset._y = y; + graphicAsset._flipH = flipH; + graphicAsset._flipV = flipV; + graphicAsset._rectangle = null; + + return graphicAsset; + } + + public recycle(): void + { + this._texture = null; + + GraphicAsset.GRAPHIC_POOL.push(this); + } + + private initialize(): void + { + if(this._initialized || !this._texture) return; + + this._width = this._texture.width; + this._height = this._texture.height; + + this._initialized = true; + } + + public get name(): string + { + return this._name; + } + + public get source(): string + { + return this._source; + } + + public get texture(): Canvas + { + return this._texture; + } + + public get usesPalette(): boolean + { + return this._usesPalette; + } + + public get x(): number + { + return this._x; + } + + public get y(): number + { + return this._y; + } + + public get width(): number + { + this.initialize(); + + return this._width; + } + + public get height(): number + { + this.initialize(); + + return this._height; + } + + public get offsetX(): number + { + if(!this._flipH) return this._x; + + return (-(this._x)); + } + + public get offsetY(): number + { + if(!this._flipV) return this._y; + + return (-(this._y)); + } + + public get flipH(): boolean + { + return this._flipH; + } + + public get flipV(): boolean + { + return this._flipV; + } + + public get rectangle(): Rectangle + { + if(!this._rectangle) this._rectangle = new Rectangle(0, 0, this.width, this.height); + + return this._rectangle; + } +} diff --git a/src/core/asset/utils/GraphicAssetCollection.ts b/src/core/asset/utils/GraphicAssetCollection.ts new file mode 100644 index 0000000..bb0e30b --- /dev/null +++ b/src/core/asset/utils/GraphicAssetCollection.ts @@ -0,0 +1,314 @@ +import { Canvas, createCanvas, Image } from 'canvas'; +import { AdvancedMap } from '../../utils'; +import { IAsset, IAssetData, IAssetPalette } from '../interfaces'; +import { GraphicAsset } from './GraphicAsset'; +import { GraphicAssetPalette } from './GraphicAssetPalette'; +import { IGraphicAsset } from './IGraphicAsset'; +import { IGraphicAssetCollection } from './IGraphicAssetCollection'; + +export class GraphicAssetCollection implements IGraphicAssetCollection +{ + private static PALETTE_ASSET_DISPOSE_THRESHOLD: number = 10; + + private _name: string; + private _data: IAssetData; + private _textures: AdvancedMap; + private _assets: AdvancedMap; + private _palettes: AdvancedMap; + private _paletteAssetNames: string[]; + + constructor(data: IAssetData, baseTexture: Image) + { + if(!data) throw new Error('invalid_collection'); + + this._name = data.name; + this._data = data; + this._textures = new AdvancedMap(); + this._assets = new AdvancedMap(); + this._palettes = new AdvancedMap(); + this._paletteAssetNames = []; + + if(baseTexture) this.processBaseTexture(baseTexture); + + this.define(data); + } + + public dispose(): void + { + if(this._palettes) + { + for(const palette of this._palettes.getValues()) palette.dispose(); + + this._palettes.reset(); + } + + if(this._paletteAssetNames) + { + this.disposePaletteAssets(); + + this._paletteAssetNames = null; + } + + if(this._assets) + { + for(const asset of this._assets.getValues()) asset.recycle(); + + this._assets.reset(); + } + } + + private processBaseTexture(baseTexture: Image): void + { + const frames = this._data.spritesheet.frames; + + for(const name in frames) + { + const frame = frames[name]; + + if(!frame) continue; + + const frameData = frame.frame; + + const canvas = createCanvas(frameData.w, frameData.h); + const ctx = canvas.getContext('2d'); + + ctx.drawImage(baseTexture, frameData.x, frameData.y, frameData.w, frameData.h, 0, 0, frameData.w, frameData.h); + + this._textures.add(name, canvas); + } + } + + public define(data: IAssetData): void + { + const assets = data.assets; + const palettes = data.palettes; + + if(assets) this.defineAssets(assets); + + if(palettes) this.definePalettes(palettes); + } + + private defineAssets(assets: { [index: string]: IAsset }): void + { + if(!assets) return; + + for(const name in assets) + { + const asset = assets[name]; + + if(!asset) continue; + + const x = (-(asset.x) || 0); + const y = (-(asset.y) || 0); + let flipH = false; + let flipV = false; + const usesPalette = (asset.usesPalette || false); + let source = (asset.source || ''); + + if(asset.flipH && source.length) flipH = true; + + if(asset.flipV && source.length) flipV = true; + + if(!source.length) source = name; + + const texture = this.getLibraryAsset(source); + + if(!texture) continue; + + let didAddAsset = this.createAsset(name, source, texture, flipH, flipV, x, y, usesPalette); + + if(!didAddAsset) + { + const existingAsset = this.getAsset(name); + + if(existingAsset && (existingAsset.name !== existingAsset.source)) + { + didAddAsset = this.replaceAsset(name, source, texture, flipH, flipV, x, y, usesPalette); + } + } + } + } + + private definePalettes(palettes: { [index: string]: IAssetPalette }): void + { + if(!palettes) return; + + for(const name in palettes) + { + const palette = palettes[name]; + + if(!palette) continue; + + const id = palette.id.toString(); + + if(this._palettes.getValue(id)) continue; + + let colorOne = 0xFFFFFF; + let colorTwo = 0xFFFFFF; + + let color = palette.color1; + + if(color && color.length > 0) colorOne = parseInt(color, 16); + + color = palette.color2; + + if(color && color.length > 0) colorTwo = parseInt(color, 16); + + this._palettes.add(id, new GraphicAssetPalette(palette.rgb, colorOne, colorTwo)); + } + } + + private createAsset(name: string, source: string, texture: Canvas, flipH: boolean, flipV: boolean, x: number, y: number, usesPalette: boolean): boolean + { + if(this._assets.getValue(name)) return false; + + const graphicAsset = GraphicAsset.createAsset(name, source, texture, x, y, flipH, flipV, usesPalette); + + this._assets.add(name, graphicAsset); + + return true; + } + + private replaceAsset(name: string, source: string, texture: Canvas, flipH: boolean, flipV: boolean, x: number, y: number, usesPalette: boolean): boolean + { + const existing = this._assets.getValue(name); + + if(existing) + { + this._assets.remove(name); + + existing.recycle(); + } + + return this.createAsset(name, source, texture, flipH, flipV, x, y, usesPalette); + } + + public getAsset(name: string): IGraphicAsset + { + if(!name) return null; + + const existing = this._assets.getValue(name); + + if(!existing) return null; + + return existing; + } + + public getAssetWithPalette(name: string, paletteName: string): IGraphicAsset + { + const saveName = (name + '@' + paletteName); + + let asset = this.getAsset(saveName); + + if(!asset) + { + asset = this.getAsset(name); + + if(!asset || !asset.usesPalette) return asset; + + const palette = this.getPalette(paletteName); + + if(palette) + { + const texture = palette.applyPalette(asset.texture); + + if(texture) + { + this._paletteAssetNames.push(saveName); + + this.createAsset(saveName, (asset.source + '@' + paletteName), texture, asset.flipH, asset.flipV, asset.x, asset.y, false); + + asset = this.getAsset(saveName); + } + } + } + + return asset; + } + + public getPaletteNames(): string[] + { + return Array.from(this._palettes.getKeys()); + } + + public getPaletteColors(paletteName: string): number[] + { + const palette = this.getPalette(paletteName); + + if(palette) return [ palette.primaryColor, palette.secondaryColor ]; + + return null; + } + + public getPalette(name: string): GraphicAssetPalette + { + if(!name) return null; + + const existing = this._palettes.getValue(name); + + if(!existing) return null; + + return existing; + } + + public disposeAsset(name: string): void + { + const existing = this._assets.getValue(name); + + if(!existing) return; + + this._assets.remove(name); + + const texture = this.getLibraryAsset(existing.source); + + if(texture) this._textures.remove(existing.source); + + existing.recycle(); + } + + public getLibraryAsset(name: string): Canvas + { + if(!name) return null; + + name = this._name + '_' + name; + + const texture = this._textures.getValue(name); + + if(!texture) return null; + + return texture; + } + + private disposePaletteAssets(disposeAll: boolean = true): void + { + if(this._paletteAssetNames) + { + if(disposeAll || (this._paletteAssetNames.length > GraphicAssetCollection.PALETTE_ASSET_DISPOSE_THRESHOLD)) + { + for(const name of this._paletteAssetNames) this.disposeAsset(name); + + this._paletteAssetNames = []; + } + } + } + + public get name(): string + { + return this._name; + } + + public get data(): IAssetData + { + return this._data; + } + + public get textures(): AdvancedMap + { + return this._textures; + } + + public get assets(): AdvancedMap + { + return this._assets; + } +} diff --git a/src/core/asset/utils/GraphicAssetPalette.ts b/src/core/asset/utils/GraphicAssetPalette.ts new file mode 100644 index 0000000..5af18e9 --- /dev/null +++ b/src/core/asset/utils/GraphicAssetPalette.ts @@ -0,0 +1,59 @@ +import { Canvas } from 'canvas'; + +export class GraphicAssetPalette +{ + private _palette: [ number, number, number ][]; + private _primaryColor: number; + private _secondaryColor: number; + + constructor(palette: [ number, number, number ][], primaryColor: number, secondaryColor: number) + { + this._palette = palette; + + while(this._palette.length < 256) this._palette.push([ 0, 0, 0 ]); + + this._primaryColor = primaryColor; + this._secondaryColor = secondaryColor; + } + + public dispose(): void + { + + } + + public applyPalette(texture: Canvas): Canvas + { + return null; + + // const ctx = texture.getContext('2d'); + // const imageData = ctx.getImageData(0, 0, texture.width, texture.height); + // const data = imageData.data; + // const newCanvas = createCanvas(texture.width, texture.height); + // const newCanvasCtx = newCanvas.getContext('2d'); + + // for(let i = 0; i < data.length; i += 4) + // { + // let paletteColor = this._palette[data[ i + 1 ]]; + + // if(paletteColor === undefined) paletteColor = [ 0, 0, 0 ]; + + // data[ i ] = paletteColor[0]; + // data[ i + 1 ] = paletteColor[1]; + // data[ i + 2 ] = paletteColor[2]; + // } + + // newCanvasCtx.drawImage(data, 0, 0, texture.width, texture.height); + + // return newCanvas; + } + + public get primaryColor(): number + { + return this._primaryColor; + } + + public get secondaryColor(): number + { + return this._secondaryColor; + } +} diff --git a/src/core/asset/utils/IGraphicAsset.ts b/src/core/asset/utils/IGraphicAsset.ts new file mode 100644 index 0000000..f97135c --- /dev/null +++ b/src/core/asset/utils/IGraphicAsset.ts @@ -0,0 +1,19 @@ +import { Canvas } from 'canvas'; +import { Rectangle } from '../../utils'; + +export interface IGraphicAsset +{ + name: string; + source: string; + texture: Canvas; + usesPalette: boolean; + x: number; + y: number; + width: number; + height: number; + offsetX: number; + offsetY: number; + flipH: boolean; + flipV: boolean; + rectangle: Rectangle; +} diff --git a/src/core/asset/utils/IGraphicAssetCollection.ts b/src/core/asset/utils/IGraphicAssetCollection.ts new file mode 100644 index 0000000..07ac503 --- /dev/null +++ b/src/core/asset/utils/IGraphicAssetCollection.ts @@ -0,0 +1,17 @@ +import { IAssetData } from '../interfaces'; +import { GraphicAssetPalette } from './GraphicAssetPalette'; +import { IGraphicAsset } from './IGraphicAsset'; + +export interface IGraphicAssetCollection +{ + dispose(): void; + define(data: IAssetData): void; + getAsset(name: string): IGraphicAsset; + getAssetWithPalette(name: string, paletteName: string): IGraphicAsset; + getPaletteNames(): string[]; + getPaletteColors(paletteName: string): number[]; + getPalette(name: string): GraphicAssetPalette; + disposeAsset(name: string): void; + name: string; + data: IAssetData; +} diff --git a/src/core/asset/utils/index.ts b/src/core/asset/utils/index.ts new file mode 100644 index 0000000..fbad163 --- /dev/null +++ b/src/core/asset/utils/index.ts @@ -0,0 +1,5 @@ +export * from './GraphicAsset'; +export * from './GraphicAssetCollection'; +export * from './GraphicAssetPalette'; +export * from './IGraphicAsset'; +export * from './IGraphicAssetCollection'; diff --git a/src/core/common/INitroManager.ts b/src/core/common/INitroManager.ts new file mode 100644 index 0000000..9462132 --- /dev/null +++ b/src/core/common/INitroManager.ts @@ -0,0 +1,10 @@ +import { INitroLogger } from '../logger'; +import { IDisposable } from './disposable/IDisposable'; + +export interface INitroManager extends IDisposable +{ + init(): Promise; + logger: INitroLogger; + isLoaded: boolean; + isLoading: boolean; +} diff --git a/src/core/common/NitroManager.ts b/src/core/common/NitroManager.ts new file mode 100644 index 0000000..95ee0fd --- /dev/null +++ b/src/core/common/NitroManager.ts @@ -0,0 +1,53 @@ +import { INitroLogger, NitroLogger } from '../logger'; +import { Disposable } from './disposable'; +import { INitroManager } from './INitroManager'; + +export class NitroManager extends Disposable implements INitroManager +{ + private _logger: INitroLogger; + + private _isLoaded: boolean; + private _isLoading: boolean; + + constructor(logger: INitroLogger = null) + { + super(); + + this._logger = logger instanceof NitroLogger ? logger : new NitroLogger(this.constructor.name); + + this._isLoaded = false; + this._isLoading = false; + } + + public async init(): Promise + { + if(this._isLoaded || this._isLoading || this.isDisposing) return; + + this._isLoading = true; + + await this.onInit(); + + this._isLoaded = true; + this._isLoading = false; + } + + protected async onInit(): Promise + { + return; + } + + public get logger(): INitroLogger + { + return this._logger; + } + + public get isLoaded(): boolean + { + return this._isLoaded; + } + + public get isLoading(): boolean + { + return this._isLoading; + } +} diff --git a/src/core/common/disposable/Disposable.ts b/src/core/common/disposable/Disposable.ts new file mode 100644 index 0000000..6725fdc --- /dev/null +++ b/src/core/common/disposable/Disposable.ts @@ -0,0 +1,40 @@ +import { IDisposable } from './IDisposable'; + +export class Disposable implements IDisposable +{ + protected _isDisposed: boolean; + protected _isDisposing: boolean; + + constructor() + { + this._isDisposed = false; + this._isDisposing = false; + } + + public async dispose(): Promise + { + if(this._isDisposed || this._isDisposing) return; + + this._isDisposing = true; + + await this.onDispose(); + + this._isDisposed = true; + this._isDisposing = false; + } + + protected async onDispose(): Promise + { + return; + } + + public get disposed(): boolean + { + return this._isDisposed; + } + + public get isDisposing(): boolean + { + return this._isDisposing; + } +} diff --git a/src/core/common/disposable/IDisposable.ts b/src/core/common/disposable/IDisposable.ts new file mode 100644 index 0000000..0701608 --- /dev/null +++ b/src/core/common/disposable/IDisposable.ts @@ -0,0 +1,5 @@ +export interface IDisposable +{ + dispose(): Promise; + disposed: boolean; +} diff --git a/src/core/common/disposable/index.ts b/src/core/common/disposable/index.ts new file mode 100644 index 0000000..2edb6e9 --- /dev/null +++ b/src/core/common/disposable/index.ts @@ -0,0 +1,2 @@ +export * from './Disposable'; +export * from './IDisposable'; diff --git a/src/core/common/index.ts b/src/core/common/index.ts new file mode 100644 index 0000000..0c22eea --- /dev/null +++ b/src/core/common/index.ts @@ -0,0 +1,3 @@ +export * from './disposable'; +export * from './INitroManager'; +export * from './NitroManager'; diff --git a/src/core/configuration/ConfigurationManager.ts b/src/core/configuration/ConfigurationManager.ts new file mode 100644 index 0000000..760001c --- /dev/null +++ b/src/core/configuration/ConfigurationManager.ts @@ -0,0 +1,113 @@ +import fetch from 'node-fetch'; +import { NitroManager } from '../common'; +import { AdvancedMap } from '../utils'; +import { IConfigurationManager } from './IConfigurationManager'; + +export class ConfigurationManager extends NitroManager implements IConfigurationManager +{ + private _definitions: AdvancedMap; + + constructor() + { + super(); + + this._definitions = new AdvancedMap(); + } + + protected async onInit(): Promise + { + await this.loadConfigurationFromUrl((process.env.CONFIG_URL || null)); + } + + private async loadConfigurationFromUrl(url: string): Promise + { + if(!url || (url === '')) return Promise.reject('invalid_config_url'); + + try + { + const response = await fetch(url); + const json = await response.json(); + + if(!this.parseConfiguration(json)) return Promise.reject('invalid_config'); + } + + catch(err) + { + return Promise.reject(err); + } + } + + private parseConfiguration(data: { [index: string]: any }): boolean + { + if(!data) return false; + + try + { + const regex = new RegExp(/\${(.*?)}/g); + + for(const key in data) + { + let value = data[key]; + + if(typeof value === 'string') + { + value = this.interpolate((value as string), regex); + } + + this._definitions.add(key, value); + } + + return true; + } + + catch (e) + { + this.logger.error(e.stack); + + return false; + } + } + + public interpolate(value: string, regex: RegExp = null): string + { + if(!regex) regex = new RegExp(/\${(.*?)}/g); + + const pieces = value.match(regex); + + if(pieces && pieces.length) + { + for(const piece of pieces) + { + const existing = (this._definitions.getValue(this.removeInterpolateKey(piece)) as string); + + if(existing) (value = value.replace(piece, existing)); + } + } + + return value; + } + + private removeInterpolateKey(value: string): string + { + return value.replace('${', '').replace('}', ''); + } + + public getValue(key: string, value: T = null): T + { + let existing = this._definitions.getValue(key); + + if(existing === undefined) + { + this.logger.warn(`Missing configuration key: ${ key }`); + + existing = value; + } + + return (existing as T); + } + + public setValue(key: string, value: string): void + { + this._definitions.add(key, value); + } +} diff --git a/src/core/configuration/IConfigurationManager.ts b/src/core/configuration/IConfigurationManager.ts new file mode 100644 index 0000000..1d18a8f --- /dev/null +++ b/src/core/configuration/IConfigurationManager.ts @@ -0,0 +1,8 @@ +import { INitroManager } from '../common/INitroManager'; + +export interface IConfigurationManager extends INitroManager +{ + interpolate(value: string, regex?: RegExp): string; + getValue(key: string, value?: T): T; + setValue(key: string, value: string): void; +} \ No newline at end of file diff --git a/src/core/configuration/index.ts b/src/core/configuration/index.ts new file mode 100644 index 0000000..7a9be69 --- /dev/null +++ b/src/core/configuration/index.ts @@ -0,0 +1,2 @@ +export * from './ConfigurationManager'; +export * from './IConfigurationManager'; diff --git a/src/core/index.ts b/src/core/index.ts new file mode 100644 index 0000000..7c38b28 --- /dev/null +++ b/src/core/index.ts @@ -0,0 +1,7 @@ +export * from './asset'; +export * from './common'; +export * from './configuration'; +export * from './INitroCore'; +export * from './logger'; +export * from './NitroCore'; +export * from './utils'; diff --git a/src/core/logger/INitroLogger.ts b/src/core/logger/INitroLogger.ts new file mode 100644 index 0000000..0416a50 --- /dev/null +++ b/src/core/logger/INitroLogger.ts @@ -0,0 +1,8 @@ +export interface INitroLogger +{ + log(message: any): void; + error(message: any, trace?: any): void; + warn(message: any): void; + description: string | number; + print: boolean; +} diff --git a/src/core/logger/NitroLogger.ts b/src/core/logger/NitroLogger.ts new file mode 100644 index 0000000..a234067 --- /dev/null +++ b/src/core/logger/NitroLogger.ts @@ -0,0 +1,79 @@ +import chalk = require("chalk"); +import { INitroLogger } from './INitroLogger'; + +export class NitroLogger implements INitroLogger +{ + private static LAST_TIMESTAMP: number = Date.now(); + + private _name: string; + private _description: string | number; + private _print: boolean; + + constructor(name: string, description: string | number = null) + { + this._name = name; + this._description = description; + this._print = true; + } + + public log(message: any): void + { + this.printMessage(message, chalk.green); + } + + public error(message: any, trace: any = null): void + { + this.printMessage(trace || message, chalk.red); + } + + public warn(message: any): void + { + this.printMessage(message, chalk.yellow); + } + + private printMessage(message: any, color: Function = null): void + { + if(!this._print) return; + + process.stdout.write(` ${ color(`[Nitro]`) } `); + + if(this._name !== null) process.stdout.write(chalk.cyan(`[${ this._name }] `)); + + if(this._description !== null) process.stdout.write(chalk.gray(`[${ this._description }] `)); + + process.stdout.write(color(message)); + + this.printTimestamp(); + + process.stdout.write(`\n`); + } + + private printTimestamp(): void + { + const now = Date.now(); + + process.stdout.write(chalk.gray(` +${ now - NitroLogger.LAST_TIMESTAMP || 0 }ms`)); + + NitroLogger.LAST_TIMESTAMP = now; + } + + public get description(): string | number + { + return this._description; + } + + public set description(description: string | number) + { + this._description = description; + } + + public get print(): boolean + { + return this._print; + } + + public set print(flag: boolean) + { + this._print = flag; + } +} diff --git a/src/core/logger/index.ts b/src/core/logger/index.ts new file mode 100644 index 0000000..147aa16 --- /dev/null +++ b/src/core/logger/index.ts @@ -0,0 +1,2 @@ +export * from './INitroLogger'; +export * from './NitroLogger'; diff --git a/src/core/utils/AdvancedMap.ts b/src/core/utils/AdvancedMap.ts new file mode 100644 index 0000000..f7e883b --- /dev/null +++ b/src/core/utils/AdvancedMap.ts @@ -0,0 +1,157 @@ +export class AdvancedMap +{ + private _length: number; + private _dictionary: Map; + private _array: U[]; + private _keys: T[]; + + constructor(map: Map = null) + { + this._length = 0; + this._dictionary = new Map(); + this._array = []; + this._keys = []; + + if(map) for(const [ key, value ] of map.entries()) this.add(key, value); + } + + public get length(): number + { + return this._length; + } + + public get disposed(): boolean + { + return (!this._dictionary); + } + + public dispose(): void + { + if(!this._dictionary) + { + for(const key of this._dictionary.keys()) this._dictionary.delete(key); + + this._dictionary = null; + } + + this._length = 0; + this._array = null; + this._keys = null; + } + + public reset(): void + { + for(const key of this._dictionary.keys()) this._dictionary.delete(key); + + this._length = 0; + this._array = []; + this._keys = []; + } + + public unshift(key: T, value: U): boolean + { + if(this._dictionary.get(key) !== null) return false; + + this._dictionary.set(key, value); + + this._array.unshift(value); + this._keys.unshift(key); + + this._length++; + + return true; + } + + public add(key: T, value: U): boolean + { + if(this._dictionary.get(key) !== undefined) return false; + + this._dictionary.set(key, value); + + this._array[this._length] = value; + this._keys[this._length] = key; + + this._length++; + + return true; + } + + public remove(key: T): U + { + const value = this._dictionary.get(key); + + if(!value) return null; + + const index = this._array.indexOf(value); + + if(index >= 0) + { + this._array.splice(index, 1); + this._keys.splice(index, 1); + + this._length--; + } + + this._dictionary.delete(key); + + return value; + } + + public getWithIndex(index: number): U + { + if((index < 0) || (index >= this._length)) return null; + + return this._array[index]; + } + + public getKey(index: number): T + { + if((index < 0) || (index >= this._length)) return null; + + return this._keys[index]; + } + + public getKeys(): T[] + { + return this._keys.slice(); + } + + public hasKey(key: T): boolean + { + return (this._keys.indexOf(key) > -1); + } + + public getValue(key: T): U + { + return this._dictionary.get(key); + } + + public getValues(): U[] + { + return this._array.slice(); + } + + public hasValue(value: U): boolean + { + return (this._array.indexOf(value) > -1); + } + + public indexOf(value: U): number + { + return this._array.indexOf(value); + } + + public concatenate(newValues: AdvancedMap): void + { + for(const k of newValues._keys) this.add(k, newValues.getValue(k)); + } + + public clone(): AdvancedMap + { + const map = new AdvancedMap(); + + map.concatenate(this); + + return map; + } +} diff --git a/src/core/utils/BinaryReader.ts b/src/core/utils/BinaryReader.ts new file mode 100644 index 0000000..3f1293f --- /dev/null +++ b/src/core/utils/BinaryReader.ts @@ -0,0 +1,47 @@ +import { wrap } from 'bytebuffer'; +export class BinaryReader +{ + private _position: number; + private _dataView: ByteBuffer; + + constructor(buffer: ArrayBuffer) + { + this._position = 0; + this._dataView = wrap(buffer); + } + + public readByte(): number + { + return this._dataView.readInt8(); + } + + public readBytes(length: number): ByteBuffer + { + return this._dataView.readBytes(length); + } + + public readShort(): number + { + return this._dataView.readInt16(this._position); + } + + public readInt(): number + { + return this._dataView.readInt32(this._position); + } + + public remaining(): number + { + return this._dataView.remaining(); + } + + public toString(encoding?: string): string + { + return new TextDecoder().decode(this._dataView.buffer); + } + + public toArrayBuffer(): ArrayBuffer + { + return this._dataView.buffer; + } +} diff --git a/src/core/utils/File.ts b/src/core/utils/File.ts new file mode 100644 index 0000000..5ff7c3a --- /dev/null +++ b/src/core/utils/File.ts @@ -0,0 +1,43 @@ +import { existsSync, lstatSync, mkdirSync, readdirSync, RmOptions, rmSync } from 'fs'; + +export class File +{ + private readonly _path: string; + + constructor(path: string) + { + this._path = path; + } + + public exists(): boolean + { + return existsSync(this._path); + } + + public mkdirs(): void + { + return mkdirSync(this._path); + } + + public list(): string[] + { + const test = readdirSync(this._path); + + return test; + } + + public isDirectory(): boolean + { + return this.exists() && lstatSync(this._path).isDirectory(); + } + + public rmdir(options: RmOptions): void + { + return rmSync(this._path, options); + } + + public get path(): string + { + return this._path; + } +} diff --git a/src/core/utils/FileUtilities.ts b/src/core/utils/FileUtilities.ts new file mode 100644 index 0000000..7bf3a38 --- /dev/null +++ b/src/core/utils/FileUtilities.ts @@ -0,0 +1,75 @@ +import { readFile } from 'fs'; +import fetch from 'node-fetch'; +import { promisify } from 'util'; +import { File } from './File'; + +const readFileAsync = promisify(readFile); + +export class FileUtilities +{ + public static getDirectory(baseFolderPath: string, childFolderName: string = null): File + { + let folder = new File(baseFolderPath); + + if(!folder.isDirectory()) folder.mkdirs(); + + if(childFolderName) + { + folder = new File(folder.path + childFolderName); + + if(!folder.isDirectory()) folder.mkdirs(); + } + + return folder; + } + + public static async readFileAsBuffer(url: string): Promise + { + if(!url) return null; + + let content: Buffer = null; + + if(url.startsWith('//')) url = ('https:' + url); + + if(url.startsWith('http')) + { + const data = await fetch(url); + const arrayBuffer = await data.arrayBuffer(); + + if(data.headers.get('Content-Type') !== 'application/octet-stream') return; + + if(arrayBuffer) content = Buffer.from(arrayBuffer); + } + else + { + content = await readFileAsync(url); + } + + return content; + } + + public static async readFileAsString(url: string): Promise + { + if(!url) return null; + + let content = null; + + if(url.startsWith('//')) url = ('https:' + url); + + if(url.startsWith('http')) + { + const data = await fetch(url); + if(data.status === 404) return null; + + if(data) content = await data.text(); + } + else + { + const data = await readFileAsync(url); + + content = data.toString('utf-8'); + } + + return content; + } +} diff --git a/src/core/utils/Point.ts b/src/core/utils/Point.ts new file mode 100644 index 0000000..aa6b7e2 --- /dev/null +++ b/src/core/utils/Point.ts @@ -0,0 +1,36 @@ +export class Point +{ + public x = 0; + public y = 0; + + constructor(x: number = 0, y: number = 0) + { + this.x = x; + this.y = y; + } + + public clone(): Point + { + return new Point(this.x, this.y); + } + + public copyFrom(p: Point): Point + { + this.add(p.x, p.y); + + return this; + } + + public equals(p: Point): boolean + { + return ((p.x === this.x) && (p.y === this.y)); + } + + public set(x: number = 0, y: number = x): Point + { + this.x = x; + this.y = y; + + return this; + } +} diff --git a/src/core/utils/Rectangle.ts b/src/core/utils/Rectangle.ts new file mode 100644 index 0000000..cc85ea8 --- /dev/null +++ b/src/core/utils/Rectangle.ts @@ -0,0 +1,125 @@ +export class Rectangle +{ + public x: number; + public y: number; + public width: number; + public height: number; + + constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public clone(): Rectangle + { + return new Rectangle(this.x, this.y, this.width, this.height); + } + + public copyFrom(rectangle: Rectangle): Rectangle + { + this.x = rectangle.x; + this.y = rectangle.y; + this.width = rectangle.width; + this.height = rectangle.height; + + return this; + } + + public copyTo(rectangle: Rectangle): Rectangle + { + rectangle.x = this.x; + rectangle.y = this.y; + rectangle.width = this.width; + rectangle.height = this.height; + + return rectangle; + } + + public contains(x: number, y: number): boolean + { + if(this.width <= 0 || this.height <= 0) return false; + + if(x >= this.x && x < this.x + this.width) + { + if(y >= this.y && y < this.y + this.height) return true; + } + + return false; + } + + public pad(paddingX: number = 0, paddingY: number = paddingX): Rectangle + { + this.x -= paddingX; + this.y -= paddingY; + this.width += paddingX * 2; + this.height += paddingY * 2; + + return this; + } + + public fit(rectangle: Rectangle): Rectangle + { + const x1 = Math.max(this.x, rectangle.x); + const x2 = Math.min(this.x + this.width, rectangle.x + rectangle.width); + const y1 = Math.max(this.y, rectangle.y); + const y2 = Math.min(this.y + this.height, rectangle.y + rectangle.height); + + this.x = x1; + this.width = Math.max(x2 - x1, 0); + this.y = y1; + this.height = Math.max(y2 - y1, 0); + + return this; + } + + public ceil(resolution: number = 1, eps: number = 0.001): Rectangle + { + const x2 = Math.ceil((this.x + this.width - eps) * resolution) / resolution; + const y2 = Math.ceil((this.y + this.height - eps) * resolution) / resolution; + + this.x = Math.floor((this.x + eps) * resolution) / resolution; + this.y = Math.floor((this.y + eps) * resolution) / resolution; + this.width = x2 - this.x; + this.height = y2 - this.y; + + return this; + } + + public enlarge(rectangle: Rectangle): Rectangle + { + const x1 = Math.min(this.x, rectangle.x); + const x2 = Math.max(this.x + this.width, rectangle.x + rectangle.width); + const y1 = Math.min(this.y, rectangle.y); + const y2 = Math.max(this.y + this.height, rectangle.y + rectangle.height); + + this.x = x1; + this.width = x2 - x1; + this.y = y1; + this.height = y2 - y1; + + return this; + } + + public get left(): number + { + return this.x; + } + + public get right(): number + { + return this.x + this.width; + } + + public get top(): number + { + return this.y; + } + + public get bottom(): number + { + return this.y + this.height; + } +} diff --git a/src/core/utils/index.ts b/src/core/utils/index.ts new file mode 100644 index 0000000..270ad8d --- /dev/null +++ b/src/core/utils/index.ts @@ -0,0 +1,6 @@ +export * from './AdvancedMap'; +export * from './BinaryReader'; +export * from './File'; +export * from './FileUtilities'; +export * from './Point'; +export * from './Rectangle'; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..104b80d --- /dev/null +++ b/src/main.ts @@ -0,0 +1,24 @@ +require('dotenv').config(); + +import { Application } from './app'; +import { NitroCore } from './core'; + +const core = new NitroCore(); +const instance = new Application(core); + +async function init(): Promise +{ + try + { + await instance.init(); + } + + catch(err) + { + console.error(err.message || err); + + core.dispose(); + } +} + +init();