Compare commits

...

6 Commits

Author SHA1 Message Date
Daniel Scalzi
f119985211
Add version.jar to cp until 1.17. 2021-11-14 13:10:09 -05:00
Daniel Scalzi
2064e7ddd9
Patches to get 1.17 working, need to revise into real solutions. 2021-11-14 13:09:53 -05:00
Daniel Scalzi
9c6d75f812
Implement helios-core and use Server List Ping protocol. 2021-10-31 02:20:03 -04:00
Daniel Scalzi
a2168da999
Update eletron to v15, target node 16 to match. 2021-10-14 23:55:31 -04:00
Daniel Scalzi
430e840514
Update JDK handling to account for AdoptOpenJDK migration to Adoptium.
Fix bug with AdmZip by replacing it for the jdk extraction task. It will have to eventually be replaced for everything else.
Remove disclaimer about Oracle JDK, as it is no longer used.
2021-10-14 23:17:40 -04:00
Daniel Scalzi
f9e4fd8561
Fix Let's Encrypt DST Root CA X3 certificate expiration. 2021-10-01 21:57:22 -04:00
10 changed files with 5673 additions and 1297 deletions

View File

@ -17,7 +17,7 @@ jobs:
- name: Install Node.js, NPM and Yarn - name: Install Node.js, NPM and Yarn
uses: actions/setup-node@v1 uses: actions/setup-node@v1
with: with:
node-version: 14 node-version: 16
- name: Build/release Electron app - name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1 uses: samuelmeuli/action-electron-builder@v1

2
.nvmrc
View File

@ -1 +1 @@
14 16

View File

@ -83,7 +83,7 @@ This section details the setup of a basic developmentment environment.
**System Requirements** **System Requirements**
* [Node.js][nodejs] v14 * [Node.js][nodejs] v16
--- ---

View File

