mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 19:52:14 -08:00
d33476bcf9
Added new configuration option, launchDetached. Added validation function to ConfigManager to add missing keys (due to updates). Updated westeroscraft.json Game process can now be detached from the launcher.
493 lines
15 KiB
JavaScript
493 lines
15 KiB
JavaScript
const fs = require('fs')
|
|
const mkpath = require('mkdirp')
|
|
const os = require('os')
|
|
const path = require('path')
|
|
const uuidV4 = require('uuid/v4')
|
|
|
|
const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : '/var/local')
|
|
const dataPath = path.join(sysRoot, '.westeroscraft')
|
|
|
|
const firstLaunch = !fs.existsSync(dataPath)
|
|
|
|
function resolveMaxRAM(){
|
|
const mem = os.totalmem()
|
|
return mem >= 8000000000 ? '4G' : (mem >= 6000000000 ? '3G' : '2G')
|
|
}
|
|
|
|
/**
|
|
* 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: null,
|
|
jvmOptions: [
|
|
'-XX:+UseConcMarkSweepGC',
|
|
'-XX:+CMSIncrementalMode',
|
|
'-XX:-UseAdaptiveSizePolicy',
|
|
'-Xmn128M'
|
|
],
|
|
},
|
|
game: {
|
|
directory: path.join(dataPath, 'game'),
|
|
resWidth: 1280,
|
|
resHeight: 720,
|
|
fullscreen: false,
|
|
autoConnect: true,
|
|
launchDetached: true
|
|
},
|
|
launcher: {}
|
|
},
|
|
clientToken: uuidV4().replace(/-/g, ''),
|
|
selectedServer: null, // Resolved
|
|
selectedAccount: null,
|
|
authenticationDatabase: {}
|
|
}
|
|
|
|
let config = null;
|
|
|
|
// Persistance Utility Functions
|
|
|
|
/**
|
|
* 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')
|
|
}
|
|
|
|
/**
|
|
* 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(dataPath, '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'))
|
|
config = validateKeySet(DEFAULT_CONFIG, config)
|
|
exports.save()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Validate that the destination object has at least every field
|
|
* present in the source object. Assign a default value otherwise.
|
|
*
|
|
* @param {Object} srcObj The source object to reference against.
|
|
* @param {Object} destObj The destination object.
|
|
* @returns {Object} A validated destination object.
|
|
*/
|
|
function validateKeySet(srcObj, destObj){
|
|
if(srcObj == null){
|
|
srcObj = {}
|
|
}
|
|
const validationBlacklist = ['authenticationDatabase']
|
|
const keys = Object.keys(srcObj)
|
|
console.log(keys)
|
|
for(let i=0; i<keys.length; i++){
|
|
if(typeof destObj[keys[i]] === 'undefined'){
|
|
destObj[keys[i]] = srcObj[keys[i]]
|
|
} else if(typeof srcObj[keys[i]] === 'object' && srcObj[keys[i]] != null && !(srcObj[keys[i]] instanceof Array) && validationBlacklist.indexOf(keys[i]) === -1){
|
|
destObj[keys[i]] = validateKeySet(srcObj[keys[i]], destObj[keys[i]])
|
|
}
|
|
}
|
|
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.
|
|
*
|
|
* @returns {boolean} True if this is the first launch, otherwise false.
|
|
*/
|
|
exports.isFirstLaunch = function(){
|
|
return firstLaunch
|
|
}
|
|
|
|
/**
|
|
* Returns the name of the folder in the OS temp directory which we
|
|
* will use to extract and store native dependencies for game launch.
|
|
*
|
|
* @returns {string} The name of the folder.
|
|
*/
|
|
exports.getTempNativeFolder = function(){
|
|
return 'WCNatives'
|
|
}
|
|
|
|
// System Settings (Unconfigurable on UI)
|
|
|
|
/**
|
|
* Retrieve the launcher's Client Token.
|
|
* There is no default client token.
|
|
*
|
|
* @returns {string} The launcher's Client Token.
|
|
*/
|
|
exports.getClientToken = function(){
|
|
return 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
|
|
}
|
|
|
|
/**
|
|
* Get an array of each account currently authenticated by the launcher.
|
|
*
|
|
* @returns {Array.<Object>} An array of each stored authenticated account.
|
|
*/
|
|
exports.getAuthAccounts = function(){
|
|
return config.authenticationDatabase
|
|
}
|
|
|
|
/**
|
|
* Returns the authenticated account with the given uuid. Value may
|
|
* be null.
|
|
*
|
|
* @param {string} uuid The uuid of the authenticated account.
|
|
* @returns {Object} The authenticated account with the given uuid.
|
|
*/
|
|
exports.getAuthAccount = function(uuid){
|
|
return config.authenticationDatabase[uuid]
|
|
}
|
|
|
|
/**
|
|
* Update the access token of an authenticated account.
|
|
*
|
|
* @param {string} uuid The uuid of the authenticated account.
|
|
* @param {string} accessToken The new Access Token.
|
|
*
|
|
* @returns {Object} The authenticated account object created by this action.
|
|
*/
|
|
exports.updateAuthAccount = function(uuid, accessToken){
|
|
config.authenticationDatabase[uuid].accessToken = accessToken
|
|
return config.authenticationDatabase[uuid]
|
|
}
|
|
|
|
/**
|
|
* Adds an authenticated account to the database to be stored.
|
|
*
|
|
* @param {string} uuid The uuid of the authenticated account.
|
|
* @param {string} accessToken The accessToken of the authenticated account.
|
|
* @param {string} username The username (usually email) of the authenticated account.
|
|
* @param {string} displayName The in game name of the authenticated account.
|
|
*
|
|
* @returns {Object} The authenticated account object created by this action.
|
|
*/
|
|
exports.addAuthAccount = function(uuid, accessToken, username, displayName){
|
|
config.selectedAccount = uuid
|
|
config.authenticationDatabase[uuid] = {
|
|
accessToken,
|
|
username,
|
|
uuid,
|
|
displayName
|
|
}
|
|
return config.authenticationDatabase[uuid]
|
|
}
|
|
|
|
/**
|
|
* Remove an authenticated account from the database. If the account
|
|
* was also the selected account, a new one will be selected. If there
|
|
* are no accounts, the selected account will be null.
|
|
*
|
|
* @param {string} uuid The uuid of the authenticated account.
|
|
*
|
|
* @returns {boolean} True if the account was removed, false if it never existed.
|
|
*/
|
|
exports.removeAuthAccount = function(uuid){
|
|
if(config.authenticationDatabase[uuid] != null){
|
|
delete config.authenticationDatabase[uuid]
|
|
if(config.selectedAccount === uuid){
|
|
const keys = Object.keys(config.authenticationDatabase)
|
|
if(keys.length > 0){
|
|
config.selectedAccount = keys[0]
|
|
} else {
|
|
config.selectedAccount = null
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Get the currently selected authenticated account.
|
|
*
|
|
* @returns {Object} The selected authenticated account.
|
|
*/
|
|
exports.getSelectedAccount = function(){
|
|
return config.authenticationDatabase[config.selectedAccount]
|
|
}
|
|
|
|
/**
|
|
* Set the selected authenticated account.
|
|
*
|
|
* @param {string} uuid The UUID of the account which is to be set
|
|
* as the selected account.
|
|
*
|
|
* @returns {Object} The selected authenticated account.
|
|
*/
|
|
exports.setSelectedAccount = function(uuid){
|
|
const authAcc = config.authenticationDatabase[uuid]
|
|
if(authAcc != null) {
|
|
config.selectedAccount = uuid
|
|
}
|
|
return authAcc
|
|
}
|
|
|
|
// 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.<string>} 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.<string>} 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
|
|
}
|
|
|
|
/**
|
|
* Check if the game should launch as a detached process.
|
|
*
|
|
* @param {boolean} def Optional. If true, the default value will be returned.
|
|
* @returns {boolean} Whether or not the game will launch as a detached process.
|
|
*/
|
|
exports.isLaunchDetached = function(def = false){
|
|
return !def ? config.settings.game.launchDetached : DEFAULT_CONFIG.settings.game.launchDetached
|
|
}
|
|
|
|
/**
|
|
* Change the status of whether or not the game should launch as a detached process.
|
|
*
|
|
* @param {boolean} launchDetached Whether or not the game should launch as a detached process.
|
|
*/
|
|
exports.setLaunchDetached = function(launchDetached){
|
|
config.settings.game.launchDetached = launchDetached
|
|
} |