Dependency injection + prerendered alpha

This commit is contained in:
SpreedBLood 2021-02-15 17:13:43 +01:00
parent 7a7d913282
commit cf97fd6862
38 changed files with 940 additions and 373 deletions

525
package-lock.json generated
View File

@ -4,6 +4,14 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.12.13",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.13.tgz",
"integrity": "sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"@gizeta/swf-reader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@gizeta/swf-reader/-/swf-reader-1.0.0.tgz",
@ -12,6 +20,327 @@
"lzma-purejs": "~0.9.3"
}
},
"@jimp/bmp": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.1.tgz",
"integrity": "sha512-iwyNYQeBawrdg/f24x3pQ5rEx+/GwjZcCXd3Kgc+ZUd+Ivia7sIqBsOnDaMZdKCBPlfW364ekexnlOqyVa0NWg==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"bmp-js": "^0.1.0"
}
},
"@jimp/core": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.16.1.tgz",
"integrity": "sha512-la7kQia31V6kQ4q1kI/uLimu8FXx7imWVajDGtwUG8fzePLWDFJyZl0fdIXVCL1JW2nBcRHidUot6jvlRDi2+g==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"any-base": "^1.1.0",
"buffer": "^5.2.0",
"exif-parser": "^0.1.12",
"file-type": "^9.0.0",
"load-bmfont": "^1.3.1",
"mkdirp": "^0.5.1",
"phin": "^2.9.1",
"pixelmatch": "^4.0.2",
"tinycolor2": "^1.4.1"
}
},
"@jimp/custom": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.16.1.tgz",
"integrity": "sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/core": "^0.16.1"
}
},
"@jimp/gif": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.16.1.tgz",
"integrity": "sha512-r/1+GzIW1D5zrP4tNrfW+3y4vqD935WBXSc8X/wm23QTY9aJO9Lw6PEdzpYCEY+SOklIFKaJYUAq/Nvgm/9ryw==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"gifwrap": "^0.9.2",
"omggif": "^1.0.9"
}
},
"@jimp/jpeg": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.16.1.tgz",
"integrity": "sha512-8352zrdlCCLFdZ/J+JjBslDvml+fS3Z8gttdml0We759PnnZGqrnPRhkOEOJbNUlE+dD4ckLeIe6NPxlS/7U+w==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"jpeg-js": "0.4.2"
}
},
"@jimp/plugin-blit": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.16.1.tgz",
"integrity": "sha512-fKFNARm32RoLSokJ8WZXHHH2CGzz6ire2n1Jh6u+XQLhk9TweT1DcLHIXwQMh8oR12KgjbgsMGvrMVlVknmOAg==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-blur": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.16.1.tgz",
"integrity": "sha512-1WhuLGGj9MypFKRcPvmW45ht7nXkOKu+lg3n2VBzIB7r4kKNVchuI59bXaCYQumOLEqVK7JdB4glaDAbCQCLyw==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-circle": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.16.1.tgz",
"integrity": "sha512-JK7yi1CIU7/XL8hdahjcbGA3V7c+F+Iw+mhMQhLEi7Q0tCnZ69YJBTamMiNg3fWPVfMuvWJJKOBRVpwNTuaZRg==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-color": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.16.1.tgz",
"integrity": "sha512-9yQttBAO5SEFj7S6nJK54f+1BnuBG4c28q+iyzm1JjtnehjqMg6Ljw4gCSDCvoCQ3jBSYHN66pmwTV74SU1B7A==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"tinycolor2": "^1.4.1"
}
},
"@jimp/plugin-contain": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.16.1.tgz",
"integrity": "sha512-44F3dUIjBDHN+Ym/vEfg+jtjMjAqd2uw9nssN67/n4FdpuZUVs7E7wadKY1RRNuJO+WgcD5aDQcsvurXMETQTg==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-cover": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.16.1.tgz",
"integrity": "sha512-YztWCIldBAVo0zxcQXR+a/uk3/TtYnpKU2CanOPJ7baIuDlWPsG+YE4xTsswZZc12H9Kl7CiziEbDtvF9kwA/Q==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-crop": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.16.1.tgz",
"integrity": "sha512-UQdva9oQzCVadkyo3T5Tv2CUZbf0klm2cD4cWMlASuTOYgaGaFHhT9st+kmfvXjKL8q3STkBu/zUPV6PbuV3ew==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-displace": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.16.1.tgz",
"integrity": "sha512-iVAWuz2+G6Heu8gVZksUz+4hQYpR4R0R/RtBzpWEl8ItBe7O6QjORAkhxzg+WdYLL2A/Yd4ekTpvK0/qW8hTVw==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-dither": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.16.1.tgz",
"integrity": "sha512-tADKVd+HDC9EhJRUDwMvzBXPz4GLoU6s5P7xkVq46tskExYSptgj5713J5Thj3NMgH9Rsqu22jNg1H/7tr3V9Q==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-fisheye": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.1.tgz",
"integrity": "sha512-BWHnc5hVobviTyIRHhIy9VxI1ACf4CeSuCfURB6JZm87YuyvgQh5aX5UDKtOz/3haMHXBLP61ZBxlNpMD8CG4A==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-flip": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.16.1.tgz",
"integrity": "sha512-KdxTf0zErfZ8DyHkImDTnQBuHby+a5YFdoKI/G3GpBl3qxLBvC+PWkS2F/iN3H7wszP7/TKxTEvWL927pypT0w==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-gaussian": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.1.tgz",
"integrity": "sha512-u9n4wjskh3N1mSqketbL6tVcLU2S5TEaFPR40K6TDv4phPLZALi1Of7reUmYpVm8mBDHt1I6kGhuCJiWvzfGyg==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-invert": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.16.1.tgz",
"integrity": "sha512-2DKuyVXANH8WDpW9NG+PYFbehzJfweZszFYyxcaewaPLN0GxvxVLOGOPP1NuUTcHkOdMFbE0nHDuB7f+sYF/2w==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-mask": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.16.1.tgz",
"integrity": "sha512-snfiqHlVuj4bSFS0v96vo2PpqCDMe4JB+O++sMo5jF5mvGcGL6AIeLo8cYqPNpdO6BZpBJ8MY5El0Veckhr39Q==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-normalize": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.16.1.tgz",
"integrity": "sha512-dOQfIOvGLKDKXPU8xXWzaUeB0nvkosHw6Xg1WhS1Z5Q0PazByhaxOQkSKgUryNN/H+X7UdbDvlyh/yHf3ITRaw==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-print": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.16.1.tgz",
"integrity": "sha512-ceWgYN40jbN4cWRxixym+csyVymvrryuKBQ+zoIvN5iE6OyS+2d7Mn4zlNgumSczb9GGyZZESIgVcBDA1ezq0Q==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"load-bmfont": "^1.4.0"
}
},
"@jimp/plugin-resize": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz",
"integrity": "sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-rotate": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.16.1.tgz",
"integrity": "sha512-ZUU415gDQ0VjYutmVgAYYxC9Og9ixu2jAGMCU54mSMfuIlmohYfwARQmI7h4QB84M76c9hVLdONWjuo+rip/zg==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-scale": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.16.1.tgz",
"integrity": "sha512-jM2QlgThIDIc4rcyughD5O7sOYezxdafg/2Xtd1csfK3z6fba3asxDwthqPZAgitrLgiKBDp6XfzC07Y/CefUw==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-shadow": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.16.1.tgz",
"integrity": "sha512-MeD2Is17oKzXLnsphAa1sDstTu6nxscugxAEk3ji0GV1FohCvpHBcec0nAq6/czg4WzqfDts+fcPfC79qWmqrA==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugin-threshold": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.16.1.tgz",
"integrity": "sha512-iGW8U/wiCSR0+6syrPioVGoSzQFt4Z91SsCRbgNKTAk7D+XQv6OI78jvvYg4o0c2FOlwGhqz147HZV5utoSLxA==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1"
}
},
"@jimp/plugins": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.16.1.tgz",
"integrity": "sha512-c+lCqa25b+4q6mJZSetlxhMoYuiltyS+ValLzdwK/47+aYsq+kcJNl+TuxIEKf59yr9+5rkbpsPkZHLF/V7FFA==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/plugin-blit": "^0.16.1",
"@jimp/plugin-blur": "^0.16.1",
"@jimp/plugin-circle": "^0.16.1",
"@jimp/plugin-color": "^0.16.1",
"@jimp/plugin-contain": "^0.16.1",
"@jimp/plugin-cover": "^0.16.1",
"@jimp/plugin-crop": "^0.16.1",
"@jimp/plugin-displace": "^0.16.1",
"@jimp/plugin-dither": "^0.16.1",
"@jimp/plugin-fisheye": "^0.16.1",
"@jimp/plugin-flip": "^0.16.1",
"@jimp/plugin-gaussian": "^0.16.1",
"@jimp/plugin-invert": "^0.16.1",
"@jimp/plugin-mask": "^0.16.1",
"@jimp/plugin-normalize": "^0.16.1",
"@jimp/plugin-print": "^0.16.1",
"@jimp/plugin-resize": "^0.16.1",
"@jimp/plugin-rotate": "^0.16.1",
"@jimp/plugin-scale": "^0.16.1",
"@jimp/plugin-shadow": "^0.16.1",
"@jimp/plugin-threshold": "^0.16.1",
"timm": "^1.6.1"
}
},
"@jimp/png": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.16.1.tgz",
"integrity": "sha512-iyWoCxEBTW0OUWWn6SveD4LePW89kO7ZOy5sCfYeDM/oTPLpR8iMIGvZpZUz1b8kvzFr27vPst4E5rJhGjwsdw==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/utils": "^0.16.1",
"pngjs": "^3.3.3"
}
},
"@jimp/tiff": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.16.1.tgz",
"integrity": "sha512-3K3+xpJS79RmSkAvFMgqY5dhSB+/sxhwTFA9f4AVHUK0oKW+u6r52Z1L0tMXHnpbAdR9EJ+xaAl2D4x19XShkQ==",
"requires": {
"@babel/runtime": "^7.7.2",
"utif": "^2.0.1"
}
},
"@jimp/types": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.16.1.tgz",
"integrity": "sha512-g1w/+NfWqiVW4CaXSJyD28JQqZtm2eyKMWPhBBDCJN9nLCN12/Az0WFF3JUAktzdsEC2KRN2AqB1a2oMZBNgSQ==",
"requires": {
"@babel/runtime": "^7.7.2",
"@jimp/bmp": "^0.16.1",
"@jimp/gif": "^0.16.1",
"@jimp/jpeg": "^0.16.1",
"@jimp/png": "^0.16.1",
"@jimp/tiff": "^0.16.1",
"timm": "^1.6.1"
}
},
"@jimp/utils": {
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.16.1.tgz",
"integrity": "sha512-8fULQjB0x4LzUSiSYG6ZtQl355sZjxbv8r9PPAuYHzS9sGiSHJQavNqK/nKnpDsVkU88/vRGcE7t3nMU0dEnVw==",
"requires": {
"@babel/runtime": "^7.7.2",
"regenerator-runtime": "^0.13.3"
}
},
"@jvitela/mustache-wax": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@jvitela/mustache-wax/-/mustache-wax-1.0.3.tgz",
@ -38,6 +367,11 @@
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-0.1.1.tgz",
"integrity": "sha1-tcdcUyBS3M1qOcAGTHcsjVegbNI="
},
"any-base": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz",
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
},
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@ -71,6 +405,11 @@
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
@ -93,9 +432,18 @@
}
},
"bmp-js": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz",
"integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo="
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
"integrity": "sha1-4Fpj95amwf8l9Hcex62twUjAcjM="
},
"buffer": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
"requires": {
"base64-js": "^1.3.1",
"ieee754": "^1.1.13"
}
},
"buffer-crc32": {
"version": "0.2.13",
@ -209,9 +557,9 @@
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"file-type": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-9.0.0.tgz",
"integrity": "sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw=="
},
"forever-agent": {
"version": "0.6.1",
@ -238,6 +586,59 @@
"maxrects-packer": "^2.5.0",
"mustache": "^2.3.0",
"tinify": "^1.5.0"
},
"dependencies": {
"bmp-js": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz",
"integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo="
},
"file-type": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
},
"jimp": {
"version": "0.2.28",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz",
"integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=",
"requires": {
"bignumber.js": "^2.1.0",
"bmp-js": "0.0.3",
"es6-promise": "^3.0.2",
"exif-parser": "^0.1.9",
"file-type": "^3.1.0",
"jpeg-js": "^0.2.0",
"load-bmfont": "^1.2.3",
"mime": "^1.3.4",
"mkdirp": "0.5.1",
"pixelmatch": "^4.0.0",
"pngjs": "^3.0.0",
"read-chunk": "^1.0.1",
"request": "^2.65.0",
"stream-to-buffer": "^0.1.0",
"tinycolor2": "^1.1.2",
"url-regex": "^3.0.0"
}
},
"jpeg-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz",
"integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII="
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
}
}
},
"getpass": {
@ -248,6 +649,15 @@
"assert-plus": "^1.0.0"
}
},
"gifwrap": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.2.tgz",
"integrity": "sha512-fcIswrPaiCDAyO8xnWvHSZdWChjKXUanKKpAiWWJ/UTkEi/aYKn5+90e7DE820zbEaVR9CE2y4z9bzhQijZ0BA==",
"requires": {
"image-q": "^1.1.1",
"omggif": "^1.0.10"
}
},
"global": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
@ -281,6 +691,16 @@
"sshpk": "^1.7.0"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
},
"image-q": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/image-q/-/image-q-1.1.1.tgz",
"integrity": "sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@ -312,32 +732,21 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"jimp": {
"version": "0.2.28",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz",
"integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=",
"version": "0.16.1",
"resolved": "https://registry.npmjs.org/jimp/-/jimp-0.16.1.tgz",
"integrity": "sha512-+EKVxbR36Td7Hfd23wKGIeEyHbxShZDX6L8uJkgVW3ESA9GiTEPK08tG1XI2r/0w5Ch0HyJF5kPqF9K7EmGjaw==",
"requires": {
"bignumber.js": "^2.1.0",
"bmp-js": "0.0.3",
"es6-promise": "^3.0.2",
"exif-parser": "^0.1.9",
"file-type": "^3.1.0",
"jpeg-js": "^0.2.0",
"load-bmfont": "^1.2.3",
"mime": "^1.3.4",
"mkdirp": "0.5.1",
"pixelmatch": "^4.0.0",
"pngjs": "^3.0.0",
"read-chunk": "^1.0.1",
"request": "^2.65.0",
"stream-to-buffer": "^0.1.0",
"tinycolor2": "^1.1.2",
"url-regex": "^3.0.0"
"@babel/runtime": "^7.7.2",
"@jimp/custom": "^0.16.1",
"@jimp/plugins": "^0.16.1",
"@jimp/types": "^0.16.1",
"regenerator-runtime": "^0.13.3"
}
},
"jpeg-js": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz",
"integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII="
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.2.tgz",
"integrity": "sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw=="
},
"jpg-stream": {
"version": "1.1.2",
@ -445,16 +854,16 @@
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "0.0.8"
"minimist": "^1.2.5"
}
},
"mustache": {
@ -477,6 +886,16 @@
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"omggif": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
"integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
},
"parse-bmfont-ascii": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz",
@ -589,6 +1008,16 @@
"string_decoder": "~0.10.x"
}
},
"reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
},
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@ -678,6 +1107,11 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
},
"timm": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz",
"integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw=="
},
"tinify": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/tinify/-/tinify-1.5.0.tgz",
@ -701,6 +1135,19 @@
"punycode": "^2.1.1"
}
},
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"tsyringe": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.4.0.tgz",
"integrity": "sha512-SlMApe1lhIq546CDp7bF+IdF4RB6d+9C5T7B0AS0P/Bm+Qpizj/gEmZzvw9J/KlXPEt4qHTbi1TRvX3rCPSdTg==",
"requires": {
"tslib": "^1.9.3"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -730,6 +1177,14 @@
"ip-regex": "^1.0.1"
}
},
"utif": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/utif/-/utif-2.0.1.tgz",
"integrity": "sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg==",
"requires": {
"pako": "^1.0.5"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",

View File

@ -14,12 +14,15 @@
"bytebuffer": "^5.0.1",
"concat-frames": "^1.0.3",
"free-tex-packer-core": "^0.3.2",
"jimp": "^0.16.1",
"jpg-stream": "^1.1.2",
"lodash": "^4.17.20",
"node-fetch": "^2.6.1",
"node-gzip": "^1.1.2",
"png-stream": "^1.0.5",
"reflect-metadata": "^0.1.13",
"stream-to-array": "^2.3.0",
"tsyringe": "^4.4.0",
"xml2js": "^0.4.23"
},
"devDependencies": {}

