Preliminary Java 9+ Support (#20).

We will still not allow these versions to be used until they have been fully verified on our far-future 1.13 test server.
This commit is contained in:
Daniel Scalzi 2018-12-31 10:39:27 -05:00
parent be533af38b
commit d7fe519923
No known key found for this signature in database
GPG Key ID: 5CA2F145B63535F9
4 changed files with 146 additions and 43 deletions

View File

@ -475,12 +475,29 @@ class AssetGuard extends EventEmitter {
/** /**
* Parses a **full** Java Runtime version string and resolves * Parses a **full** Java Runtime version string and resolves
* the version information. Uses Java 8 formatting. * the version information. Dynamically detects the formatting
* to use.
* *
* @param {string} verString Full version string to parse. * @param {string} verString Full version string to parse.
* @returns Object containing the version information. * @returns Object containing the version information.
*/ */
static parseJavaRuntimeVersion(verString){ static parseJavaRuntimeVersion(verString){
const major = verString.split('.')[0]
if(major == 1){
return AssetGuard._parseJavaRuntimeVersion_8(verString)
} else {
return AssetGuard._parseJavaRuntimeVersion_9(verString)
}
}
/**
* Parses a **full** Java Runtime version string and resolves
* the version information. Uses Java 8 formatting.
*
* @param {string} verString Full version string to parse.
* @returns Object containing the version information.
*/
static _parseJavaRuntimeVersion_8(verString){
// 1.{major}.0_{update}-b{build} // 1.{major}.0_{update}-b{build}
// ex. 1.8.0_152-b16 // ex. 1.8.0_152-b16
const ret = {} const ret = {}
@ -492,16 +509,56 @@ class AssetGuard extends EventEmitter {
return ret return ret
} }
/**
* Parses a **full** Java Runtime version string and resolves
* the version information. Uses Java 9+ formatting.
*
* @param {string} verString Full version string to parse.
* @returns Object containing the version information.
*/
static _parseJavaRuntimeVersion_9(verString){
// {major}.{minor}.{revision}+{build}
// ex. 10.0.2+13
const ret = {}
let pts = verString.split('+')
ret.build = parseInt(pts[1])
pts = pts[0].split('.')
ret.major = parseInt(pts[0])
ret.minor = parseInt(pts[1])
ret.revision = parseInt(pts[2])
return ret
}
/**
* 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.
*/
static 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
}
/** /**
* Validates the output of a JVM's properties. Currently validates that a JRE is x64 * Validates the output of a JVM's properties. Currently validates that a JRE is x64
* and that the major = 8, update > 52. * and that the major = 8, update > 52.
* *
* @param {string} stderr The output to validate. * @param {string} stderr The output to validate.
* @param {string} mcVersion The minecraft version we are scanning for.
* *
* @returns {Promise.<Object>} A promise which resolves to a meta object about the JVM. * @returns {Promise.<Object>} A promise which resolves to a meta object about the JVM.
* The validity is stored inside the `valid` property. * The validity is stored inside the `valid` property.
*/ */
static _validateJVMProperties(stderr){ static _validateJVMProperties(stderr, mcVersion){
const res = stderr const res = stderr
const props = res.split('\n') const props = res.split('\n')
@ -526,11 +583,24 @@ class AssetGuard extends EventEmitter {
let verString = props[i].split('=')[1].trim() let verString = props[i].split('=')[1].trim()
console.log(props[i].trim()) console.log(props[i].trim())
const verOb = AssetGuard.parseJavaRuntimeVersion(verString) const verOb = AssetGuard.parseJavaRuntimeVersion(verString)
if(verOb.major === 8 && verOb.update > 52){ if(verOb.major < 9){
meta.version = verOb // Java 8
++checksum if(verOb.major === 8 && verOb.update > 52){
if(checksum === goal){ meta.version = verOb
break ++checksum
if(checksum === goal){
break
}
}
} else {
// Java 9+
if(AssetGuard.mcVersionAtLeast('1.13', mcVersion)){
console.log('Java 9+ not yet tested.')
/* meta.version = verOb
++checksum
if(checksum === goal){
break
} */
} }
} }
} }
@ -550,11 +620,12 @@ class AssetGuard extends EventEmitter {
* removed. * removed.
* *
* @param {string} binaryExecPath Path to the java executable we wish to validate. * @param {string} binaryExecPath Path to the java executable we wish to validate.
* @param {string} mcVersion The minecraft version we are scanning for.
* *
* @returns {Promise.<Object>} A promise which resolves to a meta object about the JVM. * @returns {Promise.<Object>} A promise which resolves to a meta object about the JVM.
* The validity is stored inside the `valid` property. * The validity is stored inside the `valid` property.
*/ */
static _validateJavaBinary(binaryExecPath){ static _validateJavaBinary(binaryExecPath, mcVersion){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if(!AssetGuard.isJavaExecPath(binaryExecPath)){ if(!AssetGuard.isJavaExecPath(binaryExecPath)){
@ -563,7 +634,7 @@ class AssetGuard extends EventEmitter {
child_process.exec('"' + binaryExecPath + '" -XshowSettings:properties', (err, stdout, stderr) => { child_process.exec('"' + binaryExecPath + '" -XshowSettings:properties', (err, stdout, stderr) => {
try { try {
// Output is stored in stderr? // Output is stored in stderr?
resolve(this._validateJVMProperties(stderr)) resolve(this._validateJVMProperties(stderr, mcVersion))
} catch (err){ } catch (err){
// Output format might have changed, validation cannot be completed. // Output format might have changed, validation cannot be completed.
resolve({valid: false}) resolve({valid: false})
@ -772,10 +843,11 @@ class AssetGuard extends EventEmitter {
/** /**
* *
* @param {Set.<string>} rootSet A set of JVM root strings to validate. * @param {Set.<string>} rootSet A set of JVM root strings to validate.
* @param {string} mcVersion The minecraft version we are scanning for.
* @returns {Promise.<Object[]>} A promise which resolves to an array of meta objects * @returns {Promise.<Object[]>} A promise which resolves to an array of meta objects
* for each valid JVM root directory. * for each valid JVM root directory.
*/ */
static async _validateJavaRootSet(rootSet){ static async _validateJavaRootSet(rootSet, mcVersion){
const rootArr = Array.from(rootSet) const rootArr = Array.from(rootSet)
const validArr = [] const validArr = []
@ -783,7 +855,7 @@ class AssetGuard extends EventEmitter {
for(let i=0; i<rootArr.length; i++){ for(let i=0; i<rootArr.length; i++){
const execPath = AssetGuard.javaExecFromRoot(rootArr[i]) const execPath = AssetGuard.javaExecFromRoot(rootArr[i])
const metaOb = await AssetGuard._validateJavaBinary(execPath) const metaOb = await AssetGuard._validateJavaBinary(execPath, mcVersion)
if(metaOb.valid){ if(metaOb.valid){
metaOb.execPath = execPath metaOb.execPath = execPath
@ -805,36 +877,50 @@ class AssetGuard extends EventEmitter {
*/ */
static _sortValidJavaArray(validArr){ static _sortValidJavaArray(validArr){
const retArr = validArr.sort((a, b) => { const retArr = validArr.sort((a, b) => {
// Note that Java 9+ uses semver and that will need to be accounted for in
// the future.
if(a.version.major === b.version.major){ if(a.version.major === b.version.major){
if(a.version.update === b.version.update){ if(a.version.major < 9){
// Java 8
if(a.version.build === b.version.build){ if(a.version.update === b.version.update){
if(a.version.build === b.version.build){
// Same version, give priority to JRE.
// Same version, give priority to JRE.
if(a.execPath.toLowerCase().indexOf('jdk') > -1){ if(a.execPath.toLowerCase().indexOf('jdk') > -1){
return b.execPath.toLowerCase().indexOf('jdk') > -1 ? 0 : 1 return b.execPath.toLowerCase().indexOf('jdk') > -1 ? 0 : 1
} else {
return -1
}
} else { } else {
return -1 return a.version.build > b.version.build ? -1 : 1
} }
} else { } else {
return a.version.build > b.version.build ? -1 : 1 return a.version.update > b.version.update ? -1 : 1
} }
} else { } else {
return a.version.update > b.version.update ? -1 : 1 // Java 9+
if(a.version.minor === b.version.minor){
if(a.version.revision === b.version.revision){
// Same version, give priority to JRE.
if(a.execPath.toLowerCase().indexOf('jdk') > -1){
return b.execPath.toLowerCase().indexOf('jdk') > -1 ? 0 : 1
} else {
return -1
}
} else {
return a.version.revision > b.version.revision ? -1 : 1
}
} else {
return a.version.minor > b.version.minor ? -1 : 1
}
} }
} else { } else {
return a.version.major > b.version.major ? -1 : 1 return a.version.major > b.version.major ? -1 : 1
} }
}) })
return retArr return retArr
@ -851,10 +937,11 @@ class AssetGuard extends EventEmitter {
* If versions are equal, JRE > JDK. * If versions are equal, JRE > JDK.
* *
* @param {string} dataDir The base launcher directory. * @param {string} dataDir The base launcher directory.
* @param {string} mcVersion The minecraft version we are scanning for.
* @returns {Promise.<string>} A Promise which resolves to the executable 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. * x64 Java installation. If none are found, null is returned.
*/ */
static async _win32JavaValidate(dataDir){ static async _win32JavaValidate(dataDir, mcVersion){
// Get possible paths from the registry. // Get possible paths from the registry.
let pathSet1 = await AssetGuard._scanRegistry() let pathSet1 = await AssetGuard._scanRegistry()
@ -875,7 +962,7 @@ class AssetGuard extends EventEmitter {
uberSet.add(jHome) uberSet.add(jHome)
} }
let pathArr = await AssetGuard._validateJavaRootSet(uberSet) let pathArr = await AssetGuard._validateJavaRootSet(uberSet, mcVersion)
pathArr = AssetGuard._sortValidJavaArray(pathArr) pathArr = AssetGuard._sortValidJavaArray(pathArr)
if(pathArr.length > 0){ if(pathArr.length > 0){
@ -896,10 +983,11 @@ class AssetGuard extends EventEmitter {
* If versions are equal, JRE > JDK. * If versions are equal, JRE > JDK.
* *
* @param {string} dataDir The base launcher directory. * @param {string} dataDir The base launcher directory.
* @param {string} mcVersion The minecraft version we are scanning for.
* @returns {Promise.<string>} A Promise which resolves to the executable 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. * x64 Java installation. If none are found, null is returned.
*/ */
static async _darwinJavaValidate(dataDir){ static async _darwinJavaValidate(dataDir, mcVersion){
const pathSet1 = await AssetGuard._scanFileSystem('/Library/Java/JavaVirtualMachines') const pathSet1 = await AssetGuard._scanFileSystem('/Library/Java/JavaVirtualMachines')
const pathSet2 = await AssetGuard._scanFileSystem(path.join(dataDir, 'runtime', 'x64')) const pathSet2 = await AssetGuard._scanFileSystem(path.join(dataDir, 'runtime', 'x64'))
@ -922,7 +1010,7 @@ class AssetGuard extends EventEmitter {
uberSet.add(jHome) uberSet.add(jHome)
} }
let pathArr = await AssetGuard._validateJavaRootSet(uberSet) let pathArr = await AssetGuard._validateJavaRootSet(uberSet, mcVersion)
pathArr = AssetGuard._sortValidJavaArray(pathArr) pathArr = AssetGuard._sortValidJavaArray(pathArr)
if(pathArr.length > 0){ if(pathArr.length > 0){
@ -941,10 +1029,11 @@ class AssetGuard extends EventEmitter {
* If versions are equal, JRE > JDK. * If versions are equal, JRE > JDK.
* *
* @param {string} dataDir The base launcher directory. * @param {string} dataDir The base launcher directory.
* @param {string} mcVersion The minecraft version we are scanning for.
* @returns {Promise.<string>} A Promise which resolves to the executable 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. * x64 Java installation. If none are found, null is returned.
*/ */
static async _linuxJavaValidate(dataDir){ static async _linuxJavaValidate(dataDir, mcVersion){
const pathSet1 = await AssetGuard._scanFileSystem('/usr/lib/jvm') const pathSet1 = await AssetGuard._scanFileSystem('/usr/lib/jvm')
const pathSet2 = await AssetGuard._scanFileSystem(path.join(dataDir, 'runtime', 'x64')) const pathSet2 = await AssetGuard._scanFileSystem(path.join(dataDir, 'runtime', 'x64'))
@ -957,7 +1046,7 @@ class AssetGuard extends EventEmitter {
uberSet.add(jHome) uberSet.add(jHome)
} }
let pathArr = await AssetGuard._validateJavaRootSet(uberSet) let pathArr = await AssetGuard._validateJavaRootSet(uberSet, mcVersion)
pathArr = AssetGuard._sortValidJavaArray(pathArr) pathArr = AssetGuard._sortValidJavaArray(pathArr)
if(pathArr.length > 0){ if(pathArr.length > 0){
@ -971,10 +1060,11 @@ class AssetGuard extends EventEmitter {
* Retrieve the path of a valid x64 Java installation. * Retrieve the path of a valid x64 Java installation.
* *
* @param {string} dataDir The base launcher directory. * @param {string} dataDir The base launcher directory.
* @param {string} mcVersion The minecraft version we are scanning for.
* @returns {string} A path to a valid x64 Java installation, null if none found. * @returns {string} A path to a valid x64 Java installation, null if none found.
*/ */
static async validateJava(dataDir){ static async validateJava(dataDir, mcVersion){
return await AssetGuard['_' + process.platform + 'JavaValidate'](dataDir) return await AssetGuard['_' + process.platform + 'JavaValidate'](dataDir, mcVersion)
} }
// #endregion // #endregion

View File

@ -86,21 +86,22 @@ function setLaunchEnabled(val){
// Bind launch button // Bind launch button
document.getElementById('launch_button').addEventListener('click', function(e){ document.getElementById('launch_button').addEventListener('click', function(e){
loggerLanding.log('Launching game..') loggerLanding.log('Launching game..')
const mcVersion = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion()
const jExe = ConfigManager.getJavaExecutable() const jExe = ConfigManager.getJavaExecutable()
if(jExe == null){ if(jExe == null){
asyncSystemScan() asyncSystemScan(mcVersion)
} else { } else {
setLaunchDetails('Please wait..') setLaunchDetails('Please wait..')
toggleLaunchArea(true) toggleLaunchArea(true)
setLaunchPercentage(0, 100) setLaunchPercentage(0, 100)
AssetGuard._validateJavaBinary(jExe).then((v) => { AssetGuard._validateJavaBinary(jExe, mcVersion).then((v) => {
loggerLanding.log('Java version meta', v) loggerLanding.log('Java version meta', v)
if(v.valid){ if(v.valid){
dlAsync() dlAsync()
} else { } else {
asyncSystemScan() asyncSystemScan(mcVersion)
} }
}) })
} }
@ -260,7 +261,13 @@ let scanAt
let extractListener let extractListener
function asyncSystemScan(launchAfter = true){ /**
* Asynchronously scan the system for valid Java installations.
*
* @param {string} mcVersion The Minecraft version we are scanning for.
* @param {boolean} launchAfter Whether we should begin to launch after scanning.
*/
function asyncSystemScan(mcVersion, launchAfter = true){
setLaunchDetails('Please wait..') setLaunchDetails('Please wait..')
toggleLaunchArea(true) toggleLaunchArea(true)
@ -424,7 +431,7 @@ function asyncSystemScan(launchAfter = true){
// Begin system Java scan. // Begin system Java scan.
setLaunchDetails('Checking system info..') setLaunchDetails('Checking system info..')
sysAEx.send({task: 'execute', function: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory()]}) sysAEx.send({task: 'execute', function: 'validateJava', argsArr: [ConfigManager.getLauncherDirectory(), mcVersion]})
} }

View File

@ -237,6 +237,8 @@ loginCancelButton.onclick = (e) => {
loginCancelEnabled(false) loginCancelEnabled(false)
if(loginViewCancelHandler != null){ if(loginViewCancelHandler != null){
loginViewCancelHandler() loginViewCancelHandler()
loginUsername.value = ''
loginPassword.value = ''
loginViewCancelHandler = null loginViewCancelHandler = null
} }
}) })

View File

@ -1107,7 +1107,11 @@ settingsJavaExecSel.onchange = (e) => {
function populateJavaExecDetails(execPath){ function populateJavaExecDetails(execPath){
AssetGuard._validateJavaBinary(execPath).then(v => { AssetGuard._validateJavaBinary(execPath).then(v => {
if(v.valid){ if(v.valid){
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major} Update ${v.version.update} (x${v.arch})` if(v.version.major < 9) {
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major} Update ${v.version.update} (x${v.arch})`
} else {
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major}.${v.version.minor}.${v.version.revision} (x${v.arch})`
}
} else { } else {
settingsJavaExecDetails.innerHTML = 'Invalid Selection' settingsJavaExecDetails.innerHTML = 'Invalid Selection'
} }