Browse Source

Remove some old code, apply fix from master.

Reference to the old code will be made from the master branch.
Daniel Scalzi 5 năm trước cách đây
mục cha
commit
dc7386f19d

+ 9 - 9
package-lock.json

@@ -5290,9 +5290,9 @@
       "dev": true
     },
     "eslint": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.0.0.tgz",
-      "integrity": "sha512-qY1cwdOxMONHJfGqw52UOpZDeqXy8xmD0u8CT6jIstil72jkhURC704W8CFyTPDPllz4z4lu0Ql1+07PG/XdIg==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.1.0.tgz",
+      "integrity": "sha512-DfS3b8iHMK5z/YLSme8K5cge168I8j8o1uiVmFCgnnjxZQbCGyraF8bMl7Ju4yfBmCuxD7shOF7eqGkcuIHfsA==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
@@ -6990,9 +6990,9 @@
       }
     },
     "glob-parent": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz",
-      "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
       "dev": true,
       "requires": {
         "is-glob": "^4.0.1"
@@ -8862,9 +8862,9 @@
       "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
     },
     "mocha": {
-      "version": "7.1.2",
-      "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.2.tgz",
-      "integrity": "sha512-o96kdRKMKI3E8U0bjnfqW4QMk12MwZ4mhdBTf+B5a1q9+aq2HRnj+3ZdJu0B/ZhJeK78MgYuv6L8d/rA5AeBJA==",
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz",
+      "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==",
       "dev": true,
       "requires": {
         "ansi-colors": "3.2.3",

+ 2 - 2
package.json

@@ -68,9 +68,9 @@
     "electron-builder": "^22.6.1",
     "electron-webpack": "^2.8.2",
     "electron-webpack-ts": "^4.0.1",
-    "eslint": "^7.0.0",
+    "eslint": "^7.1.0",
     "helios-distribution-types": "1.0.0-pre.1",
-    "mocha": "^7.1.2",
+    "mocha": "^7.2.0",
     "nock": "^12.0.3",
     "react": "^16.13.0",
     "react-dom": "^16.13.0",

+ 1 - 1
src/common/util/MojangUtils.ts

@@ -1,4 +1,4 @@
-import { Rule, Natives } from "../../main/asset/model/mojang/VersionJson"
+import { Rule, Natives } from "../asset/model/mojang/VersionJson"
 
 export function getMojangOS(): string {
     const opSys = process.platform

+ 11 - 8
src/main/index.ts

@@ -230,16 +230,19 @@ function createMenu() {
 }
 
 function getPlatformIcon(filename: string){
-    const opSys = process.platform
-    if (opSys === 'darwin') {
-        filename = filename + '.icns'
-    } else if (opSys === 'win32') {
-        filename = filename + '.ico'
-    } else {
-        filename = filename + '.png'
+    let ext
+    switch(process.platform) {
+        case 'win32':
+            ext = 'ico'
+            break
+        case 'darwin':
+        case 'linux':
+        default:
+            ext = 'png'
+            break
     }
 
-    return join(__dirname, '..', 'assets', 'images', filename)
+    return join(__dirname, '..', 'assets', 'images', `${filename}.${ext}`)
 }
 
 app.on('ready', createWindow)

+ 0 - 69
src/main/old/assetexec.ts

@@ -1,69 +0,0 @@
-let target = require('./assetguard')[process.argv[2]]
-
-if(target == null){
-    process.send!({context: 'error', data: null, error: 'Invalid class name'})
-    console.error('Invalid class name passed to argv[2], cannot continue.')
-    process.exit(1)
-}
-let tracker = new target(...(process.argv.splice(3)))
-
-process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
-
-//const tracker = new AssetGuard(process.argv[2], process.argv[3])
-console.log('AssetExec Started')
-
-// Temporary for debug purposes.
-process.on('unhandledRejection', r => console.log(r))
-
-function assignListeners(){
-    tracker.on('validate', (data: any) => {
-        process.send!({context: 'validate', data})
-    })
-    tracker.on('progress', (data: any, acc: number, total: number) => {
-        process.send!({context: 'progress', data, value: acc, total, percent: parseInt(((acc/total)*100) as unknown as string)})
-    })
-    tracker.on('complete', (data: any, ...args: any[]) => {
-        process.send!({context: 'complete', data, args})
-    })
-    tracker.on('error', (data: any, error: any) => {
-        process.send!({context: 'error', data, error})
-    })
-}
-
-assignListeners()
-
-process.on('message', (msg) => {
-    if(msg.task === 'execute'){
-        const func = msg.function
-        let nS = tracker[func] // Nonstatic context
-        let iS = target[func] // Static context
-        if(typeof nS === 'function' || typeof iS === 'function'){
-            const f = typeof nS === 'function' ? nS : iS
-            const res = f.apply(f === nS ? tracker : null, msg.argsArr)
-            if(res instanceof Promise){
-                res.then((v) => {
-                    process.send!({result: v, context: func})
-                }).catch((err) => {
-                    process.send!({result: err.message || err, context: func})
-                })
-            } else {
-                process.send!({result: res, context: func})
-            }
-        } else {
-            process.send!({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`})
-        }
-    } else if(msg.task === 'changeContext'){
-        target = require('./assetguard')[msg.class]
-        if(target == null){
-            process.send!({context: 'error', data: null, error: `Invalid class ${msg.class}`})
-        } else {
-            tracker = new target(...(msg.args))
-            assignListeners()
-        }
-    }
-})
-
-process.on('disconnect', () => {
-    console.log('AssetExec Disconnected')
-    process.exit(0)
-})

+ 0 - 1916
src/main/old/assetguard.ts

@@ -1,1916 +0,0 @@
-import { EventEmitter } from 'events'
-import request from 'request'
-import { join } from 'path'
-import { pathExistsSync, pathExists, readdir, exists, readFileSync, createWriteStream, ensureDirSync, readFile, writeFileSync, unlink, createReadStream, readJsonSync } from 'fs-extra'
-import Registry from 'winreg'
-import { exec, spawn } from 'child_process'
-import { LauncherJson } from 'common/asset/model/mojang/LauncherJson'
-import { createHash } from 'crypto'
-import AdmZip from 'adm-zip'
-import { forEachOfLimit, eachLimit } from 'async'
-import { extract } from 'tar-fs'
-import { createGunzip } from 'zlib'
-import { VersionJson, AssetIndex, Rule, Natives, Library } from 'common/asset/model/mojang/VersionJson'
-
-import { ConfigManager } from 'common/config/configmanager'
-import isDev from 'common/util/isdev'
-const DistroManager = require('./distromanager')
-
-// Constants
-// const PLATFORM_MAP = {
-//     win32: '-windows-x64.tar.gz',
-//     darwin: '-macosx-x64.tar.gz',
-//     linux: '-linux-x64.tar.gz'
-// }
-
-// Classes
-
-/** Class representing a base asset. */
-export class Asset {
-    /**
-     * Create an asset.
-     * 
-     * @param {any} id The id of the asset.
-     * @param {string} hash The hash value of the asset.
-     * @param {number} size The size in bytes of the asset.
-     * @param {string} from The url where the asset can be found.
-     * @param {string} to The absolute local file path of the asset.
-     */
-    constructor(
-        public id: any,
-        public hash: string,
-        public size: number,
-        public from: string,
-        public to: string
-    ) {}
-}
-
-/** Class representing a mojang library. */
-export class LibraryInternal extends Asset {
-
-    /**
-     * Converts the process.platform OS names to match mojang's OS names.
-     */
-    public static mojangFriendlyOS(){
-        const opSys = process.platform
-        if (opSys === 'darwin') {
-            return 'osx'
-        } else if (opSys === 'win32'){
-            return 'windows'
-        } else if (opSys === 'linux'){
-            return 'linux'
-        } else {
-            return null
-        }
-    }
-
-    // TODO types
-    /**
-     * Checks whether or not a library is valid for download on a particular OS, following
-     * the rule format specified in the mojang version data index. If the allow property has
-     * an OS specified, then the library can ONLY be downloaded on that OS. If the disallow
-     * property has instead specified an OS, the library can be downloaded on any OS EXCLUDING
-     * the one specified.
-     * 
-     * If the rules are undefined, the natives property will be checked for a matching entry
-     * for the current OS.
-     * 
-     * @param {Array.<Object>} rules The Library's download rules.
-     * @param {Object} natives The Library's natives object.
-     * @returns {boolean} True if the Library follows the specified rules, otherwise false.
-     */
-    public static validateRules(rules: Rule[] | null | undefined, natives: Natives | null | undefined){
-        if(rules == null) {
-            if(natives == null) {
-                return true
-            } else {
-                return natives[LibraryInternal.mojangFriendlyOS()!] != null
-            }
-        }
-
-        for(let rule of rules){
-            const action = rule.action
-            const osProp = rule.os
-            if(action != null && osProp != null){
-                const osName = osProp.name
-                const osMoj = LibraryInternal.mojangFriendlyOS()
-                if(action === 'allow'){
-                    return osName === osMoj
-                } else if(action === 'disallow'){
-                    return osName !== osMoj
-                }
-            }
-        }
-        return true
-    }
-}
-
-class DistroModule extends Asset {
-
-    /**
-     * Create a DistroModule. This is for processing,
-     * not equivalent to the module objects in the
-     * distro index.
-     * 
-     * @param {any} id The id of the asset.
-     * @param {string} hash The hash value of the asset.
-     * @param {number} size The size in bytes of the asset.
-     * @param {string} from The url where the asset can be found.
-     * @param {string} to The absolute local file path of the asset.
-     * @param {string} type The the module type.
-     */
-    constructor(
-        id: any,
-        hash: string,
-        size: number,
-        from: string,
-        to: string,
-        public type: string
-    ) {
-        super(id, hash, size, from, to)
-        this.type = type
-    }
-
-}
-
-/**
- * Class representing a download tracker. This is used to store meta data
- * about a download queue, including the queue itself.
- */
-class DLTracker {
-
-    /**
-     * Create a DLTracker
-     * 
-     * @param {Array.<Asset>} dlqueue An array containing assets queued for download.
-     * @param {number} dlsize The combined size of each asset in the download queue array.
-     * @param {function(Asset)} callback Optional callback which is called when an asset finishes downloading.
-     */
-    constructor(
-        public dlqueue: Asset[],
-        public dlsize: number,
-        public callback?: (asset: Asset, ...args: any[]) => void
-    ) {}
-
-}
-
-export class Util {
-
-    /**
-     * Returns true if the actual version is greater than
-     * or equal to the desired version.
-     * 
-     * @param {string} desired The desired version.
-     * @param {string} actual The actual version.
-     */
-    public static mcVersionAtLeast(desired: string, actual: string){
-        const des = desired.split('.')
-        const act = actual.split('.')
-
-        for(let i=0; i<des.length; i++){
-            if(!(parseInt(act[i]) >= parseInt(des[i]))){
-                return false
-            }
-        }
-        return true
-    }
-
-}
-
-interface OpenJDKData {
-    uri: string
-    size: number
-    name: string
-}
-
-interface JDK8Version {
-    major: number
-    update: number
-    build: number
-}
-
-interface JDK9Version {
-    major: number
-    minor: number
-    revision: number
-    build: number
-}
-
-interface JVMMeta {
-    arch?: number
-    version?: JDK8Version | JDK9Version
-    execPath?: string
-    valid: boolean // Above properties are present if valid.
-}
-
-export class JavaGuard extends EventEmitter {
-
-    constructor(
-        public mcVersion: string
-    ) {
-        super()
-    }
-
-    // /**
-    //  * @typedef OracleJREData
-    //  * @property {string} uri The base uri of the JRE.
-    //  * @property {{major: string, update: string, build: string}} version Object containing version information.
-    //  */
-
-    // /**
-    //  * Resolves the latest version of Oracle's JRE and parses its download link.
-    //  * 
-    //  * @returns {Promise.<OracleJREData>} Promise which resolved to an object containing the JRE download data.
-    //  */
-    // static _latestJREOracle(){
-
-    //     const url = 'https://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html'
-    //     const regex = /https:\/\/.+?(?=\/java)\/java\/jdk\/([0-9]+u[0-9]+)-(b[0-9]+)\/([a-f0-9]{32})?\/jre-\1/
-    
-    //     return new Promise((resolve, reject) => {
-    //         request(url, (err, resp, body) => {
-    //             if(!err){
-    //                 const arr = body.match(regex)
-    //                 const verSplit = arr[1].split('u')
-    //                 resolve({
-    //                     uri: arr[0],
-    //                     version: {
-    //                         major: verSplit[0],
-    //                         update: verSplit[1],
-    //                         build: arr[2]
-    //                     }
-    //                 })
-    //             } else {
-    //                 resolve(null)
-    //             }
-    //         })
-    //     })
-    // }
-
-    /**
-     * Fetch the last open JDK binary. Uses https://api.adoptopenjdk.net/
-     * 
-     * @param {string} major The major version of Java to fetch.
-     * 
-     * @returns {Promise.<OpenJDKData>} Promise which resolved to an object containing the JRE download data.
-     */
-    // TODO reject not null use try catch in caller
-    public static latestOpenJDK(major = '8'): Promise<OpenJDKData | null> {
-
-        const sanitizedOS = process.platform === 'win32' ? 'windows' : (process.platform === 'darwin' ? 'mac' : process.platform)
-
-        const url = `https://api.adoptopenjdk.net/v2/latestAssets/nightly/openjdk${major}?os=${sanitizedOS}&arch=x64&heap_size=normal&openjdk_impl=hotspot&type=jre`
-        
-        return new Promise((resolve, reject) => {
-            request({url, json: true}, (err, resp, body) => {
-                if(!err && body.length > 0){
-                    resolve({
-                        uri: body[0].binary_link,
-                        size: body[0].binary_size,
-                        name: body[0].binary_name
-                    })
-                } else {
-                    resolve(null)
-                }
-            })
-        })
-    }
-
-    /**
-     * Returns the path of the OS-specific executable for the given Java
-     * installation. Supported OS's are win32, darwin, linux.
-     * 
-     * @param {string} rootDir The root directory of the Java installation.
-     * @returns {string} The path to the Java executable.
-     */
-    public static javaExecFromRoot(rootDir: string){
-        if(process.platform === 'win32'){
-            return join(rootDir, 'bin', 'javaw.exe')
-        } else if(process.platform === 'darwin'){
-            return join(rootDir, 'Contents', 'Home', 'bin', 'java')
-        } else if(process.platform === 'linux'){
-            return join(rootDir, 'bin', 'java')
-        }
-        return rootDir
-    }
-
-    /**
-     * Check to see if the given path points to a Java executable.
-     * 
-     * @param {string} pth The path to check against.
-     * @returns {boolean} True if the path points to a Java executable, otherwise false.
-     */
-    public static isJavaExecPath(pth: string){
-        if(process.platform === 'win32'){
-            return pth.endsWith(join('bin', 'javaw.exe'))
-        } else if(process.platform === 'darwin'){
-            return pth.endsWith(join('bin', 'java'))
-        } else if(process.platform === 'linux'){
-            return pth.endsWith(join('bin', 'java'))
-        }
-        return false
-    }
-
-    /**
-     * Load Mojang's launcher.json file.
-     * 
-     * @returns {Promise.<Object>} Promise which resolves to Mojang's launcher.json object.
-     */
-    // TODO reject and have caller try catch
-    public static loadMojangLauncherData(): Promise<LauncherJson | null> {
-        return new Promise((resolve, reject) => {
-            request.get('https://launchermeta.mojang.com/mc/launcher.json', (err, resp, body) => {
-                if(err){
-                    resolve(null)
-                } else {
-                    resolve(JSON.parse(body))
-                }
-            })
-        })
-    }
-
-    /**
-     * Parses a **full** Java Runtime version string and resolves
-     * the version information. Dynamically detects the formatting
-     * to use.
-     * 
-     * @param {string} verString Full version string to parse.
-     * @returns Object containing the version information.
-     */
-    public static parseJavaRuntimeVersion(verString: string){
-        const major = Number(verString.split('.')[0])
-        if(major === 1){
-            return JavaGuard._parseJavaRuntimeVersion_8(verString)
-        } else {
-            return JavaGuard._parseJavaRuntimeVersion_9(verString)
-        }
-    }
-
-    /**
-     * Parses a **full** Java Runtime version string and resolves
-     * the version information. Uses Java 8 formatting.
-     * 
-     * @param {string} verString Full version string to parse.
-     * @returns Object containing the version information.
-     */
-    public static _parseJavaRuntimeVersion_8(verString: string): JDK8Version {
-        // 1.{major}.0_{update}-b{build}
-        // ex. 1.8.0_152-b16
-        const ptsOne = verString.split('-')
-        const ptsTwo = ptsOne[0].split('_')
-        return {
-            major: parseInt(ptsTwo[0].split('.')[1]),
-            update: parseInt(ptsTwo[1]),
-            build: parseInt(ptsOne[1].substring(1))
-        }
-    }
-
-    /**
-     * Parses a **full** Java Runtime version string and resolves
-     * the version information. Uses Java 9+ formatting.
-     * 
-     * @param {string} verString Full version string to parse.
-     * @returns Object containing the version information.
-     */
-    public static _parseJavaRuntimeVersion_9(verString: string): JDK9Version {
-        // {major}.{minor}.{revision}+{build}
-        // ex. 10.0.2+13
-        const ptsOne = verString.split('+')
-        const ptsTwo = ptsOne[0].split('.')
-        return {
-            major: parseInt(ptsTwo[0]),
-            minor: parseInt(ptsTwo[1]),
-            revision: parseInt(ptsTwo[2]),
-            build: parseInt(ptsOne[1])
-        }
-    }
-
-    /**
-     * Validates the output of a JVM's properties. Currently validates that a JRE is x64
-     * and that the major = 8, update > 52.
-     * 
-     * @param {string} stderr The output to validate.
-     * 
-     * @returns {JVMMeta} A meta object about the JVM.
-     * The validity is stored inside the `valid` property.
-     */
-    private _validateJVMProperties(stderr: string) {
-        const res = stderr
-        const props = res.split('\n')
-
-        const goal = 2
-        let checksum = 0
-
-        const meta: any = {}
-
-        for(let i=0; i<props.length; i++){
-            if(props[i].indexOf('sun.arch.data.model') > -1){
-                const arch = parseInt(props[i].split('=')[1].trim())
-                console.log(props[i].trim())
-                if(arch === 64){
-                    meta.arch = arch
-                    ++checksum
-                    if(checksum === goal){
-                        break
-                    }
-                }
-            } else if(props[i].indexOf('java.runtime.version') > -1){
-                let verString = props[i].split('=')[1].trim()
-                console.log(props[i].trim())
-                const verOb = JavaGuard.parseJavaRuntimeVersion(verString)
-                if(verOb.major < 9){
-                    // Java 8
-                    if(verOb.major === 8 && (verOb as JDK8Version).update > 52){
-                        meta.version = verOb
-                        ++checksum
-                        if(checksum === goal){
-                            break
-                        }
-                    }
-                } else {
-                    // Java 9+
-                    if(Util.mcVersionAtLeast('1.13', this.mcVersion)){
-                        console.log('Java 9+ not yet tested.')
-                        /* meta.version = verOb
-                        ++checksum
-                        if(checksum === goal){
-                            break
-                        } */
-                    }
-                }
-            }
-        }
-
-        meta.valid = checksum === goal
-        
-        return meta as JVMMeta
-    }
-
-    /**
-     * Validates that a Java binary is at least 64 bit. This makes use of the non-standard
-     * command line option -XshowSettings:properties. The output of this contains a property,
-     * sun.arch.data.model = ARCH, in which ARCH is either 32 or 64. This option is supported
-     * in Java 8 and 9. Since this is a non-standard option. This will resolve to true if
-     * the function's code throws errors. That would indicate that the option is changed or
-     * removed.
-     * 
-     * @param {string} binaryExecPath Path to the java executable we wish to validate.
-     * 
-     * @returns {Promise.<JVMMeta>} A promise which resolves to a meta object about the JVM.
-     * The validity is stored inside the `valid` property.
-     */
-    private _validateJavaBinary(binaryExecPath: string): Promise<JVMMeta> {
-
-        return new Promise((resolve, reject) => {
-            if(!JavaGuard.isJavaExecPath(binaryExecPath)){
-                resolve({valid: false})
-            } else if(pathExistsSync(binaryExecPath)){
-                // Workaround (javaw.exe no longer outputs this information.)
-                console.log(typeof binaryExecPath)
-                if(binaryExecPath.indexOf('javaw.exe') > -1) {
-                    binaryExecPath.replace('javaw.exe', 'java.exe')
-                }
-                exec('"' + binaryExecPath + '" -XshowSettings:properties', (err, stdout, stderr) => {
-                    try {
-                        // Output is stored in stderr?
-                        resolve(this._validateJVMProperties(stderr))
-                    } catch (err){
-                        // Output format might have changed, validation cannot be completed.
-                        resolve({valid: false})
-                    }
-                })
-            } else {
-                resolve({valid: false})
-            }
-        })
-        
-    }
-
-    /**
-     * Checks for the presence of the environment variable JAVA_HOME. If it exits, we will check
-     * to see if the value points to a path which exists. If the path exits, the path is returned.
-     * 
-     * @returns {string} The path defined by JAVA_HOME, if it exists. Otherwise null.
-     */
-    private static _scanJavaHome(){
-        const jHome = process.env.JAVA_HOME as string
-        try {
-            let res = pathExistsSync(jHome)
-            return res ? jHome : null
-        } catch (err) {
-            // Malformed JAVA_HOME property.
-            return null
-        }
-    }
-
-    /**
-     * Scans the registry for 64-bit Java entries. The paths of each entry are added to
-     * a set and returned. Currently, only Java 8 (1.8) is supported.
-     * 
-     * @returns {Promise.<Set.<string>>} A promise which resolves to a set of 64-bit Java root
-     * paths found in the registry.
-     */
-    private static _scanRegistry(): Promise<Set<string>> {
-
-        return new Promise((resolve, reject) => {
-            // Keys for Java v9.0.0 and later:
-            // 'SOFTWARE\\JavaSoft\\JRE'
-            // 'SOFTWARE\\JavaSoft\\JDK'
-            // Forge does not yet support Java 9, therefore we do not.
-
-            // Keys for Java 1.8 and prior:
-            const regKeys = [
-                '\\SOFTWARE\\JavaSoft\\Java Runtime Environment',
-                '\\SOFTWARE\\JavaSoft\\Java Development Kit'
-            ]
-
-            let keysDone = 0
-
-            const candidates = new Set<string>()
-
-            for(let i=0; i<regKeys.length; i++){
-                const key = new Registry({
-                    hive: Registry.HKLM,
-                    key: regKeys[i],
-                    arch: 'x64'
-                })
-                key.keyExists((err, exists) => {
-                    if(exists) {
-                        key.keys((err, javaVers) => {
-                            if(err){
-                                keysDone++
-                                console.error(err)
-
-                                // REG KEY DONE
-                                // DUE TO ERROR
-                                if(keysDone === regKeys.length){
-                                    resolve(candidates)
-                                }
-                            } else {
-                                if(javaVers.length === 0){
-                                    // REG KEY DONE
-                                    // NO SUBKEYS
-                                    keysDone++
-                                    if(keysDone === regKeys.length){
-                                        resolve(candidates)
-                                    }
-                                } else {
-
-                                    let numDone = 0
-
-                                    for(let j=0; j<javaVers.length; j++){
-                                        const javaVer = javaVers[j]
-                                        const vKey = javaVer.key.substring(javaVer.key.lastIndexOf('\\')+1)
-                                        // Only Java 8 is supported currently.
-                                        if(parseFloat(vKey) === 1.8){
-                                            javaVer.get('JavaHome', (err, res) => {
-                                                const jHome = res.value
-                                                if(jHome.indexOf('(x86)') === -1){
-                                                    candidates.add(jHome)
-                                                }
-
-                                                // SUBKEY DONE
-
-                                                numDone++
-                                                if(numDone === javaVers.length){
-                                                    keysDone++
-                                                    if(keysDone === regKeys.length){
-                                                        resolve(candidates)
-                                                    }
-                                                }
-                                            })
-                                        } else {
-
-                                            // SUBKEY DONE
-                                            // NOT JAVA 8
-
-                                            numDone++
-                                            if(numDone === javaVers.length){
-                                                keysDone++
-                                                if(keysDone === regKeys.length){
-                                                    resolve(candidates)
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        })
-                    } else {
-
-                        // REG KEY DONE
-                        // DUE TO NON-EXISTANCE
-
-                        keysDone++
-                        if(keysDone === regKeys.length){
-                            resolve(candidates)
-                        }
-                    }
-                })
-            }
-
-        })
-        
-    }
-
-    /**
-     * See if JRE exists in the Internet Plug-Ins folder.
-     * 
-     * @returns {string} The path of the JRE if found, otherwise null.
-     */
-    private static _scanInternetPlugins(){
-        // /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java
-        const pth = '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin'
-        const res = pathExistsSync(JavaGuard.javaExecFromRoot(pth))
-        return res ? pth : null
-    }
-
-    /**
-     * Scan a directory for root JVM folders.
-     * 
-     * @param {string} scanDir The directory to scan.
-     * @returns {Promise.<Set.<string>>} A promise which resolves to a set of the discovered
-     * root JVM folders.
-     */
-    private static _scanFileSystem(scanDir: string): Promise<Set<string>> {
-        return new Promise((resolve, reject) => {
-
-            pathExists(scanDir, (e) => {
-
-                let res = new Set<string>()
-                
-                if(e){
-                    readdir(scanDir, (err, files) => {
-                        if(err){
-                            resolve(res)
-                            console.log(err)
-                        } else {
-                            let pathsDone = 0
-
-                            for(let i=0; i<files.length; i++){
-
-                                const combinedPath = join(scanDir, files[i])
-                                const execPath = JavaGuard.javaExecFromRoot(combinedPath)
-
-                                exists(execPath, (v) => {
-
-                                    if(v){
-                                        res.add(combinedPath)
-                                    }
-
-                                    ++pathsDone
-
-                                    if(pathsDone === files.length){
-                                        resolve(res)
-                                    }
-
-                                })
-                            }
-                            if(pathsDone === files.length){
-                                resolve(res)
-                            }
-                        }
-                    })
-                } else {
-                    resolve(res)
-                }
-            })
-
-        })
-    }
-
-    /**
-     * 
-     * @param {Set.<string>} rootSet A set of JVM root strings to validate.
-     * @returns {Promise.<Object[]>} A promise which resolves to an array of meta objects
-     * for each valid JVM root directory.
-     */
-    private async _validateJavaRootSet(rootSet: Set<string>): Promise<JVMMeta[]>{
-
-        const rootArr = Array.from(rootSet)
-        const validArr: JVMMeta[] = []
-
-        for(let i=0; i<rootArr.length; i++){
-
-            const execPath = JavaGuard.javaExecFromRoot(rootArr[i])
-            const metaOb = await this._validateJavaBinary(execPath)
-
-            if(metaOb.valid){
-                metaOb.execPath = execPath
-                validArr.push(metaOb)
-            }
-
-        }
-
-        return validArr
-
-    }
-
-    /**
-     * Sort an array of JVM meta objects. Best candidates are placed before all others.
-     * Sorts based on version and gives priority to JREs over JDKs if versions match.
-     * 
-     * @param {Object[]} validArr An array of JVM meta objects.
-     * @returns {Object[]} A sorted array of JVM meta objects.
-     */
-    private static _sortValidJavaArray(validArr: any[]){
-        const retArr = validArr.sort((a, b) => {
-
-            if(a.version.major === b.version.major){
-                
-                if(a.version.major < 9){
-                    // Java 8
-                    if(a.version.update === b.version.update){
-                        if(a.version.build === b.version.build){
-    
-                            // Same version, give priority to JRE.
-                            if(a.execPath.toLowerCase().indexOf('jdk') > -1){
-                                return b.execPath.toLowerCase().indexOf('jdk') > -1 ? 0 : 1
-                            } else {
-                                return -1
-                            }
-    
-                        } else {
-                            return a.version.build > b.version.build ? -1 : 1
-                        }
-                    } else {
-                        return  a.version.update > b.version.update ? -1 : 1
-                    }
-                } else {
-                    // Java 9+
-                    if(a.version.minor === b.version.minor){
-                        if(a.version.revision === b.version.revision){
-    
-                            // Same version, give priority to JRE.
-                            if(a.execPath.toLowerCase().indexOf('jdk') > -1){
-                                return b.execPath.toLowerCase().indexOf('jdk') > -1 ? 0 : 1
-                            } else {
-                                return -1
-                            }
-    
-                        } else {
-                            return a.version.revision > b.version.revision ? -1 : 1
-                        }
-                    } else {
-                        return  a.version.minor > b.version.minor ? -1 : 1
-                    }
-                }
-
-            } else {
-                return a.version.major > b.version.major ? -1 : 1
-            }
-        })
-
-        return retArr
-    }
-
-    /**
-     * Attempts to find a valid x64 installation of Java on Windows machines.
-     * Possible paths will be pulled from the registry and the JAVA_HOME environment
-     * variable. The paths will be sorted with higher versions preceeding lower, and
-     * JREs preceeding JDKs. The binaries at the sorted paths will then be validated.
-     * The first validated is returned.
-     * 
-     * Higher versions > Lower versions
-     * If versions are equal, JRE > JDK.
-     * 
-     * @param {string} dataDir The base launcher directory.
-     * @returns {Promise.<string>} A Promise which resolves to the executable path of a valid 
-     * x64 Java installation. If none are found, null is returned.
-     */
-    private async _win32JavaValidate(dataDir: string){
-
-        // Get possible paths from the registry.
-        let pathSet1 = await JavaGuard._scanRegistry()
-        if(pathSet1.size === 0){
-            // Do a manual file system scan of program files.
-            pathSet1 = await JavaGuard._scanFileSystem('C:\\Program Files\\Java')
-        }
-
-        // Get possible paths from the data directory.
-        const pathSet2 = await JavaGuard._scanFileSystem(join(dataDir, 'runtime', 'x64'))
-
-        // Merge the results.
-        const uberSet = new Set([...pathSet1, ...pathSet2])
-
-        // Validate JAVA_HOME.
-        const jHome = JavaGuard._scanJavaHome()
-        if(jHome != null && jHome.indexOf('(x86)') === -1){
-            uberSet.add(jHome)
-        }
-
-        let pathArr = await this._validateJavaRootSet(uberSet)
-        pathArr = JavaGuard._sortValidJavaArray(pathArr)
-
-        if(pathArr.length > 0){
-            return pathArr[0].execPath
-        } else {
-            return null
-        }
-
-    }
-
-    /**
-     * Attempts to find a valid x64 installation of Java on MacOS.
-     * The system JVM directory is scanned for possible installations.
-     * The JAVA_HOME enviroment variable and internet plugins directory
-     * are also scanned and validated.
-     * 
-     * Higher versions > Lower versions
-     * If versions are equal, JRE > JDK.
-     * 
-     * @param {string} dataDir The base launcher directory.
-     * @returns {Promise.<string>} A Promise which resolves to the executable path of a valid 
-     * x64 Java installation. If none are found, null is returned.
-     */
-    async _darwinJavaValidate(dataDir: string){
-
-        const pathSet1 = await JavaGuard._scanFileSystem('/Library/Java/JavaVirtualMachines')
-        const pathSet2 = await JavaGuard._scanFileSystem(join(dataDir, 'runtime', 'x64'))
-
-        const uberSet = new Set([...pathSet1, ...pathSet2])
-
-        // Check Internet Plugins folder.
-        const iPPath = JavaGuard._scanInternetPlugins()
-        if(iPPath != null){
-            uberSet.add(iPPath)
-        }
-
-        // Check the JAVA_HOME environment variable.
-        let jHome = JavaGuard._scanJavaHome()
-        if(jHome != null){
-            // Ensure we are at the absolute root.
-            if(jHome.includes('/Contents/Home')){
-                jHome = jHome.substring(0, jHome.indexOf('/Contents/Home'))
-            }
-            uberSet.add(jHome)
-        }
-
-        let pathArr = await this._validateJavaRootSet(uberSet)
-        pathArr = JavaGuard._sortValidJavaArray(pathArr)
-
-        if(pathArr.length > 0){
-            return pathArr[0].execPath
-        } else {
-            return null
-        }
-    }
-
-    /**
-     * Attempts to find a valid x64 installation of Java on Linux.
-     * The system JVM directory is scanned for possible installations.
-     * The JAVA_HOME enviroment variable is also scanned and validated.
-     * 
-     * Higher versions > Lower versions
-     * If versions are equal, JRE > JDK.
-     * 
-     * @param {string} dataDir The base launcher directory.
-     * @returns {Promise.<string>} A Promise which resolves to the executable path of a valid 
-     * x64 Java installation. If none are found, null is returned.
-     */
-    async _linuxJavaValidate(dataDir: string){
-
-        const pathSet1 = await JavaGuard._scanFileSystem('/usr/lib/jvm')
-        const pathSet2 = await JavaGuard._scanFileSystem(join(dataDir, 'runtime', 'x64'))
-        
-        const uberSet = new Set([...pathSet1, ...pathSet2])
-
-        // Validate JAVA_HOME
-        const jHome = JavaGuard._scanJavaHome()
-        if(jHome != null){
-            uberSet.add(jHome)
-        }
-        
-        let pathArr = await this._validateJavaRootSet(uberSet)
-        pathArr = JavaGuard._sortValidJavaArray(pathArr)
-
-        if(pathArr.length > 0){
-            return pathArr[0].execPath
-        } else {
-            return null
-        }
-    }
-
-    /**
-     * Retrieve the path of a valid x64 Java installation.
-     * 
-     * @param {string} dataDir The base launcher directory.
-     * @returns {string} A path to a valid x64 Java installation, null if none found.
-     */
-    async validateJava(dataDir: string){
-        return await (this as any)[`_${process.platform}JavaValidate`](dataDir)
-    }
-
-}
-
-
-
-
-/**
- * Central object class used for control flow. This object stores data about
- * categories of downloads. Each category is assigned an identifier with a 
- * DLTracker object as its value. Combined information is also stored, such as
- * the total size of all the queued files in each category. This event is used
- * to emit events so that external modules can listen into processing done in
- * this module.
- */
-class AssetGuard extends EventEmitter {
-
-    protected totaldlsize: number
-    protected progress: number
-    protected assets: DLTracker
-    protected libraries: DLTracker
-    protected files: DLTracker
-    protected forge: DLTracker
-    protected java: DLTracker
-    protected extractQueue: any[]
-
-    /**
-     * Create an instance of AssetGuard.
-     * On creation the object's properties are never-null default
-     * values. Each identifier is resolved to an empty DLTracker.
-     * 
-     * @param {string} commonPath The common path for shared game files.
-     * @param {string} javaexec The path to a java executable which will be used
-     * to finalize installation.
-     */
-    constructor(
-        public commonPath: string,
-        public javaexec: string
-    ) {
-        super()
-        this.totaldlsize = 0
-        this.progress = 0
-        this.assets = new DLTracker([], 0)
-        this.libraries = new DLTracker([], 0)
-        this.files = new DLTracker([], 0)
-        this.forge = new DLTracker([], 0)
-        this.java = new DLTracker([], 0)
-        this.extractQueue = []
-        this.commonPath = commonPath
-        this.javaexec = javaexec
-    }
-
-    // Static Utility Functions
-    // #region
-
-    // Static Hash Validation Functions
-    // #region
-
-    /**
-     * Calculates the hash for a file using the specified algorithm.
-     * 
-     * @param {Buffer} buf The buffer containing file data.
-     * @param {string} algo The hash algorithm.
-     * @returns {string} The calculated hash in hex.
-     */
-    private static _calculateHash(buf: Buffer, algo: string){
-        return createHash(algo).update(buf).digest('hex')
-    }
-
-    /**
-     * Used to parse a checksums file. This is specifically designed for
-     * the checksums.sha1 files found inside the forge scala dependencies.
-     * 
-     * @param {string} content The string content of the checksums file.
-     * @returns {Object} An object with keys being the file names, and values being the hashes.
-     */
-    private static _parseChecksumsFile(content: string) {
-        let finalContent: {[fileName: string]: string} = {}
-        let lines = content.split('\n')
-        for(let i=0; i<lines.length; i++){
-            let bits = lines[i].split(' ')
-            if(bits[1] == null) {
-                continue
-            }
-            finalContent[bits[1]] = bits[0]
-        }
-        return finalContent
-    }
-
-    /**
-     * Validate that a file exists and matches a given hash value.
-     * 
-     * @param {string} filePath The path of the file to validate.
-     * @param {string} algo The hash algorithm to check against.
-     * @param {string} hash The existing hash to check against.
-     * @returns {boolean} True if the file exists and calculated hash matches the given hash, otherwise false.
-     */
-    private static _validateLocal(filePath: string, algo: string, hash: string){
-        if(pathExistsSync(filePath)){
-            //No hash provided, have to assume it's good.
-            if(hash == null){
-                return true
-            }
-            let buf = readFileSync(filePath)
-            let calcdhash = AssetGuard._calculateHash(buf, algo)
-            return calcdhash === hash
-        }
-        return false
-    }
-
-    /**
-     * Validates a file in the style used by forge's version index.
-     * 
-     * @param {string} filePath The path of the file to validate.
-     * @param {Array.<string>} checksums The checksums listed in the forge version index.
-     * @returns {boolean} True if the file exists and the hashes match, otherwise false.
-     */
-    private static _validateForgeChecksum(filePath: string, checksums: string[]){
-        if(pathExistsSync(filePath)){
-            if(checksums == null || checksums.length === 0){
-                return true
-            }
-            let buf = readFileSync(filePath)
-            let calcdhash = AssetGuard._calculateHash(buf, 'sha1')
-            let valid = checksums.includes(calcdhash)
-            if(!valid && filePath.endsWith('.jar')){
-                valid = AssetGuard._validateForgeJar(buf, checksums)
-            }
-            return valid
-        }
-        return false
-    }
-
-    /**
-     * Validates a forge jar file dependency who declares a checksums.sha1 file.
-     * This can be an expensive task as it usually requires that we calculate thousands
-     * of hashes.
-     * 
-     * @param {Buffer} buf The buffer of the jar file.
-     * @param {Array.<string>} checksums The checksums listed in the forge version index.
-     * @returns {boolean} True if all hashes declared in the checksums.sha1 file match the actual hashes.
-     */
-    private static _validateForgeJar(buf: Buffer, checksums: string[]){
-        // Double pass method was the quickest I found. I tried a version where we store data
-        // to only require a single pass, plus some quick cleanup but that seemed to take slightly more time.
-
-        const hashes: {[fileName: string]: string} = {}
-        let expected: {[fileName: string]: string} = {}
-
-        const zip = new AdmZip(buf)
-        const zipEntries = zip.getEntries()
-
-        //First pass
-        for(let i=0; i<zipEntries.length; i++){
-            let entry = zipEntries[i]
-            if(entry.entryName === 'checksums.sha1'){
-                expected = AssetGuard._parseChecksumsFile(zip.readAsText(entry))
-            }
-            hashes[entry.entryName] = AssetGuard._calculateHash(entry.getData(), 'sha1')
-        }
-
-        if(!checksums.includes(hashes['checksums.sha1'])){
-            return false
-        }
-
-        //Check against expected
-        const expectedEntries = Object.keys(expected)
-        for(let i=0; i<expectedEntries.length; i++){
-            if(expected[expectedEntries[i]] !== hashes[expectedEntries[i]]){
-                return false
-            }
-        }
-        return true
-    }
-
-    // #endregion
-
-    // Miscellaneous Static Functions
-    // #region
-
-    /**
-     * Extracts and unpacks a file from .pack.xz format.
-     * 
-     * @param {Array.<string>} filePaths The paths of the files to be extracted and unpacked.
-     * @returns {Promise.<void>} An empty promise to indicate the extraction has completed.
-     */
-    private static _extractPackXZ(filePaths: string[], javaExecutable: string){
-        console.log('[PackXZExtract] Starting')
-        return new Promise((resolve, reject) => {
-
-            let libPath
-            if(isDev){
-                libPath = join(process.cwd(), 'libraries', 'java', 'PackXZExtract.jar')
-            } else {
-                if(process.platform === 'darwin'){
-                    libPath = join(process.cwd(),'Contents', 'Resources', 'libraries', 'java', 'PackXZExtract.jar')
-                } else {
-                    libPath = join(process.cwd(), 'resources', 'libraries', 'java', 'PackXZExtract.jar')
-                }
-            }
-
-            const filePath = filePaths.join(',')
-            const child = spawn(javaExecutable, ['-jar', libPath, '-packxz', filePath])
-            child.stdout.on('data', (data) => {
-                console.log('[PackXZExtract]', data.toString('utf8').trim())
-            })
-            child.stderr.on('data', (data) => {
-                console.log('[PackXZExtract]', data.toString('utf8').trim())
-            })
-            child.on('close', (code, signal) => {
-                console.log('[PackXZExtract]', 'Exited with code', code)
-                resolve()
-            })
-        })
-    }
-
-    /**
-     * Function which finalizes the forge installation process. This creates a 'version'
-     * instance for forge and saves its version.json file into that instance. If that
-     * instance already exists, the contents of the version.json file are read and returned
-     * in a promise.
-     * 
-     * @param {Asset} asset The Asset object representing Forge.
-     * @param {string} commonPath The common path for shared game files.
-     * @returns {Promise.<Object>} A promise which resolves to the contents of forge's version.json.
-     */
-    // TODO type def
-    private static _finalizeForgeAsset(asset: Asset, commonPath: string){
-        return new Promise((resolve, reject) => {
-            readFile(asset.to, (err, data) => {
-                const zip = new AdmZip(data)
-                const zipEntries = zip.getEntries()
-
-                for(let i=0; i<zipEntries.length; i++){
-                    if(zipEntries[i].entryName === 'version.json'){
-                        const forgeVersion = JSON.parse(zip.readAsText(zipEntries[i]))
-                        const versionPath = join(commonPath, 'versions', forgeVersion.id)
-                        const versionFile = join(versionPath, forgeVersion.id + '.json')
-                        if(!pathExistsSync(versionFile)){
-                            ensureDirSync(versionPath)
-                            writeFileSync(join(versionPath, forgeVersion.id + '.json'), zipEntries[i].getData())
-                            resolve(forgeVersion)
-                        } else {
-                            //Read the saved file to allow for user modifications.
-                            resolve(JSON.parse(readFileSync(versionFile, 'utf-8')))
-                        }
-                        return
-                    }
-                }
-                //We didn't find forge's version.json.
-                reject('Unable to finalize Forge processing, version.json not found! Has forge changed their format?')
-            })
-        })
-    }
-
-    // #endregion
-
-    // #endregion
-
-    // Validation Functions
-    // #region
-
-    /**
-     * Loads the version data for a given minecraft version.
-     * 
-     * @param {string} version The game version for which to load the index data.
-     * @param {boolean} force Optional. If true, the version index will be downloaded even if it exists locally. Defaults to false.
-     * @returns {Promise.<VersionJson>} Promise which resolves to the version data object.
-     */
-    public loadVersionData(version: string, force = false): Promise<VersionJson>{
-        const self = this
-        return new Promise(async (resolve, reject) => {
-            const versionPath = join(self.commonPath, 'versions', version)
-            const versionFile = join(versionPath, version + '.json')
-            if(!pathExistsSync(versionFile) || force){
-                const url = await self._getVersionDataUrl(version)
-                if (url == null) {
-                    console.error(`No version index found for ${version}.`)
-                    reject()
-                    return
-                }
-                //This download will never be tracked as it's essential and trivial.
-                console.log('Preparing download of ' + version + ' assets.')
-                ensureDirSync(versionPath)
-                const stream = request(url).pipe(createWriteStream(versionFile))
-                stream.on('finish', () => {
-                    resolve(readJsonSync(versionFile) as VersionJson)
-                })
-            } else {
-                resolve(readJsonSync(versionFile) as VersionJson)
-            }
-        })
-    }
-
-    /**
-     * Parses Mojang's version manifest and retrieves the url of the version
-     * data index.
-     * 
-     * @param {string} version The version to lookup.
-     * @returns {Promise.<string>} Promise which resolves to the url of the version data index.
-     * If the version could not be found, resolves to null.
-     */
-    private _getVersionDataUrl(version: string): Promise<string | null> {
-        return new Promise((resolve, reject) => {
-            request('https://launchermeta.mojang.com/mc/game/version_manifest.json', (error, resp, body) => {
-                if(error){
-                    reject(error)
-                } else {
-                    const manifest = JSON.parse(body)
-
-                    for(let v of manifest.versions){
-                        if(v.id === version){
-                            resolve(v.url)
-                        }
-                    }
-
-                    resolve(null)
-                }
-            })
-        })
-    }
-
-
-    // Asset (Category=''') Validation Functions
-    // #region
-
-    /**
-     * Public asset validation function. This function will handle the validation of assets.
-     * It will parse the asset index specified in the version data, analyzing each
-     * asset entry. In this analysis it will check to see if the local file exists and is valid.
-     * If not, it will be added to the download queue for the 'assets' identifier.
-     * 
-     * @param {VersionJson} versionData The version data for the assets.
-     * @param {boolean} force Optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    public validateAssets(versionData: VersionJson, force = false): Promise<void> {
-        const self = this
-        return new Promise((resolve, reject) => {
-            self._assetChainIndexData(versionData, force).then(() => {
-                resolve()
-            })
-        })
-    }
-
-    //Chain the asset tasks to provide full async. The below functions are private.
-    /**
-     * Private function used to chain the asset validation process. This function retrieves
-     * the index data.
-     * @param {VersionJson} versionData
-     * @param {boolean} force
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    private _assetChainIndexData(versionData: VersionJson, force = false): Promise<void> {
-        const self = this
-        return new Promise((resolve, reject) => {
-            //Asset index constants.
-            const assetIndex = versionData.assetIndex
-            const name = assetIndex.id + '.json'
-            const indexPath = join(self.commonPath, 'assets', 'indexes')
-            const assetIndexLoc = join(indexPath, name)
-
-            let data = null
-            if(!pathExistsSync(assetIndexLoc) || force){
-                console.log('Downloading ' + versionData.id + ' asset index.')
-                ensureDirSync(indexPath)
-                const stream = request(assetIndex.url).pipe(createWriteStream(assetIndexLoc))
-                stream.on('finish', () => {
-                    data = JSON.parse(readFileSync(assetIndexLoc, 'utf-8'))
-                    self._assetChainValidateAssets(versionData, data).then(() => {
-                        resolve()
-                    })
-                })
-            } else {
-                data = JSON.parse(readFileSync(assetIndexLoc, 'utf-8'))
-                self._assetChainValidateAssets(versionData, data).then(() => {
-                    resolve()
-                })
-            }
-        })
-    }
-
-    /**
-     * Private function used to chain the asset validation process. This function processes
-     * the assets and enqueues missing or invalid files.
-     * @param {VersionJson} versionData
-     * @param {boolean} force
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    private _assetChainValidateAssets(versionData: VersionJson, indexData: AssetIndex): Promise<void> {
-        const self = this
-        return new Promise((resolve, reject) => {
-
-            //Asset constants
-            const resourceURL = 'http://resources.download.minecraft.net/'
-            const localPath = join(self.commonPath, 'assets')
-            const objectPath = join(localPath, 'objects')
-
-            const assetDlQueue: Asset[] = []
-            let dlSize = 0
-            let acc = 0
-            const total = Object.keys(indexData.objects).length
-            //const objKeys = Object.keys(data.objects)
-            forEachOfLimit(indexData.objects, 10, (value, key, cb) => {
-                acc++
-                self.emit('progress', 'assets', acc, total)
-                const hash = value.hash
-                const assetName = join(hash.substring(0, 2), hash)
-                const urlName = hash.substring(0, 2) + '/' + hash
-                const ast = new Asset(key, hash, value.size, resourceURL + urlName, join(objectPath, assetName))
-                if(!AssetGuard._validateLocal(ast.to, 'sha1', ast.hash)){
-                    dlSize += (ast.size*1)
-                    assetDlQueue.push(ast)
-                }
-                cb()
-            }, (err) => {
-                self.assets = new DLTracker(assetDlQueue, dlSize)
-                resolve()
-            })
-        })
-    }
-    
-    // #endregion
-
-    // Library (Category=''') Validation Functions
-    // #region
-
-    /**
-     * Public library validation function. This function will handle the validation of libraries.
-     * It will parse the version data, analyzing each library entry. In this analysis, it will
-     * check to see if the local file exists and is valid. If not, it will be added to the download
-     * queue for the 'libraries' identifier.
-     * 
-     * @param {VersionJson} versionData The version data for the assets.
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    public validateLibraries(versionData: VersionJson){
-        const self = this
-        return new Promise((resolve, reject) => {
-
-            const libArr = versionData.libraries
-            const libPath = join(self.commonPath, 'libraries')
-
-            const libDlQueue: LibraryInternal[] = []
-            let dlSize = 0
-
-            //Check validity of each library. If the hashs don't match, download the library.
-            eachLimit(libArr, 5, (lib: Library, cb) => {
-                if(LibraryInternal.validateRules(lib.rules, lib.natives)){
-                    // @ts-ignore
-                    let artifact = (lib.natives == null) ? lib.downloads.artifact : lib.downloads.classifiers[lib.natives[LibraryInternal.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))]
-                    const libItm = new LibraryInternal(lib.name, artifact.sha1, artifact.size, artifact.url, join(libPath, artifact.path))
-                    if(!AssetGuard._validateLocal(libItm.to, 'sha1', libItm.hash)){
-                        dlSize += (libItm.size*1)
-                        libDlQueue.push(libItm)
-                    }
-                }
-                cb()
-            }, (err) => {
-                self.libraries = new DLTracker(libDlQueue, dlSize)
-                resolve()
-            })
-        })
-    }
-
-    // #endregion
-
-    // Miscellaneous (Category=files) Validation Functions
-    // #region
-
-    /**
-     * Public miscellaneous mojang file validation function. These files will be enqueued under
-     * the 'files' identifier.
-     * 
-     * @param {VersionJson} versionData The version data for the assets.
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    public validateMiscellaneous(versionData: VersionJson){
-        const self = this
-        return new Promise(async (resolve, reject) => {
-            await self.validateClient(versionData)
-            await self.validateLogConfig(versionData)
-            resolve()
-        })
-    }
-
-    /**
-     * Validate client file - artifact renamed from client.jar to '{version}'.jar.
-     * 
-     * @param {VersionJson} versionData The version data for the assets.
-     * @param {boolean} force Optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    public validateClient(versionData: VersionJson, force = false){
-        const self = this
-        return new Promise((resolve, reject) => {
-            const clientData = versionData.downloads.client
-            const version = versionData.id
-            const targetPath = join(self.commonPath, 'versions', version)
-            const targetFile = version + '.jar'
-
-            let client = new Asset(version + ' client', clientData.sha1, clientData.size, clientData.url, join(targetPath, targetFile))
-
-            if(!AssetGuard._validateLocal(client.to, 'sha1', client.hash) || force){
-                self.files.dlqueue.push(client)
-                self.files.dlsize += client.size*1
-                resolve()
-            } else {
-                resolve()
-            }
-        })
-    }
-
-    /**
-     * Validate log config.
-     * 
-     * @param {VersionJson} versionData The version data for the assets.
-     * @param {boolean} force Optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
-     * @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
-     */
-    public validateLogConfig(versionData: VersionJson){
-        const self = this
-        return new Promise((resolve, reject) => {
-            const client = versionData.logging.client
-            const file = client.file
-            const targetPath = join(self.commonPath, 'assets', 'log_configs')
-
-            let logConfig = new Asset(file.id, file.sha1, file.size, file.url, join(targetPath, file.id))
-
-            if(!AssetGuard._validateLocal(logConfig.to, 'sha1', logConfig.hash)){
-                self.files.dlqueue.push(logConfig)
-                self.files.dlsize += logConfig.size*1
-                resolve()
-            } else {
-                resolve()
-            }
-        })
-    }
-
-    // #endregion
-
-    // Distribution (Category=forge) Validation Functions
-    // #region
-
-    /**
-     * Validate the distribution.
-     * 
-     * @param {Server} server The Server to validate.
-     * @returns {Promise.<Object>} A promise which resolves to the server distribution object.
-     */
-    public validateDistribution(server: any){
-        const self = this
-        return new Promise((resolve, reject) => {
-            self.forge = self._parseDistroModules(server.getModules(), server.getMinecraftVersion(), server.getID())
-            resolve(server)
-        })
-    }
-
-    private _parseDistroModules(modules: any[], version: string, servid: string){
-        let alist: any[] = []
-        let asize = 0
-        for(let ob of modules){
-            let obArtifact = ob.getArtifact()
-            let obPath = obArtifact.getPath()
-            let artifact = new DistroModule(ob.getIdentifier(), obArtifact.getHash(), obArtifact.getSize(), obArtifact.getURL(), obPath, ob.getType())
-            const validationPath = obPath.toLowerCase().endsWith('.pack.xz') ? obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')) : obPath
-            if(!AssetGuard._validateLocal(validationPath, 'MD5', artifact.hash)){
-                asize += artifact.size*1
-                alist.push(artifact)
-                // @ts-ignore
-                // TODO revisit
-                if(validationPath !== obPath) this.extractQueue.push(obPath)
-            }
-            //Recursively process the submodules then combine the results.
-            if(ob.getSubModules() != null){
-                let dltrack = this._parseDistroModules(ob.getSubModules(), version, servid)
-                asize += dltrack.dlsize*1
-                alist = alist.concat(dltrack.dlqueue)
-            }
-        }
-
-        return new DLTracker(alist, asize)
-    }
-
-    /**
-     * Loads Forge's version.json data into memory for the specified server id.
-     * 
-     * @param {any} server The Server to load Forge data for.
-     * @returns {Promise.<Object>} A promise which resolves to Forge's version.json data.
-     */
-    public loadForgeData(server: any){
-        const self = this
-        return new Promise(async (resolve, reject) => {
-            const modules = server.getModules()
-            for(let ob of modules){
-                const type = ob.getType()
-                if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Forge){
-                    if(Util.mcVersionAtLeast('1.13', server.getMinecraftVersion())){
-                        // Read Manifest
-                        for(let sub of ob.getSubModules()){
-                            if(sub.getType() === DistroManager.Types.VersionManifest){
-                                resolve(JSON.parse(readFileSync(sub.getArtifact().getPath(), 'utf-8')))
-                                return
-                            }
-                        }
-                        reject('No forge version manifest found!')
-                        return
-                    } else {
-                        let obArtifact = ob.getArtifact()
-                        let obPath = obArtifact.getPath()
-                        let asset = new DistroModule(ob.getIdentifier(), obArtifact.getHash(), obArtifact.getSize(), obArtifact.getURL(), obPath, type)
-                        try {
-                            let forgeData = await AssetGuard._finalizeForgeAsset(asset, self.commonPath)
-                            resolve(forgeData)
-                        } catch (err){
-                            reject(err)
-                        }
-                        return
-                    }
-                }
-            }
-            reject('No forge module found!')
-        })
-    }
-
-    private _parseForgeLibraries(){
-        /* TODO
-        * Forge asset validations are already implemented. When there's nothing much
-        * to work on, implement forge downloads using forge's version.json. This is to
-        * have the code on standby if we ever need it (since it's half implemented already).
-        */
-    }
-
-    // #endregion
-
-    // Java (Category=''') Validation (download) Functions
-    // #region
-
-    private _enqueueOpenJDK(dataDir: string){
-        return new Promise((resolve, reject) => {
-            JavaGuard.latestOpenJDK('8').then(verData => {
-                if(verData != null){
-
-                    dataDir = join(dataDir, 'runtime', 'x64')
-                    const fDir = join(dataDir, verData.name)
-                    // @ts-ignore
-                    // TODO revisit
-                    const jre = new Asset(verData.name, null, verData.size, verData.uri, fDir)
-                    this.java = new DLTracker([jre], jre.size, (a: Asset, self: this) => {
-                        if(verData.name.endsWith('zip')){
-
-                            const zip = new AdmZip(a.to)
-                            const pos = join(dataDir, zip.getEntries()[0].entryName)
-                            zip.extractAllToAsync(dataDir, true, (err) => {
-                                if(err){
-                                    console.log(err)
-                                    self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
-                                } else {
-                                    unlink(a.to, err => {
-                                        if(err){
-                                            console.log(err)
-                                        }
-                                        self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
-                                    })
-                                }
-                            })
-
-                        } else {
-                            // Tar.gz
-                            let h: string
-                            createReadStream(a.to)
-                                .on('error', err => console.log(err))
-                                .pipe(createGunzip())
-                                .on('error', err => console.log(err))
-                                .pipe(extract(dataDir, {
-                                    map: (header) => {
-                                        if(h == null){
-                                            h = header.name
-                                        }
-                                        return header
-                                    }
-                                }))
-                                .on('error', err => console.log(err))
-                                .on('finish', () => {
-                                    unlink(a.to, err => {
-                                        if(err){
-                                            console.log(err)
-                                        }
-                                        if(h.indexOf('/') > -1){
-                                            h = h.substring(0, h.indexOf('/'))
-                                        }
-                                        const pos = join(dataDir, h)
-                                        self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
-                                    })
-                                })
-                        }
-                    })
-                    resolve(true)
-
-                } else {
-                    resolve(false)
-                }
-            })
-        })
-
-    }
-
-    // _enqueueOracleJRE(dataDir){
-    //     return new Promise((resolve, reject) => {
-    //         JavaGuard._latestJREOracle().then(verData => {
-    //             if(verData != null){
-
-    //                 const combined = verData.uri + PLATFORM_MAP[process.platform]
-        
-    //                 const opts = {
-    //                     url: combined,
-    //                     headers: {
-    //                         'Cookie': 'oraclelicense=accept-securebackup-cookie'
-    //                     }
-    //                 }
-        
-    //                 request.head(opts, (err, resp, body) => {
-    //                     if(err){
-    //                         resolve(false)
-    //                     } else {
-    //                         dataDir = path.join(dataDir, 'runtime', 'x64')
-    //                         const name = combined.substring(combined.lastIndexOf('/')+1)
-    //                         const fDir = path.join(dataDir, name)
-    //                         const jre = new Asset(name, null, parseInt(resp.headers['content-length']), opts, fDir)
-    //                         this.java = new DLTracker([jre], jre.size, (a, self) => {
-    //                             let h = null
-    //                             fs.createReadStream(a.to)
-    //                                 .on('error', err => console.log(err))
-    //                                 .pipe(zlib.createGunzip())
-    //                                 .on('error', err => console.log(err))
-    //                                 .pipe(tar.extract(dataDir, {
-    //                                     map: (header) => {
-    //                                         if(h == null){
-    //                                             h = header.name
-    //                                         }
-    //                                     }
-    //                                 }))
-    //                                 .on('error', err => console.log(err))
-    //                                 .on('finish', () => {
-    //                                     fs.unlink(a.to, err => {
-    //                                         if(err){
-    //                                             console.log(err)
-    //                                         }
-    //                                         if(h.indexOf('/') > -1){
-    //                                             h = h.substring(0, h.indexOf('/'))
-    //                                         }
-    //                                         const pos = path.join(dataDir, h)
-    //                                         self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
-    //                                     })
-    //                                 })
-                                
-    //                         })
-    //                         resolve(true)
-    //                     }
-    //                 })
-
-    //             } else {
-    //                 resolve(false)
-    //             }
-    //         })
-    //     })
-
-    // }
-
-    // _enqueueMojangJRE(dir){
-    //     return new Promise((resolve, reject) => {
-    //         // Mojang does not host the JRE for linux.
-    //         if(process.platform === 'linux'){
-    //             resolve(false)
-    //         }
-    //         AssetGuard.loadMojangLauncherData().then(data => {
-    //             if(data != null) {
-
-    //                 try {
-    //                     const mJRE = data[Library.mojangFriendlyOS()]['64'].jre
-    //                     const url = mJRE.url
-
-    //                     request.head(url, (err, resp, body) => {
-    //                         if(err){
-    //                             resolve(false)
-    //                         } else {
-    //                             const name = url.substring(url.lastIndexOf('/')+1)
-    //                             const fDir = path.join(dir, name)
-    //                             const jre = new Asset('jre' + mJRE.version, mJRE.sha1, resp.headers['content-length'], url, fDir)
-    //                             this.java = new DLTracker([jre], jre.size, a => {
-    //                                 fs.readFile(a.to, (err, data) => {
-    //                                     // Data buffer needs to be decompressed from lzma,
-    //                                     // not really possible using node.js
-    //                                 })
-    //                             })
-    //                         }
-    //                     })
-    //                 } catch (err){
-    //                     resolve(false)
-    //                 }
-
-    //             }
-    //         })
-    //     })
-    // }
-
-
-    // #endregion
-
-    // #endregion
-
-    // Control Flow Functions
-    // #region
-
-    /**
-     * Initiate an async download process for an AssetGuard DLTracker.
-     * 
-     * @param {string} identifier The identifier of the AssetGuard DLTracker.
-     * @param {number} limit Optional. The number of async processes to run in parallel.
-     * @returns {boolean} True if the process began, otherwise false.
-     */
-    public startAsyncProcess(identifier: string, limit = 5){
-
-        const self = this
-        const dlTracker = (this as any)[identifier]
-        const dlQueue = dlTracker.dlqueue
-
-        if(dlQueue.length > 0){
-            console.log('DLQueue', dlQueue)
-
-            eachLimit(dlQueue, limit, (asset: Asset, cb) => {
-
-                ensureDirSync(join(asset.to, '..'))
-
-                let req = request(asset.from)
-                req.pause()
-
-                req.on('response', (resp) => {
-
-                    if(resp.statusCode === 200){
-
-                        let doHashCheck = false
-                        const contentLength = parseInt(resp.headers['content-length'] as string)
-
-                        if(contentLength !== asset.size){
-                            console.log(`WARN: Got ${contentLength} bytes for ${asset.id}: Expected ${asset.size}`)
-                            doHashCheck = true
-
-                            // Adjust download
-                            this.totaldlsize -= asset.size
-                            this.totaldlsize += contentLength
-                        }
-
-                        let writeStream = createWriteStream(asset.to)
-                        writeStream.on('close', () => {
-                            if(dlTracker.callback != null){
-                                dlTracker.callback.apply(dlTracker, [asset, self])
-                            }
-
-                            if(doHashCheck){
-                                // @ts-ignore
-                                // TODO revisit
-                                const v = AssetGuard._validateLocal(asset.to, asset.type != null ? 'md5' : 'sha1', asset.hash)
-                                if(v){
-                                    console.log(`Hashes match for ${asset.id}, byte mismatch is an issue in the distro index.`)
-                                } else {
-                                    console.error(`Hashes do not match, ${asset.id} may be corrupted.`)
-                                }
-                            }
-
-                            cb()
-                        })
-                        req.pipe(writeStream)
-                        req.resume()
-
-                    } else {
-
-                        req.abort()
-                        // @ts-ignore
-                        // TODO revisit
-                        console.log(`Failed to download ${asset.id}(${typeof asset.from === 'object' ? asset.from.url : asset.from}). Response code ${resp.statusCode}`)
-                        self.progress += asset.size*1
-                        self.emit('progress', 'download', self.progress, self.totaldlsize)
-                        cb()
-
-                    }
-
-                })
-
-                req.on('error', (err) => {
-                    self.emit('error', 'download', err)
-                })
-
-                req.on('data', (chunk) => {
-                    self.progress += chunk.length
-                    self.emit('progress', 'download', self.progress, self.totaldlsize)
-                })
-
-            }, (err) => {
-
-                if(err){
-                    console.log('An item in ' + identifier + ' failed to process')
-                } else {
-                    console.log('All ' + identifier + ' have been processed successfully')
-                }
-
-                //self.totaldlsize -= dlTracker.dlsize
-                //self.progress -= dlTracker.dlsize
-                (self as any)[identifier] = new DLTracker([], 0)
-
-                if(self.progress >= self.totaldlsize) {
-                    if(self.extractQueue.length > 0){
-                        self.emit('progress', 'extract', 1, 1)
-                        //self.emit('extracting')
-                        AssetGuard._extractPackXZ(self.extractQueue, self.javaexec).then(() => {
-                            self.extractQueue = []
-                            self.emit('complete', 'download')
-                        })
-                    } else {
-                        self.emit('complete', 'download')
-                    }
-                }
-
-            })
-
-            return true
-
-        } else {
-            return false
-        }
-    }
-
-    /**
-     * This function will initiate the download processed for the specified identifiers. If no argument is
-     * given, all identifiers will be initiated. Note that in order for files to be processed you need to run
-     * the processing function corresponding to that identifier. If you run this function without processing
-     * the files, it is likely nothing will be enqueued in the object and processing will complete
-     * immediately. Once all downloads are complete, this function will fire the 'complete' event on the
-     * global object instance.
-     * 
-     * @param {Array.<{id: string, limit: number}>} identifiers Optional. The identifiers to process and corresponding parallel async task limit.
-     */
-    public processDlQueues(identifiers = [{id:'assets', limit:20}, {id:'libraries', limit:5}, {id:'files', limit:5}, {id:'forge', limit:5}]){
-        return new Promise((resolve, reject) => {
-            let shouldFire = true
-
-            // Assign dltracking variables.
-            this.totaldlsize = 0
-            this.progress = 0
-
-            for(let iden of identifiers){
-                this.totaldlsize += (this as any)[iden.id].dlsize
-            }
-
-            this.once('complete', (data) => {
-                resolve()
-            })
-
-            for(let iden of identifiers){
-                let r = this.startAsyncProcess(iden.id, iden.limit)
-                if(r) shouldFire = false
-            }
-
-            if(shouldFire){
-                this.emit('complete', 'download')
-            }
-        })
-    }
-
-    public async validateEverything(serverid: string, dev = false){
-
-        try {
-            if(!ConfigManager.isLoaded()){
-                ConfigManager.load()
-            }
-            DistroManager.setDevMode(dev)
-            const dI = await DistroManager.pullLocal()
-    
-            const server = dI.getServer(serverid)
-    
-            // Validate Everything
-    
-            await this.validateDistribution(server)
-            this.emit('validate', 'distribution')
-            const versionData = await this.loadVersionData(server.getMinecraftVersion())
-            this.emit('validate', 'version')
-            await this.validateAssets(versionData)
-            this.emit('validate', 'assets')
-            await this.validateLibraries(versionData)
-            this.emit('validate', 'libraries')
-            await this.validateMiscellaneous(versionData)
-            this.emit('validate', 'files')
-            await this.processDlQueues()
-            //this.emit('complete', 'download')
-            const forgeData = await this.loadForgeData(server)
-        
-            return {
-                versionData,
-                forgeData
-            }
-
-        } catch (err){
-            return {
-                versionData: null,
-                forgeData: null,
-                error: err
-            }
-        }
-        
-
-    }
-
-    // #endregion
-
-}

+ 0 - 101
src/main/old/authmanager.ts

@@ -1,101 +0,0 @@
-import { LoggerUtil } from './loggerutil'
-import { ConfigManager } from '../../common/config/configmanager'
-import { Mojang } from '../../common/mojang/mojang'
-import { SavedAccount } from '../../common/config/model/SavedAccount'
-
-/**
- * AuthManager
- * 
- * This module aims to abstract login procedures. Results from Mojang's REST api
- * are retrieved through our Mojang module. These results are processed and stored,
- * if applicable, in the config using the ConfigManager. All login procedures should
- * be made through this module.
- * 
- * @module authmanager
- */
-
-const logger        = new LoggerUtil('%c[AuthManager]', 'color: #a02d2a; font-weight: bold')
-const loggerSuccess = new LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight: bold')
-
-// Functions
-
-/**
- * Add an account. This will authenticate the given credentials with Mojang's
- * authserver. The resultant data will be stored as an auth account in the
- * configuration database.
- * 
- * @param {string} username The account username (email if migrated).
- * @param {string} password The account password.
- * @returns {Promise.<Object>} Promise which resolves the resolved authenticated account object.
- */
-exports.addAccount = async function(username: string, password: string){
-    try {
-        const session = await Mojang.authenticate(username, password, ConfigManager.getClientToken())
-        if(session.selectedProfile != null){
-            const ret = ConfigManager.addAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name)
-            if(ConfigManager.getClientToken() == null){
-                ConfigManager.setClientToken(session.clientToken)
-            }
-            ConfigManager.save()
-            return ret
-        } else {
-            throw new Error('NotPaidAccount')
-        }
-        
-    } catch (err){
-        return Promise.reject(err)
-    }
-}
-
-/**
- * Remove an account. This will invalidate the access token associated
- * with the account and then remove it from the database.
- * 
- * @param {string} uuid The UUID of the account to be removed.
- * @returns {Promise.<void>} Promise which resolves to void when the action is complete.
- */
-exports.removeAccount = async function(uuid: string){
-    try {
-        const authAcc = ConfigManager.getAuthAccount(uuid)
-        await Mojang.invalidate(authAcc.accessToken, ConfigManager.getClientToken() as string)
-        ConfigManager.removeAuthAccount(uuid)
-        ConfigManager.save()
-        return Promise.resolve()
-    } catch (err){
-        return Promise.reject(err)
-    }
-}
-
-/**
- * Validate the selected account with Mojang's authserver. If the account is not valid,
- * we will attempt to refresh the access token and update that value. If that fails, a
- * new login will be required.
- * 
- * **Function is WIP**
- * 
- * @returns {Promise.<boolean>} Promise which resolves to true if the access token is valid,
- * otherwise false.
- */
-exports.validateSelected = async function(){
-    const current = ConfigManager.getSelectedAccount() as SavedAccount
-    const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken() as string)
-    if(!isValid){
-        try {
-            const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken() as string)
-            ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
-            ConfigManager.save()
-        } catch(err) {
-            logger.debug('Error while validating selected profile:', err)
-            if(err && err.error === 'ForbiddenOperationException'){
-                // What do we do?
-            }
-            logger.log('Account access token is invalid.')
-            return false
-        }
-        loggerSuccess.log('Account access token validated.')
-        return true
-    } else {
-        loggerSuccess.log('Account access token validated.')
-        return true
-    }
-}

+ 0 - 50
src/main/old/discordwrapper.ts

@@ -1,50 +0,0 @@
-import { LoggerUtil } from './loggerutil'
-import { Client, Presence } from 'discord-rpc'
-
-// Work in progress
-const logger = new LoggerUtil('%c[DiscordWrapper]', 'color: #7289da; font-weight: bold')
-
-let client: Client
-let activity: Presence
-
-// TODO types for these settings
-export function initRPC(genSettings: any, servSettings: any, initialDetails = 'Waiting for Client..'){
-    client = new Client({ transport: 'ipc' })
-
-    activity = {
-        details: initialDetails,
-        state: 'Server: ' + servSettings.shortId,
-        largeImageKey: servSettings.largeImageKey,
-        largeImageText: servSettings.largeImageText,
-        smallImageKey: genSettings.smallImageKey,
-        smallImageText: genSettings.smallImageText,
-        startTimestamp: new Date().getTime(),
-        instance: false
-    }
-
-    client.on('ready', () => {
-        logger.log('Discord RPC Connected')
-        client.setActivity(activity)
-    })
-    
-    client.login({clientId: genSettings.clientId}).catch(error => {
-        if(error.message.includes('ENOENT')) {
-            logger.log('Unable to initialize Discord Rich Presence, no client detected.')
-        } else {
-            logger.log('Unable to initialize Discord Rich Presence: ' + error.message, error)
-        }
-    })
-}
-
-export function updateDetails(details: string){
-    activity.details = details
-    client.setActivity(activity)
-}
-
-export function shutdownRPC(){
-    if(!client) return
-    client.clearActivity()
-    client.destroy()
-    client = null as unknown as Client // TODO cleanup
-    activity = null as unknown as Presence // TODO cleanup
-}

+ 0 - 296
src/main/old/distromanager.ts

@@ -1,296 +0,0 @@
-import request from 'request'
-import { Distribution, Module, Type, TypeMetadata, Server } from 'helios-distribution-types'
-import { readJson, writeJson } from 'fs-extra'
-import { join } from 'path'
-import { LoggerUtil } from './loggerutil'
-import { ConfigManager } from '../../common/config/configmanager'
-
-const logger = new LoggerUtil('%c[DistroManager]', 'color: #a02d2a; font-weight: bold')
-
-interface ArtifactMeta {
-    group: string
-    artifact: string
-    version: string
-    classifier?: string
-    extension: string
-}
-
-export class ModuleWrapper {
-    
-    private artifactMeta: ArtifactMeta
-    private subModules: ModuleWrapper[] = []
-
-    constructor(public module: Module, private serverId: string) {
-        this.artifactMeta = this.resolveMetaData()
-        this.resolveArtifactPath()
-        this.resolveRequired()
-        if (this.module.subModules != null) {
-            this.subModules = this.module.subModules.map(mdl => new ModuleWrapper(mdl, serverId))
-        }
-    }
-
-    private resolveMetaData(): ArtifactMeta {
-        try {
-
-            const m0 = this.module.id.split('@')
-            const m1 = m0[0].split(':')
-
-            return {
-                group:  m1[0] || '???',
-                artifact: m1[1] || '???',
-                version: m1[2] || '???',
-                classifier: m1[3] || undefined,
-                extension: m0[1] || TypeMetadata[this.module.type].defaultExtension || 'undefined'
-            }
-
-        } catch (err) {
-            logger.error('Improper ID for module', this.module.id, err)
-            return {
-                group: '???',
-                artifact: '???',
-                version: '???',
-                classifier: undefined,
-                extension: '???'
-            }
-        }
-    }
-
-    private resolveArtifactPath(): void {
-        const relativePath = this.module.artifact.path == null ? join(
-            ...this.artifactMeta.group.split('.'),
-            this.artifactMeta.artifact,
-            this.artifactMeta.version,
-            `${this.artifactMeta.artifact}-${this.artifactMeta.version}${this.artifactMeta.classifier != undefined ? `-${this.artifactMeta.classifier}` : ''}.${this.artifactMeta.extension}`
-        ) : this.module.artifact.path
-
-        switch (this.module.type){
-            case Type.Library:
-            case Type.ForgeHosted:
-            case Type.LiteLoader:
-                this.module.artifact.path = join(ConfigManager.getCommonDirectory(), 'libraries', relativePath)
-                break
-            case Type.ForgeMod:
-            case Type.LiteMod:
-                this.module.artifact.path = join(ConfigManager.getCommonDirectory(), 'modstore', relativePath)
-                break
-            case Type.VersionManifest:
-                this.module.artifact.path = join(ConfigManager.getCommonDirectory(), 'versions', this.module.id, `${this.module.id}.json`)
-                break
-            case Type.File:
-            default:
-                this.module.artifact.path = join(ConfigManager.getInstanceDirectory(), this.serverId, relativePath)
-                break
-        }
-
-    }
-
-    private resolveRequired(): void {
-        if (this.module.required == null) {
-            this.module.required = {
-                value: true,
-                def: true
-            }
-        } else {
-            if (this.module.required.value == null) {
-                this.module.required.value = true
-            }
-            if (this.module.required.def == null) {
-                this.module.required.def = true
-            }
-        }
-    }
-
-    /**
-     * @returns {string} The maven identifier of this module's artifact.
-     */
-    public getArtifact(): string {
-        return this.artifactMeta.artifact
-    }
-
-    /**
-     * @returns {string} The maven group of this module's artifact.
-     */
-    public getGroup(): string {
-        return this.artifactMeta.group
-    }
-
-    /**
-     * @returns {string} The version of this module's artifact.
-     */
-    public getVersion(): string {
-        return this.artifactMeta.version
-    }
-
-    /**
-     * @returns {string | undefined} The classifier of this module's artifact
-     */
-    public getClassifier(): string | undefined {
-        return this.artifactMeta.classifier
-    }
-
-    /**
-     * @returns {string} The extension of this module's artifact.
-     */
-    public getExtension(): string {
-        return this.artifactMeta.extension
-    }
-
-    /**
-     * @returns {string} The identifier without he version or extension.
-     */
-    public getVersionlessID(): string {
-        return this.artifactMeta.group + ':' + this.artifactMeta.artifact
-    }
-
-    /**
-     * @returns {string} The identifier without the extension.
-     */
-    public getExtensionlessID(): string {
-        return this.module.id.split('@')[0]
-    }
-
-    /**
-     * @returns {boolean} Whether or not this module has sub modules.
-     */
-    public hasSubModules(): boolean {
-        return this.module.subModules != null
-    }
-
-    public getWrappedSubmodules(): ModuleWrapper[] {
-        return this.subModules
-    }
-
-}
-
-export class ServerWrapper {
-
-    private modules: ModuleWrapper[] = []
-
-    constructor(public server: Server) {
-        this.server.modules.map(mdl => new ModuleWrapper(mdl, server.id))
-    }
-
-    public getWrappedModules() {
-        return this.modules
-    }
-
-}
-
-export class DistributionWrapper {
-
-    private mainServer: ServerWrapper | null = null
-    private servers: ServerWrapper[]
-
-    constructor(public distro: Distribution) {
-        this.servers = this.distro.servers.map(serv => new ServerWrapper(serv))
-        this.resolveMainServer()
-    }
-
-    private resolveMainServer(): void {
-
-        for(const serv of this.servers){
-            if(serv.server.mainServer){
-                this.mainServer = serv
-                return
-            }
-        }
-
-        // If no server declares default_selected, default to the first one declared.
-        this.mainServer = (this.servers.length > 0) ? this.servers[0] : null
-    }
-    
-    public getServer(id: string): ServerWrapper | null {
-        for(const serv of this.servers){
-            if(serv.server.id === id){
-                return serv
-            }
-        }
-        return null
-    }
-
-    public getMainServer(): ServerWrapper | null {
-        return this.mainServer
-    }
-
-}
-
-
-export class DistroManager {
-
-    private static readonly DISTRO_PATH = join(ConfigManager.getLauncherDirectory(), 'distribution.json')
-    private static readonly DEV_PATH = join(ConfigManager.getLauncherDirectory(), 'dev_distribution.json')
-
-    private static readonly DISTRIBUTION_URL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
-    // private static readonly DISTRIBUTION_URL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/'
-
-    private static DEV_MODE = false
-
-    private static distro: DistributionWrapper
-
-    public static isDevMode() {
-        return DistroManager.DEV_MODE
-    }
-
-    public static setDevMode(value: boolean) {
-        if(value){
-            logger.log('Developer mode enabled.')
-            logger.log('If you don\'t know what that means, revert immediately.')
-        } else {
-            logger.log('Developer mode disabled.')
-        }
-        DistroManager.DEV_MODE = value
-    }
-
-
-    public static pullRemote(): Promise<DistributionWrapper> {
-        if(DistroManager.DEV_MODE){
-            return DistroManager.pullLocal()
-        }
-        return new Promise((resolve, reject) => {
-            const opts = {
-                url: DistroManager.DISTRIBUTION_URL,
-                timeout: 2500
-            }
-            const distroDest = join(ConfigManager.getLauncherDirectory(), 'distribution.json')
-            request(opts, async (error, resp, body) => {
-                if(!error){
-                    
-                    let data: Distribution
-
-                    try {
-                        data = JSON.parse(body) as Distribution
-
-                        DistroManager.distro = new DistributionWrapper(data)
-                    } catch (e) {
-                        reject(e)
-                        return;
-                    }
-
-                    try {
-                        await writeJson(distroDest, DistroManager.distro)
-                        resolve(DistroManager.distro)
-                    } catch (err) {
-                        reject(err)
-                    }
-                    
-                } else {
-                    reject(error)
-                }
-            })
-        })
-    }
-
-    public static async pullLocal(): Promise<DistributionWrapper> {
-        const data = await readJson(DistroManager.DEV_MODE ? DistroManager.DEV_PATH : DistroManager.DISTRO_PATH) as Distribution
-
-        DistroManager.distro = new DistributionWrapper(data)
-
-        return DistroManager.distro
-    }
-
-    public static getDistribution(): DistributionWrapper {
-        return DistroManager.distro
-    }
-
-}
-

+ 0 - 232
src/main/old/dropinmodutil.ts

@@ -1,232 +0,0 @@
-import { ensureDirSync, pathExistsSync, readdirSync, moveSync, readFileSync, writeFileSync, rename } from 'fs-extra'
-import { join } from 'path'
-import { shell } from 'electron'
-
-// Group #1: File Name (without .disabled, if any)
-// Group #2: File Extension (jar, zip, or litemod)
-// Group #3: If it is disabled (if string 'disabled' is present)
-const MOD_REGEX = /^(.+(jar|zip|litemod))(?:\.(disabled))?$/
-const DISABLED_EXT = '.disabled'
-
-const SHADER_REGEX = /^(.+)\.zip$/
-const SHADER_OPTION = /shaderPack=(.+)/
-const SHADER_DIR = 'shaderpacks'
-const SHADER_CONFIG = 'optionsshaders.txt'
-
-/**
- * Validate that the given directory exists. If not, it is
- * created.
- * 
- * @param {string} modsDir The path to the mods directory.
- */
-export function validateDir(dir: string) {
-    ensureDirSync(dir)
-}
-
-/**
- * Scan for drop-in mods in both the mods folder and version
- * safe mods folder.
- * 
- * @param {string} modsDir The path to the mods directory.
- * @param {string} version The minecraft version of the server configuration.
- * 
- * @returns {{fullName: string, name: string, ext: string, disabled: boolean}[]}
- * An array of objects storing metadata about each discovered mod.
- */
-export function scanForDropinMods(modsDir: string, version: string) {
-    const modsDiscovered = []
-    if(pathExistsSync(modsDir)){
-        let modCandidates = readdirSync(modsDir)
-        let verCandidates: string[] = []
-        const versionDir = join(modsDir, version)
-        if(pathExistsSync(versionDir)){
-            verCandidates = readdirSync(versionDir)
-        }
-        for(let file of modCandidates){
-            const match = MOD_REGEX.exec(file)
-            if(match != null){
-                modsDiscovered.push({
-                    fullName: match[0],
-                    name: match[1],
-                    ext: match[2],
-                    disabled: match[3] != null
-                })
-            }
-        }
-        for(let file of verCandidates){
-            const match = MOD_REGEX.exec(file)
-            if(match != null){
-                modsDiscovered.push({
-                    fullName: join(version, match[0]),
-                    name: match[1],
-                    ext: match[2],
-                    disabled: match[3] != null
-                })
-            }
-        }
-    }
-    return modsDiscovered
-}
-
-/**
- * Add dropin mods.
- * 
- * @param {FileList} files The files to add.
- * @param {string} modsDir The path to the mods directory.
- */
-export function addDropinMods(files: any, modsdir: string) {
-
-    exports.validateDir(modsdir)
-
-    for(let f of files) {
-        if(MOD_REGEX.exec(f.name) != null) {
-            moveSync(f.path, join(modsdir, f.name))
-        }
-    }
-
-}
-
-/**
- * Delete a drop-in mod from the file system.
- * 
- * @param {string} modsDir The path to the mods directory.
- * @param {string} fullName The fullName of the discovered mod to delete.
- * 
- * @returns {boolean} True if the mod was deleted, otherwise false.
- */
-export function deleteDropinMod(modsDir: string, fullName: string){
-    const res = shell.moveItemToTrash(join(modsDir, fullName))
-    if(!res){
-        shell.beep()
-    }
-    return res
-}
-
-/**
- * Toggle a discovered mod on or off. This is achieved by either 
- * adding or disabling the .disabled extension to the local file.
- * 
- * @param {string} modsDir The path to the mods directory.
- * @param {string} fullName The fullName of the discovered mod to toggle.
- * @param {boolean} enable Whether to toggle on or off the mod.
- * 
- * @returns {Promise.<void>} A promise which resolves when the mod has
- * been toggled. If an IO error occurs the promise will be rejected.
- */
-export function toggleDropinMod(modsDir: string, fullName: string, enable: boolean){
-    return new Promise((resolve, reject) => {
-        const oldPath = join(modsDir, fullName)
-        const newPath = join(modsDir, enable ? fullName.substring(0, fullName.indexOf(DISABLED_EXT)) : fullName + DISABLED_EXT)
-
-        rename(oldPath, newPath, (err) => {
-            if(err){
-                reject(err)
-            } else {
-                resolve()
-            }
-        })
-    })
-}
-
-/**
- * Check if a drop-in mod is enabled.
- * 
- * @param {string} fullName The fullName of the discovered mod to toggle.
- * @returns {boolean} True if the mod is enabled, otherwise false.
- */
-export function isDropinModEnabled(fullName: string){
-    return !fullName.endsWith(DISABLED_EXT)
-}
-
-/**
- * Scan for shaderpacks inside the shaderpacks folder.
- * 
- * @param {string} instanceDir The path to the server instance directory.
- * 
- * @returns {{fullName: string, name: string}[]}
- * An array of objects storing metadata about each discovered shaderpack.
- */
-export function scanForShaderpacks(instanceDir: string){
-    const shaderDir = join(instanceDir, SHADER_DIR)
-    const packsDiscovered = [{
-        fullName: 'OFF',
-        name: 'Off (Default)'
-    }]
-    if(pathExistsSync(shaderDir)){
-        let modCandidates = readdirSync(shaderDir)
-        for(let file of modCandidates){
-            const match = SHADER_REGEX.exec(file)
-            if(match != null){
-                packsDiscovered.push({
-                    fullName: match[0],
-                    name: match[1]
-                })
-            }
-        }
-    }
-    return packsDiscovered
-}
-
-/**
- * Read the optionsshaders.txt file to locate the current
- * enabled pack. If the file does not exist, OFF is returned.
- * 
- * @param {string} instanceDir The path to the server instance directory.
- * 
- * @returns {string} The file name of the enabled shaderpack.
- */
-export function getEnabledShaderpack(instanceDir: string){
-    validateDir(instanceDir)
-
-    const optionsShaders = join(instanceDir, SHADER_CONFIG)
-    if(pathExistsSync(optionsShaders)){
-        const buf = readFileSync(optionsShaders, {encoding: 'utf-8'})
-        const match = SHADER_OPTION.exec(buf)
-        if(match != null){
-            return match[1]
-        } else {
-            console.warn('WARNING: Shaderpack regex failed.')
-        }
-    }
-    return 'OFF'
-}
-
-/**
- * Set the enabled shaderpack.
- * 
- * @param {string} instanceDir The path to the server instance directory.
- * @param {string} pack the file name of the shaderpack.
- */
-export function setEnabledShaderpack(instanceDir: string, pack: string){
-    validateDir(instanceDir)
-
-    const optionsShaders = join(instanceDir, SHADER_CONFIG)
-    let buf
-    if(pathExistsSync(optionsShaders)){
-        buf = readFileSync(optionsShaders, {encoding: 'utf-8'})
-        buf = buf.replace(SHADER_OPTION, `shaderPack=${pack}`)
-    } else {
-        buf = `shaderPack=${pack}`
-    }
-    writeFileSync(optionsShaders, buf, {encoding: 'utf-8'})
-}
-
-/**
- * Add shaderpacks.
- * 
- * @param {FileList} files The files to add.
- * @param {string} instanceDir The path to the server instance directory.
- */
-export function addShaderpacks(files: any, instanceDir: string) {
-
-    const p = join(instanceDir, SHADER_DIR)
-
-    exports.validateDir(p)
-
-    for(let f of files) {
-        if(SHADER_REGEX.exec(f.name) != null) {
-            moveSync(f.path, join(p, f.name))
-        }
-    }
-
-}

+ 0 - 23
src/main/old/langloader.ts

@@ -1,23 +0,0 @@
-import { readJSONSync } from 'fs-extra'
-import { join } from 'path'
-
-// TODO revisit
-
-let lang: any
-
-export function loadLanguage(id: string){
-    lang = readJSONSync(join(__dirname, '..', 'assets', 'lang', `${id}.json`)) || {}
-}
-
-export function query(id: string){
-    let query = id.split('.')
-    let res = lang
-    for(let q of query){
-        res = res[q]
-    }
-    return res === lang ? {} : res
-}
-
-export function queryJS(id: string){
-    return exports.query(`js.${id}`)
-}

+ 0 - 28
src/main/old/loggerutil.ts

@@ -1,28 +0,0 @@
-export class LoggerUtil {
-
-    constructor(
-        protected prefix: string,
-        protected style: string
-    ){}
-
-    public log(...args: any[]){
-        console.log(this.prefix, this.style, ...args)
-    }
-
-    public info(...args: any[]){
-        console.info(this.prefix, this.style, ...args)
-    }
-
-    public warn(...args: any[]){
-        console.warn(this.prefix, this.style, ...args)
-    }
-
-    public debug(...args: any[]){
-        console.debug(this.prefix, this.style, ...args)
-    }
-
-    public error(...args: any[]){
-        console.error(this.prefix, this.style, ...args)
-    }
-
-}

+ 0 - 71
src/main/old/preloader.ts

@@ -1,71 +0,0 @@
-import { ConfigManager } from '../../common/config/configmanager'
-import { DistroManager, DistributionWrapper } from './distromanager'
-import { join } from 'path'
-import { remove } from 'fs-extra'
-import { loadLanguage } from './langloader'
-import { LoggerUtil } from './loggerutil'
-import { tmpdir } from 'os'
-import { ipcRenderer } from 'electron'
-
-const logger        = new LoggerUtil('%c[Preloader]', 'color: #a02d2a; font-weight: bold')
-
-logger.log('Loading..')
-
-// Load ConfigManager
-ConfigManager.load()
-
-// Load Strings
-loadLanguage('en_US')
-
-function onDistroLoad(data: DistributionWrapper | null){
-    if(data != null){
-        
-        // Resolve the selected server if its value has yet to be set.
-        if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()!) == null){
-            logger.log('Determining default selected server..')
-            // TODO what if undefined
-            ConfigManager.setSelectedServer(data.getMainServer()!.server.id as string)
-            ConfigManager.save()
-        }
-    }
-    ipcRenderer.send('distributionIndexDone', data != null)
-}
-
-// Ensure Distribution is downloaded and cached.
-DistroManager.pullRemote().then((data) => {
-    logger.log('Loaded distribution index.')
-
-    onDistroLoad(data)
-
-}).catch((err) => {
-    logger.log('Failed to load distribution index.')
-    logger.error(err)
-
-    logger.log('Attempting to load an older version of the distribution index.')
-    // Try getting a local copy, better than nothing.
-    DistroManager.pullLocal().then((data) => {
-        logger.log('Successfully loaded an older version of the distribution index.')
-
-        onDistroLoad(data)
-
-
-    }).catch((err) => {
-
-        logger.log('Failed to load an older version of the distribution index.')
-        logger.log('Application cannot run.')
-        logger.error(err)
-
-        onDistroLoad(null)
-
-    })
-
-})
-
-// Clean up temp dir incase previous launches ended unexpectedly. 
-remove(join(tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
-    if(err){
-        logger.warn('Error while cleaning natives directory', err)
-    } else {
-        logger.log('Cleaned natives directory.')
-    }
-})

+ 0 - 755
src/main/old/processbuilder.ts

@@ -1,755 +0,0 @@
-import AdmZip from 'adm-zip'
-import { pathExistsSync, writeFile, ensureDirSync, writeFileSync, remove } from 'fs-extra'
-import { join, basename } from 'path'
-import { ModuleWrapper, ServerWrapper } from './distromanager'
-import { Type, Required } from 'helios-distribution-types'
-import { LoggerUtil } from './loggerutil'
-import { ConfigManager } from '../../common/config/configmanager'
-import { spawn } from 'child_process'
-import { SavedAccount } from '../../common/config/model/SavedAccount'
-import { tmpdir, release } from 'os'
-import { SubModConfig } from '../../common/config/model/ModConfig'
-import { pseudoRandomBytes } from 'crypto'
-import { Util, LibraryInternal } from './assetguard'
-import { VersionJson, Rule } from '../asset/model/mojang/VersionJson'
-import { URL } from 'url'
-
-const logger = new LoggerUtil('%c[ProcessBuilder]', 'color: #003996; font-weight: bold')
-
-export class ProcessBuilder {
-
-    private gameDir: string
-    private commonDir: string
-    private fmlDir: string
-    private llDir: string
-    private libPath: string
-    
-    private usingLiteLoader: boolean
-    private llPath: string | null
-
-    constructor(
-        private wrappedServer: ServerWrapper,
-        private versionData: VersionJson,
-        private forgeData: any, // TODO type
-        private authUser: SavedAccount,
-        private launcherVersion: string
-    ){
-        this.gameDir = join(ConfigManager.getInstanceDirectory(), wrappedServer.server.id)
-        this.commonDir = ConfigManager.getCommonDirectory()
-        this.authUser = authUser
-        this.launcherVersion = launcherVersion
-        this.fmlDir = join(this.gameDir, 'forgeModList.json')
-        this.llDir = join(this.gameDir, 'liteloaderModList.json')
-        this.libPath = join(this.commonDir, 'libraries')
-
-        this.usingLiteLoader = false
-        this.llPath = null
-    }
-    
-    /**
-     * Convienence method to run the functions typically used to build a process.
-     */
-    build(){
-        ensureDirSync(this.gameDir)
-        const tempNativePath = join(tmpdir(), ConfigManager.getTempNativeFolder(), pseudoRandomBytes(16).toString('hex'))
-        process.throwDeprecation = true
-        this.setupLiteLoader()
-        logger.log('Using liteloader:', this.usingLiteLoader)
-        const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.wrappedServer.server.id)!.mods, this.wrappedServer.getWrappedModules())
-        
-        // Mod list below 1.13
-        if(!Util.mcVersionAtLeast('1.13', this.wrappedServer.server.minecraftVersion)){
-            this.constructModList('forge', modObj.fMods, true)
-            if(this.usingLiteLoader){
-                this.constructModList('liteloader', modObj.lMods, true)
-            }
-        }
-        
-        const uberModArr = modObj.fMods.concat(modObj.lMods)
-        let args = this.constructJVMArguments(uberModArr, tempNativePath)
-
-        if(Util.mcVersionAtLeast('1.13', this.wrappedServer.server.minecraftVersion)){
-            args = args.concat(this.constructModArguments(modObj.fMods))
-        }
-
-        logger.log('Launch Arguments:', args)
-
-        const child = spawn(ConfigManager.getJavaExecutable()!, args, {
-            cwd: this.gameDir,
-            detached: ConfigManager.getLaunchDetached()
-        })
-
-        if(ConfigManager.getLaunchDetached()){
-            child.unref()
-        }
-
-        child.stdout.setEncoding('utf8')
-        child.stderr.setEncoding('utf8')
-
-        const loggerMCstdout = new LoggerUtil('%c[Minecraft]', 'color: #36b030; font-weight: bold')
-        const loggerMCstderr = new LoggerUtil('%c[Minecraft]', 'color: #b03030; font-weight: bold')
-
-        child.stdout.on('data', (data) => {
-            loggerMCstdout.log(data)
-        })
-        child.stderr.on('data', (data) => {
-            loggerMCstderr.log(data)
-        })
-        child.on('close', (code, signal) => {
-            logger.log('Exited with code', code)
-            remove(tempNativePath, (err) => {
-                if(err){
-                    logger.warn('Error while deleting temp dir', err)
-                } else {
-                    logger.log('Temp dir deleted successfully.')
-                }
-            })
-        })
-
-        return child
-    }
-
-    /**
-     * Determine if an optional mod is enabled from its configuration value. If the
-     * configuration value is null, the required object will be used to
-     * determine if it is enabled.
-     * 
-     * A mod is enabled if:
-     *   * The configuration is not null and one of the following:
-     *     * The configuration is a boolean and true.
-     *     * The configuration is an object and its 'value' property is true.
-     *   * The configuration is null and one of the following:
-     *     * The required object is null.
-     *     * The required object's 'def' property is null or true.
-     * 
-     * @param {SubModConfig | boolean} modCfg The mod configuration object.
-     * @param {Required | undefined} required Optional. The required object from the mod's distro declaration.
-     * @returns {boolean} True if the mod is enabled, false otherwise.
-     */
-    public static isModEnabled(modCfg: SubModConfig | boolean, required?: Required){
-        return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.def : true
-    }
-
-    /**
-     * Function which performs a preliminary scan of the top level
-     * mods. If liteloader is present here, we setup the special liteloader
-     * launch options. Note that liteloader is only allowed as a top level
-     * mod. It must not be declared as a submodule.
-     */
-    private setupLiteLoader(): void {
-        for(const ll of this.wrappedServer.getWrappedModules()){
-            if(ll.module.type === Type.LiteLoader){
-                if(!ll.module.required!.value!){
-                    const modCfg = ConfigManager.getModConfiguration(this.wrappedServer.server.id)!.mods
-                    if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessID()], ll.module.required)){
-                        if(pathExistsSync(ll.module.artifact.path!)){
-                            this.usingLiteLoader = true
-                            this.llPath = ll.module.artifact.path!
-                        }
-                    }
-                } else {
-                    if(pathExistsSync(ll.module.artifact.path!)){
-                        this.usingLiteLoader = true
-                        this.llPath = ll.module.artifact.path!
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Resolve an array of all enabled mods. These mods will be constructed into
-     * a mod list format and enabled at launch.
-     * 
-     * @param {{[id: string]: boolean | SubModConfig}} modCfg The mod configuration object.
-     * @param {Array.<ModuleWrapper>} mdls An array of modules to parse.
-     * @returns {{fMods: Array.<ModuleWrapper>, lMods: Array.<ModuleWrapper>}} An object which contains
-     * a list of enabled forge mods and litemods.
-     */
-    resolveModConfiguration(modCfg: {[id: string]: boolean | SubModConfig}, mdls: ModuleWrapper[]): {fMods: ModuleWrapper[], lMods: ModuleWrapper[]}{
-        let fMods: ModuleWrapper[] = []
-        let lMods: ModuleWrapper[] = []
-
-        for(const mdl of mdls){
-            const type = mdl.module.type
-            if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
-                const o = !mdl.module.required!.value!
-                const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessID()], mdl.module.required)
-                if(!o || (o && e)){
-                    if(mdl.hasSubModules()){
-                        const v = this.resolveModConfiguration((modCfg[mdl.getVersionlessID()] as SubModConfig).mods, mdl.getWrappedSubmodules())
-                        fMods = fMods.concat(v.fMods)
-                        lMods = lMods.concat(v.lMods)
-                        if(mdl.module.type === Type.LiteLoader){
-                            continue
-                        }
-                    }
-                    if(mdl.module.type === Type.ForgeMod){
-                        fMods.push(mdl)
-                    } else {
-                        lMods.push(mdl)
-                    }
-                }
-            }
-        }
-
-        return {
-            fMods,
-            lMods
-        }
-    }
-
-    _isBelowOneDotSeven() {
-        return Number(this.forgeData.id.split('-')[0].split('.')[1]) <= 7
-    }
-
-    /**
-     * Test to see if this version of forge requires the absolute: prefix
-     * on the modListFile repository field.
-     */
-    _requiresAbsolute(){
-        try {
-            if(this._isBelowOneDotSeven()) {
-                return false
-            }
-            const ver = this.forgeData.id.split('-')[2]
-            const pts = ver.split('.')
-            const min = [14, 23, 3, 2655]
-            for(let i=0; i<pts.length; i++){
-                const parsed = Number.parseInt(pts[i])
-                if(parsed < min[i]){
-                    return false
-                } else if(parsed > min[i]){
-                    return true
-                }
-            }
-        } catch (err) {
-            // We know old forge versions follow this format.
-            // Error must be caused by newer version.
-        }
-        
-        // Equal or errored
-        return true
-    }
-
-    /**
-     * Construct a mod list json object.
-     * 
-     * @param {'forge' | 'liteloader'} type The mod list type to construct.
-     * @param {Array.<ModuleWrapper>} mods An array of mods to add to the mod list.
-     * @param {boolean} save Optional. Whether or not we should save the mod list file.
-     */
-    constructModList(type: 'forge' | 'liteloader', mods: ModuleWrapper[], save = false){
-        const modList = {
-            repositoryRoot: ((type === 'forge' && this._requiresAbsolute()) ? 'absolute:' : '') + join(this.commonDir, 'modstore'),
-            modRef: [] as string[]
-        }
-
-        const ids = []
-        if(type === 'forge'){
-            for(let mod of mods){
-                ids.push(mod.getExtensionlessID())
-            }
-        } else {
-            for(let mod of mods){
-                ids.push(mod.getExtensionlessID() + '@' + mod.getExtension())
-            }
-        }
-        modList.modRef = ids
-        
-        if(save){
-            const json = JSON.stringify(modList, null, 4)
-            writeFileSync(type === 'forge' ? this.fmlDir : this.llDir, json, 'UTF-8')
-        }
-
-        return modList
-    }
-
-    /**
-     * Construct the mod argument list for forge 1.13
-     * 
-     * @param {Array.<ModuleWrapper>} mods An array of mods to add to the mod list.
-     */
-    constructModArguments(mods: ModuleWrapper[]){
-        const argStr = mods.map(mod => {
-            return mod.getExtensionlessID()
-        }).join(',')
-
-        if(argStr){
-            return [
-                '--fml.mavenRoots',
-                join('..', '..', 'common', 'modstore'),
-                '--fml.mods',
-                argStr
-            ]
-        } else {
-            return []
-        }
-        
-    }
-
-    /**
-     * Construct the argument array that will be passed to the JVM process.
-     * 
-     * @param {Array.<ModuleWrapper>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string| number>} An array containing the full JVM arguments for this process.
-     */
-    constructJVMArguments(mods: ModuleWrapper[], tempNativePath: string): string[] {
-        if(Util.mcVersionAtLeast('1.13', this.wrappedServer.server.minecraftVersion)){
-            return this._constructJVMArguments113(mods, tempNativePath)
-        } else {
-            return this._constructJVMArguments112(mods, tempNativePath)
-        }
-    }
-
-    /**
-     * Construct the argument array that will be passed to the JVM process.
-     * This function is for 1.12 and below.
-     * 
-     * @param {Array.<ModuleWrapper>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the full JVM arguments for this process.
-     */
-    _constructJVMArguments112(mods: ModuleWrapper[], tempNativePath: string): string[] {
-
-        let args = []
-
-        // Classpath Argument
-        args.push('-cp')
-        args.push(this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':'))
-
-        // Java Arguments
-        if(process.platform === 'darwin'){
-            args.push('-Xdock:name=HeliosLauncher')
-            args.push('-Xdock:icon=' + join(__dirname, '..', 'images', 'minecraft.icns'))
-        }
-        args.push('-Xmx' + ConfigManager.getMaxRAM())
-        args.push('-Xms' + ConfigManager.getMinRAM())
-        args = args.concat(ConfigManager.getJVMOptions())
-        args.push('-Djava.library.path=' + tempNativePath)
-
-        // Main Java Class
-        args.push(this.forgeData.mainClass)
-
-        // Forge Arguments
-        args = args.concat(this._resolveForgeArgs())
-
-        return args
-    }
-
-    /**
-     * Construct the argument array that will be passed to the JVM process.
-     * This function is for 1.13+
-     * 
-     * Note: Required Libs https://github.com/MinecraftForge/MinecraftForge/blob/af98088d04186452cb364280340124dfd4766a5c/src/fmllauncher/java/net/minecraftforge/fml/loading/LibraryFinder.java#L82
-     * 
-     * @param {Array.<ModuleWrapper>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the full JVM arguments for this process.
-     */
-    _constructJVMArguments113(mods: ModuleWrapper[], tempNativePath: string): string[] {
-
-        const argDiscovery = /\${*(.*)}/
-
-        // JVM Arguments First
-        let args: (string | { rules: Rule[], value: string[] })[] = this.versionData.arguments.jvm
-
-        //args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
-
-        // Java Arguments
-        if(process.platform === 'darwin'){
-            args.push('-Xdock:name=HeliosLauncher')
-            args.push('-Xdock:icon=' + join(__dirname, '..', 'images', 'minecraft.icns'))
-        }
-        args.push('-Xmx' + ConfigManager.getMaxRAM())
-        args.push('-Xms' + ConfigManager.getMinRAM())
-        args = args.concat(ConfigManager.getJVMOptions())
-
-        // Main Java Class
-        args.push(this.forgeData.mainClass)
-
-        // Vanilla Arguments
-        args = args.concat(this.versionData.arguments.game)
-
-        for(let i=0; i<args.length; i++){
-            if(typeof args[i] === 'object' && (args[i] as any).rules != null){
-                const arg = args[i] as { rules: Rule[], value: string[] }
-                
-                let checksum = 0
-                for(let rule of arg.rules){
-                    if(rule.os != null){
-                        if(rule.os.name === LibraryInternal.mojangFriendlyOS()
-                            && (rule.os.version == null || new RegExp(rule.os.version).test(release()))){
-                            if(rule.action === 'allow'){
-                                checksum++
-                            }
-                        } else {
-                            if(rule.action === 'disallow'){
-                                checksum++
-                            }
-                        }
-                    } else if(rule.features != null){
-                        // We don't have many 'features' in the index at the moment.
-                        // This should be fine for a while.
-                        if(rule.features.has_custom_resolution != null && rule.features.has_custom_resolution === true){
-                            if(ConfigManager.getFullscreen()){
-                                arg.value = [
-                                    '--fullscreen',
-                                    'true'
-                                ]
-                            }
-                            checksum++
-                        }
-                    }
-                }
-
-                // TODO splice not push
-                if(checksum === arg.rules.length){
-                    if(typeof arg.value === 'string'){
-                        args[i] = arg.value
-                    } else if(typeof arg.value === 'object'){
-                        //args = args.concat(args[i].value)
-                        args.splice(i, 1, ...arg.value)
-                    }
-
-                    // Decrement i to reprocess the resolved value
-                    i--
-                } else {
-                    args[i] = null! // TODO lol
-                }
-
-            } else if(typeof args[i] === 'string'){
-                const arg = args[i] as string
-                if(argDiscovery.test(arg)){
-                    const identifier = arg.match(argDiscovery)![1]
-                    let val = null
-                    switch(identifier){
-                        case 'auth_player_name':
-                            val = this.authUser.displayName.trim()
-                            break
-                        case 'version_name':
-                            //val = versionData.id
-                            val = this.wrappedServer.server.id
-                            break
-                        case 'game_directory':
-                            val = this.gameDir
-                            break
-                        case 'assets_root':
-                            val = join(this.commonDir, 'assets')
-                            break
-                        case 'assets_index_name':
-                            val = this.versionData.assets
-                            break
-                        case 'auth_uuid':
-                            val = this.authUser.uuid.trim()
-                            break
-                        case 'auth_access_token':
-                            val = this.authUser.accessToken
-                            break
-                        case 'user_type':
-                            val = 'mojang'
-                            break
-                        case 'version_type':
-                            val = this.versionData.type
-                            break
-                        case 'resolution_width':
-                            val = ConfigManager.getGameWidth()
-                            break
-                        case 'resolution_height':
-                            val = ConfigManager.getGameHeight()
-                            break
-                        case 'natives_directory':
-                            val = arg.replace(argDiscovery, tempNativePath)
-                            break
-                        case 'launcher_name':
-                            val = arg.replace(argDiscovery, 'Helios-Launcher')
-                            break
-                        case 'launcher_version':
-                            val = arg.replace(argDiscovery, this.launcherVersion)
-                            break
-                        case 'classpath':
-                            val = this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':')
-                            break
-                    }
-                    if(val != null){
-                        args[i] = val.toString()
-                    }
-                }
-            }
-        }
-
-        // Forge Specific Arguments
-        args = args.concat(this.forgeData.arguments.game)
-
-        // Filter null values
-        args = args.filter(arg => {
-            return arg != null
-        })
-
-        return args as string[]
-    }
-
-    /**
-     * Resolve the arguments required by forge.
-     * 
-     * @returns {Array.<string>} An array containing the arguments required by forge.
-     */
-    _resolveForgeArgs(): string[] {
-        const mcArgs: string[] = this.forgeData.minecraftArguments.split(' ')
-        const argDiscovery = /\${*(.*)}/
-
-        // Replace the declared variables with their proper values.
-        for(let i=0; i<mcArgs.length; ++i){
-            if(argDiscovery.test(mcArgs[i])){
-                const identifier = mcArgs[i].match(argDiscovery)![1]
-                let val = null
-                switch(identifier){
-                    case 'auth_player_name':
-                        val = this.authUser.displayName.trim()
-                        break
-                    case 'version_name':
-                        //val = versionData.id
-                        val = this.wrappedServer.server.id
-                        break
-                    case 'game_directory':
-                        val = this.gameDir
-                        break
-                    case 'assets_root':
-                        val = join(this.commonDir, 'assets')
-                        break
-                    case 'assets_index_name':
-                        val = this.versionData.assets
-                        break
-                    case 'auth_uuid':
-                        val = this.authUser.uuid.trim()
-                        break
-                    case 'auth_access_token':
-                        val = this.authUser.accessToken
-                        break
-                    case 'user_type':
-                        val = 'mojang'
-                        break
-                    case 'user_properties': // 1.8.9 and below.
-                        val = '{}'
-                        break
-                    case 'version_type':
-                        val = this.versionData.type
-                        break
-                }
-                if(val != null){
-                    mcArgs[i] = val
-                }
-            }
-        }
-
-        // Autoconnect to the selected server.
-        if(ConfigManager.getAutoConnect() && this.wrappedServer.server.autoconnect){
-            const serverURL = new URL('my://' + this.wrappedServer.server.address)
-            mcArgs.push('--server')
-            mcArgs.push(serverURL.hostname)
-            if(serverURL.port){
-                mcArgs.push('--port')
-                mcArgs.push(serverURL.port)
-            }
-        }
-
-        // Prepare game resolution
-        if(ConfigManager.getFullscreen()){
-            mcArgs.push('--fullscreen')
-            mcArgs.push('true')
-        } else {
-            mcArgs.push('--width')
-            mcArgs.push(ConfigManager.getGameWidth().toString())
-            mcArgs.push('--height')
-            mcArgs.push(ConfigManager.getGameHeight().toString())
-        }
-        
-        // Mod List File Argument
-        mcArgs.push('--modListFile')
-        if(this._isBelowOneDotSeven()) {
-            mcArgs.push(basename(this.fmlDir))
-        } else {
-            mcArgs.push('absolute:' + this.fmlDir)
-        }
-        
-
-        // LiteLoader
-        if(this.usingLiteLoader){
-            mcArgs.push('--modRepo')
-            mcArgs.push(this.llDir)
-
-            // Set first arg to liteloader tweak class
-            mcArgs.unshift('com.mumfrey.liteloader.launch.LiteLoaderTweaker')
-            mcArgs.unshift('--tweakClass')
-        }
-
-        return mcArgs
-    }
-
-    /**
-     * Resolve the full classpath argument list for this process. This method will resolve all Mojang-declared
-     * libraries as well as the libraries declared by the server. Since mods are permitted to declare libraries,
-     * this method requires all enabled mods as an input
-     * 
-     * @param {Array.<ModuleWrapper>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the paths of each library required by this process.
-     */
-    classpathArg(mods: ModuleWrapper[], tempNativePath: string): string[] {
-        let cpArgs: string[] = []
-
-        // Add the version.jar to the classpath.
-        const version = this.versionData.id
-        cpArgs.push(join(this.commonDir, 'versions', version, version + '.jar'))
-
-        if(this.usingLiteLoader){
-            cpArgs.push(this.llPath!)
-        }
-
-        // Resolve the Mojang declared libraries.
-        const mojangLibs = this._resolveMojangLibraries(tempNativePath)
-
-        // Resolve the server declared libraries.
-        const servLibs = this._resolveServerLibraries(mods)
-
-        // Merge libraries, server libs with the same
-        // maven identifier will override the mojang ones.
-        // Ex. 1.7.10 forge overrides mojang's guava with newer version.
-        const finalLibs = {...mojangLibs, ...servLibs}
-        cpArgs = cpArgs.concat(Object.values(finalLibs))
-
-        return cpArgs
-    }
-
-    /**
-     * Resolve the libraries defined by Mojang's version data. This method will also extract
-     * native libraries and point to the correct location for its classpath.
-     * 
-     * TODO - clean up function
-     * 
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {{[id: string]: string}} An object containing the paths of each library mojang declares.
-     */
-    _resolveMojangLibraries(tempNativePath: string): {[id: string]: string} {
-        const libs: {[id: string]: string} = {}
-
-        const libArr = this.versionData.libraries
-        ensureDirSync(tempNativePath)
-        for(let i=0; i<libArr.length; i++){
-            const lib = libArr[i]
-            if(LibraryInternal.validateRules(lib.rules, lib.natives)){
-                if(lib.natives == null){
-                    const dlInfo = lib.downloads
-                    const artifact = dlInfo.artifact
-                    const to = join(this.libPath, artifact.path)
-                    const versionIndependentId: string = lib.name.substring(0, lib.name.lastIndexOf(':'))
-                    libs[versionIndependentId] = to
-                } else {
-                    // Extract the native library.
-                    const exclusionArr: string[] = lib.extract != null ? lib.extract.exclude : ['META-INF/']
-                    // @ts-ignore
-                    const artifact = lib.downloads.classifiers[lib.natives[LibraryInternal.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))]
-    
-                    // Location of native zip.
-                    const to = join(this.libPath, artifact.path)
-    
-                    let zip = new AdmZip(to)
-                    let zipEntries = zip.getEntries()
-    
-                    // Unzip the native zip.
-                    for(let i=0; i<zipEntries.length; i++){
-                        const fileName = zipEntries[i].entryName
-    
-                        let shouldExclude = false
-
-                        // Exclude noted files.
-                        exclusionArr.forEach((exclusion: string) => {
-                            if(fileName.indexOf(exclusion) > -1){
-                                shouldExclude = true
-                            }
-                        })
-
-                        // Extract the file.
-                        if(!shouldExclude){
-                            writeFile(join(tempNativePath, fileName), zipEntries[i].getData(), (err) => {
-                                if(err){
-                                    logger.error('Error while extracting native library:', err)
-                                }
-                            })
-                        }
-    
-                    }
-                }
-            }
-        }
-
-        return libs
-    }
-
-    /**
-     * Resolve the libraries declared by this server in order to add them to the classpath.
-     * This method will also check each enabled mod for libraries, as mods are permitted to
-     * declare libraries.
-     * 
-     * @param {Array.<ModuleWrapper>} mods An array of enabled mods which will be launched with this process.
-     * @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
-     */
-    _resolveServerLibraries(mods: ModuleWrapper[]): {[id: string]: string} {
-        const mdls: ModuleWrapper[] = this.wrappedServer.getWrappedModules()
-        let libs: {[id: string]: string} = {}
-
-        // Locate Forge/Libraries
-        for(let mdl of mdls){
-            const type = mdl.module.type
-            if(type === Type.ForgeHosted || type === Type.Library){
-                libs[mdl.getVersionlessID()] = mdl.module.artifact.path as string
-                if(mdl.hasSubModules()){
-                    const res = this._resolveModuleLibraries(mdl)
-                    if(Object.keys(res).length > 0){
-                        libs = {...libs, ...res}
-                    }
-                }
-            }
-        }
-
-        //Check for any libraries in our mod list.
-        for(let i=0; i<mods.length; i++){
-            if(mods[i].hasSubModules()){
-                const res = this._resolveModuleLibraries(mods[i])
-                if(Object.keys(res).length > 0){
-                    libs = {...libs, ...res}
-                }
-            }
-        }
-
-        return libs
-    }
-
-    /**
-     * Recursively resolve the path of each library required by this module.
-     * 
-     * @param {ModuleWrapper} mdl A module object from the server distro index.
-     * @returns {Array.<string>} An array containing the paths of each library this module requires.
-     */
-    _resolveModuleLibraries(mdl: ModuleWrapper): {[id: string]: string} {
-        if(!mdl.hasSubModules()){
-            return {}
-        }
-        let libs: {[id: string]: string} = {}
-        for(const sm of mdl.getWrappedSubmodules()){
-            if(sm.module.type === Type.Library){
-                libs[sm.getVersionlessID()] = sm.module.artifact.path as string
-            }
-            // If this module has submodules, we need to resolve the libraries for those.
-            // To avoid unnecessary recursive calls, base case is checked here.
-            if(mdl.hasSubModules()){
-                const res = this._resolveModuleLibraries(sm)
-                if(Object.keys(res).length > 0){
-                    libs = {...libs, ...res}
-                }
-            }
-        }
-        return libs
-    }
-}

+ 0 - 738
src/main/old/processbuilderold.js

@@ -1,738 +0,0 @@
-const AdmZip                = require('adm-zip')
-const child_process         = require('child_process')
-const crypto                = require('crypto')
-const fs                    = require('fs-extra')
-const os                    = require('os')
-const path                  = require('path')
-const { URL }               = require('url')
-
-const { Util, Library: LibraryInternal }  = require('./assetguard')
-const ConfigManager            = require('./configmanager')
-const DistroManager            = require('./distromanager')
-const LoggerUtil               = require('./loggerutil')
-
-const logger = LoggerUtil('%c[ProcessBuilder]', 'color: #003996; font-weight: bold')
-
-class ProcessBuilder {
-
-    constructor(distroServer, versionData, forgeData, authUser, launcherVersion){
-        this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.getID())
-        this.commonDir = ConfigManager.getCommonDirectory()
-        this.server = distroServer
-        this.versionData = versionData
-        this.forgeData = forgeData
-        this.authUser = authUser
-        this.launcherVersion = launcherVersion
-        this.fmlDir = path.join(this.gameDir, 'forgeModList.json')
-        this.llDir = path.join(this.gameDir, 'liteloaderModList.json')
-        this.libPath = path.join(this.commonDir, 'libraries')
-
-        this.usingLiteLoader = false
-        this.llPath = null
-    }
-    
-    /**
-     * Convienence method to run the functions typically used to build a process.
-     */
-    build(){
-        fs.ensureDirSync(this.gameDir)
-        const tempNativePath = path.join(os.tmpdir(), ConfigManager.getTempNativeFolder(), crypto.pseudoRandomBytes(16).toString('hex'))
-        process.throwDeprecation = true
-        this.setupLiteLoader()
-        logger.log('Using liteloader:', this.usingLiteLoader)
-        const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.getID()).mods, this.server.getModules())
-        
-        // Mod list below 1.13
-        if(!Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
-            this.constructModList('forge', modObj.fMods, true)
-            if(this.usingLiteLoader){
-                this.constructModList('liteloader', modObj.lMods, true)
-            }
-        }
-        
-        const uberModArr = modObj.fMods.concat(modObj.lMods)
-        let args = this.constructJVMArguments(uberModArr, tempNativePath)
-
-        if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
-            args = args.concat(this.constructModArguments(modObj.fMods))
-        }
-
-        logger.log('Launch Arguments:', args)
-
-        const child = child_process.spawn(ConfigManager.getJavaExecutable(), args, {
-            cwd: this.gameDir,
-            detached: ConfigManager.getLaunchDetached()
-        })
-
-        if(ConfigManager.getLaunchDetached()){
-            child.unref()
-        }
-
-        child.stdout.setEncoding('utf8')
-        child.stderr.setEncoding('utf8')
-
-        const loggerMCstdout = LoggerUtil('%c[Minecraft]', 'color: #36b030; font-weight: bold')
-        const loggerMCstderr = LoggerUtil('%c[Minecraft]', 'color: #b03030; font-weight: bold')
-
-        child.stdout.on('data', (data) => {
-            loggerMCstdout.log(data)
-        })
-        child.stderr.on('data', (data) => {
-            loggerMCstderr.log(data)
-        })
-        child.on('close', (code, signal) => {
-            logger.log('Exited with code', code)
-            fs.remove(tempNativePath, (err) => {
-                if(err){
-                    logger.warn('Error while deleting temp dir', err)
-                } else {
-                    logger.log('Temp dir deleted successfully.')
-                }
-            })
-        })
-
-        return child
-    }
-
-    /**
-     * Determine if an optional mod is enabled from its configuration value. If the
-     * configuration value is null, the required object will be used to
-     * determine if it is enabled.
-     * 
-     * A mod is enabled if:
-     *   * The configuration is not null and one of the following:
-     *     * The configuration is a boolean and true.
-     *     * The configuration is an object and its 'value' property is true.
-     *   * The configuration is null and one of the following:
-     *     * The required object is null.
-     *     * The required object's 'def' property is null or true.
-     * 
-     * @param {Object | boolean} modCfg The mod configuration object.
-     * @param {Object} required Optional. The required object from the mod's distro declaration.
-     * @returns {boolean} True if the mod is enabled, false otherwise.
-     */
-    static isModEnabled(modCfg, required = null){
-        return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.isDefault() : true
-    }
-
-    /**
-     * Function which performs a preliminary scan of the top level
-     * mods. If liteloader is present here, we setup the special liteloader
-     * launch options. Note that liteloader is only allowed as a top level
-     * mod. It must not be declared as a submodule.
-     */
-    setupLiteLoader(){
-        for(let ll of this.server.getModules()){
-            if(ll.getType() === DistroManager.Types.LiteLoader){
-                if(!ll.getRequired().isRequired()){
-                    const modCfg = ConfigManager.getModConfiguration(this.server.getID()).mods
-                    if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessID()], ll.getRequired())){
-                        if(fs.existsSync(ll.getArtifact().getPath())){
-                            this.usingLiteLoader = true
-                            this.llPath = ll.getArtifact().getPath()
-                        }
-                    }
-                } else {
-                    if(fs.existsSync(ll.getArtifact().getPath())){
-                        this.usingLiteLoader = true
-                        this.llPath = ll.getArtifact().getPath()
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Resolve an array of all enabled mods. These mods will be constructed into
-     * a mod list format and enabled at launch.
-     * 
-     * @param {Object} modCfg The mod configuration object.
-     * @param {Array.<Object>} mdls An array of modules to parse.
-     * @returns {{fMods: Array.<Object>, lMods: Array.<Object>}} An object which contains
-     * a list of enabled forge mods and litemods.
-     */
-    resolveModConfiguration(modCfg, mdls){
-        let fMods = []
-        let lMods = []
-
-        for(let mdl of mdls){
-            const type = mdl.getType()
-            if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
-                const o = !mdl.getRequired().isRequired()
-                const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessID()], mdl.getRequired())
-                if(!o || (o && e)){
-                    if(mdl.hasSubModules()){
-                        const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessID()].mods, mdl.getSubModules())
-                        fMods = fMods.concat(v.fMods)
-                        lMods = lMods.concat(v.lMods)
-                        if(mdl.type === DistroManager.Types.LiteLoader){
-                            continue
-                        }
-                    }
-                    if(mdl.type === DistroManager.Types.ForgeMod){
-                        fMods.push(mdl)
-                    } else {
-                        lMods.push(mdl)
-                    }
-                }
-            }
-        }
-
-        return {
-            fMods,
-            lMods
-        }
-    }
-
-    _isBelowOneDotSeven() {
-        return Number(this.forgeData.id.split('-')[0].split('.')[1]) <= 7
-    }
-
-    /**
-     * Test to see if this version of forge requires the absolute: prefix
-     * on the modListFile repository field.
-     */
-    _requiresAbsolute(){
-        try {
-            if(this._isBelowOneDotSeven()) {
-                return false
-            }
-            const ver = this.forgeData.id.split('-')[2]
-            const pts = ver.split('.')
-            const min = [14, 23, 3, 2655]
-            for(let i=0; i<pts.length; i++){
-                const parsed = Number.parseInt(pts[i])
-                if(parsed < min[i]){
-                    return false
-                } else if(parsed > min[i]){
-                    return true
-                }
-            }
-        } catch (err) {
-            // We know old forge versions follow this format.
-            // Error must be caused by newer version.
-        }
-        
-        // Equal or errored
-        return true
-    }
-
-    /**
-     * Construct a mod list json object.
-     * 
-     * @param {'forge' | 'liteloader'} type The mod list type to construct.
-     * @param {Array.<Object>} mods An array of mods to add to the mod list.
-     * @param {boolean} save Optional. Whether or not we should save the mod list file.
-     */
-    constructModList(type, mods, save = false){
-        const modList = {
-            repositoryRoot: ((type === 'forge' && this._requiresAbsolute()) ? 'absolute:' : '') + path.join(this.commonDir, 'modstore')
-        }
-
-        const ids = []
-        if(type === 'forge'){
-            for(let mod of mods){
-                ids.push(mod.getExtensionlessID())
-            }
-        } else {
-            for(let mod of mods){
-                ids.push(mod.getExtensionlessID() + '@' + mod.getExtension())
-            }
-        }
-        modList.modRef = ids
-        
-        if(save){
-            const json = JSON.stringify(modList, null, 4)
-            fs.writeFileSync(type === 'forge' ? this.fmlDir : this.llDir, json, 'UTF-8')
-        }
-
-        return modList
-    }
-
-    /**
-     * Construct the mod argument list for forge 1.13
-     * 
-     * @param {Array.<Object>} mods An array of mods to add to the mod list.
-     */
-    constructModArguments(mods){
-        const argStr = mods.map(mod => {
-            return mod.getExtensionlessID()
-        }).join(',')
-
-        if(argStr){
-            return [
-                '--fml.mavenRoots',
-                path.join('..', '..', 'common', 'modstore'),
-                '--fml.mods',
-                argStr
-            ]
-        } else {
-            return []
-        }
-        
-    }
-
-    /**
-     * Construct the argument array that will be passed to the JVM process.
-     * 
-     * @param {Array.<Object>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the full JVM arguments for this process.
-     */
-    constructJVMArguments(mods, tempNativePath){
-        if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
-            return this._constructJVMArguments113(mods, tempNativePath)
-        } else {
-            return this._constructJVMArguments112(mods, tempNativePath)
-        }
-    }
-
-    /**
-     * Construct the argument array that will be passed to the JVM process.
-     * This function is for 1.12 and below.
-     * 
-     * @param {Array.<Object>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the full JVM arguments for this process.
-     */
-    _constructJVMArguments112(mods, tempNativePath){
-
-        let args = []
-
-        // Classpath Argument
-        args.push('-cp')
-        args.push(this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':'))
-
-        // Java Arguments
-        if(process.platform === 'darwin'){
-            args.push('-Xdock:name=HeliosLauncher')
-            args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
-        }
-        args.push('-Xmx' + ConfigManager.getMaxRAM())
-        args.push('-Xms' + ConfigManager.getMinRAM())
-        args = args.concat(ConfigManager.getJVMOptions())
-        args.push('-Djava.library.path=' + tempNativePath)
-
-        // Main Java Class
-        args.push(this.forgeData.mainClass)
-
-        // Forge Arguments
-        args = args.concat(this._resolveForgeArgs())
-
-        return args
-    }
-
-    /**
-     * Construct the argument array that will be passed to the JVM process.
-     * This function is for 1.13+
-     * 
-     * Note: Required Libs https://github.com/MinecraftForge/MinecraftForge/blob/af98088d04186452cb364280340124dfd4766a5c/src/fmllauncher/java/net/minecraftforge/fml/loading/LibraryFinder.java#L82
-     * 
-     * @param {Array.<Object>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the full JVM arguments for this process.
-     */
-    _constructJVMArguments113(mods, tempNativePath){
-
-        const argDiscovery = /\${*(.*)}/
-
-        // JVM Arguments First
-        let args = this.versionData.arguments.jvm
-
-        //args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
-
-        // Java Arguments
-        if(process.platform === 'darwin'){
-            args.push('-Xdock:name=HeliosLauncher')
-            args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
-        }
-        args.push('-Xmx' + ConfigManager.getMaxRAM())
-        args.push('-Xms' + ConfigManager.getMinRAM())
-        args = args.concat(ConfigManager.getJVMOptions())
-
-        // Main Java Class
-        args.push(this.forgeData.mainClass)
-
-        // Vanilla Arguments
-        args = args.concat(this.versionData.arguments.game)
-
-        for(let i=0; i<args.length; i++){
-            if(typeof args[i] === 'object' && args[i].rules != null){
-                
-                let checksum = 0
-                for(let rule of args[i].rules){
-                    if(rule.os != null){
-                        if(rule.os.name === LibraryInternal.mojangFriendlyOS()
-                            && (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){
-                            if(rule.action === 'allow'){
-                                checksum++
-                            }
-                        } else {
-                            if(rule.action === 'disallow'){
-                                checksum++
-                            }
-                        }
-                    } else if(rule.features != null){
-                        // We don't have many 'features' in the index at the moment.
-                        // This should be fine for a while.
-                        if(rule.features.has_custom_resolution != null && rule.features.has_custom_resolution === true){
-                            if(ConfigManager.getFullscreen()){
-                                rule.values = [
-                                    '--fullscreen',
-                                    'true'
-                                ]
-                            }
-                            checksum++
-                        }
-                    }
-                }
-
-                // TODO splice not push
-                if(checksum === args[i].rules.length){
-                    if(typeof args[i].value === 'string'){
-                        args[i] = args[i].value
-                    } else if(typeof args[i].value === 'object'){
-                        //args = args.concat(args[i].value)
-                        args.splice(i, 1, ...args[i].value)
-                    }
-
-                    // Decrement i to reprocess the resolved value
-                    i--
-                } else {
-                    args[i] = null
-                }
-
-            } else if(typeof args[i] === 'string'){
-                if(argDiscovery.test(args[i])){
-                    const identifier = args[i].match(argDiscovery)[1]
-                    let val = null
-                    switch(identifier){
-                        case 'auth_player_name':
-                            val = this.authUser.displayName.trim()
-                            break
-                        case 'version_name':
-                            //val = versionData.id
-                            val = this.server.getID()
-                            break
-                        case 'game_directory':
-                            val = this.gameDir
-                            break
-                        case 'assets_root':
-                            val = path.join(this.commonDir, 'assets')
-                            break
-                        case 'assets_index_name':
-                            val = this.versionData.assets
-                            break
-                        case 'auth_uuid':
-                            val = this.authUser.uuid.trim()
-                            break
-                        case 'auth_access_token':
-                            val = this.authUser.accessToken
-                            break
-                        case 'user_type':
-                            val = 'mojang'
-                            break
-                        case 'version_type':
-                            val = this.versionData.type
-                            break
-                        case 'resolution_width':
-                            val = ConfigManager.getGameWidth()
-                            break
-                        case 'resolution_height':
-                            val = ConfigManager.getGameHeight()
-                            break
-                        case 'natives_directory':
-                            val = args[i].replace(argDiscovery, tempNativePath)
-                            break
-                        case 'launcher_name':
-                            val = args[i].replace(argDiscovery, 'Helios-Launcher')
-                            break
-                        case 'launcher_version':
-                            val = args[i].replace(argDiscovery, this.launcherVersion)
-                            break
-                        case 'classpath':
-                            val = this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':')
-                            break
-                    }
-                    if(val != null){
-                        args[i] = val
-                    }
-                }
-            }
-        }
-
-        // Forge Specific Arguments
-        args = args.concat(this.forgeData.arguments.game)
-
-        // Filter null values
-        args = args.filter(arg => {
-            return arg != null
-        })
-
-        return args
-    }
-
-    /**
-     * Resolve the arguments required by forge.
-     * 
-     * @returns {Array.<string>} An array containing the arguments required by forge.
-     */
-    _resolveForgeArgs(){
-        const mcArgs = this.forgeData.minecraftArguments.split(' ')
-        const argDiscovery = /\${*(.*)}/
-
-        // Replace the declared variables with their proper values.
-        for(let i=0; i<mcArgs.length; ++i){
-            if(argDiscovery.test(mcArgs[i])){
-                const identifier = mcArgs[i].match(argDiscovery)[1]
-                let val = null
-                switch(identifier){
-                    case 'auth_player_name':
-                        val = this.authUser.displayName.trim()
-                        break
-                    case 'version_name':
-                        //val = versionData.id
-                        val = this.server.getID()
-                        break
-                    case 'game_directory':
-                        val = this.gameDir
-                        break
-                    case 'assets_root':
-                        val = path.join(this.commonDir, 'assets')
-                        break
-                    case 'assets_index_name':
-                        val = this.versionData.assets
-                        break
-                    case 'auth_uuid':
-                        val = this.authUser.uuid.trim()
-                        break
-                    case 'auth_access_token':
-                        val = this.authUser.accessToken
-                        break
-                    case 'user_type':
-                        val = 'mojang'
-                        break
-                    case 'user_properties': // 1.8.9 and below.
-                        val = '{}'
-                        break
-                    case 'version_type':
-                        val = this.versionData.type
-                        break
-                }
-                if(val != null){
-                    mcArgs[i] = val
-                }
-            }
-        }
-
-        // Autoconnect to the selected server.
-        if(ConfigManager.getAutoConnect() && this.server.isAutoConnect()){
-            const serverURL = new URL('my://' + this.server.getAddress())
-            mcArgs.push('--server')
-            mcArgs.push(serverURL.hostname)
-            if(serverURL.port){
-                mcArgs.push('--port')
-                mcArgs.push(serverURL.port)
-            }
-        }
-
-        // Prepare game resolution
-        if(ConfigManager.getFullscreen()){
-            mcArgs.push('--fullscreen')
-            mcArgs.push(true)
-        } else {
-            mcArgs.push('--width')
-            mcArgs.push(ConfigManager.getGameWidth())
-            mcArgs.push('--height')
-            mcArgs.push(ConfigManager.getGameHeight())
-        }
-        
-        // Mod List File Argument
-        mcArgs.push('--modListFile')
-        if(this._isBelowOneDotSeven()) {
-            mcArgs.push(path.basename(this.fmlDir))
-        } else {
-            mcArgs.push('absolute:' + this.fmlDir)
-        }
-        
-
-        // LiteLoader
-        if(this.usingLiteLoader){
-            mcArgs.push('--modRepo')
-            mcArgs.push(this.llDir)
-
-            // Set first arg to liteloader tweak class
-            mcArgs.unshift('com.mumfrey.liteloader.launch.LiteLoaderTweaker')
-            mcArgs.unshift('--tweakClass')
-        }
-
-        return mcArgs
-    }
-
-    /**
-     * Resolve the full classpath argument list for this process. This method will resolve all Mojang-declared
-     * libraries as well as the libraries declared by the server. Since mods are permitted to declare libraries,
-     * this method requires all enabled mods as an input
-     * 
-     * @param {Array.<Object>} mods An array of enabled mods which will be launched with this process.
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {Array.<string>} An array containing the paths of each library required by this process.
-     */
-    classpathArg(mods, tempNativePath){
-        let cpArgs = []
-
-        // Add the version.jar to the classpath.
-        const version = this.versionData.id
-        cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
-
-        if(this.usingLiteLoader){
-            cpArgs.push(this.llPath)
-        }
-
-        // Resolve the Mojang declared libraries.
-        const mojangLibs = this._resolveMojangLibraries(tempNativePath)
-
-        // Resolve the server declared libraries.
-        const servLibs = this._resolveServerLibraries(mods)
-
-        // Merge libraries, server libs with the same
-        // maven identifier will override the mojang ones.
-        // Ex. 1.7.10 forge overrides mojang's guava with newer version.
-        const finalLibs = {...mojangLibs, ...servLibs}
-        cpArgs = cpArgs.concat(Object.values(finalLibs))
-
-        return cpArgs
-    }
-
-    /**
-     * Resolve the libraries defined by Mojang's version data. This method will also extract
-     * native libraries and point to the correct location for its classpath.
-     * 
-     * TODO - clean up function
-     * 
-     * @param {string} tempNativePath The path to store the native libraries.
-     * @returns {{[id: string]: string}} An object containing the paths of each library mojang declares.
-     */
-    _resolveMojangLibraries(tempNativePath){
-        const libs = {}
-
-        const libArr = this.versionData.libraries
-        fs.ensureDirSync(tempNativePath)
-        for(let i=0; i<libArr.length; i++){
-            const lib = libArr[i]
-            if(LibraryInternal.validateRules(lib.rules, lib.natives)){
-                if(lib.natives == null){
-                    const dlInfo = lib.downloads
-                    const artifact = dlInfo.artifact
-                    const to = path.join(this.libPath, artifact.path)
-                    const versionIndependentId = lib.name.substring(0, lib.name.lastIndexOf(':'))
-                    libs[versionIndependentId] = to
-                } else {
-                    // Extract the native library.
-                    const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/']
-                    const artifact = lib.downloads.classifiers[lib.natives[LibraryInternal.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))]
-    
-                    // Location of native zip.
-                    const to = path.join(this.libPath, artifact.path)
-    
-                    let zip = new AdmZip(to)
-                    let zipEntries = zip.getEntries()
-    
-                    // Unzip the native zip.
-                    for(let i=0; i<zipEntries.length; i++){
-                        const fileName = zipEntries[i].entryName
-    
-                        let shouldExclude = false
-
-                        // Exclude noted files.
-                        exclusionArr.forEach(function(exclusion){
-                            if(fileName.indexOf(exclusion) > -1){
-                                shouldExclude = true
-                            }
-                        })
-
-                        // Extract the file.
-                        if(!shouldExclude){
-                            fs.writeFile(path.join(tempNativePath, fileName), zipEntries[i].getData(), (err) => {
-                                if(err){
-                                    logger.error('Error while extracting native library:', err)
-                                }
-                            })
-                        }
-    
-                    }
-                }
-            }
-        }
-
-        return libs
-    }
-
-    /**
-     * Resolve the libraries declared by this server in order to add them to the classpath.
-     * This method will also check each enabled mod for libraries, as mods are permitted to
-     * declare libraries.
-     * 
-     * @param {Array.<Object>} mods An array of enabled mods which will be launched with this process.
-     * @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
-     */
-    _resolveServerLibraries(mods){
-        const mdls = this.server.getModules()
-        let libs = {}
-
-        // Locate Forge/Libraries
-        for(let mdl of mdls){
-            const type = mdl.getType()
-            if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Library){
-                libs[mdl.getVersionlessID()] = mdl.getArtifact().getPath()
-                if(mdl.hasSubModules()){
-                    const res = this._resolveModuleLibraries(mdl)
-                    if(res.length > 0){
-                        libs = {...libs, ...res}
-                    }
-                }
-            }
-        }
-
-        //Check for any libraries in our mod list.
-        for(let i=0; i<mods.length; i++){
-            if(mods.sub_modules != null){
-                const res = this._resolveModuleLibraries(mods[i])
-                if(res.length > 0){
-                    libs = {...libs, ...res}
-                }
-            }
-        }
-
-        return libs
-    }
-
-    /**
-     * Recursively resolve the path of each library required by this module.
-     * 
-     * @param {Object} mdl A module object from the server distro index.
-     * @returns {Array.<string>} An array containing the paths of each library this module requires.
-     */
-    _resolveModuleLibraries(mdl){
-        if(!mdl.hasSubModules()){
-            return []
-        }
-        let libs = []
-        for(let sm of mdl.getSubModules()){
-            if(sm.getType() === DistroManager.Types.Library){
-                libs.push(sm.getArtifact().getPath())
-            }
-            // If this module has submodules, we need to resolve the libraries for those.
-            // To avoid unnecessary recursive calls, base case is checked here.
-            if(mdl.hasSubModules()){
-                const res = this._resolveModuleLibraries(sm)
-                if(res.length > 0){
-                    libs = libs.concat(res)
-                }
-            }
-        }
-        return libs
-    }
-}
-
-module.exports = ProcessBuilder