@ -5,6 +5,7 @@ const child_process = require('child_process')
const crypto = require('crypto') const crypto = require('crypto')
const EventEmitter = require('events') const EventEmitter = require('events')
const fs = require('fs-extra') const fs = require('fs-extra')
const StreamZip = require('node-stream-zip')
const path = require('path') const path = require('path')
const Registry = require('winreg') const Registry = require('winreg')
const request = require('request') const request = require('request')
@ -222,42 +223,6 @@ class JavaGuard extends EventEmitter {
this.mcVersion = mcVersion this.mcVersion = mcVersion
} }
// /**
// * @typedef OracleJREData
// * @property {string} uri The base uri of the JRE.
// * @property {{major: string, update: string, build: string}} version Object containing version information.
// */
// /**
// * Resolves the latest version of Oracle's JRE and parses its download link.
// *
// * @returns {Promise.<OracleJREData>} Promise which resolved to an object containing the JRE download data.
// */
// static _latestJREOracle(){
// const url = 'https://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html'
// const regex = /https:\/\/.+?(?=\/java)\/java\/jdk\/([0-9]+u[0-9]+)-(b[0-9]+)\/([a-f0-9]{32})?\/jre-\1/
// return new Promise((resolve, reject) => {
// request(url, (err, resp, body) => {
// if(!err){
// const arr = body.match(regex)
// const verSplit = arr[1].split('u')
// resolve({
// uri: arr[0],
// version: {
// major: verSplit[0],
// update: verSplit[1],
// build: arr[2]
// }
// })
// } else {
// resolve(null)
// }
// })
// })
// }
/** /**
* @typedef OpenJDKData * @typedef OpenJDKData
* @property {string} uri The base uri of the JRE. * @property {string} uri The base uri of the JRE.
@ -281,30 +246,41 @@ class JavaGuard extends EventEmitter {
if(process.platform === 'darwin') { if(process.platform === 'darwin') {
return this._latestCorretto(major) return this._latestCorretto(major)
} else { } else {
return this._latestAdoptOpenJDK(major) return this._latestAdoptium(major)
} }
} }
static _latestAdoptOpenJDK(major) { static _latestAdoptium(major) {
const majorNum = Number(major)
const sanitizedOS = process.platform === 'win32' ? 'windows' : (process.platform === 'darwin' ? 'mac' : process.platform) const sanitizedOS = process.platform === 'win32' ? 'windows' : (process.platform === 'darwin' ? 'mac' : process.platform)
const url = `https://api.adoptium.net/v3/assets/latest/${major}/hotspot?vendor=eclipse`
const url = `https://api.adoptopenjdk.net/v2/latestAssets/nightly/openjdk${major}?os=${sanitizedOS}&arch=x64&heap_size=normal&openjdk_impl=hotspot&type=jre`
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request({url, json: true}, (err, resp, body) => { request({url, json: true}, (err, resp, body) => {
if(!err && body.length > 0){ if(!err && body.length > 0){
resolve({
uri: body[0].binary_link, const targetBinary = body.find(entry => {
size: body[0].binary_size, return entry.version.major === majorNum
name: body[0].binary_name && entry.binary.os === sanitizedOS
&& entry.binary.image_type === 'jdk'
&& entry.binary.architecture === 'x64'
}) })
if(targetBinary != null) {
resolve({
uri: targetBinary.binary.package.link,
size: targetBinary.binary.package.size,
name: targetBinary.binary.package.name
})
} else {
resolve(null)
}
} else { } else {
resolve(null) resolve(null)
} }
}) })
}) })
} }
static _latestCorretto(major) { static _latestCorretto(major) {
@ -499,15 +475,15 @@ class JavaGuard extends EventEmitter {
break break
} }
} }
} else { } else if(verOb.major >= 16) {
// TODO Make this logic better. Make java 16 required.
// Java 9+ // Java 9+
if(Util.mcVersionAtLeast('1.13', this.mcVersion)){ if(Util.mcVersionAtLeast('1.17', this.mcVersion)){
console.log('Java 9+ not yet tested.') meta.version = verOb
/* meta.version = verOb
++checksum ++checksum
if(checksum === goal){ if(checksum === goal){
break break
} */ }
} }
} }
// Space included so we get only the vendor. // Space included so we get only the vendor.
@ -839,6 +815,7 @@ class JavaGuard extends EventEmitter {
pathSet1 = new Set([ pathSet1 = new Set([
...pathSet1, ...pathSet1,
...(await JavaGuard._scanFileSystem('C:\\Program Files\\Java')), ...(await JavaGuard._scanFileSystem('C:\\Program Files\\Java')),
...(await JavaGuard._scanFileSystem('C:\\Program Files\\Eclipse Foundation')),
...(await JavaGuard._scanFileSystem('C:\\Program Files\\AdoptOpenJDK')) ...(await JavaGuard._scanFileSystem('C:\\Program Files\\AdoptOpenJDK'))
]) ])
} }
@ -1583,21 +1560,7 @@ class AssetGuard extends EventEmitter {
this.java = new DLTracker([jre], jre.size, (a, self) => { this.java = new DLTracker([jre], jre.size, (a, self) => {
if(verData.name.endsWith('zip')){ if(verData.name.endsWith('zip')){
const zip = new AdmZip(a.to) this._extractJdkZip(a.to, dataDir, self)
const pos = path.join(dataDir, zip.getEntries()[0].entryName)
zip.extractAllToAsync(dataDir, true, (err) => {
if(err){
console.log(err)
self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
} else {
fs.unlink(a.to, err => {
if(err){
console.log(err)
}
self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
})
}
})
} else { } else {
// Tar.gz // Tar.gz
@ -1638,67 +1601,31 @@ class AssetGuard extends EventEmitter {
} }
// _enqueueOracleJRE(dataDir){ async _extractJdkZip(zipPath, runtimeDir, self) {
// return new Promise((resolve, reject) => {
// JavaGuard._latestJREOracle().then(verData => {
// if(verData != null){
// const combined = verData.uri + PLATFORM_MAP[process.platform] const zip = new StreamZip.async({
file: zipPath,
storeEntries: true
})
// const opts = { let pos = ''
// url: combined, try {
// headers: { const entries = await zip.entries()
// 'Cookie': 'oraclelicense=accept-securebackup-cookie' pos = path.join(runtimeDir, Object.keys(entries)[0])
// }
// }
// request.head(opts, (err, resp, body) => { console.log('Extracting jdk..')
// if(err){ await zip.extract(null, runtimeDir)
// resolve(false) console.log('Cleaning up..')
// } else { await fs.remove(zipPath)
// dataDir = path.join(dataDir, 'runtime', 'x64') console.log('Jdk extraction complete.')
// const name = combined.substring(combined.lastIndexOf('/')+1)
// const fDir = path.join(dataDir, name)
// const jre = new Asset(name, null, parseInt(resp.headers['content-length']), opts, fDir)
// 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('complete', 'java', JavaGuard.javaExecFromRoot(pos))
// })
// })
// }) } catch(err) {
// resolve(true) console.log(err)
// } } finally {
// }) zip.close()
self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos))
// } else { }
// resolve(false) }
// }
// })
// })
// }
// _enqueueMojangJRE(dir){ // _enqueueMojangJRE(dir){
// return new Promise((resolve, reject) => { // return new Promise((resolve, reject) => {

View File

@ -96,6 +96,16 @@ class ProcessBuilder {
return child return child
} }
/**
* Get the platform specific classpath separator. On windows, this is a semicolon.
* On Unix, this is a colon.
*
* @returns {string} The classpath separator for the current operating system.
*/
static getClasspathSeparator() {
return process.platform === 'win32' ? ';' : ':'
}
/** /**
* Determine if an optional mod is enabled from its configuration value. If the * Determine if an optional mod is enabled from its configuration value. If the
* configuration value is null, the required object will be used to * configuration value is null, the required object will be used to
@ -339,7 +349,7 @@ class ProcessBuilder {
// Classpath Argument // Classpath Argument
args.push('-cp') args.push('-cp')
args.push(this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':')) args.push(this.classpathArg(mods, tempNativePath).join(ProcessBuilder.getClasspathSeparator()))
// Java Arguments // Java Arguments
if(process.platform === 'darwin'){ if(process.platform === 'darwin'){
@ -377,6 +387,19 @@ class ProcessBuilder {
// JVM Arguments First // JVM Arguments First
let args = this.versionData.arguments.jvm let args = this.versionData.arguments.jvm
// Debug securejarhandler
// args.push('-Dbsl.debug=true')
if(this.forgeData.arguments.jvm != null) {
for(const argStr of this.forgeData.arguments.jvm) {
args.push(argStr
.replaceAll('${library_directory}', this.libPath)
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
.replaceAll('${version_name}', this.forgeData.id)
)
}
}
//args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml') //args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
// Java Arguments // Java Arguments
@ -489,7 +512,7 @@ class ProcessBuilder {
val = args[i].replace(argDiscovery, this.launcherVersion) val = args[i].replace(argDiscovery, this.launcherVersion)
break break
case 'classpath': case 'classpath':
val = this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':') val = this.classpathArg(mods, tempNativePath).join(ProcessBuilder.getClasspathSeparator())
break break
} }
if(val != null){ if(val != null){
@ -647,9 +670,13 @@ class ProcessBuilder {
classpathArg(mods, tempNativePath){ classpathArg(mods, tempNativePath){
let cpArgs = [] let cpArgs = []
// Add the version.jar to the classpath. if(!Util.mcVersionAtLeast('1.17', this.server.getMinecraftVersion())) {
const version = this.versionData.id // Add the version.jar to the classpath.
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar')) // Must not be added to the classpath for Forge 1.17+.
const version = this.versionData.id
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
}
if(this.usingLiteLoader){ if(this.usingLiteLoader){
cpArgs.push(this.llPath) cpArgs.push(this.llPath)
@ -788,6 +815,15 @@ class ProcessBuilder {
let libs = [] let libs = []
for(let sm of mdl.getSubModules()){ for(let sm of mdl.getSubModules()){
if(sm.getType() === DistroManager.Types.Library){ if(sm.getType() === DistroManager.Types.Library){
// TODO Add as file or something.
const x = sm.getIdentifier()
console.log(x)
if(x.includes(':universal') || x.includes(':slim') || x.includes(':extra') || x.includes(':srg') || x.includes(':client')) {
console.log('SKIPPING ' + x)
continue
}
libs.push(sm.getArtifact().getPath()) libs.push(sm.getArtifact().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.

View File

@ -4,7 +4,8 @@
// Requirements // Requirements
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 { getServerStatus } = require('helios-core')
// Internal Requirements // Internal Requirements
const DiscordWrapper = require('./assets/js/discordwrapper') const DiscordWrapper = require('./assets/js/discordwrapper')
@ -225,11 +226,11 @@ const refreshServerStatus = async function(fade = false){
try { try {
const serverURL = new URL('my://' + serv.getAddress()) const serverURL = new URL('my://' + serv.getAddress())
const servStat = await ServerStatus.getStatus(serverURL.hostname, serverURL.port)
if(servStat.online){ const servStat = await getServerStatus(47, serverURL.hostname, Number(serverURL.port))
pLabel = 'PLAYERS' console.log(servStat)
pVal = servStat.onlinePlayers + '/' + servStat.maxPlayers pLabel = 'PLAYERS'
} pVal = servStat.players.online + '/' + servStat.players.max
} catch (err) { } catch (err) {
loggerLanding.warn('Unable to refresh server status, assuming offline.') loggerLanding.warn('Unable to refresh server status, assuming offline.')
@ -323,7 +324,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){
// Show this information to the user. // Show this information to the user.
setOverlayContent( setOverlayContent(
'No Compatible<br>Java Installation Found', 'No Compatible<br>Java Installation Found',
'In order to join WesterosCraft, you need a 64-bit installation of Java 8. Would you like us to install a copy? By installing, you accept <a href="http://www.oracle.com/technetwork/java/javase/terms/license/index.html">Oracle\'s license agreement</a>.', 'In order to join WesterosCraft, you need a 64-bit installation of Java 8. Would you like us to install a copy?',
'Install Java', 'Install Java',
'Install Manually' 'Install Manually'
) )

View File

@ -85,7 +85,7 @@ bindFileSelectors()
/** /**
* Bind value validators to the settings UI elements. These will * Bind value validators to the settings UI elements. These will
* validate against the criteria defined in the ConfigManager (if * validate against the criteria defined in the ConfigManager (if
* and). If the value is invalid, the UI will reflect this and saving * any). If the value is invalid, the UI will reflect this and saving
* will be disabled until the value is corrected. This is an automated * will be disabled until the value is corrected. This is an automated
* process. More complex UI may need to be bound separately. * process. More complex UI may need to be bound separately.
*/ */

View File

@ -1,4 +1,5 @@
require('@electron/remote/main').initialize() const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
// Requirements // Requirements
const { app, BrowserWindow, ipcMain, Menu } = require('electron') const { app, BrowserWindow, ipcMain, Menu } = require('electron')
@ -87,9 +88,6 @@ ipcMain.on('distributionIndexDone', (event, res) => {
// https://electronjs.org/docs/tutorial/offscreen-rendering // https://electronjs.org/docs/tutorial/offscreen-rendering
app.disableHardwareAcceleration() app.disableHardwareAcceleration()
// https://github.com/electron/electron/issues/18397
app.allowRendererProcessReuse = true
// Keep a global reference of the window object, if you don't, the window will // Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected. // be closed automatically when the JavaScript object is garbage collected.
let win let win
@ -104,11 +102,11 @@ function createWindow() {
webPreferences: { webPreferences: {
preload: path.join(__dirname, 'app', 'assets', 'js', 'preloader.js'), preload: path.join(__dirname, 'app', 'assets', 'js', 'preloader.js'),
nodeIntegration: true, nodeIntegration: true,
contextIsolation: false, contextIsolation: false
enableRemoteModule: true
}, },
backgroundColor: '#171614' backgroundColor: '#171614'
}) })
remoteMain.enable(win.webContents)
ejse.data('bkid', Math.floor((Math.random() * fs.readdirSync(path.join(__dirname, 'app', 'assets', 'images', 'backgrounds')).length))) ejse.data('bkid', Math.floor((Math.random() * fs.readdirSync(path.join(__dirname, 'app', 'assets', 'images', 'backgrounds')).length)))

