├── .editorconfig ├── .erb ├── configs │ ├── .eslintrc │ ├── webpack.config.base.ts │ ├── webpack.config.eslint.ts │ ├── webpack.config.main.prod.ts │ ├── webpack.config.renderer.dev.dll.ts │ ├── webpack.config.renderer.dev.ts │ ├── webpack.config.renderer.prod.ts │ └── webpack.paths.ts ├── img │ ├── erb-banner.svg │ └── erb-logo.png ├── mocks │ └── fileMock.js └── scripts │ ├── .eslintrc │ ├── check-build-exists.ts │ ├── check-native-dep.js │ ├── check-node-env.js │ ├── check-port-in-use.js │ ├── clean.js │ ├── delete-source-maps.js │ ├── electron-rebuild.js │ ├── link-modules.ts │ └── notarize.js ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github └── workflows │ └── release.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── COMMAND.md ├── FAQ.md ├── LICENSE ├── README.md ├── assets ├── NanumSquareB.woff ├── NanumSquareEB.woff ├── NanumSquareL.woff ├── NanumSquareR.woff ├── adb │ ├── AdbWinApi.dll │ ├── AdbWinUsbApi.dll │ └── adb.exe ├── arrowLeft.svg ├── asFilePaths.lock ├── assets.d.ts ├── boot_ffc6.as ├── delta.png ├── discord.svg ├── entitlements.mac.plist ├── extract.svg ├── ffdec │ ├── CHANGELOG.md │ ├── ffdec.jar │ ├── lib │ │ ├── JavactiveX.jar │ │ ├── LZMA.jar │ │ ├── avi.jar │ │ ├── avi.montemedia.license.txt │ │ ├── cmykjpeg.jar │ │ ├── ddsreader.jar │ │ ├── ffdec_lib.jar │ │ ├── ffdec_lib.license.txt │ │ ├── flamingo-6.2.jar │ │ ├── flamingo.license.txt │ │ ├── flashdebugger.jar │ │ ├── gif.jar │ │ ├── gif.license.txt │ │ ├── gnujpdf.jar │ │ ├── graphs.jar │ │ ├── jargs.jar │ │ ├── jl.license.txt │ │ ├── jl1.0.1.jar │ │ ├── jna-3.5.1.jar │ │ ├── jna.license.txt │ │ ├── jpacker.jar │ │ ├── jpacker.license.txt │ │ ├── jpproxy.jar │ │ ├── jpproxy.muffin.license.txt │ │ ├── jsyntaxpane-0.9.5.jar │ │ ├── jsyntaxpane.license.txt │ │ ├── minimal-json-0.9.5.jar │ │ ├── minimal-json.license.txt │ │ ├── nellymoser.jar │ │ ├── nellymoser.license.txt │ │ ├── sfntly.jar │ │ ├── sfntly.license.txt │ │ ├── substance-6.2.jar │ │ ├── substance-flamingo-6.2.jar │ │ ├── substance-flamingo.license.txt │ │ ├── substance.license.txt │ │ ├── tablelayout.jar │ │ ├── treetable.jar │ │ ├── trident-6.2.jar │ │ ├── trident.license.txt │ │ ├── ttf.doubletype.license.txt │ │ ├── ttf.fontastic.license.txt │ │ └── ttf.jar │ └── license.txt ├── filePaths.lock ├── folder.svg ├── github.png ├── icon.icns ├── icon.ico ├── icons │ ├── 1024x1024.png │ ├── 128x128.png │ ├── 16x16.png │ ├── 24x24.png │ ├── 256x256.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 512x512.png │ ├── 64x64.png │ └── 96x96.png ├── images │ ├── ch10.jpg │ ├── ch10_banner.png │ ├── ch10_special.gif │ ├── ch10_spin.png │ ├── ch10_walk.gif │ ├── couette.jpg │ ├── couette_banner.png │ ├── couette_special.gif │ ├── couette_spin.png │ ├── couette_walk.gif │ ├── theo.jpg │ ├── theo_banner.png │ ├── theo_special.gif │ ├── theo_spin.png │ └── theo_walk.gif ├── info.svg ├── item_bronze.png ├── item_gold.png ├── item_rainbow.png ├── item_silver.png ├── item_white.png ├── settings.svg ├── trash.svg └── viewer.svg ├── package.json ├── release └── app │ ├── package.json │ └── yarn.lock ├── src ├── main │ ├── flatomo │ │ ├── customTweenRecord.ts │ │ ├── customTweenTools.ts │ │ ├── graphicsLoopKindTools.ts │ │ ├── graphicsSource.ts │ │ ├── intMatrix.ts │ │ ├── matrixHashTable.ts │ │ ├── partState.ts │ │ ├── partStateParameter.ts │ │ ├── partStateParameterHashTable.ts │ │ └── partsAnimationSource.ts │ ├── main.ts │ ├── menu.ts │ ├── preload.js │ ├── util.ts │ └── wf │ │ ├── constants.js │ │ ├── digest.js │ │ ├── helpers.ts │ │ ├── index.ts │ │ ├── logger.ts │ │ ├── readOrderedMap.js │ │ ├── restoreMp3.js │ │ ├── typedefs.ts │ │ └── wfFileReader.js └── renderer │ ├── App.css │ ├── App.tsx │ ├── components │ ├── Modal.tsx │ ├── Switch.tsx │ ├── TextField.tsx │ ├── Typography.tsx │ ├── WfButton.tsx │ └── WfCard.tsx │ ├── helpers │ ├── hooks.tsx │ └── index.tsx │ ├── index.ejs │ ├── index.tsx │ └── worker.ejs ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = crlf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.erb/configs/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": "off", 4 | "global-require": "off", 5 | "import/no-dynamic-require": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.base.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Base webpack config used across other specific configs 3 | */ 4 | 5 | import webpack from 'webpack'; 6 | import webpackPaths from './webpack.paths'; 7 | import { dependencies as externals } from '../../release/app/package.json'; 8 | 9 | const configuration: webpack.Configuration = { 10 | externals: [...Object.keys(externals || {})], 11 | 12 | stats: 'errors-only', 13 | 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.[jt]sx?$/, 18 | exclude: /node_modules/, 19 | use: { 20 | loader: 'ts-loader', 21 | options: { 22 | // Remove this line to enable type checking in webpack builds 23 | transpileOnly: true, 24 | }, 25 | }, 26 | }, 27 | ], 28 | }, 29 | 30 | output: { 31 | path: webpackPaths.srcPath, 32 | // https://github.com/webpack/webpack/issues/1114 33 | library: { 34 | type: 'commonjs2', 35 | }, 36 | }, 37 | 38 | /** 39 | * Determine the array of extensions that should be used to resolve modules. 40 | */ 41 | resolve: { 42 | extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], 43 | modules: [webpackPaths.srcPath, 'node_modules'], 44 | }, 45 | 46 | plugins: [ 47 | new webpack.EnvironmentPlugin({ 48 | NODE_ENV: 'production', 49 | }), 50 | ], 51 | }; 52 | 53 | export default configuration; 54 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.eslint.ts: -------------------------------------------------------------------------------- 1 | /* eslint import/no-unresolved: off, import/no-self-import: off */ 2 | 3 | module.exports = require('./webpack.config.renderer.dev').default; 4 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.main.prod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Webpack config for production electron main process 3 | */ 4 | 5 | import path from 'path'; 6 | import webpack from 'webpack'; 7 | import { merge } from 'webpack-merge'; 8 | import TerserPlugin from 'terser-webpack-plugin'; 9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 10 | import baseConfig from './webpack.config.base'; 11 | import webpackPaths from './webpack.paths'; 12 | import checkNodeEnv from '../scripts/check-node-env'; 13 | import deleteSourceMaps from '../scripts/delete-source-maps'; 14 | 15 | checkNodeEnv('production'); 16 | deleteSourceMaps(); 17 | 18 | const devtoolsConfig = 19 | process.env.DEBUG_PROD === 'true' 20 | ? { 21 | devtool: 'source-map', 22 | } 23 | : {}; 24 | 25 | const configuration: webpack.Configuration = { 26 | ...devtoolsConfig, 27 | 28 | mode: 'production', 29 | 30 | target: 'electron-main', 31 | 32 | entry: { 33 | main: path.join(webpackPaths.srcMainPath, 'main.ts'), 34 | preload: path.join(webpackPaths.srcMainPath, 'preload.js'), 35 | }, 36 | 37 | output: { 38 | path: webpackPaths.distMainPath, 39 | filename: '[name].js', 40 | }, 41 | 42 | optimization: { 43 | minimizer: [ 44 | new TerserPlugin({ 45 | parallel: true, 46 | }), 47 | ], 48 | }, 49 | 50 | plugins: [ 51 | new BundleAnalyzerPlugin({ 52 | analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', 53 | }), 54 | 55 | /** 56 | * Create global constants which can be configured at compile time. 57 | * 58 | * Useful for allowing different behaviour between development builds and 59 | * release builds 60 | * 61 | * NODE_ENV should be production so that modules do not perform certain 62 | * development checks 63 | */ 64 | new webpack.EnvironmentPlugin({ 65 | NODE_ENV: 'production', 66 | DEBUG_PROD: false, 67 | START_MINIMIZED: false, 68 | }), 69 | ], 70 | 71 | /** 72 | * Disables webpack processing of __dirname and __filename. 73 | * If you run the bundle in node.js it falls back to these values of node.js. 74 | * https://github.com/webpack/webpack/issues/2010 75 | */ 76 | node: { 77 | __dirname: false, 78 | __filename: false, 79 | }, 80 | }; 81 | 82 | export default merge(baseConfig, configuration); 83 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.renderer.dev.dll.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Builds the DLL for development electron renderer process 3 | */ 4 | 5 | import webpack from 'webpack'; 6 | import path from 'path'; 7 | import { merge } from 'webpack-merge'; 8 | import baseConfig from './webpack.config.base'; 9 | import webpackPaths from './webpack.paths'; 10 | import { dependencies } from '../../package.json'; 11 | import checkNodeEnv from '../scripts/check-node-env'; 12 | 13 | checkNodeEnv('development'); 14 | 15 | const dist = webpackPaths.dllPath; 16 | 17 | const configuration: webpack.Configuration = { 18 | context: webpackPaths.rootPath, 19 | 20 | devtool: 'eval', 21 | 22 | mode: 'development', 23 | 24 | target: 'electron-renderer', 25 | 26 | externals: ['fsevents', 'crypto-browserify'], 27 | 28 | /** 29 | * Use `module` from `webpack.config.renderer.dev.js` 30 | */ 31 | module: require('./webpack.config.renderer.dev').default.module, 32 | 33 | entry: { 34 | renderer: Object.keys(dependencies || {}), 35 | }, 36 | 37 | output: { 38 | path: dist, 39 | filename: '[name].dev.dll.js', 40 | library: { 41 | name: 'renderer', 42 | type: 'var', 43 | }, 44 | }, 45 | 46 | plugins: [ 47 | new webpack.DllPlugin({ 48 | path: path.join(dist, '[name].json'), 49 | name: '[name]', 50 | }), 51 | 52 | /** 53 | * Create global constants which can be configured at compile time. 54 | * 55 | * Useful for allowing different behaviour between development builds and 56 | * release builds 57 | * 58 | * NODE_ENV should be production so that modules do not perform certain 59 | * development checks 60 | */ 61 | new webpack.EnvironmentPlugin({ 62 | NODE_ENV: 'development', 63 | }), 64 | 65 | new webpack.LoaderOptionsPlugin({ 66 | debug: true, 67 | options: { 68 | context: webpackPaths.srcPath, 69 | output: { 70 | path: webpackPaths.dllPath, 71 | }, 72 | }, 73 | }), 74 | ], 75 | }; 76 | 77 | export default merge(baseConfig, configuration); 78 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.renderer.dev.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import fs from 'fs'; 3 | import webpack from 'webpack'; 4 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 5 | import chalk from 'chalk'; 6 | import { merge } from 'webpack-merge'; 7 | import { spawn, execSync } from 'child_process'; 8 | import baseConfig from './webpack.config.base'; 9 | import webpackPaths from './webpack.paths'; 10 | import checkNodeEnv from '../scripts/check-node-env'; 11 | import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; 12 | 13 | // When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's 14 | // at the dev webpack config is not accidentally run in a production environment 15 | if (process.env.NODE_ENV === 'production') { 16 | checkNodeEnv('development'); 17 | } 18 | 19 | const port = process.env.PORT || 1212; 20 | const manifest = path.resolve(webpackPaths.dllPath, 'renderer.json'); 21 | const requiredByDLLConfig = module.parent!.filename.includes( 22 | 'webpack.config.renderer.dev.dll' 23 | ); 24 | 25 | /** 26 | * Warn if the DLL is not built 27 | */ 28 | if ( 29 | !requiredByDLLConfig && 30 | !(fs.existsSync(webpackPaths.dllPath) && fs.existsSync(manifest)) 31 | ) { 32 | console.log( 33 | chalk.black.bgYellow.bold( 34 | 'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"' 35 | ) 36 | ); 37 | execSync('npm run postinstall'); 38 | } 39 | 40 | const configuration: webpack.Configuration = { 41 | devtool: 'inline-source-map', 42 | 43 | mode: 'development', 44 | 45 | target: ['web', 'electron-renderer'], 46 | 47 | entry: [ 48 | `webpack-dev-server/client?http://localhost:${port}/dist`, 49 | 'webpack/hot/only-dev-server', 50 | 'core-js', 51 | 'regenerator-runtime/runtime', 52 | path.join(webpackPaths.srcRendererPath, 'index.tsx'), 53 | ], 54 | 55 | output: { 56 | path: webpackPaths.distRendererPath, 57 | publicPath: '/', 58 | filename: 'renderer.dev.js', 59 | library: { 60 | type: 'umd', 61 | }, 62 | }, 63 | 64 | module: { 65 | rules: [ 66 | { 67 | test: /\.s?css$/, 68 | use: [ 69 | 'style-loader', 70 | { 71 | loader: 'css-loader', 72 | options: { 73 | modules: true, 74 | sourceMap: true, 75 | importLoaders: 1, 76 | }, 77 | }, 78 | 'sass-loader', 79 | ], 80 | include: /\.module\.s?(c|a)ss$/, 81 | }, 82 | { 83 | test: /\.s?css$/, 84 | use: ['style-loader', 'css-loader', 'sass-loader'], 85 | exclude: /\.module\.s?(c|a)ss$/, 86 | }, 87 | // Fonts 88 | { 89 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 90 | type: 'asset/resource', 91 | }, 92 | // Images 93 | { 94 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 95 | type: 'asset/resource', 96 | }, 97 | ], 98 | }, 99 | plugins: [ 100 | ...(requiredByDLLConfig 101 | ? [] 102 | : [ 103 | new webpack.DllReferencePlugin({ 104 | context: webpackPaths.dllPath, 105 | manifest: require(manifest), 106 | sourceType: 'var', 107 | }), 108 | ]), 109 | 110 | new webpack.NoEmitOnErrorsPlugin(), 111 | 112 | /** 113 | * Create global constants which can be configured at compile time. 114 | * 115 | * Useful for allowing different behaviour between development builds and 116 | * release builds 117 | * 118 | * NODE_ENV should be production so that modules do not perform certain 119 | * development checks 120 | * 121 | * By default, use 'development' as NODE_ENV. This can be overriden with 122 | * 'staging', for example, by changing the ENV variables in the npm scripts 123 | */ 124 | new webpack.EnvironmentPlugin({ 125 | NODE_ENV: 'development', 126 | }), 127 | 128 | new webpack.LoaderOptionsPlugin({ 129 | debug: true, 130 | }), 131 | 132 | new ReactRefreshWebpackPlugin(), 133 | 134 | new HtmlWebpackPlugin({ 135 | filename: path.join('index.html'), 136 | template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), 137 | minify: { 138 | collapseWhitespace: true, 139 | removeAttributeQuotes: true, 140 | removeComments: true, 141 | }, 142 | isBrowser: false, 143 | env: process.env.NODE_ENV, 144 | isDevelopment: process.env.NODE_ENV !== 'production', 145 | nodeModules: webpackPaths.appNodeModulesPath, 146 | }), 147 | ], 148 | 149 | node: { 150 | __dirname: false, 151 | __filename: false, 152 | }, 153 | 154 | // @ts-ignore 155 | devServer: { 156 | port, 157 | compress: true, 158 | hot: true, 159 | headers: { 'Access-Control-Allow-Origin': '*' }, 160 | static: { 161 | publicPath: '/', 162 | }, 163 | historyApiFallback: { 164 | verbose: true, 165 | }, 166 | onBeforeSetupMiddleware() { 167 | console.log('Starting Main Process...'); 168 | spawn('npm', ['run', 'start:main'], { 169 | shell: true, 170 | env: process.env, 171 | stdio: 'inherit', 172 | }) 173 | .on('close', (code: number) => process.exit(code!)) 174 | .on('error', (spawnError) => console.error(spawnError)); 175 | }, 176 | }, 177 | }; 178 | 179 | export default merge(baseConfig, configuration); 180 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.renderer.prod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Build config for electron renderer process 3 | */ 4 | 5 | import path from 'path'; 6 | import webpack from 'webpack'; 7 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 8 | import MiniCssExtractPlugin from 'mini-css-extract-plugin'; 9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 10 | import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; 11 | import { merge } from 'webpack-merge'; 12 | import TerserPlugin from 'terser-webpack-plugin'; 13 | import baseConfig from './webpack.config.base'; 14 | import webpackPaths from './webpack.paths'; 15 | import checkNodeEnv from '../scripts/check-node-env'; 16 | import deleteSourceMaps from '../scripts/delete-source-maps'; 17 | 18 | checkNodeEnv('production'); 19 | deleteSourceMaps(); 20 | 21 | const devtoolsConfig = 22 | process.env.DEBUG_PROD === 'true' 23 | ? { 24 | devtool: 'source-map', 25 | } 26 | : {}; 27 | 28 | const configuration: webpack.Configuration = { 29 | ...devtoolsConfig, 30 | 31 | mode: 'production', 32 | 33 | target: ['web', 'electron-renderer'], 34 | 35 | entry: [ 36 | 'core-js', 37 | 'regenerator-runtime/runtime', 38 | path.join(webpackPaths.srcRendererPath, 'index.tsx'), 39 | ], 40 | 41 | output: { 42 | path: webpackPaths.distRendererPath, 43 | publicPath: './', 44 | filename: 'renderer.js', 45 | library: { 46 | type: 'umd', 47 | }, 48 | }, 49 | 50 | module: { 51 | rules: [ 52 | { 53 | test: /\.s?(a|c)ss$/, 54 | use: [ 55 | MiniCssExtractPlugin.loader, 56 | { 57 | loader: 'css-loader', 58 | options: { 59 | modules: true, 60 | sourceMap: true, 61 | importLoaders: 1, 62 | }, 63 | }, 64 | 'sass-loader', 65 | ], 66 | include: /\.module\.s?(c|a)ss$/, 67 | }, 68 | { 69 | test: /\.s?(a|c)ss$/, 70 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'], 71 | exclude: /\.module\.s?(c|a)ss$/, 72 | }, 73 | // Fonts 74 | { 75 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 76 | type: 'asset/resource', 77 | }, 78 | // Images 79 | { 80 | test: /\.(png|svg|jpg|jpeg|gif)$/i, 81 | type: 'asset/resource', 82 | }, 83 | ], 84 | }, 85 | 86 | optimization: { 87 | minimize: true, 88 | minimizer: [ 89 | new TerserPlugin({ 90 | parallel: true, 91 | }), 92 | new CssMinimizerPlugin(), 93 | ], 94 | }, 95 | 96 | plugins: [ 97 | /** 98 | * Create global constants which can be configured at compile time. 99 | * 100 | * Useful for allowing different behaviour between development builds and 101 | * release builds 102 | * 103 | * NODE_ENV should be production so that modules do not perform certain 104 | * development checks 105 | */ 106 | new webpack.EnvironmentPlugin({ 107 | NODE_ENV: 'production', 108 | DEBUG_PROD: false, 109 | }), 110 | 111 | new MiniCssExtractPlugin({ 112 | filename: 'style.css', 113 | }), 114 | 115 | new BundleAnalyzerPlugin({ 116 | analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', 117 | }), 118 | 119 | new HtmlWebpackPlugin({ 120 | filename: 'index.html', 121 | template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), 122 | minify: { 123 | collapseWhitespace: true, 124 | removeAttributeQuotes: true, 125 | removeComments: true, 126 | }, 127 | isBrowser: false, 128 | isDevelopment: process.env.NODE_ENV !== 'production', 129 | }), 130 | ], 131 | }; 132 | 133 | export default merge(baseConfig, configuration); 134 | -------------------------------------------------------------------------------- /.erb/configs/webpack.paths.ts: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const rootPath = path.join(__dirname, '../..'); 4 | 5 | const dllPath = path.join(__dirname, '../dll'); 6 | 7 | const srcPath = path.join(rootPath, 'src'); 8 | const srcMainPath = path.join(srcPath, 'main'); 9 | const srcRendererPath = path.join(srcPath, 'renderer'); 10 | 11 | const releasePath = path.join(rootPath, 'release'); 12 | const appPath = path.join(releasePath, 'app'); 13 | const appPackagePath = path.join(appPath, 'package.json'); 14 | const appNodeModulesPath = path.join(appPath, 'node_modules'); 15 | const srcNodeModulesPath = path.join(srcPath, 'node_modules'); 16 | 17 | const distPath = path.join(appPath, 'dist'); 18 | const distMainPath = path.join(distPath, 'main'); 19 | const distRendererPath = path.join(distPath, 'renderer'); 20 | 21 | const buildPath = path.join(releasePath, 'build'); 22 | 23 | export default { 24 | rootPath, 25 | dllPath, 26 | srcPath, 27 | srcMainPath, 28 | srcRendererPath, 29 | releasePath, 30 | appPath, 31 | appPackagePath, 32 | appNodeModulesPath, 33 | srcNodeModulesPath, 34 | distPath, 35 | distMainPath, 36 | distRendererPath, 37 | buildPath, 38 | }; 39 | -------------------------------------------------------------------------------- /.erb/img/erb-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/.erb/img/erb-logo.png -------------------------------------------------------------------------------- /.erb/mocks/fileMock.js: -------------------------------------------------------------------------------- 1 | export default 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /.erb/scripts/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": "off", 4 | "global-require": "off", 5 | "import/no-dynamic-require": "off", 6 | "import/no-extraneous-dependencies": "off" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.erb/scripts/check-build-exists.ts: -------------------------------------------------------------------------------- 1 | // Check if the renderer and main bundles are built 2 | import path from 'path'; 3 | import chalk from 'chalk'; 4 | import fs from 'fs'; 5 | import webpackPaths from '../configs/webpack.paths'; 6 | 7 | const mainPath = path.join(webpackPaths.distMainPath, 'main.js'); 8 | const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js'); 9 | 10 | if (!fs.existsSync(mainPath)) { 11 | throw new Error( 12 | chalk.whiteBright.bgRed.bold( 13 | 'The main process is not built yet. Build it by running "npm run build:main"' 14 | ) 15 | ); 16 | } 17 | 18 | if (!fs.existsSync(rendererPath)) { 19 | throw new Error( 20 | chalk.whiteBright.bgRed.bold( 21 | 'The renderer process is not built yet. Build it by running "npm run build:renderer"' 22 | ) 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /.erb/scripts/check-native-dep.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import chalk from 'chalk'; 3 | import { execSync } from 'child_process'; 4 | import { dependencies } from '../../package.json'; 5 | 6 | if (dependencies) { 7 | const dependenciesKeys = Object.keys(dependencies); 8 | const nativeDeps = fs 9 | .readdirSync('node_modules') 10 | .filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`)); 11 | if (nativeDeps.length === 0) { 12 | process.exit(0); 13 | } 14 | try { 15 | // Find the reason for why the dependency is installed. If it is installed 16 | // because of a devDependency then that is okay. Warn when it is installed 17 | // because of a dependency 18 | const { dependencies: dependenciesObject } = JSON.parse( 19 | execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString() 20 | ); 21 | const rootDependencies = Object.keys(dependenciesObject); 22 | const filteredRootDependencies = rootDependencies.filter((rootDependency) => 23 | dependenciesKeys.includes(rootDependency) 24 | ); 25 | if (filteredRootDependencies.length > 0) { 26 | const plural = filteredRootDependencies.length > 1; 27 | console.log(` 28 | ${chalk.whiteBright.bgYellow.bold( 29 | 'Webpack does not work with native dependencies.' 30 | )} 31 | ${chalk.bold(filteredRootDependencies.join(', '))} ${ 32 | plural ? 'are native dependencies' : 'is a native dependency' 33 | } and should be installed inside of the "./release/app" folder. 34 | First, uninstall the packages from "./package.json": 35 | ${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')} 36 | ${chalk.bold( 37 | 'Then, instead of installing the package to the root "./package.json":' 38 | )} 39 | ${chalk.whiteBright.bgRed.bold('npm install your-package')} 40 | ${chalk.bold('Install the package to "./release/app/package.json"')} 41 | ${chalk.whiteBright.bgGreen.bold('cd ./release/app && npm install your-package')} 42 | Read more about native dependencies at: 43 | ${chalk.bold( 44 | 'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure' 45 | )} 46 | `); 47 | process.exit(1); 48 | } 49 | } catch (e) { 50 | console.log('Native dependencies could not be checked'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /.erb/scripts/check-node-env.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | export default function checkNodeEnv(expectedEnv) { 4 | if (!expectedEnv) { 5 | throw new Error('"expectedEnv" not set'); 6 | } 7 | 8 | if (process.env.NODE_ENV !== expectedEnv) { 9 | console.log( 10 | chalk.whiteBright.bgRed.bold( 11 | `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config` 12 | ) 13 | ); 14 | process.exit(2); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.erb/scripts/check-port-in-use.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import detectPort from 'detect-port'; 3 | 4 | const port = process.env.PORT || '1212'; 5 | 6 | detectPort(port, (err, availablePort) => { 7 | if (port !== String(availablePort)) { 8 | throw new Error( 9 | chalk.whiteBright.bgRed.bold( 10 | `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start` 11 | ) 12 | ); 13 | } else { 14 | process.exit(0); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /.erb/scripts/clean.js: -------------------------------------------------------------------------------- 1 | import rimraf from 'rimraf'; 2 | import webpackPaths from '../configs/webpack.paths.ts'; 3 | import process from 'process'; 4 | 5 | const args = process.argv.slice(2); 6 | const commandMap = { 7 | dist: webpackPaths.distPath, 8 | release: webpackPaths.releasePath, 9 | dll: webpackPaths.dllPath, 10 | }; 11 | 12 | args.forEach((x) => { 13 | const pathToRemove = commandMap[x]; 14 | if (pathToRemove !== undefined) { 15 | rimraf.sync(pathToRemove); 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /.erb/scripts/delete-source-maps.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import rimraf from 'rimraf'; 3 | import webpackPaths from '../configs/webpack.paths'; 4 | 5 | export default function deleteSourceMaps() { 6 | rimraf.sync(path.join(webpackPaths.distMainPath, '*.js.map')); 7 | rimraf.sync(path.join(webpackPaths.distRendererPath, '*.js.map')); 8 | } 9 | -------------------------------------------------------------------------------- /.erb/scripts/electron-rebuild.js: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import { execSync } from 'child_process'; 3 | import fs from 'fs'; 4 | import { dependencies } from '../../release/app/package.json'; 5 | import webpackPaths from '../configs/webpack.paths'; 6 | 7 | if ( 8 | Object.keys(dependencies || {}).length > 0 && 9 | fs.existsSync(webpackPaths.appNodeModulesPath) 10 | ) { 11 | const electronRebuildCmd = 12 | '../../node_modules/.bin/electron-rebuild --parallel --force --types prod,dev,optional --module-dir .'; 13 | const cmd = 14 | process.platform === 'win32' 15 | ? electronRebuildCmd.replace(/\//g, '\\') 16 | : electronRebuildCmd; 17 | execSync(cmd, { 18 | cwd: webpackPaths.appPath, 19 | stdio: 'inherit', 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /.erb/scripts/link-modules.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import webpackPaths from '../configs/webpack.paths'; 3 | 4 | const srcNodeModulesPath = webpackPaths.srcNodeModulesPath; 5 | const appNodeModulesPath = webpackPaths.appNodeModulesPath 6 | 7 | if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) { 8 | fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction'); 9 | } 10 | -------------------------------------------------------------------------------- /.erb/scripts/notarize.js: -------------------------------------------------------------------------------- 1 | const { notarize } = require('electron-notarize'); 2 | const { build } = require('../../package.json'); 3 | 4 | exports.default = async function notarizeMacos(context) { 5 | const { electronPlatformName, appOutDir } = context; 6 | if (electronPlatformName !== 'darwin') { 7 | return; 8 | } 9 | 10 | if (process.env.CI !== "true") { 11 | console.warn('Skipping notarizing step. Packaging is not running in CI'); 12 | return; 13 | } 14 | 15 | if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) { 16 | console.warn('Skipping notarizing step. APPLE_ID and APPLE_ID_PASS env variables must be set'); 17 | return; 18 | } 19 | 20 | const appName = context.packager.appInfo.productFilename; 21 | 22 | await notarize({ 23 | appBundleId: build.appId, 24 | appPath: `${appOutDir}/${appName}.app`, 25 | appleId: process.env.APPLE_ID, 26 | appleIdPassword: process.env.APPLE_ID_PASS, 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage directory used by tools like istanbul 11 | coverage 12 | .eslintcache 13 | 14 | # Dependency directory 15 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 16 | node_modules 17 | 18 | # OSX 19 | .DS_Store 20 | 21 | release/app/dist 22 | release/build 23 | .erb/dll 24 | 25 | .idea 26 | npm-debug.log.* 27 | *.css.d.ts 28 | *.sass.d.ts 29 | *.scss.d.ts 30 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'erb', 3 | rules: { 4 | // A temporary hack related to IDE not resolving correct package.json 5 | 'import/no-extraneous-dependencies': 'off', 6 | 'import/no-unresolved': 'error', 7 | // Since React 17 and typescript 4.1 you can safely disable the rule 8 | 'react/react-in-jsx-scope': 'off', 9 | 'jsx-a11y/click-events-have-key-events': 'off', 10 | 'jsx-a11y/no-static-element-interactions': 'off', 11 | 'no-restricted-syntax': 'off', 12 | 'no-underscore-dangle': 'off', 13 | 'no-await-in-loop': 'off', 14 | 'max-classes-per-file': 'off', 15 | 'no-continue': 'off', 16 | 'jsx-a11y/anchor-is-valid': 'off', 17 | 'react/jsx-props-no-spreading': 'off', 18 | 'no-bitwise': 'off', 19 | 'no-plusplus': 'off', 20 | 'jsx-a11y/no-noninteractive-element-interactions': 'off', 21 | '@typescript-eslint/no-loop-func': 'off', 22 | 'prettier/prettier': [ 23 | 'error', 24 | { 25 | endOfLine: 'auto', 26 | }, 27 | ], 28 | }, 29 | parserOptions: { 30 | ecmaVersion: 2020, 31 | sourceType: 'module', 32 | project: './tsconfig.json', 33 | tsconfigRootDir: __dirname, 34 | createDefaultProgram: true, 35 | }, 36 | settings: { 37 | 'import/resolver': { 38 | // See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below 39 | node: {}, 40 | webpack: { 41 | config: require.resolve('./.erb/configs/webpack.config.eslint.ts'), 42 | }, 43 | typescript: {}, 44 | }, 45 | 'import/parsers': { 46 | '@typescript-eslint/parser': ['.ts', '.tsx'], 47 | }, 48 | }, 49 | }; 50 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.exe binary 3 | *.png binary 4 | *.jpg binary 5 | *.gif binary 6 | *.jpeg binary 7 | *.ico binary 8 | *.icns binary 9 | *.eot binary 10 | *.otf binary 11 | *.ttf binary 12 | *.woff binary 13 | *.woff2 binary 14 | *.jar binary 15 | *.dll binary 16 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ "master" ] 4 | pull_request: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | build-windows: 9 | runs-on: windows-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - name: Use Node.js 16 13 | uses: actions/setup-node@v3 14 | with: 15 | node-version: 16 16 | - name: Install dependencies 17 | run: yarn install --network-timeout 600000 18 | - name: Build and publish to github release. 19 | run: npx cross-env GH_TOKEN=${{ secrets.GH_TOKEN }} yarn deploy 20 | build-linux: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Use Node.js 16 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: 16 28 | - name: Install dependencies 29 | run: yarn install --network-timeout 600000 30 | - name: Build and publish to github release. 31 | run: npx cross-env GH_TOKEN=${{ secrets.GH_TOKEN }} yarn deploy 32 | build-macos: 33 | runs-on: macos-latest 34 | steps: 35 | - uses: actions/checkout@v3 36 | - name: Use Node.js 16 37 | uses: actions/setup-node@v3 38 | with: 39 | node-version: 16 40 | - name: Setup Python 41 | uses: actions/setup-python@v4.5.0 42 | with: 43 | python-version: 3 44 | - name: Install dependencies 45 | run: yarn install --network-timeout 600000 46 | - name: Build and publish to github release. 47 | run: npx cross-env GH_TOKEN=${{ secrets.GH_TOKEN }} yarn deploy 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # build config 6 | electron-builder.yml 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | .eslintcache 16 | *package-lock.json 17 | 18 | # Dependency directory 19 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 20 | node_modules 21 | 22 | # OSX 23 | .DS_Store 24 | 25 | release/app/dist 26 | release/build 27 | .erb/dll 28 | 29 | tests* 30 | 31 | .idea 32 | npm-debug.log.* 33 | *.css.d.ts 34 | *.sass.d.ts 35 | *.scss.d.ts 36 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "EditorConfig.EditorConfig"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.1", 3 | "configurations": [ 4 | { 5 | "name": "Electron: Main", 6 | "type": "node", 7 | "request": "launch", 8 | "protocol": "inspector", 9 | "runtimeExecutable": "npm", 10 | "runtimeArgs": [ 11 | "run start:main --inspect=5858 --remote-debugging-port=9223" 12 | ], 13 | "preLaunchTask": "Start Webpack Dev" 14 | }, 15 | { 16 | "name": "Electron: Renderer", 17 | "type": "chrome", 18 | "request": "attach", 19 | "port": 9223, 20 | "webRoot": "${workspaceFolder}", 21 | "timeout": 15000 22 | } 23 | ], 24 | "compounds": [ 25 | { 26 | "name": "Electron: All", 27 | "configurations": ["Electron: Main", "Electron: Renderer"] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | ".eslintrc": "jsonc", 4 | ".prettierrc": "jsonc", 5 | ".eslintignore": "ignore" 6 | }, 7 | 8 | "javascript.validate.enable": false, 9 | "javascript.format.enable": false, 10 | "typescript.format.enable": false, 11 | 12 | "search.exclude": { 13 | ".git": true, 14 | ".eslintcache": true, 15 | ".erb/dll": true, 16 | "release/{build,app/dist}": true, 17 | "node_modules": true, 18 | "npm-debug.log.*": true, 19 | "test/**/__snapshots__": true, 20 | "package-lock.json": true, 21 | "*.{css,sass,scss}.d.ts": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "label": "Start Webpack Dev", 7 | "script": "start:renderer", 8 | "options": { 9 | "cwd": "${workspaceFolder}" 10 | }, 11 | "isBackground": true, 12 | "problemMatcher": { 13 | "owner": "custom", 14 | "pattern": { 15 | "regexp": "____________" 16 | }, 17 | "background": { 18 | "activeOnStart": true, 19 | "beginsPattern": "Compiling\\.\\.\\.$", 20 | "endsPattern": "(Compiled successfully|Failed to compile)\\.$" 21 | } 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /COMMAND.md: -------------------------------------------------------------------------------- 1 | image 2 | 3 | 4 | Supported commands are like below: 5 | 6 | ## animate [option] 7 | 8 | Crop normal/special sprite sheet of specific character and create animated gif of it. characterId is dev id of specific character, for example characterId of fluffy is combat_animal. 9 | 10 | If you want to generate animated GIF of boss monsters (as in battle/boss/*), use the animateBoss command instead 11 | 12 | #### Options: 13 | **-character \** Specify characterId you want to create animation for. Either this or general argument is required. 14 | 15 | **-general \** Specify path to the sprite_sheet you want to generate animated GIFs based on timeline/atlas file located along with the sprite. Either this or character argument is required. 16 | 17 | **-scale \** Specify scale of generated GIF. default to 1. 18 | 19 | **-sheetName \** Specify name of the sprite sheet png file in the target directory. Default to "sprite_sheet". 20 | 21 | **-atlasName \** Specify name of the *.atlas.json file in the target directory. Default to "sprite_sheet". 22 | 23 | **-timelineName \** Specify name of the *.timeline.json file in the target directory. Default to "pixelart". 24 | 25 | **-metaName \** Specify name of the sprite_sheet, atlas, timeline name at the same time, if they're all same. 26 | 27 | 28 | #### Example: 29 | animate -character combat_animal 30 | 31 | animate -general character/big_bear_monster_light/pixelart -scale 2 32 | 33 | 34 | 35 | ## animateBoss [option] 36 | 37 | Create animated gif based on specific sprite_sheet with .parts / .timeline / .atlas file. .parts file is required to execute this command. 38 | 39 | If you want to generate animated GIF of common characters (as in character/*), use the animate command instead 40 | 41 | #### Options: 42 | **-sprite \** Specify path to the sprite_sheet you want to generate animated GIFs based on parts file located along with the sprite. Required. 43 | 44 | **-scale \** Specify scale of generated GIF. default to 1. 45 | 46 | **-meta \** Specify name root of the parts/timeline/atlas file, if you'd like to pick just one. if this is not specified, command will target all the parts file that is found within target directory. 47 | 48 | **-merge** If this flag is set, while generating GIFs, tool will try to merge same group of GIFs into a single GIF, such as `skill_start1, skill_charge1, skill_attack1, skill_attack_loop1, skill_attack_end1` 49 | 50 | **-frameMs \** Specify the time span of a single frame, in milliseconds. Default to 16 (60 frames in one second) 51 | 52 | **-mergeLoopAmount \** While merging, loop animations will loop number of times as specified. Default to 8. 53 | 54 | **-mergeChargeAmount \** While merging, charge animations will loop number of times as specified. Default to 3. 55 | 56 | **-all** Recursively search target directory specified by -searchTarget and find all boos-like sprites / parts metadata and generate animation if possible. 57 | 58 | **-searchTarget** Target directory to search when -all flag is set. Default to `battle/boss` 59 | 60 | 61 | #### Example: 62 | animateBoss -sprite battle/boss/maou_2nd/maou_2nd -scale 2 -merge 63 | 64 | animateBoss -meta high_epuration_boss_3anv -sprite battle/boss/high_epuration_boss_3anv/high_epuration_boss_3anv -scale 4 -merge 65 | 66 | animateBoss -all -searchTarget battle/boss -scale 2 -merge -mergeLoopAmount 5 -mergeChargeAmount 2 67 | 68 | 69 | ## sprite [option] [assetpath] 70 | 71 | Crop sprites and scale cropped images to the specified ratio. 72 | 73 | #### Options: 74 | **-scale \** Specify scale ratio of cropped sprite images. default to 1. 75 | 76 | **-delta \** Specify target delta version to change work directory to that delta directory. 77 | 78 | **-eliyabot** Set this flag if you want to extract equipment sprites from item/sprite_sheet specially formatted for eliyabot asset format. 79 | 80 | #### Example: 81 | sprite -delta 1.570.21 -scale 4 -eliyabot item/sprite_sheet 82 | 83 | sprite -scale 16 character/battle_maid_xm19/pixelart/sprite_sheet 84 | 85 | 86 | ## search [assetpath] 87 | **-format \<.fileformat1|.fileformat2|...\>** 88 | **-ff \<.fileformat1|.fileformat2|...\>** Specify file formats to be used within format search. 89 | 90 | **-extract** 91 | **-e** If found, proceed to extract the asset found by path query. 92 | 93 | Search the asset hash and file formats if anything matches your path query. Useful if you want to find hidden master table files or assets. 94 | 95 | #### Example: 96 | search master/ex_boost/odds/ability/alterite_r3_a 97 | 98 | 99 | ## master [assetpath] 100 | 101 | Rename, decompile and export master table (orderedmap) asset from assetpath to output/orderedmap directory 102 | 103 | #### Example: 104 | master master/ex_boost/odds/ability/alterite_r3_a.orderedmap 105 | 106 | 107 | ## image [assetpath] 108 | 109 | Rename, decompile and export image asset from assetpath to output/asset directory. 110 | 111 | #### Example: 112 | image item/sprite_sheet.png 113 | 114 | 115 | ## audio [assetpath] 116 | 117 | Rename, decompile and export image asset from assetpath to output/asset directory. 118 | 119 | #### Example: 120 | audio bgm/common/encyclopedia.mp3 121 | 122 | 123 | ## general [assetpath] 124 | 125 | Rename, decompile and export general asset from assetpath to output/asset directory. (Automatically converts amf3 into json file format.) 126 | 127 | #### Example: 128 | general battle/action/skill/action/rare5/hero_girl_vt22$hero_girl_vt22_2.action.dsl.amf3.deflate 129 | 130 | 131 | ## enemyDsl [assetpath] 132 | 133 | search for the path if .esdl file exist. if exist, export all related assets with found .esdl file. 134 | 135 | #### Example: 136 | master master/ex_boost/odds/ability/alterite_r3_a.orderedmap 137 | 138 | 139 | ## exboost 140 | 141 | Extract and create odds summary json for exboost odds table [JP Only] 142 | 143 | ## fetchAssets [baseVersion] 144 | 145 | Fetch assets from JP asset api server, using baseVersion as client asset version header. 146 | 147 | #### Example: 148 | fetchAssets 1.531.10 149 | 150 | ## character [characterId] 151 | 152 | Force search for specific [characterId] assets and export them if exists. This command is useful if there's any character assets whose characterId isn't documented in character master table files yet. 153 | 154 | #### Example: 155 | character kyaru 156 | 157 | ## checkUnknowns [option] 158 | 159 | Search and export images files u failed to recover hashes. (WARNING: do not run this command if u have unexported set of images, such as when u only exported character images but general image assets. these unexported set of images will be recognized as unknown images.) 160 | 161 | Exported images are saved under [delta-assetVersion if exists, or workspace root]/output/assets/unknown/images 162 | 163 | #### Options: 164 | **-delta \** Specify target delta asset version if u need to search for specific delta directory. (Available for only those versions u exported with delta-extraction mode) 165 | 166 | #### Example: 167 | checkUnknowns 168 | 169 | checkUnknowns -delta 1.532.20 170 | 171 | 172 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # World Filpper Asset Extractor FAQs 2 | 3 | These Frequantly asked quetions have been taken from Guthub Issues and other comments made from the commmunity. 4 | 5 | 📝 Controbutions to this documentation are encouraged. 6 | 7 | ## Q: What operating Systems are currently supported for this tool? 8 | 9 | Currently, only Windows is supported. (recommended 10 or higher) 10 | 11 | ## Q: Why is extracting assets from my real device not working? 12 | 13 | Althought there may be other reasons, the most common issue is becuase your device is not rooted. 14 | 15 | ## Q: Where do I find the 5 Element Icons? 16 | 17 | These assets can be found in the sprite sheet `output\assets\scene\general\sprite_sheet_minimal.png` and in the folder `output\assets\scene\general\sprite_sheet\vector_icon_color-assets`. 18 | 19 | ## Q: Why don't I have the `output\assets\scene\general` folder after extracting? 20 | 21 | Some assets, especially those with prefix `scene/general`, are not downloadable through asset API and they're shipped with APK itself (/assets/bundle.zip). The tool's already built to search for those assets (more likely to, if you have full swf scripts decompiled), and if its not found on your end, you need to either pull assets directly from your device using the tool or manually extract them from APK and put it to `dump/` directory along with other asset dumps. 22 | 23 | So if you want to extract those assets manually, follow the next steps. 24 | 25 | 1. Unpack application APK file. 26 | 27 | 2. Locate the bundled assets saved in `PATH_TO_UNPACKED_APK/assets/bundle.zip.` 28 | 29 | 3. Unzip it. 30 | 31 | 4. Copy all the contents inside `bundle.zip/production/bundle` `bundle.zip/production/medium_bundle` into `WORK_DIRECTORY/dump/upload`. WORK_DIR is the Extraction Directory you selected from the tool. (Make sure copied raw asset file paths are look like `WORK_DIR/dump/upload/73/4130924e07d945ae79acac1599758c4e50c432`) 32 | 33 | 5. Open `WORK_DIR/metadata.json` file and modify the key `lockedHashMap` value to `false`. 34 | 35 | 5.1. If you want to confirm everything was done correctly, try executing the command `image scene/general/sprite_sheet.png`. If that command successfully exports the designated asset then you're good to go. 36 | 37 | 6. Try extracting assets again. 38 | 39 | If you can't still find assets after 6 but command in 5.1 works, make sure you turned on the `Search ActionScripts for assets` option and put all the decompiled SWF scripts in the right location. or you can try manually extract them one by one using commands. note that the paths you mentioned above are generated paths and they're actually included in one same sprite file named `scene/general/sprite_sheet` so you'd want to run sprite `scene/general/sprite_sheet` command to crop the image and save cropped sprite to designated path. 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-present Electron React Boilerplate 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # World Filpper Asset Extractor 2 | 3 | #### DISCLAIMER: All the rights of extracted assets belong to cygames/citail and/or its affiliates. Do not share the files extracted by the tool. I do not encourage you to use any of extracted assets in inappropriate purpose. If you use any assets extracted by this tool, you do so at your sole risk. 4 | 5 | Asset Extraction tool for World Flipper. 6 | 7 | This tool extracts the assets from world flipper application installed on your device / emulator using ADB and FFDEC, rename digested file paths with original file path, restore corrupted png and mp3 data, export irregular (amf, orderedmap, etc) files in regular data format such as json. 8 | 9 | Supports JP/EN/KR/CN/TW Variants 10 | 11 | ## Installation 12 | 13 | Check out the [release page of this repo](https://github.com/ScripterSugar/wdfp-extractor/releases). 14 | 15 | ## Requirements 16 | 17 | Runs on Windows, Mac or Linux machines. 18 | 19 | #### Pulling from API 20 | 21 | Some regions may not be able to call asset download api (For example, KR/CN Ips are banned from JP api server.) If you have trouble pulling assets from API, consider using VPN to call those APIs 22 | 23 | #### Pulling from devices/emulator 24 | 25 | Requires [Java 8 or later](https://www.java.com/en/download/) to run FFDEC. 26 | 27 | if you're willing to extract assets from real device, your device must be rooted. 28 | 29 | ## Recommended environments 30 | 31 | #### General environmental concerns 32 | 33 | The tool isnt greatly optimized performance-wise, so your machine's cpu/ram usage may reach very high load while extraction. 34 | 35 | #### Emulator/Device extraction 36 | 37 | The tool only tested for limited use cases, thus should have various bugs or even crahses among other enviornments. Basically this tool works best with modified, non-production adbd, which supports adb running as root permission and grants full access to data directory. 38 | 39 | To use this tool, your device should at least have file-listing access to the /data directory. 40 | 41 | #### Using Emulator 42 | 43 | - Nox player (version 7.0.x) - **Recommended (Global)** 44 | - Bluestacks 5 (Not recommended - bad performance due to unabled adbd root access.) 45 | 46 | #### Using Real device 47 | 48 | - Pixel 2 (Android 11) 49 | - Pixel 4 XL (Android 12) 50 | - Pixel 6 Pro (Android 13) 51 | 52 | ## Usage 53 | 54 | #### Select workspace directory 55 | 56 | Select the directory you want to use as workspace directory. Note that your directory must only includes english alphabets or numbers. I recommend you to use the directory under the root directory in the disk such as `C:/wafuriextract` 57 | 58 | #### Pull Assets from API / Device / Emulator 59 | 60 | ![image](https://user-images.githubusercontent.com/19164553/179390921-e370ffbd-d02b-468c-9104-df70d7bdce70.png) 61 | 62 | You need to pull raw asset files from your device/emulator or directly from wdfp api server. 63 | 64 | Click on the `Pull/Downlaod Assets` and select the asset source, region variant and start pulling the assets. Wait until the pulling process is done. 65 | 66 | When using your device or emulator, The device must downloaded all the assets from world flipper client before you use this tool. 67 | 68 | #### Extract assets 69 | 70 | ![image](https://user-images.githubusercontent.com/19164553/179390928-5cc9a112-edba-4234-b33a-dd42c5ddc674.png) 71 | 72 | Once you pulled raw assets successfully, click on the `Extract Data` button and select options you want and proceed. 73 | 74 | Once the extraction is done, you can find inflated asset files located in the output directory under your extraction directory. 75 | 76 | **Do not close the app even if it hangs. The process might hangs a lot and several tasks require more than dozens of minutes. Be patient while extraction is in progress** 77 | 78 | #### Delta extraction 79 | 80 | ![image](https://user-images.githubusercontent.com/19164553/179390974-91716614-5473-4c3a-a452-1cdb9a6e2bd0.png) 81 | 82 | You can turn on the delta extraction mode by clicking the delta icon button located at right side of extract data button. 83 | 84 | In the delta extraction mode, 85 | 86 | - You can pull new assets from API mode only. 87 | - newly pulled assets will placed inside `delta-latest` directory under your workspace directory. 88 | - once you pulled delta assets, `Extract Data` feature will only targets assets inside delta directory created above. 89 | - after your delta extraction is done, `delta-latest` directory will be renamed to `delta-{assetVersion}` directory for better labeling. 90 | 91 | #### Supported commands 92 | 93 | U can use in-built commands for debugging or advanced usage. refer to the [Command documentation](COMMAND.md) for more details. 94 | 95 | ## Frequently asked questions 96 | 97 | Refer to the [FAQ for more details](FAQ.md). 98 | 99 | Thanks to @michaelcurry for the documentation. 100 | 101 | ## Supported Assets 102 | 103 | - APK 104 | - Decompiled SWF 105 | - Master table 106 | - Character image assets 107 | - Character image atlases/frame/parts/timeline (exported as json format) 108 | - Miscellaneous image assets. 109 | - Audio files including BGM, Character voice lines, S/E and more. 110 | - Cropped sprites based on atlases and sprite sheet 111 | - Animated images generated from sprites (Character images only) 112 | - Skill/Action descriptors for characters / bosses / items, including all the details about the skills. 113 | - Summarized Gacha, EX Boost rates table. 114 | 115 | ## Planned feature 116 | 117 | - Support extraction of ability texts 118 | - Data viewer 119 | 120 | ## Known issues 121 | 122 | The repository is open to your contribution! if you're having problem with the issues that listed here, feel free to open PRs to resolve it and make other pepople can benefit from your contribution. 123 | 124 | - Whitespaces in Windows user name / extraction directory path causing crashes on extraction process. (Due date: TBD) 125 | 126 | ## Contributing 127 | 128 | I won't actively troubleshoot the bugs as far as it works for me, so if you're having trouble using the tool on your side, in most cases you'll have to fix the problem yourself, or at least provide me all the details about your environments, runtime context, ETC. Please include all the details when you open issue here. Also feel free to open any PR. 129 | 130 | If you want more asset coverage added to tool, please provide the details about assets you want to export, including file formats, asset path, format of data, etc. 131 | 132 | The application is built from the [electron-react-boilerplate](https://github.com/electron-react-boilerplate/electron-react-boilerplate). Refer to the repository to check how to install dependencies and start development on your local machine. 133 | 134 | -------------------------------------------------------------------------------- /assets/NanumSquareB.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/NanumSquareB.woff -------------------------------------------------------------------------------- /assets/NanumSquareEB.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/NanumSquareEB.woff -------------------------------------------------------------------------------- /assets/NanumSquareL.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/NanumSquareL.woff -------------------------------------------------------------------------------- /assets/NanumSquareR.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/NanumSquareR.woff -------------------------------------------------------------------------------- /assets/adb/AdbWinApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/adb/AdbWinApi.dll -------------------------------------------------------------------------------- /assets/adb/AdbWinUsbApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/adb/AdbWinUsbApi.dll -------------------------------------------------------------------------------- /assets/adb/adb.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/adb/adb.exe -------------------------------------------------------------------------------- /assets/arrowLeft.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/assets.d.ts: -------------------------------------------------------------------------------- 1 | type Styles = Record; 2 | 3 | declare module '*.svg' { 4 | const content: string; 5 | export default content; 6 | } 7 | 8 | declare module '*.png' { 9 | const content: string; 10 | export default content; 11 | } 12 | 13 | declare module '*.jpg' { 14 | const content: string; 15 | export default content; 16 | } 17 | 18 | declare module '*.scss' { 19 | const content: Styles; 20 | export default content; 21 | } 22 | 23 | declare module '*.sass' { 24 | const content: Styles; 25 | export default content; 26 | } 27 | 28 | declare module '*.css' { 29 | const content: Styles; 30 | export default content; 31 | } 32 | -------------------------------------------------------------------------------- /assets/delta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/delta.png -------------------------------------------------------------------------------- /assets/discord.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/entitlements.mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/extract.svg: -------------------------------------------------------------------------------- 1 | 3 | Archive Folder 4 | A line styled icon from Orion Icon Library. 5 | 8 | 11 | 14 | -------------------------------------------------------------------------------- /assets/ffdec/ffdec.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/ffdec.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/JavactiveX.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/JavactiveX.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/LZMA.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/LZMA.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/avi.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/avi.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/avi.montemedia.license.txt: -------------------------------------------------------------------------------- 1 | Monte Media Library � 2012 2 | Werner Randelshofer, Hausmatt 10, CH-6405 Goldau Switzerland 3 | werner.randelshofer@bluewin.ch 4 | All Rights Reserved. 5 | 6 | The Monte Media Library can be licensed under the terms of the Creative Commons BY 3.0 license, and/or under the terms of the Lesser General Public License LGPL Version 3. 7 | 8 | The license is free for commercial and non-commercial use. 9 | -------------------------------------------------------------------------------- /assets/ffdec/lib/cmykjpeg.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/cmykjpeg.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/ddsreader.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/ddsreader.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/ffdec_lib.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/ffdec_lib.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/ffdec_lib.license.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /assets/ffdec/lib/flamingo-6.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/flamingo-6.2.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/flamingo.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | o Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | o Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | o Neither the name of Flamingo Kirill Grouchnikov nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /assets/ffdec/lib/flashdebugger.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/flashdebugger.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/gif.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/gif.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/gif.license.txt: -------------------------------------------------------------------------------- 1 | Created by Elliot Kroo on 2009-04-25. 2 | 3 | This work is licensed under the Creative Commons Attribution 3.0 Unported 4 | License. To view a copy of this license, visit 5 | http://creativecommons.org/licenses/by/3.0/ or send a letter to Creative 6 | Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. 7 | -------------------------------------------------------------------------------- /assets/ffdec/lib/gnujpdf.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/gnujpdf.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/graphs.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/graphs.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jargs.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/jargs.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jl.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 1993, 1994 Tobias Bading (bading@cs.tu-berlin.de) 2 | Berlin University of Technology 3 | ----------------------------------------------------------------------- 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU Library General Public License as published 6 | by the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU Library General Public License for more details. 13 | 14 | You should have received a copy of the GNU Library General Public 15 | License along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | ---------------------------------------------------------------------- 18 | -------------------------------------------------------------------------------- /assets/ffdec/lib/jl1.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/jl1.0.1.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jna-3.5.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/jna-3.5.1.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jna.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007 Timothy Wall, All Rights Reserved 2 | 3 | This library is free software; you can redistribute it and/or 4 | modify it under the terms of the GNU Lesser General Public 5 | License as published by the Free Software Foundation; either 6 | version 2.1 of the License, or (at your option) any later version. 7 | 8 | This library is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | Lesser General Public License for more details. 12 | -------------------------------------------------------------------------------- /assets/ffdec/lib/jpacker.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/jpacker.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jpacker.license.txt: -------------------------------------------------------------------------------- 1 | Packer version 3.0 (final) 2 | Copyright 2004-2007, Dean Edwards 3 | Web: http://dean.edwards.name/ 4 | 5 | This software is licensed under the MIT license 6 | Web: http://www.opensource.org/licenses/mit-license 7 | 8 | Ported to Java by Pablo Santiago based on C# version by Jesse Hansen, 9 | Web: http://jpacker.googlecode.com/ 10 | Email: pablo.santiago@gmail.com 11 | -------------------------------------------------------------------------------- /assets/ffdec/lib/jpproxy.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/jpproxy.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jpproxy.muffin.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 1996-2003 Mark R. Boyns 2 | 3 | Muffin is free software; you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; either version 2 of the License, or 6 | (at your option) any later version. 7 | 8 | Muffin is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with Muffin; see the file COPYING. If not, write to the 15 | Free Software Foundation, Inc., 16 | 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 17 | -------------------------------------------------------------------------------- /assets/ffdec/lib/jsyntaxpane-0.9.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/jsyntaxpane-0.9.5.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/jsyntaxpane.license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2008 Ayman Al-Sairafi ayman.alsairafi@gmail.com 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License 6 | at http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | -------------------------------------------------------------------------------- /assets/ffdec/lib/minimal-json-0.9.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/minimal-json-0.9.5.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/minimal-json.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, 2014 EclipseSource 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /assets/ffdec/lib/nellymoser.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/nellymoser.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/nellymoser.license.txt: -------------------------------------------------------------------------------- 1 | NellyMoser ASAO codec 2 | Copyright (C) 2007-2008 UAB "DKD" 3 | Copyright (C) 2007-2008 Joseph Artsimovich 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with FFmpeg; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | -------------------------------------------------------------------------------- /assets/ffdec/lib/sfntly.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/sfntly.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/sfntly.license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010 Google Inc. All Rights Reserved. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /assets/ffdec/lib/substance-6.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/substance-6.2.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/substance-flamingo-6.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/substance-flamingo-6.2.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/substance-flamingo.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2010 Flamingo / Substance Kirill Grouchnikov. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | o Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | o Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | o Neither the name of Flamingo Kirill Grouchnikov nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /assets/ffdec/lib/substance.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2010, Kirill Grouchnikov and contributors 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of the Kirill Grouchnikov and contributors nor 13 | the names of its contributors may be used to endorse or promote products 14 | derived from this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 | THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 29 | 30 | The original artwork used in the Quaqua color chooser implementation 31 | has been replaced by images from Famfam Silk collection available 32 | under Creative Commons Attribution-ShareAlike 2.5 license and 33 | images created dynamically by the Substance core code. 34 | -------------------------------------------------------------------------------- /assets/ffdec/lib/tablelayout.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/tablelayout.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/treetable.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/treetable.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/trident-6.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/trident-6.2.jar -------------------------------------------------------------------------------- /assets/ffdec/lib/trident.license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2010 Trident Kirill Grouchnikov. All Rights Reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | o Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | o Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | o Neither the name of Trident Kirill Grouchnikov nor the names of 14 | its contributors may be used to endorse or promote products derived 15 | from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /assets/ffdec/lib/ttf.doubletype.license.txt: -------------------------------------------------------------------------------- 1 | This program is free software; you can redistribute it and/or modify 2 | it under the terms of the GNU General Public License as published by 3 | the Free Software Foundation; either version 2 of the License, or 4 | (at your option) any later version. 5 | 6 | This Program is distributed in the hope that it will be useful, 7 | but WITHOUT ANY WARRANTY; without even the implied warranty of 8 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 9 | GNU General Public License for more details. 10 | 11 | You should have received a copy of the GNU General Public License 12 | along with this program; if not, write to the Free Software 13 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 14 | 15 | In addition, as a special exception, e.e d3si9n gives permission to 16 | link the code of this program with any Java Platform that is available 17 | to public with free of charge, including but not limited to 18 | Sun Microsystem's JAVA(TM) 2 RUNTIME ENVIRONMENT (J2RE), 19 | and distribute linked combinations including the two. 20 | You must obey the GNU General Public License in all respects for all 21 | of the code used other than Java Platform. If you modify this file, 22 | you may extend this exception to your version of the file, but you are not 23 | obligated to do so. If you do not wish to do so, delete this exception 24 | statement from your version. 25 | -------------------------------------------------------------------------------- /assets/ffdec/lib/ttf.fontastic.license.txt: -------------------------------------------------------------------------------- 1 | Fontastic 2 | A font file writer to create TTF and WOFF (Webfonts). 3 | http://code.andreaskoller.com/libraries/fontastic 4 | 5 | Copyright (C) 2013 Andreas Koller http://andreaskoller.com 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General 18 | Public License along with this library; if not, write to the 19 | Free Software Foundation, Inc., 59 Temple Place, Suite 330, 20 | Boston, MA 02111-1307 USA 21 | -------------------------------------------------------------------------------- /assets/ffdec/lib/ttf.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/ffdec/lib/ttf.jar -------------------------------------------------------------------------------- /assets/folder.svg: -------------------------------------------------------------------------------- 1 | 3 | Search Folder 4 | A line styled icon from Orion Icon Library. 5 | 8 | 10 | 12 | -------------------------------------------------------------------------------- /assets/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/github.png -------------------------------------------------------------------------------- /assets/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icon.icns -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icon.ico -------------------------------------------------------------------------------- /assets/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/1024x1024.png -------------------------------------------------------------------------------- /assets/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/128x128.png -------------------------------------------------------------------------------- /assets/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/16x16.png -------------------------------------------------------------------------------- /assets/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/24x24.png -------------------------------------------------------------------------------- /assets/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/256x256.png -------------------------------------------------------------------------------- /assets/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/32x32.png -------------------------------------------------------------------------------- /assets/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/48x48.png -------------------------------------------------------------------------------- /assets/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/512x512.png -------------------------------------------------------------------------------- /assets/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/64x64.png -------------------------------------------------------------------------------- /assets/icons/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/icons/96x96.png -------------------------------------------------------------------------------- /assets/images/ch10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/ch10.jpg -------------------------------------------------------------------------------- /assets/images/ch10_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/ch10_banner.png -------------------------------------------------------------------------------- /assets/images/ch10_special.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/ch10_special.gif -------------------------------------------------------------------------------- /assets/images/ch10_spin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/ch10_spin.png -------------------------------------------------------------------------------- /assets/images/ch10_walk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/ch10_walk.gif -------------------------------------------------------------------------------- /assets/images/couette.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/couette.jpg -------------------------------------------------------------------------------- /assets/images/couette_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/couette_banner.png -------------------------------------------------------------------------------- /assets/images/couette_special.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/couette_special.gif -------------------------------------------------------------------------------- /assets/images/couette_spin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/couette_spin.png -------------------------------------------------------------------------------- /assets/images/couette_walk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/couette_walk.gif -------------------------------------------------------------------------------- /assets/images/theo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/theo.jpg -------------------------------------------------------------------------------- /assets/images/theo_banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/theo_banner.png -------------------------------------------------------------------------------- /assets/images/theo_special.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/theo_special.gif -------------------------------------------------------------------------------- /assets/images/theo_spin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/theo_spin.png -------------------------------------------------------------------------------- /assets/images/theo_walk.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/images/theo_walk.gif -------------------------------------------------------------------------------- /assets/info.svg: -------------------------------------------------------------------------------- 1 | 3 | New Message 4 | A line styled icon from Orion Icon Library. 5 | 9 | 11 | -------------------------------------------------------------------------------- /assets/item_bronze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/item_bronze.png -------------------------------------------------------------------------------- /assets/item_gold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/item_gold.png -------------------------------------------------------------------------------- /assets/item_rainbow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/item_rainbow.png -------------------------------------------------------------------------------- /assets/item_silver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/item_silver.png -------------------------------------------------------------------------------- /assets/item_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ScripterSugar/wdfp-extractor/28dc2e06d79de65894b95f04ead880633f149708/assets/item_white.png -------------------------------------------------------------------------------- /assets/settings.svg: -------------------------------------------------------------------------------- 1 | 3 | Gear 4 | A line styled icon from Orion Icon Library. 5 | 8 | 11 | -------------------------------------------------------------------------------- /assets/trash.svg: -------------------------------------------------------------------------------- 1 | 3 | Bin 4 | A line styled icon from Orion Icon Library. 5 | 8 | 11 | -------------------------------------------------------------------------------- /assets/viewer.svg: -------------------------------------------------------------------------------- 1 | 3 | Responsive 4 | A line styled icon from Orion Icon Library. 5 | 8 | 11 | 13 | 15 | 18 | 20 | 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wdfp-extractor", 3 | "version": "0.6.10", 4 | "description": "World Flipper asset extractor.", 5 | "scripts": { 6 | "build": "concurrently \"npm run build:main\" \"npm run build:renderer\"", 7 | "build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts", 8 | "build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts", 9 | "rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app", 10 | "lint": "cross-env NODE_ENV=development eslint . --ext .js,.jsx,.ts,.tsx", 11 | "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish never", 12 | "deploy": "ts-node ./.erb/scripts/clean.js dist && npm run build && electron-builder build --publish always", 13 | "postinstall": "ts-node .erb/scripts/check-native-dep.js && electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.dev.dll.ts && opencollective-postinstall", 14 | "start": "ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer", 15 | "start:main": "cross-env NODE_ENV=development electron -r ts-node/register/transpile-only ./src/main/main.ts", 16 | "start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./.erb/configs/webpack.config.renderer.dev.ts", 17 | "test": "jest" 18 | }, 19 | "lint-staged": { 20 | "*.{js,jsx,ts,tsx}": [ 21 | "cross-env NODE_ENV=development eslint --cache" 22 | ], 23 | "*.json,.{eslintrc,prettierrc}": [ 24 | "prettier --ignore-path .eslintignore --parser json --write" 25 | ], 26 | "*.{css,scss}": [ 27 | "prettier --ignore-path .eslintignore --single-quote --write" 28 | ], 29 | "*.{html,md,yml}": [ 30 | "prettier --ignore-path .eslintignore --single-quote --write" 31 | ] 32 | }, 33 | "build": { 34 | "productName": "WDFP Extractor", 35 | "appId": "org.inasom.wdfpextractor", 36 | "asar": true, 37 | "asarUnpack": "**\\*.{node,dll}", 38 | "files": [ 39 | "dist", 40 | "node_modules", 41 | "package.json" 42 | ], 43 | "afterSign": ".erb/scripts/notarize.js", 44 | "mac": { 45 | "target": { 46 | "target": "default", 47 | "arch": [ 48 | "arm64", 49 | "x64" 50 | ] 51 | }, 52 | "type": "distribution", 53 | "hardenedRuntime": true, 54 | "entitlements": "assets/entitlements.mac.plist", 55 | "entitlementsInherit": "assets/entitlements.mac.plist", 56 | "gatekeeperAssess": false 57 | }, 58 | "dmg": { 59 | "contents": [ 60 | { 61 | "x": 130, 62 | "y": 220 63 | }, 64 | { 65 | "x": 410, 66 | "y": 220, 67 | "type": "link", 68 | "path": "/Applications" 69 | } 70 | ] 71 | }, 72 | "win": { 73 | "target": [ 74 | "nsis" 75 | ] 76 | }, 77 | "linux": { 78 | "target": [ 79 | "AppImage" 80 | ], 81 | "category": "Development" 82 | }, 83 | "directories": { 84 | "app": "release/app", 85 | "buildResources": "assets", 86 | "output": "release/build" 87 | }, 88 | "extraResources": [ 89 | "./assets/**" 90 | ] 91 | }, 92 | "repository": { 93 | "type": "git", 94 | "url": "https://github.com/ScripterSugar/wdfp-extractor.git" 95 | }, 96 | "author": { 97 | "name": "NASOM", 98 | "email": "scriptersugar@gmail.com" 99 | }, 100 | "license": "MIT", 101 | "keywords": [ 102 | "electron", 103 | "boilerplate", 104 | "react", 105 | "typescript", 106 | "ts", 107 | "sass", 108 | "webpack", 109 | "hot", 110 | "reload" 111 | ], 112 | "devDependencies": { 113 | "@pmmmwh/react-refresh-webpack-plugin": "0.5.4", 114 | "@teamsupercell/typings-for-css-modules-loader": "^2.5.1", 115 | "@testing-library/jest-dom": "^5.16.1", 116 | "@testing-library/react": "^12.1.2", 117 | "@types/jest": "^27.0.3", 118 | "@types/node": "17.0.5", 119 | "@types/react": "^17.0.38", 120 | "@types/react-dom": "^17.0.11", 121 | "@types/react-test-renderer": "^17.0.1", 122 | "@types/terser-webpack-plugin": "^5.0.4", 123 | "@types/webpack-env": "^1.16.3", 124 | "@typescript-eslint/eslint-plugin": "^5.8.1", 125 | "@typescript-eslint/parser": "^5.8.1", 126 | "browserslist-config-erb": "^0.0.3", 127 | "chalk": "^4.1.2", 128 | "concurrently": "^6.5.1", 129 | "core-js": "^3.20.1", 130 | "cross-env": "^7.0.3", 131 | "css-loader": "^6.5.1", 132 | "css-minimizer-webpack-plugin": "^3.3.1", 133 | "detect-port": "^1.3.0", 134 | "electron": "^16.0.5", 135 | "electron-builder": "^23.6.0", 136 | "electron-devtools-installer": "^3.2.0", 137 | "electron-notarize": "^1.1.1", 138 | "electron-rebuild": "^3.2.5", 139 | "eslint": "^8.5.0", 140 | "eslint-config-airbnb-base": "^15.0.0", 141 | "eslint-config-erb": "^4.0.3", 142 | "eslint-import-resolver-typescript": "^2.5.0", 143 | "eslint-import-resolver-webpack": "^0.13.2", 144 | "eslint-plugin-compat": "^4.0.0", 145 | "eslint-plugin-import": "^2.25.3", 146 | "eslint-plugin-jest": "^25.3.2", 147 | "eslint-plugin-jsx-a11y": "^6.5.1", 148 | "eslint-plugin-promise": "^6.0.0", 149 | "eslint-plugin-react": "^7.28.0", 150 | "eslint-plugin-react-hooks": "^4.3.0", 151 | "file-loader": "^6.2.0", 152 | "html-webpack-plugin": "^5.5.0", 153 | "identity-obj-proxy": "^3.0.0", 154 | "jest": "^27.4.5", 155 | "lint-staged": "^12.1.4", 156 | "mini-css-extract-plugin": "^2.4.5", 157 | "opencollective-postinstall": "^2.0.3", 158 | "prettier": "^2.5.1", 159 | "react-refresh": "^0.11.0", 160 | "react-refresh-typescript": "^2.0.3", 161 | "react-test-renderer": "^17.0.2", 162 | "rimraf": "^3.0.2", 163 | "sass": "^1.45.1", 164 | "sass-loader": "^12.4.0", 165 | "style-loader": "^3.3.1", 166 | "terser-webpack-plugin": "^5.3.0", 167 | "ts-jest": "^27.1.2", 168 | "ts-loader": "^9.2.6", 169 | "ts-node": "^10.4.0", 170 | "typescript": "^4.5.4", 171 | "url-loader": "^4.1.1", 172 | "webpack": "^5.65.0", 173 | "webpack-bundle-analyzer": "^4.5.0", 174 | "webpack-cli": "^4.9.1", 175 | "webpack-dev-server": "^4.7.1", 176 | "webpack-merge": "^5.8.0" 177 | }, 178 | "dependencies": { 179 | "adm-zip": "^0.5.9", 180 | "amfjs": "^1.3.1", 181 | "bytearray-nodejs": "^1.0.1", 182 | "csv-parse": "^5.3.0", 183 | "electron-debug": "^3.2.0", 184 | "electron-log": "^4.4.4", 185 | "electron-updater": "^4.6.4", 186 | "get-pixels": "^3.3.3", 187 | "gif-encoder": "^0.7.2", 188 | "history": "^5.2.0", 189 | "moment": "^2.29.2", 190 | "msgpack-lite": "^0.1.26", 191 | "node-fetch": "2.x", 192 | "react": "^17.0.2", 193 | "react-dom": "^17.0.2", 194 | "react-router-dom": "^6.2.1", 195 | "regenerator-runtime": "^0.13.9", 196 | "simple-get": "4.0.1", 197 | "styled-components": "^5.3.3" 198 | }, 199 | "devEngines": { 200 | "node": ">=14.x", 201 | "npm": ">=7.x" 202 | }, 203 | "browserslist": [], 204 | "prettier": { 205 | "overrides": [ 206 | { 207 | "files": [ 208 | ".prettierrc", 209 | ".eslintrc" 210 | ], 211 | "options": { 212 | "parser": "json" 213 | } 214 | } 215 | ], 216 | "singleQuote": true 217 | } 218 | } 219 | 220 | -------------------------------------------------------------------------------- /release/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wdfp-extractor", 3 | "version": "0.6.10", 4 | "description": "World Flipper asset extractor.", 5 | "main": "./dist/main/main.js", 6 | "author": { 7 | "name": "NASOM", 8 | "email": "scriptersugar@gmail.com" 9 | }, 10 | "scripts": { 11 | "electron-rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js", 12 | "link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts", 13 | "postinstall": "npm run electron-rebuild && npm run link-modules" 14 | }, 15 | "dependencies": { 16 | "fkill": "7.2.1", 17 | "iconv-lite": "^0.6.3", 18 | "sharp": "^0.29.3" 19 | }, 20 | "license": "MIT" 21 | } 22 | 23 | -------------------------------------------------------------------------------- /src/main/flatomo/customTweenRecord.ts: -------------------------------------------------------------------------------- 1 | import CustomTweenTools from './customTweenTools'; 2 | 3 | export default class CustomTweenRecord { 4 | segments: SegmentRecord[]; 5 | 6 | segmentNumber: number; 7 | 8 | resource: number[]; 9 | 10 | constructor(param1: number[] = undefined) { 11 | this.resource = param1; 12 | const segmentNumberCalc = Math.floor((param1.length + 2) / 6); 13 | this.segmentNumber = 14 | segmentNumberCalc < 0 15 | ? Math.floor(segmentNumberCalc - 1e-10) 16 | : Math.floor(segmentNumberCalc + 1e-10); 17 | this.segments = Array(this.segmentNumber).fill(null); 18 | } 19 | 20 | getTweenRatio(param1: number): number { 21 | let index = 0; 22 | let high = this.segmentNumber - 1; 23 | while (high !== index) { 24 | const mid = index + Math.ceil((high - index) / 2); 25 | const midValue = 26 | this.resource[mid * 6 - 2] / CustomTweenTools.CUSTOM_TWEEN_MAX; 27 | if (param1 < midValue) { 28 | high = mid - 1; 29 | } else { 30 | index = mid; 31 | } 32 | } 33 | 34 | let segment = this.segments[index]; 35 | if (segment === null) { 36 | const startX = 37 | index === 0 38 | ? 0 39 | : this.resource[index * 6 - 2] / CustomTweenTools.CUSTOM_TWEEN_MAX; 40 | const startY = 41 | index === 0 42 | ? 0 43 | : this.resource[index * 6 - 1] / CustomTweenTools.CUSTOM_TWEEN_MAX; 44 | const endX = 45 | index === this.segmentNumber - 1 46 | ? 1 47 | : this.resource[index * 6 + 4] / CustomTweenTools.CUSTOM_TWEEN_MAX; 48 | const endY = 49 | index === this.segmentNumber - 1 50 | ? 1 51 | : this.resource[index * 6 + 5] / CustomTweenTools.CUSTOM_TWEEN_MAX; 52 | 53 | segment = this.segments[index] = new SegmentRecord( 54 | startX, 55 | startY, 56 | this.resource[index * 6] / CustomTweenTools.CUSTOM_TWEEN_MAX, 57 | this.resource[index * 6 + 1] / CustomTweenTools.CUSTOM_TWEEN_MAX, 58 | this.resource[index * 6 + 2] / CustomTweenTools.CUSTOM_TWEEN_MAX, 59 | this.resource[index * 6 + 3] / CustomTweenTools.CUSTOM_TWEEN_MAX, 60 | endX, 61 | endY 62 | ); 63 | } 64 | 65 | return segment.getYForX(param1); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/flatomo/customTweenTools.ts: -------------------------------------------------------------------------------- 1 | export default class CustomTweenTools { 2 | static CUSTOM_TWEEN_MAX: number = 1000000; 3 | 4 | static toResource(param1: { x: number; y: number }[]): number[] { 5 | const result: number[] = []; 6 | for (let i = 1; i < param1.length - 1; i++) { 7 | const item = param1[i]; 8 | result.push(Math.round(item.x * CustomTweenTools.CUSTOM_TWEEN_MAX)); 9 | result.push(Math.round(item.y * CustomTweenTools.CUSTOM_TWEEN_MAX)); 10 | } 11 | return result; 12 | } 13 | 14 | static toString(param1: any[]): string { 15 | return param1.join(','); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/flatomo/graphicsLoopKindTools.ts: -------------------------------------------------------------------------------- 1 | export default class GraphicsLoopKindTools { 2 | static getFutureFrame( 3 | param1: number, 4 | param2: number, 5 | param3: number, 6 | param4: number 7 | ): number { 8 | switch (param1) { 9 | case 0: 10 | return param2; 11 | case 1: 12 | return Math.ceil(Math.min(param2 + param3, param4 - 1)); 13 | case 2: 14 | return (param2 + param3) % param4; 15 | default: 16 | return 0; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/flatomo/intMatrix.ts: -------------------------------------------------------------------------------- 1 | export default class IntMatrix { 2 | static RESOLUTION: number = 4096; 3 | 4 | intTy: number; 5 | 6 | intTx: number; 7 | 8 | intD: number; 9 | 10 | intC: number; 11 | 12 | intB: number; 13 | 14 | intA: number; 15 | 16 | constructor( 17 | param1 = 0, 18 | param2 = 0, 19 | param3 = 0, 20 | param4 = 0, 21 | param5 = 0, 22 | param6 = 0 23 | ) { 24 | this.intA = param1; 25 | this.intB = param2; 26 | this.intC = param3; 27 | this.intD = param4; 28 | this.intTx = param5; 29 | this.intTy = param6; 30 | } 31 | 32 | static getIdentity(): IntMatrix { 33 | return new IntMatrix( 34 | IntMatrix.RESOLUTION, 35 | 0, 36 | 0, 37 | IntMatrix.RESOLUTION, 38 | 0, 39 | 0 40 | ); 41 | } 42 | 43 | static floatToInt(param1: number): number { 44 | let modifiableParam = param1; 45 | 46 | modifiableParam *= IntMatrix.RESOLUTION; 47 | if (modifiableParam >= 2147483647) { 48 | return 2147483647; 49 | } 50 | if (modifiableParam <= -2147483648) { 51 | return -2147483648; 52 | } 53 | if (modifiableParam < 0) { 54 | return Math.floor(modifiableParam - 1e-10); 55 | } 56 | return Math.floor(modifiableParam + 1e-10); 57 | } 58 | 59 | get ty(): number { 60 | return this.intTy / IntMatrix.RESOLUTION; 61 | } 62 | 63 | get tx(): number { 64 | return this.intTx / IntMatrix.RESOLUTION; 65 | } 66 | 67 | get d(): number { 68 | return this.intD / IntMatrix.RESOLUTION; 69 | } 70 | 71 | get c(): number { 72 | return this.intC / IntMatrix.RESOLUTION; 73 | } 74 | 75 | get b(): number { 76 | return this.intB / IntMatrix.RESOLUTION; 77 | } 78 | 79 | get a(): number { 80 | return this.intA / IntMatrix.RESOLUTION; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/flatomo/matrixHashTable.ts: -------------------------------------------------------------------------------- 1 | import IntMatrix from './intMatrix'; 2 | 3 | export default class MatrixHashTable { 4 | static init__: boolean; 5 | 6 | static SIZE: number = 100000; 7 | 8 | static table: IntMatrix[] = []; 9 | 10 | constructor() {} 11 | 12 | static getByFloat( 13 | param1: number, 14 | param2: number, 15 | param3: number, 16 | param4: number, 17 | param5: number, 18 | param6: number 19 | ): IntMatrix { 20 | const _loc7_: number = param1 * IntMatrix.RESOLUTION; 21 | const _loc8_: number = this.floatToInt(_loc7_); 22 | const _loc9_: number = param2 * IntMatrix.RESOLUTION; 23 | const _loc10_: number = this.floatToInt(_loc9_); 24 | const _loc11_: number = param3 * IntMatrix.RESOLUTION; 25 | const _loc12_: number = this.floatToInt(_loc11_); 26 | const _loc13_: number = param4 * IntMatrix.RESOLUTION; 27 | const _loc14_: number = this.floatToInt(_loc13_); 28 | const _loc15_: number = param5 * IntMatrix.RESOLUTION; 29 | const _loc16_: number = this.floatToInt(_loc15_); 30 | const _loc17_: number = param6 * IntMatrix.RESOLUTION; 31 | const _loc18_: number = this.floatToInt(_loc17_); 32 | const _loc19_: number = 33 | 1759 + 34 | _loc8_ * 5360233 + 35 | _loc10_ * 8417077 + 36 | _loc12_ * 4323961 + 37 | _loc14_ * 1764881 + 38 | _loc16_ * 2337539 + 39 | _loc18_ * 3257117; 40 | const _loc20_: number = 41 | _loc19_ < 0 ? Math.floor(_loc19_ - 1e-10) : Math.floor(_loc19_ + 1e-10); 42 | const _loc21_: number = Math.abs(_loc20_) % MatrixHashTable.SIZE; 43 | const _loc22_: IntMatrix = MatrixHashTable.table[_loc21_]; 44 | 45 | if ( 46 | _loc22_ && 47 | _loc22_.intA === _loc8_ && 48 | _loc22_.intB === _loc10_ && 49 | _loc22_.intC === _loc12_ && 50 | _loc22_.intD === _loc14_ && 51 | _loc22_.intTx === _loc16_ && 52 | _loc22_.intTy === _loc18_ 53 | ) { 54 | return _loc22_; 55 | } 56 | 57 | return (MatrixHashTable.table[_loc21_] = new IntMatrix( 58 | _loc8_, 59 | _loc10_, 60 | _loc12_, 61 | _loc14_, 62 | _loc16_, 63 | _loc18_ 64 | )); 65 | } 66 | 67 | static get( 68 | param1: number, 69 | param2: number, 70 | param3: number, 71 | param4: number, 72 | param5: number, 73 | param6: number 74 | ): IntMatrix { 75 | const _loc7_: number = 76 | 1759 + 77 | param1 * 5360233 + 78 | param2 * 8417077 + 79 | param3 * 4323961 + 80 | param4 * 1764881 + 81 | param5 * 2337539 + 82 | param6 * 3257117; 83 | const _loc8_: number = 84 | _loc7_ < 0 ? Math.floor(_loc7_ - 1e-10) : Math.floor(_loc7_ + 1e-10); 85 | const _loc9_: number = Math.abs(_loc8_) % MatrixHashTable.SIZE; 86 | const _loc10_: IntMatrix = MatrixHashTable.table[_loc9_]; 87 | 88 | if ( 89 | _loc10_ && 90 | _loc10_.intA === param1 && 91 | _loc10_.intB === param2 && 92 | _loc10_.intC === param3 && 93 | _loc10_.intD === param4 && 94 | _loc10_.intTx === param5 && 95 | _loc10_.intTy === param6 96 | ) { 97 | return _loc10_; 98 | } 99 | 100 | return (MatrixHashTable.table[_loc9_] = new IntMatrix( 101 | param1, 102 | param2, 103 | param3, 104 | param4, 105 | param5, 106 | param6 107 | )); 108 | } 109 | 110 | static calculateHash( 111 | param1: number, 112 | param2: number, 113 | param3: number, 114 | param4: number, 115 | param5: number, 116 | param6: number 117 | ): number { 118 | const _loc7_: number = 119 | 1759 + 120 | param1 * 5360233 + 121 | param2 * 8417077 + 122 | param3 * 4323961 + 123 | param4 * 1764881 + 124 | param5 * 2337539 + 125 | param6 * 3257117; 126 | const _loc8_: number = 127 | _loc7_ < 0 ? Math.floor(_loc7_ - 1e-10) : Math.floor(_loc7_ + 1e-10); 128 | return Math.abs(_loc8_); 129 | } 130 | 131 | private static floatToInt(param1: number): number { 132 | if (param1 >= 2147483647) { 133 | return 2147483647; 134 | } 135 | if (param1 <= -2147483648) { 136 | return -2147483648; 137 | } 138 | if (param1 < 0) { 139 | return Math.floor(param1 - 1e-10); 140 | } 141 | return Math.floor(param1 + 1e-10); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/flatomo/partState.ts: -------------------------------------------------------------------------------- 1 | import PartStateParameters from './partStateParameter'; 2 | 3 | export default class PartState { 4 | parameters: PartStateParameters; 5 | 6 | next: PartState; 7 | 8 | kind: number; 9 | 10 | referencingFrame: number; 11 | 12 | id: number; 13 | 14 | indexForPath: number; 15 | 16 | constructor( 17 | param1 = 0, 18 | param2 = 0, 19 | param3 = 0, 20 | param4 = 0, 21 | param5: PartStateParameters, 22 | param6: PartState 23 | ) { 24 | this.parameters = param5; 25 | this.next = param6; 26 | this.kind = param1; 27 | this.referencingFrame = param3; 28 | this.id = param2; 29 | this.indexForPath = param4; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/flatomo/partStateParameter.ts: -------------------------------------------------------------------------------- 1 | import IntMatrix from './intMatrix'; 2 | 3 | export default class PartStateParameters { 4 | matrix: IntMatrix; 5 | 6 | colorTransform: number; 7 | 8 | alphaAndBlendMode: number; 9 | 10 | constructor(param1: IntMatrix, param2 = 0, param3 = 0) { 11 | this.alphaAndBlendMode = param2; 12 | this.matrix = param1; 13 | this.colorTransform = param3; 14 | } 15 | 16 | get intAlpha(): number { 17 | return this.alphaAndBlendMode & 255; 18 | } 19 | 20 | get blendMode(): number { 21 | return this.alphaAndBlendMode >> 8; 22 | } 23 | 24 | get alpha(): number { 25 | return (this.alphaAndBlendMode & 255) / 255; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/flatomo/partStateParameterHashTable.ts: -------------------------------------------------------------------------------- 1 | import IntMatrix from './intMatrix'; 2 | import PartStateParameters from './partStateParameter'; 3 | 4 | export default class PartStateParametersHashTable { 5 | static init__: boolean; 6 | 7 | static SIZE: number = 100000; 8 | 9 | static table: PartStateParameters[] = []; 10 | 11 | constructor() {} 12 | 13 | static get( 14 | param1: IntMatrix, 15 | param2: number, 16 | param3: number 17 | ): PartStateParameters { 18 | const _loc4_: number = 19 | 1759 + 20 | param1.intA * 5360233 + 21 | param1.intB * 8417077 + 22 | param1.intC * 4323961 + 23 | param1.intD * 1764881 + 24 | param1.intTx * 2337539 + 25 | param1.intTy * 3257117 + 26 | param2 * 28979 + 27 | param3 * 178627 + 28 | 99809; 29 | const _loc5_: number = 30 | _loc4_ < 0 ? Math.floor(_loc4_ - 1e-10) : Math.floor(_loc4_ + 1e-10); 31 | const _loc6_: number = Math.abs(_loc5_) % PartStateParametersHashTable.SIZE; 32 | const _loc7_: PartStateParameters = 33 | PartStateParametersHashTable.table[_loc6_]; 34 | if ( 35 | _loc7_ && 36 | _loc7_.matrix === param1 && 37 | _loc7_.alphaAndBlendMode === param2 && 38 | _loc7_.colorTransform === param3 39 | ) { 40 | return _loc7_; 41 | } 42 | return (PartStateParametersHashTable.table[_loc6_] = 43 | new PartStateParameters(param1, param2, param3)); 44 | } 45 | 46 | static calculateHash( 47 | param1: IntMatrix, 48 | param2: number, 49 | param3: number 50 | ): number { 51 | const _loc4_: number = 52 | 1759 + 53 | param1.intA * 5360233 + 54 | param1.intB * 8417077 + 55 | param1.intC * 4323961 + 56 | param1.intD * 1764881 + 57 | param1.intTx * 2337539 + 58 | param1.intTy * 3257117 + 59 | param2 * 28979 + 60 | param3 * 178627 + 61 | 99809; 62 | const _loc5_: number = 63 | _loc4_ < 0 ? Math.floor(_loc4_ - 1e-10) : Math.floor(_loc4_ + 1e-10); 64 | return Math.abs(_loc5_); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/flatomo/partsAnimationSource.ts: -------------------------------------------------------------------------------- 1 | import GraphicsSource from './graphicsSource'; 2 | import IntMatrix from './intMatrix'; 3 | import MatrixHashTable from './matrixHashTable'; 4 | 5 | export default class PartsAnimationSource { 6 | defaultScale: number; 7 | 8 | imageMaxNumbers: number; 9 | 10 | movieMaxNumbers: number; 11 | 12 | metaData: Record; 13 | 14 | images: any[]; 15 | 16 | graphics: GraphicsSource[] = []; 17 | 18 | constructor(parts: Record) { 19 | this.defaultScale = parts.s; 20 | this.imageMaxNumbers = parts.a; 21 | this.movieMaxNumbers = parts.o; 22 | this.metaData = parts.f; 23 | const parsedMatrices = PartsAnimationSource.parseMatrix(parts); 24 | this.images = parts.i; 25 | 26 | this.parseGraphics(parts, parsedMatrices); 27 | } 28 | 29 | static parseMatrix(param1: any): IntMatrix[] { 30 | const _loc2_: number = param1.t.length; 31 | const _loc3_: IntMatrix[] = new Array(_loc2_); 32 | for (let _loc4_ = 0; _loc4_ < _loc2_; _loc4_++) { 33 | const _loc6_ = param1.t[_loc4_]; 34 | const _loc7_: number = _loc6_.a; 35 | const _loc8_: number = _loc6_.b; 36 | const _loc9_: number = _loc6_.c; 37 | const _loc10_: number = _loc6_.d; 38 | const _loc11_: number = _loc6_.x; 39 | const _loc12_: number = _loc6_.y; 40 | const _loc13_: number = 41 | 1759 + 42 | _loc7_ * 5360233 + 43 | _loc8_ * 8417077 + 44 | _loc9_ * 4323961 + 45 | _loc10_ * 1764881 + 46 | _loc11_ * 2337539 + 47 | _loc12_ * 3257117; 48 | const _loc14_: number = 49 | _loc13_ < 0 ? Math.floor(_loc13_ - 1e-10) : Math.floor(_loc13_ + 1e-10); 50 | const _loc15_: number = Math.abs(_loc14_) % MatrixHashTable.SIZE; 51 | const _loc16_: IntMatrix = MatrixHashTable.table[_loc15_]; 52 | _loc3_[_loc4_] = 53 | _loc16_ && 54 | _loc16_.intA === _loc7_ && 55 | _loc16_.intB === _loc8_ && 56 | _loc16_.intC === _loc9_ && 57 | _loc16_.intD === _loc10_ && 58 | _loc16_.intTx === _loc11_ && 59 | _loc16_.intTy === _loc12_ 60 | ? _loc16_ 61 | : (MatrixHashTable.table[_loc15_] = new IntMatrix( 62 | _loc7_, 63 | _loc8_, 64 | _loc9_, 65 | _loc10_, 66 | _loc11_, 67 | _loc12_ 68 | )); 69 | } 70 | return _loc3_; 71 | } 72 | 73 | parseGraphics(parts: Record, matrices: IntMatrix[]): void { 74 | for (const graphicDescriber of parts.g) { 75 | const graphic = new GraphicsSource( 76 | graphicDescriber.s, 77 | graphicDescriber.t, 78 | matrices, 79 | parts.g 80 | ); 81 | this.graphics.push(graphic); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/main.ts: -------------------------------------------------------------------------------- 1 | /* eslint global-require: off, no-console: off, promise/always-return: off */ 2 | 3 | /** 4 | * This module executes inside of electron's main process. You can start 5 | * electron renderer process from here and communicate with the other processes 6 | * through IPC. 7 | * 8 | * When running `npm run build` or `npm run build:main`, this file is compiled to 9 | * `./src/main.js` using webpack. This gives us some performance wins. 10 | */ 11 | import 'core-js/stable'; 12 | import 'regenerator-runtime/runtime'; 13 | import path from 'path'; 14 | import { app, BrowserWindow, shell, ipcMain, dialog } from 'electron'; 15 | import { autoUpdater } from 'electron-updater'; 16 | import log from 'electron-log'; 17 | import { createWriteStream } from 'fs'; 18 | import MenuBuilder from './menu'; 19 | import { resolveHtmlPath } from './util'; 20 | import logger from './wf/logger'; 21 | import WfExtractor from './wf'; 22 | import { asyncReadFile } from './wf/helpers'; 23 | 24 | let mainWindow: BrowserWindow | null = null; 25 | 26 | ipcMain.on('showOpenDialog', async (event, arg) => { 27 | const returnedPath = dialog.showOpenDialogSync({ 28 | properties: ['openDirectory'], 29 | }); 30 | 31 | event.reply('showOpenDialog', returnedPath); 32 | }); 33 | 34 | ipcMain.on('openDevTools', async (event, arg) => { 35 | mainWindow.webContents.openDevTools(); 36 | }); 37 | 38 | ipcMain.on('getAppVersion', async (event) => { 39 | event.reply('appVersion', app.getVersion()); 40 | }); 41 | 42 | ipcMain.on('openDirectory', async (event, openPath) => { 43 | shell.openPath(openPath); 44 | }); 45 | ipcMain.on('updateApp', async (event, openPath) => { 46 | autoUpdater.quitAndInstall(); 47 | }); 48 | 49 | ipcMain.on('clearMeta', async (event, rootDir, targetData) => { 50 | const wfExtractor = new WfExtractor({ 51 | rootDir, 52 | }); 53 | 54 | await wfExtractor.init(); 55 | 56 | switch (targetData) { 57 | case 'characterSprites': { 58 | await wfExtractor.markMetaData({ 59 | spriteProcessedLock: [], 60 | specialSpriteProcessedLock: [], 61 | }); 62 | 63 | logger.log('Character sprites cache cleared.'); 64 | 65 | return null; 66 | } 67 | default: { 68 | return null; 69 | } 70 | } 71 | }); 72 | 73 | class ExtractionProcessor { 74 | packetResolver = (data: string) => {}; 75 | 76 | awaitNextPacket = (): Promise => { 77 | return new Promise((resolve) => { 78 | this.packetResolver = resolve; 79 | }); 80 | }; 81 | 82 | resolveAwait = (data: string) => { 83 | if (this.packetResolver) { 84 | this.packetResolver(data); 85 | this.packetResolver = () => {}; 86 | } 87 | }; 88 | } 89 | 90 | const extractionProcessor = new ExtractionProcessor(); 91 | 92 | ipcMain.on('extractionResponseRenderer', async (event, response) => { 93 | extractionProcessor.resolveAwait(response); 94 | }); 95 | 96 | ipcMain.on('getMeta', async (event, rootDir) => { 97 | let meta = {}; 98 | 99 | try { 100 | meta = JSON.parse(await asyncReadFile(`${rootDir}/metadata.json`)); 101 | } catch (err) { 102 | console.log(err); 103 | } 104 | event.reply('getMetaResponse', meta); 105 | }); 106 | 107 | ipcMain.on( 108 | 'startPull', 109 | async ( 110 | event, 111 | rootDir, 112 | { 113 | region, 114 | regionVariant, 115 | variant, 116 | baseVersion, 117 | ignoreFull, 118 | skipSwfDecompile, 119 | parseActionScript, 120 | customPort, 121 | customCdn, 122 | deltaMode, 123 | } 124 | ) => { 125 | let replyPacket = ''; 126 | let extractionPhase = 0; 127 | 128 | const wfExtractor = new WfExtractor({ 129 | region, 130 | regionVariant, 131 | rootDir, 132 | swfMode: (parseActionScript && 'full') || 'simple', 133 | customPort, 134 | extractAllFrames: false, 135 | deltaMode, 136 | }); 137 | 138 | while (replyPacket !== 'done') { 139 | if (/phase/.test(replyPacket)) { 140 | const targetPhase = parseFloat(replyPacket.split(':')[1]); 141 | 142 | extractionPhase = targetPhase; 143 | } 144 | try { 145 | if (extractionPhase <= 0) { 146 | await wfExtractor.init({ requireJava: variant === 'device' }); 147 | extractionPhase = 1; 148 | } 149 | 150 | switch (variant) { 151 | case 'device': { 152 | if (extractionPhase <= 1) { 153 | if (/selectDevice/.test(replyPacket)) { 154 | const deviceId = replyPacket.replace(/selectDevice/, ''); 155 | await wfExtractor.selectDevice(deviceId); 156 | } else { 157 | await wfExtractor.selectDevice(); 158 | } 159 | 160 | extractionPhase = 2; 161 | } 162 | 163 | if (extractionPhase <= 2) { 164 | await wfExtractor.connectAdbShell(); 165 | extractionPhase = 3; 166 | } 167 | 168 | if (skipSwfDecompile) { 169 | extractionPhase = 4; 170 | } 171 | 172 | if (extractionPhase <= 3) { 173 | await wfExtractor.dumpAndExtractApk(); 174 | await wfExtractor.decompileAndExportSwf(); 175 | extractionPhase = 4; 176 | } 177 | 178 | if (extractionPhase <= 4) { 179 | await wfExtractor.indexWfAssets(); 180 | await wfExtractor.dumpWfAssets(); 181 | await wfExtractor.mergeAssets(); 182 | extractionPhase = 4.5; 183 | } 184 | 185 | break; 186 | } 187 | case 'api': { 188 | await wfExtractor.fetchAssetsFromApi(baseVersion, { 189 | ...(customCdn && { cdn: customCdn }), 190 | ignoreFull, 191 | }); 192 | 193 | break; 194 | } 195 | default: { 196 | throw new Error(`Variant ${variant} not defined.`); 197 | } 198 | } 199 | 200 | break; 201 | } catch (err) { 202 | event.reply('extractionResponseMain', { 203 | error: err?.message || 'UNKNOWN', 204 | }); 205 | replyPacket = await extractionProcessor.awaitNextPacket(); 206 | } 207 | } 208 | event.reply('extractionResponseMain', { success: true }); 209 | } 210 | ); 211 | 212 | ipcMain.on( 213 | 'startExtraction', 214 | async ( 215 | event, 216 | rootDir, 217 | { 218 | region, 219 | extractMaster, 220 | extractCharacterImage, 221 | extractMiscImage, 222 | extractAudio, 223 | extractAllFrames, 224 | extractGeneralAmf, 225 | extractEsdl, 226 | processAtlas, 227 | processAtlasMisc, 228 | parseActionScript, 229 | customPort, 230 | debug, 231 | deltaMode, 232 | } 233 | ) => { 234 | let replyPacket; 235 | let extractionPhase = 0; 236 | 237 | const wfExtractor = new WfExtractor({ 238 | region, 239 | rootDir, 240 | swfMode: (parseActionScript && 'full') || 'simple', 241 | customPort, 242 | extractAllFrames, 243 | deltaMode, 244 | }); 245 | 246 | if (debug) { 247 | const start = new Date().getTime(); 248 | try { 249 | logger.log(`Executing command ${debug}`); 250 | await wfExtractor.executeCommand(debug); 251 | } catch (err) { 252 | console.log(err); 253 | logger.log(`Error executing command ${debug}`); 254 | logger.log(err?.message || `${err}`); 255 | } 256 | const end = new Date().getTime(); 257 | logger.log(`Process done in ${((end - start) / 1000).toFixed(2)}s`); 258 | 259 | event.reply('extractionResponseMain', { success: true }); 260 | return; 261 | } 262 | 263 | while (replyPacket !== 'done') { 264 | console.log(`TRYING EXTRACTION, Current Phase ${extractionPhase}`); 265 | 266 | if (replyPacket === 'purgeSwf') { 267 | await wfExtractor.markMetaData({ 268 | lastSwfChecksum: null, 269 | lastSwfMode: null, 270 | }); 271 | } 272 | if (/phase/.test(replyPacket)) { 273 | const targetPhase = parseFloat(replyPacket.split(':')[1]); 274 | 275 | extractionPhase = targetPhase; 276 | } 277 | try { 278 | if (extractionPhase <= 0) { 279 | await wfExtractor.init(); 280 | extractionPhase = 1; 281 | } 282 | 283 | if (extractionPhase <= 4.5) { 284 | await wfExtractor.buildDigestFileMap(); 285 | 286 | extractionPhase = 5; 287 | } 288 | 289 | if (extractionPhase <= 5) { 290 | if (extractMaster || /extractMaster/.test(replyPacket)) { 291 | await wfExtractor.extractMasterTable(); 292 | if (parseActionScript) { 293 | await wfExtractor.buildAsFilePaths(); 294 | } else { 295 | await wfExtractor.loadAsFilePaths(); 296 | } 297 | } else { 298 | await wfExtractor.loadFilePaths(); 299 | await wfExtractor.loadAsFilePaths(); 300 | } 301 | extractionPhase = 5.5; 302 | } 303 | 304 | if (extractionPhase <= 5.5) { 305 | if (extractMaster) { 306 | await wfExtractor.extractGachaOdds(); 307 | } 308 | 309 | extractionPhase = 6; 310 | } 311 | 312 | if (extractionPhase <= 6) { 313 | if (extractCharacterImage) { 314 | await wfExtractor.extractCharacterImageAssets(); 315 | 316 | if (processAtlas) { 317 | await wfExtractor.extractCharacterSpriteMetaDatas(); 318 | await wfExtractor.generateAnimatedSprites(); 319 | } 320 | } 321 | extractionPhase = 7; 322 | } 323 | 324 | if (extractionPhase <= 7) { 325 | if (extractMiscImage) { 326 | await wfExtractor.extractPossibleImageAssets({ 327 | cropSprites: processAtlasMisc, 328 | }); 329 | } 330 | 331 | extractionPhase = 7.5; 332 | } 333 | 334 | if (extractionPhase <= 7.5) { 335 | if (extractGeneralAmf) { 336 | await wfExtractor.extractPossibleGeneralAmf3Assets(); 337 | await wfExtractor.extractSkillEffects(); 338 | } 339 | 340 | extractionPhase = 8; 341 | } 342 | 343 | if (extractionPhase <= 8) { 344 | if (extractAudio) { 345 | await wfExtractor.extractCharacterVoiceAssets(); 346 | await wfExtractor.extractPossibleAudioAssets(); 347 | } 348 | 349 | extractionPhase = 9; 350 | } 351 | 352 | if (extractionPhase <= 9) { 353 | if (extractEsdl) { 354 | await wfExtractor.extractPossibleEnemyDslAssets(); 355 | } 356 | 357 | extractionPhase = 10; 358 | } 359 | 360 | await wfExtractor.saveConfirmedDigests(); 361 | 362 | break; 363 | } catch (err) { 364 | console.log(err); 365 | logger.log(`Error ocurred while extraction: ${err?.message || err}`); 366 | 367 | event.reply('extractionResponseMain', { 368 | error: err?.message || 'UNKNOWN', 369 | }); 370 | replyPacket = await extractionProcessor.awaitNextPacket(); 371 | } 372 | } 373 | 374 | event.reply('extractionResponseMain', { success: true }); 375 | } 376 | ); 377 | 378 | if (process.env.NODE_ENV === 'production') { 379 | const sourceMapSupport = require('source-map-support'); 380 | sourceMapSupport.install(); 381 | } 382 | 383 | const isDevelopment = 384 | process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; 385 | if (isDevelopment) { 386 | require('electron-debug')(); 387 | } 388 | 389 | const installExtensions = async () => { 390 | const installer = require('electron-devtools-installer'); 391 | const forceDownload = !!process.env.UPGRADE_EXTENSIONS; 392 | const extensions = ['REACT_DEVELOPER_TOOLS']; 393 | 394 | return installer 395 | .default( 396 | extensions.map((name) => installer[name]), 397 | forceDownload 398 | ) 399 | .catch(console.log); 400 | }; 401 | 402 | const RESOURCE_PATH = app.isPackaged 403 | ? process.resourcesPath 404 | : path.join(__dirname, '../../'); 405 | 406 | const ASSETS_PATH = path.join(RESOURCE_PATH, 'assets'); 407 | 408 | const getAssetPath = (...paths: string[]): string => { 409 | return path.join(ASSETS_PATH, ...paths); 410 | }; 411 | 412 | if (process.env.NODE_ENV !== 'development') { 413 | const logs = createWriteStream(path.join(RESOURCE_PATH, '/debug_out.log')); 414 | process.stdout.write = process.stderr.write = logs.write.bind(logs); // eslint-disable-line 415 | } 416 | 417 | const createWindow = async () => { 418 | if (isDevelopment) { 419 | await installExtensions(); 420 | } 421 | 422 | mainWindow = new BrowserWindow({ 423 | show: false, 424 | width: 1024, 425 | height: 728, 426 | resizable: false, 427 | icon: getAssetPath('icon.ico'), 428 | webPreferences: { 429 | preload: path.join(__dirname, 'preload.js'), 430 | }, 431 | }); 432 | 433 | logger.connectWindow(mainWindow); 434 | 435 | mainWindow.setMenu(null); 436 | 437 | mainWindow.loadURL(resolveHtmlPath('index.html')); 438 | 439 | mainWindow.on('ready-to-show', () => { 440 | if (!mainWindow) { 441 | throw new Error('"mainWindow" is not defined'); 442 | } 443 | if (process.env.START_MINIMIZED) { 444 | mainWindow.minimize(); 445 | } else { 446 | mainWindow.show(); 447 | } 448 | autoUpdater.checkForUpdatesAndNotify(); 449 | }); 450 | 451 | mainWindow.on('closed', () => { 452 | mainWindow = null; 453 | }); 454 | }; 455 | 456 | /** 457 | * Add event listeners... 458 | */ 459 | 460 | app.on('window-all-closed', () => { 461 | // Respect the OSX convention of having the application in memory even 462 | // after all windows have been closed 463 | if (process.platform !== 'darwin') { 464 | app.quit(); 465 | } 466 | }); 467 | 468 | app 469 | .whenReady() 470 | .then(() => { 471 | createWindow(); 472 | app.on('activate', () => { 473 | // On macOS it's common to re-create a window in the app when the 474 | // dock icon is clicked and there are no other windows open. 475 | if (mainWindow === null) createWindow(); 476 | }); 477 | }) 478 | .catch(console.log); 479 | 480 | autoUpdater.on('update-available', () => { 481 | mainWindow.webContents.send('update_available'); 482 | }); 483 | autoUpdater.on('update-downloaded', () => { 484 | mainWindow.webContents.send('update_downloaded'); 485 | }); 486 | -------------------------------------------------------------------------------- /src/main/menu.ts: -------------------------------------------------------------------------------- 1 | import { 2 | app, 3 | Menu, 4 | shell, 5 | BrowserWindow, 6 | MenuItemConstructorOptions, 7 | } from 'electron'; 8 | 9 | interface DarwinMenuItemConstructorOptions extends MenuItemConstructorOptions { 10 | selector?: string; 11 | submenu?: DarwinMenuItemConstructorOptions[] | Menu; 12 | } 13 | 14 | export default class MenuBuilder { 15 | mainWindow: BrowserWindow; 16 | 17 | constructor(mainWindow: BrowserWindow) { 18 | this.mainWindow = mainWindow; 19 | } 20 | 21 | buildMenu(): Menu { 22 | if ( 23 | process.env.NODE_ENV === 'development' || 24 | process.env.DEBUG_PROD === 'true' 25 | ) { 26 | this.setupDevelopmentEnvironment(); 27 | } 28 | 29 | const template = this.buildDefaultTemplate(); 30 | 31 | const menu = Menu.buildFromTemplate(template); 32 | Menu.setApplicationMenu(menu); 33 | 34 | return menu; 35 | } 36 | 37 | setupDevelopmentEnvironment(): void { 38 | this.mainWindow.webContents.on('context-menu', (_, props) => { 39 | const { x, y } = props; 40 | 41 | Menu.buildFromTemplate([ 42 | { 43 | label: 'Inspect element', 44 | click: () => { 45 | this.mainWindow.webContents.inspectElement(x, y); 46 | }, 47 | }, 48 | ]).popup({ window: this.mainWindow }); 49 | }); 50 | } 51 | 52 | buildDefaultTemplate() { 53 | const templateDefault = [ 54 | { 55 | label: '&File', 56 | submenu: [ 57 | { 58 | label: '&Open', 59 | accelerator: 'Ctrl+O', 60 | }, 61 | { 62 | label: '&Close', 63 | accelerator: 'Ctrl+W', 64 | click: () => { 65 | this.mainWindow.close(); 66 | }, 67 | }, 68 | ], 69 | }, 70 | ]; 71 | 72 | return templateDefault; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/preload.js: -------------------------------------------------------------------------------- 1 | const { contextBridge, ipcRenderer, shell } = require('electron'); 2 | 3 | contextBridge.exposeInMainWorld('electron', { 4 | ipcRenderer: { 5 | showOpenDialog() { 6 | ipcRenderer.send('showOpenDialog', 'asd'); 7 | }, 8 | openDirectory(dir) { 9 | ipcRenderer.send('openDirectory', dir); 10 | }, 11 | startExtraction(rootDir, options) { 12 | ipcRenderer.send('startExtraction', rootDir, options); 13 | }, 14 | startPull(rootDir, options) { 15 | ipcRenderer.send('startPull', rootDir, options); 16 | }, 17 | openExternal(external) { 18 | shell.openExternal(external); 19 | }, 20 | openDevTools() { 21 | ipcRenderer.send('openDevTools'); 22 | }, 23 | clearMeta(rootDir, targetData) { 24 | ipcRenderer.send('clearMeta', rootDir, targetData); 25 | }, 26 | getMeta(rootDir) { 27 | ipcRenderer.send('getMeta', rootDir); 28 | }, 29 | getAppVersion() { 30 | ipcRenderer.send('getAppVersion'); 31 | }, 32 | updateApp() { 33 | ipcRenderer.send('updateApp'); 34 | }, 35 | responseExtraction(response) { 36 | ipcRenderer.send('extractionResponseRenderer', response); 37 | }, 38 | on(channel, func) { 39 | ipcRenderer.on(channel, (event, ...args) => func(...args)); 40 | }, 41 | once(channel, func) { 42 | ipcRenderer.once(channel, (event, ...args) => func(...args)); 43 | }, 44 | removeAllListeners(channel) { 45 | ipcRenderer.removeAllListeners(channel); 46 | }, 47 | }, 48 | }); 49 | -------------------------------------------------------------------------------- /src/main/util.ts: -------------------------------------------------------------------------------- 1 | /* eslint import/prefer-default-export: off, import/no-mutable-exports: off */ 2 | import { URL } from 'url'; 3 | import path from 'path'; 4 | 5 | export let resolveHtmlPath: (htmlFileName: string) => string; 6 | 7 | if (process.env.NODE_ENV === 'development') { 8 | const port = process.env.PORT || 1212; 9 | resolveHtmlPath = (htmlFileName: string) => { 10 | const url = new URL(`http://localhost:${port}`); 11 | url.pathname = htmlFileName; 12 | return url.href; 13 | }; 14 | } else { 15 | resolveHtmlPath = (htmlFileName: string) => { 16 | return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/wf/constants.js: -------------------------------------------------------------------------------- 1 | export const ELIGIBLE_PATH_PREFIXES = [ 2 | 'dump/upload/', 3 | 'dump/medium_upload/', 4 | 'dump/small_upload', 5 | ]; 6 | 7 | export const MERGEABLE_PATH_PREFIXES = [ 8 | 'dump/android_upload/', 9 | 'dump/android_small_upload/', 10 | 'dump/android_medium_upload/', 11 | 'dump/bundle/', 12 | 'dump/medium_bundle/', 13 | 'dump/small_bundle/', 14 | ]; 15 | 16 | export const ANIMATION_COMMON_POSTFIXES = [ 17 | 'start', 18 | 'charge', 19 | 'fire', 20 | 'attack', 21 | 'loop', 22 | 'set', 23 | 'end', 24 | 'start1', 25 | 'charge1', 26 | 'fire1', 27 | 'attack1', 28 | 'loop1', 29 | 'set1', 30 | 'end1', 31 | 'start2', 32 | 'charge2', 33 | 'fire2', 34 | 'attack2', 35 | 'loop2', 36 | 'set2', 37 | 'end2', 38 | 'start3', 39 | 'charge3', 40 | 'fire3', 41 | 'attack3', 42 | 'loop3', 43 | 'set3', 44 | 'end3', 45 | 'start4', 46 | 'charge4', 47 | 'fire4', 48 | 'attack4', 49 | 'loop4', 50 | 'set4', 51 | 'end4', 52 | 'start5', 53 | 'charge5', 54 | 'fire5', 55 | 'attack5', 56 | 'loop5', 57 | 'set5', 58 | 'end5', 59 | ]; 60 | 61 | export const ACTION_DSL_FORMAT_DEFLATE = '.action.dsl.amf3.deflate'; 62 | export const ENEMY_DSL_FORMAT_DEFLATE = '.esdl.amf3.deflate'; 63 | 64 | export const CHARACTER_SPRITE_PRESETS = [ 65 | (character, index) => `character/${character}/pixelart/sprite_sheet`, 66 | (character, index) => `character/${character}/pixelart/special_sprite_sheet`, 67 | (character, index) => `character/${character}/pixelart/special`, 68 | (character, index) => `character/${character}/ui/skill_cutin_${index}`, 69 | (character, index) => `character/${character}/ui/cutin_skill_chain_${index}`, 70 | (character, index) => `character/${character}/pixelart/pixelart`, 71 | (character, index) => `character/${character}/ui/thumb_party_unison_${index}`, 72 | (character, index) => `character/${character}/ui/thumb_party_main_${index}`, 73 | (character, index) => 74 | `character/${character}/ui/battle_member_status_${index}`, 75 | (character, index) => `character/${character}/ui/thumb_level_up_${index}`, 76 | (character, index) => `character/${character}/ui/square_${index}`, 77 | (character, index) => `character/${character}/ui/square_132_132_${index}`, 78 | (character, index) => 79 | `character/${character}/ui/square_round_136_136_${index}`, 80 | (character, index) => `character/${character}/ui/square_round_95_95_${index}`, 81 | (character, index) => 82 | `character/${character}/ui/battle_member_status_${index}`, 83 | (character, index) => `character/${character}/ui/episode_banner_0`, 84 | (character, index) => 85 | `character/${character}/ui/battle_control_board_${index}`, 86 | (character, index) => 87 | `character/${character}/battle/character_detail_skill_preview`, 88 | (character, index) => 89 | `character/${character}/ui/illustration_setting_sprite_sheet`, 90 | (character, index) => 91 | `character/${character}/battle/character_info_skill_preview`, 92 | (character, index) => 93 | `character/${character}/ui/full_shot_1440_1920_${index}`, 94 | (character, index) => 95 | `character/${character}/ui/full_shot_illustration_setting_${index}`, 96 | (character) => `character/${character}/ui/story/anger`, 97 | (character) => `character/${character}/ui/story/anger_b`, 98 | (character) => `character/${character}/ui/story/anger_c`, 99 | (character) => `character/${character}/ui/story/anger_d`, 100 | (character) => `character/${character}/ui/story/anger_e`, 101 | (character) => `character/${character}/ui/story/anger_f`, 102 | (character) => `character/${character}/ui/story/base_0`, 103 | (character) => `character/${character}/ui/story/base_0_b`, 104 | (character) => `character/${character}/ui/story/base_0_c`, 105 | (character) => `character/${character}/ui/story/base_0_d`, 106 | (character) => `character/${character}/ui/story/base_0_e`, 107 | (character) => `character/${character}/ui/story/base_0_f`, 108 | (character) => `character/${character}/ui/story/base_1`, 109 | (character) => `character/${character}/ui/story/base_1_b`, 110 | (character) => `character/${character}/ui/story/base_1_c`, 111 | (character) => `character/${character}/ui/story/base_1_d`, 112 | (character) => `character/${character}/ui/story/base_1_e`, 113 | (character) => `character/${character}/ui/story/base_1_f`, 114 | (character) => `character/${character}/ui/story/normal`, 115 | (character) => `character/${character}/ui/story/normal_b`, 116 | (character) => `character/${character}/ui/story/normal_c`, 117 | (character) => `character/${character}/ui/story/normal_d`, 118 | (character) => `character/${character}/ui/story/normal_e`, 119 | (character) => `character/${character}/ui/story/normal_f`, 120 | (character) => `character/${character}/ui/story/sad`, 121 | (character) => `character/${character}/ui/story/sad_b`, 122 | (character) => `character/${character}/ui/story/sad_c`, 123 | (character) => `character/${character}/ui/story/sad_d`, 124 | (character) => `character/${character}/ui/story/sad_e`, 125 | (character) => `character/${character}/ui/story/sad_f`, 126 | (character) => `character/${character}/ui/story/serious`, 127 | (character) => `character/${character}/ui/story/serious_b`, 128 | (character) => `character/${character}/ui/story/serious_c`, 129 | (character) => `character/${character}/ui/story/serious_d`, 130 | (character) => `character/${character}/ui/story/serious_e`, 131 | (character) => `character/${character}/ui/story/serious_f`, 132 | (character) => `character/${character}/ui/story/shame`, 133 | (character) => `character/${character}/ui/story/shame_b`, 134 | (character) => `character/${character}/ui/story/shame_c`, 135 | (character) => `character/${character}/ui/story/shame_d`, 136 | (character) => `character/${character}/ui/story/shame_e`, 137 | (character) => `character/${character}/ui/story/shame_f`, 138 | (character) => `character/${character}/ui/story/shout`, 139 | (character) => `character/${character}/ui/story/shout_b`, 140 | (character) => `character/${character}/ui/story/shout_c`, 141 | (character) => `character/${character}/ui/story/shout_d`, 142 | (character) => `character/${character}/ui/story/shout_e`, 143 | (character) => `character/${character}/ui/story/shout_f`, 144 | (character) => `character/${character}/ui/story/smile`, 145 | (character) => `character/${character}/ui/story/smile_b`, 146 | (character) => `character/${character}/ui/story/smile_c`, 147 | (character) => `character/${character}/ui/story/smile_d`, 148 | (character) => `character/${character}/ui/story/smile_e`, 149 | (character) => `character/${character}/ui/story/smile_f`, 150 | (character) => `character/${character}/ui/story/surprise`, 151 | (character) => `character/${character}/ui/story/surprise_b`, 152 | (character) => `character/${character}/ui/story/surprise_c`, 153 | (character) => `character/${character}/ui/story/surprise_d`, 154 | (character) => `character/${character}/ui/story/surprise_e`, 155 | (character) => `character/${character}/ui/story/surprise_f`, 156 | (character) => `character/${character}/ui/story/sweat`, 157 | (character) => `character/${character}/ui/story/sweat_b`, 158 | (character) => `character/${character}/ui/story/sweat_c`, 159 | (character) => `character/${character}/ui/story/sweat_d`, 160 | (character) => `character/${character}/ui/story/sweat_e`, 161 | (character) => `character/${character}/ui/story/sweat_f`, 162 | (character) => `character/${character}/ui/story/think`, 163 | (character) => `character/${character}/ui/story/think_b`, 164 | (character) => `character/${character}/ui/story/think_c`, 165 | (character) => `character/${character}/ui/story/think_d`, 166 | (character) => `character/${character}/ui/story/think_e`, 167 | (character) => `character/${character}/ui/story/think_f`, 168 | (character) => `character/${character}/ui/story/vigilant`, 169 | (character) => `character/${character}/ui/story/vigilant_b`, 170 | (character) => `character/${character}/ui/story/vigilant_c`, 171 | (character) => `character/${character}/ui/story/vigilant_d`, 172 | (character) => `character/${character}/ui/story/vigilant_e`, 173 | (character) => `character/${character}/ui/story/vigilant_f`, 174 | ]; 175 | 176 | export const CHARACTER_AMF_PRESERTS = [ 177 | (character) => `character/${character}/pixelart/pixelart.frame.amf3.deflate`, 178 | (character) => 179 | `character/${character}/pixelart/sprite_sheet.parts.amf3.deflate`, 180 | (character) => 181 | `character/${character}/pixelart/pixelart.timeline.amf3.deflate`, 182 | (character) => `character/${character}/pixelart/special.frame.amf3.deflate`, 183 | (character) => 184 | `character/${character}/pixelart/special_sprite_sheet.parts.amf3.deflate`, 185 | (character) => 186 | `character/${character}/pixelart/special.timeline.amf3.deflate`, 187 | (character) => 188 | `character/${character}/pixelart/special_sprite_sheet.atlas.amf3.deflate`, 189 | (character) => 190 | `character/${character}/pixelart/sprite_sheet.atlas.amf3.deflate`, 191 | ]; 192 | 193 | export const BASE_ODD_MAP = { 194 | 3: 0.7, 195 | 4: 0.25, 196 | 5: 0.05, 197 | }; 198 | 199 | export const POSSIBLE_PATH_REGEX = /[.$a-zA-Z_0-9-]+?\/[.$a-zA-Z_0-9/-]+/g; 200 | 201 | export const IS_DEVELOPMENT = process.env.NODE_ENV === 'development'; 202 | 203 | export const CHARACTER_VOICE_PRESETS = [ 204 | (character) => `character/${character}/voice/ally/evolution.mp3`, 205 | (character) => `character/${character}/voice/ally/join.mp3`, 206 | (character) => `character/${character}/voice/battle/battle_start_0.mp3`, 207 | (character) => `character/${character}/voice/battle/battle_start_1.mp3`, 208 | (character) => `character/${character}/voice/battle/outhole_0.mp3`, 209 | (character) => `character/${character}/voice/battle/outhole_1.mp3`, 210 | (character) => `character/${character}/voice/battle/power_flip_0.mp3`, 211 | (character) => `character/${character}/voice/battle/power_flip_1.mp3`, 212 | (character) => `character/${character}/voice/battle/skill_0.mp3`, 213 | (character) => `character/${character}/voice/battle/skill_1.mp3`, 214 | (character) => `character/${character}/voice/battle/skill_ready.mp3`, 215 | (character) => `character/${character}/voice/battle/win_0.mp3`, 216 | (character) => `character/${character}/voice/battle/win_1.mp3`, 217 | ]; 218 | 219 | export const NOX_PORT_LIST = [62001, 62025]; 220 | export const DATEFORMAT_A = 'YYYY-MM-DD HH:mm'; 221 | 222 | export const COMMON_FILE_FORMAT = [".php",".html",".txt",".htm",".aspx",".asp",".js",".css",".pgsql.txt",".mysql.txt",".pdf",".cgi",".inc",".gif",".jpg",".swf",".xml",".cfm",".xhtml",".wmv",".zip",".axd",".gz",".png",".doc",".shtml",".jsp",".ico",".exe",".csi",".inc.php",".config",".jpeg",".ashx",".log",".tar",".ini",".asa",".tgz",".PDF",".flv.bak",".rar",".asmx",".xlsx",".page",".phtml",".dll",".JPG",".asax.msg",".pl",".GIF",".ZIP",".csv",".nsf",".Pdf",".Gif",".bmp",".sql",".Jpeg",".Jpg",".xml.gz",".Zip",".new",".avi",".psd",".rss.wav",".action",".db",".dat",".do",".xsl",".class",".mdb",".include.cs",".class.php",".htc",".mov",".tpl.js.php",".mpg",".rdf",".rtf.ascx",".mvc.files",".master",".jar",".fla",".require",".de",".docx.wci",".readme.cfg",".aspx.cs",".cfc",".dwt",".ru",".LCK",".Config",".gif_var_DE",".net",".ttf",".HTM",".X-AOM",".jhtml",".mpeg",".ASP",".LOG",".vcf",".X-RMA",".X-OFFERS",".X-FCOMP",".X-GIFTREG",".X-PCONF",".X-SURVEY",".tif",".dir",".json.Zif",".wma.mid",".rm",".aspx.vb",".tar.gz",".woa",".main",".ram",".feed",".lasso.shtm",".sitemap",".scc",".tmp",".backup",".sln",".org",".conf",".uk",".TXT",".orig",".kml",".lck",".pps",".asx",".bok",".msi.c",".fcgi",".fopen",".html.",".bin",".htaccess",".info",".java",".jsf",".tmpl",".DOC",".bat",".com.html",".print",".resx",".ics",".php.php",".x",".PNG",".data",".dcr",".enfinity",".html.html",".licx",".mno",".plx",".vm",".dwg",".edu",".search",".static",".wws",".OLD.co.uk",".ece",".epc",".ice",".jspa",".lst",".php-dist",".svc",".vbs",".ai",".cur",".dmg",".img",".inf",".seam",".smtp.php",".ajax",".cfm.cfm",".chm",".csp",".edit",".file",".py",".sh",".test",".zdat.admin",".dev",".eps",".fr",".fsockopen",".new.html",".p",".store",".webinfo",".xml.php",".BAK",".htm.",".php.bak",".bk",".bsp",".cms",".d",".html,",".htmll",".idx",".images",".jad",".master.cs",".prev_next",".ssf",".stm",".txt.gz",".as",".asp.asp",".au",".cnf",".dhtml",".enu",".html.old",".lock",".m",".phps",".pm",".pptx",".sav",".ssi",".suo",".vbproj",".wml",".xsd",".ASPX",".JS",".PHP",".array-keys",".atom",".award",".bkp",".crt",".default",".eml",".epl",".fancybox",".fil",".geo",".h",".hmtl",".html.bak",".ida",".implode",".index.php",".iso",".kmz",".php.old",".php.txt",".rec",".storefront",".taf",".war",".xslt.CSS",".NSF",".Sponsors",".a",".aquery",".ascx.cs",".cat",".contrib",".ds",".dwf",".film",".g",".go",".googlebook",".gpx",".hotelName",".htm.htm",".ihtml",".in-array",".index",".ini.php",".layer",".maninfo",".odt",".price",".read",".sit",".src",".tpl.php",".trck",".uguide",".vorteil",".wbp",".AVI",".Asp",".EXE",".WMV",".asax.vb",".aspx.aspx",".btr",".cer",".common.php",".de.html",".jbf",".lbi",".lib.php",".lnk",".login",".login.php",".mhtml",".mpl",".mso",".original",".pgp",".ph",".php.",".preview",".search.htm",".site",".text",".view.ICO",".Web",".XLS.asc",".asp.bak",".aspx.resx",".browse",".code",".csproj",".dtd",".en.html",".ep",".eu",".index.html",".it",".nl",".ogg",".out",".pgt",".php",".po",".prt",".query",".rb",".rhtml",".ru.html",".save",".search.php",".t",".wsdl",".CFM",".MOV",".MPEG",".Master",".PPT",".TTF",".Templates",".XML",".adp",".ajax.php",".apsx",".asf",".bck",".bu",".calendar",".captcha",".cart",".com.crt",".core",".dict.php",".dot",".egov",".en.php",".eot",".git",".ht",".hta",".html.LCK",".ini.sample",".lib",".lic",".map",".master.vb",".mi",".mkdir",".o.pac",".pd",".phtm",".png.php",".portal",".printable",".psql",".pub",".q",".ra",".reg",".rpm",".strpos",".tcl",".template",".tiff",".tv",".us",".WAV",".acgi",".alt",".back",".cfml",".cmd",".detail",".disabled",".dist.php",".djvu",".dta",".e",".extract",".fpl",".framework",".fread",".htm.LCK",".inc.js",".includes",".jp",".jpg.html",".l",".letter",".local",".num",".pem",".php.sample",".php",".php~",".pot",".preg-match",".process",".ps",".r",".raw",".rc",".s",".search.",".server",".sis",".sql.gz",".squery",".subscribe",".svg",".svn",".thtml",".tpl.html",".ua",".vcs",".xhtm",".xml.asp",".xpi.A",".PAGE",".SWF",".add",".array-rand",".asax.cs",".asax.resx",".ascx.vb",".aspx,",".aspx.",".awm",".b",".bhtml",".bml",".ca",".cache",".cfg.php",".cn",".cz",".de.txt",".diff",".email",".en",".error",".faces",".filesize",".hml",".htmls",".htx",".i",".idq",".jpe",".js.aspx",".js.gz",".jspf",".load",".media.mspx",".mv",".mysql",".new.php",".ocx",".oui",".outcontrol",".pad",".pages",".pdb",".pdf.",".pnp",".popup.php",".pvk",".results",".run",".scripts",".sdb",".ser",".shop",".smi",".start",".ste",".swf.swf",".templates",".textsearch",".torrent",".v",".web",".wmf",".wpd",".ws",".xpml",".y",".AdCode",".Aspx",".C.",".COM",".Html",".Run.AdCode",".Skins",".Z",".ajax.asp",".app",".asd",".asm",".assets",".at",".bad.blog",".casino",".cc",".cdr",".children",".com,",".content",".copy",".count",".cp",".custom",".dbf",".deb",".delete",".dic",".divx",".download",".epub",".err",".es",".exclude",".home",".htlm",".htm,",".html-",".image",".inc.html",".it.html",".j",".jnlp",".link",".mc_id",".menu.php",".mgi",".mod",".net.html",".news",".none",".prg",".print.html",".print.php",".pwd",".pyc",".red",".se",".sea",".sema",".session",".setup",".sitx",".smil",".srv",".swi",".swp",".sxw.tem",".temp",".top",".txt.php",".types",".unlink",".url",".vspscc",".vssscc",".w",".work",".wvx",".xspf",".-",".Admin",".E.",".Engineer",".INC",".LOG.new",".MAXIMIZE",".MPG",".NDM",".Php",".R",".SIM",".SQL",".Services",".file",".accdb",".act",".admin.php",".ads",".alhtm",".all",".ani",".apf",".apj",".ar",".arc",".bfhtm",".br",".browser",".build",".buscar",".categorias",".categories",".ccs",".ch",".cl",".click.php",".cls",".cls.php",".com.ar",".com.br",".com.htm",".com.old",".common",".conf.php",".control",".core.php",".create.php",".dbm",".dct",".dmb",".doc.doc",".dxf",".ed",".en.htm",".engine",".env",".error-log",".esp",".ex",".exc",".exe,",".ext",".external",".ficheros",".fichiers",".flush",".fmt",".fn",".footer",".form_jhtml",".friend",".g.",".geo.xml",".ghtml",".google.com",".gov",".gpg",".hl",".href",".htm.d",".htm.html",".html.sav",".html",".html",".htmlprint",".htm~",".hts",".hu",".hwp",".ibf",".il",".image.php",".imagejpeg",".iml",".imprimer",".imprimir",".info.html",".info.php",".ini.bak",".inl",".inv",".join",".jpg.jpg",".jps",".key",".kit",".lang",".lignee",".ltr",".lzh.mail",".metadesc",".metakeys",".mht",".min",".mld",".mobi",".mobile.n",".nfo",".nikon",".nodos",".nxg",".obyx",".old.html",".open",".ord",".org.zip",".ori",".partfinder",".pho",".php-",".phpl",".phpx",".pix",".pls",".prc",".pre",".prhtm",".print.",".printer",".properties",".propfinder",".pvx",".php",".recherche",".redirect",".req",".safe",".sbk",".se.php",".search.asp",".sec",".seo",".serv",".server.php",".servlet",".settings",".sf",".show",".sht",".skins",".so",".sph",".split",".sso",".stats.php",".story",".swd",".swf.html",".sys",".tex",".tga",".thm",".tlp",".tml",".tmp.php",".touch",".tsv",".txt.",".txt.html",".ug",".vsprintf",".vstemplate",".vtl",".wbmp",".webc",".webproj",".wihtm",".wp",".wps",".wri",".wsc",".www",".xsp",".xsql",".zip,",".zml",".ztml",". T.",". php",".A..AEFA",".ALT",".ASC.",".Appraisal",".BBC.BMP",".C.R.D.",".CAA",".Cfm",".Commerce",".Css",".D.",".D.R.",".DBF.DESC.",".DLL",".DOCX",".Direct",".EEA.Email",".Eus.FAE",".FRK",".H.I.",".INFO",".INI",".ISO",".Includes",".K.E.",".K.T.",".KB",".L.",".L.jpg",".LassoApp",".MLD",".Main",".NET",".Old",".Org.master",".Org.sln",".Org.vssscc",".P.",".PSD",".Publish",".RAW",".S",".SideMenu",".T.A",".T.A.",".TEST",".Tung.php",".WTC",".XMLHTTP",".Xml","._._order","._order",".a.html.aac",".access",".act.php",".action.php",".actions",".ad.php",".add.php",".adenaw.com",".adm",".advsearch",".ag.php",".aj_",".all.hawaii",".ap",".api",".apk",".archiv",".arj",".array-map",".art",".artdeco",".articlePk",".artnet.",".ascx.resx",".asia",".asp-",".asp.LCK",".asp",".asp_files",".aspl",".aspp",".asps",".aspx_files",".aspxx",".aspy",".asxp",".at.html",".avatar.php",".awstats",".backup.php",".bak.php",".banan.se",".banner.php",".barnes",".baut",".bc",".beta",".biz",".bmp.php",".board.asd",".boom",".buyadspace",".bycategory",".bylocation",".bz",".c.html",".cache.php",".car",".cat.php",".catalog",".cdf",".ce",".cfm.bak",".cfswf",".cfx",".cgis",".chat",".chdir",".cmp",".cnt",".co",".co.il",".com.au",".com.php",".com.ua",".com_files",".comments",".comments.",".conf.html",".console",".contact",".corp",".cqs",".cron",".crx",".csr",".css.LCK",".css.gz",".cssd",".csv.php",".ctp",".cx",".dal",".daniel",".data.php",".data_",".davis",".dbml",".dcf",".de.jsp",".del",".deleted",".dell",".demo",".dig",".dist",".dk",".dm",".dms",".dnn",".dogpl",".dontcopy",".du",".dump",".dws",".ebay",".ehtml",".en.jsp",".enn",".es.html",".es.jsp",".eur",".exec",".exp",".f.l.",".feeds.php",".ffa",".ficken.cx",".filereader",".flac",".flypage",".fon",".form.php",".forms",".forum",".frk",".ft",".ftl",".fucks.nl",".funzz.fr",".garcia",".gb",".get",".gif.count",".glasner.ru",".google",".gray",".gsp",".guiaweb.tk",".gutschein",".guy",".ha",".hasrett.de",".hawaii",".header.php",".henry",".him",".history",".hlr",".hm",".ho",".hokkaido",".hold",".home.php",".home.test",".homepage",".hp",".htm.bak",".htm.rc",".htm_",".html,,",".html-c",".html-old",".html-p",".html.htm",".html.inc",".html.none",".html.pdf",".html.start",".html_old",".htmla",".htmlc",".htmlfeed",".htmlq",".htmlu",".htn",".htpasswd",".html",".iac.",".iconv",".idf",".ignore.php",".ihmtl",".ihya",".imp",".in",".inactive",".incl",".indt",".insert",".ipl",".issues",".itml",".ixi",".jhtm",".job",".joseph",".jpf",".jpg.xml",".jpg",".js,",".js.LCK",".jsa",".jsd",".jso",".jsp.old",".jsps",".jtp",".keyword",".kk",".kokuken",".ks",".lang.php",".last",".latest",".lha",".links",".listing",".lng",".loc",".local.cfm",".lynkx",".mag",".mail.php",".mbizgroup",".mel",".members",".meus.php",".midi",".min_",".mkv",".mmap",".mp",".mreply.rc",".msp",".mvn",".mysqli",".net-en",".new.htm",".newsletter",".nl.html",".nonude.org",".nth",".nz",".od",".offer.php",".offline",".ogv",".ok.old.htm",".old.old",".older",".oliver",".online",".opensearch",".orig.html",".origin.php",".osg",".outbound",".owen",".pae",".pan",".parse-url",".part",".pass",".patch",".paul",".pdd",".pdf.html",".pdf.pdf",".pdf.php",".pdfx",".phdo",".photo",".php.LCK",".php.backup",".php.html",".php.inc",".php.mno",".php_",".php_OLD",".php_old",".phphp",".phppar",".php",".pht",".pl.html",".plugins",".png,bmp",".popup",".pornz.tv",".prev",".print.jsp",".prl",".prosdo.com",".psb",".qtgp",".qxd",".r.",".rabattlp",".rails",".readfile",".rec.html",".remove",".remove.php",".removed",".resultados",".resume",".rhtm",".rmvb",".ro",".roma",".rpt",".rsp",".rss.php",".rss_cars",".rss_homes",".rss_jobs",".rtfd",".rvt",".s.html",".safariextz",".sc",".scandir",".sec.cfm",".section",".secure",".send",".sent-",".service",".set",".sgf",".show.php",".shtml.html",".sidebar",".sisx",".sitemap.",".skin",".snuffx.com",".sort",".sp.srch",".srf",".srvl",".sta",".staged.php",".staging",".start.php",".stat",".stats",".step",".stml",".sts.php",".suarez",".submit",".support",".swf.LCK",".sym",".system",".tab-",".table.html",".tb",".tech",".temp.php",".test.cgi",".test.php",".tf",".tg",".thanks",".theme",".thompson",".thumb.jpg",".tim",".tk",".tls",".to",".trace",".trade",".ts",".tst",".tvpi",".txt.txt",".ufo",".update",".upgrade",".var.verify",".video",".vn",".vs",".vx",".vxlpub",".wax",".webalizer",".webarchive",".webm",".weedooz.eu",".wgx",".wimzi.php",".wireless",".wm",".working",".wpl",".wplus",".wps.rtf",".write.php",".xcam.at",".xconf",".xcwc.com",".xgi.xlt",".xm",".xml.old",".xpdf",".xqy",".xslx",".xst",".xsx",".xy.php",".yp",".ys",".z",".za",".zh.html",".zhtml",".zip.php"] // eslint-disable-line 223 | -------------------------------------------------------------------------------- /src/main/wf/digest.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | 3 | const digestSha1 = (originText) => { 4 | const hash = crypto.createHash('sha1'); 5 | hash.update(originText); 6 | return hash.digest('hex'); 7 | }; 8 | 9 | const digest = (originText) => { 10 | const shasum = crypto.createHash('sha1'); 11 | shasum.update(`${originText}K6R9T9Hz22OpeIGEWB0ui6c6PYFQnJGy`); 12 | return shasum.digest('hex'); 13 | }; 14 | 15 | module.exports = { 16 | digestWfFileName: digest, 17 | digestSha1, 18 | }; 19 | -------------------------------------------------------------------------------- /src/main/wf/helpers.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import { exec, spawn } from 'child_process'; 3 | import logger from './logger'; 4 | import { NOX_PORT_LIST } from './constants'; 5 | 6 | export const asyncMkdir = (...args) => 7 | new Promise((resolve) => fs.mkdir(...args, resolve)); 8 | 9 | export const asyncReadFile = (...args) => 10 | new Promise((resolve) => fs.readFile(...args, (err, data) => resolve(data))); 11 | 12 | export const asyncReadDir = (...args) => 13 | new Promise((resolve, reject) => 14 | fs.readdir(...args, (err, data) => (err ? reject(err) : resolve(data))) 15 | ); 16 | 17 | export const asyncRename = (...args) => 18 | new Promise((resolve, reject) => 19 | fs.rename(...args, (err, data) => (err ? reject(err) : resolve(data))) 20 | ); 21 | 22 | export const asyncExec = async (command: string): Promise => { 23 | console.log(command); 24 | return new Promise((resolve, reject) => 25 | exec(command, (err, stdout) => { 26 | console.log('EXEC', err, stdout); 27 | return err ? reject(err) : resolve(stdout); 28 | }) 29 | ); 30 | }; 31 | 32 | export const sleep = (timeout) => 33 | new Promise((resolve) => setTimeout(resolve, timeout)); 34 | 35 | export const spawnCommand = (command, args, { wait, logFn }) => { 36 | const child = spawn(command, args, {}); 37 | child.stderr.pipe(process.stderr); 38 | let awaitResolver; 39 | 40 | const awaiter = new Promise((resolve) => { 41 | awaitResolver = resolve; 42 | }); 43 | 44 | if (logFn) { 45 | child.stdout.on('data', (chunk) => logFn(chunk, awaitResolver)); 46 | } 47 | 48 | if (wait) { 49 | let lastChunkString; 50 | 51 | child.stdout.on('data', (chunk) => { 52 | console.log(chunk.toString()); 53 | if (`${lastChunkString}${chunk.toString()}`.includes(wait)) { 54 | awaitResolver(); 55 | } 56 | 57 | lastChunkString = chunk.toString(); 58 | }); 59 | 60 | return { process: child, awaiter }; 61 | } 62 | 63 | child.on('exit', awaitResolver); 64 | 65 | return { process: child, awaiter }; 66 | }; 67 | 68 | export const refineLs = (lsResult): Array => { 69 | const splits = lsResult.split(/[\r]{0,}\n/); 70 | 71 | let root; 72 | 73 | return splits 74 | .map((split) => { 75 | if (!/^[-a-z]{10}/.test(split)) { 76 | if (/:$/.test(split)) { 77 | [root] = split.split(':'); 78 | } 79 | return null; 80 | } 81 | 82 | const chunks = split.split(' ').filter((val) => val); 83 | 84 | const [permission, linkCount, owner, group, size, date, time, name] = 85 | chunks; 86 | 87 | return { 88 | isDirectory: permission[0] === 'd', 89 | permission, 90 | linkCount, 91 | owner, 92 | group, 93 | size, 94 | modifiedDate: `${date} ${time}`, 95 | name, 96 | path: `${root}/${name}`, 97 | }; 98 | }) 99 | .filter((val) => val); 100 | }; 101 | 102 | export const deepSearchUniqueMeaningfulStringsFromObject = (obj, arr = []) => { 103 | for (const prop in obj) { 104 | if (obj.hasOwnProperty(prop)) { 105 | if (typeof obj[prop] === 'object') { 106 | deepSearchUniqueMeaningfulStringsFromObject(obj[prop], arr); 107 | } else if (typeof obj[prop] === 'string') { 108 | if (arr.indexOf(obj[prop]) === -1) { 109 | arr.push(obj[prop]); 110 | } 111 | } 112 | } 113 | } 114 | return arr; 115 | }; 116 | 117 | export const withAsyncBandwidth = ( 118 | array, 119 | asyncMapper, 120 | { bandwidth = 5 } = {} 121 | ) => { 122 | if (bandwidth < 2) throw new Error('Bandwidth must bigger than 1'); 123 | 124 | const entries = [...array]; 125 | const chainedResponses = new Array(bandwidth) 126 | .fill() 127 | .map(() => new Promise((resolve) => resolve())); 128 | let iterator = 0; 129 | let index = 0; 130 | 131 | while (entries.length) { 132 | const currentEntry = entries.shift(); 133 | const currentIndex = index; 134 | 135 | const beforeResponse = chainedResponses[iterator]; 136 | 137 | chainedResponses[iterator] = beforeResponse.then(() => 138 | asyncMapper(currentEntry, currentIndex) 139 | ); 140 | 141 | index += 1; 142 | if (iterator < bandwidth - 1) { 143 | iterator += 1; 144 | } else { 145 | iterator = 0; 146 | } 147 | } 148 | 149 | return chainedResponses; 150 | }; 151 | 152 | export const compareVersion = (prev, next) => { 153 | const prevSplit = prev.split('.').map(parseFloat); 154 | const nextSplit = next.split('.').map(parseFloat); 155 | 156 | for (let majority = 0; majority < prevSplit.length; majority += 1) { 157 | const prevVersion = prevSplit[majority]; 158 | const nextVersion = nextSplit[majority]; 159 | 160 | if (prevVersion > nextVersion || !nextVersion) { 161 | return 1; 162 | } 163 | if (nextVersion > prevVersion) { 164 | return -1; 165 | } 166 | } 167 | 168 | return 0; 169 | }; 170 | -------------------------------------------------------------------------------- /src/main/wf/logger.ts: -------------------------------------------------------------------------------- 1 | import electron, { ipcMain } from 'electron'; 2 | 3 | class Logger { 4 | window: electron.BrowserWindow; 5 | 6 | preventDoneLog = false; 7 | 8 | constructor({ window }: { window: electron.BrowserWindow }) { 9 | this.window = window; 10 | this.absCount = 0; 11 | } 12 | 13 | setThrottle = () => { 14 | if (this.throttleTimeout) { 15 | clearTimeout(this.throttleTimeout); 16 | } 17 | this.throttle = true; 18 | 19 | this.throttleTimeout = setTimeout(() => { 20 | this.throttle = false; 21 | }, 100); 22 | }; 23 | 24 | isThrottled = (targetCount) => { 25 | this.absCount += 1; 26 | 27 | if (this.absCount >= (targetCount || 500)) { 28 | this.absCount = 0; 29 | this.setThrottle(); 30 | return false; 31 | } 32 | 33 | if (this.throttle) return true; 34 | 35 | this.setThrottle(); 36 | 37 | return false; 38 | }; 39 | 40 | log = (...args) => { 41 | console.log(...args); 42 | 43 | if (this.window) { 44 | this.window.webContents.send('ipc-logger-log', ...args); 45 | } 46 | }; 47 | 48 | data = (serializable, { maxThrottled } = { maxThrottled: 500 }) => { 49 | if (serializable.type === 'progress') { 50 | if (this.isThrottled(maxThrottled)) return; 51 | } 52 | if (this.window) { 53 | this.window.webContents.send( 54 | 'ipc-logger-log', 55 | JSON.stringify(serializable), 56 | 'data' 57 | ); 58 | } 59 | }; 60 | 61 | progressStart = ({ id, max }) => { 62 | this.data({ 63 | type: 'progressStart', 64 | data: { 65 | id, 66 | max, 67 | }, 68 | }); 69 | 70 | let count = 0; 71 | 72 | return { 73 | progress: (add = 1) => { 74 | count += add; 75 | this.data({ 76 | type: 'progress', 77 | data: { 78 | id, 79 | progress: count, 80 | }, 81 | }); 82 | }, 83 | end: (preventLog = false) => { 84 | this.data({ 85 | type: 'progressEnd', 86 | data: { 87 | id, 88 | }, 89 | }); 90 | if (preventLog || this.preventDoneLog) { 91 | return; 92 | } 93 | this.log(`${id} Done`); 94 | }, 95 | }; 96 | }; 97 | 98 | progressAbort = (id) => { 99 | this.data({ 100 | type: 'progressEnd', 101 | data: { 102 | id, 103 | }, 104 | }); 105 | this.log(`${id} Done`); 106 | }; 107 | 108 | devLog = (...args) => { 109 | if (process.env.IS_DEBUG === 'true') { 110 | console.log(...args); 111 | } 112 | }; 113 | 114 | connectWindow = (window: electron.BrowserWindow) => { 115 | this.window = window; 116 | }; 117 | } 118 | 119 | export default new Logger({}); 120 | -------------------------------------------------------------------------------- /src/main/wf/readOrderedMap.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { readFile } = require('fs/promises'); 3 | const { parse } = require('csv-parse/sync'); 4 | const zlib = require('zlib'); 5 | 6 | const asyncUnzip = (...args) => 7 | new Promise((resolve, reject) => 8 | zlib.unzip(...args, (err, res) => (err ? reject(err) : resolve(res))) 9 | ); 10 | 11 | const asyncDeflate = (data) => 12 | new Promise((resolve, reject) => 13 | zlib.deflate(data, (err, res) => (err ? reject(err) : resolve(res))) 14 | ); 15 | 16 | const parseCsv = (data, options = {}) => { 17 | const records = parse(data, options); 18 | 19 | return records.reduce((acc, cur) => [...acc, ...cur], []); 20 | }; 21 | 22 | const readOrderedMap = async (mapping) => { 23 | try { 24 | const rawUnzipped = await asyncUnzip(mapping); 25 | 26 | return parseCsv(rawUnzipped.toString('utf-8')); 27 | } catch (err) { 28 | // pass 29 | } 30 | 31 | try { 32 | const readHeaderSize = (buffer) => buffer.readInt32LE(0); 33 | 34 | const headerSize = readHeaderSize(mapping); 35 | 36 | const zlibCompressedHeader = mapping.slice(4, headerSize + 4); 37 | const uncompressedHeader = await asyncUnzip(zlibCompressedHeader); 38 | 39 | const readHeaderData = (headerDataBuffer) => { 40 | const entriesCount = headerDataBuffer.readInt32LE(0); 41 | const entryOffsetsBuffer = headerDataBuffer.slice( 42 | 4, 43 | entriesCount * 8 + 4 44 | ); 45 | 46 | const entryOffsets = new Array(entriesCount) 47 | .fill() 48 | .map((_, entryIndex) => { 49 | const keyEndOffset = entryOffsetsBuffer.readInt32LE(entryIndex * 8); 50 | const dataEndOffset = entryOffsetsBuffer.readInt32LE( 51 | entryIndex * 8 + 4 52 | ); 53 | 54 | return [keyEndOffset, dataEndOffset]; 55 | }); 56 | 57 | let currentKeyOffset = 0; 58 | const keysBuffer = headerDataBuffer.slice(entriesCount * 8 + 4); 59 | 60 | const keys = entryOffsets.map(([keyEndOffset]) => { 61 | const currentKey = keysBuffer.slice(currentKeyOffset, keyEndOffset); 62 | currentKeyOffset = keyEndOffset; 63 | 64 | return currentKey.toString('utf-8'); 65 | }); 66 | 67 | return { 68 | entryOffsets, 69 | keys, 70 | }; 71 | }; 72 | 73 | const { entryOffsets, keys } = readHeaderData(uncompressedHeader); 74 | 75 | const contentSection = mapping.slice(4 + headerSize); 76 | 77 | const readContentData = async (contentBuffer, offsets) => { 78 | let currentOffset = 0; 79 | 80 | const contents = offsets.map(([, dataOffset]) => { 81 | const content = contentBuffer.slice(currentOffset, dataOffset); 82 | currentOffset = dataOffset; 83 | 84 | return content; 85 | }); 86 | 87 | return Promise.all( 88 | contents.map(async (content) => { 89 | try { 90 | const unzipped = await asyncUnzip(content); 91 | 92 | return unzipped.toString('utf-8'); 93 | } catch (err) { 94 | return readOrderedMap(content); 95 | } 96 | }) 97 | ); 98 | }; 99 | 100 | const values = await readContentData(contentSection, entryOffsets); 101 | 102 | return keys.reduce( 103 | (acc, key, index) => ({ 104 | ...acc, 105 | [key]: 106 | typeof values[index] === 'string' 107 | ? parseCsv(values[index]) 108 | : values[index], 109 | }), 110 | {} 111 | ); 112 | } catch (err) { 113 | console.log('FAILED READING FILE DATA'); 114 | console.log(err); 115 | 116 | return {}; 117 | } 118 | }; 119 | 120 | const createOrderedMap = async (targetObject) => { 121 | const keys = Object.keys(targetObject).map((key) => Buffer.from(key)); 122 | 123 | const values = await Promise.all( 124 | Object.values(targetObject).map(async (value) => 125 | Array.isArray(value) 126 | ? asyncDeflate(value.join(',')) 127 | : createOrderedMap(value) 128 | ) 129 | ); 130 | 131 | let keyOffset = 0; 132 | let valueOffset = 0; 133 | 134 | const entryOffsets = keys 135 | .map((key, idx) => { 136 | const value = values[idx]; 137 | 138 | keyOffset += key.length; 139 | valueOffset += value.length; 140 | 141 | const entryBuffer = Buffer.alloc(8); 142 | 143 | entryBuffer.writeInt32LE(keyOffset, 0); 144 | entryBuffer.writeInt32LE(valueOffset, 4); 145 | 146 | return entryBuffer; 147 | }) 148 | .reduce((acc, buf) => Buffer.concat([acc, buf]), Buffer.alloc(0)); 149 | 150 | const entriesCount = Buffer.alloc(4); 151 | 152 | entriesCount.writeInt32LE(keys.length); 153 | 154 | const headerBuffer = Buffer.concat([entriesCount, entryOffsets, ...keys]); 155 | const headerData = await asyncDeflate(headerBuffer); 156 | 157 | const headerLength = Buffer.alloc(4); 158 | headerLength.writeInt32LE(headerData.length); 159 | 160 | const data = Buffer.concat([headerLength, headerData, ...values]); 161 | 162 | return data; 163 | }; 164 | 165 | const openAndReadOrderedMap = async (fileName) => { 166 | const openedFile = await readFile(fileName); 167 | return readOrderedMap(openedFile); 168 | }; 169 | 170 | module.exports = { 171 | openAndReadOrderedMap, 172 | readOrderedMap, 173 | }; 174 | -------------------------------------------------------------------------------- /src/main/wf/restoreMp3.js: -------------------------------------------------------------------------------- 1 | const { readFile, writeFile } = require('fs/promises'); 2 | const iconv = require('iconv-lite'); 3 | 4 | const hexesToBin = (hexString) => { 5 | return hexString 6 | .match(/.{2}/g) 7 | .map((hex) => parseInt(hex, 16).toString(2).padStart(8, '0')) 8 | .reduce((acc, cur) => acc + cur, ''); 9 | }; 10 | 11 | const LAYER = { 12 | '00': 0, 13 | '01': 3, 14 | 10: 2, 15 | 11: 1, 16 | }; 17 | 18 | const VERSION = { 19 | '00': 2.5, 20 | 10: 2, 21 | 11: 1, 22 | }; 23 | 24 | const BITRATE_INDEX = { 25 | 1000: { 26 | v1l1: '256', 27 | v1l2: '128', 28 | v1l3: '112', 29 | v2l1: '128', 30 | v2l2: '64', 31 | v2l3: '64', 32 | }, 33 | 1001: { 34 | v1l1: '288', 35 | v1l2: '160', 36 | v1l3: '128', 37 | v2l1: '144', 38 | v2l2: '80', 39 | v2l3: '80', 40 | }, 41 | 1010: { 42 | v1l1: '320', 43 | v1l2: '192', 44 | v1l3: '160', 45 | v2l1: '160', 46 | v2l2: '96', 47 | v2l3: '96', 48 | }, 49 | 1011: { 50 | v1l1: '352', 51 | v1l2: '224', 52 | v1l3: '192', 53 | v2l1: '176', 54 | v2l2: '112', 55 | v2l3: '112', 56 | }, 57 | 1100: { 58 | v1l1: '384', 59 | v1l2: '256', 60 | v1l3: '224', 61 | v2l1: '192', 62 | v2l2: '128', 63 | v2l3: '128', 64 | }, 65 | 1101: { 66 | v1l1: '416', 67 | v1l2: '320', 68 | v1l3: '256', 69 | v2l1: '224', 70 | v2l2: '144', 71 | v2l3: '144', 72 | }, 73 | 1110: { 74 | v1l1: '448', 75 | v1l2: '384', 76 | v1l3: '320', 77 | v2l1: '256', 78 | v2l2: '160', 79 | v2l3: '160', 80 | }, 81 | 1111: { 82 | v1l1: 'bad', 83 | v1l2: 'bad', 84 | v1l3: 'bad', 85 | v2l1: 'bad', 86 | v2l2: 'bad', 87 | v2l3: 'bad', 88 | }, 89 | '0000': { 90 | v1l1: 'free', 91 | v1l2: 'free', 92 | v1l3: 'free', 93 | v2l1: 'free', 94 | v2l2: 'free', 95 | v2l3: 'free', 96 | }, 97 | '0001': { 98 | v1l1: '32', 99 | v1l2: '32', 100 | v1l3: '32', 101 | v2l1: '32', 102 | v2l2: '8', 103 | v2l3: '8', 104 | }, 105 | '0010': { 106 | v1l1: '64', 107 | v1l2: '48', 108 | v1l3: '40', 109 | v2l1: '48', 110 | v2l2: '16', 111 | v2l3: '16', 112 | }, 113 | '0011': { 114 | v1l1: '96', 115 | v1l2: '56', 116 | v1l3: '48', 117 | v2l1: '56', 118 | v2l2: '24', 119 | v2l3: '24', 120 | }, 121 | '0100': { 122 | v1l1: '128', 123 | v1l2: '64', 124 | v1l3: '56', 125 | v2l1: '64', 126 | v2l2: '32', 127 | v2l3: '32', 128 | }, 129 | '0101': { 130 | v1l1: '160', 131 | v1l2: '80', 132 | v1l3: '64', 133 | v2l1: '80', 134 | v2l2: '40', 135 | v2l3: '40', 136 | }, 137 | '0110': { 138 | v1l1: '192', 139 | v1l2: '96', 140 | v1l3: '80', 141 | v2l1: '96', 142 | v2l2: '48', 143 | v2l3: '48', 144 | }, 145 | '0111': { 146 | v1l1: '224', 147 | v1l2: '112', 148 | v1l3: '96', 149 | v2l1: '112', 150 | v2l2: '56', 151 | v2l3: '56', 152 | }, 153 | }; 154 | 155 | const FREQUENCY = { 156 | 1: { 157 | '00': 44100, 158 | '01': 48000, 159 | 10: 32000, 160 | }, 161 | 2: { 162 | '00': 22050, 163 | '01': 24000, 164 | 10: 16000, 165 | }, 166 | 2.5: { 167 | '00': 11025, 168 | '01': 12000, 169 | 10: 8000, 170 | }, 171 | }; 172 | 173 | const calculateFrameSize = (binaryHeader) => { 174 | const mpegVersion = VERSION[binaryHeader.slice(11, 13)]; 175 | const layer = LAYER[binaryHeader.slice(13, 15)]; 176 | const bitrate = 177 | parseFloat( 178 | BITRATE_INDEX[binaryHeader.slice(16, 20)][ 179 | `v${mpegVersion === 1 ? 1 : 2}l${layer}` 180 | ] 181 | ) * 1000; 182 | const frequency = FREQUENCY[mpegVersion][binaryHeader.slice(20, 22)]; 183 | const padding = parseFloat(binaryHeader.slice(22, 23)); 184 | 185 | return Math.floor((bitrate * 144) / frequency + padding); 186 | }; 187 | 188 | const spliceBuffer = (buffer, targetIndex, deleteCount, ...items) => { 189 | const bufferArray = Array.from(buffer); 190 | 191 | bufferArray.splice(targetIndex, deleteCount, ...items); 192 | 193 | return Buffer.from(bufferArray); 194 | }; 195 | 196 | const restoreCorruptedMp3 = async (filePath, debug) => { 197 | let file = await readFile(filePath); 198 | 199 | const hexString = file.toString('hex'); 200 | if (hexString.slice(0, 6) === '494433') { 201 | // ID3V2 202 | const tit2Index = hexString.indexOf('54495432'); 203 | if (tit2Index !== -1 && tit2Index < 1024) { 204 | const sizeByteIndex = (tit2Index + 8) / 2; 205 | const encodingByteIndex = (tit2Index + 20) / 2; 206 | const tit2Size = parseInt( 207 | hexString.slice(tit2Index + 8, tit2Index + 16), 208 | 16 209 | ); 210 | const shiftJisTitle = file.slice( 211 | tit2Index / 2 + 11, 212 | tit2Index / 2 + 11 + tit2Size - 1 213 | ); 214 | const decodedTitle = iconv.decode(shiftJisTitle, 'SHIFT_JIS'); 215 | const utf8Title = iconv.encode(decodedTitle, 'utf-16'); 216 | file[encodingByteIndex] = 1; 217 | utf8Title.length 218 | .toString(16) 219 | .padStart(8, '0') 220 | .match(/.{2}/g) 221 | .map((hex) => parseInt(hex, 16)) 222 | .forEach((sizeByte, idx) => { 223 | file[sizeByteIndex + idx] = sizeByte; 224 | }); 225 | 226 | try { 227 | if (tit2Size > 1024) throw Error('TOO LARGE TIT2'); 228 | file = spliceBuffer(file, tit2Index / 2 + 11, tit2Size, ...utf8Title); 229 | } catch (err) { 230 | console.log(debug, tit2Index, tit2Size); 231 | } 232 | } 233 | } 234 | 235 | let byteIndex = file.toString('hex').indexOf('7ffb') / 2; 236 | 237 | while (byteIndex < file.byteLength) { 238 | const header = file.slice(byteIndex, byteIndex + 4).toString('hex'); 239 | const binaryHeader = hexesToBin(header); 240 | if (!/^7f/.test(header)) { 241 | break; 242 | } 243 | file[byteIndex] = 255; 244 | const frameSize = calculateFrameSize(binaryHeader); 245 | byteIndex += frameSize; 246 | } 247 | 248 | return file; 249 | }; 250 | 251 | module.exports = { 252 | restoreCorruptedMp3, 253 | }; 254 | -------------------------------------------------------------------------------- /src/main/wf/typedefs.ts: -------------------------------------------------------------------------------- 1 | export type LSResult = { 2 | permission: string; 3 | linkCount: string; 4 | owner: string; 5 | group: string; 6 | size: string; 7 | modifiedDate: string; 8 | name: string; 9 | path: string; 10 | }; 11 | 12 | export type WFExtractorMetaData = { 13 | lastExtractionDate: string; 14 | lastPackageVersion: string; 15 | lastSwfChecksum: string; 16 | lastSwfMode: 'full' | 'simple'; 17 | jpLatestApiAssetVersion: string; 18 | krLatestApiAssetVersion: string; 19 | enLatestApiAssetVersion: string; 20 | twLatestApiAssetVersion: string; 21 | cnLatestApiAssetVersion: string; 22 | spriteProcessedLock: string[]; 23 | specialSpriteProcessedLock: string[]; 24 | lockedHashMap: boolean; 25 | latestPullStamp: string; 26 | deltaAvailable: boolean; 27 | }; 28 | -------------------------------------------------------------------------------- /src/renderer/App.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @NOTE: Prepend a `~` to css file paths that are in your node_modules 3 | * See https://github.com/webpack-contrib/sass-loader#imports 4 | */ 5 | 6 | @font-face { 7 | font-family: 'NanumSquare'; 8 | font-weight: 400; 9 | src: url(../../assets/NanumSquareR.woff) format('woff'), 10 | } 11 | @font-face { 12 | font-family: 'NanumSquare'; 13 | font-weight: 600; 14 | src: url(../../assets/NanumSquareB.woff) format('woff'), 15 | } 16 | @font-face { 17 | font-family: 'NanumSquare'; 18 | font-weight: 800; 19 | src: url(../../assets/NanumSquareEB.woff) format('woff'), 20 | } 21 | @font-face { 22 | font-family: 'NanumSquare'; 23 | font-weight: 300; 24 | src: url(../../assets/NanumSquareL.woff) format('woff'), 25 | } 26 | 27 | * { 28 | box-sizing: border-box; 29 | font-family: NanumSquare, sans-serif; 30 | font-weight: 500; 31 | } 32 | 33 | body { 34 | position: relative; 35 | width: 100%; 36 | height: 100vh; 37 | padding: 0; 38 | margin: 0; 39 | } 40 | 41 | button { 42 | cursor: pointer; 43 | border: none; 44 | appearance: none; 45 | } 46 | 47 | li { 48 | list-style: none; 49 | } 50 | 51 | a { 52 | text-decoration: none; 53 | height: fit-content; 54 | width: fit-content; 55 | margin: 10px; 56 | } 57 | 58 | a:hover { 59 | opacity: 1; 60 | text-decoration: none; 61 | } 62 | 63 | .Hello { 64 | display: flex; 65 | justify-content: center; 66 | align-items: center; 67 | margin: 20px 0; 68 | } 69 | 70 | #root, #app-main { 71 | width: 100%; 72 | height: 100%; 73 | display: flex; 74 | flex-direction: column; 75 | align-items: center; 76 | justify-content: center; 77 | } 78 | -------------------------------------------------------------------------------- /src/renderer/components/Modal.tsx: -------------------------------------------------------------------------------- 1 | import { createPortal } from 'react-dom'; 2 | import styled from 'styled-components'; 3 | import WfCard from './WfCard'; 4 | 5 | const Backdrop = styled.div` 6 | position: absolute; 7 | width: 100%; 8 | height: 100%; 9 | top: 0; 10 | left: 0; 11 | z-index: 50; 12 | background: rgba(0, 0, 0, 0.15); 13 | `; 14 | 15 | const ModalLayout = styled.div` 16 | position: fixed; 17 | width: 100vw; 18 | height: 100vh; 19 | top: 0; 20 | left: 0; 21 | display: flex; 22 | z-index: 100; 23 | align-items: center; 24 | justify-content: center; 25 | `; 26 | 27 | const ModalContent = styled.div` 28 | position: relative; 29 | z-index: 100; 30 | `; 31 | 32 | const Modal = ({ 33 | open, 34 | children, 35 | onClose, 36 | ...rest 37 | }: { 38 | open: boolean; 39 | children: React.ReactChildren; 40 | onClose: () => void; 41 | }) => { 42 | if (!open) return null; 43 | 44 | return createPortal( 45 | <> 46 | 47 | 48 | 49 | {children} 50 | 51 | 52 | , 53 | document.getElementById('root') 54 | ); 55 | }; 56 | 57 | export default Modal; 58 | -------------------------------------------------------------------------------- /src/renderer/components/Switch.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const SwitchWrapper = styled.div` 5 | flex-shrink: 0; 6 | width: 64px; 7 | height: 32px; 8 | display: flex; 9 | flex-direction: row; 10 | justify-content: space-around; 11 | border-radius: 32px; 12 | transition: all 0.2s ease-out; 13 | position: relative; 14 | 15 | border: #747474 2px solid; 16 | background: #686868; 17 | 18 | &[data-value='true'] { 19 | border: #f4b34a 2px solid; 20 | background: #f2a241; 21 | } 22 | 23 | cursor: pointer; 24 | 25 | &[data-disabled='true'] { 26 | border: #747474 2px solid; 27 | background: #343434; 28 | 29 | > * { 30 | background: #686868 !important; 31 | } 32 | 33 | cursor: initial; 34 | } 35 | `; 36 | 37 | const SwitchButton = styled.div` 38 | height: 24px; 39 | width: 24px; 40 | position: absolute; 41 | z-index: 1000; 42 | background: white; 43 | border-radius: 38px; 44 | transition: all 0.2s ease-out; 45 | left: 2px; 46 | top: 2px; 47 | 48 | &[data-value='true'] { 49 | left: 34px; 50 | } 51 | `; 52 | 53 | const Switch = ({ 54 | value, 55 | onClick, 56 | ...rest 57 | }: { 58 | value: boolean; 59 | onClick: () => void; 60 | }) => { 61 | return ( 62 | 63 | 64 | 65 | ); 66 | }; 67 | 68 | export default Switch; 69 | -------------------------------------------------------------------------------- /src/renderer/components/TextField.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const TextFieldInput = styled.input` 5 | width: 100%; 6 | height: 24px; 7 | `; 8 | 9 | type TextFieldProps = { 10 | onChange: () => void; 11 | onEnter: () => void; 12 | onArrowUp: () => void; 13 | onArrowDown: () => void; 14 | value: string; 15 | }; 16 | 17 | const TextField = ({ 18 | onChange, 19 | onEnter, 20 | onArrowUp, 21 | onArrowDown, 22 | value, 23 | ...restinput 24 | }: TextFieldProps) => { 25 | return ( 26 | { 29 | if (event.keyCode === 13 && onEnter) { 30 | onEnter(); 31 | } 32 | if (event.keyCode === 38 && onArrowUp) { 33 | onArrowUp(); 34 | } 35 | if (event.keyCode === 40 && onArrowDown) { 36 | onArrowDown(); 37 | } 38 | }} 39 | onChange={onChange} 40 | value={value} 41 | /> 42 | ); 43 | }; 44 | 45 | export default TextField; 46 | -------------------------------------------------------------------------------- /src/renderer/components/Typography.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const IndicatorTypo = styled.p` 4 | display: inline-block; 5 | margin: 0; 6 | opacity: 0.7; 7 | font-size: 0.825rem; 8 | `; 9 | 10 | export default styled.p` 11 | display: inline-block; 12 | text-overflow: ellipsis; 13 | overflow: hidden; 14 | white-space: nowrap; 15 | margin: 0; 16 | `; 17 | -------------------------------------------------------------------------------- /src/renderer/components/WfButton.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | const WfButton = styled.button` 4 | padding: 8px; 5 | width: 100%; 6 | height: 64px; 7 | display: flex; 8 | align-items: center; 9 | justify-content: flex-start; 10 | font-size: 1.3rem; 11 | background: white; 12 | box-shadow: 0px 3px 13px -3px rgb(0 0 0 / 30%); 13 | border-radius: 16px; 14 | padding-left: 16px; 15 | 16 | > img, 17 | > svg { 18 | margin-right: 24px; 19 | } 20 | 21 | cursor: pointer; 22 | 23 | &:hover { 24 | background: #fafafa; 25 | transform: scale(1.01); 26 | } 27 | &:active { 28 | background: #efefef; 29 | } 30 | 31 | &:disabled { 32 | cursor: initial; 33 | background: #efefef; 34 | &:hover { 35 | background: #efefef; 36 | transform: scale(1); 37 | } 38 | &:active { 39 | background: #efefef; 40 | } 41 | } 42 | `; 43 | 44 | export const WfDangerButton = styled(WfButton)` 45 | background: #ea3450; 46 | color: white; 47 | 48 | &:hover { 49 | background: #d81634; 50 | } 51 | &:active { 52 | background: #be001d; 53 | } 54 | 55 | &:disabled { 56 | &:hover { 57 | background: #ea3450; 58 | } 59 | &:active { 60 | background: #ea3450; 61 | } 62 | } 63 | `; 64 | 65 | export const WfSelectButton = styled(WfButton)` 66 | &[data-selected='true'] { 67 | background: #f2a241; 68 | color: white; 69 | 70 | &:hover { 71 | background: #f2a241; 72 | } 73 | &:active { 74 | background: #f2a241; 75 | } 76 | } 77 | `; 78 | 79 | export default WfButton; 80 | -------------------------------------------------------------------------------- /src/renderer/components/WfCard.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export default styled.div` 4 | padding: 24px; 5 | background: white; 6 | box-shadow: 0px 3px 13px -3px rgb(0 0 0 / 30%); 7 | border-radius: 16px; 8 | background-color: #fafafa; 9 | display: flex; 10 | flex-direction: column; 11 | `; 12 | -------------------------------------------------------------------------------- /src/renderer/helpers/hooks.tsx: -------------------------------------------------------------------------------- 1 | import { useRef, useState } from 'react'; 2 | 3 | export const usePermanentState = ( 4 | defaultState: T, 5 | permanentKey: string, 6 | getter: (string) => any = (val) => val, 7 | setter: (string) => any = (val) => val 8 | ): [T, React.Dispatch>] => { 9 | const [permanentValue, setPermanentValueOrigin] = useState( 10 | getter(localStorage.getItem(permanentKey)) || defaultState 11 | ); 12 | 13 | const setPermanentValue = (newValue) => { 14 | setPermanentValueOrigin(newValue); 15 | 16 | if (newValue) { 17 | localStorage.setItem(permanentKey, setter(newValue)); 18 | } else { 19 | localStorage.removeItem(permanentKey); 20 | } 21 | }; 22 | 23 | return [permanentValue, setPermanentValue]; 24 | }; 25 | 26 | export const useStateRef = (initialValue) => { 27 | const [state, stateSetterOrigin] = useState(initialValue); 28 | 29 | const stateRef = useRef(state); 30 | 31 | const stateSetter = (nextState) => { 32 | if (typeof nextState === 'function') { 33 | let res = nextState(state); 34 | 35 | stateRef.current = res; 36 | 37 | if (typeof res === 'function') { 38 | res = () => res; 39 | } 40 | return stateSetterOrigin(res); 41 | } 42 | stateRef.current = nextState; 43 | 44 | return stateSetterOrigin(nextState); 45 | }; 46 | 47 | return [state, stateSetter, stateRef]; 48 | }; 49 | 50 | export const asd = 1; 51 | -------------------------------------------------------------------------------- /src/renderer/helpers/index.tsx: -------------------------------------------------------------------------------- 1 | export const getIpcReturn = (channel) => { 2 | return new Promise((resolve) => { 3 | window.electron.ipcRenderer.once(channel, resolve); 4 | }); 5 | }; 6 | 7 | export const asd = 1; 8 | -------------------------------------------------------------------------------- /src/renderer/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | World Flipper Extractor 6 | 7 | 8 |
9 | 10 | 12 | 13 | -------------------------------------------------------------------------------- /src/renderer/index.tsx: -------------------------------------------------------------------------------- 1 | import { render } from 'react-dom'; 2 | import App from './App'; 3 | 4 | render(, document.getElementById('root')); 5 | -------------------------------------------------------------------------------- /src/renderer/worker.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | World Flipper Extractor 6 | 7 | 8 |
9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2021", 4 | "module": "commonjs", 5 | "lib": ["dom", "esnext"], 6 | "declaration": true, 7 | "declarationMap": true, 8 | "jsx": "react-jsx", 9 | "strict": true, 10 | "pretty": true, 11 | "sourceMap": true, 12 | "baseUrl": "./src", 13 | "noUnusedLocals": true, 14 | "noUnusedParameters": true, 15 | "noImplicitReturns": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "moduleResolution": "node", 18 | "esModuleInterop": true, 19 | "allowSyntheticDefaultImports": true, 20 | "resolveJsonModule": true, 21 | "allowJs": true, 22 | "outDir": "release/app/dist" 23 | }, 24 | "exclude": ["test", "release/build", "release/app/dist", ".erb/dll"] 25 | } 26 | --------------------------------------------------------------------------------