mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 19:52:14 -08:00
Compare commits
6 Commits
e314599d99
...
15b2efefde
Author | SHA1 | Date | |
---|---|---|---|
|
15b2efefde | ||
|
4273be5a4c | ||
|
8d26db70dc | ||
|
13f86339bb | ||
|
d9291d82e5 | ||
|
b9b67b7824 |
@ -1,5 +1,4 @@
|
|||||||
// Requirements
|
// Requirements
|
||||||
const AdmZip = require('adm-zip')
|
|
||||||
const async = require('async')
|
const async = require('async')
|
||||||
const child_process = require('child_process')
|
const child_process = require('child_process')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
@ -14,8 +13,6 @@ const request = require('request')
|
|||||||
const tar = require('tar-fs')
|
const tar = require('tar-fs')
|
||||||
const zlib = require('zlib')
|
const zlib = require('zlib')
|
||||||
|
|
||||||
const ConfigManager = require('./configmanager')
|
|
||||||
const DistroManager = require('./distromanager')
|
|
||||||
const isDev = require('./isdev')
|
const isDev = require('./isdev')
|
||||||
|
|
||||||
// Classes
|
// Classes
|
||||||
@ -40,86 +37,6 @@ class Asset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Class representing a mojang library. */
|
|
||||||
class Library extends Asset {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the process.platform OS names to match mojang's OS names.
|
|
||||||
*/
|
|
||||||
static mojangFriendlyOS(){
|
|
||||||
const opSys = process.platform
|
|
||||||
if (opSys === 'darwin') {
|
|
||||||
return 'osx'
|
|
||||||
} else if (opSys === 'win32'){
|
|
||||||
return 'windows'
|
|
||||||
} else if (opSys === 'linux'){
|
|
||||||
return 'linux'
|
|
||||||
} else {
|
|
||||||
return 'unknown_os'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether or not a library is valid for download on a particular OS, following
|
|
||||||
* the rule format specified in the mojang version data index. If the allow property has
|
|
||||||
* an OS specified, then the library can ONLY be downloaded on that OS. If the disallow
|
|
||||||
* property has instead specified an OS, the library can be downloaded on any OS EXCLUDING
|
|
||||||
* the one specified.
|
|
||||||
*
|
|
||||||
* If the rules are undefined, the natives property will be checked for a matching entry
|
|
||||||
* for the current OS.
|
|
||||||
*
|
|
||||||
* @param {Array.<Object>} rules The Library's download rules.
|
|
||||||
* @param {Object} natives The Library's natives object.
|
|
||||||
* @returns {boolean} True if the Library follows the specified rules, otherwise false.
|
|
||||||
*/
|
|
||||||
static validateRules(rules, natives){
|
|
||||||
if(rules == null) {
|
|
||||||
if(natives == null) {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return natives[Library.mojangFriendlyOS()] != null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(let rule of rules){
|
|
||||||
const action = rule.action
|
|
||||||
const osProp = rule.os
|
|
||||||
if(action != null && osProp != null){
|
|
||||||
const osName = osProp.name
|
|
||||||
const osMoj = Library.mojangFriendlyOS()
|
|
||||||
if(action === 'allow'){
|
|
||||||
return osName === osMoj
|
|
||||||
} else if(action === 'disallow'){
|
|
||||||
return osName !== osMoj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DistroModule extends Asset {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a DistroModule. This is for processing,
|
|
||||||
* not equivalent to the module objects in the
|
|
||||||
* distro index.
|
|
||||||
*
|
|
||||||
* @param {any} id The id of the asset.
|
|
||||||
* @param {string} hash The hash value of the asset.
|
|
||||||
* @param {number} size The size in bytes of the asset.
|
|
||||||
* @param {string} from The url where the asset can be found.
|
|
||||||
* @param {string} to The absolute local file path of the asset.
|
|
||||||
* @param {string} type The the module type.
|
|
||||||
*/
|
|
||||||
constructor(id, hash, size, from, to, type){
|
|
||||||
super(id, hash, size, from, to)
|
|
||||||
this.type = type
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing a download tracker. This is used to store meta data
|
* Class representing a download tracker. This is used to store meta data
|
||||||
* about a download queue, including the queue itself.
|
* about a download queue, including the queue itself.
|
||||||
@ -162,34 +79,6 @@ class Util {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
static isForgeGradle3(mcVersion, forgeVersion) {
|
|
||||||
|
|
||||||
if(Util.mcVersionAtLeast('1.13', mcVersion)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
const forgeVer = forgeVersion.split('-')[1]
|
|
||||||
|
|
||||||
const maxFG2 = [14, 23, 5, 2847]
|
|
||||||
const verSplit = forgeVer.split('.').map(v => Number(v))
|
|
||||||
|
|
||||||
for(let i=0; i<maxFG2.length; i++) {
|
|
||||||
if(verSplit[i] > maxFG2[i]) {
|
|
||||||
return true
|
|
||||||
} else if(verSplit[i] < maxFG2[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
} catch(err) {
|
|
||||||
throw new Error('Forge version is complex (changed).. launcher requires a patch.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static isAutoconnectBroken(forgeVersion) {
|
static isAutoconnectBroken(forgeVersion) {
|
||||||
|
|
||||||
const minWorking = [31, 2, 15]
|
const minWorking = [31, 2, 15]
|
||||||
@ -1002,26 +891,6 @@ class AssetGuard extends EventEmitter {
|
|||||||
return crypto.createHash(algo).update(buf).digest('hex')
|
return crypto.createHash(algo).update(buf).digest('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to parse a checksums file. This is specifically designed for
|
|
||||||
* the checksums.sha1 files found inside the forge scala dependencies.
|
|
||||||
*
|
|
||||||
* @param {string} content The string content of the checksums file.
|
|
||||||
* @returns {Object} An object with keys being the file names, and values being the hashes.
|
|
||||||
*/
|
|
||||||
static _parseChecksumsFile(content){
|
|
||||||
let finalContent = {}
|
|
||||||
let lines = content.split('\n')
|
|
||||||
for(let i=0; i<lines.length; i++){
|
|
||||||
let bits = lines[i].split(' ')
|
|
||||||
if(bits[1] == null) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
finalContent[bits[1]] = bits[0]
|
|
||||||
}
|
|
||||||
return finalContent
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate that a file exists and matches a given hash value.
|
* Validate that a file exists and matches a given hash value.
|
||||||
*
|
*
|
||||||
@ -1043,71 +912,6 @@ class AssetGuard extends EventEmitter {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates a file in the style used by forge's version index.
|
|
||||||
*
|
|
||||||
* @param {string} filePath The path of the file to validate.
|
|
||||||
* @param {Array.<string>} checksums The checksums listed in the forge version index.
|
|
||||||
* @returns {boolean} True if the file exists and the hashes match, otherwise false.
|
|
||||||
*/
|
|
||||||
static _validateForgeChecksum(filePath, checksums){
|
|
||||||
if(fs.existsSync(filePath)){
|
|
||||||
if(checksums == null || checksums.length === 0){
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
let buf = fs.readFileSync(filePath)
|
|
||||||
let calcdhash = AssetGuard._calculateHash(buf, 'sha1')
|
|
||||||
let valid = checksums.includes(calcdhash)
|
|
||||||
if(!valid && filePath.endsWith('.jar')){
|
|
||||||
valid = AssetGuard._validateForgeJar(filePath, checksums)
|
|
||||||
}
|
|
||||||
return valid
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates a forge jar file dependency who declares a checksums.sha1 file.
|
|
||||||
* This can be an expensive task as it usually requires that we calculate thousands
|
|
||||||
* of hashes.
|
|
||||||
*
|
|
||||||
* @param {Buffer} buf The buffer of the jar file.
|
|
||||||
* @param {Array.<string>} checksums The checksums listed in the forge version index.
|
|
||||||
* @returns {boolean} True if all hashes declared in the checksums.sha1 file match the actual hashes.
|
|
||||||
*/
|
|
||||||
static _validateForgeJar(buf, checksums){
|
|
||||||
// Double pass method was the quickest I found. I tried a version where we store data
|
|
||||||
// to only require a single pass, plus some quick cleanup but that seemed to take slightly more time.
|
|
||||||
|
|
||||||
const hashes = {}
|
|
||||||
let expected = {}
|
|
||||||
|
|
||||||
const zip = new AdmZip(buf)
|
|
||||||
const zipEntries = zip.getEntries()
|
|
||||||
|
|
||||||
//First pass
|
|
||||||
for(let i=0; i<zipEntries.length; i++){
|
|
||||||
let entry = zipEntries[i]
|
|
||||||
if(entry.entryName === 'checksums.sha1'){
|
|
||||||
expected = AssetGuard._parseChecksumsFile(zip.readAsText(entry))
|
|
||||||
}
|
|
||||||
hashes[entry.entryName] = AssetGuard._calculateHash(entry.getData(), 'sha1')
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!checksums.includes(hashes['checksums.sha1'])){
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check against expected
|
|
||||||
const expectedEntries = Object.keys(expected)
|
|
||||||
for(let i=0; i<expectedEntries.length; i++){
|
|
||||||
if(expected[expectedEntries[i]] !== hashes[expectedEntries[i]]){
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// Miscellaneous Static Functions
|
// Miscellaneous Static Functions
|
||||||
@ -1150,416 +954,10 @@ class AssetGuard extends EventEmitter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function which finalizes the forge installation process. This creates a 'version'
|
|
||||||
* instance for forge and saves its version.json file into that instance. If that
|
|
||||||
* instance already exists, the contents of the version.json file are read and returned
|
|
||||||
* in a promise.
|
|
||||||
*
|
|
||||||
* @param {Asset} asset The Asset object representing Forge.
|
|
||||||
* @param {string} commonPath The common path for shared game files.
|
|
||||||
* @returns {Promise.<Object>} A promise which resolves to the contents of forge's version.json.
|
|
||||||
*/
|
|
||||||
static _finalizeForgeAsset(asset, commonPath){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
fs.readFile(asset.to, (err, data) => {
|
|
||||||
const zip = new AdmZip(data)
|
|
||||||
const zipEntries = zip.getEntries()
|
|
||||||
|
|
||||||
for(let i=0; i<zipEntries.length; i++){
|
|
||||||
if(zipEntries[i].entryName === 'version.json'){
|
|
||||||
const forgeVersion = JSON.parse(zip.readAsText(zipEntries[i]))
|
|
||||||
const versionPath = path.join(commonPath, 'versions', forgeVersion.id)
|
|
||||||
const versionFile = path.join(versionPath, forgeVersion.id + '.json')
|
|
||||||
if(!fs.existsSync(versionFile)){
|
|
||||||
fs.ensureDirSync(versionPath)
|
|
||||||
fs.writeFileSync(path.join(versionPath, forgeVersion.id + '.json'), zipEntries[i].getData())
|
|
||||||
resolve(forgeVersion)
|
|
||||||
} else {
|
|
||||||
//Read the saved file to allow for user modifications.
|
|
||||||
resolve(JSON.parse(fs.readFileSync(versionFile, 'utf-8')))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//We didn't find forge's version.json.
|
|
||||||
reject('Unable to finalize Forge processing, version.json not found! Has forge changed their format?')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// Validation Functions
|
|
||||||
// #region
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the version data for a given minecraft version.
|
|
||||||
*
|
|
||||||
* @param {string} version The game version for which to load the index data.
|
|
||||||
* @param {boolean} force Optional. If true, the version index will be downloaded even if it exists locally. Defaults to false.
|
|
||||||
* @returns {Promise.<Object>} Promise which resolves to the version data object.
|
|
||||||
*/
|
|
||||||
loadVersionData(version, force = false){
|
|
||||||
const self = this
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
const versionPath = path.join(self.commonPath, 'versions', version)
|
|
||||||
const versionFile = path.join(versionPath, version + '.json')
|
|
||||||
if(!fs.existsSync(versionFile) || force){
|
|
||||||
const url = await self._getVersionDataUrl(version)
|
|
||||||
//This download will never be tracked as it's essential and trivial.
|
|
||||||
AssetGuard.logger.info('Preparing download of ' + version + ' assets.')
|
|
||||||
fs.ensureDirSync(versionPath)
|
|
||||||
const stream = request(url).pipe(fs.createWriteStream(versionFile))
|
|
||||||
stream.on('finish', () => {
|
|
||||||
resolve(JSON.parse(fs.readFileSync(versionFile)))
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
resolve(JSON.parse(fs.readFileSync(versionFile)))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses Mojang's version manifest and retrieves the url of the version
|
|
||||||
* data index.
|
|
||||||
*
|
|
||||||
* @param {string} version The version to lookup.
|
|
||||||
* @returns {Promise.<string>} Promise which resolves to the url of the version data index.
|
|
||||||
* If the version could not be found, resolves to null.
|
|
||||||
*/
|
|
||||||
_getVersionDataUrl(version){
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request('https://launchermeta.mojang.com/mc/game/version_manifest.json', (error, resp, body) => {
|
|
||||||
if(error){
|
|
||||||
reject(error)
|
|
||||||
} else {
|
|
||||||
const manifest = JSON.parse(body)
|
|
||||||
|
|
||||||
for(let v of manifest.versions){
|
|
||||||
if(v.id === version){
|
|
||||||
resolve(v.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(null)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Asset (Category=''') Validation Functions
|
|
||||||
// #region
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public asset validation function. This function will handle the validation of assets.
|
|
||||||
* It will parse the asset index specified in the version data, analyzing each
|
|
||||||
* asset entry. In this analysis it will check to see if the local file exists and is valid.
|
|
||||||
* If not, it will be added to the download queue for the 'assets' identifier.
|
|
||||||
*
|
|
||||||
* @param {Object} versionData The version data for the assets.
|
|
||||||
* @param {boolean} force Optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
validateAssets(versionData, force = false){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
self._assetChainIndexData(versionData, force).then(() => {
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
//Chain the asset tasks to provide full async. The below functions are private.
|
|
||||||
/**
|
|
||||||
* Private function used to chain the asset validation process. This function retrieves
|
|
||||||
* the index data.
|
|
||||||
* @param {Object} versionData
|
|
||||||
* @param {boolean} force
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
_assetChainIndexData(versionData, force = false){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
//Asset index constants.
|
|
||||||
const assetIndex = versionData.assetIndex
|
|
||||||
const name = assetIndex.id + '.json'
|
|
||||||
const indexPath = path.join(self.commonPath, 'assets', 'indexes')
|
|
||||||
const assetIndexLoc = path.join(indexPath, name)
|
|
||||||
|
|
||||||
let data = null
|
|
||||||
if(!fs.existsSync(assetIndexLoc) || force){
|
|
||||||
AssetGuard.logger.info('Downloading ' + versionData.id + ' asset index.')
|
|
||||||
fs.ensureDirSync(indexPath)
|
|
||||||
const stream = request(assetIndex.url).pipe(fs.createWriteStream(assetIndexLoc))
|
|
||||||
stream.on('finish', () => {
|
|
||||||
data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
|
|
||||||
self._assetChainValidateAssets(versionData, data).then(() => {
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
|
|
||||||
self._assetChainValidateAssets(versionData, data).then(() => {
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Private function used to chain the asset validation process. This function processes
|
|
||||||
* the assets and enqueues missing or invalid files.
|
|
||||||
* @param {Object} versionData
|
|
||||||
* @param {boolean} force
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
_assetChainValidateAssets(versionData, indexData){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
//Asset constants
|
|
||||||
const resourceURL = 'https://resources.download.minecraft.net/'
|
|
||||||
const localPath = path.join(self.commonPath, 'assets')
|
|
||||||
const objectPath = path.join(localPath, 'objects')
|
|
||||||
|
|
||||||
const assetDlQueue = []
|
|
||||||
let dlSize = 0
|
|
||||||
let acc = 0
|
|
||||||
const total = Object.keys(indexData.objects).length
|
|
||||||
//const objKeys = Object.keys(data.objects)
|
|
||||||
async.forEachOfLimit(indexData.objects, 10, (value, key, cb) => {
|
|
||||||
acc++
|
|
||||||
self.emit('progress', 'assets', acc, total)
|
|
||||||
const hash = value.hash
|
|
||||||
const assetName = path.join(hash.substring(0, 2), hash)
|
|
||||||
const urlName = hash.substring(0, 2) + '/' + hash
|
|
||||||
const ast = new Asset(key, hash, value.size, resourceURL + urlName, path.join(objectPath, assetName))
|
|
||||||
if(!AssetGuard._validateLocal(ast.to, 'sha1', ast.hash)){
|
|
||||||
dlSize += (ast.size*1)
|
|
||||||
assetDlQueue.push(ast)
|
|
||||||
}
|
|
||||||
cb()
|
|
||||||
}, (err) => {
|
|
||||||
self.assets = new DLTracker(assetDlQueue, dlSize)
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
|
|
||||||
// Library (Category=''') Validation Functions
|
|
||||||
// #region
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public library validation function. This function will handle the validation of libraries.
|
|
||||||
* It will parse the version data, analyzing each library entry. In this analysis, it will
|
|
||||||
* check to see if the local file exists and is valid. If not, it will be added to the download
|
|
||||||
* queue for the 'libraries' identifier.
|
|
||||||
*
|
|
||||||
* @param {Object} versionData The version data for the assets.
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
validateLibraries(versionData){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
|
|
||||||
const libArr = versionData.libraries
|
|
||||||
const libPath = path.join(self.commonPath, 'libraries')
|
|
||||||
|
|
||||||
const libDlQueue = []
|
|
||||||
let dlSize = 0
|
|
||||||
|
|
||||||
//Check validity of each library. If the hashs don't match, download the library.
|
|
||||||
async.eachLimit(libArr, 5, (lib, cb) => {
|
|
||||||
if(Library.validateRules(lib.rules, lib.natives)){
|
|
||||||
let artifact = (lib.natives == null) ? lib.downloads.artifact : lib.downloads.classifiers[lib.natives[Library.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))]
|
|
||||||
const libItm = new Library(lib.name, artifact.sha1, artifact.size, artifact.url, path.join(libPath, artifact.path))
|
|
||||||
if(!AssetGuard._validateLocal(libItm.to, 'sha1', libItm.hash)){
|
|
||||||
dlSize += (libItm.size*1)
|
|
||||||
libDlQueue.push(libItm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cb()
|
|
||||||
}, (err) => {
|
|
||||||
self.libraries = new DLTracker(libDlQueue, dlSize)
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
|
|
||||||
// Miscellaneous (Category=files) Validation Functions
|
|
||||||
// #region
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Public miscellaneous mojang file validation function. These files will be enqueued under
|
|
||||||
* the 'files' identifier.
|
|
||||||
*
|
|
||||||
* @param {Object} versionData The version data for the assets.
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
validateMiscellaneous(versionData){
|
|
||||||
const self = this
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
await self.validateClient(versionData)
|
|
||||||
await self.validateLogConfig(versionData)
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate client file - artifact renamed from client.jar to '{version}'.jar.
|
|
||||||
*
|
|
||||||
* @param {Object} versionData The version data for the assets.
|
|
||||||
* @param {boolean} force Optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
validateClient(versionData, force = false){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const clientData = versionData.downloads.client
|
|
||||||
const version = versionData.id
|
|
||||||
const targetPath = path.join(self.commonPath, 'versions', version)
|
|
||||||
const targetFile = version + '.jar'
|
|
||||||
|
|
||||||
let client = new Asset(version + ' client', clientData.sha1, clientData.size, clientData.url, path.join(targetPath, targetFile))
|
|
||||||
|
|
||||||
if(!AssetGuard._validateLocal(client.to, 'sha1', client.hash) || force){
|
|
||||||
self.files.dlqueue.push(client)
|
|
||||||
self.files.dlsize += client.size*1
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate log config.
|
|
||||||
*
|
|
||||||
* @param {Object} versionData The version data for the assets.
|
|
||||||
* @param {boolean} force Optional. If true, the asset index will be downloaded even if it exists locally. Defaults to false.
|
|
||||||
* @returns {Promise.<void>} An empty promise to indicate the async processing has completed.
|
|
||||||
*/
|
|
||||||
validateLogConfig(versionData){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const client = versionData.logging.client
|
|
||||||
const file = client.file
|
|
||||||
const targetPath = path.join(self.commonPath, 'assets', 'log_configs')
|
|
||||||
|
|
||||||
let logConfig = new Asset(file.id, file.sha1, file.size, file.url, path.join(targetPath, file.id))
|
|
||||||
|
|
||||||
if(!AssetGuard._validateLocal(logConfig.to, 'sha1', logConfig.hash)){
|
|
||||||
self.files.dlqueue.push(logConfig)
|
|
||||||
self.files.dlsize += logConfig.size*1
|
|
||||||
resolve()
|
|
||||||
} else {
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
|
|
||||||
// Distribution (Category=forge) Validation Functions
|
|
||||||
// #region
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the distribution.
|
|
||||||
*
|
|
||||||
* @param {Server} server The Server to validate.
|
|
||||||
* @returns {Promise.<Object>} A promise which resolves to the server distribution object.
|
|
||||||
*/
|
|
||||||
validateDistribution(server){
|
|
||||||
const self = this
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
self.forge = self._parseDistroModules(server.getModules(), server.getMinecraftVersion(), server.getID())
|
|
||||||
resolve(server)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
_parseDistroModules(modules, version, servid){
|
|
||||||
let alist = []
|
|
||||||
let asize = 0
|
|
||||||
for(let ob of modules){
|
|
||||||
let obArtifact = ob.getArtifact()
|
|
||||||
let obPath = obArtifact.getPath()
|
|
||||||
let artifact = new DistroModule(ob.getIdentifier(), obArtifact.getHash(), obArtifact.getSize(), obArtifact.getURL(), obPath, ob.getType())
|
|
||||||
const validationPath = obPath.toLowerCase().endsWith('.pack.xz') ? obPath.substring(0, obPath.toLowerCase().lastIndexOf('.pack.xz')) : obPath
|
|
||||||
if(!AssetGuard._validateLocal(validationPath, 'MD5', artifact.hash)){
|
|
||||||
asize += artifact.size*1
|
|
||||||
alist.push(artifact)
|
|
||||||
if(validationPath !== obPath) this.extractQueue.push(obPath)
|
|
||||||
}
|
|
||||||
//Recursively process the submodules then combine the results.
|
|
||||||
if(ob.getSubModules() != null){
|
|
||||||
let dltrack = this._parseDistroModules(ob.getSubModules(), version, servid)
|
|
||||||
asize += dltrack.dlsize*1
|
|
||||||
alist = alist.concat(dltrack.dlqueue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new DLTracker(alist, asize)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads Forge's version.json data into memory for the specified server id.
|
|
||||||
*
|
|
||||||
* @param {string} server The Server to load Forge data for.
|
|
||||||
* @returns {Promise.<Object>} A promise which resolves to Forge's version.json data.
|
|
||||||
*/
|
|
||||||
loadForgeData(server){
|
|
||||||
const self = this
|
|
||||||
return new Promise(async (resolve, reject) => {
|
|
||||||
const modules = server.getModules()
|
|
||||||
for(let ob of modules){
|
|
||||||
const type = ob.getType()
|
|
||||||
if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Forge){
|
|
||||||
if(Util.isForgeGradle3(server.getMinecraftVersion(), ob.getVersion())){
|
|
||||||
// Read Manifest
|
|
||||||
for(let sub of ob.getSubModules()){
|
|
||||||
if(sub.getType() === DistroManager.Types.VersionManifest){
|
|
||||||
resolve(JSON.parse(fs.readFileSync(sub.getArtifact().getPath(), 'utf-8')))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reject('No forge version manifest found!')
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
let obArtifact = ob.getArtifact()
|
|
||||||
let obPath = obArtifact.getPath()
|
|
||||||
let asset = new DistroModule(ob.getIdentifier(), obArtifact.getHash(), obArtifact.getSize(), obArtifact.getURL(), obPath, type)
|
|
||||||
try {
|
|
||||||
let forgeData = await AssetGuard._finalizeForgeAsset(asset, self.commonPath)
|
|
||||||
resolve(forgeData)
|
|
||||||
} catch (err){
|
|
||||||
reject(err)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
reject('No forge module found!')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
_parseForgeLibraries(){
|
|
||||||
/* TODO
|
|
||||||
* Forge asset validations are already implemented. When there's nothing much
|
|
||||||
* to work on, implement forge downloads using forge's version.json. This is to
|
|
||||||
* have the code on standby if we ever need it (since it's half implemented already).
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
|
||||||
|
|
||||||
// Java (Category=''') Validation (download) Functions
|
// Java (Category=''') Validation (download) Functions
|
||||||
// #region
|
// #region
|
||||||
|
|
||||||
@ -1642,43 +1040,6 @@ class AssetGuard extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _enqueueMojangJRE(dir){
|
|
||||||
// return new Promise((resolve, reject) => {
|
|
||||||
// // Mojang does not host the JRE for linux.
|
|
||||||
// if(process.platform === 'linux'){
|
|
||||||
// resolve(false)
|
|
||||||
// }
|
|
||||||
// AssetGuard.loadMojangLauncherData().then(data => {
|
|
||||||
// if(data != null) {
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// const mJRE = data[Library.mojangFriendlyOS()]['64'].jre
|
|
||||||
// const url = mJRE.url
|
|
||||||
|
|
||||||
// request.head(url, (err, resp, body) => {
|
|
||||||
// if(err){
|
|
||||||
// resolve(false)
|
|
||||||
// } else {
|
|
||||||
// const name = url.substring(url.lastIndexOf('/')+1)
|
|
||||||
// const fDir = path.join(dir, name)
|
|
||||||
// const jre = new Asset('jre' + mJRE.version, mJRE.sha1, resp.headers['content-length'], url, fDir)
|
|
||||||
// this.java = new DLTracker([jre], jre.size, a => {
|
|
||||||
// fs.readFile(a.to, (err, data) => {
|
|
||||||
// // Data buffer needs to be decompressed from lzma,
|
|
||||||
// // not really possible using node.js
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// } catch (err){
|
|
||||||
// resolve(false)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
@ -1838,57 +1199,11 @@ class AssetGuard extends EventEmitter {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateEverything(serverid, dev = false){
|
|
||||||
|
|
||||||
try {
|
|
||||||
if(!ConfigManager.isLoaded()){
|
|
||||||
ConfigManager.load()
|
|
||||||
}
|
|
||||||
DistroManager.setDevMode(dev)
|
|
||||||
const dI = await DistroManager.pullLocal()
|
|
||||||
|
|
||||||
const server = dI.getServer(serverid)
|
|
||||||
|
|
||||||
// Validate Everything
|
|
||||||
|
|
||||||
await this.validateDistribution(server)
|
|
||||||
this.emit('validate', 'distribution')
|
|
||||||
const versionData = await this.loadVersionData(server.getMinecraftVersion())
|
|
||||||
this.emit('validate', 'version')
|
|
||||||
await this.validateAssets(versionData)
|
|
||||||
this.emit('validate', 'assets')
|
|
||||||
await this.validateLibraries(versionData)
|
|
||||||
this.emit('validate', 'libraries')
|
|
||||||
await this.validateMiscellaneous(versionData)
|
|
||||||
this.emit('validate', 'files')
|
|
||||||
await this.processDlQueues()
|
|
||||||
//this.emit('complete', 'download')
|
|
||||||
const forgeData = await this.loadForgeData(server)
|
|
||||||
|
|
||||||
return {
|
|
||||||
versionData,
|
|
||||||
forgeData
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err){
|
|
||||||
return {
|
|
||||||
versionData: null,
|
|
||||||
forgeData: null,
|
|
||||||
error: err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
Util,
|
|
||||||
AssetGuard,
|
AssetGuard,
|
||||||
JavaGuard,
|
JavaGuard
|
||||||
Asset,
|
|
||||||
Library
|
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
|
const { mcVersionAtLeast } = require('helios-core/common')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
@ -64,27 +65,6 @@ function resolveMinRAM(){
|
|||||||
return resolveMaxRAM()
|
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<des.length; i++){
|
|
||||||
if(!(parseInt(act[i]) >= parseInt(des[i]))){
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Three types of values:
|
* Three types of values:
|
||||||
* Static = Explicitly declared.
|
* Static = Explicitly declared.
|
||||||
|
@ -1,621 +1,15 @@
|
|||||||
const fs = require('fs')
|
const { DistributionAPI } = require('helios-core/common')
|
||||||
const path = require('path')
|
|
||||||
const request = require('request')
|
|
||||||
const { LoggerUtil } = require('helios-core')
|
|
||||||
|
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('DistroManager')
|
exports.REMOTE_DISTRO_URL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
|
||||||
|
|
||||||
/**
|
const api = new DistributionAPI(
|
||||||
* Represents the download information
|
ConfigManager.getLauncherDirectory(),
|
||||||
* for a specific module.
|
null, // Injected forcefully by the preloader.
|
||||||
*/
|
null, // Injected forcefully by the preloader.
|
||||||
class Artifact {
|
exports.REMOTE_DISTRO_URL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
exports.DistroAPI = api
|
||||||
* 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)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.<Module>} 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.<Module>} 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.<Server>} 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.<DistroIndex>}
|
|
||||||
*/
|
|
||||||
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.<DistroIndex>}
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
}
|
|
@ -4,9 +4,11 @@ const os = require('os')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
const DistroManager = require('./distromanager')
|
const { DistroAPI } = require('./distromanager')
|
||||||
const LangLoader = require('./langloader')
|
const LangLoader = require('./langloader')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const { HeliosDistribution } = require('helios-core/common')
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('Preloader')
|
const logger = LoggerUtil.getLogger('Preloader')
|
||||||
|
|
||||||
@ -15,16 +17,25 @@ logger.info('Loading..')
|
|||||||
// Load ConfigManager
|
// Load ConfigManager
|
||||||
ConfigManager.load()
|
ConfigManager.load()
|
||||||
|
|
||||||
|
// Yuck!
|
||||||
|
// TODO Fix this
|
||||||
|
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
|
||||||
|
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
|
||||||
|
|
||||||
// Load Strings
|
// Load Strings
|
||||||
LangLoader.loadLanguage('en_US')
|
LangLoader.loadLanguage('en_US')
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HeliosDistribution} data
|
||||||
|
*/
|
||||||
function onDistroLoad(data){
|
function onDistroLoad(data){
|
||||||
if(data != null){
|
if(data != null){
|
||||||
|
|
||||||
// Resolve the selected server if its value has yet to be set.
|
// 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..')
|
logger.info('Determining default selected server..')
|
||||||
ConfigManager.setSelectedServer(data.getMainServer().getID())
|
ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
|
||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,35 +43,20 @@ function onDistroLoad(data){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure Distribution is downloaded and cached.
|
// Ensure Distribution is downloaded and cached.
|
||||||
DistroManager.pullRemote().then((data) => {
|
DistroAPI.getDistribution()
|
||||||
logger.info('Loaded distribution index.')
|
.then(heliosDistro => {
|
||||||
|
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) => {
|
|
||||||
|
|
||||||
|
onDistroLoad(heliosDistro)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
logger.info('Failed to load an older version of the distribution index.')
|
logger.info('Failed to load an older version of the distribution index.')
|
||||||
logger.info('Application cannot run.')
|
logger.info('Application cannot run.')
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
|
|
||||||
onDistroLoad(null)
|
onDistroLoad(null)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
// Clean up temp dir incase previous launches ended unexpectedly.
|
// Clean up temp dir incase previous launches ended unexpectedly.
|
||||||
fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
|
fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
|
||||||
if(err){
|
if(err){
|
||||||
|
@ -3,20 +3,19 @@ const child_process = require('child_process')
|
|||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
|
const { getMojangOS, isLibraryCompatible, mcVersionAtLeast } = require('helios-core/common')
|
||||||
|
const { Type } = require('helios-distribution-types')
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { URL } = require('url')
|
|
||||||
|
|
||||||
const { Util, Library } = require('./assetguard')
|
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
const DistroManager = require('./distromanager')
|
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('ProcessBuilder')
|
const logger = LoggerUtil.getLogger('ProcessBuilder')
|
||||||
|
|
||||||
class ProcessBuilder {
|
class ProcessBuilder {
|
||||||
|
|
||||||
constructor(distroServer, versionData, forgeData, authUser, launcherVersion){
|
constructor(distroServer, versionData, forgeData, authUser, launcherVersion){
|
||||||
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.getID())
|
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.rawServer.id)
|
||||||
this.commonDir = ConfigManager.getCommonDirectory()
|
this.commonDir = ConfigManager.getCommonDirectory()
|
||||||
this.server = distroServer
|
this.server = distroServer
|
||||||
this.versionData = versionData
|
this.versionData = versionData
|
||||||
@ -41,10 +40,10 @@ class ProcessBuilder {
|
|||||||
process.throwDeprecation = true
|
process.throwDeprecation = true
|
||||||
this.setupLiteLoader()
|
this.setupLiteLoader()
|
||||||
logger.info('Using liteloader:', this.usingLiteLoader)
|
logger.info('Using liteloader:', this.usingLiteLoader)
|
||||||
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.getID()).mods, this.server.getModules())
|
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules)
|
||||||
|
|
||||||
// Mod list below 1.13
|
// Mod list below 1.13
|
||||||
if(!Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
|
if(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
||||||
this.constructJSONModList('forge', modObj.fMods, true)
|
this.constructJSONModList('forge', modObj.fMods, true)
|
||||||
if(this.usingLiteLoader){
|
if(this.usingLiteLoader){
|
||||||
this.constructJSONModList('liteloader', modObj.lMods, true)
|
this.constructJSONModList('liteloader', modObj.lMods, true)
|
||||||
@ -54,14 +53,14 @@ class ProcessBuilder {
|
|||||||
const uberModArr = modObj.fMods.concat(modObj.lMods)
|
const uberModArr = modObj.fMods.concat(modObj.lMods)
|
||||||
let args = this.constructJVMArguments(uberModArr, tempNativePath)
|
let args = this.constructJVMArguments(uberModArr, tempNativePath)
|
||||||
|
|
||||||
if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
|
if(mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
||||||
//args = args.concat(this.constructModArguments(modObj.fMods))
|
//args = args.concat(this.constructModArguments(modObj.fMods))
|
||||||
args = args.concat(this.constructModList(modObj.fMods))
|
args = args.concat(this.constructModList(modObj.fMods))
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('Launch Arguments:', args)
|
logger.info('Launch Arguments:', args)
|
||||||
|
|
||||||
const child = child_process.spawn(ConfigManager.getJavaExecutable(this.server.getID()), args, {
|
const child = child_process.spawn(ConfigManager.getJavaExecutable(this.server.rawServer.id), args, {
|
||||||
cwd: this.gameDir,
|
cwd: this.gameDir,
|
||||||
detached: ConfigManager.getLaunchDetached()
|
detached: ConfigManager.getLaunchDetached()
|
||||||
})
|
})
|
||||||
@ -122,7 +121,7 @@ class ProcessBuilder {
|
|||||||
* @returns {boolean} True if the mod is enabled, false otherwise.
|
* @returns {boolean} True if the mod is enabled, false otherwise.
|
||||||
*/
|
*/
|
||||||
static isModEnabled(modCfg, required = null){
|
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 +131,20 @@ class ProcessBuilder {
|
|||||||
* mod. It must not be declared as a submodule.
|
* mod. It must not be declared as a submodule.
|
||||||
*/
|
*/
|
||||||
setupLiteLoader(){
|
setupLiteLoader(){
|
||||||
for(let ll of this.server.getModules()){
|
for(let ll of this.server.modules){
|
||||||
if(ll.getType() === DistroManager.Types.LiteLoader){
|
if(ll.rawModule.type === Type.LiteLoader){
|
||||||
if(!ll.getRequired().isRequired()){
|
if(!ll.getRequired().value){
|
||||||
const modCfg = ConfigManager.getModConfiguration(this.server.getID()).mods
|
const modCfg = ConfigManager.getModConfiguration(this.server.rawServer.id).mods
|
||||||
if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessID()], ll.getRequired())){
|
if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessMavenIdentifier()], ll.getRequired())){
|
||||||
if(fs.existsSync(ll.getArtifact().getPath())){
|
if(fs.existsSync(ll.getPath())){
|
||||||
this.usingLiteLoader = true
|
this.usingLiteLoader = true
|
||||||
this.llPath = ll.getArtifact().getPath()
|
this.llPath = ll.getPath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(fs.existsSync(ll.getArtifact().getPath())){
|
if(fs.existsSync(ll.getPath())){
|
||||||
this.usingLiteLoader = true
|
this.usingLiteLoader = true
|
||||||
this.llPath = ll.getArtifact().getPath()
|
this.llPath = ll.getPath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,20 +165,20 @@ class ProcessBuilder {
|
|||||||
let lMods = []
|
let lMods = []
|
||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.getType()
|
const type = mdl.rawModule.type
|
||||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
const o = !mdl.getRequired().isRequired()
|
const o = !mdl.getRequired().value
|
||||||
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessID()], mdl.getRequired())
|
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
|
||||||
if(!o || (o && e)){
|
if(!o || (o && e)){
|
||||||
if(mdl.hasSubModules()){
|
if(mdl.subModules.length > 0){
|
||||||
const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessID()].mods, mdl.getSubModules())
|
const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessMavenIdentifier()].mods, mdl.subModules)
|
||||||
fMods = fMods.concat(v.fMods)
|
fMods = fMods.concat(v.fMods)
|
||||||
lMods = lMods.concat(v.lMods)
|
lMods = lMods.concat(v.lMods)
|
||||||
if(mdl.type === DistroManager.Types.LiteLoader){
|
if(mdl.type === Type.LiteLoader){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(mdl.type === DistroManager.Types.ForgeMod){
|
if(mdl.type === Type.ForgeMod){
|
||||||
fMods.push(mdl)
|
fMods.push(mdl)
|
||||||
} else {
|
} else {
|
||||||
lMods.push(mdl)
|
lMods.push(mdl)
|
||||||
@ -307,14 +306,11 @@ class ProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_processAutoConnectArg(args){
|
_processAutoConnectArg(args){
|
||||||
if(ConfigManager.getAutoConnect() && this.server.isAutoConnect()){
|
if(ConfigManager.getAutoConnect() && this.server.rawServer.autoconnect){
|
||||||
const serverURL = new URL('my://' + this.server.getAddress())
|
|
||||||
args.push('--server')
|
args.push('--server')
|
||||||
args.push(serverURL.hostname)
|
args.push(this.server.hostname)
|
||||||
if(serverURL.port){
|
args.push('--port')
|
||||||
args.push('--port')
|
args.push(this.server.port)
|
||||||
args.push(serverURL.port)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +322,7 @@ class ProcessBuilder {
|
|||||||
* @returns {Array.<string>} An array containing the full JVM arguments for this process.
|
* @returns {Array.<string>} An array containing the full JVM arguments for this process.
|
||||||
*/
|
*/
|
||||||
constructJVMArguments(mods, tempNativePath){
|
constructJVMArguments(mods, tempNativePath){
|
||||||
if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
|
if(mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
||||||
return this._constructJVMArguments113(mods, tempNativePath)
|
return this._constructJVMArguments113(mods, tempNativePath)
|
||||||
} else {
|
} else {
|
||||||
return this._constructJVMArguments112(mods, tempNativePath)
|
return this._constructJVMArguments112(mods, tempNativePath)
|
||||||
@ -354,9 +350,9 @@ class ProcessBuilder {
|
|||||||
args.push('-Xdock:name=HeliosLauncher')
|
args.push('-Xdock:name=HeliosLauncher')
|
||||||
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
||||||
}
|
}
|
||||||
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.getID()))
|
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.rawServer.id))
|
||||||
args.push('-Xms' + ConfigManager.getMinRAM(this.server.getID()))
|
args.push('-Xms' + ConfigManager.getMinRAM(this.server.rawServer.id))
|
||||||
args = args.concat(ConfigManager.getJVMOptions(this.server.getID()))
|
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
|
||||||
args.push('-Djava.library.path=' + tempNativePath)
|
args.push('-Djava.library.path=' + tempNativePath)
|
||||||
|
|
||||||
// Main Java Class
|
// Main Java Class
|
||||||
@ -405,9 +401,9 @@ class ProcessBuilder {
|
|||||||
args.push('-Xdock:name=HeliosLauncher')
|
args.push('-Xdock:name=HeliosLauncher')
|
||||||
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
||||||
}
|
}
|
||||||
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.getID()))
|
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.rawServer.id))
|
||||||
args.push('-Xms' + ConfigManager.getMinRAM(this.server.getID()))
|
args.push('-Xms' + ConfigManager.getMinRAM(this.server.rawServer.id))
|
||||||
args = args.concat(ConfigManager.getJVMOptions(this.server.getID()))
|
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
|
||||||
|
|
||||||
// Main Java Class
|
// Main Java Class
|
||||||
args.push(this.forgeData.mainClass)
|
args.push(this.forgeData.mainClass)
|
||||||
@ -421,7 +417,7 @@ class ProcessBuilder {
|
|||||||
let checksum = 0
|
let checksum = 0
|
||||||
for(let rule of args[i].rules){
|
for(let rule of args[i].rules){
|
||||||
if(rule.os != null){
|
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))){
|
&& (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){
|
||||||
if(rule.action === 'allow'){
|
if(rule.action === 'allow'){
|
||||||
checksum++
|
checksum++
|
||||||
@ -471,7 +467,7 @@ class ProcessBuilder {
|
|||||||
break
|
break
|
||||||
case 'version_name':
|
case 'version_name':
|
||||||
//val = versionData.id
|
//val = versionData.id
|
||||||
val = this.server.getID()
|
val = this.server.rawServer.id
|
||||||
break
|
break
|
||||||
case 'game_directory':
|
case 'game_directory':
|
||||||
val = this.gameDir
|
val = this.gameDir
|
||||||
@ -523,7 +519,7 @@ class ProcessBuilder {
|
|||||||
// Autoconnect
|
// Autoconnect
|
||||||
let isAutoconnectBroken
|
let isAutoconnectBroken
|
||||||
try {
|
try {
|
||||||
isAutoconnectBroken = Util.isAutoconnectBroken(this.forgeData.id.split('-')[2])
|
isAutoconnectBroken = ProcessBuilder.isAutoconnectBroken(this.forgeData.id.split('-')[2])
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
logger.error('Forge version format changed.. assuming autoconnect works.')
|
logger.error('Forge version format changed.. assuming autoconnect works.')
|
||||||
@ -569,7 +565,7 @@ class ProcessBuilder {
|
|||||||
break
|
break
|
||||||
case 'version_name':
|
case 'version_name':
|
||||||
//val = versionData.id
|
//val = versionData.id
|
||||||
val = this.server.getID()
|
val = this.server.rawServer.id
|
||||||
break
|
break
|
||||||
case 'game_directory':
|
case 'game_directory':
|
||||||
val = this.gameDir
|
val = this.gameDir
|
||||||
@ -668,7 +664,7 @@ class ProcessBuilder {
|
|||||||
classpathArg(mods, tempNativePath){
|
classpathArg(mods, tempNativePath){
|
||||||
let cpArgs = []
|
let cpArgs = []
|
||||||
|
|
||||||
if(!Util.mcVersionAtLeast('1.17', this.server.getMinecraftVersion())) {
|
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion)) {
|
||||||
// Add the version.jar to the classpath.
|
// Add the version.jar to the classpath.
|
||||||
// Must not be added to the classpath for Forge 1.17+.
|
// Must not be added to the classpath for Forge 1.17+.
|
||||||
const version = this.versionData.id
|
const version = this.versionData.id
|
||||||
@ -714,13 +710,13 @@ class ProcessBuilder {
|
|||||||
fs.ensureDirSync(tempNativePath)
|
fs.ensureDirSync(tempNativePath)
|
||||||
for(let i=0; i<libArr.length; i++){
|
for(let i=0; i<libArr.length; i++){
|
||||||
const lib = libArr[i]
|
const lib = libArr[i]
|
||||||
if(Library.validateRules(lib.rules, lib.natives)){
|
if(isLibraryCompatible(lib.rules, lib.natives)){
|
||||||
|
|
||||||
// Pre-1.19 has a natives object.
|
// Pre-1.19 has a natives object.
|
||||||
if(lib.natives != null) {
|
if(lib.natives != null) {
|
||||||
// Extract the native library.
|
// Extract the native library.
|
||||||
const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/']
|
const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/']
|
||||||
const artifact = lib.downloads.classifiers[lib.natives[Library.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))]
|
const artifact = lib.downloads.classifiers[lib.natives[getMojangOS()].replace('${arch}', process.arch.replace('x', ''))]
|
||||||
|
|
||||||
// Location of native zip.
|
// Location of native zip.
|
||||||
const to = path.join(this.libPath, artifact.path)
|
const to = path.join(this.libPath, artifact.path)
|
||||||
@ -826,15 +822,15 @@ class ProcessBuilder {
|
|||||||
* @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
|
* @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
|
||||||
*/
|
*/
|
||||||
_resolveServerLibraries(mods){
|
_resolveServerLibraries(mods){
|
||||||
const mdls = this.server.getModules()
|
const mdls = this.server.modules
|
||||||
let libs = {}
|
let libs = {}
|
||||||
|
|
||||||
// Locate Forge/Libraries
|
// Locate Forge/Libraries
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.getType()
|
const type = mdl.rawModule.type
|
||||||
if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Library){
|
if(type === Type.ForgeHosted || type === Type.Library){
|
||||||
libs[mdl.getVersionlessID()] = mdl.getArtifact().getPath()
|
libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
|
||||||
if(mdl.hasSubModules()){
|
if(mdl.subModules.length > 0){
|
||||||
const res = this._resolveModuleLibraries(mdl)
|
const res = this._resolveModuleLibraries(mdl)
|
||||||
if(res.length > 0){
|
if(res.length > 0){
|
||||||
libs = {...libs, ...res}
|
libs = {...libs, ...res}
|
||||||
@ -863,20 +859,20 @@ class ProcessBuilder {
|
|||||||
* @returns {Array.<string>} An array containing the paths of each library this module requires.
|
* @returns {Array.<string>} An array containing the paths of each library this module requires.
|
||||||
*/
|
*/
|
||||||
_resolveModuleLibraries(mdl){
|
_resolveModuleLibraries(mdl){
|
||||||
if(!mdl.hasSubModules()){
|
if(!mdl.subModules.length > 0){
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
let libs = []
|
let libs = []
|
||||||
for(let sm of mdl.getSubModules()){
|
for(let sm of mdl.subModules){
|
||||||
if(sm.getType() === DistroManager.Types.Library){
|
if(sm.rawModule.type === Type.Library){
|
||||||
|
|
||||||
if(sm.getClasspath()) {
|
if(sm.rawModule.classpath ?? true) {
|
||||||
libs.push(sm.getArtifact().getPath())
|
libs.push(sm.getPath())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If this module has submodules, we need to resolve the libraries for those.
|
// If this module has submodules, we need to resolve the libraries for those.
|
||||||
// To avoid unnecessary recursive calls, base case is checked here.
|
// To avoid unnecessary recursive calls, base case is checked here.
|
||||||
if(mdl.hasSubModules()){
|
if(mdl.subModules.length > 0){
|
||||||
const res = this._resolveModuleLibraries(sm)
|
const res = this._resolveModuleLibraries(sm)
|
||||||
if(res.length > 0){
|
if(res.length > 0){
|
||||||
libs = libs.concat(res)
|
libs = libs.concat(res)
|
||||||
@ -886,6 +882,24 @@ class ProcessBuilder {
|
|||||||
return libs
|
return libs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isAutoconnectBroken(forgeVersion) {
|
||||||
|
|
||||||
|
const minWorking = [31, 2, 15]
|
||||||
|
const verSplit = forgeVersion.split('.').map(v => Number(v))
|
||||||
|
|
||||||
|
if(verSplit[0] === 31) {
|
||||||
|
for(let i=0; i<minWorking.length; i++) {
|
||||||
|
if(verSplit[i] > minWorking[i]) {
|
||||||
|
return false
|
||||||
|
} else if(verSplit[i] < minWorking[i]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ProcessBuilder
|
module.exports = ProcessBuilder
|
@ -5,14 +5,24 @@
|
|||||||
const cp = require('child_process')
|
const cp = require('child_process')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const { URL } = require('url')
|
const { URL } = require('url')
|
||||||
const { MojangRestAPI, getServerStatus } = require('helios-core/mojang')
|
const {
|
||||||
|
MojangRestAPI,
|
||||||
|
getServerStatus
|
||||||
|
} = require('helios-core/mojang')
|
||||||
|
const {
|
||||||
|
RestResponseStatus,
|
||||||
|
isDisplayableError,
|
||||||
|
mcVersionAtLeast
|
||||||
|
} = require('helios-core/common')
|
||||||
|
const {
|
||||||
|
FullRepair,
|
||||||
|
DistributionIndexProcessor,
|
||||||
|
MojangIndexProcessor
|
||||||
|
} = require('helios-core/dl')
|
||||||
|
|
||||||
// Internal Requirements
|
// Internal Requirements
|
||||||
const DiscordWrapper = require('./assets/js/discordwrapper')
|
const DiscordWrapper = require('./assets/js/discordwrapper')
|
||||||
const ProcessBuilder = require('./assets/js/processbuilder')
|
const ProcessBuilder = require('./assets/js/processbuilder')
|
||||||
const { Util } = require('./assets/js/assetguard')
|
|
||||||
const { RestResponseStatus, isDisplayableError } = require('helios-core/common')
|
|
||||||
const { stdout } = require('process')
|
|
||||||
|
|
||||||
// Launch Elements
|
// Launch Elements
|
||||||
const launch_content = document.getElementById('launch_content')
|
const launch_content = document.getElementById('launch_content')
|
||||||
@ -54,26 +64,22 @@ function setLaunchDetails(details){
|
|||||||
/**
|
/**
|
||||||
* Set the value of the loading progress bar and display that value.
|
* Set the value of the loading progress bar and display that value.
|
||||||
*
|
*
|
||||||
* @param {number} value The progress value.
|
* @param {number} percent Percentage (0-100)
|
||||||
* @param {number} max The total size.
|
|
||||||
* @param {number|string} percent Optional. The percentage to display on the progress label.
|
|
||||||
*/
|
*/
|
||||||
function setLaunchPercentage(value, max, percent = ((value/max)*100)){
|
function setLaunchPercentage(percent){
|
||||||
launch_progress.setAttribute('max', max)
|
launch_progress.setAttribute('max', 100)
|
||||||
launch_progress.setAttribute('value', value)
|
launch_progress.setAttribute('value', percent)
|
||||||
launch_progress_label.innerHTML = percent + '%'
|
launch_progress_label.innerHTML = percent + '%'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of the OS progress bar and display that on the UI.
|
* Set the value of the OS progress bar and display that on the UI.
|
||||||
*
|
*
|
||||||
* @param {number} value The progress value.
|
* @param {number} percent Percentage (0-100)
|
||||||
* @param {number} max The total download size.
|
|
||||||
* @param {number|string} percent Optional. The percentage to display on the progress label.
|
|
||||||
*/
|
*/
|
||||||
function setDownloadPercentage(value, max, percent = ((value/max)*100)){
|
function setDownloadPercentage(percent){
|
||||||
remote.getCurrentWindow().setProgressBar(value/max)
|
remote.getCurrentWindow().setProgressBar(percent/100)
|
||||||
setLaunchPercentage(value, max, percent)
|
setLaunchPercentage(percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -86,9 +92,9 @@ function setLaunchEnabled(val){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bind launch button
|
// Bind launch button
|
||||||
document.getElementById('launch_button').addEventListener('click', function(e){
|
document.getElementById('launch_button').addEventListener('click', async (e) => {
|
||||||
loggerLanding.info('Launching game..')
|
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())
|
const jExe = ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer())
|
||||||
if(jExe == null){
|
if(jExe == null){
|
||||||
asyncSystemScan(mcVersion)
|
asyncSystemScan(mcVersion)
|
||||||
@ -99,10 +105,10 @@ document.getElementById('launch_button').addEventListener('click', function(e){
|
|||||||
setLaunchPercentage(0, 100)
|
setLaunchPercentage(0, 100)
|
||||||
|
|
||||||
const jg = new JavaGuard(mcVersion)
|
const jg = new JavaGuard(mcVersion)
|
||||||
jg._validateJavaBinary(jExe).then((v) => {
|
jg._validateJavaBinary(jExe).then(async v => {
|
||||||
loggerLanding.info('Java version meta', v)
|
loggerLanding.info('Java version meta', v)
|
||||||
if(v.valid){
|
if(v.valid){
|
||||||
dlAsync()
|
await dlAsync()
|
||||||
} else {
|
} else {
|
||||||
asyncSystemScan(mcVersion)
|
asyncSystemScan(mcVersion)
|
||||||
}
|
}
|
||||||
@ -111,14 +117,14 @@ document.getElementById('launch_button').addEventListener('click', function(e){
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Bind settings button
|
// Bind settings button
|
||||||
document.getElementById('settingsMediaButton').onclick = (e) => {
|
document.getElementById('settingsMediaButton').onclick = async e => {
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
switchView(getCurrentView(), VIEWS.settings)
|
switchView(getCurrentView(), VIEWS.settings)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind avatar overlay button.
|
// Bind avatar overlay button.
|
||||||
document.getElementById('avatarOverlay').onclick = (e) => {
|
document.getElementById('avatarOverlay').onclick = async e => {
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
|
||||||
settingsNavItemListener(document.getElementById('settingsNavAccount'), false)
|
settingsNavItemListener(document.getElementById('settingsNavAccount'), false)
|
||||||
})
|
})
|
||||||
@ -144,9 +150,9 @@ function updateSelectedServer(serv){
|
|||||||
if(getCurrentView() === VIEWS.settings){
|
if(getCurrentView() === VIEWS.settings){
|
||||||
fullSettingsSave()
|
fullSettingsSave()
|
||||||
}
|
}
|
||||||
ConfigManager.setSelectedServer(serv != null ? serv.getID() : null)
|
ConfigManager.setSelectedServer(serv != null ? serv.rawServer.id : null)
|
||||||
ConfigManager.save()
|
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){
|
if(getCurrentView() === VIEWS.settings){
|
||||||
animateSettingsTabRefresh()
|
animateSettingsTabRefresh()
|
||||||
}
|
}
|
||||||
@ -154,9 +160,9 @@ function updateSelectedServer(serv){
|
|||||||
}
|
}
|
||||||
// Real text is set in uibinder.js on distributionIndexDone.
|
// Real text is set in uibinder.js on distributionIndexDone.
|
||||||
server_selection_button.innerHTML = '\u2022 Loading..'
|
server_selection_button.innerHTML = '\u2022 Loading..'
|
||||||
server_selection_button.onclick = (e) => {
|
server_selection_button.onclick = async e => {
|
||||||
e.target.blur()
|
e.target.blur()
|
||||||
toggleServerSelection(true)
|
await toggleServerSelection(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Mojang Status Color
|
// Update Mojang Status Color
|
||||||
@ -220,17 +226,16 @@ const refreshMojangStatuses = async function(){
|
|||||||
document.getElementById('mojang_status_icon').style.color = MojangRestAPI.statusToHex(status)
|
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')
|
loggerLanding.info('Refreshing Server Status')
|
||||||
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
||||||
|
|
||||||
let pLabel = 'SERVER'
|
let pLabel = 'SERVER'
|
||||||
let pVal = 'OFFLINE'
|
let pVal = 'OFFLINE'
|
||||||
|
|
||||||
try {
|
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)
|
console.log(servStat)
|
||||||
pLabel = 'PLAYERS'
|
pLabel = 'PLAYERS'
|
||||||
pVal = servStat.players.online + '/' + servStat.players.max
|
pVal = servStat.players.online + '/' + servStat.players.max
|
||||||
@ -318,9 +323,9 @@ function asyncSystemScan(mcVersion, launchAfter = true){
|
|||||||
console.log(`\x1b[31m[SysAEx]\x1b[0m ${data}`)
|
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.context === 'validateJava'){
|
||||||
if(m.result == null){
|
if(m.result == null){
|
||||||
@ -368,10 +373,10 @@ function asyncSystemScan(mcVersion, launchAfter = true){
|
|||||||
// We need to make sure that the updated value is on the settings UI.
|
// We need to make sure that the updated value is on the settings UI.
|
||||||
// Just incase the settings UI is already open.
|
// Just incase the settings UI is already open.
|
||||||
settingsJavaExecVal.value = m.result
|
settingsJavaExecVal.value = m.result
|
||||||
populateJavaExecDetails(settingsJavaExecVal.value)
|
await populateJavaExecDetails(settingsJavaExecVal.value)
|
||||||
|
|
||||||
if(launchAfter){
|
if(launchAfter){
|
||||||
dlAsync()
|
await dlAsync()
|
||||||
}
|
}
|
||||||
sysAEx.disconnect()
|
sysAEx.disconnect()
|
||||||
}
|
}
|
||||||
@ -447,7 +452,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){
|
|||||||
setLaunchDetails('Java Installed!')
|
setLaunchDetails('Java Installed!')
|
||||||
|
|
||||||
if(launchAfter){
|
if(launchAfter){
|
||||||
dlAsync()
|
await dlAsync()
|
||||||
}
|
}
|
||||||
|
|
||||||
sysAEx.disconnect()
|
sysAEx.disconnect()
|
||||||
@ -475,18 +480,28 @@ const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
|
|||||||
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/
|
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/
|
||||||
const MIN_LINGER = 5000
|
const MIN_LINGER = 5000
|
||||||
|
|
||||||
let aEx
|
async function dlAsync(login = true) {
|
||||||
let serv
|
|
||||||
let versionData
|
|
||||||
let forgeData
|
|
||||||
|
|
||||||
let progressListener
|
|
||||||
|
|
||||||
function dlAsync(login = true){
|
|
||||||
|
|
||||||
// Login parameter is temporary for debug purposes. Allows testing the validation/downloads without
|
// Login parameter is temporary for debug purposes. Allows testing the validation/downloads without
|
||||||
// launching the game.
|
// launching the game.
|
||||||
|
|
||||||
|
const loggerLaunchSuite = LoggerUtil.getLogger('LaunchSuite')
|
||||||
|
|
||||||
|
setLaunchDetails('Loading server information..')
|
||||||
|
|
||||||
|
let distro
|
||||||
|
|
||||||
|
try {
|
||||||
|
distro = await DistroAPI.refreshDistributionOrFallback()
|
||||||
|
onDistroRefresh(distro)
|
||||||
|
} 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.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const serv = distro.getServerById(ConfigManager.getSelectedServer())
|
||||||
|
|
||||||
if(login) {
|
if(login) {
|
||||||
if(ConfigManager.getSelectedAccount() == null){
|
if(ConfigManager.getSelectedAccount() == null){
|
||||||
loggerLanding.error('You must be logged into an account.')
|
loggerLanding.error('You must be logged into an account.')
|
||||||
@ -498,272 +513,148 @@ function dlAsync(login = true){
|
|||||||
toggleLaunchArea(true)
|
toggleLaunchArea(true)
|
||||||
setLaunchPercentage(0, 100)
|
setLaunchPercentage(0, 100)
|
||||||
|
|
||||||
const loggerLaunchSuite = LoggerUtil.getLogger('LaunchSuite')
|
const fullRepairModule = new FullRepair(
|
||||||
|
|
||||||
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'), [
|
|
||||||
'AssetGuard',
|
|
||||||
ConfigManager.getCommonDirectory(),
|
ConfigManager.getCommonDirectory(),
|
||||||
ConfigManager.getJavaExecutable(ConfigManager.getSelectedServer())
|
ConfigManager.getInstanceDirectory(),
|
||||||
], {
|
ConfigManager.getLauncherDirectory(),
|
||||||
env: forkEnv,
|
ConfigManager.getSelectedServer(),
|
||||||
stdio: 'pipe'
|
DistroAPI.isDevMode()
|
||||||
})
|
)
|
||||||
// Stdout
|
|
||||||
aEx.stdio[1].setEncoding('utf8')
|
fullRepairModule.spawnReceiver()
|
||||||
aEx.stdio[1].on('data', (data) => {
|
|
||||||
console.log(`\x1b[32m[AEx]\x1b[0m ${data}`)
|
fullRepairModule.childProcess.on('error', (err) => {
|
||||||
})
|
|
||||||
// Stderr
|
|
||||||
aEx.stdio[2].setEncoding('utf8')
|
|
||||||
aEx.stdio[2].on('data', (data) => {
|
|
||||||
console.log(`\x1b[31m[AEx]\x1b[0m ${data}`)
|
|
||||||
})
|
|
||||||
aEx.on('error', (err) => {
|
|
||||||
loggerLaunchSuite.error('Error during launch', err)
|
loggerLaunchSuite.error('Error during launch', err)
|
||||||
showLaunchFailure('Error During Launch', err.message || 'See console (CTRL + Shift + i) for more details.')
|
showLaunchFailure('Error During Launch', err.message || 'See console (CTRL + Shift + i) for more details.')
|
||||||
})
|
})
|
||||||
aEx.on('close', (code, signal) => {
|
fullRepairModule.childProcess.on('close', (code, _signal) => {
|
||||||
if(code !== 0){
|
if(code !== 0){
|
||||||
loggerLaunchSuite.error(`AssetExec exited with code ${code}, assuming error.`)
|
loggerLaunchSuite.error(`AssetExec exited with code ${code}, assuming error.`)
|
||||||
showLaunchFailure('Error During Launch', 'See console (CTRL + Shift + i) for more details.')
|
showLaunchFailure('Error During Launch', 'See console (CTRL + Shift + i) for more details.')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Establish communications between the AssetExec and current process.
|
loggerLaunchSuite.info('Validating files.')
|
||||||
aEx.on('message', (m) => {
|
setLaunchDetails('Validating file integrity..')
|
||||||
|
const invalidFileCount = await fullRepairModule.verifyFiles(percent => {
|
||||||
|
setLaunchPercentage(percent)
|
||||||
|
})
|
||||||
|
setLaunchPercentage(100)
|
||||||
|
|
||||||
if(m.context === 'validate'){
|
if(invalidFileCount > 0) {
|
||||||
switch(m.data){
|
loggerLaunchSuite.info('Downloading files.')
|
||||||
case 'distribution':
|
setLaunchDetails('Downloading files..')
|
||||||
setLaunchPercentage(20, 100)
|
await fullRepairModule.download(percent => {
|
||||||
loggerLaunchSuite.info('Validated distibution index.')
|
setDownloadPercentage(percent)
|
||||||
setLaunchDetails('Loading version information..')
|
})
|
||||||
break
|
setDownloadPercentage(100)
|
||||||
case 'version':
|
} else {
|
||||||
setLaunchPercentage(40, 100)
|
loggerLaunchSuite.info('No invalid files, skipping download.')
|
||||||
loggerLaunchSuite.info('Version data loaded.')
|
}
|
||||||
setLaunchDetails('Validating asset integrity..')
|
|
||||||
break
|
// Remove download bar.
|
||||||
case 'assets':
|
remote.getCurrentWindow().setProgressBar(-1)
|
||||||
setLaunchPercentage(60, 100)
|
|
||||||
loggerLaunchSuite.info('Asset Validation Complete')
|
fullRepairModule.destroyReceiver()
|
||||||
setLaunchDetails('Validating library integrity..')
|
|
||||||
break
|
setLaunchDetails('Preparing to launch..')
|
||||||
case 'libraries':
|
|
||||||
setLaunchPercentage(80, 100)
|
const mojangIndexProcessor = new MojangIndexProcessor(
|
||||||
loggerLaunchSuite.info('Library validation complete.')
|
ConfigManager.getCommonDirectory(),
|
||||||
setLaunchDetails('Validating miscellaneous file integrity..')
|
serv.rawServer.minecraftVersion)
|
||||||
break
|
const distributionIndexProcessor = new DistributionIndexProcessor(
|
||||||
case 'files':
|
ConfigManager.getCommonDirectory(),
|
||||||
setLaunchPercentage(100, 100)
|
distro,
|
||||||
loggerLaunchSuite.info('File validation complete.')
|
serv.rawServer.id
|
||||||
setLaunchDetails('Downloading files..')
|
)
|
||||||
break
|
|
||||||
|
// TODO need to load these.
|
||||||
|
const forgeData = await distributionIndexProcessor.loadForgeVersionJson(serv)
|
||||||
|
const versionData = await mojangIndexProcessor.getVersionJson()
|
||||||
|
|
||||||
|
if(login) {
|
||||||
|
const authUser = ConfigManager.getSelectedAccount()
|
||||||
|
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
|
||||||
|
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion())
|
||||||
|
setLaunchDetails('Launching game..')
|
||||||
|
|
||||||
|
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/
|
||||||
|
const SERVER_JOINED_REGEX = new RegExp(`\\[.+\\]: \\[CHAT\\] ${authUser.displayName} joined the game`)
|
||||||
|
|
||||||
|
const onLoadComplete = () => {
|
||||||
|
toggleLaunchArea(false)
|
||||||
|
if(hasRPC){
|
||||||
|
DiscordWrapper.updateDetails('Loading game..')
|
||||||
}
|
}
|
||||||
} else if(m.context === 'progress'){
|
proc.stdout.on('data', gameStateChange)
|
||||||
switch(m.data){
|
proc.stdout.removeListener('data', tempListener)
|
||||||
case 'assets': {
|
proc.stderr.removeListener('data', gameErrorListener)
|
||||||
const perc = (m.value/m.total)*20
|
}
|
||||||
setLaunchPercentage(40+perc, 100, parseInt(40+perc))
|
const start = Date.now()
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'download':
|
|
||||||
setDownloadPercentage(m.value, m.total, m.percent)
|
|
||||||
break
|
|
||||||
case 'extract': {
|
|
||||||
// Show installing progress bar.
|
|
||||||
remote.getCurrentWindow().setProgressBar(2)
|
|
||||||
|
|
||||||
// Download done, extracting.
|
// Attach a temporary listener to the client output.
|
||||||
const eLStr = 'Extracting libraries'
|
// Will wait for a certain bit of text meaning that
|
||||||
let dotStr = ''
|
// the client application has started, and we can hide
|
||||||
setLaunchDetails(eLStr)
|
// the progress bar stuff.
|
||||||
progressListener = setInterval(() => {
|
const tempListener = function(data){
|
||||||
if(dotStr.length >= 3){
|
if(GAME_LAUNCH_REGEX.test(data.trim())){
|
||||||
dotStr = ''
|
const diff = Date.now()-start
|
||||||
} else {
|
if(diff < MIN_LINGER) {
|
||||||
dotStr += '.'
|
setTimeout(onLoadComplete, MIN_LINGER-diff)
|
||||||
}
|
} else {
|
||||||
setLaunchDetails(eLStr + dotStr)
|
onLoadComplete()
|
||||||
}, 750)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(m.context === 'complete'){
|
}
|
||||||
switch(m.data){
|
|
||||||
case 'download':
|
|
||||||
// Download and extraction complete, remove the loading from the OS progress bar.
|
|
||||||
remote.getCurrentWindow().setProgressBar(-1)
|
|
||||||
if(progressListener != null){
|
|
||||||
clearInterval(progressListener)
|
|
||||||
progressListener = null
|
|
||||||
}
|
|
||||||
|
|
||||||
setLaunchDetails('Preparing to launch..')
|
// Listener for Discord RPC.
|
||||||
break
|
const gameStateChange = function(data){
|
||||||
|
data = data.trim()
|
||||||
|
if(SERVER_JOINED_REGEX.test(data)){
|
||||||
|
DiscordWrapper.updateDetails('Exploring the Realm!')
|
||||||
|
} else if(GAME_JOINED_REGEX.test(data)){
|
||||||
|
DiscordWrapper.updateDetails('Sailing to Westeros!')
|
||||||
}
|
}
|
||||||
} else if(m.context === 'error'){
|
}
|
||||||
switch(m.data){
|
|
||||||
case 'download':
|
|
||||||
loggerLaunchSuite.error('Error while downloading:', m.error)
|
|
||||||
|
|
||||||
if(m.error.code === 'ENOENT'){
|
const gameErrorListener = function(data){
|
||||||
showLaunchFailure(
|
data = data.trim()
|
||||||
'Download Error',
|
if(data.indexOf('Could not find or load main class net.minecraft.launchwrapper.Launch') > -1){
|
||||||
'Could not connect to the file server. Ensure that you are connected to the internet and try again.'
|
loggerLaunchSuite.error('Game launch failed, LaunchWrapper was not downloaded properly.')
|
||||||
)
|
showLaunchFailure('Error During Launch', 'The main file, LaunchWrapper, failed to download properly. As a result, the game cannot launch.<br><br>To fix this issue, temporarily turn off your antivirus software and launch the game again.<br><br>If you have time, please <a href="https://github.com/dscalzi/HeliosLauncher/issues">submit an issue</a> and let us know what antivirus software you use. We\'ll contact them and try to straighten things out.')
|
||||||
} else {
|
|
||||||
showLaunchFailure(
|
|
||||||
'Download Error',
|
|
||||||
'Check the console (CTRL + Shift + i) for more details. Please try again.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
remote.getCurrentWindow().setProgressBar(-1)
|
|
||||||
|
|
||||||
// Disconnect from AssetExec
|
|
||||||
aEx.disconnect()
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
} else if(m.context === 'validateEverything'){
|
}
|
||||||
|
|
||||||
let allGood = true
|
try {
|
||||||
|
// Build Minecraft process.
|
||||||
|
proc = pb.build()
|
||||||
|
|
||||||
// If these properties are not defined it's likely an error.
|
// Bind listeners to stdout.
|
||||||
if(m.result.forgeData == null || m.result.versionData == null){
|
proc.stdout.on('data', tempListener)
|
||||||
loggerLaunchSuite.error('Error during validation:', m.result)
|
proc.stderr.on('data', gameErrorListener)
|
||||||
|
|
||||||
loggerLaunchSuite.error('Error during launch', m.result.error)
|
setLaunchDetails('Done. Enjoy the server!')
|
||||||
showLaunchFailure('Error During Launch', 'Please check the console (CTRL + Shift + i) for more details.')
|
|
||||||
|
|
||||||
allGood = false
|
// Init Discord Hook
|
||||||
|
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..')
|
||||||
|
DiscordWrapper.shutdownRPC()
|
||||||
|
hasRPC = false
|
||||||
|
proc = null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
forgeData = m.result.forgeData
|
} catch(err) {
|
||||||
versionData = m.result.versionData
|
|
||||||
|
|
||||||
if(login && allGood) {
|
loggerLaunchSuite.error('Error during launch', err)
|
||||||
const authUser = ConfigManager.getSelectedAccount()
|
showLaunchFailure('Error During Launch', 'Please check the console (CTRL + Shift + i) for more details.')
|
||||||
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
|
|
||||||
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, remote.app.getVersion())
|
|
||||||
setLaunchDetails('Launching game..')
|
|
||||||
|
|
||||||
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/
|
|
||||||
const SERVER_JOINED_REGEX = new RegExp(`\\[.+\\]: \\[CHAT\\] ${authUser.displayName} joined the game`)
|
|
||||||
|
|
||||||
const onLoadComplete = () => {
|
|
||||||
toggleLaunchArea(false)
|
|
||||||
if(hasRPC){
|
|
||||||
DiscordWrapper.updateDetails('Loading game..')
|
|
||||||
}
|
|
||||||
proc.stdout.on('data', gameStateChange)
|
|
||||||
proc.stdout.removeListener('data', tempListener)
|
|
||||||
proc.stderr.removeListener('data', gameErrorListener)
|
|
||||||
}
|
|
||||||
const start = Date.now()
|
|
||||||
|
|
||||||
// Attach a temporary listener to the client output.
|
|
||||||
// Will wait for a certain bit of text meaning that
|
|
||||||
// the client application has started, and we can hide
|
|
||||||
// the progress bar stuff.
|
|
||||||
const tempListener = function(data){
|
|
||||||
if(GAME_LAUNCH_REGEX.test(data.trim())){
|
|
||||||
const diff = Date.now()-start
|
|
||||||
if(diff < MIN_LINGER) {
|
|
||||||
setTimeout(onLoadComplete, MIN_LINGER-diff)
|
|
||||||
} else {
|
|
||||||
onLoadComplete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listener for Discord RPC.
|
|
||||||
const gameStateChange = function(data){
|
|
||||||
data = data.trim()
|
|
||||||
if(SERVER_JOINED_REGEX.test(data)){
|
|
||||||
DiscordWrapper.updateDetails('Exploring the Realm!')
|
|
||||||
} else if(GAME_JOINED_REGEX.test(data)){
|
|
||||||
DiscordWrapper.updateDetails('Sailing to Westeros!')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const gameErrorListener = function(data){
|
|
||||||
data = data.trim()
|
|
||||||
if(data.indexOf('Could not find or load main class net.minecraft.launchwrapper.Launch') > -1){
|
|
||||||
loggerLaunchSuite.error('Game launch failed, LaunchWrapper was not downloaded properly.')
|
|
||||||
showLaunchFailure('Error During Launch', 'The main file, LaunchWrapper, failed to download properly. As a result, the game cannot launch.<br><br>To fix this issue, temporarily turn off your antivirus software and launch the game again.<br><br>If you have time, please <a href="https://github.com/dscalzi/HeliosLauncher/issues">submit an issue</a> and let us know what antivirus software you use. We\'ll contact them and try to straighten things out.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Build Minecraft process.
|
|
||||||
proc = pb.build()
|
|
||||||
|
|
||||||
// Bind listeners to stdout.
|
|
||||||
proc.stdout.on('data', tempListener)
|
|
||||||
proc.stderr.on('data', gameErrorListener)
|
|
||||||
|
|
||||||
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)
|
|
||||||
hasRPC = true
|
|
||||||
proc.on('close', (code, signal) => {
|
|
||||||
loggerLaunchSuite.info('Shutting down Discord Rich Presence..')
|
|
||||||
DiscordWrapper.shutdownRPC()
|
|
||||||
hasRPC = false
|
|
||||||
proc = null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch(err) {
|
|
||||||
|
|
||||||
loggerLaunchSuite.error('Error during launch', err)
|
|
||||||
showLaunchFailure('Error During Launch', 'Please check the console (CTRL + Shift + i) for more details.')
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disconnect from AssetExec
|
|
||||||
aEx.disconnect()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
// Begin Validations
|
|
||||||
|
|
||||||
// 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) => {
|
|
||||||
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()]})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1089,10 +980,13 @@ function displayArticle(articleObject, index){
|
|||||||
* Load news information from the RSS feed specified in the
|
* Load news information from the RSS feed specified in the
|
||||||
* distribution index.
|
* distribution index.
|
||||||
*/
|
*/
|
||||||
function loadNews(){
|
async function loadNews(){
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const distroData = DistroManager.getDistribution()
|
const distroData = await DistroAPI.getDistribution()
|
||||||
const newsFeed = distroData.getRSS()
|
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
|
||||||
|
const newsFeed = distroData.rawDistribution.rss
|
||||||
const newsHost = new URL(newsFeed).origin + '/'
|
const newsHost = new URL(newsFeed).origin + '/'
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: newsFeed,
|
url: newsFeed,
|
||||||
@ -1147,4 +1041,6 @@ function loadNews(){
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return await promise
|
||||||
}
|
}
|
||||||
|
@ -193,10 +193,10 @@ loginButton.addEventListener('click', () => {
|
|||||||
$('.circle-loader').toggleClass('load-complete')
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
$('.checkmark').toggle()
|
$('.checkmark').toggle()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => {
|
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, async () => {
|
||||||
// Temporary workaround
|
// Temporary workaround
|
||||||
if(loginViewOnSuccess === VIEWS.settings){
|
if(loginViewOnSuccess === VIEWS.settings){
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
}
|
}
|
||||||
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
||||||
loginCancelEnabled(false) // Reset this for good measure.
|
loginCancelEnabled(false) // Reset this for good measure.
|
||||||
|
@ -117,8 +117,8 @@ function toggleOverlay(toggleState, dismissable = false, content = 'overlayConte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleServerSelection(toggleState){
|
async function toggleServerSelection(toggleState){
|
||||||
prepareServerSelectionList()
|
await prepareServerSelectionList()
|
||||||
toggleOverlay(toggleState, true, 'serverSelectContent')
|
toggleOverlay(toggleState, true, 'serverSelectContent')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,11 +171,11 @@ function setDismissHandler(handler){
|
|||||||
|
|
||||||
/* Server Select View */
|
/* Server Select View */
|
||||||
|
|
||||||
document.getElementById('serverSelectConfirm').addEventListener('click', () => {
|
document.getElementById('serverSelectConfirm').addEventListener('click', async () => {
|
||||||
const listings = document.getElementsByClassName('serverListing')
|
const listings = document.getElementsByClassName('serverListing')
|
||||||
for(let i=0; i<listings.length; i++){
|
for(let i=0; i<listings.length; i++){
|
||||||
if(listings[i].hasAttribute('selected')){
|
if(listings[i].hasAttribute('selected')){
|
||||||
const serv = DistroManager.getDistribution().getServer(listings[i].getAttribute('servid'))
|
const serv = (await DistroAPI.getDistribution()).getServerById(listings[i].getAttribute('servid'))
|
||||||
updateSelectedServer(serv)
|
updateSelectedServer(serv)
|
||||||
refreshServerStatus(true)
|
refreshServerStatus(true)
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
@ -184,13 +184,13 @@ document.getElementById('serverSelectConfirm').addEventListener('click', () => {
|
|||||||
}
|
}
|
||||||
// None are selected? Not possible right? Meh, handle it.
|
// None are selected? Not possible right? Meh, handle it.
|
||||||
if(listings.length > 0){
|
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)
|
updateSelectedServer(serv)
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
document.getElementById('accountSelectConfirm').addEventListener('click', () => {
|
document.getElementById('accountSelectConfirm').addEventListener('click', async () => {
|
||||||
const listings = document.getElementsByClassName('accountListing')
|
const listings = document.getElementsByClassName('accountListing')
|
||||||
for(let i=0; i<listings.length; i++){
|
for(let i=0; i<listings.length; i++){
|
||||||
if(listings[i].hasAttribute('selected')){
|
if(listings[i].hasAttribute('selected')){
|
||||||
@ -198,7 +198,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', () =>
|
|||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
updateSelectedAccount(authAcc)
|
updateSelectedAccount(authAcc)
|
||||||
if(getCurrentView() === VIEWS.settings) {
|
if(getCurrentView() === VIEWS.settings) {
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
}
|
}
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
validateSelectedAccount()
|
validateSelectedAccount()
|
||||||
@ -211,7 +211,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', () =>
|
|||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
updateSelectedAccount(authAcc)
|
updateSelectedAccount(authAcc)
|
||||||
if(getCurrentView() === VIEWS.settings) {
|
if(getCurrentView() === VIEWS.settings) {
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
}
|
}
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
validateSelectedAccount()
|
validateSelectedAccount()
|
||||||
@ -267,21 +267,21 @@ function setAccountListingHandlers(){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateServerListings(){
|
async function populateServerListings(){
|
||||||
const distro = DistroManager.getDistribution()
|
const distro = await DistroAPI.getDistribution()
|
||||||
const giaSel = ConfigManager.getSelectedServer()
|
const giaSel = ConfigManager.getSelectedServer()
|
||||||
const servers = distro.getServers()
|
const servers = distro.servers
|
||||||
let htmlString = ''
|
let htmlString = ''
|
||||||
for(const serv of servers){
|
for(const serv of servers){
|
||||||
htmlString += `<button class="serverListing" servid="${serv.getID()}" ${serv.getID() === giaSel ? 'selected' : ''}>
|
htmlString += `<button class="serverListing" servid="${serv.rawServer.id}" ${serv.rawServer.id === giaSel ? 'selected' : ''}>
|
||||||
<img class="serverListingImg" src="${serv.getIcon()}"/>
|
<img class="serverListingImg" src="${serv.rawServer.icon}"/>
|
||||||
<div class="serverListingDetails">
|
<div class="serverListingDetails">
|
||||||
<span class="serverListingName">${serv.getName()}</span>
|
<span class="serverListingName">${serv.rawServer.name}</span>
|
||||||
<span class="serverListingDescription">${serv.getDescription()}</span>
|
<span class="serverListingDescription">${serv.rawServer.description}</span>
|
||||||
<div class="serverListingInfo">
|
<div class="serverListingInfo">
|
||||||
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div>
|
<div class="serverListingVersion">${serv.rawServer.minecraftVersion}</div>
|
||||||
<div class="serverListingRevision">${serv.getVersion()}</div>
|
<div class="serverListingRevision">${serv.rawServer.version}</div>
|
||||||
${serv.isMainServer() ? `<div class="serverListingStarWrapper">
|
${serv.rawServer.mainServer ? `<div class="serverListingStarWrapper">
|
||||||
<svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px">
|
<svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px">
|
||||||
<defs>
|
<defs>
|
||||||
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style>
|
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style>
|
||||||
@ -313,8 +313,8 @@ function populateAccountListings(){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareServerSelectionList(){
|
async function prepareServerSelectionList(){
|
||||||
populateServerListings()
|
await populateServerListings()
|
||||||
setServerListingHandlers()
|
setServerListingHandlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ function bindFileSelectors(){
|
|||||||
if(!res.canceled) {
|
if(!res.canceled) {
|
||||||
ele.previousElementSibling.value = res.filePaths[0]
|
ele.previousElementSibling.value = res.filePaths[0]
|
||||||
if(isJavaExecSel) {
|
if(isJavaExecSel) {
|
||||||
populateJavaExecDetails(ele.previousElementSibling.value)
|
await populateJavaExecDetails(ele.previousElementSibling.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,9 +123,10 @@ function initSettingsValidators(){
|
|||||||
/**
|
/**
|
||||||
* Load configuration values onto the UI. This is an automated process.
|
* Load configuration values onto the UI. This is an automated process.
|
||||||
*/
|
*/
|
||||||
function initSettingsValues(){
|
async function initSettingsValues(){
|
||||||
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
|
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
|
||||||
Array.from(sEls).map((v, index, arr) => {
|
|
||||||
|
for(const v of sEls) {
|
||||||
const cVal = v.getAttribute('cValue')
|
const cVal = v.getAttribute('cValue')
|
||||||
const serverDependent = v.hasAttribute('serverDependent') // Means the first argument is the server id.
|
const serverDependent = v.hasAttribute('serverDependent') // Means the first argument is the server id.
|
||||||
const gFn = ConfigManager['get' + cVal]
|
const gFn = ConfigManager['get' + cVal]
|
||||||
@ -139,7 +140,7 @@ function initSettingsValues(){
|
|||||||
// Special Conditions
|
// Special Conditions
|
||||||
if(cVal === 'JavaExecutable'){
|
if(cVal === 'JavaExecutable'){
|
||||||
v.value = gFn.apply(null, gFnOpts)
|
v.value = gFn.apply(null, gFnOpts)
|
||||||
populateJavaExecDetails(v.value)
|
await populateJavaExecDetails(v.value)
|
||||||
} else if (cVal === 'DataDirectory'){
|
} else if (cVal === 'DataDirectory'){
|
||||||
v.value = gFn.apply(null, gFnOpts)
|
v.value = gFn.apply(null, gFnOpts)
|
||||||
} else if(cVal === 'JVMOptions'){
|
} else if(cVal === 'JVMOptions'){
|
||||||
@ -168,8 +169,8 @@ function initSettingsValues(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -416,8 +417,8 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
|
|||||||
const authCode = queryMap.code
|
const authCode = queryMap.code
|
||||||
AuthManager.addMicrosoftAccount(authCode).then(value => {
|
AuthManager.addMicrosoftAccount(authCode).then(value => {
|
||||||
updateSelectedAccount(value)
|
updateSelectedAccount(value)
|
||||||
switchView(getCurrentView(), viewOnClose, 500, 500, () => {
|
switchView(getCurrentView(), viewOnClose, 500, 500, async () => {
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((displayableError) => {
|
.catch((displayableError) => {
|
||||||
@ -713,13 +714,13 @@ const settingsModsContainer = document.getElementById('settingsModsContainer')
|
|||||||
/**
|
/**
|
||||||
* Resolve and update the mods on the UI.
|
* Resolve and update the mods on the UI.
|
||||||
*/
|
*/
|
||||||
function resolveModsForUI(){
|
async function resolveModsForUI(){
|
||||||
const serv = ConfigManager.getSelectedServer()
|
const serv = ConfigManager.getSelectedServer()
|
||||||
|
|
||||||
const distro = DistroManager.getDistribution()
|
const distro = await DistroAPI.getDistribution()
|
||||||
const servConf = ConfigManager.getModConfiguration(serv)
|
const servConf = ConfigManager.getModConfiguration(serv)
|
||||||
|
|
||||||
const modStr = parseModulesForUI(distro.getServer(serv).getModules(), false, servConf.mods)
|
const modStr = parseModulesForUI(distro.getServerById(serv).modules, false, servConf.mods)
|
||||||
|
|
||||||
document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods
|
document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods
|
||||||
document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods
|
document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods
|
||||||
@ -739,17 +740,17 @@ function parseModulesForUI(mdls, submodules, servConf){
|
|||||||
|
|
||||||
for(const mdl of mdls){
|
for(const mdl of mdls){
|
||||||
|
|
||||||
if(mdl.getType() === DistroManager.Types.ForgeMod || mdl.getType() === DistroManager.Types.LiteMod || mdl.getType() === DistroManager.Types.LiteLoader){
|
if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader){
|
||||||
|
|
||||||
if(mdl.getRequired().isRequired()){
|
if(mdl.getRequired().value){
|
||||||
|
|
||||||
reqMods += `<div id="${mdl.getVersionlessID()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" enabled>
|
reqMods += `<div id="${mdl.getVersionlessMavenIdentifier()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" enabled>
|
||||||
<div class="settingsModContent">
|
<div class="settingsModContent">
|
||||||
<div class="settingsModMainWrapper">
|
<div class="settingsModMainWrapper">
|
||||||
<div class="settingsModStatus"></div>
|
<div class="settingsModStatus"></div>
|
||||||
<div class="settingsModDetails">
|
<div class="settingsModDetails">
|
||||||
<span class="settingsModName">${mdl.getName()}</span>
|
<span class="settingsModName">${mdl.rawModule.name}</span>
|
||||||
<span class="settingsModVersion">v${mdl.getVersion()}</span>
|
<span class="settingsModVersion">v${mdl.mavenComponents.version}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="toggleSwitch" reqmod>
|
<label class="toggleSwitch" reqmod>
|
||||||
@ -757,32 +758,32 @@ function parseModulesForUI(mdls, submodules, servConf){
|
|||||||
<span class="toggleSwitchSlider"></span>
|
<span class="toggleSwitchSlider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${mdl.hasSubModules() ? `<div class="settingsSubModContainer">
|
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
||||||
${Object.values(parseModulesForUI(mdl.getSubModules(), true, servConf[mdl.getVersionlessID()])).join('')}
|
${Object.values(parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const conf = servConf[mdl.getVersionlessID()]
|
const conf = servConf[mdl.getVersionlessMavenIdentifier()]
|
||||||
const val = typeof conf === 'object' ? conf.value : conf
|
const val = typeof conf === 'object' ? conf.value : conf
|
||||||
|
|
||||||
optMods += `<div id="${mdl.getVersionlessID()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" ${val ? 'enabled' : ''}>
|
optMods += `<div id="${mdl.getVersionlessMavenIdentifier()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" ${val ? 'enabled' : ''}>
|
||||||
<div class="settingsModContent">
|
<div class="settingsModContent">
|
||||||
<div class="settingsModMainWrapper">
|
<div class="settingsModMainWrapper">
|
||||||
<div class="settingsModStatus"></div>
|
<div class="settingsModStatus"></div>
|
||||||
<div class="settingsModDetails">
|
<div class="settingsModDetails">
|
||||||
<span class="settingsModName">${mdl.getName()}</span>
|
<span class="settingsModName">${mdl.rawModule.name}</span>
|
||||||
<span class="settingsModVersion">v${mdl.getVersion()}</span>
|
<span class="settingsModVersion">v${mdl.mavenComponents.version}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="toggleSwitch">
|
<label class="toggleSwitch">
|
||||||
<input type="checkbox" formod="${mdl.getVersionlessID()}" ${val ? 'checked' : ''}>
|
<input type="checkbox" formod="${mdl.getVersionlessMavenIdentifier()}" ${val ? 'checked' : ''}>
|
||||||
<span class="toggleSwitchSlider"></span>
|
<span class="toggleSwitchSlider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${mdl.hasSubModules() ? `<div class="settingsSubModContainer">
|
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
||||||
${Object.values(parseModulesForUI(mdl.getSubModules(), true, conf.mods)).join('')}
|
${Object.values(parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
@ -858,10 +859,10 @@ let CACHE_DROPIN_MODS
|
|||||||
* Resolve any located drop-in mods for this server and
|
* Resolve any located drop-in mods for this server and
|
||||||
* populate the results onto the UI.
|
* populate the results onto the UI.
|
||||||
*/
|
*/
|
||||||
function resolveDropinModsForUI(){
|
async function resolveDropinModsForUI(){
|
||||||
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
||||||
CACHE_SETTINGS_MODS_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.getID(), 'mods')
|
CACHE_SETTINGS_MODS_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.rawServer.id, 'mods')
|
||||||
CACHE_DROPIN_MODS = DropinModUtil.scanForDropinMods(CACHE_SETTINGS_MODS_DIR, serv.getMinecraftVersion())
|
CACHE_DROPIN_MODS = DropinModUtil.scanForDropinMods(CACHE_SETTINGS_MODS_DIR, serv.rawServer.minecraftVersion)
|
||||||
|
|
||||||
let dropinMods = ''
|
let dropinMods = ''
|
||||||
|
|
||||||
@ -934,12 +935,12 @@ function bindDropinModFileSystemButton(){
|
|||||||
fsBtn.removeAttribute('drag')
|
fsBtn.removeAttribute('drag')
|
||||||
}
|
}
|
||||||
|
|
||||||
fsBtn.ondrop = e => {
|
fsBtn.ondrop = async e => {
|
||||||
fsBtn.removeAttribute('drag')
|
fsBtn.removeAttribute('drag')
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
DropinModUtil.addDropinMods(e.dataTransfer.files, CACHE_SETTINGS_MODS_DIR)
|
DropinModUtil.addDropinMods(e.dataTransfer.files, CACHE_SETTINGS_MODS_DIR)
|
||||||
reloadDropinMods()
|
await reloadDropinMods()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -971,18 +972,18 @@ function saveDropinModConfiguration(){
|
|||||||
|
|
||||||
// Refresh the drop-in mods when F5 is pressed.
|
// Refresh the drop-in mods when F5 is pressed.
|
||||||
// Only active on the mods tab.
|
// Only active on the mods tab.
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', async (e) => {
|
||||||
if(getCurrentView() === VIEWS.settings && selectedSettingsTab === 'settingsTabMods'){
|
if(getCurrentView() === VIEWS.settings && selectedSettingsTab === 'settingsTabMods'){
|
||||||
if(e.key === 'F5'){
|
if(e.key === 'F5'){
|
||||||
reloadDropinMods()
|
await reloadDropinMods()
|
||||||
saveShaderpackSettings()
|
saveShaderpackSettings()
|
||||||
resolveShaderpacksForUI()
|
await resolveShaderpacksForUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function reloadDropinMods(){
|
async function reloadDropinMods(){
|
||||||
resolveDropinModsForUI()
|
await resolveDropinModsForUI()
|
||||||
bindDropinModsRemoveButton()
|
bindDropinModsRemoveButton()
|
||||||
bindDropinModFileSystemButton()
|
bindDropinModFileSystemButton()
|
||||||
bindModsToggleSwitch()
|
bindModsToggleSwitch()
|
||||||
@ -997,9 +998,9 @@ let CACHE_SELECTED_SHADERPACK
|
|||||||
/**
|
/**
|
||||||
* Load shaderpack information.
|
* Load shaderpack information.
|
||||||
*/
|
*/
|
||||||
function resolveShaderpacksForUI(){
|
async function resolveShaderpacksForUI(){
|
||||||
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
||||||
CACHE_SETTINGS_INSTANCE_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.getID())
|
CACHE_SETTINGS_INSTANCE_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.rawServer.id)
|
||||||
CACHE_SHADERPACKS = DropinModUtil.scanForShaderpacks(CACHE_SETTINGS_INSTANCE_DIR)
|
CACHE_SHADERPACKS = DropinModUtil.scanForShaderpacks(CACHE_SETTINGS_INSTANCE_DIR)
|
||||||
CACHE_SELECTED_SHADERPACK = DropinModUtil.getEnabledShaderpack(CACHE_SETTINGS_INSTANCE_DIR)
|
CACHE_SELECTED_SHADERPACK = DropinModUtil.getEnabledShaderpack(CACHE_SETTINGS_INSTANCE_DIR)
|
||||||
|
|
||||||
@ -1058,13 +1059,13 @@ function bindShaderpackButton() {
|
|||||||
spBtn.removeAttribute('drag')
|
spBtn.removeAttribute('drag')
|
||||||
}
|
}
|
||||||
|
|
||||||
spBtn.ondrop = e => {
|
spBtn.ondrop = async e => {
|
||||||
spBtn.removeAttribute('drag')
|
spBtn.removeAttribute('drag')
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
DropinModUtil.addShaderpacks(e.dataTransfer.files, CACHE_SETTINGS_INSTANCE_DIR)
|
DropinModUtil.addShaderpacks(e.dataTransfer.files, CACHE_SETTINGS_INSTANCE_DIR)
|
||||||
saveShaderpackSettings()
|
saveShaderpackSettings()
|
||||||
resolveShaderpacksForUI()
|
await resolveShaderpacksForUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1073,19 +1074,19 @@ function bindShaderpackButton() {
|
|||||||
/**
|
/**
|
||||||
* Load the currently selected server information onto the mods tab.
|
* Load the currently selected server information onto the mods tab.
|
||||||
*/
|
*/
|
||||||
function loadSelectedServerOnModsTab(){
|
async function loadSelectedServerOnModsTab(){
|
||||||
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
||||||
|
|
||||||
for(const el of document.getElementsByClassName('settingsSelServContent')) {
|
for(const el of document.getElementsByClassName('settingsSelServContent')) {
|
||||||
el.innerHTML = `
|
el.innerHTML = `
|
||||||
<img class="serverListingImg" src="${serv.getIcon()}"/>
|
<img class="serverListingImg" src="${serv.rawServer.icon}"/>
|
||||||
<div class="serverListingDetails">
|
<div class="serverListingDetails">
|
||||||
<span class="serverListingName">${serv.getName()}</span>
|
<span class="serverListingName">${serv.rawServer.name}</span>
|
||||||
<span class="serverListingDescription">${serv.getDescription()}</span>
|
<span class="serverListingDescription">${serv.rawServer.description}</span>
|
||||||
<div class="serverListingInfo">
|
<div class="serverListingInfo">
|
||||||
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div>
|
<div class="serverListingVersion">${serv.rawServer.minecraftVersion}</div>
|
||||||
<div class="serverListingRevision">${serv.getVersion()}</div>
|
<div class="serverListingRevision">${serv.rawServer.version}</div>
|
||||||
${serv.isMainServer() ? `<div class="serverListingStarWrapper">
|
${serv.rawServer.mainServer ? `<div class="serverListingStarWrapper">
|
||||||
<svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px">
|
<svg id="Layer_1" viewBox="0 0 107.45 104.74" width="20px" height="20px">
|
||||||
<defs>
|
<defs>
|
||||||
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style>
|
<style>.cls-1{fill:#fff;}.cls-2{fill:none;stroke:#fff;stroke-miterlimit:10;}</style>
|
||||||
@ -1103,9 +1104,9 @@ function loadSelectedServerOnModsTab(){
|
|||||||
|
|
||||||
// Bind functionality to the server switch button.
|
// Bind functionality to the server switch button.
|
||||||
Array.from(document.getElementsByClassName('settingsSwitchServerButton')).forEach(el => {
|
Array.from(document.getElementsByClassName('settingsSwitchServerButton')).forEach(el => {
|
||||||
el.addEventListener('click', (e) => {
|
el.addEventListener('click', async e => {
|
||||||
e.target.blur()
|
e.target.blur()
|
||||||
toggleServerSelection(true)
|
await toggleServerSelection(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -1123,8 +1124,8 @@ function saveAllModConfigurations(){
|
|||||||
* server is changed.
|
* server is changed.
|
||||||
*/
|
*/
|
||||||
function animateSettingsTabRefresh(){
|
function animateSettingsTabRefresh(){
|
||||||
$(`#${selectedSettingsTab}`).fadeOut(500, () => {
|
$(`#${selectedSettingsTab}`).fadeOut(500, async () => {
|
||||||
prepareSettings()
|
await prepareSettings()
|
||||||
$(`#${selectedSettingsTab}`).fadeIn(500)
|
$(`#${selectedSettingsTab}`).fadeIn(500)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1132,15 +1133,15 @@ function animateSettingsTabRefresh(){
|
|||||||
/**
|
/**
|
||||||
* Prepare the Mods tab for display.
|
* Prepare the Mods tab for display.
|
||||||
*/
|
*/
|
||||||
function prepareModsTab(first){
|
async function prepareModsTab(first){
|
||||||
resolveModsForUI()
|
await resolveModsForUI()
|
||||||
resolveDropinModsForUI()
|
await resolveDropinModsForUI()
|
||||||
resolveShaderpacksForUI()
|
await resolveShaderpacksForUI()
|
||||||
bindDropinModsRemoveButton()
|
bindDropinModsRemoveButton()
|
||||||
bindDropinModFileSystemButton()
|
bindDropinModFileSystemButton()
|
||||||
bindShaderpackButton()
|
bindShaderpackButton()
|
||||||
bindModsToggleSwitch()
|
bindModsToggleSwitch()
|
||||||
loadSelectedServerOnModsTab()
|
await loadSelectedServerOnModsTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1348,8 +1349,8 @@ function populateMemoryStatus(){
|
|||||||
*
|
*
|
||||||
* @param {string} execPath The executable path to populate against.
|
* @param {string} execPath The executable path to populate against.
|
||||||
*/
|
*/
|
||||||
function populateJavaExecDetails(execPath){
|
async function populateJavaExecDetails(execPath){
|
||||||
const jg = new JavaGuard(DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion())
|
const jg = new JavaGuard((await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer()).rawServer.minecraftVersion)
|
||||||
jg._validateJavaBinary(execPath).then(v => {
|
jg._validateJavaBinary(execPath).then(v => {
|
||||||
if(v.valid){
|
if(v.valid){
|
||||||
const vendor = v.vendor != null ? ` (${v.vendor})` : ''
|
const vendor = v.vendor != null ? ` (${v.vendor})` : ''
|
||||||
@ -1364,18 +1365,18 @@ function populateJavaExecDetails(execPath){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateJavaReqDesc() {
|
async function populateJavaReqDesc() {
|
||||||
const mcVer = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion()
|
const mcVer = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer()).rawServer.minecraftVersion
|
||||||
if(Util.mcVersionAtLeast('1.17', mcVer)) {
|
if(mcVersionAtLeast('1.17', mcVer)) {
|
||||||
settingsJavaReqDesc.innerHTML = 'Requires Java 17 x64.'
|
settingsJavaReqDesc.innerHTML = 'Requires Java 17 x64.'
|
||||||
} else {
|
} else {
|
||||||
settingsJavaReqDesc.innerHTML = 'Requires Java 8 x64.'
|
settingsJavaReqDesc.innerHTML = 'Requires Java 8 x64.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateJvmOptsLink() {
|
async function populateJvmOptsLink() {
|
||||||
const mcVer = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion()
|
const mcVer = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer()).rawServer.minecraftVersion
|
||||||
if(Util.mcVersionAtLeast('1.17', mcVer)) {
|
if(mcVersionAtLeast('1.17', mcVer)) {
|
||||||
settingsJvmOptsLink.innerHTML = 'Available Options for Java 17 (HotSpot VM)'
|
settingsJvmOptsLink.innerHTML = 'Available Options for Java 17 (HotSpot VM)'
|
||||||
settingsJvmOptsLink.href = 'https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#extra-options-for-java'
|
settingsJvmOptsLink.href = 'https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#extra-options-for-java'
|
||||||
} else {
|
} else {
|
||||||
@ -1387,11 +1388,11 @@ function populateJvmOptsLink() {
|
|||||||
/**
|
/**
|
||||||
* Prepare the Java tab for display.
|
* Prepare the Java tab for display.
|
||||||
*/
|
*/
|
||||||
function prepareJavaTab(){
|
async function prepareJavaTab(){
|
||||||
bindRangeSlider()
|
bindRangeSlider()
|
||||||
populateMemoryStatus()
|
populateMemoryStatus()
|
||||||
populateJavaReqDesc()
|
await populateJavaReqDesc()
|
||||||
populateJvmOptsLink()
|
await populateJvmOptsLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1567,17 +1568,17 @@ function prepareUpdateTab(data = null){
|
|||||||
*
|
*
|
||||||
* @param {boolean} first Whether or not it is the first load.
|
* @param {boolean} first Whether or not it is the first load.
|
||||||
*/
|
*/
|
||||||
function prepareSettings(first = false) {
|
async function prepareSettings(first = false) {
|
||||||
if(first){
|
if(first){
|
||||||
setupSettingsTabs()
|
setupSettingsTabs()
|
||||||
initSettingsValidators()
|
initSettingsValidators()
|
||||||
prepareUpdateTab()
|
prepareUpdateTab()
|
||||||
} else {
|
} else {
|
||||||
prepareModsTab()
|
await prepareModsTab()
|
||||||
}
|
}
|
||||||
initSettingsValues()
|
await initSettingsValues()
|
||||||
prepareAccountsTab()
|
prepareAccountsTab()
|
||||||
prepareJavaTab()
|
await prepareJavaTab()
|
||||||
prepareAboutTab()
|
prepareAboutTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
*/
|
*/
|
||||||
// Requirements
|
// Requirements
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const { Type } = require('helios-distribution-types')
|
||||||
|
|
||||||
const AuthManager = require('./assets/js/authmanager')
|
const AuthManager = require('./assets/js/authmanager')
|
||||||
const ConfigManager = require('./assets/js/configmanager')
|
const ConfigManager = require('./assets/js/configmanager')
|
||||||
const DistroManager = require('./assets/js/distromanager')
|
const { DistroAPI } = require('./assets/js/distromanager')
|
||||||
const Lang = require('./assets/js/langloader')
|
const Lang = require('./assets/js/langloader')
|
||||||
|
|
||||||
let rscShouldLoad = false
|
let rscShouldLoad = false
|
||||||
@ -40,10 +41,10 @@ let currentView
|
|||||||
*/
|
*/
|
||||||
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
|
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
|
||||||
currentView = next
|
currentView = next
|
||||||
$(`${current}`).fadeOut(currentFadeTime, () => {
|
$(`${current}`).fadeOut(currentFadeTime, async () => {
|
||||||
onCurrentFade()
|
await onCurrentFade()
|
||||||
$(`${next}`).fadeIn(nextFadeTime, () => {
|
$(`${next}`).fadeIn(nextFadeTime, async () => {
|
||||||
onNextFade()
|
await onNextFade()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -57,15 +58,15 @@ function getCurrentView(){
|
|||||||
return currentView
|
return currentView
|
||||||
}
|
}
|
||||||
|
|
||||||
function showMainUI(data){
|
async function showMainUI(data){
|
||||||
|
|
||||||
if(!isDev){
|
if(!isDev){
|
||||||
loggerAutoUpdater.info('Initializing..')
|
loggerAutoUpdater.info('Initializing..')
|
||||||
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
|
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareSettings(true)
|
await prepareSettings(true)
|
||||||
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
updateSelectedServer(data.getServerById(ConfigManager.getSelectedServer()))
|
||||||
refreshServerStatus()
|
refreshServerStatus()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
||||||
@ -133,7 +134,7 @@ function showFatalStartupError(){
|
|||||||
* @param {Object} data The distro index object.
|
* @param {Object} data The distro index object.
|
||||||
*/
|
*/
|
||||||
function onDistroRefresh(data){
|
function onDistroRefresh(data){
|
||||||
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
updateSelectedServer(data.getServerById(ConfigManager.getSelectedServer()))
|
||||||
refreshServerStatus()
|
refreshServerStatus()
|
||||||
initNews()
|
initNews()
|
||||||
syncModConfigurations(data)
|
syncModConfigurations(data)
|
||||||
@ -149,10 +150,10 @@ function syncModConfigurations(data){
|
|||||||
|
|
||||||
const syncedCfgs = []
|
const syncedCfgs = []
|
||||||
|
|
||||||
for(let serv of data.getServers()){
|
for(let serv of data.servers){
|
||||||
|
|
||||||
const id = serv.getID()
|
const id = serv.rawServer.id
|
||||||
const mdls = serv.getModules()
|
const mdls = serv.modules
|
||||||
const cfg = ConfigManager.getModConfiguration(id)
|
const cfg = ConfigManager.getModConfiguration(id)
|
||||||
|
|
||||||
if(cfg != null){
|
if(cfg != null){
|
||||||
@ -161,20 +162,20 @@ function syncModConfigurations(data){
|
|||||||
const mods = {}
|
const mods = {}
|
||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.getType()
|
const type = mdl.rawModule.type
|
||||||
|
|
||||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
if(!mdl.getRequired().isRequired()){
|
if(!mdl.getRequired().value){
|
||||||
const mdlID = mdl.getVersionlessID()
|
const mdlID = mdl.getVersionlessMavenIdentifier()
|
||||||
if(modsOld[mdlID] == null){
|
if(modsOld[mdlID] == null){
|
||||||
mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
mods[mdlID] = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
} else {
|
} else {
|
||||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false)
|
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.subModules, mdl), false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(mdl.hasSubModules()){
|
if(mdl.subModules.length > 0){
|
||||||
const mdlID = mdl.getVersionlessID()
|
const mdlID = mdl.getVersionlessMavenIdentifier()
|
||||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
const v = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
if(typeof v === 'object'){
|
if(typeof v === 'object'){
|
||||||
if(modsOld[mdlID] == null){
|
if(modsOld[mdlID] == null){
|
||||||
mods[mdlID] = v
|
mods[mdlID] = v
|
||||||
@ -197,15 +198,15 @@ function syncModConfigurations(data){
|
|||||||
const mods = {}
|
const mods = {}
|
||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.getType()
|
const type = mdl.rawModule.type
|
||||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
if(!mdl.getRequired().isRequired()){
|
if(!mdl.getRequired().value){
|
||||||
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
} else {
|
} else {
|
||||||
if(mdl.hasSubModules()){
|
if(mdl.subModules.length > 0){
|
||||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
const v = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
if(typeof v === 'object'){
|
if(typeof v === 'object'){
|
||||||
mods[mdl.getVersionlessID()] = v
|
mods[mdl.getVersionlessMavenIdentifier()] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,8 +233,8 @@ function syncModConfigurations(data){
|
|||||||
function ensureJavaSettings(data) {
|
function ensureJavaSettings(data) {
|
||||||
|
|
||||||
// Nothing too fancy for now.
|
// Nothing too fancy for now.
|
||||||
for(const serv of data.getServers()){
|
for(const serv of data.servers){
|
||||||
ConfigManager.ensureJavaConfig(serv.getID(), serv.getMinecraftVersion())
|
ConfigManager.ensureJavaConfig(serv.rawServer.id, serv.rawServer.minecraftVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
@ -251,17 +252,17 @@ function scanOptionalSubModules(mdls, origin){
|
|||||||
const mods = {}
|
const mods = {}
|
||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.getType()
|
const type = mdl.rawModule.type
|
||||||
// Optional types.
|
// Optional types.
|
||||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
// It is optional.
|
// It is optional.
|
||||||
if(!mdl.getRequired().isRequired()){
|
if(!mdl.getRequired().value){
|
||||||
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
} else {
|
} else {
|
||||||
if(mdl.hasSubModules()){
|
if(mdl.hasSubModules()){
|
||||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
const v = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
if(typeof v === 'object'){
|
if(typeof v === 'object'){
|
||||||
mods[mdl.getVersionlessID()] = v
|
mods[mdl.getVersionlessMavenIdentifier()] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -272,13 +273,13 @@ function scanOptionalSubModules(mdls, origin){
|
|||||||
const ret = {
|
const ret = {
|
||||||
mods
|
mods
|
||||||
}
|
}
|
||||||
if(!origin.getRequired().isRequired()){
|
if(!origin.getRequired().value){
|
||||||
ret.value = origin.getRequired().isDefault()
|
ret.value = origin.getRequired().def
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return origin.getRequired().isDefault()
|
return origin.getRequired().def
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -323,18 +324,6 @@ function mergeModConfiguration(o, n, nReq = false){
|
|||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshDistributionIndex(remote, onSuccess, onError){
|
|
||||||
if(remote){
|
|
||||||
DistroManager.pullRemote()
|
|
||||||
.then(onSuccess)
|
|
||||||
.catch(onError)
|
|
||||||
} else {
|
|
||||||
DistroManager.pullLocal()
|
|
||||||
.then(onSuccess)
|
|
||||||
.catch(onError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function validateSelectedAccount(){
|
async function validateSelectedAccount(){
|
||||||
const selectedAcc = ConfigManager.getSelectedAccount()
|
const selectedAcc = ConfigManager.getSelectedAccount()
|
||||||
if(selectedAcc != null){
|
if(selectedAcc != null){
|
||||||
@ -429,14 +418,14 @@ function setSelectedAccount(uuid){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Synchronous Listener
|
// Synchronous Listener
|
||||||
document.addEventListener('readystatechange', function(){
|
document.addEventListener('readystatechange', async () => {
|
||||||
|
|
||||||
if (document.readyState === 'interactive' || document.readyState === 'complete'){
|
if (document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||||
if(rscShouldLoad){
|
if(rscShouldLoad){
|
||||||
rscShouldLoad = false
|
rscShouldLoad = false
|
||||||
if(!fatalStartupError){
|
if(!fatalStartupError){
|
||||||
const data = DistroManager.getDistribution()
|
const data = await DistroAPI.getDistribution()
|
||||||
showMainUI(data)
|
await showMainUI(data)
|
||||||
} else {
|
} else {
|
||||||
showFatalStartupError()
|
showFatalStartupError()
|
||||||
}
|
}
|
||||||
@ -446,13 +435,13 @@ document.addEventListener('readystatechange', function(){
|
|||||||
}, false)
|
}, false)
|
||||||
|
|
||||||
// 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, res) => {
|
ipcRenderer.on('distributionIndexDone', async (event, res) => {
|
||||||
if(res) {
|
if(res) {
|
||||||
const data = DistroManager.getDistribution()
|
const data = await DistroAPI.getDistribution()
|
||||||
syncModConfigurations(data)
|
syncModConfigurations(data)
|
||||||
ensureJavaSettings(data)
|
ensureJavaSettings(data)
|
||||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||||
showMainUI(data)
|
await showMainUI(data)
|
||||||
} else {
|
} else {
|
||||||
rscShouldLoad = true
|
rscShouldLoad = true
|
||||||
}
|
}
|
||||||
@ -467,11 +456,10 @@ ipcRenderer.on('distributionIndexDone', (event, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Util for development
|
// Util for development
|
||||||
function devModeToggle() {
|
async function devModeToggle() {
|
||||||
DistroManager.setDevMode(true)
|
DistroAPI.toggleDevMode(true)
|
||||||
DistroManager.pullLocal().then((data) => {
|
const data = await DistroAPI.getDistributionLocalLoadOnly()
|
||||||
ensureJavaSettings(data)
|
ensureJavaSettings(data)
|
||||||
updateSelectedServer(data.getServers()[0])
|
updateSelectedServer(data.getServers()[0])
|
||||||
syncModConfigurations(data)
|
syncModConfigurations(data)
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
226
package-lock.json
generated
226
package-lock.json
generated
@ -19,7 +19,7 @@
|
|||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.1.0",
|
||||||
"github-syntax-dark": "^0.5.0",
|
"github-syntax-dark": "^0.5.0",
|
||||||
"got": "^11.8.5",
|
"got": "^11.8.5",
|
||||||
"helios-core": "~0.1.2",
|
"helios-distribution-types": "^1.1.0",
|
||||||
"jquery": "^3.6.1",
|
"jquery": "^3.6.1",
|
||||||
"node-disk-info": "^1.3.0",
|
"node-disk-info": "^1.3.0",
|
||||||
"node-stream-zip": "^1.15.0",
|
"node-stream-zip": "^1.15.0",
|
||||||
@ -37,24 +37,6 @@
|
|||||||
"node": "18.x.x"
|
"node": "18.x.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@colors/colors": {
|
|
||||||
"version": "1.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
|
|
||||||
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.1.90"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@dabh/diagnostics": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
|
|
||||||
"integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==",
|
|
||||||
"dependencies": {
|
|
||||||
"colorspace": "1.1.x",
|
|
||||||
"enabled": "2.0.x",
|
|
||||||
"kuler": "^2.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@develar/schema-utils": {
|
"node_modules/@develar/schema-utils": {
|
||||||
"version": "2.6.5",
|
"version": "2.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
|
||||||
@ -439,11 +421,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz",
|
||||||
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw=="
|
"integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw=="
|
||||||
},
|
},
|
||||||
"node_modules/@types/triple-beam": {
|
|
||||||
"version": "1.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz",
|
|
||||||
"integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g=="
|
|
||||||
},
|
|
||||||
"node_modules/@types/verror": {
|
"node_modules/@types/verror": {
|
||||||
"version": "1.10.6",
|
"version": "1.10.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.6.tgz",
|
||||||
@ -1037,15 +1014,6 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/color": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
|
|
||||||
"dependencies": {
|
|
||||||
"color-convert": "^1.9.3",
|
|
||||||
"color-string": "^1.6.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@ -1062,28 +1030,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||||
},
|
},
|
||||||
"node_modules/color-string": {
|
|
||||||
"version": "1.9.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
|
|
||||||
"integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
|
|
||||||
"dependencies": {
|
|
||||||
"color-name": "^1.0.0",
|
|
||||||
"simple-swizzle": "^0.2.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color/node_modules/color-convert": {
|
|
||||||
"version": "1.9.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
|
||||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
|
||||||
"dependencies": {
|
|
||||||
"color-name": "1.1.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/color/node_modules/color-name": {
|
|
||||||
"version": "1.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
|
||||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
|
|
||||||
},
|
|
||||||
"node_modules/colors": {
|
"node_modules/colors": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
|
||||||
@ -1093,15 +1039,6 @@
|
|||||||
"node": ">=0.1.90"
|
"node": ">=0.1.90"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/colorspace": {
|
|
||||||
"version": "1.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz",
|
|
||||||
"integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==",
|
|
||||||
"dependencies": {
|
|
||||||
"color": "^3.1.3",
|
|
||||||
"text-hex": "1.0.x"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
@ -1596,11 +1533,6 @@
|
|||||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/enabled": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="
|
|
||||||
},
|
|
||||||
"node_modules/end-of-stream": {
|
"node_modules/end-of-stream": {
|
||||||
"version": "1.4.4",
|
"version": "1.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||||
@ -1873,11 +1805,6 @@
|
|||||||
"pend": "~1.2.0"
|
"pend": "~1.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fecha": {
|
|
||||||
"version": "4.2.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz",
|
|
||||||
"integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw=="
|
|
||||||
},
|
|
||||||
"node_modules/file-entry-cache": {
|
"node_modules/file-entry-cache": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||||
@ -1952,11 +1879,6 @@
|
|||||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/fn.name": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw=="
|
|
||||||
},
|
|
||||||
"node_modules/forever-agent": {
|
"node_modules/forever-agent": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||||
@ -2268,30 +2190,10 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/helios-core": {
|
"node_modules/helios-distribution-types": {
|
||||||
"version": "0.1.2",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/helios-core/-/helios-core-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/helios-distribution-types/-/helios-distribution-types-1.1.0.tgz",
|
||||||
"integrity": "sha512-xM3+nZcymy9iS36Z5odmuFZAsrSuyviQUh+dffXc+utXOP/Ox7m2HUo76t86cN8R1tLjJ/OzQJLzILACVaRryg==",
|
"integrity": "sha512-mxZPvPIBTltWUGzMzj/8LuG/UPwIEf7ZCE9h9o7pj1QCsMsctQIDu8bv91HDUEH0MByghe+t5Pi5XCHTHhzayg=="
|
||||||
"dependencies": {
|
|
||||||
"fs-extra": "^10.1.0",
|
|
||||||
"got": "^11.8.5",
|
|
||||||
"luxon": "^3.1.0",
|
|
||||||
"triple-beam": "^1.3.0",
|
|
||||||
"winston": "^3.8.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/helios-core/node_modules/fs-extra": {
|
|
||||||
"version": "10.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
|
|
||||||
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"graceful-fs": "^4.2.0",
|
|
||||||
"jsonfile": "^6.0.1",
|
|
||||||
"universalify": "^2.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/hosted-git-info": {
|
"node_modules/hosted-git-info": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
@ -2459,11 +2361,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
},
|
},
|
||||||
"node_modules/is-arrayish": {
|
|
||||||
"version": "0.3.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
|
||||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
|
||||||
},
|
|
||||||
"node_modules/is-ci": {
|
"node_modules/is-ci": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
|
||||||
@ -2515,17 +2412,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/is-stream": {
|
|
||||||
"version": "2.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
|
||||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=8"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-typedarray": {
|
"node_modules/is-typedarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||||
@ -2686,11 +2572,6 @@
|
|||||||
"json-buffer": "3.0.1"
|
"json-buffer": "3.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/kuler": {
|
|
||||||
"version": "2.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz",
|
|
||||||
"integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A=="
|
|
||||||
},
|
|
||||||
"node_modules/lazy-val": {
|
"node_modules/lazy-val": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
|
||||||
@ -2746,19 +2627,6 @@
|
|||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/logform": {
|
|
||||||
"version": "2.5.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz",
|
|
||||||
"integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==",
|
|
||||||
"dependencies": {
|
|
||||||
"@colors/colors": "1.5.0",
|
|
||||||
"@types/triple-beam": "^1.3.2",
|
|
||||||
"fecha": "^4.2.0",
|
|
||||||
"ms": "^2.1.1",
|
|
||||||
"safe-stable-stringify": "^2.3.1",
|
|
||||||
"triple-beam": "^1.3.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lowercase-keys": {
|
"node_modules/lowercase-keys": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||||
@ -2778,14 +2646,6 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/luxon": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-QrwPArQCNLAKGO/C+ZIilgIuDnEnKx5QYODdDtbFaxzsbZcc/a7WFq7MhsVYgRlwawLtvOUESTlfJ+hc/USqPg==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/matcher": {
|
"node_modules/matcher": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
||||||
@ -3003,14 +2863,6 @@
|
|||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/one-time": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==",
|
|
||||||
"dependencies": {
|
|
||||||
"fn.name": "1.x.x"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/optionator": {
|
"node_modules/optionator": {
|
||||||
"version": "0.9.1",
|
"version": "0.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
|
||||||
@ -3418,14 +3270,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/safe-stable-stringify": {
|
|
||||||
"version": "2.4.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz",
|
|
||||||
"integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/safer-buffer": {
|
"node_modules/safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
@ -3513,14 +3357,6 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/simple-swizzle": {
|
|
||||||
"version": "0.2.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
|
||||||
"integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
|
|
||||||
"dependencies": {
|
|
||||||
"is-arrayish": "^0.3.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/simple-update-notifier": {
|
"node_modules/simple-update-notifier": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
|
||||||
@ -3617,14 +3453,6 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/stack-trace": {
|
|
||||||
"version": "0.0.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
|
|
||||||
"integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==",
|
|
||||||
"engines": {
|
|
||||||
"node": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/stat-mode": {
|
"node_modules/stat-mode": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
|
||||||
@ -3774,11 +3602,6 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/text-hex": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
|
|
||||||
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
|
|
||||||
},
|
|
||||||
"node_modules/text-table": {
|
"node_modules/text-table": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
@ -3823,11 +3646,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||||
},
|
},
|
||||||
"node_modules/triple-beam": {
|
|
||||||
"version": "1.3.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
|
|
||||||
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
|
|
||||||
},
|
|
||||||
"node_modules/truncate-utf8-bytes": {
|
"node_modules/truncate-utf8-bytes": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
|
||||||
@ -3976,40 +3794,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/winreg/-/winreg-1.2.4.tgz",
|
||||||
"integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA=="
|
"integrity": "sha512-IHpzORub7kYlb8A43Iig3reOvlcBJGX9gZ0WycHhghHtA65X0LYnMRuJs+aH1abVnMJztQkvQNlltnbPi5aGIA=="
|
||||||
},
|
},
|
||||||
"node_modules/winston": {
|
|
||||||
"version": "3.8.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz",
|
|
||||||
"integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==",
|
|
||||||
"dependencies": {
|
|
||||||
"@colors/colors": "1.5.0",
|
|
||||||
"@dabh/diagnostics": "^2.0.2",
|
|
||||||
"async": "^3.2.3",
|
|
||||||
"is-stream": "^2.0.0",
|
|
||||||
"logform": "^2.4.0",
|
|
||||||
"one-time": "^1.0.0",
|
|
||||||
"readable-stream": "^3.4.0",
|
|
||||||
"safe-stable-stringify": "^2.3.1",
|
|
||||||
"stack-trace": "0.0.x",
|
|
||||||
"triple-beam": "^1.3.0",
|
|
||||||
"winston-transport": "^4.5.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/winston-transport": {
|
|
||||||
"version": "4.5.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz",
|
|
||||||
"integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==",
|
|
||||||
"dependencies": {
|
|
||||||
"logform": "^2.3.2",
|
|
||||||
"readable-stream": "^3.6.0",
|
|
||||||
"triple-beam": "^1.3.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6.4.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/word-wrap": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
|
@ -33,7 +33,8 @@
|
|||||||
"fs-extra": "^11.1.0",
|
"fs-extra": "^11.1.0",
|
||||||
"github-syntax-dark": "^0.5.0",
|
"github-syntax-dark": "^0.5.0",
|
||||||
"got": "^11.8.5",
|
"got": "^11.8.5",
|
||||||
"helios-core": "~0.1.2",
|
"helios-core": "~0.2.0-pre.1",
|
||||||
|
"helios-distribution-types": "^1.1.0",
|
||||||
"jquery": "^3.6.1",
|
"jquery": "^3.6.1",
|
||||||
"node-disk-info": "^1.3.0",
|
"node-disk-info": "^1.3.0",
|
||||||
"node-stream-zip": "^1.15.0",
|
"node-stream-zip": "^1.15.0",
|
||||||
|
Loading…
Reference in New Issue
Block a user