6702
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -20,28 +20,30 @@
"lint": "eslint --config .eslintrc.json ." "lint": "eslint --config .eslintrc.json ."
}, },
"engines": { "engines": {
"node": "14.x.x" "node": "16.x.x"
}, },
"dependencies": { "dependencies": {
"@electron/remote": "^1.2.0", "@electron/remote": "^2.0.1",
"adm-zip": "^0.5.5", "adm-zip": "^0.5.9",
"async": "^3.2.0", "async": "^3.2.1",
"discord-rpc": "^3.2.0", "discord-rpc": "^3.2.0",
"ejs": "^3.1.6", "ejs": "^3.1.6",
"ejs-electron": "^2.1.1", "ejs-electron": "^2.1.1",
"electron-updater": "^4.3.9", "electron-updater": "^4.3.9",
"fs-extra": "^10.0.0", "fs-extra": "^10.0.0",
"github-syntax-dark": "^0.5.0", "github-syntax-dark": "^0.5.0",
"helios-core": "^0.1.0-alpha.3",
"jquery": "^3.6.0", "jquery": "^3.6.0",
"node-stream-zip": "^1.15.0",
"request": "^2.88.2", "request": "^2.88.2",
"semver": "^7.3.5", "semver": "^7.3.5",
"tar-fs": "^2.1.1", "tar-fs": "^2.1.1",
"winreg": "^1.2.4" "winreg": "^1.2.4"
}, },
"devDependencies": { "devDependencies": {
"electron": "^13.1.4", "electron": "^15.2.0",
"electron-builder": "^22.11.7", "electron-builder": "^22.13.1",
"eslint": "^7.29.0" "eslint": "^8.0.1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",