View File

@ -1,123 +1,34 @@
import "reflect-metadata";
import Configuration from "./config/Configuration";
import FigureDownloader from "./downloaders/FigureDownloader";
import HabboAssetSWF from "./swf/HabboAssetSWF";
import SpriteSheetConverter from "./converters/util/SpriteSheetConverter";
import FigureConverter from "./converters/figure/FigureConverter";
import File from "./utils/File";
import FurnitureDownloader from "./downloaders/FurnitureDownloader";
import FurnitureConverter from "./converters/furniture/FurnitureConverter";
import EffectConverter from "./converters/effect/EffectConverter";
import EffectDownloader from "./downloaders/EffectDownloader";
import PetDownloader from "./downloaders/PetDownloader";
import PetConverter from "./converters/pet/PetConverter";
import {container} from "tsyringe";
import FigureConverter from "./figure/FigureConverter";
import FurnitureConverter from "./furniture/FurnitureConverter";
import PetConverter from "./pet/PetConverter";
import EffectConverter from "./effect/EffectConverter";
(async () => {
const config = new Configuration();
const config = container.resolve(Configuration);
await config.init();
const outputFolderFigure = new File(config.getValue("output.folder.figure"));
if (!outputFolderFigure.isDirectory()) {
outputFolderFigure.mkdirs();
}
const outputFolderFurniture = new File(config.getValue("output.folder.furniture"));
if (!outputFolderFurniture.isDirectory()) {
outputFolderFurniture.mkdirs();
}
const outputFolderEffect = new File(config.getValue("output.folder.effect"));
if (!outputFolderEffect.isDirectory()) {
outputFolderEffect.mkdirs();
}
const outputFolderPet = new File(config.getValue("output.folder.pet"));
if (!outputFolderPet.isDirectory()) {
outputFolderPet.mkdirs();
}
const spriteSheetConverter = new SpriteSheetConverter();
const figureConverter = new FigureConverter(config);
const furnitureConverter = new FurnitureConverter(config);
const effectConverter = new EffectConverter(config);
const petConverter = new PetConverter();
if (config.getBoolean("convert.figure")) {
const figureDownloader = new FigureDownloader(config);
await figureDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing figure: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, outputFolderFigure.path, "figure");
if (spriteSheetType !== null)
await figureConverter.fromHabboAsset(habboAssetSwf, outputFolderFigure.path, "figure", spriteSheetType);
} catch (e) {
console.log("Figure error: " + habboAssetSwf.getDocumentClass());
console.log(e);
}
});
const figureConverter = container.resolve(FigureConverter);
await figureConverter.convertAsync();
}
if (config.getBoolean("convert.furniture")) {
let count = 0;
const furnitureDownloader = new FurnitureDownloader(config);
await furnitureDownloader.download(async function (habboAssetSwf: HabboAssetSWF, className: string) {
console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, outputFolderFurniture.path, "furniture");
if (spriteSheetType !== null) {
await furnitureConverter.fromHabboAsset(habboAssetSwf, outputFolderFurniture.path, "furniture", spriteSheetType);
}
} catch (e) {
console.log("Furniture error: " + habboAssetSwf.getDocumentClass());
console.log(e);
}
});
console.log(`Parsed ${++count} furnitures`)
}
if (config.getBoolean("convert.effect")) {
const effectDownloader = new EffectDownloader(config);
await effectDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing effect: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, outputFolderFurniture.path, "effect");
if (spriteSheetType !== null) {
await effectConverter.fromHabboAsset(habboAssetSwf, outputFolderEffect.path, "effect", spriteSheetType);
}
} catch (e) {
console.log(e);
console.log("Effect error: " + habboAssetSwf.getDocumentClass());
}
});
const furnitureConverter = container.resolve(FurnitureConverter);
await furnitureConverter.convertAsync();
}
if (config.getBoolean("convert.pet")) {
const petDownloader = new PetDownloader(config);
await petDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing pet: " + habboAssetSwf.getDocumentClass());
const petConverter = container.resolve(PetConverter);
await petConverter.convertAsync();
}
try {
const spriteSheetType = await spriteSheetConverter.generateSpriteSheet(habboAssetSwf, outputFolderPet.path, "pet");
if (spriteSheetType !== null) {
await petConverter.fromHabboAsset(habboAssetSwf, outputFolderPet.path, "pet", spriteSheetType);
}
} catch (e) {
console.log(e);
console.log("Pet error: " + habboAssetSwf.getDocumentClass());
}
});
if (config.getBoolean("convert.effect")) {
const effectConverter = container.resolve(EffectConverter);
await effectConverter.convertAsync();
}
console.log('finished!');
/*outputFolderEffect.rmdir({
recursive: true,
force: true
});*/
})()