+ 0 - 67
src/main/old/serverstatus.ts

@@ -1,67 +0,0 @@
-import { connect } from 'net'
-
-/**
- * Retrieves the status of a minecraft server.
- * 
- * @param {string} address The server address.
- * @param {number} port Optional. The port of the server. Defaults to 25565.
- * @returns {Promise.<Object>} A promise which resolves to an object containing
- * status information.
- */
-export function getStatus(address: string, port: number | string = 25565){
-
-    let sanitizedPort: number
-
-    if(port == null || port == ''){
-        sanitizedPort = 25565
-    }
-    if(typeof port === 'string'){
-        sanitizedPort = parseInt(port)
-    }
-
-    return new Promise((resolve, reject) => {
-        const socket = connect(sanitizedPort, address, () => {
-            let buff = Buffer.from([0xFE, 0x01])
-            socket.write(buff)
-        })
-
-        socket.setTimeout(2500, () => {
-            socket.end()
-            reject({
-                code: 'ETIMEDOUT',
-                errno: 'ETIMEDOUT',
-                address,
-                sanitizedPort
-            })
-        })
-
-        socket.on('data', (data) => {
-            if(data != null){
-                let server_info = data.toString().split('\x00\x00\x00')
-                const NUM_FIELDS = 6
-                if(server_info != null && server_info.length >= NUM_FIELDS){
-                    resolve({
-                        online: true,
-                        version: server_info[2].replace(/\u0000/g, ''),
-                        motd: server_info[3].replace(/\u0000/g, ''),
-                        onlinePlayers: server_info[4].replace(/\u0000/g, ''),
-                        maxPlayers: server_info[5].replace(/\u0000/g,'')
-                    })
-                } else {
-                    resolve({
-                        online: false
-                    })
-                }
-            }
-            socket.end()
-        })
-
-        socket.on('error', (err) => {
-            socket.destroy()
-            reject(err)
-            // ENOTFOUND = Unable to resolve.
-            // ECONNREFUSED = Unable to connect to port.
-        })
-    })
-
-}