Added initial support for optional mods.

Optional mods are stored by ID in the configuration. Their enabled state is stored here. The mod configurations are updated each time the distro index is refreshed. Configurations are stored by server id. If the id no longer exists (changed/removed), the mod configuration is removed. If new optional mods are added, they are added to the configuration. If they are removed, they are removed from the configuration.

Currently only top level optional mods are supported.
This commit is contained in:
Daniel Scalzi 2018-06-23 15:17:26 -04:00
parent 4196856d31
commit 145a2fe77b
No known key found for this signature in database
GPG Key ID: 5CA2F145B63535F9
4 changed files with 166 additions and 26 deletions

View File

@ -247,6 +247,20 @@ class AssetGuard extends EventEmitter {
return cs.join('/') return cs.join('/')
} }
/**
* Resolves an artiface id without the version. For example,
* 'net.minecraftforge:forge:1.11.2-13.20.0.2282' becomes
* 'net.minecraftforge:forge'.
*
* @param {string} artifactid The artifact id string.
* @returns {string} The resolved identifier without the version.
*/
static _resolveWithoutVersion(artifactid){
let ps = artifactid.split(':')
return ps[0] + ':' + ps[1]
}
// #endregion // #endregion
// Static Hash Validation Functions // Static Hash Validation Functions

View File

