Implemented Java validations within the UI.
When a user attemps to launch, the configured Java executable will be validated. If it is invalid, we will look for a valid installation. If no valid installation is found, the user will be prompted with an option to install Java. An option to decline needs to be added. If they choose to install, it will download, extract, and update the executable in the config. The game will then be launched. Also added progress tracking for asset validations, as they can potentially take a bit longer. Showing progress assures the user that the program isn't stuck or broken.
This commit is contained in:
@@ -32,7 +32,8 @@ const mkpath = require('mkdirp');
|
||||
const path = require('path')
|
||||
const Registry = require('winreg')
|
||||
const request = require('request')
|
||||
const targz = require('targz')
|
||||
const tar = require('tar-fs')
|
||||
const zlib = require('zlib')
|
||||
|
||||
// Constants
|
||||
const PLATFORM_MAP = {
|
||||
@@ -558,6 +559,23 @@ class AssetGuard extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the OS-specific executable for the given Java
|
||||
* installation. Supported OS's are win32, darwin, linux.
|
||||
*
|
||||
* @param {string} rootDir The root directory of the Java installation.
|
||||
*/
|
||||
static javaExecFromRoot(rootDir){
|
||||
if(process.platform === 'win32'){
|
||||
return path.join(rootDir, 'bin', 'javaw.exe')
|
||||
} else if(process.platform === 'darwin'){
|
||||
return path.join(rootDir, 'Contents', 'Home', 'bin', 'java')
|
||||
} else if(process.platform === 'linux'){
|
||||
return path.join(rootDir, 'bin', 'java')
|
||||
}
|
||||
return rootDir
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Mojang's launcher.json file.
|
||||
*
|
||||
@@ -583,20 +601,16 @@ class AssetGuard extends EventEmitter {
|
||||
* the function's code throws errors. That would indicate that the option is changed or
|
||||
* removed.
|
||||
*
|
||||
* @param {string} binaryPath Path to the root of the java binary we wish to validate.
|
||||
* @param {string} binaryExecPath Path to the java executable we wish to validate.
|
||||
*
|
||||
* @returns {Promise.<boolean>} Resolves to false only if the test is successful and the result
|
||||
* is less than 64.
|
||||
*/
|
||||
static _validateJavaBinary(binaryPath){
|
||||
static _validateJavaBinary(binaryExecPath){
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let fBp = binaryPath
|
||||
if(!fBp.endsWith('.exe')){
|
||||
fBp = path.join(binaryPath, 'bin', 'java.exe')
|
||||
}
|
||||
if(fs.existsSync(fBp)){
|
||||
child_process.exec('"' + fBp + '" -XshowSettings:properties', (err, stdout, stderr) => {
|
||||
if(fs.existsSync(binaryExecPath)){
|
||||
child_process.exec('"' + binaryExecPath + '" -XshowSettings:properties', (err, stdout, stderr) => {
|
||||
|
||||
try {
|
||||
// Output is stored in stderr?
|
||||
@@ -605,7 +619,7 @@ class AssetGuard extends EventEmitter {
|
||||
for(let i=0; i<props.length; i++){
|
||||
if(props[i].indexOf('sun.arch.data.model') > -1){
|
||||
let arch = props[i].split('=')[1].trim()
|
||||
console.log(props[i].trim() + ' for ' + binaryPath)
|
||||
console.log(props[i].trim() + ' for ' + binaryExecPath)
|
||||
resolve(parseInt(arch) >= 64)
|
||||
}
|
||||
}
|
||||
@@ -770,7 +784,7 @@ class AssetGuard extends EventEmitter {
|
||||
* If versions are equal, JRE > JDK.
|
||||
*
|
||||
* @param {string} dataDir The base launcher directory.
|
||||
* @returns {Promise.<string>} A Promise which resolves to the root path of a valid
|
||||
* @returns {Promise.<string>} A Promise which resolves to the executable path of a valid
|
||||
* x64 Java installation. If none are found, null is returned.
|
||||
*/
|
||||
static async _win32JavaValidate(dataDir){
|
||||
@@ -813,9 +827,10 @@ class AssetGuard extends EventEmitter {
|
||||
|
||||
// Validate that the binary is actually x64.
|
||||
for(let i=0; i<pathArr.length; i++) {
|
||||
let res = await AssetGuard._validateJavaBinary(pathArr[i])
|
||||
const execPath = AssetGuard.javaExecFromRoot(pathArr[i])
|
||||
let res = await AssetGuard._validateJavaBinary(execPath)
|
||||
if(res){
|
||||
return pathArr[i]
|
||||
return execPath
|
||||
}
|
||||
}
|
||||
|
||||
@@ -961,9 +976,13 @@ class AssetGuard extends EventEmitter {
|
||||
const objectPath = path.join(localPath, 'objects')
|
||||
|
||||
const assetDlQueue = []
|
||||
let dlSize = 0;
|
||||
let dlSize = 0
|
||||
let acc = 0
|
||||
const total = Object.keys(indexData.objects).length
|
||||
//const objKeys = Object.keys(data.objects)
|
||||
async.forEachOfLimit(indexData.objects, 10, function(value, key, cb){
|
||||
acc++
|
||||
self.emit('assetVal', {acc, total})
|
||||
const hash = value.hash
|
||||
const assetName = path.join(hash.substring(0, 2), hash)
|
||||
const urlName = hash.substring(0, 2) + "/" + hash
|
||||
@@ -1128,7 +1147,7 @@ class AssetGuard extends EventEmitter {
|
||||
self.forge = self._parseDistroModules(serv.modules, serv.mc_version)
|
||||
//Correct our workaround here.
|
||||
let decompressqueue = self.forge.callback
|
||||
self.forge.callback = function(asset){
|
||||
self.forge.callback = function(asset, self){
|
||||
if(asset.to.toLowerCase().endsWith('.pack.xz')){
|
||||
AssetGuard._extractPackXZ([asset.to], self.javaexec)
|
||||
}
|
||||
@@ -1251,7 +1270,7 @@ class AssetGuard extends EventEmitter {
|
||||
// Java (Category=''') Validation (download) Functions
|
||||
// #region
|
||||
|
||||
_enqueueOracleJRE(dir){
|
||||
_enqueueOracleJRE(dataDir){
|
||||
return new Promise((resolve, reject) => {
|
||||
AssetGuard._latestJREOracle().then(verData => {
|
||||
if(verData != null){
|
||||
@@ -1269,24 +1288,37 @@ class AssetGuard extends EventEmitter {
|
||||
if(err){
|
||||
resolve(false)
|
||||
} else {
|
||||
dataDir = path.join(dataDir, 'runtime', 'x64')
|
||||
const name = combined.substring(combined.lastIndexOf('/')+1)
|
||||
const fDir = path.join(dir, name)
|
||||
const fDir = path.join(dataDir, name)
|
||||
const jre = new Asset(name, null, resp.headers['content-length'], opts, fDir)
|
||||
this.java = new DLTracker([jre], jre.size, a => {
|
||||
targz.decompress({
|
||||
src: a.to,
|
||||
dest: dir
|
||||
}, err => {
|
||||
if(err){
|
||||
console.log(err)
|
||||
} else {
|
||||
this.java = new DLTracker([jre], jre.size, (a, self) => {
|
||||
let h = null
|
||||
fs.createReadStream(a.to)
|
||||
.on('error', err => console.log(err))
|
||||
.pipe(zlib.createGunzip())
|
||||
.on('error', err => console.log(err))
|
||||
.pipe(tar.extract(dataDir, {
|
||||
map: (header) => {
|
||||
if(h == null){
|
||||
h = header.name
|
||||
}
|
||||
}
|
||||
}))
|
||||
.on('error', err => console.log(err))
|
||||
.on('finish', () => {
|
||||
fs.unlink(a.to, err => {
|
||||
if(err){
|
||||
console.log(err)
|
||||
}
|
||||
if(h.indexOf('/') > -1){
|
||||
h = h.substring(0, h.indexOf('/'))
|
||||
}
|
||||
const pos = path.join(dataDir, h)
|
||||
self.emit('jExtracted', AssetGuard.javaExecFromRoot(pos))
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
resolve(true)
|
||||
}
|
||||
@@ -1371,7 +1403,7 @@ class AssetGuard extends EventEmitter {
|
||||
writeStream.on('close', () => {
|
||||
//console.log('DLResults ' + asset.size + ' ' + count + ' ', asset.size === count)
|
||||
if(concurrentDlTracker.callback != null){
|
||||
concurrentDlTracker.callback.apply(concurrentDlTracker, [asset])
|
||||
concurrentDlTracker.callback.apply(concurrentDlTracker, [asset, self])
|
||||
}
|
||||
cb()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user