View File

@ -1,14 +1,16 @@
let {packAsync} = require("free-tex-packer-core");
import HabboAssetSWF from "../swf/HabboAssetSWF";
import BundleTypes from "./BundleTypes";
import SymbolClassTag from "../swf/tags/SymbolClassTag";
import ImageTag from "../swf/tags/ImageTag";
import {singleton} from "tsyringe";
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import SymbolClassTag from "../../swf/tags/SymbolClassTag";
import ImageTag from "../../swf/tags/ImageTag";
import ArchiveType from "../ArchiveType";
const {packAsync} = require('free-tex-packer-core');
export default class SpriteSheetConverter {
@singleton()
export default class BundleProvider {
public static imageSource: Map<string, string> = new Map<string, string>();
public async generateSpriteSheet(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string): Promise<ArchiveType | null> {
public async generateSpriteSheet(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string): Promise<BundleTypes | null> {
const tagList: Array<SymbolClassTag> = habboAssetSWF.symbolTags();
const names: Array<string> = new Array<string>();
const tags: Array<number> = new Array<number>();
@ -31,7 +33,7 @@ export default class SpriteSheetConverter {
(names[i].includes("_64_") && type === "pet")) {
if (names[i] !== imageTag.className) {
SpriteSheetConverter.imageSource.set(names[i].substring(habboAssetSWF.getDocumentClass().length + 1), imageTag.className.substring(habboAssetSWF.getDocumentClass().length + 1));
BundleProvider.imageSource.set(names[i].substring(habboAssetSWF.getDocumentClass().length + 1), imageTag.className.substring(habboAssetSWF.getDocumentClass().length + 1));
if ((imageTag.className.includes("_32_") && type === "furniture") ||
(imageTag.className.includes("_sh_") && (type === "figure" || type === "effect")) ||
(imageTag.className.includes("_32_") && type === "pet")) {
@ -47,6 +49,7 @@ export default class SpriteSheetConverter {
}
if ((imageTag.className.includes("_64_") && type === "furniture") ||
(imageTag.className.includes("_1_") && type === "furniture") ||
(imageTag.className.includes("_icon_") && type === "furniture") ||
(imageTag.className.includes("_h_") && (type === "figure" || type === "effect")) ||
(imageTag.className.includes("_64_") && type === "pet")) {
@ -57,6 +60,7 @@ export default class SpriteSheetConverter {
}
}
if (images.length === 0) {
return null;
}
@ -64,7 +68,7 @@ export default class SpriteSheetConverter {
return await this.packImages(habboAssetSWF.getDocumentClass(), outputFolder + "/", images);
}
async packImages(documentClass: string, outputFolder: string, images: Array<{ path: string, contents: Buffer }>): Promise<ArchiveType | null> {
async packImages(documentClass: string, outputFolder: string, images: Array<{ path: string, contents: Buffer }>): Promise<BundleTypes | null> {
let options = {
textureName: documentClass,
width: 3072,
@ -76,7 +80,7 @@ export default class SpriteSheetConverter {
exporter: "Pixi"
};
const archiveType: ArchiveType = {} as any;
const archiveType: BundleTypes = {} as any;
const imageData: {
name: string,
buffer: Buffer
@ -103,6 +107,7 @@ export default class SpriteSheetConverter {
archiveType.spriteSheetType.meta.image = imageData.name;
archiveType.imageData = imageData;
}
return archiveType;
}
}

View File

@ -1,3 +1,11 @@
export default interface BundleTypes {
spriteSheetType: SpriteSheetType,
imageData: {
name: string,
buffer: Buffer
}
}
export interface SpriteSheetType {
frames: SpriteSheetFrames,
meta: SpriteSheetMeta

View File

@ -3,11 +3,11 @@
"output.folder.figure": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/figure-test/",
"output.folder.effect": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/effect-test/",
"output.folder.pet": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/pet-test/",
"furnidata.url": "http://assets.nitro.se/game/gamedata/furnidata-entry.xml",
"figuremap.url": "http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/figuremap.xml",
"furnidata.url": "http://assets.nitro.se/game/harmony/furnidata.xml",
"figuremap.url": "http://assets.nitro.se/game/gordon/figuremap.xml",
"effectmap.url": "http://assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/effectmap.xml",
"external_vars.url": "http://assets.nitro.se/game/gamedata/external_variables.txt",
"dynamic.download.url.furniture": "/home/user/WebstormProjects/sites/assets.nitro.se/game/dcr/endrit/hof_furni/%className%.swf",
"dynamic.download.url.furniture": "/home/user/WebstormProjects/sites/assets.nitro.se/game/harmony/hof_furni/%className%.swf",
"dynamic.download.url.figure": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf",
"dynamic.download.url.effect": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf",
"dynamic.download.url.pet": "/home/user/WebstormProjects/sites/assets.nitro.se/game/gordon/PRODUCTION-201701242205-837386173/%className%.swf",

View File

@ -1,8 +1,11 @@
import {singleton} from "tsyringe";
const fs = require('fs/promises');
const fetch = require('node-fetch');
const config = require('../config.json');
@singleton()
export default class Configuration {
private readonly _config: Map<string, string>;

View File

@ -1,9 +0,0 @@
import {SpriteSheetType} from "./util/SpriteSheetTypes";
export default interface ArchiveType {
spriteSheetType: SpriteSheetType,
imageData: {
name: string,
buffer: Buffer
}
}

View File

@ -1,65 +0,0 @@
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
import Configuration from "../../config/Configuration";
import FigureJsonMapper from "./FigureJsonMapper";
import {FigureJson} from "./FigureJsonType";
import File from "../../utils/File";
import ArchiveType from "../ArchiveType";
import NitroBundle from "../../utils/NitroBundle";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
export default class FigureConverter {
private readonly _figureJsonMapper: FigureJsonMapper;
constructor(config: Configuration) {
this._figureJsonMapper = new FigureJsonMapper(config);
}
private getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
let binaryName: string = habboAssetSWF.getFullClassName(type, documentNameTwice);
let tag = habboAssetSWF.getBinaryTagByName(binaryName);
if (tag === null) {
binaryName = habboAssetSWF.getFullClassNameSnake(type, documentNameTwice, true);
tag = habboAssetSWF.getBinaryTagByName(binaryName);
}
return tag;
}
private async convertXML2JSON(habboAssetSWF: HabboAssetSWF): Promise<FigureJson | null> {
const manifestXML: DefineBinaryDataTag | null = this.getBinaryData(habboAssetSWF, "manifest", false);
if (manifestXML !== null) {
const result = await parser.parseStringPromise(manifestXML.binaryData);
return this._figureJsonMapper.mapXML(habboAssetSWF, result);
}
return null;
}
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
const manifestJson = await this.convertXML2JSON(habboAssetSWF);
if (manifestJson !== null) {
manifestJson.spritesheet = archiveType.spriteSheetType;
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
const assetOuputFolder = new File(path);
if (assetOuputFolder.exists()) {
console.log("Figure already exists or the directory is not empty!");
return;
}
const nitroBundle = new NitroBundle();
nitroBundle.addFile(habboAssetSWF.getDocumentClass() + ".json", Buffer.from(JSON.stringify(manifestJson)));
nitroBundle.addFile(archiveType.imageData.name, archiveType.imageData.buffer);
const buffer = await nitroBundle.toBufferAsync();
await fs.writeFile(path, buffer);
}
}
}

View File

@ -1,22 +1,27 @@
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
import ArchiveType from "../ArchiveType";
import File from "../../utils/File";
import NitroBundle from "../../utils/NitroBundle";
import {EffectJson} from "./EffectTypes";
import Configuration from "../../config/Configuration";
import EffectJsonMapper from "./EffectJsonMapper";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../swf/tags/DefineBinaryDataTag";
import {EffectJson} from "./mapper/EffectTypes";
import BundleTypes from "../bundle/BundleTypes";
import File from "../utils/File";
import NitroBundle from "../utils/NitroBundle";
import EffectDownloader from "./EffectDownloader";
import EffectJsonMapper from "./mapper/EffectJsonMapper";
import Configuration from "../config/Configuration";
import BundleProvider from "../bundle/BundleProvider";
import {singleton} from "tsyringe";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
@singleton()
export default class EffectConverter {
private readonly _effectJsonMapper: EffectJsonMapper;
constructor(config: Configuration) {
this._effectJsonMapper = new EffectJsonMapper();
constructor(
private readonly _effectDownloader: EffectDownloader,
private readonly _effectJsonMapper: EffectJsonMapper,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider) {
}
private static getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
@ -55,15 +60,15 @@ export default class EffectConverter {
return this._effectJsonMapper.mapXML(habboAssetSWF, manifestXML, animationXML);
}
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: BundleTypes) {
const effectJson = await this.convertXML2JSON(habboAssetSWF);
if (effectJson !== null) {
effectJson.spritesheet = archiveType.spriteSheetType;
effectJson.type = type;
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
const assetOuputFolder = new File(path);
if (assetOuputFolder.exists()) {
const assetOutputFolder = new File(path);
if (assetOutputFolder.exists()) {
console.log("Effect already exists or the directory is not empty!");
return;
@ -77,4 +82,26 @@ export default class EffectConverter {
await fs.writeFile(path, buffer);
}
}
public async convertAsync() {
const outputFolderEffect = new File(this._config.getValue("output.folder.effect"));
if (!outputFolderEffect.isDirectory()) {
outputFolderEffect.mkdirs();
}
const effectConverter = this;
await this._effectDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing effect: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await effectConverter._bundleProvider.generateSpriteSheet(habboAssetSwf, outputFolderEffect.path, "effect");
if (spriteSheetType !== null) {
await effectConverter.fromHabboAsset(habboAssetSwf, outputFolderEffect.path, "effect", spriteSheetType);
}
} catch (e) {
console.log(e);
console.log("Effect error: " + habboAssetSwf.getDocumentClass());
}
});
}
}

View File

@ -1,19 +1,21 @@
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fetch = require('node-fetch');
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
@singleton()
export default class EffectDownloader {
private readonly _config: Configuration;
constructor(config: Configuration) {
this._config = config;
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
public static types: Map<string, string> = new Map<string, string>();
public async download(callback: (habboAssetSwf: HabboAssetSWF) => Promise<void>) {
@ -21,7 +23,6 @@ export default class EffectDownloader {
const figureMap = await this.parseEffectMap();
const map = figureMap.map;
let count = 0;
for (const lib of map.effect) {
const info = lib['$'];
const className: string = info.lib;
@ -48,7 +49,7 @@ export default class EffectDownloader {
const file = new File(url);
if (!file.exists()) {
console.log("SWF File does not exist: " + file.path);
return;
continue;
}
}
@ -59,8 +60,7 @@ export default class EffectDownloader {
EffectDownloader.types.set(className, info.type);
await callback(newHabboAssetSWF);
} catch (e) {
console.log(className);
console.log(e);
await this._logger.logErrorAsync(`[${className}]` + e);
}
}
}

View File

@ -12,41 +12,44 @@ import {
Frame,
Fx, Item, Override, Remove, Shadow, Sprite
} from "./EffectTypes";
import EffectDownloader from "../../downloaders/EffectDownloader";
import {ManifestXML} from "./EffectManifestXMLTypes";
import SpriteSheetConverter from "../util/SpriteSheetConverter";
import {
AnimationXML,
BodyPartXML
} from "./EffectAnimationXMLTypes";
import {singleton} from "tsyringe";
import EffectDownloader from "../EffectDownloader";
import BundleProvider from "../../bundle/BundleProvider";
@singleton()
export default class EffectJsonMapper {
public static readonly MUST_START_WITH: string = "h_";
public mapXML(habboAssetSWF: HabboAssetSWF, manifest: any, animation: any): EffectJson {
const name = habboAssetSWF.getDocumentClass();
const result = {} as EffectJson;
result.name = name;
result.type = EffectDownloader.types.get(name) as string;
EffectJsonMapper.mapManifestXML(new ManifestXML(manifest), result);
this.mapManifestXML(new ManifestXML(manifest), result);
EffectJsonMapper.mapAnimationXML(new AnimationXML(animation), result);
return result;
}
private static mapManifestXML(manifestXML: ManifestXML, output: EffectJson) {
private mapManifestXML(manifestXML: ManifestXML, output: EffectJson) {
const assets: AssetsJSON = {};
for (const assetXML of manifestXML.library.assets) {
if (assetXML.name.startsWith(this.MUST_START_WITH)) {
if (assetXML.name.startsWith(EffectJsonMapper.MUST_START_WITH)) {
const asset: AssetJSON = {} as any;
if (assetXML.param != undefined && assetXML.param.value !== undefined) {
asset.x = parseInt(assetXML.param.value.split(",")[0]);
asset.y = parseInt(assetXML.param.value.split(",")[1]);
}
if (SpriteSheetConverter.imageSource.has(assetXML.name)) {
asset.source = SpriteSheetConverter.imageSource.get(assetXML.name) as any;
if (BundleProvider.imageSource.has(assetXML.name)) {
asset.source = BundleProvider.imageSource.get(assetXML.name) as string;
}
assets[assetXML.name] = asset;
@ -55,10 +58,10 @@ export default class EffectJsonMapper {
output.assets = assets;
if (manifestXML.library.aliases.length > 0 || SpriteSheetConverter.imageSource.size > 0) {
if (manifestXML.library.aliases.length > 0 || BundleProvider.imageSource.size > 0) {
const aliases: Aliases = {};
for (const aliasXML of manifestXML.library.aliases) {
if (aliasXML.name.startsWith(this.MUST_START_WITH)) {
if (aliasXML.name.startsWith(EffectJsonMapper.MUST_START_WITH)) {
const alias: Alias = {} as any;
alias.link = aliasXML.link;

View File

@ -1,4 +1,4 @@
import {SpriteSheetType} from "../util/SpriteSheetTypes";
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface EffectJson {
type: string,

View File

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

View File

@ -1,18 +1,19 @@
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fs = require("fs");
const fetch = require('node-fetch');
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
@singleton()
export default class FigureDownloader {
private readonly _config: Configuration;
constructor(config: Configuration) {
this._config = config;
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
@ -36,36 +37,35 @@ export default class FigureDownloader {
}
if (!FigureDownloader.types.has(className)) {
if (className !== "jacket_U_snowwar4_team1" &&
className !== "jacket_U_snowwar4_team2") { //TODO: Figure out why snowstorm assets aren't converting...
if (className !== "hh_human_hats") continue;
const url = this._config.getValue("dynamic.download.url.figure").replace("%className%", className);
let buffer: Buffer | null = null;
const url = this._config.getValue("dynamic.download.url.figure").replace("%className%", className);
let buffer: Buffer | null = null;
if (url.includes("http")) {
const fetchData = await fetch(url);
if (fetchData.status === 404) {
console.log("SWF File does not exist: " + url);
continue;
}
const arrayBuffer = await fetchData.arrayBuffer();
buffer = Buffer.from(arrayBuffer);
} else {
const file = new File(url);
if (!file.exists()) {
console.log("SWF File does not exist: " + file.path);
return;
}
if (url.includes("http")) {
const fetchData = await fetch(url);
if (fetchData.status === 404) {
console.log("SWF File does not exist: " + url);
continue;
}
const arrayBuffer = await fetchData.arrayBuffer();
buffer = Buffer.from(arrayBuffer);
} else {
const file = new File(url);
if (!file.exists()) {
console.log("SWF File does not exist: " + file.path);
continue;
}
}
try {
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(buffer !== null ? buffer : url);
await newHabboAssetSWF.setupAsync();
FigureDownloader.types.set(className, lib.part[0]['$'].type);
await callback(newHabboAssetSWF);
} catch (e) {
await this._logger.logErrorAsync("[" + className + "]" + e);
}
}
}

View File

@ -1,18 +1,19 @@
import Configuration from "../../config/Configuration";
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import {FigureAsset, FigureAssets, FigureJson} from "./FigureJsonType";
import FigureDownloader from "../../downloaders/FigureDownloader";
import SpriteSheetConverter from "../util/SpriteSheetConverter";
import {FigureXMLManifest} from "./FigureXMLTypes";
import FigureDownloader from "../FigureDownloader";
import {singleton} from "tsyringe";
import BundleProvider from "../../bundle/BundleProvider";
@singleton()
export default class FigureJsonMapper {
private static MUST_START_WITH: string = "h_";
private readonly _config: Configuration;
constructor(config: Configuration) {
this._config = config;
constructor(
private readonly _config: Configuration
) {
}
@ -47,8 +48,8 @@ export default class FigureJsonMapper {
figureAsset.x = parseFloat(asset.param.value.split(',')[0]);
figureAsset.y = parseFloat(asset.param.value.split(',')[1]);
if (SpriteSheetConverter.imageSource.has(name)) {
figureAsset.source = SpriteSheetConverter.imageSource.get(name) as string;
if (BundleProvider.imageSource.has(name)) {
figureAsset.source = BundleProvider.imageSource.get(name) as string;
}
assets[name] = figureAsset;

View File

@ -1,4 +1,4 @@
import {SpriteSheetType} from "../util/SpriteSheetTypes";
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface FigureJson {
type: string,

View File

@ -1,23 +1,30 @@
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
import Configuration from "../../config/Configuration";
import FurniJsonMapper from "./FurniJsonMapper";
import {FurniJson} from "./FurniTypes";
import File from "../../utils/File";
import ArchiveType from "../ArchiveType";
import NitroBundle from "../../utils/NitroBundle";
import FurniJsonMapper from "./mapper/FurniJsonMapper";
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import DefineBinaryDataTag from "../swf/tags/DefineBinaryDataTag";
import {FurniJson} from "./mapper/FurniTypes";
import BundleTypes from "../bundle/BundleTypes";
import File from "../utils/File";
import NitroBundle from "../utils/NitroBundle";
import BundleProvider from "../bundle/BundleProvider";
import FurnitureDownloader from "./FurnitureDownloader";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
@singleton()
export default class FurnitureConverter {
private readonly _furniJsonMapper: FurniJsonMapper;
constructor(config: Configuration) {
this._furniJsonMapper = new FurniJsonMapper();
constructor(
private readonly _furniDownloader: FurnitureDownloader,
private readonly _furniJsonMapper: FurniJsonMapper,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider,
private readonly _logger: Logger) {
}
private static getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
@ -76,15 +83,15 @@ export default class FurnitureConverter {
return this._furniJsonMapper.mapXML(assetXml, indexXml, logicXml, visualizationXml);
}
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: BundleTypes) {
const furnitureJson = await this.convertXML2JSON(habboAssetSWF);
if (furnitureJson !== null) {
furnitureJson.spritesheet = archiveType.spriteSheetType;
furnitureJson.type = type;
const path = outputFolder + "/" + habboAssetSWF.getDocumentClass() + ".nitro";
const assetOuputFolder = new File(path);
if (assetOuputFolder.exists()) {
const assetOutputFolder = new File(path);
if (assetOutputFolder.exists()) {
console.log("Furniture already exists or the directory is not empty!");
return;
@ -98,4 +105,25 @@ export default class FurnitureConverter {
await fs.writeFile(path, buffer);
}
}
public async convertAsync() {
const outputFolderFurniture = new File(this._config.getValue("output.folder.furniture"));
if (!outputFolderFurniture.isDirectory()) {
outputFolderFurniture.mkdirs();
}
const furnitureConverter = this;
await this._furniDownloader.download(async function (habboAssetSwf: HabboAssetSWF, className: string) {
console.log("Attempt parsing furniture: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await furnitureConverter._bundleProvider.generateSpriteSheet(habboAssetSwf, outputFolderFurniture.path, "furniture");
if (spriteSheetType !== null) {
await furnitureConverter.fromHabboAsset(habboAssetSwf, outputFolderFurniture.path, "furniture", spriteSheetType);
}
} catch (e) {
await furnitureConverter._logger.logErrorAsync("Furniture error: " + habboAssetSwf.getDocumentClass() + " " + e);
}
});
}
}

View File

@ -2,6 +2,8 @@ import HabboAssetSWF from "../swf/HabboAssetSWF";
import Configuration from "../config/Configuration";
import {type} from "os";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fs = require("fs");
const fetch = require('node-fetch');
@ -11,12 +13,12 @@ const util = require('util');
const readFile = util.promisify(fs.readFile);
@singleton()
export default class FurnitureDownloader {
private readonly _config: Configuration;
constructor(config: Configuration) {
this._config = config;
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
public async download(callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>) {
@ -67,9 +69,7 @@ export default class FurnitureDownloader {
}
async extractFurniture(revision: string, className: string, callback: (habboAssetSwf: HabboAssetSWF, className: string) => Promise<void>) {
//if (className !== "rare_dragonlamp" && className !== "tiki_bflies" && className !== "room_wl15_ele") return;
//if (className !== 'scifidoor') return;
//if (/*className !== 'present_wrap' && */className !== 'holo_dragon') return;
const url = this._config.getValue("dynamic.download.url.furniture").replace("%revision%", revision).replace("%className%", className);
let buffer: Buffer | null = null;
@ -97,8 +97,7 @@ export default class FurnitureDownloader {
await callback(newHabboAssetSWF, className);
} catch (e) {
console.log("Error with furniture: " + url);
console.log(e);
await this._logger.logErrorAsync(`Error with furniture: ${url} \n ${e}`);
}
}

View File

@ -22,7 +22,6 @@ import {
Visualization,
VisualizationLayers
} from "./FurniTypes";
import SpriteSheetConverter from "../util/SpriteSheetConverter";
import {AssetsXML, IndexXML, LogicXML} from "./FurniXMLTypes";
import {
AnimationLayerXML,
@ -32,8 +31,10 @@ import {
VisualizationDataXML,
VisualizationXML
} from "./VisualizationXMLTypes";
import {log} from "util";
import BundleProvider from "../../bundle/BundleProvider";
import {singleton} from "tsyringe";
@singleton()
export default class FurniJsonMapper {
private static readonly VISUALIZATION_DEFAULT_SIZE = 64;
@ -42,7 +43,7 @@ export default class FurniJsonMapper {
public mapXML(assets: any, indexXML: any, logic: any, visualization: any): FurniJson {
const furniJson: FurniJson = {} as any;
FurniJsonMapper.mapAssetsXML(new AssetsXML(assets), furniJson);
this.mapAssetsXML(new AssetsXML(assets), furniJson);
FurniJsonMapper.mapIndexXML(new IndexXML(indexXML.object), furniJson);
FurniJsonMapper.mapLogicXML(new LogicXML(logic.objectData), furniJson);
FurniJsonMapper.mapVisualizationXML(new VisualizationDataXML(visualization.visualizationData), furniJson);
@ -51,7 +52,7 @@ export default class FurniJsonMapper {
}
private static mapAssetsXML(assetsXML: AssetsXML, output: FurniJson) {
private mapAssetsXML(assetsXML: AssetsXML, output: FurniJson) {
const assets: FurniAssets = {} as any;
for (const asset of assetsXML.assets) {
@ -60,13 +61,13 @@ export default class FurniJsonMapper {
if (asset.source !== undefined) {
furniAsset.source = asset.source;
if (SpriteSheetConverter.imageSource.has(asset.source)) {
furniAsset.source = SpriteSheetConverter.imageSource.get(asset.source) as string;
if (BundleProvider.imageSource.has(asset.source)) {
furniAsset.source = BundleProvider.imageSource.get(asset.source) as string;
}
}
if (SpriteSheetConverter.imageSource.has(asset.name)) {
furniAsset.source = SpriteSheetConverter.imageSource.get(asset.name) as string;
if (BundleProvider.imageSource.has(asset.name)) {
furniAsset.source = BundleProvider.imageSource.get(asset.name) as string;
}
if (asset.x !== undefined)
@ -158,7 +159,8 @@ export default class FurniJsonMapper {
const layers: VisualizationLayers = {};
for (const layerXML of layersXML) {
const layer: Layer = {} as any;
layer.alpha = layerXML.alpha;
if (layerXML.alpha !== undefined)
layer.alpha = parseInt(layerXML.alpha.toString());
layer.ink = layerXML.ink;
layer.tag = layerXML.tag;
@ -253,9 +255,15 @@ export default class FurniJsonMapper {
const animationLayers: AnimationLayers = {};
for (const animationLayerXML of animationXML.layers) {
const animationLayer: AnimationLayer = {} as any;
animationLayer.frameRepeat = animationLayerXML.frameRepeat;
animationLayer.loopCount = animationLayerXML.loopCount;
animationLayer.random = animationLayerXML.random;
if (animationLayerXML.frameRepeat !== undefined)
animationLayer.frameRepeat = parseInt(animationLayerXML.frameRepeat.toString());
if (animationLayerXML.loopCount !== undefined)
animationLayer.loopCount = parseInt(animationLayerXML.loopCount.toString());
if (animationLayerXML.random !== undefined)
animationLayer.random = parseInt(animationLayerXML.random.toString());
if (animationLayerXML.frameSequences.length > 0) {
animationLayer.frameSequences = FurniJsonMapper.mapVisualizationFrameSequenceXML(animationLayerXML);
@ -277,10 +285,16 @@ export default class FurniJsonMapper {
const frames: Frames = {};
for (const frameXML of frameSequenceXML.frames) {
const frame: Frame = {} as any;
frame.x = frameXML.x;
frame.y = frameXML.y;
frame.randomX = frameXML.randomX;
frame.randomY = frameXML.randomY;
if (frameXML.x !== undefined)
frame.x = parseInt(frameXML.x.toString());
if (frameXML.y !== undefined)
frame.y = parseInt(frameXML.y.toString());
if (frameXML.randomX !== undefined)
frame.randomX = parseInt(frameXML.randomX.toString());
if (frameXML.randomY !== undefined)
frame.randomY = parseInt(frameXML.randomY.toString());
if (frameXML.id === "NaN") {
frame.id = 0;
} else {

View File

@ -1,4 +1,4 @@
import {SpriteSheetType} from "../util/SpriteSheetTypes";
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface FurniJson {
type: string,

View File

@ -1,22 +1,28 @@
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import ArchiveType from "../ArchiveType";
import File from "../../utils/File";
import NitroBundle from "../../utils/NitroBundle";
import {FurniJson} from "../furniture/FurniTypes";
import DefineBinaryDataTag from "../../swf/tags/DefineBinaryDataTag";
import PetJsonMapper from "./PetJsonMapper";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import BundleTypes from "../bundle/BundleTypes";
import File from "../utils/File";
import NitroBundle from "../utils/NitroBundle";
import DefineBinaryDataTag from "../swf/tags/DefineBinaryDataTag";
import PetJsonMapper from "./mapper/PetJsonMapper";
import {PetJson} from "./mapper/PetTypes";
import Configuration from "../config/Configuration";
import BundleProvider from "../bundle/BundleProvider";
import PetDownloader from "./PetDownloader";
import {singleton} from "tsyringe";
const xml2js = require('xml2js');
const parser = new xml2js.Parser(/* options */);
const fs = require('fs').promises;
@singleton()
export default class PetConverter {
private readonly _petJsonMapper: PetJsonMapper;
constructor() {
this._petJsonMapper = new PetJsonMapper();
constructor(
private readonly _petDownloader: PetDownloader,
private readonly _petJsonMapper: PetJsonMapper,
private readonly _config: Configuration,
private readonly _bundleProvider: BundleProvider) {
}
private static getBinaryData(habboAssetSWF: HabboAssetSWF, type: string, documentNameTwice: boolean) {
@ -66,7 +72,7 @@ export default class PetConverter {
return null;
}
private async convertXML2JSON(habboAssetSWF: HabboAssetSWF): Promise<FurniJson | null> {
private async convertXML2JSON(habboAssetSWF: HabboAssetSWF): Promise<PetJson | null> {
const assetXml = await PetConverter.getAssetsXML(habboAssetSWF);
const logicXml = await PetConverter.getLogicXML(habboAssetSWF);
const indexXml = await PetConverter.getIndexXML(habboAssetSWF);
@ -75,7 +81,7 @@ export default class PetConverter {
return this._petJsonMapper.mapXML(habboAssetSWF, assetXml, indexXml, logicXml, visualizationXml);
}
public async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: ArchiveType) {
private async fromHabboAsset(habboAssetSWF: HabboAssetSWF, outputFolder: string, type: string, archiveType: BundleTypes) {
const petJson = await this.convertXML2JSON(habboAssetSWF);
if (petJson !== null) {
petJson.spritesheet = archiveType.spriteSheetType;
@ -97,4 +103,26 @@ export default class PetConverter {
await fs.writeFile(path, buffer);
}
}
public async convertAsync() {
const outputFolderPet = new File(this._config.getValue("output.folder.pet"));
if (!outputFolderPet.isDirectory()) {
outputFolderPet.mkdirs();
}
const petConverter = this;
await this._petDownloader.download(async function (habboAssetSwf: HabboAssetSWF) {
console.log("Attempt parsing pet: " + habboAssetSwf.getDocumentClass());
try {
const spriteSheetType = await petConverter._bundleProvider.generateSpriteSheet(habboAssetSwf, outputFolderPet.path, "pet");
if (spriteSheetType !== null) {
await petConverter.fromHabboAsset(habboAssetSwf, outputFolderPet.path, "pet", spriteSheetType);
}
} catch (e) {
console.log(e);
console.log("Pet error: " + habboAssetSwf.getDocumentClass());
}
});
}
}

View File

@ -1,14 +1,16 @@
import Configuration from "../config/Configuration";
import HabboAssetSWF from "../swf/HabboAssetSWF";
import File from "../utils/File";
import {singleton} from "tsyringe";
import Logger from "../utils/Logger";
const fetch = require('node-fetch');
@singleton()
export default class PetDownloader {
private readonly _config: Configuration;
constructor(config: Configuration) {
this._config = config;
constructor(
private readonly _config: Configuration,
private readonly _logger: Logger) {
}
public async download(callback: (habboAssetSwf: HabboAssetSWF) => Promise<void>) {
@ -39,6 +41,7 @@ export default class PetDownloader {
const arrayBuffer = await fetchData.arrayBuffer();
buffer = Buffer.from(arrayBuffer);
console.log(buffer.toString('utf-8'));
} else {
const file = new File(url);
if (!file.exists()) {
@ -47,10 +50,14 @@ export default class PetDownloader {
}
}
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(buffer !== null ? buffer : url);
await newHabboAssetSWF.setupAsync();
try {
const newHabboAssetSWF: HabboAssetSWF = new HabboAssetSWF(buffer !== null ? buffer : url);
await newHabboAssetSWF.setupAsync();
await callback(newHabboAssetSWF);
await callback(newHabboAssetSWF);
} catch (e) {
await this._logger.logErrorAsync(`[${pet}]` + e);
}
}
itemClassNames.push(pet);

View File

@ -1,4 +1,3 @@
import SpriteSheetConverter from "../util/SpriteSheetConverter";
import {
Action, Animation, AnimationLayer, AnimationLayers, Animations, Color, ColorLayer, ColorLayers, Colors,
Direction,
@ -21,9 +20,12 @@ import {
} from "./VisualizationXMLTypes";
import HabboAssetSWF from "../../swf/HabboAssetSWF";
import RGB from "./RGB";
import BundleProvider from "../../bundle/BundleProvider";
import {singleton} from "tsyringe";
const ByteBuffer = require('bytebuffer');
@singleton()
export default class PetJsonMapper {
@ -52,13 +54,13 @@ export default class PetJsonMapper {
if (asset.source !== undefined) {
petAsset.source = asset.source;
if (SpriteSheetConverter.imageSource.has(asset.source)) {
petAsset.source = SpriteSheetConverter.imageSource.get(asset.source) as string;
if (BundleProvider.imageSource.has(asset.source)) {
petAsset.source = BundleProvider.imageSource.get(asset.source) as string;
}
}
if (SpriteSheetConverter.imageSource.has(asset.name)) {
petAsset.source = SpriteSheetConverter.imageSource.get(asset.name) as string;
if (BundleProvider.imageSource.has(asset.name)) {
petAsset.source = BundleProvider.imageSource.get(asset.name) as string;
}
petAsset.x = parseInt(asset.x.toString());

View File

@ -1,4 +1,4 @@
import {SpriteSheetType} from "../util/SpriteSheetTypes";
import {SpriteSheetType} from "../../bundle/BundleTypes";
export interface PetJson {
type: string,

View File

@ -1,4 +1,4 @@
import {readImagesDefineBitsLossless, readImagesJPEG, readSwfAsync} from "../utils/SwfReader";
import {ImageTagData, readImagesDefineBitsLossless, readImagesJPEG, readSwfAsync} from "../utils/SwfReader";
import ITag from "./tags/ITag";
import SymbolClassTag from "./tags/SymbolClassTag";
import DefineBinaryDataTag from "./tags/DefineBinaryDataTag";
@ -38,12 +38,14 @@ export default class HabboAssetSWF {
break;
case 35:
const jpegTag = await readImagesJPEG(35, tag);
const jpegTag: any = await readImagesJPEG(35, tag);
this._tags.push(new ImageTag({
code: jpegTag.code,
characterID: jpegTag.characterId,
imgType: jpegTag.imgType,
imgData: jpegTag.imgData
imgData: jpegTag.imgData,
bitmapWidth: jpegTag.bitmapWidth,
bitmapHeight: jpegTag.bitmapHeight
}));
break;
@ -53,7 +55,9 @@ export default class HabboAssetSWF {
code: pngTag.code,
characterID: pngTag.characterId,
imgType: pngTag.imgType,
imgData: pngTag.imgData
imgData: pngTag.imgData,
bitmapWidth: pngTag.bitmapWidth,
bitmapHeight: pngTag.bitmapHeight
}));
break;

View File

@ -8,7 +8,10 @@ export default class ImageTag extends CharacterTag implements ITag {
private readonly _imgType: string;
private readonly _imgData: Buffer;
constructor(image: { code: number, characterID: number, imgType: string, imgData: Buffer }) {
private readonly _bitmapWidth: number;
private readonly _bitmapHeight: number;
constructor(image: { code: number, characterID: number, imgType: string, imgData: Buffer, bitmapWidth: number, bitmapHeight: number }) {
super();
this._code = image.code;
@ -17,6 +20,9 @@ export default class ImageTag extends CharacterTag implements ITag {
this._imgData = image.imgData;
this.characterId = this._characterID;
this._bitmapWidth = image.bitmapWidth;
this._bitmapHeight = image.bitmapHeight;
}
get code(): number {
@ -34,4 +40,12 @@ export default class ImageTag extends CharacterTag implements ITag {
get imgData(): Buffer {
return this._imgData;
}
get bitmapWidth(): number {
return this._bitmapWidth;
}
get bitmapHeight(): number {
return this._bitmapHeight;
}
}

19
src/utils/Logger.ts Normal file
View File

@ -0,0 +1,19 @@
import {singleton} from "tsyringe";
const fs = require('fs');
const fsAsync = require('fs/promises');
@singleton()
export default class Logger {
constructor() {
if (!fs.existsSync("error.log")) {
const createStream = fs.createWriteStream("error.log");
createStream.end();
}
}
public logErrorAsync(message: string): Promise<void> {
return fsAsync.appendFile("error.log", message + "\n");
}
}

View File

@ -164,6 +164,15 @@ export async function readImagesJPEG(code: number, tagData: any): Promise<any> {
});
}
export interface ImageTagData {
code: number,
characterId: number,
imgType: string,
imgData: Buffer,
bitmapWidth: number,
bitmapHeight: number
}
export function readImagesDefineBitsLossless(tag: any) {
const characterId = tag.characterId,
bitmapFormat = tag.bitmapFormat,
@ -188,9 +197,9 @@ export function readImagesDefineBitsLossless(tag: any) {
for (var y = 0; y < bitmapHeight; ++y) {
for (var x = 0; x < bitmapWidth; ++x) {
var alpha = dataBuf[ptr];
output[index] = dataBuf[ptr + 1];
output[index + 1] = dataBuf[ptr + 2];
output[index + 2] = dataBuf[ptr + 3];
output[index] = dataBuf[ptr + 1] * (255 / alpha);
output[index + 1] = dataBuf[ptr + 2] * (255 / alpha);
output[index + 2] = dataBuf[ptr + 3] * (255 / alpha);
output[index + 3] = alpha;
index += 4;
ptr += 4;
@ -231,7 +240,9 @@ export function readImagesDefineBitsLossless(tag: any) {
code: 36,
characterId: characterId,
imgType: 'png',
imgData: Buffer.concat(buffers)
imgData: Buffer.concat(buffers),
bitmapWidth: bitmapWidth,
bitmapHeight: bitmapHeight
});
});
}).catch(function (e) {

View File

@ -9,7 +9,9 @@
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": [
"src/config.json",