@ -69,7 +69,8 @@ const DEFAULT_CONFIG = {
clientToken: uuidV4().replace(/-/g, ''), clientToken: uuidV4().replace(/-/g, ''),
selectedServer: null, // Resolved selectedServer: null, // Resolved
selectedAccount: null, selectedAccount: null,
authenticationDatabase: {} authenticationDatabase: {},
modConfigurations: []
} }
let config = null; let config = null;
@ -92,7 +93,6 @@ exports.save = function(){
*/ */
exports.load = function(){ exports.load = function(){
// Determine the effective configuration. // Determine the effective configuration.
//const EFFECTIVE_CONFIG = config == null ? DEFAULT_CONFIG : config
const filePath = path.join(dataPath, 'config.json') const filePath = path.join(dataPath, 'config.json')
if(!fs.existsSync(filePath)){ if(!fs.existsSync(filePath)){
@ -353,6 +353,57 @@ exports.setSelectedAccount = function(uuid){
return authAcc return authAcc
} }
/**
* Get an array of each mod configuration currently stored.
*
* @returns {Array.<Object>} An array of each stored mod configuration.
*/
exports.getModConfigurations = function(){
return config.modConfigurations
}
/**
* Set the array of stored mod configurations.
*
* @param {Array.<Object>} configurations An array of mod configurations.
*/
exports.setModConfigurations = function(configurations){
config.modConfigurations = configurations
}
/**
* Get the mod configuration for a specific server.
*
* @param {string} serverid The id of the server.
* @returns {Object} The mod configuration for the given server.
*/
exports.getModConfiguration = function(serverid){
const cfgs = config.modConfigurations
for(let i=0; i<cfgs.length; i++){
if(cfgs[i].id === serverid){
return cfgs[i]
}
}
return null
}
/**
* Set the mod configuration for a specific server. This overrides any existing value.
*
* @param {string} serverid The id of the server for the given mod configuration.
* @param {Object} configuration The mod configuration for the given server.
*/
exports.setModConfiguration = function(serverid, configuration){
const cfgs = config.modConfigurations
for(let i=0; i<cfgs.length; i++){
if(cfgs[i].id === serverid){
cfgs[i] = configuration
return
}
}
cfgs.push(configuration)
}
// User Configurable Settings // User Configurable Settings
// Java Settings // Java Settings

View File

@ -1,18 +1,14 @@
/** const AdmZip = require('adm-zip')
* The initial iteration of this file will not support optional submodules.
* Support will be added down the line, only top-level modules will recieve optional support.
*/
const AdmZip = require('adm-zip')
const {AssetGuard, Library} = require('./assetguard.js') const {AssetGuard, Library} = require('./assetguard.js')
const child_process = require('child_process') const child_process = require('child_process')
const ConfigManager = require('./configmanager.js') const ConfigManager = require('./configmanager.js')
const crypto = require('crypto') const crypto = require('crypto')
const fs = require('fs') const fs = require('fs')
const mkpath = require('mkdirp') const mkpath = require('mkdirp')
const os = require('os') const os = require('os')
const path = require('path') const path = require('path')
const rimraf = require('rimraf') const rimraf = require('rimraf')
const {URL} = require('url') const {URL} = require('url')
class ProcessBuilder { class ProcessBuilder {
@ -26,11 +22,6 @@ class ProcessBuilder {
this.fmlDir = path.join(this.commonDir, 'versions', this.server.id + '.json') this.fmlDir = path.join(this.commonDir, 'versions', this.server.id + '.json')
this.libPath = path.join(this.commonDir, 'libraries') this.libPath = path.join(this.commonDir, 'libraries')
} }
static shouldInclude(mdle){
//If the module should be included by default
return mdle.required == null || mdle.required.value == null || mdle.required.value === true || (mdle.required.value === false && (mdle.required.def == null || mdle.required.def === true))
}
/** /**
* Convienence method to run the functions typically used to build a process. * Convienence method to run the functions typically used to build a process.
@ -77,12 +68,19 @@ class ProcessBuilder {
resolveDefaultMods(options = {type: 'forgemod'}){ resolveDefaultMods(options = {type: 'forgemod'}){
//Returns array of default forge mods to load. //Returns array of default forge mods to load.
const mods = [] const mods = []
const mdles = this.server.modules const mdls = this.server.modules
const modCfg = ConfigManager.getModConfiguration(this.server.id).mods
for(let i=0; i<mdles.length; ++i){ for(let i=0; i<mdls.length; ++i){
if(mdles[i].type != null && mdles[i].type === options.type){ const mdl = mdls[i]
if(ProcessBuilder.shouldInclude(mdles[i])){ if(mdl.type != null && mdl.type === options.type){
mods.push(mdles[i]) if(mdl.required != null && mdl.required.value === false){
const val = modCfg[AssetGuard._resolveWithoutVersion(mdl.id)]
if(val === true){
mods.push(mdl)
}
} else {
mods.push(mdl)
} }
} }
} }

View File

@ -125,10 +125,86 @@ function showFatalStartupError(){
}, 750) }, 750)
} }
/**
* Common functions to perform after refreshing the distro index.
*
* @param {Object} data The distro index object.
*/
function onDistroRefresh(data){ function onDistroRefresh(data){
updateSelectedServer(AssetGuard.getServerById(ConfigManager.getSelectedServer()).name) updateSelectedServer(AssetGuard.getServerById(ConfigManager.getSelectedServer()).name)
refreshServerStatus() refreshServerStatus()
initNews() initNews()
syncModConfigurations(data)
}
/**
* Sync the mod configurations with the distro index.
*
* @param {Object} data The distro index object.
*/
function syncModConfigurations(data){
const syncedCfgs = []
const servers = data.servers
for(let i=0; i<servers.length; i++){
const id = servers[i].id
const mdls = servers[i].modules
const cfg = ConfigManager.getModConfiguration(servers[i].id)
if(cfg != null){
const modsOld = cfg.mods
const mods = {}
for(let j=0; j<mdls.length; j++){
const mdl = mdls[j]
if(mdl.type === 'forgemod'){
if(mdl.required != null){
if(mdl.required.value === false){
const mdlID = AssetGuard._resolveWithoutVersion(mdl.id)
if(modsOld[mdlID] == null){
mods[mdlID] = mdl.required.def != null ? mdl.required.def : true
} else {
mods[mdlID] = modsOld[mdlID]
}
}
}
}
}
syncedCfgs.push({
id,
mods
})
} else {
const mods = {}
for(let j=0; j<mdls.length; j++){
const mdl = mdls[j]
if(mdl.type === 'forgemod'){
if(mdl.required != null){
if(mdl.required.value === false){
mods[AssetGuard._resolveWithoutVersion(mdl.id)] = mdl.required.def != null ? mdl.required.def : true
}
}
}
}
syncedCfgs.push({
id,
mods
})
}
}
ConfigManager.setModConfigurations(syncedCfgs)
ConfigManager.save()
} }
function refreshDistributionIndex(remote, onSuccess, onError){ function refreshDistributionIndex(remote, onSuccess, onError){
@ -223,6 +299,7 @@ document.addEventListener('readystatechange', function(){
// Actions that must be performed after the distribution index is downloaded. // Actions that must be performed after the distribution index is downloaded.
ipcRenderer.on('distributionIndexDone', (event, data) => { ipcRenderer.on('distributionIndexDone', (event, data) => {
if(data != null) { if(data != null) {
syncModConfigurations(data)
if(document.readyState === 'complete'){ if(document.readyState === 'complete'){
showMainUI() showMainUI()
} else { } else {