diff --git a/app/assets/css/launcher.css b/app/assets/css/launcher.css index 29a12b11..e203abf9 100644 --- a/app/assets/css/launcher.css +++ b/app/assets/css/launcher.css @@ -1092,8 +1092,9 @@ body, button { display: flex; align-items: center; justify-content: space-between; - margin: 20px 0px; + padding: 20px 0px; width: 75%; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); } .settingsFieldLeft { display: flex; @@ -1107,6 +1108,7 @@ body, button { .settingsFieldDesc { font-size: 12px; color: rgba(255, 255, 255, .95); + margin-top: 5px; } .settingsDivider { height: 1px; @@ -1187,6 +1189,93 @@ input:checked + .toggleSwitchSlider:before { cursor: ew-resize; } +/* File selectors */ + +/* Main container for File selectors. */ +.settingsFileSelContainer { + display: flex; + flex-direction: column; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); + margin-bottom: 20px; + margin-top: 20px; + width: 75%; +} + +/* File selector title. */ +.settingsFileSelTitle { + margin-bottom: 10px; +} + +/* Wrapper container for the actionable elements. */ +.settingsFileSelActions { + display: flex; + width: 90%; +} + +/* File selector icon settings. */ +.settingsFileSelIcon { + display: flex; + align-items: center; + background: rgba(126, 126, 126, 0.57); + border-radius: 3px 0px 0px 3px; + padding: 5px; + transition: 0.25s ease; +} +.settingsFileSelSVG { + width: 20px; + height: 20px; + fill: white; +} + +/* Disabled text field which stores the selected file path. */ +.settingsFileSelVal { + border-radius: 0px !important; + width: 100%; + padding: 5px 10px; + font-size: 12px; + height: 30px; +} + +/* File input for file selection. */ +.settingsFileSelSel { + width: 0px; + height: 0px; + opacity: 0; +} +.settingsFileSelSel::-webkit-file-upload-button { + display: none; +} + +/* Wrapper label to add a custom style to the file input. */ +.settingsFileSelLabel { + border-left: 0px; + border-radius: 0px 3px 3px 0px; + font-size: 12px; + padding: 0px 5px; + cursor: pointer; + display: flex; + align-items: center; + background: rgba(126, 126, 126, 0.57); + transition: 0.25s ease; + white-space: nowrap; +} +.settingsFileSelLabel:hover, +.settingsFileSelLabel:focus, +.settingsFileSelSel:focus ~ #settingsJavaExecLabel { + text-shadow: 0px 0px 20px white; +} + +/* Description for the file selector. */ +.settingsFileSelDesc { + font-size: 10px; + margin: 20px 0px; + color: lightgrey; + width: 89%; +} +.settingsFileSelDesc strong { + font-family: 'Avenir Medium'; +} + /* * * * Settings View (Account Tab) * * */ @@ -1347,7 +1436,9 @@ input:checked + .toggleSwitchSlider:before { #settingsGameResolutionContainer { display: flex; flex-direction: column; - margin-bottom: 20px; + padding-bottom: 20px; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); + width: 75%; } #settingsGameResolutionContent { display: flex; @@ -1805,20 +1896,6 @@ input:checked + .toggleSwitchSlider:before { font-weight: bold; } -/* Main container for the Java executable setting. */ -#settingsJavaExecContainer { - display: flex; - flex-direction: column; - border-bottom: 1px solid rgba(255, 255, 255, 0.50); - margin-bottom: 20px; - width: 75%; -} - -/* Java executable setting title. */ -#settingsJavaExecTitle { - margin-bottom: 10px; -} - /* Status text which displays details on the selected executable. */ #settingsJavaExecDetails { font-weight: bold; @@ -1826,76 +1903,6 @@ input:checked + .toggleSwitchSlider:before { font-size: 12px; } -/* Wrapper container for the actionable elements. */ -#settingsJavaExecActions { - display: flex; - width: 90%; -} - -/* Java icon settings. */ -.settingsJavaIcon { - display: flex; - align-items: center; - background: rgba(126, 126, 126, 0.57); - border-radius: 3px 0px 0px 3px; - padding: 5px; - transition: 0.25s ease; -} -.settingsJavaIconSVG { - width: 20px; - height: 20px; - fill: white; -} - -/* Disabled text field which stores the selected executable path. */ -#settingsJavaExecVal { - border-radius: 0px !important; - width: 100%; - padding: 5px 10px; - font-size: 12px; -} - -/* File input for executable selection. */ -#settingsJavaExecSel { - width: 0px; - height: 0px; - opacity: 0; -} -#settingsJavaExecSel::-webkit-file-upload-button { - display: none; -} - -/* Wrapper label to add a custom style to the file input. */ -#settingsJavaExecLabel { - border-left: 0px; - border-radius: 0px 3px 3px 0px; - font-size: 12px; - padding: 0px 5px; - cursor: pointer; - display: flex; - align-items: center; - background: rgba(126, 126, 126, 0.57); - transition: 0.25s ease; - white-space: nowrap; -} -#settingsJavaExecLabel:hover, -#settingsJavaExecLabel:focus, -#settingsJavaExecSel:focus ~ #settingsJavaExecLabel { - text-shadow: 0px 0px 20px white; -} - -/* Description for the Java executable setting. */ -#settingsJavaExecDesc { - font-size: 10px; - margin: 20px 0px; - color: lightgrey; - font-weight: bold; - width: 89%; -} -#settingsJavaExecDesc strong { - font-family: 'Avenir Medium'; -} - /* Main container for the JVM options setting. */ #settingsJVMOptsContainer { width: 75%; @@ -1932,6 +1939,15 @@ input:checked + .toggleSwitchSlider:before { width: 89%; } +/* * * +* Settings View (Launcher Tab) +* * */ + +/* Tailored style for the data directory header. */ +#settingsDataDirTitle { + margin-bottom: 10px; +} + /* * * * Settings View (About Tab) * * */ diff --git a/app/assets/js/configmanager.js b/app/assets/js/configmanager.js index 3061d712..ef908c7e 100644 --- a/app/assets/js/configmanager.js +++ b/app/assets/js/configmanager.js @@ -1,13 +1,46 @@ -const fs = require('fs-extra') -const os = require('os') -const path = require('path') +const fs = require('fs-extra') +const os = require('os') +const path = require('path') const logger = require('./loggerutil')('%c[ConfigManager]', 'color: #a02d2a; font-weight: bold') const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME) const dataPath = path.join(sysRoot, '.westeroscraft') -const firstLaunch = !fs.existsSync(dataPath) +// Forked processes do not have access to electron, so we have this workaround. +const launcherDir = process.env.CONFIG_DIRECT_PATH || require('electron').remote.app.getPath('userData') + +/** + * Retrieve the absolute path of the launcher directory. + * + * @returns {string} The absolute path of the launcher directory. + */ +exports.getLauncherDirectory = function(){ + return launcherDir +} + +/** + * Get the launcher's data directory. This is where all files related + * to game launch are installed (common, instances, java, etc). + * + * @returns {string} The absolute path of the launcher's data directory. + */ +exports.getDataDirectory = function(def = false){ + return !def ? config.settings.launcher.dataDirectory : DEFAULT_CONFIG.settings.launcher.dataDirectory +} + +/** + * Set the new data directory. + * + * @param {string} dataDirectory The new data directory. + */ +exports.setDataDirectory = function(dataDirectory){ + config.settings.launcher.dataDirectory = dataDirectory +} + +const configPath = path.join(exports.getLauncherDirectory(), 'config.json') +const configPathLEGACY = path.join(dataPath, 'config.json') +const firstLaunch = !fs.existsSync(configPath) && !fs.existsSync(configPathLEGACY) exports.getAbsoluteMinRAM = function(){ const mem = os.totalmem() @@ -56,7 +89,8 @@ const DEFAULT_CONFIG = { launchDetached: true }, launcher: { - allowPrerelease: false + allowPrerelease: false, + dataDirectory: dataPath } }, newsCache: { @@ -64,8 +98,6 @@ const DEFAULT_CONFIG = { content: null, dismissed: false }, - commonDirectory: path.join(dataPath, 'common'), - instanceDirectory: path.join(dataPath, 'instances'), clientToken: null, selectedServer: null, // Resolved selectedAccount: null, @@ -81,8 +113,7 @@ let config = null * Save the current configuration to a file. */ exports.save = function(){ - const filePath = path.join(dataPath, 'config.json') - fs.writeFileSync(filePath, JSON.stringify(config, null, 4), 'UTF-8') + fs.writeFileSync(configPath, JSON.stringify(config, null, 4), 'UTF-8') } /** @@ -92,24 +123,29 @@ exports.save = function(){ * need to be externally assigned. */ exports.load = function(){ - // Determine the effective configuration. - const filePath = path.join(dataPath, 'config.json') + let doLoad = true - if(!fs.existsSync(filePath)){ + if(!fs.existsSync(configPath)){ // Create all parent directories. - fs.ensureDirSync(path.join(filePath, '..')) - config = DEFAULT_CONFIG - exports.save() - } else { + fs.ensureDirSync(path.join(configPath, '..')) + if(fs.existsSync(configPathLEGACY)){ + fs.moveSync(configPathLEGACY, configPath) + } else { + doLoad = false + config = DEFAULT_CONFIG + exports.save() + } + } + if(doLoad){ let doValidate = false try { - config = JSON.parse(fs.readFileSync(filePath, 'UTF-8')) + config = JSON.parse(fs.readFileSync(configPath, 'UTF-8')) doValidate = true } catch (err){ logger.error(err) logger.log('Configuration file contains malformed JSON or is corrupt.') logger.log('Generating a new configuration file.') - fs.ensureDirSync(path.join(filePath, '..')) + fs.ensureDirSync(path.join(configPath, '..')) config = DEFAULT_CONFIG exports.save() } @@ -152,15 +188,6 @@ function validateKeySet(srcObj, destObj){ return destObj } -/** - * Retrieve the absolute path of the launcher directory. - * - * @returns {string} The absolute path of the launcher directory. - */ -exports.getLauncherDirectory = function(){ - return dataPath -} - /** * Check to see if this is the first time the user has launched the * application. This is determined by the existance of the data path. @@ -218,7 +245,7 @@ exports.setNewsCacheDismissed = function(dismissed){ * @returns {string} The launcher's common directory. */ exports.getCommonDirectory = function(){ - return config.commonDirectory + return path.join(exports.getDataDirectory(), 'common') } /** @@ -228,7 +255,7 @@ exports.getCommonDirectory = function(){ * @returns {string} The launcher's instance directory. */ exports.getInstanceDirectory = function(){ - return config.instanceDirectory + return path.join(exports.getDataDirectory(), 'instances') } /** diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js index e7b73845..31a6f924 100644 --- a/app/assets/js/scripts/landing.js +++ b/app/assets/js/scripts/landing.js @@ -275,11 +275,15 @@ function asyncSystemScan(mcVersion, launchAfter = true){ const loggerSysAEx = LoggerUtil('%c[SysAEx]', 'color: #353232; font-weight: bold') + const forkEnv = JSON.parse(JSON.stringify(process.env)) + forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory() + // Fork a process to run validations. sysAEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [ ConfigManager.getCommonDirectory(), ConfigManager.getJavaExecutable() ], { + env: forkEnv, stdio: 'pipe' }) // Stdout @@ -307,7 +311,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){ ) setOverlayHandler(() => { setLaunchDetails('Preparing Java Download..') - sysAEx.send({task: 'execute', function: '_enqueueOracleJRE', argsArr: [ConfigManager.getLauncherDirectory()]}) + sysAEx.send({task: 'execute', function: '_enqueueOracleJRE', argsArr: [ConfigManager.getDataDirectory()]}) toggleOverlay(false) }) setDismissHandler(() => { @@ -431,7 +435,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){ // Begin system Java scan. setLaunchDetails('Checking system info..') - sysAEx.send({task: 'execute', function: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory(), mcVersion]}) + sysAEx.send({task: 'execute', function: 'validateJava', argsArr: [ConfigManager.getDataDirectory(), mcVersion]}) } @@ -470,11 +474,15 @@ function dlAsync(login = true){ const loggerAEx = LoggerUtil('%c[AEx]', 'color: #353232; font-weight: bold') const loggerLaunchSuite = LoggerUtil('%c[LaunchSuite]', 'color: #000668; font-weight: bold') + const forkEnv = JSON.parse(JSON.stringify(process.env)) + forkEnv.CONFIG_DIRECT_PATH = ConfigManager.getLauncherDirectory() + // Start AssetExec to run validations and downloads in a forked process. aEx = cp.fork(path.join(__dirname, 'assets', 'js', 'assetexec.js'), [ ConfigManager.getCommonDirectory(), ConfigManager.getJavaExecutable() ], { + env: forkEnv, stdio: 'pipe' }) // Stdout diff --git a/app/assets/js/scripts/settings.js b/app/assets/js/scripts/settings.js index 52445cf1..8e8c54ba 100644 --- a/app/assets/js/scripts/settings.js +++ b/app/assets/js/scripts/settings.js @@ -41,6 +41,24 @@ document.addEventListener('click', closeSettingsSelect) bindSettingsSelect() +function bindFileSelectors(){ + for(let ele of document.getElementsByClassName('settingsFileSelSel')){ + if(ele.id === 'settingsJavaExecSel'){ + ele.onchange = (e) => { + ele.previousElementSibling.value = ele.files[0].path + populateJavaExecDetails(ele.previousElementSibling.value) + } + } else { + ele.onchange = (e) => { + ele.previousElementSibling.value = ele.files[0].path + } + } + } +} + +bindFileSelectors() + + /** * General Settings Functions */ @@ -97,6 +115,8 @@ function initSettingsValues(){ if(cVal === 'JavaExecutable'){ populateJavaExecDetails(v.value) v.value = gFn() + } else if (cVal === 'DataDirectory'){ + v.value = gFn() } else if(cVal === 'JVMOptions'){ v.value = gFn().join(' ') } else { @@ -905,8 +925,6 @@ const settingsMinRAMLabel = document.getElementById('settingsMinRAMLabel') const settingsMemoryTotal = document.getElementById('settingsMemoryTotal') const settingsMemoryAvail = document.getElementById('settingsMemoryAvail') const settingsJavaExecDetails = document.getElementById('settingsJavaExecDetails') -const settingsJavaExecVal = document.getElementById('settingsJavaExecVal') -const settingsJavaExecSel = document.getElementById('settingsJavaExecSel') // Store maximum memory values. const SETTINGS_MAX_MEMORY = ConfigManager.getAbsoluteMaxRAM() @@ -1092,12 +1110,6 @@ function populateMemoryStatus(){ settingsMemoryAvail.innerHTML = Number(os.freemem()/1000000000).toFixed(1) + 'G' } -// Bind the executable file input to the display text input. -settingsJavaExecSel.onchange = (e) => { - settingsJavaExecVal.value = settingsJavaExecSel.files[0].path - populateJavaExecDetails(settingsJavaExecVal.value) -} - /** * Validate the provided executable path and display the data on * the UI. diff --git a/app/settings.ejs b/app/settings.ejs index b1ed183b..caa0f532 100644 --- a/app/settings.ejs +++ b/app/settings.ejs @@ -53,7 +53,6 @@ -