diff --git a/app/assets/js/actionbinder.js b/app/assets/js/actionbinder.js index 0272a844..db115ad6 100644 --- a/app/assets/js/actionbinder.js +++ b/app/assets/js/actionbinder.js @@ -2,7 +2,7 @@ const mojang = require('mojang') const path = require('path') const {AssetGuard} = require(path.join(__dirname, 'assets', 'js', 'assetguard.js')) const ProcessBuilder = require(path.join(__dirname, 'assets', 'js', 'processbuilder.js')) -const {GAME_DIRECTORY, DEFAULT_CONFIG} = require(path.join(__dirname, 'assets', 'js', 'enumerator.js')).enum +const ConfigManager = require(path.join(__dirname, 'assets', 'js', 'configmanager.js')) document.addEventListener('readystatechange', function(){ if (document.readyState === 'interactive'){ @@ -15,7 +15,7 @@ document.addEventListener('readystatechange', function(){ // TODO convert this to dropdown menu. // Bind selected server - document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(GAME_DIRECTORY, DEFAULT_CONFIG.getSelectedServer()).name + document.getElementById('server_selection').innerHTML = '\u2022 ' + AssetGuard.getServerById(ConfigManager.getGameDirectory(), ConfigManager.getSelectedServer()).name } }, false) @@ -35,11 +35,10 @@ testdownloads = async function(){ details.style.display = 'flex' content.style.display = 'none' - console.log(DEFAULT_CONFIG.getJavaExecutable()) - tracker = new AssetGuard(GAME_DIRECTORY, DEFAULT_CONFIG.getJavaExecutable()) + tracker = new AssetGuard(ConfigManager.getGameDirectory(), ConfigManager.getJavaExecutable()) det_text.innerHTML = 'Loading server information..' - const serv = await tracker.validateDistribution(DEFAULT_CONFIG.getSelectedServer()) + const serv = await tracker.validateDistribution(ConfigManager.getSelectedServer()) progress.setAttribute('value', 20) progress_text.innerHTML = '20%' console.log('forge stuff done') @@ -78,11 +77,11 @@ testdownloads = async function(){ det_text.innerHTML = 'Preparing to launch..' const forgeData = await tracker.loadForgeData(serv.id) - const authUser = await mojang.auth('EMAIL', 'PASS', DEFAULT_CONFIG.getClientToken(), { + const authUser = await mojang.auth('EMAIL', 'PASS', ConfigManager.getClientToken(), { name: 'Minecraft', version: 1 }) - let pb = new ProcessBuilder(GAME_DIRECTORY, serv, versionData, forgeData, authUser) + let pb = new ProcessBuilder(ConfigManager.getGameDirectory(), serv, versionData, forgeData, authUser) det_text.innerHTML = 'Launching game..' let proc; try{ diff --git a/app/assets/js/configmanager.js b/app/assets/js/configmanager.js index fb39cd72..9967c42f 100644 --- a/app/assets/js/configmanager.js +++ b/app/assets/js/configmanager.js @@ -4,171 +4,331 @@ const os = require('os') const path = require('path') const uuidV4 = require('uuid/v4') -class ConfigManager { - - constructor(path){ - this.path = path - this.config = null - this.load() - } - - /* Private functions to resolve default settings based on system specs. */ - - static _resolveMaxRAM(){ - const mem = os.totalmem() - return mem >= 8000000000 ? '4G' : (mem >= 6000000000 ? '3G' : '2G') - } - - /** - * Generates a default configuration object and saves it. - * - * @param {Boolean} save - optional. If true, the default config will be saved after being generated. - */ - _generateDefault(save = true){ - this.config = { - settings: { - java: { - minRAM: '2G', - maxRAM: ConfigManager._resolveMaxRAM(), - executable: 'C:\\Program Files\\Java\\jdk1.8.0_152\\bin\\javaw.exe', //TODO Resolve - jvmOptions: [ - '-XX:+UseConcMarkSweepGC', - '-XX:+CMSIncrementalMode', - '-XX:-UseAdaptiveSizePolicy', - '-Xmn128M' - ], - }, - game: { - resWidth: 1280, - resHeight: 720, - fullscreen: false, - autoConnect: true - }, - launcher: { - - } - }, - clientToken: uuidV4(), - selectedServer: null, - selectedAccount: null, - authenticationDatabase: [], - discord: { - clientID: 385581240906022916 - } - } - if(save){ - this.save() - } - } - - /** - * Load the launcher configuration into memory. If the specified file does - * not exist, a default configuration will be generated and saved. - */ - load(){ - if(!fs.existsSync(this.path)){ - mkpath.sync(path.join(this.path, '..')) - this._generateDefault() - } else { - this.config = JSON.parse(fs.readFileSync(this.path, 'UTF-8')) - } - } - - /** - * Save the launcher configuration to the specified file. - */ - save(){ - fs.writeFileSync(this.path, JSON.stringify(this.config, null, 4), 'UTF-8') - } - - /** - * Retrieve the launcher's Client Token. - */ - getClientToken(){ - return this.config.clientToken - } - - /** - * Retrieve the selected server configuration value. - */ - getSelectedServer(){ - return this.config.selectedServer - } - - /** - * Set the selected server configuration value. - * - * @param {String} serverID - the id of the new selected server. - */ - setSelectedServer(serverID){ - this.config.selectedServer = serverID - this.save() - } - - /** - * Retrieve the launcher's Discord Client ID. - */ - getDiscordClientID(){ - return this.config.discord.clientID - } - - /** - * Retrieve the minimum amount of memory for JVM initialization. - */ - getMinRAM(){ - return this.config.settings.java.minRAM - } - - /** - * Retrieve the maximum amount of memory for JVM initialization. - */ - getMaxRAM(){ - return this.config.settings.java.maxRAM - } - - /** - * Retrieve the path of the java executable. - */ - getJavaExecutable(){ - return this.config.settings.java.executable - } - - /** - * Retrieve the additional arguments for JVM initialization. Required arguments, - * such as memory allocation, will be dynamically resolved. - */ - getJVMOptions(){ - return this.config.settings.java.jvmOptions - } - - /** - * Retrieve the width of the game window. - */ - getGameWidth(){ - return this.config.settings.game.resWidth - } - - /** - * Retrieve the height of the game window. - */ - getGameHeight(){ - return this.config.settings.game.resHeight - } - - /** - * Check if the game should be launched in fullscreen mode. - */ - isFullscreen(){ - return this.config.settings.game.fullscreen - } - - /** - * Check if auto connect is enabled. - */ - isAutoConnect(){ - return this.config.settings.game.autoConnect - } - +function resolveMaxRAM(){ + const mem = os.totalmem() + return mem >= 8000000000 ? '4G' : (mem >= 6000000000 ? '3G' : '2G') } -module.exports = ConfigManager \ No newline at end of file +/** + * Three types of values: + * Static = Explicitly declared. + * Dynamic = Calculated by a private function. + * Resolved = Resolved externally, defaults to null. + */ +const DEFAULT_CONFIG = { + settings: { + java: { + minRAM: '2G', + maxRAM: resolveMaxRAM(), // Dynamic + executable: 'C:\\Program Files\\Java\\jdk1.8.0_152\\bin\\javaw.exe', // TODO Resolve + jvmOptions: [ + '-XX:+UseConcMarkSweepGC', + '-XX:+CMSIncrementalMode', + '-XX:-UseAdaptiveSizePolicy', + '-Xmn128M' + ], + }, + game: { + directory: path.join(__dirname, '..', '..', '..', 'target', 'test', 'mcfiles'), + resWidth: 1280, + resHeight: 720, + fullscreen: false, + autoConnect: true + }, + launcher: { + + } + }, + clientToken: uuidV4(), + selectedServer: null, // Resolved + selectedAccount: null, + authenticationDatabase: [], + discord: { + clientID: 385581240906022916 + } +} + +let config = null; + +// Persistance Utility Functions + +/** + * Save the current configuration to a file. + */ +exports.save = function(){ + const filePath = path.join(config.settings.game.directory, 'config.json') + fs.writeFileSync(filePath, JSON.stringify(config, null, 4), 'UTF-8') +} + +/** + * Load the configuration into memory. If a configuration file exists, + * that will be read and saved. Otherwise, a default configuration will + * be generated. Note that "resolved" values default to null and will + * need to be externally assigned. + */ +exports.load = function(){ + // Determine the effective configuration. + const EFFECTIVE_CONFIG = config == null ? DEFAULT_CONFIG : config + const filePath = path.join(EFFECTIVE_CONFIG.settings.game.directory, 'config.json') + + if(!fs.existsSync(filePath)){ + // Create all parent directories. + mkpath.sync(path.join(filePath, '..')) + config = DEFAULT_CONFIG + exports.save() + } else { + config = JSON.parse(fs.readFileSync(filePath, 'UTF-8')) + } +} + +// System Settings (Unconfigurable on UI) + +/** + * Retrieve the launcher's Client Token. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {String} - the launcher's Client Token. + */ +exports.getClientToken = function(def = false){ + return !def ? config.clientToken : DEFAULT_CONFIG.clientToken +} + +/** + * Set the launcher's Client Token. + * + * @param {String} clientToken - the launcher's new Client Token. + */ +exports.setClientToken = function(clientToken){ + config.clientToken = clientToken +} + +/** + * Retrieve the ID of the selected serverpack. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {String} - the ID of the selected serverpack. + */ +exports.getSelectedServer = function(def = false){ + return !def ? config.selectedServer : DEFAULT_CONFIG.clientToken +} + +/** + * Set the ID of the selected serverpack. + * + * @param {String} serverID - the ID of the new selected serverpack. + */ +exports.setSelectedServer = function(serverID){ + config.selectedServer = serverID +} + +//TODO Write Authentication Database/Selected Account accessors here + +/** + * Retrieve the launcher's Discord Client ID. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {String} - the launcher's Discord Client ID. + */ +exports.getDiscordClientID = function(def = false){ + return !def ? config.discord.clientID : DEFAULT_CONFIG.discord.clientID +} + +/** + * Set the launcher's Discord Client ID. + * + * @param {String} clientID - the launcher's new Discord Client ID. + */ +exports.setDiscordClientID = function(clientID){ + config.discord.clientID = clientID +} + +// User Configurable Settings + +// Java Settings + +/** + * Retrieve the minimum amount of memory for JVM initialization. This value + * contains the units of memory. For example, '5G' = 5 GigaBytes, '1024M' = + * 1024 MegaBytes, etc. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {String} - the minimum amount of memory for JVM initialization. + */ +exports.getMinRAM = function(def = false){ + return !def ? config.settings.java.minRAM : DEFAULT_CONFIG.settings.java.minRAM +} + +/** + * Set the minimum amount of memory for JVM initialization. This value should + * contain the units of memory. For example, '5G' = 5 GigaBytes, '1024M' = + * 1024 MegaBytes, etc. + * + * @param {String} minRAM - the new minimum amount of memory for JVM initialization. + */ +exports.setMinRAM = function(minRAM){ + config.settings.java.minRAM = minRAM +} + +/** + * Retrieve the maximum amount of memory for JVM initialization. This value + * contains the units of memory. For example, '5G' = 5 GigaBytes, '1024M' = + * 1024 MegaBytes, etc. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {String} - the maximum amount of memory for JVM initialization. + */ +exports.getMaxRAM = function(def = false){ + return !def ? config.settings.java.maxRAM : resolveMaxRAM() +} + +/** + * Set the maximum amount of memory for JVM initialization. This value should + * contain the units of memory. For example, '5G' = 5 GigaBytes, '1024M' = + * 1024 MegaBytes, etc. + * + * @param {String} maxRAM - the new maximum amount of memory for JVM initialization. + */ +exports.setMaxRAM = function(maxRAM){ + config.settings.java.maxRAM = maxRAM +} + +/** + * Retrieve the path of the Java Executable. + * + * This is a resolved configuration value and defaults to null until externally assigned. + * + * @returns {String} - the path of the Java Executable. + */ +exports.getJavaExecutable = function(){ + return config.settings.java.executable +} + +/** + * Set the path of the Java Executable. + * + * @param {String} executable - the new path of the Java Executable. + */ +exports.setJavaExecutable = function(executable){ + config.settings.java.executable = executable +} + +/** + * Retrieve the additional arguments for JVM initialization. Required arguments, + * such as memory allocation, will be dynamically resolved and will not be included + * in this value. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {Array.} - an array of the additional arguments for JVM initialization. + */ +exports.getJVMOptions = function(def = false){ + return !def ? config.settings.java.jvmOptions : DEFAULT_CONFIG.settings.java.jvmOptions +} + +/** + * Set the additional arguments for JVM initialization. Required arguments, + * such as memory allocation, will be dynamically resolved and should not be + * included in this value. + * + * @param {Array.} jvmOptions - an array of the new additional arguments for JVM + * initialization. + */ +exports.setJVMOptions = function(jvmOptions){ + config.settings.java.jvmOptions = jvmOptions +} + +// Game Settings + +/** + * Retrieve the absolute path of the game directory. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {String} - the absolute path of the game directory. + */ +exports.getGameDirectory = function(def = false){ + return !def ? config.settings.game.directory : DEFAULT_CONFIG.settings.game.directory +} + +/** + * Set the absolute path of the game directory. + * + * @param {String} directory - the absolute path of the new game directory. + */ +exports.setGameDirectory = function(directory){ + config.settings.game.directory = directory +} + +/** + * Retrieve the width of the game window. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {Number} - the width of the game window. + */ +exports.getGameWidth = function(def = false){ + return !def ? config.settings.game.resWidth : DEFAULT_CONFIG.settings.game.resWidth +} + +/** + * Set the width of the game window. + * + * @param {Number} resWidth - the new width of the game window. + */ +exports.setGameWidth = function(resWidth){ + config.settings.game.resWidth = resWidth +} + +/** + * Retrieve the height of the game window. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {Number} - the height of the game window. + */ +exports.getGameHeight = function(def = false){ + return !def ? config.settings.game.resHeight : DEFAULT_CONFIG.settings.game.resHeight +} + +/** + * Set the height of the game window. + * + * @param {Number} resHeight - the new height of the game window. + */ +exports.setGameHeight = function(resHeight){ + config.settings.game.resHeight = resHeight +} + +/** + * Check if the game should be launched in fullscreen mode. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {Boolean} - whether or not the game is set to launch in fullscreen mode. + */ +exports.isFullscreen = function(def = false){ + return !def ? config.settings.game.fullscreen : DEFAULT_CONFIG.settings.game.fullscreen +} + +/** + * Change the status of if the game should be launched in fullscreen mode. + * + * @param {Boolean} fullscreen - whether or not the game should launch in fullscreen mode. + */ +exports.setFullscreen = function(fullscreen){ + config.settings.game.fullscreen = fullscreen +} + +/** + * Check if the game should auto connect to servers. + * + * @param {Boolean} def - optional. If true, the default value will be returned. + * @returns {Boolean} - whether or not the game should auto connect to servers. + */ +exports.isAutoConnect = function(def = false){ + return !def ? config.settings.game.autoConnect : DEFAULT_CONFIG.settings.game.autoConnect +} + +/** + * Change the status of whether or not the game should auto connect to servers. + * + * @param {Boolean} autoConnect - whether or not the game should auto connect to servers. + */ +exports.setAutoConnect = function(autoConnect){ + config.settings.game.autoConnect = autoConnect +} \ No newline at end of file diff --git a/app/assets/js/discordwrapper.js b/app/assets/js/discordwrapper.js index 579e05c2..658b19aa 100644 --- a/app/assets/js/discordwrapper.js +++ b/app/assets/js/discordwrapper.js @@ -1,19 +1,24 @@ // Work in progress const Client = require('discord-rpc') -const {DEFAULT_CONFIG} = require('./enumerator.js').enum +const ConfigManager = require('./configmanager.js') let rpc function initRPC(){ rpc = new Client({ transport: 'ipc' }); - rpc.login(DEFAULT_CONFIG.getDiscordClientID()).catch(error => { + rpc.login(ConfigManager.getDiscordClientID()).catch(error => { if(error.message.includes('ENOENT')) { console.log('Unable to initialize Discord Rich Presence, no client detected.') } else { console.log('Unable to initialize Discord Rich Presence: ' + error.message) } }) + + const activity = { + details: 'Playing on WesterosCraft', + + } } function shutdownRPC(){ diff --git a/app/assets/js/enumerator.js b/app/assets/js/enumerator.js deleted file mode 100644 index 64b9d8f7..00000000 --- a/app/assets/js/enumerator.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Module which stores constant values. These constants are mutable, however - * generally should not be changed unless a value is being added. Values are - * typically initialized during the app's preloader. - * @module enumerator - */ -exports.enum = { - -} \ No newline at end of file diff --git a/app/assets/js/preloader.js b/app/assets/js/preloader.js index 77557f2e..9bd702d3 100644 --- a/app/assets/js/preloader.js +++ b/app/assets/js/preloader.js @@ -1,22 +1,18 @@ -// Note: The following modules CANNOT require enumerator.js const {AssetGuard} = require('./assetguard.js') const ConfigManager = require('./configmanager.js') -const constants = require('./enumerator.js').enum const path = require('path') console.log('Preloading') +// Load ConfigManager +ConfigManager.load() + // Ensure Distribution is downloaded and cached. -AssetGuard.retrieveDistributionDataSync(false) +AssetGuard.retrieveDistributionDataSync(ConfigManager.getGameDirectory(), false) -// TODO: Resolve game directory based on windows, linux, or mac.. -constants.GAME_DIRECTORY = path.join(__dirname, '..', '..', '..', 'target', 'test', 'mcfiles') -constants.DISTRO_DIRECTORY = path.join(constants.GAME_DIRECTORY, 'westeroscraft.json') - -// Complete config setup -const conf = new ConfigManager(path.join(constants.GAME_DIRECTORY, 'config.json')) -if(conf.getSelectedServer() == null){ +// Resolve the selected server if its value has yet to be set. +if(ConfigManager.getSelectedServer() == null){ console.log('Determining default selected server..') - conf.setSelectedServer(AssetGuard.resolveSelectedServer(constants.GAME_DIRECTORY)) -} -constants.DEFAULT_CONFIG = conf \ No newline at end of file + ConfigManager.setSelectedServer(AssetGuard.resolveSelectedServer(ConfigManager.getGameDirectory())) + ConfigManager.save() +} \ No newline at end of file diff --git a/app/assets/js/processbuilder.js b/app/assets/js/processbuilder.js index 6ea4f2a2..9f1da79b 100644 --- a/app/assets/js/processbuilder.js +++ b/app/assets/js/processbuilder.js @@ -8,7 +8,7 @@ const AdmZip = require('adm-zip') const {AssetGuard, Library} = require('./assetguard.js') const child_process = require('child_process') -const {DEFAULT_CONFIG} = require('./enumerator.js').enum +const ConfigManager = require('./configmanager.js') const fs = require('fs') const mkpath = require('mkdirp') const path = require('path') @@ -42,7 +42,7 @@ class ProcessBuilder { console.log(args) - const child = child_process.spawn(DEFAULT_CONFIG.getJavaExecutable(), args) + const child = child_process.spawn(ConfigManager.getJavaExecutable(), args) child.stdout.on('data', (data) => { console.log('Minecraft:', data.toString('utf8')) @@ -98,8 +98,8 @@ class ProcessBuilder { */ constructJVMArguments(mods){ - let args = ['-Xmx' + DEFAULT_CONFIG.getMaxRAM(), - '-Xms' + DEFAULT_CONFIG.getMinRAM(),, + let args = ['-Xmx' + ConfigManager.getMaxRAM(), + '-Xms' + ConfigManager.getMinRAM(),, '-Djava.library.path=' + path.join(this.dir, 'natives'), '-cp', this.classpathArg(mods).join(';'), @@ -108,7 +108,7 @@ class ProcessBuilder { // For some reason this will add an undefined value unless // the delete count is 1. I suspect this is unintended behavior // by the function.. need to keep an eye on this. - args.splice(2, 1, ...DEFAULT_CONFIG.getJVMOptions()) + args.splice(2, 1, ...ConfigManager.getJVMOptions()) args = args.concat(this._resolveForgeArgs()) @@ -168,17 +168,17 @@ class ProcessBuilder { mcArgs.push('absolute:' + this.fmlDir) // Prepare game resolution - if(DEFAULT_CONFIG.isFullscreen()){ + if(ConfigManager.isFullscreen()){ mcArgs.unshift('--fullscreen') } else { - mcArgs.unshift(DEFAULT_CONFIG.getGameWidth()) + mcArgs.unshift(ConfigManager.getGameWidth()) mcArgs.unshift('--width') - mcArgs.unshift(DEFAULT_CONFIG.getGameHeight()) + mcArgs.unshift(ConfigManager.getGameHeight()) mcArgs.unshift('--height') } // Prepare autoconnect - if(DEFAULT_CONFIG.isAutoConnect() && this.server.autoconnect){ + if(ConfigManager.isAutoConnect() && this.server.autoconnect){ const serverURL = new URL('my://' + this.server.server_ip) mcArgs.unshift(serverURL.hostname) mcArgs.unshift('--server')