diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..bbd00849 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,29 @@ +name: Build/release + +on: push + +jobs: + release: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + + steps: + - name: Check out Git repository + uses: actions/checkout@v1 + + - name: Install Node.js, NPM and Yarn + uses: actions/setup-node@v1 + with: + node-version: 16 + + - name: Build/release Electron app + uses: samuelmeuli/action-electron-builder@v1 + with: + github_token: ${{ secrets.github_token }} + + # If the commit is tagged with a version (e.g. "v1.0.0"), + # release the app after building + release: ${{ startsWith(github.ref, 'refs/tags/v') }} \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index 3cacc0b9..19c7bdba 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -12 \ No newline at end of file +16 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 01b7f8a7..00000000 --- a/.travis.yml +++ /dev/null @@ -1,45 +0,0 @@ -matrix: - include: - - os: osx - osx_image: xcode11.3 - language: node_js - node_js: "12" - env: - - ELECTRON_CACHE=$HOME/.cache/electron - - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder - - ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true - - CSC_IDENTITY_AUTO_DISCOVERY=false - - - os: linux - services: docker - language: generic - node_js: "12" - env: - - ELECTRON_BUILDER_ALLOW_UNRESOLVED_DEPENDENCIES=true - -cache: - directories: - - node_modules - - $HOME/.cache/electron - - $HOME/.cache/electron-builder - -script: - - | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then - ENVS=`env | grep -iE '(DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|_TOKEN|_KEY|AWS_|STRIP|BUILD_)' | sed -n '/^[^\t]/s/=.*//p' | sed '/^$/d' | sed 's/^/-e /g' | tr '\n' ' '` - docker run $ENVS --rm \ - -v ${PWD}:/project \ - -v ~/.cache/electron:/root/.cache/electron \ - -v ~/.cache/electron-builder:/root/.cache/electron-builder \ - electronuserland/builder:wine \ - /bin/bash -c "node -v && npm ci && npm run cilinux" - else - npm run cidarwin - fi - -before_cache: - - rm -rf $HOME/.cache/electron-builder/wine - -branches: - except: - - "/^v\\d+\\.\\d+\\.\\d+$/" \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..a7ce69e2 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017-2021 Daniel D. Scalzi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index caf0fcb7..4d7d6204 100644 --- a/README.md +++ b/README.md @@ -53,9 +53,10 @@ If you download from the [Releases](https://github.com/dscalzi/HeliosLauncher/re | Platform | File | | -------- | ---- | -| Windows x64 | `helioslauncher-setup-VERSION.exe` | -| macOS | `helioslauncher-VERSION.dmg` | -| Linux x64 | `helioslauncher-VERSION-x86_64.AppImage` | +| Windows x64 | `Helios-Launcher-setup-VERSION.exe` | +| macOS x64 | `Helios-Launcher-setup-VERSION.dmg` | +| macOS arm64 | `Helios-Launcher-setup-VERSION-arm64.dmg` | +| Linux x64 | `Helios-Launcher-setup-VERSION.AppImage` | ## Console @@ -76,11 +77,13 @@ If you want to export the console output, simply right click anywhere on the con ## Development +This section details the setup of a basic developmentment environment. + ### Getting Started **System Requirements** -* [Node.js][nodejs] v12 +* [Node.js][nodejs] v16 --- @@ -175,14 +178,7 @@ Note that you **cannot** open the DevTools window while using this debug configu ### Note on Third-Party Usage -You may use this software in your own project so long as the following conditions are met. - -* Credit is expressly given to the original authors (Daniel Scalzi). - * Include a link to the original source on the launcher's About page. - * Credit the authors and provide a link to the original source in any publications or download pages. -* The source code remain **public** as a fork of this repository. - -We reserve the right to update these conditions at any time, please check back periodically. +Please give credit to the original author and provide a link to the original source. This is free software, please do at least this much. --- diff --git a/app/assets/js/assetguard.js b/app/assets/js/assetguard.js index 4d304335..36485c15 100644 --- a/app/assets/js/assetguard.js +++ b/app/assets/js/assetguard.js @@ -5,6 +5,7 @@ const child_process = require('child_process') const crypto = require('crypto') const EventEmitter = require('events') const fs = require('fs-extra') +const StreamZip = require('node-stream-zip') const path = require('path') const Registry = require('winreg') const request = require('request') @@ -222,42 +223,6 @@ class JavaGuard extends EventEmitter { 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.} 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 * @property {string} uri The base uri of the JRE. @@ -281,30 +246,41 @@ class JavaGuard extends EventEmitter { if(process.platform === 'darwin') { return this._latestCorretto(major) } 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 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) => { request({url, json: true}, (err, resp, body) => { if(!err && body.length > 0){ - resolve({ - uri: body[0].binary_link, - size: body[0].binary_size, - name: body[0].binary_name + + const targetBinary = body.find(entry => { + return entry.version.major === majorNum + && 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 { resolve(null) } }) }) - } static _latestCorretto(major) { @@ -839,6 +815,7 @@ class JavaGuard extends EventEmitter { pathSet1 = new Set([ ...pathSet1, ...(await JavaGuard._scanFileSystem('C:\\Program Files\\Java')), + ...(await JavaGuard._scanFileSystem('C:\\Program Files\\Eclipse Foundation')), ...(await JavaGuard._scanFileSystem('C:\\Program Files\\AdoptOpenJDK')) ]) } @@ -1583,21 +1560,7 @@ class AssetGuard extends EventEmitter { this.java = new DLTracker([jre], jre.size, (a, self) => { if(verData.name.endsWith('zip')){ - const zip = new AdmZip(a.to) - 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)) - }) - } - }) + this._extractJdkZip(a.to, dataDir, self) } else { // Tar.gz @@ -1638,6 +1601,32 @@ class AssetGuard extends EventEmitter { } + async _extractJdkZip(zipPath, runtimeDir, self) { + + const zip = new StreamZip.async({ + file: zipPath, + storeEntries: true + }) + + let pos = '' + try { + const entries = await zip.entries() + pos = path.join(runtimeDir, Object.keys(entries)[0]) + + console.log('Extracting jdk..') + await zip.extract(null, runtimeDir) + console.log('Cleaning up..') + await fs.remove(zipPath) + console.log('Jdk extraction complete.') + + } catch(err) { + console.log(err) + } finally { + zip.close() + self.emit('complete', 'java', JavaGuard.javaExecFromRoot(pos)) + } + } + // _enqueueOracleJRE(dataDir){ // return new Promise((resolve, reject) => { // JavaGuard._latestJREOracle().then(verData => { diff --git a/app/assets/js/configmanager.js b/app/assets/js/configmanager.js index 65a73061..2c0bb53c 100644 --- a/app/assets/js/configmanager.js +++ b/app/assets/js/configmanager.js @@ -9,7 +9,7 @@ const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.e const dataPath = path.join(sysRoot, '.helioslauncher') // Forked processes do not have access to electron, so we have this workaround. -const launcherDir = process.env.CONFIG_DIRECT_PATH || require('electron').remote.app.getPath('userData') +const launcherDir = process.env.CONFIG_DIRECT_PATH || require('@electron/remote').app.getPath('userData') /** * Retrieve the absolute path of the launcher directory. diff --git a/app/assets/js/dropinmodutil.js b/app/assets/js/dropinmodutil.js index 0a61012e..84ad4fa6 100644 --- a/app/assets/js/dropinmodutil.js +++ b/app/assets/js/dropinmodutil.js @@ -92,14 +92,17 @@ exports.addDropinMods = function(files, modsdir) { * @param {string} modsDir The path to the mods directory. * @param {string} fullName The fullName of the discovered mod to delete. * - * @returns {boolean} True if the mod was deleted, otherwise false. + * @returns {Promise.} True if the mod was deleted, otherwise false. */ -exports.deleteDropinMod = function(modsDir, fullName){ - const res = shell.moveItemToTrash(path.join(modsDir, fullName)) - if(!res){ +exports.deleteDropinMod = async function(modsDir, fullName){ + try { + await shell.trashItem(path.join(modsDir, fullName)) + return true + } catch(error) { shell.beep() + console.error('Error deleting drop-in mod.', error) + return false } - return res } /** diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js index 373337dd..77dba8f9 100644 --- a/app/assets/js/scripts/landing.js +++ b/app/assets/js/scripts/landing.js @@ -130,7 +130,7 @@ function updateSelectedAccount(authUser){ username = authUser.displayName } if(authUser.uuid != null){ - document.getElementById('avatarContainer').style.backgroundImage = `url('https://crafatar.com/renders/body/${authUser.uuid}')` + document.getElementById('avatarContainer').style.backgroundImage = `url('https://mc-heads.net/body/${authUser.uuid}/right')` } } user_text.innerHTML = username @@ -327,7 +327,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){ // Show this information to the user. setOverlayContent( 'No Compatible
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 Oracle\'s license agreement.', + '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 Manually' ) @@ -1147,4 +1147,4 @@ function loadNews(){ }) }) }) -} \ No newline at end of file +} diff --git a/app/assets/js/scripts/overlay.js b/app/assets/js/scripts/overlay.js index ed704047..22d81d62 100644 --- a/app/assets/js/scripts/overlay.js +++ b/app/assets/js/scripts/overlay.js @@ -299,7 +299,7 @@ function populateAccountListings(){ let htmlString = '' for(let i=0; i - +
${accounts[i].displayName}
` } diff --git a/app/assets/js/scripts/settings.js b/app/assets/js/scripts/settings.js index 4412a7aa..4a1997fe 100644 --- a/app/assets/js/scripts/settings.js +++ b/app/assets/js/scripts/settings.js @@ -444,7 +444,7 @@ function populateAuthAccounts(){ const acc = authAccounts[val] authAccountStr += `
- ${acc.displayName} + ${acc.displayName}
@@ -687,9 +687,9 @@ function resolveDropinModsForUI(){ function bindDropinModsRemoveButton(){ const sEls = settingsModsContainer.querySelectorAll('[remmod]') Array.from(sEls).map((v, index, arr) => { - v.onclick = () => { + v.onclick = async () => { const fullName = v.getAttribute('remmod') - const res = DropinModUtil.deleteDropinMod(CACHE_SETTINGS_MODS_DIR, fullName) + const res = await DropinModUtil.deleteDropinMod(CACHE_SETTINGS_MODS_DIR, fullName) if(res){ document.getElementById(fullName).remove() } else { diff --git a/app/assets/js/scripts/uicore.js b/app/assets/js/scripts/uicore.js index 73e372aa..7d3cddbd 100644 --- a/app/assets/js/scripts/uicore.js +++ b/app/assets/js/scripts/uicore.js @@ -5,10 +5,11 @@ * modules, excluding dependencies. */ // Requirements -const $ = require('jquery') -const {ipcRenderer, remote, shell, webFrame} = require('electron') -const isDev = require('./assets/js/isdev') -const LoggerUtil = require('./assets/js/loggerutil') +const $ = require('jquery') +const {ipcRenderer, shell, webFrame} = require('electron') +const remote = require('@electron/remote') +const isDev = require('./assets/js/isdev') +const LoggerUtil = require('./assets/js/loggerutil') const loggerUICore = LoggerUtil('%c[UICore]', 'color: #000668; font-weight: bold') const loggerAutoUpdater = LoggerUtil('%c[AutoUpdater]', 'color: #000668; font-weight: bold') @@ -48,7 +49,7 @@ if(!isDev){ loggerAutoUpdaterSuccess.log('New update available', info.version) if(process.platform === 'darwin'){ - info.darwindownload = `https://github.com/dscalzi/HeliosLauncher/releases/download/v${info.version}/helioslauncher-setup-${info.version}.dmg` + info.darwindownload = `https://github.com/dscalzi/HeliosLauncher/releases/download/v${info.version}/helioslauncher-setup-${info.version}${process.arch === 'arm64' ? '-arm64' : ''}.dmg` showUpdateUI(info) } diff --git a/app/login.ejs b/app/login.ejs index 18d93a00..7ecc4a6c 100644 --- a/app/login.ejs +++ b/app/login.ejs @@ -29,7 +29,7 @@
- forgot password? + forgot password?