diff --git a/app/assets/js/assetguard.js b/app/assets/js/assetguard.js index 1c206c50..2063cb58 100644 --- a/app/assets/js/assetguard.js +++ b/app/assets/js/assetguard.js @@ -6,6 +6,8 @@ const crypto = require('crypto') const EventEmitter = require('events') const fs = require('fs-extra') const { LoggerUtil } = require('helios-core') +const { DistributionAPI } = require('helios-core/common') +const { Type } = require('helios-distribution-types') const nodeDiskInfo = require('node-disk-info') const StreamZip = require('node-stream-zip') const path = require('path') @@ -15,7 +17,7 @@ const tar = require('tar-fs') const zlib = require('zlib') const ConfigManager = require('./configmanager') -const DistroManager = require('./distromanager') +const { REMOTE_DISTRO_URL } = require('./distromanager') const isDev = require('./isdev') // Classes @@ -1521,11 +1523,11 @@ class AssetGuard extends EventEmitter { const modules = server.getModules() for(let ob of modules){ const type = ob.getType() - if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Forge){ + if(type === Type.ForgeHosted || type === Type.Forge){ if(Util.isForgeGradle3(server.getMinecraftVersion(), ob.getVersion())){ // Read Manifest for(let sub of ob.getSubModules()){ - if(sub.getType() === DistroManager.Types.VersionManifest){ + if(sub.getType() === Type.VersionManifest){ resolve(JSON.parse(fs.readFileSync(sub.getArtifact().getPath(), 'utf-8'))) return } @@ -1844,9 +1846,15 @@ class AssetGuard extends EventEmitter { if(!ConfigManager.isLoaded()){ ConfigManager.load() } - DistroManager.setDevMode(dev) - const dI = await DistroManager.pullLocal() + const api = new DistributionAPI( + ConfigManager.getLauncherDirectory(), + REMOTE_DISTRO_URL, + dev + ) + + const dI = await api.getDistributionLocalLoadOnly() + // TODO replace all const server = dI.getServer(serverid) // Validate Everything diff --git a/app/assets/js/configmanager.js b/app/assets/js/configmanager.js index c3f74897..6869e257 100644 --- a/app/assets/js/configmanager.js +++ b/app/assets/js/configmanager.js @@ -1,5 +1,6 @@ const fs = require('fs-extra') const { LoggerUtil } = require('helios-core') +const { mcVersionAtLeast } = require('helios-core/common') const os = require('os') const path = require('path') @@ -64,27 +65,6 @@ function resolveMinRAM(){ return resolveMaxRAM() } -/** - * TODO Copy pasted, should be in a utility file. - * - * 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. - */ -function mcVersionAtLeast(desired, actual){ - const des = desired.split('.') - const act = actual.split('.') - - for(let i=0; i= parseInt(des[i]))){ - return false - } - } - return true -} - /** * Three types of values: * Static = Explicitly declared. diff --git a/app/assets/js/distromanager.js b/app/assets/js/distromanager.js index 4fcc6852..406744fe 100644 --- a/app/assets/js/distromanager.js +++ b/app/assets/js/distromanager.js @@ -1,621 +1,13 @@ -const fs = require('fs') -const path = require('path') -const request = require('request') -const { LoggerUtil } = require('helios-core') +const { DistributionAPI } = require('helios-core/common') const ConfigManager = require('./configmanager') -const logger = LoggerUtil.getLogger('DistroManager') +exports.REMOTE_DISTRO_URL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json' -/** - * Represents the download information - * for a specific module. - */ -class Artifact { - - /** - * Parse a JSON object into an Artifact. - * - * @param {Object} json A JSON object representing an Artifact. - * - * @returns {Artifact} The parsed Artifact. - */ - static fromJSON(json){ - return Object.assign(new Artifact(), json) - } +const api = new DistributionAPI( + ConfigManager.getLauncherDirectory(), + exports.REMOTE_DISTRO_URL, + false +) - /** - * Get the MD5 hash of the artifact. This value may - * be undefined for artifacts which are not to be - * validated and updated. - * - * @returns {string} The MD5 hash of the Artifact or undefined. - */ - getHash(){ - return this.MD5 - } - - /** - * @returns {number} The download size of the artifact. - */ - getSize(){ - return this.size - } - - /** - * @returns {string} The download url of the artifact. - */ - getURL(){ - return this.url - } - - /** - * @returns {string} The artifact's destination path. - */ - getPath(){ - return this.path - } - -} -exports.Artifact - -/** - * Represents a the requirement status - * of a module. - */ -class Required { - - /** - * Parse a JSON object into a Required object. - * - * @param {Object} json A JSON object representing a Required object. - * - * @returns {Required} The parsed Required object. - */ - static fromJSON(json){ - if(json == null){ - return new Required(true, true) - } else { - return new Required(json.value == null ? true : json.value, json.def == null ? true : json.def) - } - } - - constructor(value, def){ - this.value = value - this.default = def - } - - /** - * Get the default value for a required object. If a module - * is not required, this value determines whether or not - * it is enabled by default. - * - * @returns {boolean} The default enabled value. - */ - isDefault(){ - return this.default - } - - /** - * @returns {boolean} Whether or not the module is required. - */ - isRequired(){ - return this.value - } - -} -exports.Required - -/** - * Represents a module. - */ -class Module { - - /** - * Parse a JSON object into a Module. - * - * @param {Object} json A JSON object representing a Module. - * @param {string} serverid The ID of the server to which this module belongs. - * - * @returns {Module} The parsed Module. - */ - static fromJSON(json, serverid){ - return new Module(json.id, json.name, json.type, json.classpath, json.required, json.artifact, json.subModules, serverid) - } - - /** - * Resolve the default extension for a specific module type. - * - * @param {string} type The type of the module. - * - * @return {string} The default extension for the given type. - */ - static _resolveDefaultExtension(type){ - switch (type) { - case exports.Types.Library: - case exports.Types.ForgeHosted: - case exports.Types.LiteLoader: - case exports.Types.ForgeMod: - return 'jar' - case exports.Types.LiteMod: - return 'litemod' - case exports.Types.File: - default: - return 'jar' // There is no default extension really. - } - } - - constructor(id, name, type, classpath, required, artifact, subModules, serverid) { - this.identifier = id - this.type = type - this.classpath = classpath - this._resolveMetaData() - this.name = name - this.required = Required.fromJSON(required) - this.artifact = Artifact.fromJSON(artifact) - this._resolveArtifactPath(artifact.path, serverid) - this._resolveSubModules(subModules, serverid) - } - - _resolveMetaData(){ - try { - - const m0 = this.identifier.split('@') - - this.artifactExt = m0[1] || Module._resolveDefaultExtension(this.type) - - const m1 = m0[0].split(':') - - this.artifactClassifier = m1[3] || undefined - this.artifactVersion = m1[2] || '???' - this.artifactID = m1[1] || '???' - this.artifactGroup = m1[0] || '???' - - } catch (err) { - // Improper identifier - logger.error('Improper ID for module', this.identifier, err) - } - } - - _resolveArtifactPath(artifactPath, serverid){ - const pth = artifactPath == null ? path.join(...this.getGroup().split('.'), this.getID(), this.getVersion(), `${this.getID()}-${this.getVersion()}${this.artifactClassifier != undefined ? `-${this.artifactClassifier}` : ''}.${this.getExtension()}`) : artifactPath - - switch (this.type){ - case exports.Types.Library: - case exports.Types.ForgeHosted: - case exports.Types.LiteLoader: - this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'libraries', pth) - break - case exports.Types.ForgeMod: - case exports.Types.LiteMod: - this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'modstore', pth) - break - case exports.Types.VersionManifest: - this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'versions', this.getIdentifier(), `${this.getIdentifier()}.json`) - break - case exports.Types.File: - default: - this.artifact.path = path.join(ConfigManager.getInstanceDirectory(), serverid, pth) - break - } - - } - - _resolveSubModules(json, serverid){ - const arr = [] - if(json != null){ - for(let sm of json){ - arr.push(Module.fromJSON(sm, serverid)) - } - } - this.subModules = arr.length > 0 ? arr : null - } - - /** - * @returns {string} The full, unparsed module identifier. - */ - getIdentifier(){ - return this.identifier - } - - /** - * @returns {string} The name of the module. - */ - getName(){ - return this.name - } - - /** - * @returns {Required} The required object declared by this module. - */ - getRequired(){ - return this.required - } - - /** - * @returns {Artifact} The artifact declared by this module. - */ - getArtifact(){ - return this.artifact - } - - /** - * @returns {string} The maven identifier of this module's artifact. - */ - getID(){ - return this.artifactID - } - - /** - * @returns {string} The maven group of this module's artifact. - */ - getGroup(){ - return this.artifactGroup - } - - /** - * @returns {string} The identifier without he version or extension. - */ - getVersionlessID(){ - return this.getGroup() + ':' + this.getID() - } - - /** - * @returns {string} The identifier without the extension. - */ - getExtensionlessID(){ - return this.getIdentifier().split('@')[0] - } - - /** - * @returns {string} The version of this module's artifact. - */ - getVersion(){ - return this.artifactVersion - } - - /** - * @returns {string} The classifier of this module's artifact - */ - getClassifier(){ - return this.artifactClassifier - } - - /** - * @returns {string} The extension of this module's artifact. - */ - getExtension(){ - return this.artifactExt - } - - /** - * @returns {boolean} Whether or not this module has sub modules. - */ - hasSubModules(){ - return this.subModules != null - } - - /** - * @returns {Array.} An array of sub modules. - */ - getSubModules(){ - return this.subModules - } - - /** - * @returns {string} The type of the module. - */ - getType(){ - return this.type - } - - /** - * @returns {boolean} Whether or not this library should be on the classpath. - */ - getClasspath(){ - return this.classpath ?? true - } - -} -exports.Module - -/** - * Represents a server configuration. - */ -class Server { - - /** - * Parse a JSON object into a Server. - * - * @param {Object} json A JSON object representing a Server. - * - * @returns {Server} The parsed Server object. - */ - static fromJSON(json){ - - const mdls = json.modules - json.modules = [] - - const serv = Object.assign(new Server(), json) - serv._resolveModules(mdls) - - return serv - } - - _resolveModules(json){ - const arr = [] - for(let m of json){ - arr.push(Module.fromJSON(m, this.getID())) - } - this.modules = arr - } - - /** - * @returns {string} The ID of the server. - */ - getID(){ - return this.id - } - - /** - * @returns {string} The name of the server. - */ - getName(){ - return this.name - } - - /** - * @returns {string} The description of the server. - */ - getDescription(){ - return this.description - } - - /** - * @returns {string} The URL of the server's icon. - */ - getIcon(){ - return this.icon - } - - /** - * @returns {string} The version of the server configuration. - */ - getVersion(){ - return this.version - } - - /** - * @returns {string} The IP address of the server. - */ - getAddress(){ - return this.address - } - - /** - * @returns {string} The minecraft version of the server. - */ - getMinecraftVersion(){ - return this.minecraftVersion - } - - /** - * @returns {boolean} Whether or not this server is the main - * server. The main server is selected by the launcher when - * no valid server is selected. - */ - isMainServer(){ - return this.mainServer - } - - /** - * @returns {boolean} Whether or not the server is autoconnect. - * by default. - */ - isAutoConnect(){ - return this.autoconnect - } - - /** - * @returns {Array.} An array of modules for this server. - */ - getModules(){ - return this.modules - } - -} -exports.Server - -/** - * Represents the Distribution Index. - */ -class DistroIndex { - - /** - * Parse a JSON object into a DistroIndex. - * - * @param {Object} json A JSON object representing a DistroIndex. - * - * @returns {DistroIndex} The parsed Server object. - */ - static fromJSON(json){ - - const servers = json.servers - json.servers = [] - - const distro = Object.assign(new DistroIndex(), json) - distro._resolveServers(servers) - distro._resolveMainServer() - - return distro - } - - _resolveServers(json){ - const arr = [] - for(let s of json){ - arr.push(Server.fromJSON(s)) - } - this.servers = arr - } - - _resolveMainServer(){ - - for(let serv of this.servers){ - if(serv.mainServer){ - this.mainServer = serv.id - return - } - } - - // If no server declares default_selected, default to the first one declared. - this.mainServer = (this.servers.length > 0) ? this.servers[0].getID() : null - } - - /** - * @returns {string} The version of the distribution index. - */ - getVersion(){ - return this.version - } - - /** - * @returns {string} The URL to the news RSS feed. - */ - getRSS(){ - return this.rss - } - - /** - * @returns {Array.} An array of declared server configurations. - */ - getServers(){ - return this.servers - } - - /** - * Get a server configuration by its ID. If it does not - * exist, null will be returned. - * - * @param {string} id The ID of the server. - * - * @returns {Server} The server configuration with the given ID or null. - */ - getServer(id){ - for(let serv of this.servers){ - if(serv.id === id){ - return serv - } - } - return null - } - - /** - * Get the main server. - * - * @returns {Server} The main server. - */ - getMainServer(){ - return this.mainServer != null ? this.getServer(this.mainServer) : null - } - -} -exports.DistroIndex - -exports.Types = { - Library: 'Library', - ForgeHosted: 'ForgeHosted', - Forge: 'Forge', // Unimplemented - LiteLoader: 'LiteLoader', - ForgeMod: 'ForgeMod', - LiteMod: 'LiteMod', - File: 'File', - VersionManifest: 'VersionManifest' -} - -let DEV_MODE = false - -const DISTRO_PATH = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json') -const DEV_PATH = path.join(ConfigManager.getLauncherDirectory(), 'dev_distribution.json') - -let data = null - -/** - * @returns {Promise.} - */ -exports.pullRemote = function(){ - if(DEV_MODE){ - return exports.pullLocal() - } - return new Promise((resolve, reject) => { - const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json' - //const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/' - const opts = { - url: distroURL, - timeout: 2500 - } - const distroDest = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json') - request(opts, (error, resp, body) => { - if(!error){ - - try { - data = DistroIndex.fromJSON(JSON.parse(body)) - } catch (e) { - reject(e) - return - } - - fs.writeFile(distroDest, body, 'utf-8', (err) => { - if(!err){ - resolve(data) - return - } else { - reject(err) - return - } - }) - } else { - reject(error) - return - } - }) - }) -} - -/** - * @returns {Promise.} - */ -exports.pullLocal = function(){ - return new Promise((resolve, reject) => { - fs.readFile(DEV_MODE ? DEV_PATH : DISTRO_PATH, 'utf-8', (err, d) => { - if(!err){ - data = DistroIndex.fromJSON(JSON.parse(d)) - resolve(data) - return - } else { - reject(err) - return - } - }) - }) -} - -exports.setDevMode = function(value){ - if(value){ - logger.info('Developer mode enabled.') - logger.info('If you don\'t know what that means, revert immediately.') - } else { - logger.info('Developer mode disabled.') - } - DEV_MODE = value -} - -exports.isDevMode = function(){ - return DEV_MODE -} - -/** - * @returns {DistroIndex} - */ -exports.getDistribution = function(){ - return data -} \ No newline at end of file +exports.DistroAPI = api \ No newline at end of file diff --git a/app/assets/js/preloader.js b/app/assets/js/preloader.js index f43eda8e..4f66086c 100644 --- a/app/assets/js/preloader.js +++ b/app/assets/js/preloader.js @@ -4,9 +4,11 @@ const os = require('os') const path = require('path') const ConfigManager = require('./configmanager') -const DistroManager = require('./distromanager') +const { DistroAPI } = require('./distromanager') const LangLoader = require('./langloader') const { LoggerUtil } = require('helios-core') +// eslint-disable-next-line no-unused-vars +const { HeliosDistribution } = require('helios-core/common') const logger = LoggerUtil.getLogger('Preloader') @@ -18,13 +20,17 @@ ConfigManager.load() // Load Strings LangLoader.loadLanguage('en_US') +/** + * + * @param {HeliosDistribution} data + */ function onDistroLoad(data){ if(data != null){ // Resolve the selected server if its value has yet to be set. - if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()) == null){ + if(ConfigManager.getSelectedServer() == null || data.getServerById(ConfigManager.getSelectedServer()) == null){ logger.info('Determining default selected server..') - ConfigManager.setSelectedServer(data.getMainServer().getID()) + ConfigManager.setSelectedServer(data.getMainServer().rawServer.id) ConfigManager.save() } } @@ -32,35 +38,20 @@ function onDistroLoad(data){ } // Ensure Distribution is downloaded and cached. -DistroManager.pullRemote().then((data) => { - logger.info('Loaded distribution index.') - - onDistroLoad(data) - -}).catch((err) => { - logger.info('Failed to load distribution index.') - logger.error(err) - - logger.info('Attempting to load an older version of the distribution index.') - // Try getting a local copy, better than nothing. - DistroManager.pullLocal().then((data) => { - logger.info('Successfully loaded an older version of the distribution index.') - - onDistroLoad(data) - - - }).catch((err) => { +DistroAPI.getDistribution() + .then(heliosDistro => { + logger.info('Loaded distribution index.') + onDistroLoad(heliosDistro) + }) + .catch(err => { logger.info('Failed to load an older version of the distribution index.') logger.info('Application cannot run.') logger.error(err) onDistroLoad(null) - }) -}) - // Clean up temp dir incase previous launches ended unexpectedly. fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => { if(err){ diff --git a/app/assets/js/processbuilder.js b/app/assets/js/processbuilder.js index 5efc1e62..b9cddac9 100644 --- a/app/assets/js/processbuilder.js +++ b/app/assets/js/processbuilder.js @@ -3,13 +3,13 @@ const child_process = require('child_process') const crypto = require('crypto') const fs = require('fs-extra') const { LoggerUtil } = require('helios-core') +const { getMojangOS, isLibraryCompatible, mcVersionAtLeast } = require('helios-core/common') +const { Type } = require('helios-distribution-types') const os = require('os') const path = require('path') const { URL } = require('url') -const { Util, Library } = require('./assetguard') const ConfigManager = require('./configmanager') -const DistroManager = require('./distromanager') const logger = LoggerUtil.getLogger('ProcessBuilder') @@ -44,7 +44,7 @@ class ProcessBuilder { 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())){ + if(!mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ this.constructJSONModList('forge', modObj.fMods, true) if(this.usingLiteLoader){ this.constructJSONModList('liteloader', modObj.lMods, true) @@ -54,7 +54,7 @@ class ProcessBuilder { const uberModArr = modObj.fMods.concat(modObj.lMods) let args = this.constructJVMArguments(uberModArr, tempNativePath) - if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ + if(mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ //args = args.concat(this.constructModArguments(modObj.fMods)) args = args.concat(this.constructModList(modObj.fMods)) } @@ -122,7 +122,7 @@ class ProcessBuilder { * @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 + return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.def : true } /** @@ -132,20 +132,20 @@ class ProcessBuilder { * 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())){ + for(let ll of this.server.modules){ + if(ll.rawModule.type === Type.LiteLoader){ + if(!ll.getRequired().value){ + const modCfg = ConfigManager.getModConfiguration(this.server.rawServer.id).mods + if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessMavenIdentifier()], ll.getRequired())){ + if(fs.existsSync(ll.localPath)){ this.usingLiteLoader = true - this.llPath = ll.getArtifact().getPath() + this.llPath = ll.localPath } } } else { - if(fs.existsSync(ll.getArtifact().getPath())){ + if(fs.existsSync(ll.localPath)){ this.usingLiteLoader = true - this.llPath = ll.getArtifact().getPath() + this.llPath = ll.localPath } } } @@ -166,20 +166,20 @@ class ProcessBuilder { 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()) + const type = mdl.rawModule.type + if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){ + const o = !mdl.getRequired().value + const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired()) if(!o || (o && e)){ - if(mdl.hasSubModules()){ - const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessID()].mods, mdl.getSubModules()) + if(mdl.subModules.length > 0){ + const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessMavenIdentifier()].mods, mdl.subModules) fMods = fMods.concat(v.fMods) lMods = lMods.concat(v.lMods) - if(mdl.type === DistroManager.Types.LiteLoader){ + if(mdl.type === Type.LiteLoader){ continue } } - if(mdl.type === DistroManager.Types.ForgeMod){ + if(mdl.type === Type.ForgeMod){ fMods.push(mdl) } else { lMods.push(mdl) @@ -326,7 +326,7 @@ class ProcessBuilder { * @returns {Array.} An array containing the full JVM arguments for this process. */ constructJVMArguments(mods, tempNativePath){ - if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ + if(mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){ return this._constructJVMArguments113(mods, tempNativePath) } else { return this._constructJVMArguments112(mods, tempNativePath) @@ -421,7 +421,7 @@ class ProcessBuilder { let checksum = 0 for(let rule of args[i].rules){ if(rule.os != null){ - if(rule.os.name === Library.mojangFriendlyOS() + if(rule.os.name === getMojangOS() && (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){ if(rule.action === 'allow'){ checksum++ @@ -523,7 +523,7 @@ class ProcessBuilder { // Autoconnect let isAutoconnectBroken try { - isAutoconnectBroken = Util.isAutoconnectBroken(this.forgeData.id.split('-')[2]) + isAutoconnectBroken = ProcessBuilder.isAutoconnectBroken(this.forgeData.id.split('-')[2]) } catch(err) { logger.error(err) logger.error('Forge version format changed.. assuming autoconnect works.') @@ -668,7 +668,7 @@ class ProcessBuilder { classpathArg(mods, tempNativePath){ let cpArgs = [] - if(!Util.mcVersionAtLeast('1.17', this.server.getMinecraftVersion())) { + if(!mcVersionAtLeast('1.17', this.server.getMinecraftVersion())) { // Add the version.jar to the classpath. // Must not be added to the classpath for Forge 1.17+. const version = this.versionData.id @@ -714,13 +714,13 @@ class ProcessBuilder { fs.ensureDirSync(tempNativePath) for(let i=0; i Number(v)) + + if(verSplit[0] === 31) { + for(let i=0; i minWorking[i]) { + return false + } else if(verSplit[i] < minWorking[i]) { + return true + } + } + } + + return false + } + } module.exports = ProcessBuilder \ No newline at end of file diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js index a7a2d0c6..6dd31779 100644 --- a/app/assets/js/scripts/landing.js +++ b/app/assets/js/scripts/landing.js @@ -10,8 +10,7 @@ const { MojangRestAPI, getServerStatus } = require('helios-core/mojang') // Internal Requirements const DiscordWrapper = require('./assets/js/discordwrapper') const ProcessBuilder = require('./assets/js/processbuilder') -const { Util } = require('./assets/js/assetguard') -const { RestResponseStatus, isDisplayableError } = require('helios-core/common') +const { RestResponseStatus, isDisplayableError, mcVersionAtLeast } = require('helios-core/common') const { stdout } = require('process') // Launch Elements @@ -86,9 +85,9 @@ function setLaunchEnabled(val){ } // Bind launch button -document.getElementById('launch_button').addEventListener('click', function(e){ +document.getElementById('launch_button').addEventListener('click', async (e) => { loggerLanding.info('Launching game..') - const mcVersion = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion() + const mcVersion = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer()).rawServer.minecraftVersion const jExe = ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer()) if(jExe == null){ asyncSystemScan(mcVersion) @@ -111,14 +110,14 @@ document.getElementById('launch_button').addEventListener('click', function(e){ }) // Bind settings button -document.getElementById('settingsMediaButton').onclick = (e) => { - prepareSettings() +document.getElementById('settingsMediaButton').onclick = async e => { + await prepareSettings() switchView(getCurrentView(), VIEWS.settings) } // Bind avatar overlay button. -document.getElementById('avatarOverlay').onclick = (e) => { - prepareSettings() +document.getElementById('avatarOverlay').onclick = async e => { + await prepareSettings() switchView(getCurrentView(), VIEWS.settings, 500, 500, () => { settingsNavItemListener(document.getElementById('settingsNavAccount'), false) }) @@ -144,9 +143,9 @@ function updateSelectedServer(serv){ if(getCurrentView() === VIEWS.settings){ fullSettingsSave() } - ConfigManager.setSelectedServer(serv != null ? serv.getID() : null) + ConfigManager.setSelectedServer(serv != null ? serv.rawServer.id : null) ConfigManager.save() - server_selection_button.innerHTML = '\u2022 ' + (serv != null ? serv.getName() : 'No Server Selected') + server_selection_button.innerHTML = '\u2022 ' + (serv != null ? serv.rawServer.name : 'No Server Selected') if(getCurrentView() === VIEWS.settings){ animateSettingsTabRefresh() } @@ -154,9 +153,9 @@ function updateSelectedServer(serv){ } // Real text is set in uibinder.js on distributionIndexDone. server_selection_button.innerHTML = '\u2022 Loading..' -server_selection_button.onclick = (e) => { +server_selection_button.onclick = async e => { e.target.blur() - toggleServerSelection(true) + await toggleServerSelection(true) } // Update Mojang Status Color @@ -220,17 +219,16 @@ const refreshMojangStatuses = async function(){ document.getElementById('mojang_status_icon').style.color = MojangRestAPI.statusToHex(status) } -const refreshServerStatus = async function(fade = false){ +const refreshServerStatus = async (fade = false) => { loggerLanding.info('Refreshing Server Status') - const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()) + const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer()) let pLabel = 'SERVER' let pVal = 'OFFLINE' try { - const serverURL = new URL('my://' + serv.getAddress()) - const servStat = await getServerStatus(47, serverURL.hostname, Number(serverURL.port)) + const servStat = await getServerStatus(47, serv.hostname, serv.port) console.log(servStat) pLabel = 'PLAYERS' pVal = servStat.players.online + '/' + servStat.players.max @@ -318,9 +316,9 @@ function asyncSystemScan(mcVersion, launchAfter = true){ console.log(`\x1b[31m[SysAEx]\x1b[0m ${data}`) }) - const javaVer = Util.mcVersionAtLeast('1.17', mcVersion) ? '17' : '8' + const javaVer = mcVersionAtLeast('1.17', mcVersion) ? '17' : '8' - sysAEx.on('message', (m) => { + sysAEx.on('message', async (m) => { if(m.context === 'validateJava'){ if(m.result == null){ @@ -368,7 +366,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){ // We need to make sure that the updated value is on the settings UI. // Just incase the settings UI is already open. settingsJavaExecVal.value = m.result - populateJavaExecDetails(settingsJavaExecVal.value) + await populateJavaExecDetails(settingsJavaExecVal.value) if(launchAfter){ dlAsync() @@ -534,7 +532,7 @@ function dlAsync(login = true){ }) // Establish communications between the AssetExec and current process. - aEx.on('message', (m) => { + aEx.on('message', async (m) => { if(m.context === 'validate'){ switch(m.data){ @@ -710,9 +708,9 @@ function dlAsync(login = true){ setLaunchDetails('Done. Enjoy the server!') // Init Discord Hook - const distro = DistroManager.getDistribution() - if(distro.discord != null && serv.discord != null){ - DiscordWrapper.initRPC(distro.discord, serv.discord) + const distro = await DistroAPI.getDistribution() + if(distro.rawDistribution.discord != null && serv.rawServerdiscord != null){ + DiscordWrapper.initRPC(distro.rawDistribution.discord, serv.rawServer.discord) hasRPC = true proc.on('close', (code, signal) => { loggerLaunchSuite.info('Shutting down Discord Rich Presence..') @@ -741,29 +739,19 @@ function dlAsync(login = true){ // Validate Forge files. setLaunchDetails('Loading server information..') - refreshDistributionIndex(true, (data) => { - onDistroRefresh(data) - serv = data.getServer(ConfigManager.getSelectedServer()) - aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]}) - }, (err) => { - loggerLaunchSuite.info('Error while fetching a fresh copy of the distribution index.', err) - refreshDistributionIndex(false, (data) => { + DistroAPI.refreshDistributionOrFallback() + .then(data => { onDistroRefresh(data) - serv = data.getServer(ConfigManager.getSelectedServer()) - aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]}) - }, (err) => { - loggerLaunchSuite.error('Unable to refresh distribution index.', err) - if(DistroManager.getDistribution() == null){ - showLaunchFailure('Fatal Error', 'Could not load a copy of the distribution index. See the console (CTRL + Shift + i) for more details.') - - // Disconnect from AssetExec - aEx.disconnect() - } else { - serv = data.getServer(ConfigManager.getSelectedServer()) - aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroManager.isDevMode()]}) - } + serv = data.getServerById(ConfigManager.getSelectedServer()) + aEx.send({task: 'execute', function: 'validateEverything', argsArr: [ConfigManager.getSelectedServer(), DistroAPI.isDevMode()]}) + }) + .catch(err => { + loggerLaunchSuite.error('Unable to refresh distribution index.', err) + showLaunchFailure('Fatal Error', 'Could not load a copy of the distribution index. See the console (CTRL + Shift + i) for more details.') + + // Disconnect from AssetExec + aEx.disconnect() }) - }) } /** @@ -1089,10 +1077,13 @@ function displayArticle(articleObject, index){ * Load news information from the RSS feed specified in the * distribution index. */ -function loadNews(){ - return new Promise((resolve, reject) => { - const distroData = DistroManager.getDistribution() - const newsFeed = distroData.getRSS() +async function loadNews(){ + + const distroData = await DistroAPI.getDistribution() + + const promise = new Promise((resolve, reject) => { + + const newsFeed = distroData.rawDistribution.rss const newsHost = new URL(newsFeed).origin + '/' $.ajax({ url: newsFeed, @@ -1147,4 +1138,6 @@ function loadNews(){ }) }) }) + + return await promise } diff --git a/app/assets/js/scripts/login.js b/app/assets/js/scripts/login.js index 2b6d0c02..96ec9234 100644 --- a/app/assets/js/scripts/login.js +++ b/app/assets/js/scripts/login.js @@ -193,10 +193,10 @@ loginButton.addEventListener('click', () => { $('.circle-loader').toggleClass('load-complete') $('.checkmark').toggle() setTimeout(() => { - switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => { + switchView(VIEWS.login, loginViewOnSuccess, 500, 500, async () => { // Temporary workaround if(loginViewOnSuccess === VIEWS.settings){ - prepareSettings() + await prepareSettings() } loginViewOnSuccess = VIEWS.landing // Reset this for good measure. loginCancelEnabled(false) // Reset this for good measure. diff --git a/app/assets/js/scripts/overlay.js b/app/assets/js/scripts/overlay.js index cf2c5c98..f85a28b0 100644 --- a/app/assets/js/scripts/overlay.js +++ b/app/assets/js/scripts/overlay.js @@ -117,8 +117,8 @@ function toggleOverlay(toggleState, dismissable = false, content = 'overlayConte } } -function toggleServerSelection(toggleState){ - prepareServerSelectionList() +async function toggleServerSelection(toggleState){ + await prepareServerSelectionList() toggleOverlay(toggleState, true, 'serverSelectContent') } @@ -171,11 +171,11 @@ function setDismissHandler(handler){ /* Server Select View */ -document.getElementById('serverSelectConfirm').addEventListener('click', () => { +document.getElementById('serverSelectConfirm').addEventListener('click', async () => { const listings = document.getElementsByClassName('serverListing') for(let i=0; i { } // None are selected? Not possible right? Meh, handle it. if(listings.length > 0){ - const serv = DistroManager.getDistribution().getServer(listings[i].getAttribute('servid')) + const serv = (await DistroAPI.getDistribution()).getServerById(listings[i].getAttribute('servid')) updateSelectedServer(serv) toggleOverlay(false) } }) -document.getElementById('accountSelectConfirm').addEventListener('click', () => { +document.getElementById('accountSelectConfirm').addEventListener('click', async () => { const listings = document.getElementsByClassName('accountListing') for(let i=0; i ConfigManager.save() updateSelectedAccount(authAcc) if(getCurrentView() === VIEWS.settings) { - prepareSettings() + await prepareSettings() } toggleOverlay(false) validateSelectedAccount() @@ -211,7 +211,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', () => ConfigManager.save() updateSelectedAccount(authAcc) if(getCurrentView() === VIEWS.settings) { - prepareSettings() + await prepareSettings() } toggleOverlay(false) validateSelectedAccount() @@ -267,21 +267,21 @@ function setAccountListingHandlers(){ }) } -function populateServerListings(){ - const distro = DistroManager.getDistribution() +async function populateServerListings(){ + const distro = await DistroAPI.getDistribution() const giaSel = ConfigManager.getSelectedServer() - const servers = distro.getServers() + const servers = distro.servers let htmlString = '' for(const serv of servers){ - htmlString += `