Add files via upload

This commit is contained in:
PinkFloyd1213 2020-08-16 02:40:19 +02:00 committed by GitHub
parent 46853157ec
commit 3e82b100bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 18477 additions and 18474 deletions

432
README.md
View File

@ -1,216 +1,216 @@
<p align="center"><img src="./app/assets/images/SealCircle.png" width="150px" height="150px" alt="aventium softworks"></p> <p align="center"><img src="./app/assets/images/SealCircle.png" width="150px" height="150px" alt="aventium softworks"></p>
<h1 align="center">Helios Launcher</h1> <h1 align="center">Creeponnia Launcher</h1>
<em><h5 align="center">(formerly Electron Launcher)</h5></em> <em><h5 align="center">(formerly Electron Launcher)</h5></em>
[<p align="center"><img src="https://img.shields.io/travis/dscalzi/HeliosLauncher.svg?style=for-the-badge" alt="travis">](https://travis-ci.org/dscalzi/HeliosLauncher) [<img src="https://img.shields.io/github/downloads/dscalzi/HeliosLauncher/total.svg?style=for-the-badge" alt="downloads">](https://github.com/dscalzi/HeliosLauncher/releases) <img src="https://forthebadge.com/images/badges/winter-is-coming.svg" height="28px" alt="stark"></p> [<p align="center"><img src="https://img.shields.io/travis/dscalzi/HeliosLauncher.svg?style=for-the-badge" alt="travis">](https://travis-ci.org/dscalzi/HeliosLauncher) [<img src="https://img.shields.io/github/downloads/dscalzi/HeliosLauncher/total.svg?style=for-the-badge" alt="downloads">](https://github.com/dscalzi/HeliosLauncher/releases) <img src="https://forthebadge.com/images/badges/winter-is-coming.svg" height="28px" alt="stark"></p>
<p align="center">Join modded servers without worrying about installing Java, Forge, or other mods. We'll handle that for you.</p> <p align="center">Join modded servers without worrying about installing Java, Forge, or other mods. We'll handle that for you.</p>
![Screenshot 1](https://i.imgur.com/6o7SmH6.png) ![Screenshot 1](https://i.imgur.com/6o7SmH6.png)
![Screenshot 2](https://i.imgur.com/x3B34n1.png) ![Screenshot 2](https://i.imgur.com/x3B34n1.png)
## Features ## Features
* 🔒 Full account management. * 🔒 Full account management.
* Add multiple accounts and easily switch between them. * Add multiple accounts and easily switch between them.
* Credentials are never stored and transmitted directly to Mojang. * Credentials are never stored and transmitted directly to Mojang.
* 📂 Efficient asset management. * 📂 Efficient asset management.
* Receive client updates as soon as we release them. * Receive client updates as soon as we release them.
* Files are validated before launch. Corrupt or incorrect files will be redownloaded. * Files are validated before launch. Corrupt or incorrect files will be redownloaded.
* ☕ **Automatic Java validation.** * ☕ **Automatic Java validation.**
* If you have an incompatible version of Java installed, we'll install the right one *for you*. * If you have an incompatible version of Java installed, we'll install the right one *for you*.
* You do not need to have Java installed to run the launcher. * You do not need to have Java installed to run the launcher.
* 📰 News feed natively built into the launcher. * 📰 News feed natively built into the launcher.
* ⚙️ Intuitive settings management, including a Java control panel. * ⚙️ Intuitive settings management, including a Java control panel.
* Supports all of our servers. * Supports all of our servers.
* Switch between server configurations with ease. * Switch between server configurations with ease.
* View the player count of the selected server. * View the player count of the selected server.
* Automatic updates. That's right, the launcher updates itself. * Automatic updates. That's right, the launcher updates itself.
* View the status of Mojang's services. * View the status of Mojang's services.
This is not an exhaustive list. Download and install the launcher to gauge all it can do! This is not an exhaustive list. Download and install the launcher to gauge all it can do!
#### Need Help? [Check the wiki.][wiki] #### Need Help? [Check the wiki.][wiki]
#### Like the project? Leave a ⭐ star on the repository! #### Like the project? Leave a ⭐ star on the repository!
## Downloads ## Downloads
You can download from [GitHub Releases](https://github.com/dscalzi/HeliosLauncher/releases) You can download from [GitHub Releases](https://github.com/dscalzi/HeliosLauncher/releases)
#### Latest Release #### Latest Release
[![](https://img.shields.io/github/release/dscalzi/HeliosLauncher.svg?style=flat-square)](https://github.com/dscalzi/HeliosLauncher/releases/latest) [![](https://img.shields.io/github/release/dscalzi/HeliosLauncher.svg?style=flat-square)](https://github.com/dscalzi/HeliosLauncher/releases/latest)
#### Latest Pre-Release #### Latest Pre-Release
[![](https://img.shields.io/github/release/dscalzi/HeliosLauncher/all.svg?style=flat-square)](https://github.com/dscalzi/HeliosLauncher/releases) [![](https://img.shields.io/github/release/dscalzi/HeliosLauncher/all.svg?style=flat-square)](https://github.com/dscalzi/HeliosLauncher/releases)
**Supported Platforms** **Supported Platforms**
If you download from the [Releases](https://github.com/dscalzi/HeliosLauncher/releases) tab, select the installer for your system. If you download from the [Releases](https://github.com/dscalzi/HeliosLauncher/releases) tab, select the installer for your system.
| Platform | File | | Platform | File |
| -------- | ---- | | -------- | ---- |
| Windows x64 | `helioslauncher-setup-VERSION.exe` | | Windows x64 | `helioslauncher-setup-VERSION.exe` |
| macOS | `helioslauncher-VERSION.dmg` | | macOS | `helioslauncher-VERSION.dmg` |
| Linux x64 | `helioslauncher-VERSION-x86_64.AppImage` | | Linux x64 | `helioslauncher-VERSION-x86_64.AppImage` |
## Console ## Console
To open the console, use the following keybind. To open the console, use the following keybind.
```console ```console
ctrl + shift + i ctrl + shift + i
``` ```
Ensure that you have the console tab selected. Do not paste anything into the console unless you are 100% sure of what it will do. Pasting the wrong thing can expose sensitive information. Ensure that you have the console tab selected. Do not paste anything into the console unless you are 100% sure of what it will do. Pasting the wrong thing can expose sensitive information.
#### Export Output to a File #### Export Output to a File
If you want to export the console output, simply right click anywhere on the console and click **Save as..** If you want to export the console output, simply right click anywhere on the console and click **Save as..**
![console example](https://i.imgur.com/T5e73jP.png) ![console example](https://i.imgur.com/T5e73jP.png)
## Development ## Development
### Getting Started ### Getting Started
**System Requirements** **System Requirements**
* [Node.js][nodejs] v12 * [Node.js][nodejs] v12
--- ---
**Clone and Install Dependencies** **Clone and Install Dependencies**
```console ```console
> git clone https://github.com/dscalzi/HeliosLauncher.git > git clone https://github.com/dscalzi/HeliosLauncher.git
> cd HeliosLauncher > cd HeliosLauncher
> npm install > npm install
``` ```
--- ---
**Launch Application** **Launch Application**
```console ```console
> npm start > npm start
``` ```
--- ---
**Build Installers** **Build Installers**
To build for your current platform. To build for your current platform.
```console ```console
> npm run dist > npm run dist
``` ```
Build for a specific platform. Build for a specific platform.
| Platform | Command | | Platform | Command |
| ----------- | -------------------- | | ----------- | -------------------- |
| Windows x64 | `npm run dist:win` | | Windows x64 | `npm run dist:win` |
| macOS | `npm run dist:mac` | | macOS | `npm run dist:mac` |
| Linux x64 | `npm run dist:linux` | | Linux x64 | `npm run dist:linux` |
Builds for macOS may not work on Windows/Linux and vice-versa. Builds for macOS may not work on Windows/Linux and vice-versa.
--- ---
### Visual Studio Code ### Visual Studio Code
All development of the launcher should be done using [Visual Studio Code][vscode]. All development of the launcher should be done using [Visual Studio Code][vscode].
Paste the following into `.vscode/launch.json` Paste the following into `.vscode/launch.json`
```JSON ```JSON
{ {
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"name": "Debug Main Process", "name": "Debug Main Process",
"type": "node", "type": "node",
"request": "launch", "request": "launch",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": { "windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
}, },
"args": ["."], "args": ["."],
"console": "integratedTerminal", "console": "integratedTerminal",
"protocol": "inspector" "protocol": "inspector"
}, },
{ {
"name": "Debug Renderer Process", "name": "Debug Renderer Process",
"type": "chrome", "type": "chrome",
"request": "launch", "request": "launch",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": { "windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
}, },
"runtimeArgs": [ "runtimeArgs": [
"${workspaceFolder}/.", "${workspaceFolder}/.",
"--remote-debugging-port=9222" "--remote-debugging-port=9222"
], ],
"webRoot": "${workspaceFolder}" "webRoot": "${workspaceFolder}"
} }
] ]
} }
``` ```
This adds two debug configurations. This adds two debug configurations.
#### Debug Main Process #### Debug Main Process
This allows you to debug Electron's [main process][mainprocess]. You can debug scripts in the [renderer process][rendererprocess] by opening the DevTools Window. This allows you to debug Electron's [main process][mainprocess]. You can debug scripts in the [renderer process][rendererprocess] by opening the DevTools Window.
#### Debug Renderer Process #### Debug Renderer Process
This allows you to debug Electron's [renderer process][rendererprocess]. This requires you to install the [Debugger for Chrome][chromedebugger] extension. This allows you to debug Electron's [renderer process][rendererprocess]. This requires you to install the [Debugger for Chrome][chromedebugger] extension.
Note that you **cannot** open the DevTools window while using this debug configuration. Chromium only allows one debugger, opening another will crash the program. Note that you **cannot** open the DevTools window while using this debug configuration. Chromium only allows one debugger, opening another will crash the program.
--- ---
### Note on Third-Party Usage ### Note on Third-Party Usage
You may use this software in your own project so long as the following conditions are met. 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). * Credit is expressly given to the original authors (Daniel Scalzi).
* Include a link to the original source on the launcher's About page. * 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. * 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. * 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. We reserve the right to update these conditions at any time, please check back periodically.
--- ---
## Resources ## Resources
* [Wiki][wiki] * [Wiki][wiki]
* [Nebula (Create Distribution.json)][nebula] * [Nebula (Create Distribution.json)][nebula]
* [v2 Rewrite Branch (WIP)][v2branch] * [v2 Rewrite Branch (WIP)][v2branch]
The best way to contact the developers is on Discord. The best way to contact the developers is on Discord.
[![discord](https://discordapp.com/api/guilds/211524927831015424/embed.png?style=banner3)][discord] [![discord](https://discordapp.com/api/guilds/211524927831015424/embed.png?style=banner3)][discord]
--- ---
### See you ingame. ### See you ingame.
[nodejs]: https://nodejs.org/en/ 'Node.js' [nodejs]: https://nodejs.org/en/ 'Node.js'
[vscode]: https://code.visualstudio.com/ 'Visual Studio Code' [vscode]: https://code.visualstudio.com/ 'Visual Studio Code'
[mainprocess]: https://electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes 'Main Process' [mainprocess]: https://electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes 'Main Process'
[rendererprocess]: https://electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes 'Renderer Process' [rendererprocess]: https://electronjs.org/docs/tutorial/application-architecture#main-and-renderer-processes 'Renderer Process'
[chromedebugger]: https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome 'Debugger for Chrome' [chromedebugger]: https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome 'Debugger for Chrome'
[discord]: https://discord.gg/zNWUXdt 'Discord' [discord]: https://discord.gg/zNWUXdt 'Discord'
[wiki]: https://github.com/dscalzi/HeliosLauncher/wiki 'wiki' [wiki]: https://github.com/dscalzi/HeliosLauncher/wiki 'wiki'
[nebula]: https://github.com/dscalzi/Nebula 'dscalzi/Nebula' [nebula]: https://github.com/dscalzi/Nebula 'dscalzi/Nebula'
[v2branch]: https://github.com/dscalzi/HeliosLauncher/tree/ts-refactor 'v2 branch' [v2branch]: https://github.com/dscalzi/HeliosLauncher/tree/ts-refactor 'v2 branch'

View File

@ -1,53 +1,53 @@
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta charset="utf-8" http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-In6B8teKZQll5heMl9bS7CESTbGvuAt3VVV86BUQBDk='"/> <meta charset="utf-8" http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-In6B8teKZQll5heMl9bS7CESTbGvuAt3VVV86BUQBDk='"/>
<title>Helios Launcher</title> <title>Creeponnia Launcher</title>
<script src="./assets/js/scripts/uicore.js"></script> <script src="./assets/js/scripts/uicore.js"></script>
<script src="./assets/js/scripts/uibinder.js"></script> <script src="./assets/js/scripts/uibinder.js"></script>
<link type="text/css" rel="stylesheet" href="./assets/css/launcher.css"> <link type="text/css" rel="stylesheet" href="./assets/css/launcher.css">
<style> <style>
body { body {
/*background: url('assets/images/backgrounds/<%=bkid%>.jpg') no-repeat center center fixed;*/ /*background: url('assets/images/backgrounds/<%=bkid%>.jpg') no-repeat center center fixed;*/
transition: background-image 1s ease; transition: background-image 1s ease;
background-image: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAPwBwAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8VooopDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/9k='); background-image: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAPwBwAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8VooopDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/9k=');
background-size: cover; background-size: cover;
-webkit-user-select: none; -webkit-user-select: none;
} }
#main { #main {
display: none; display: none;
height: calc(100% - 22px); height: calc(100% - 22px);
background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 100%); background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 100%);
width: 100%; width: 100%;
position: absolute; position: absolute;
z-index: 10; z-index: 10;
} }
#main[overlay] { #main[overlay] {
filter: blur(3px) contrast(0.9) brightness(1.0); filter: blur(3px) contrast(0.9) brightness(1.0);
} }
</style> </style>
</head> </head>
<body bkid="<%=bkid%>"> <body bkid="<%=bkid%>">
<%- include('frame') %> <%- include('frame') %>
<div id="main"> <div id="main">
<%- include('welcome') %> <%- include('welcome') %>
<%- include('login') %> <%- include('login') %>
<%- include('settings') %> <%- include('settings') %>
<%- include('landing') %> <%- include('landing') %>
</div> </div>
<%- include('overlay') %> <%- include('overlay') %>
<div id="loadingContainer"> <div id="loadingContainer">
<div id="loadingContent"> <div id="loadingContent">
<div id="loadSpinnerContainer"> <div id="loadSpinnerContainer">
<img id="loadCenterImage" src="assets/images/LoadingSeal.png"> <img id="loadCenterImage" src="assets/images/LoadingSeal.png">
<img id="loadSpinnerImage" class="rotating" src="assets/images/LoadingText.png"> <img id="loadSpinnerImage" class="rotating" src="assets/images/LoadingText.png">
</div> </div>
</div> </div>
</div> </div>
<script> <script>
// Load language // Load language
for(let key of Object.keys(Lang.query('html'))){ for(let key of Object.keys(Lang.query('html'))){
document.getElementById(key).innerHTML = Lang.query(`html.${key}`) document.getElementById(key).innerHTML = Lang.query(`html.${key}`)
} }
</script> </script>
</body> </body>
</html> </html>

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24.87 13.97"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24.87 13.97">
<defs> <defs>
<style>.cls-1{fill:none;stroke:#FFF;stroke-width:2px;}</style> <style>.cls-1{fill:none;stroke:#FFF;stroke-width:2px;}</style>
</defs> </defs>
<title>arrow</title> <title>arrow</title>
<polyline class="cls-1" points="0.71 13.26 12.56 1.41 24.16 13.02"/> <polyline class="cls-1" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 298 B

After

Width:  |  Height:  |  Size: 304 B

View File

@ -1,10 +1,10 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style> <style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style>
<clipPath id="clip-path"><rect class="cls-1" x="36.42" y="44.23" width="68.52" height="48.96"/></clipPath> <clipPath id="clip-path"><rect class="cls-1" x="36.42" y="44.23" width="68.52" height="48.96"/></clipPath>
</defs> </defs>
<title>discord</title> <title>discord</title>
<g class="cls-2"> <g class="cls-2">
<path d="M81.23,78.48a6.14,6.14,0,1,1,6.14-6.14,6.14,6.14,0,0,1-6.14,6.14M60,78.48a6.14,6.14,0,1,1,6.14-6.14A6.14,6.14,0,0,1,60,78.48M104.41,73c-.92-7.7-8.24-22.9-8.24-22.9A43,43,0,0,0,88,45.59a17.88,17.88,0,0,0-8.38-1.27l-.13,1.06a23.52,23.52,0,0,1,5.8,1.95,87.59,87.59,0,0,1,8.17,4.87s-10.32-5.63-22.27-5.63a51.32,51.32,0,0,0-23.2,5.63,87.84,87.84,0,0,1,8.17-4.87,23.57,23.57,0,0,1,5.8-1.95l-.13-1.06a17.88,17.88,0,0,0-8.38,1.27,42.84,42.84,0,0,0-8.21,4.56S37.87,65.35,37,73s-.37,11.54-.37,11.54,4.22,5.68,9.9,7.14,7.7,1.47,7.7,1.47l3.75-4.68a21.22,21.22,0,0,1-4.65-2A24.47,24.47,0,0,1,47.93,82S61.16,88.4,70.68,88.4c10,0,22.75-6.44,22.75-6.44a24.56,24.56,0,0,1-5.35,4.56,21.22,21.22,0,0,1-4.65,2l3.75,4.68s2,0,7.7-1.47,9.89-7.14,9.89-7.14.55-3.85-.37-11.54"/> <path d="M81.23,78.48a6.14,6.14,0,1,1,6.14-6.14,6.14,6.14,0,0,1-6.14,6.14M60,78.48a6.14,6.14,0,1,1,6.14-6.14A6.14,6.14,0,0,1,60,78.48M104.41,73c-.92-7.7-8.24-22.9-8.24-22.9A43,43,0,0,0,88,45.59a17.88,17.88,0,0,0-8.38-1.27l-.13,1.06a23.52,23.52,0,0,1,5.8,1.95,87.59,87.59,0,0,1,8.17,4.87s-10.32-5.63-22.27-5.63a51.32,51.32,0,0,0-23.2,5.63,87.84,87.84,0,0,1,8.17-4.87,23.57,23.57,0,0,1,5.8-1.95l-.13-1.06a17.88,17.88,0,0,0-8.38,1.27,42.84,42.84,0,0,0-8.21,4.56S37.87,65.35,37,73s-.37,11.54-.37,11.54,4.22,5.68,9.9,7.14,7.7,1.47,7.7,1.47l3.75-4.68a21.22,21.22,0,0,1-4.65-2A24.47,24.47,0,0,1,47.93,82S61.16,88.4,70.68,88.4c10,0,22.75-6.44,22.75-6.44a24.56,24.56,0,0,1-5.35,4.56,21.22,21.22,0,0,1-4.65,2l3.75,4.68s2,0,7.7-1.47,9.89-7.14,9.89-7.14.55-3.85-.37-11.54"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,9 +1,9 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="504px" height="504px" viewBox="0 0 5040 5040" preserveAspectRatio="xMidYMid meet"> <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="504px" height="504px" viewBox="0 0 5040 5040" preserveAspectRatio="xMidYMid meet">
<g id="layer101" fill="#000000" stroke="none"> <g id="layer101" fill="#000000" stroke="none">
<path d="M1390 5024 c-163 -9 -239 -19 -315 -38 -281 -70 -477 -177 -660 -361 -184 -184 -292 -380 -361 -660 -43 -171 -53 -456 -53 -1445 0 -989 10 -1274 53 -1445 69 -280 177 -476 361 -660 184 -184 380 -292 660 -361 171 -43 456 -53 1445 -53 989 0 1274 10 1445 53 280 69 476 177 660 361 184 184 292 380 361 660 43 171 53 456 53 1445 0 989 -10 1274 -53 1445 -69 280 -177 476 -361 660 -184 184 -380 292 -660 361 -174 44 -454 53 -1470 52 -599 0 -960 -5 -1105 -14z m2230 -473 c58 -6 141 -18 185 -27 397 -78 638 -318 719 -714 37 -183 41 -309 41 -1290 0 -981 -4 -1107 -41 -1290 -81 -395 -319 -633 -714 -714 -183 -37 -309 -41 -1290 -41 -981 0 -1107 4 -1290 41 -397 81 -636 322 -714 719 -33 166 -38 296 -43 1100 -5 796 3 1203 27 1380 67 489 338 758 830 825 47 7 162 15 255 20 250 12 1907 4 2035 -9z"/> <path d="M1390 5024 c-163 -9 -239 -19 -315 -38 -281 -70 -477 -177 -660 -361 -184 -184 -292 -380 -361 -660 -43 -171 -53 -456 -53 -1445 0 -989 10 -1274 53 -1445 69 -280 177 -476 361 -660 184 -184 380 -292 660 -361 171 -43 456 -53 1445 -53 989 0 1274 10 1445 53 280 69 476 177 660 361 184 184 292 380 361 660 43 171 53 456 53 1445 0 989 -10 1274 -53 1445 -69 280 -177 476 -361 660 -184 184 -380 292 -660 361 -174 44 -454 53 -1470 52 -599 0 -960 -5 -1105 -14z m2230 -473 c58 -6 141 -18 185 -27 397 -78 638 -318 719 -714 37 -183 41 -309 41 -1290 0 -981 -4 -1107 -41 -1290 -81 -395 -319 -633 -714 -714 -183 -37 -309 -41 -1290 -41 -981 0 -1107 4 -1290 41 -397 81 -636 322 -714 719 -33 166 -38 296 -43 1100 -5 796 3 1203 27 1380 67 489 338 758 830 825 47 7 162 15 255 20 250 12 1907 4 2035 -9z"/>
<path d="M2355 3819 c-307 -42 -561 -172 -780 -400 -244 -253 -359 -543 -359 -899 0 -361 116 -648 367 -907 262 -269 563 -397 937 -397 374 0 675 128 937 397 251 259 367 546 367 907 0 361 -116 648 -367 907 -197 203 -422 326 -690 378 -101 20 -317 27 -412 14z m400 -509 c275 -88 470 -284 557 -560 20 -65 23 -95 23 -230 0 -135 -3 -165 -23 -230 -88 -278 -284 -474 -562 -562 -65 -20 -95 -23 -230 -23 -135 0 -165 3 -230 23 -278 88 -474 284 -562 562 -20 65 -23 95 -23 230 0 135 3 165 23 230 73 230 219 403 427 507 134 67 212 83 390 79 111 -3 155 -8 210 -26z"/> <path d="M2355 3819 c-307 -42 -561 -172 -780 -400 -244 -253 -359 -543 -359 -899 0 -361 116 -648 367 -907 262 -269 563 -397 937 -397 374 0 675 128 937 397 251 259 367 546 367 907 0 361 -116 648 -367 907 -197 203 -422 326 -690 378 -101 20 -317 27 -412 14z m400 -509 c275 -88 470 -284 557 -560 20 -65 23 -95 23 -230 0 -135 -3 -165 -23 -230 -88 -278 -284 -474 -562 -562 -65 -20 -95 -23 -230 -23 -135 0 -165 3 -230 23 -278 88 -474 284 -562 562 -20 65 -23 95 -23 230 0 135 3 165 23 230 73 230 219 403 427 507 134 67 212 83 390 79 111 -3 155 -8 210 -26z"/>
<path d="M3750 1473 c-29 -11 -66 -38 -106 -77 -70 -71 -94 -126 -94 -221 0 -95 24 -150 94 -221 72 -71 126 -94 225 -94 168 0 311 143 311 311 0 99 -23 154 -94 225 -43 42 -76 66 -110 77 -61 21 -166 21 -226 0z"/> <path d="M3750 1473 c-29 -11 -66 -38 -106 -77 -70 -71 -94 -126 -94 -221 0 -95 24 -150 94 -221 72 -71 126 -94 225 -94 168 0 311 143 311 311 0 99 -23 154 -94 225 -43 42 -76 66 -110 77 -61 21 -166 21 -226 0z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,11 +1,11 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style> <style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style>
<clipPath id="clip-path"><rect class="cls-1" x="29.3" y="52.62" width="82.77" height="34.15"/></clipPath> <clipPath id="clip-path"><rect class="cls-1" x="29.3" y="52.62" width="82.77" height="34.15"/></clipPath>
</defs> </defs>
<title>link</title> <title>link</title>
<g class="cls-2"> <g class="cls-2">
<path d="M75.37,65.51a3.85,3.85,0,0,0-1.73.42,8.22,8.22,0,0,1,.94,3.76A8.36,8.36,0,0,1,66.23,78H46.37a8.35,8.35,0,1,1,0-16.7h9.18a21.51,21.51,0,0,1,6.65-8.72H46.37a17.07,17.07,0,1,0,0,34.15H66.23A17,17,0,0,0,82.77,65.51Z"/> <path d="M75.37,65.51a3.85,3.85,0,0,0-1.73.42,8.22,8.22,0,0,1,.94,3.76A8.36,8.36,0,0,1,66.23,78H46.37a8.35,8.35,0,1,1,0-16.7h9.18a21.51,21.51,0,0,1,6.65-8.72H46.37a17.07,17.07,0,1,0,0,34.15H66.23A17,17,0,0,0,82.77,65.51Z"/>
<path d="M66,73.88a3.85,3.85,0,0,0,1.73-.42,8.22,8.22,0,0,1-.94-3.76,8.36,8.36,0,0,1,8.35-8.35H95A8.35,8.35,0,1,1,95,78H85.8a21.51,21.51,0,0,1-6.65,8.72H95a17.07,17.07,0,0,0,0-34.15H75.13A17,17,0,0,0,58.59,73.88Z"/> <path d="M66,73.88a3.85,3.85,0,0,0,1.73-.42,8.22,8.22,0,0,1-.94-3.76,8.36,8.36,0,0,1,8.35-8.35H95A8.35,8.35,0,1,1,95,78H85.8a21.51,21.51,0,0,1-6.65,8.72H95a17.07,17.07,0,0,0,0-34.15H75.13A17,17,0,0,0,58.59,73.88Z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 875 B

After

Width:  |  Height:  |  Size: 885 B

View File

@ -1,12 +1,12 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{fill:#231f20;}</style> <style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{fill:#231f20;}</style>
<clipPath id="clip-path"> <clipPath id="clip-path">
<rect class="cls-1" x="44.02" y="34.21" width="51.96" height="68.48"/> <rect class="cls-1" x="44.02" y="34.21" width="51.96" height="68.48"/>
</clipPath> </clipPath>
</defs> </defs>
<title>Lock</title> <title>Lock</title>
<g class="cls-2"> <g class="cls-2">
<path class="cls-3" d="M86.16,54a16.38,16.38,0,1,0-32,0H44V102.7H96V54Zm-25.9-3.39a9.89,9.89,0,1,1,19.77,0A9.78,9.78,0,0,1,79.39,54H60.89A9.78,9.78,0,0,1,60.26,50.59ZM70,96.2a6.5,6.5,0,0,1-6.5-6.5,6.39,6.39,0,0,1,3.1-5.4V67h6.5V84.11a6.42,6.42,0,0,1,3.39,5.6A6.5,6.5,0,0,1,70,96.2Z"/> <path class="cls-3" d="M86.16,54a16.38,16.38,0,1,0-32,0H44V102.7H96V54Zm-25.9-3.39a9.89,9.89,0,1,1,19.77,0A9.78,9.78,0,0,1,79.39,54H60.89A9.78,9.78,0,0,1,60.26,50.59ZM70,96.2a6.5,6.5,0,0,1-6.5-6.5,6.39,6.39,0,0,1,3.1-5.4V67h6.5V84.11a6.42,6.42,0,0,1,3.39,5.6A6.5,6.5,0,0,1,70,96.2Z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 767 B

View File

@ -1,14 +1,14 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:#231f20;}.cls-2,.cls-3{fill:none;stroke-miterlimit:10;stroke-width:6px;}.cls-2{stroke:#231f20;}.cls-3{stroke:#000;}</style> <style>.cls-1{fill:#231f20;}.cls-2,.cls-3{fill:none;stroke-miterlimit:10;stroke-width:6px;}.cls-2{stroke:#231f20;}.cls-3{stroke:#000;}</style>
</defs> </defs>
<title>News</title> <title>News</title>
<rect class="cls-1" x="31.77" y="32.96" width="33.79" height="20.76"/> <rect class="cls-1" x="31.77" y="32.96" width="33.79" height="20.76"/>
<path class="cls-2" d="M115.36,113.8H27.18a6.67,6.67,0,0,1-6.67-6.67V19.27H108.2V107.1a6.71,6.71,0,0,0,6.71,6.7h0a6.71,6.71,0,0,0,6.71-6.71v-75H108.15"/> <path class="cls-2" d="M115.36,113.8H27.18a6.67,6.67,0,0,1-6.67-6.67V19.27H108.2V107.1a6.71,6.71,0,0,0,6.71,6.7h0a6.71,6.71,0,0,0,6.71-6.71v-75H108.15"/>
<line class="cls-3" x1="73.75" y1="36.18" x2="97.14" y2="36.18"/> <line class="cls-3" x1="73.75" y1="36.18" x2="97.14" y2="36.18"/>
<line class="cls-3" x1="73.75" y1="50.22" x2="97.14" y2="50.22"/> <line class="cls-3" x1="73.75" y1="50.22" x2="97.14" y2="50.22"/>
<line class="cls-3" x1="31.66" y1="64.25" x2="97.14" y2="64.25"/> <line class="cls-3" x1="31.66" y1="64.25" x2="97.14" y2="64.25"/>
<line class="cls-3" x1="31.66" y1="78.28" x2="97.14" y2="78.28"/> <line class="cls-3" x1="31.66" y1="78.28" x2="97.14" y2="78.28"/>
<line class="cls-3" x1="31.66" y1="92.31" x2="97.14" y2="92.31"/> <line class="cls-3" x1="31.66" y1="92.31" x2="97.14" y2="92.31"/>
<line class="cls-3" x1="31.66" y1="92.31" x2="97.14" y2="92.31"/> <line class="cls-3" x1="31.66" y1="92.31" x2="97.14" y2="92.31"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 972 B

View File

@ -1,10 +1,10 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style> <style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style>
<clipPath id="clip-path"><rect class="cls-1" x="45.51" y="44.33" width="55.14" height="59.33"/></clipPath> <clipPath id="clip-path"><rect class="cls-1" x="45.51" y="44.33" width="55.14" height="59.33"/></clipPath>
</defs> </defs>
<title>Profile</title> <title>Profile</title>
<g class="cls-2"> <g class="cls-2">
<path d="M86.77,58.12A13.79,13.79,0,1,0,73,71.91,13.79,13.79,0,0,0,86.77,58.12M97,103.67a3.41,3.41,0,0,0,3.39-3.84,27.57,27.57,0,0,0-54.61,0,3.41,3.41,0,0,0,3.39,3.84Z"/> <path d="M86.77,58.12A13.79,13.79,0,1,0,73,71.91,13.79,13.79,0,0,0,86.77,58.12M97,103.67a3.41,3.41,0,0,0,3.39-3.84,27.57,27.57,0,0,0-54.61,0,3.41,3.41,0,0,0,3.39,3.84Z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 602 B

After

Width:  |  Height:  |  Size: 611 B

View File

@ -1,10 +1,10 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style> <style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style>
<clipPath id="clip-path"><rect class="cls-1" x="45.65" y="42.62" width="49.58" height="52.43"/></clipPath> <clipPath id="clip-path"><rect class="cls-1" x="45.65" y="42.62" width="49.58" height="52.43"/></clipPath>
</defs> </defs>
<title>settings</title> <title>settings</title>
<g class="cls-2"> <g class="cls-2">
<path d="M70.44,75a6.19,6.19,0,1,1,5.84-6.18A6,6,0,0,1,70.44,75M91.67,63.71h-5A18.4,18.4,0,0,0,85.19,60l3.48-3.68a3.93,3.93,0,0,0,0-5.32l-1.4-1.48a3.43,3.43,0,0,0-5,0l-3.48,3.68A16.34,16.34,0,0,0,75,51.59V46.38a3.68,3.68,0,0,0-3.56-3.76h-2a3.68,3.68,0,0,0-3.56,3.76v5.21a16.23,16.23,0,0,0-3.77,1.64l-3.48-3.68a3.43,3.43,0,0,0-5,0L52.21,51a3.93,3.93,0,0,0,0,5.32L55.69,60a18.21,18.21,0,0,0-1.48,3.67h-5a3.67,3.67,0,0,0-3.56,3.76v2.1a3.68,3.68,0,0,0,3.56,3.76h4.84a18.46,18.46,0,0,0,1.64,4.3l-3.48,3.68a3.93,3.93,0,0,0,0,5.32l1.4,1.48a3.43,3.43,0,0,0,5,0l3.48-3.68a16.36,16.36,0,0,0,3.77,1.64v5.21a3.67,3.67,0,0,0,3.56,3.76h2A3.67,3.67,0,0,0,75,91.29V86.08a16.48,16.48,0,0,0,3.77-1.64l3.48,3.68a3.43,3.43,0,0,0,5,0l1.4-1.48a3.93,3.93,0,0,0,0-5.32l-3.48-3.68a18.45,18.45,0,0,0,1.63-4.3h4.85a3.68,3.68,0,0,0,3.56-3.76v-2.1a3.67,3.67,0,0,0-3.56-3.76"/> <path d="M70.44,75a6.19,6.19,0,1,1,5.84-6.18A6,6,0,0,1,70.44,75M91.67,63.71h-5A18.4,18.4,0,0,0,85.19,60l3.48-3.68a3.93,3.93,0,0,0,0-5.32l-1.4-1.48a3.43,3.43,0,0,0-5,0l-3.48,3.68A16.34,16.34,0,0,0,75,51.59V46.38a3.68,3.68,0,0,0-3.56-3.76h-2a3.68,3.68,0,0,0-3.56,3.76v5.21a16.23,16.23,0,0,0-3.77,1.64l-3.48-3.68a3.43,3.43,0,0,0-5,0L52.21,51a3.93,3.93,0,0,0,0,5.32L55.69,60a18.21,18.21,0,0,0-1.48,3.67h-5a3.67,3.67,0,0,0-3.56,3.76v2.1a3.68,3.68,0,0,0,3.56,3.76h4.84a18.46,18.46,0,0,0,1.64,4.3l-3.48,3.68a3.93,3.93,0,0,0,0,5.32l1.4,1.48a3.43,3.43,0,0,0,5,0l3.48-3.68a16.36,16.36,0,0,0,3.77,1.64v5.21a3.67,3.67,0,0,0,3.56,3.76h2A3.67,3.67,0,0,0,75,91.29V86.08a16.48,16.48,0,0,0,3.77-1.64l3.48,3.68a3.43,3.43,0,0,0,5,0l1.4-1.48a3.93,3.93,0,0,0,0-5.32l-3.48-3.68a18.45,18.45,0,0,0,1.63-4.3h4.85a3.68,3.68,0,0,0,3.56-3.76v-2.1a3.67,3.67,0,0,0-3.56-3.76"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,13 +1,13 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74">
<defs> <defs>
<style>.cls-1{fill:#1a171b;}</style> <style>.cls-1{fill:#1a171b;}</style>
</defs> </defs>
<title>Seven Pointed Star</title> <title>Seven Pointed Star</title>
<polygon class="cls-1" points="43.83 52.37 48.83 14.03 53.83 52.37 43.83 52.37"/> <polygon class="cls-1" points="43.83 52.37 48.83 14.03 53.83 52.37 43.83 52.37"/>
<polygon class="cls-1" points="45.71 56.28 18.85 28.47 51.95 48.46 45.71 56.28"/> <polygon class="cls-1" points="45.71 56.28 18.85 28.47 51.95 48.46 45.71 56.28"/>
<polygon class="cls-1" points="49.94 57.25 11.45 60.9 47.72 47.5 49.94 57.25"/> <polygon class="cls-1" points="49.94 57.25 11.45 60.9 47.72 47.5 49.94 57.25"/>
<polygon class="cls-1" points="53.34 54.54 32.19 86.92 44.33 50.2 53.34 54.54"/> <polygon class="cls-1" points="53.34 54.54 32.19 86.92 44.33 50.2 53.34 54.54"/>
<polygon class="cls-1" points="53.34 50.2 65.47 86.92 44.33 54.54 53.34 50.2"/> <polygon class="cls-1" points="53.34 50.2 65.47 86.92 44.33 54.54 53.34 50.2"/>
<polygon class="cls-1" points="49.94 47.5 86.21 60.91 47.72 57.25 49.94 47.5"/> <polygon class="cls-1" points="49.94 47.5 86.21 60.91 47.72 57.25 49.94 47.5"/>
<polygon class="cls-1" points="45.71 48.46 78.81 28.47 51.95 56.28 45.71 48.46"/> <polygon class="cls-1" points="45.71 48.46 78.81 28.47 51.95 56.28 45.71 48.46"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 809 B

After

Width:  |  Height:  |  Size: 821 B

View File

@ -1,14 +1,14 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74">
<defs> <defs>
<style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}</style> <style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}</style>
</defs> </defs>
<title>Seven Pointed Star with Circle</title> <title>Seven Pointed Star with Circle</title>
<polygon class="cls-1" points="43.83 52.37 48.83 14.03 53.83 52.37 43.83 52.37"/> <polygon class="cls-1" points="43.83 52.37 48.83 14.03 53.83 52.37 43.83 52.37"/>
<polygon class="cls-1" points="45.71 56.28 18.85 28.47 51.95 48.46 45.71 56.28"/> <polygon class="cls-1" points="45.71 56.28 18.85 28.47 51.95 48.46 45.71 56.28"/>
<polygon class="cls-1" points="49.94 57.25 11.45 60.9 47.72 47.5 49.94 57.25"/> <polygon class="cls-1" points="49.94 57.25 11.45 60.9 47.72 47.5 49.94 57.25"/>
<polygon class="cls-1" points="53.34 54.54 32.19 86.92 44.33 50.2 53.34 54.54"/> <polygon class="cls-1" points="53.34 54.54 32.19 86.92 44.33 50.2 53.34 54.54"/>
<polygon class="cls-1" points="53.34 50.2 65.47 86.92 44.33 54.54 53.34 50.2"/> <polygon class="cls-1" points="53.34 50.2 65.47 86.92 44.33 54.54 53.34 50.2"/>
<polygon class="cls-1" points="49.94 47.5 86.21 60.91 47.72 57.25 49.94 47.5"/> <polygon class="cls-1" points="49.94 47.5 86.21 60.91 47.72 57.25 49.94 47.5"/>
<polygon class="cls-1" points="45.71 48.46 78.81 28.47 51.95 56.28 45.71 48.46"/> <polygon class="cls-1" points="45.71 48.46 78.81 28.47 51.95 56.28 45.71 48.46"/>
<circle class="cls-2" cx="48.83" cy="52.37" r="38"/> <circle class="cls-2" cx="48.83" cy="52.37" r="38"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 932 B

After

Width:  |  Height:  |  Size: 945 B

View File

@ -1,8 +1,8 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74">
<defs> <defs>
<style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}</style> <style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}</style>
</defs> </defs>
<title>Seven Pointed Star Extended with Circle</title> <title>Seven Pointed Star Extended with Circle</title>
<path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/> <path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/>
<circle class="cls-2" cx="53.73" cy="53.9" r="38"/> <circle class="cls-2" cx="53.73" cy="53.9" r="38"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 822 B

After

Width:  |  Height:  |  Size: 829 B

View File

@ -1,15 +1,15 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74">
<defs> <defs>
<style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}.cls-3{fill:#fff;}</style> <style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}.cls-3{fill:#fff;}</style>
</defs> </defs>
<title>Seven Pointed Star with Circle and Hole</title> <title>Seven Pointed Star with Circle and Hole</title>
<polygon class="cls-1" points="43.83 52.37 48.83 14.03 53.83 52.37 43.83 52.37"/> <polygon class="cls-1" points="43.83 52.37 48.83 14.03 53.83 52.37 43.83 52.37"/>
<polygon class="cls-1" points="45.71 56.28 18.85 28.47 51.95 48.46 45.71 56.28"/> <polygon class="cls-1" points="45.71 56.28 18.85 28.47 51.95 48.46 45.71 56.28"/>
<polygon class="cls-1" points="49.94 57.25 11.45 60.9 47.72 47.5 49.94 57.25"/> <polygon class="cls-1" points="49.94 57.25 11.45 60.9 47.72 47.5 49.94 57.25"/>
<polygon class="cls-1" points="53.34 54.54 32.19 86.92 44.33 50.2 53.34 54.54"/> <polygon class="cls-1" points="53.34 54.54 32.19 86.92 44.33 50.2 53.34 54.54"/>
<polygon class="cls-1" points="53.34 50.2 65.47 86.92 44.33 54.54 53.34 50.2"/> <polygon class="cls-1" points="53.34 50.2 65.47 86.92 44.33 54.54 53.34 50.2"/>
<polygon class="cls-1" points="49.94 47.5 86.21 60.91 47.72 57.25 49.94 47.5"/> <polygon class="cls-1" points="49.94 47.5 86.21 60.91 47.72 57.25 49.94 47.5"/>
<polygon class="cls-1" points="45.71 48.46 78.81 28.47 51.95 56.28 45.71 48.46"/> <polygon class="cls-1" points="45.71 48.46 78.81 28.47 51.95 56.28 45.71 48.46"/>
<circle class="cls-2" cx="48.83" cy="52.37" r="38"/> <circle class="cls-2" cx="48.83" cy="52.37" r="38"/>
<circle class="cls-3" cx="48.83" cy="52.37" r="4.56"/> <circle class="cls-3" cx="48.83" cy="52.37" r="4.56"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1018 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,9 +1,9 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74">
<defs> <defs>
<style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}.cls-3{fill:#fff;}</style> <style>.cls-1{fill:#1a171b;}.cls-2{fill:none;stroke:#1a171b;stroke-miterlimit:10;}.cls-3{fill:#fff;}</style>
</defs> </defs>
<title>Seven Pointed Star Extended with Circle and Hole</title> <title>Seven Pointed Star Extended with Circle and Hole</title>
<path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/> <path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/>
<circle class="cls-2" cx="53.73" cy="53.9" r="38"/> <circle class="cls-2" cx="53.73" cy="53.9" r="38"/>
<circle class="cls-3" cx="53.73" cy="53.9" r="4.56"/> <circle class="cls-3" cx="53.73" cy="53.9" r="4.56"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 907 B

After

Width:  |  Height:  |  Size: 915 B

View File

@ -1,7 +1,7 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 107.45 104.74">
<defs> <defs>
<style>.cls-1{fill:#1a171b;}</style> <style>.cls-1{fill:#1a171b;}</style>
</defs> </defs>
<title>Seven Pointed Star Extended</title> <title>Seven Pointed Star Extended</title>
<path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/> <path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 706 B

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -1,10 +1,10 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43"> <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 141.36 137.43">
<defs> <defs>
<style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style> <style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}</style>
<clipPath id="clip-path"><rect class="cls-1" x="38.29" y="45.86" width="70.16" height="48.48"/></clipPath> <clipPath id="clip-path"><rect class="cls-1" x="38.29" y="45.86" width="70.16" height="48.48"/></clipPath>
</defs> </defs>
<title>youtube</title> <title>youtube</title>
<g class="cls-2"> <g class="cls-2">
<path d="M84.8,69.52,65.88,79.76V59.27Zm23.65.59c0-5.14-.79-17.63-3.94-20.57S99,45.86,73.37,45.86s-28,.73-31.14,3.68S38.29,65,38.29,70.11s.79,17.63,3.94,20.57,5.52,3.68,31.14,3.68,28-.74,31.14-3.68,3.94-15.42,3.94-20.57"/> <path d="M84.8,69.52,65.88,79.76V59.27Zm23.65.59c0-5.14-.79-17.63-3.94-20.57S99,45.86,73.37,45.86s-28,.73-31.14,3.68S38.29,65,38.29,70.11s.79,17.63,3.94,20.57,5.52,3.68,31.14,3.68,28-.74,31.14-3.68,3.94-15.42,3.94-20.57"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 654 B

After

Width:  |  Height:  |  Size: 663 B

View File

@ -1,73 +1,73 @@
let target = require('./assetguard')[process.argv[2]] let target = require('./assetguard')[process.argv[2]]
if(target == null){ if(target == null){
process.send({context: 'error', data: null, error: 'Invalid class name'}) process.send({context: 'error', data: null, error: 'Invalid class name'})
console.error('Invalid class name passed to argv[2], cannot continue.') console.error('Invalid class name passed to argv[2], cannot continue.')
process.exit(1) process.exit(1)
} }
let tracker = new target(...(process.argv.splice(3))) let tracker = new target(...(process.argv.splice(3)))
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'
//const tracker = new AssetGuard(process.argv[2], process.argv[3]) //const tracker = new AssetGuard(process.argv[2], process.argv[3])
console.log('AssetExec Started') console.log('AssetExec Started')
// Temporary for debug purposes. // Temporary for debug purposes.
process.on('unhandledRejection', r => console.log(r)) process.on('unhandledRejection', r => console.log(r))
let percent = 0 let percent = 0
function assignListeners(){ function assignListeners(){
tracker.on('validate', (data) => { tracker.on('validate', (data) => {
process.send({context: 'validate', data}) process.send({context: 'validate', data})
}) })
tracker.on('progress', (data, acc, total) => { tracker.on('progress', (data, acc, total) => {
const currPercent = parseInt((acc/total) * 100) const currPercent = parseInt((acc/total) * 100)
if (currPercent !== percent) { if (currPercent !== percent) {
percent = currPercent percent = currPercent
process.send({context: 'progress', data, value: acc, total, percent}) process.send({context: 'progress', data, value: acc, total, percent})
} }
}) })
tracker.on('complete', (data, ...args) => { tracker.on('complete', (data, ...args) => {
process.send({context: 'complete', data, args}) process.send({context: 'complete', data, args})
}) })
tracker.on('error', (data, error) => { tracker.on('error', (data, error) => {
process.send({context: 'error', data, error}) process.send({context: 'error', data, error})
}) })
} }
assignListeners() assignListeners()
process.on('message', (msg) => { process.on('message', (msg) => {
if(msg.task === 'execute'){ if(msg.task === 'execute'){
const func = msg.function const func = msg.function
let nS = tracker[func] // Nonstatic context let nS = tracker[func] // Nonstatic context
let iS = target[func] // Static context let iS = target[func] // Static context
if(typeof nS === 'function' || typeof iS === 'function'){ if(typeof nS === 'function' || typeof iS === 'function'){
const f = typeof nS === 'function' ? nS : iS const f = typeof nS === 'function' ? nS : iS
const res = f.apply(f === nS ? tracker : null, msg.argsArr) const res = f.apply(f === nS ? tracker : null, msg.argsArr)
if(res instanceof Promise){ if(res instanceof Promise){
res.then((v) => { res.then((v) => {
process.send({result: v, context: func}) process.send({result: v, context: func})
}).catch((err) => { }).catch((err) => {
process.send({result: err.message || err, context: func}) process.send({result: err.message || err, context: func})
}) })
} else { } else {
process.send({result: res, context: func}) process.send({result: res, context: func})
} }
} else { } else {
process.send({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`}) process.send({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`})
} }
} else if(msg.task === 'changeContext'){ } else if(msg.task === 'changeContext'){
target = require('./assetguard')[msg.class] target = require('./assetguard')[msg.class]
if(target == null){ if(target == null){
process.send({context: 'error', data: null, error: `Invalid class ${msg.class}`}) process.send({context: 'error', data: null, error: `Invalid class ${msg.class}`})
} else { } else {
tracker = new target(...(msg.args)) tracker = new target(...(msg.args))
assignListeners() assignListeners()
} }
} }
}) })
process.on('disconnect', () => { process.on('disconnect', () => {
console.log('AssetExec Disconnected') console.log('AssetExec Disconnected')
process.exit(0) process.exit(0)
}) })

File diff suppressed because it is too large Load Diff

View File

@ -1,99 +1,99 @@
/** /**
* AuthManager * AuthManager
* *
* This module aims to abstract login procedures. Results from Mojang's REST api * This module aims to abstract login procedures. Results from Mojang's REST api
* are retrieved through our Mojang module. These results are processed and stored, * are retrieved through our Mojang module. These results are processed and stored,
* if applicable, in the config using the ConfigManager. All login procedures should * if applicable, in the config using the ConfigManager. All login procedures should
* be made through this module. * be made through this module.
* *
* @module authmanager * @module authmanager
*/ */
// Requirements // Requirements
const ConfigManager = require('./configmanager') const ConfigManager = require('./configmanager')
const LoggerUtil = require('./loggerutil') const LoggerUtil = require('./loggerutil')
const Mojang = require('./mojang') const Mojang = require('./mojang')
const logger = LoggerUtil('%c[AuthManager]', 'color: #a02d2a; font-weight: bold') const logger = LoggerUtil('%c[AuthManager]', 'color: #a02d2a; font-weight: bold')
const loggerSuccess = LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight: bold') const loggerSuccess = LoggerUtil('%c[AuthManager]', 'color: #209b07; font-weight: bold')
// Functions // Functions
/** /**
* Add an account. This will authenticate the given credentials with Mojang's * Add an account. This will authenticate the given credentials with Mojang's
* authserver. The resultant data will be stored as an auth account in the * authserver. The resultant data will be stored as an auth account in the
* configuration database. * configuration database.
* *
* @param {string} username The account username (email if migrated). * @param {string} username The account username (email if migrated).
* @param {string} password The account password. * @param {string} password The account password.
* @returns {Promise.<Object>} Promise which resolves the resolved authenticated account object. * @returns {Promise.<Object>} Promise which resolves the resolved authenticated account object.
*/ */
exports.addAccount = async function(username, password){ exports.addAccount = async function(username, password){
try { try {
const session = await Mojang.authenticate(username, password, ConfigManager.getClientToken()) const session = await Mojang.authenticate(username, password, ConfigManager.getClientToken())
if(session.selectedProfile != null){ if(session.selectedProfile != null){
const ret = ConfigManager.addAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name) const ret = ConfigManager.addAuthAccount(session.selectedProfile.id, session.accessToken, username, session.selectedProfile.name)
if(ConfigManager.getClientToken() == null){ if(ConfigManager.getClientToken() == null){
ConfigManager.setClientToken(session.clientToken) ConfigManager.setClientToken(session.clientToken)
} }
ConfigManager.save() ConfigManager.save()
return ret return ret
} else { } else {
throw new Error('NotPaidAccount') throw new Error('NotPaidAccount')
} }
} catch (err){ } catch (err){
return Promise.reject(err) return Promise.reject(err)
} }
} }
/** /**
* Remove an account. This will invalidate the access token associated * Remove an account. This will invalidate the access token associated
* with the account and then remove it from the database. * with the account and then remove it from the database.
* *
* @param {string} uuid The UUID of the account to be removed. * @param {string} uuid The UUID of the account to be removed.
* @returns {Promise.<void>} Promise which resolves to void when the action is complete. * @returns {Promise.<void>} Promise which resolves to void when the action is complete.
*/ */
exports.removeAccount = async function(uuid){ exports.removeAccount = async function(uuid){
try { try {
const authAcc = ConfigManager.getAuthAccount(uuid) const authAcc = ConfigManager.getAuthAccount(uuid)
await Mojang.invalidate(authAcc.accessToken, ConfigManager.getClientToken()) await Mojang.invalidate(authAcc.accessToken, ConfigManager.getClientToken())
ConfigManager.removeAuthAccount(uuid) ConfigManager.removeAuthAccount(uuid)
ConfigManager.save() ConfigManager.save()
return Promise.resolve() return Promise.resolve()
} catch (err){ } catch (err){
return Promise.reject(err) return Promise.reject(err)
} }
} }
/** /**
* Validate the selected account with Mojang's authserver. If the account is not valid, * Validate the selected account with Mojang's authserver. If the account is not valid,
* we will attempt to refresh the access token and update that value. If that fails, a * we will attempt to refresh the access token and update that value. If that fails, a
* new login will be required. * new login will be required.
* *
* **Function is WIP** * **Function is WIP**
* *
* @returns {Promise.<boolean>} Promise which resolves to true if the access token is valid, * @returns {Promise.<boolean>} Promise which resolves to true if the access token is valid,
* otherwise false. * otherwise false.
*/ */
exports.validateSelected = async function(){ exports.validateSelected = async function(){
const current = ConfigManager.getSelectedAccount() const current = ConfigManager.getSelectedAccount()
const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken()) const isValid = await Mojang.validate(current.accessToken, ConfigManager.getClientToken())
if(!isValid){ if(!isValid){
try { try {
const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken()) const session = await Mojang.refresh(current.accessToken, ConfigManager.getClientToken())
ConfigManager.updateAuthAccount(current.uuid, session.accessToken) ConfigManager.updateAuthAccount(current.uuid, session.accessToken)
ConfigManager.save() ConfigManager.save()
} catch(err) { } catch(err) {
logger.debug('Error while validating selected profile:', err) logger.debug('Error while validating selected profile:', err)
if(err && err.error === 'ForbiddenOperationException'){ if(err && err.error === 'ForbiddenOperationException'){
// What do we do? // What do we do?
} }
logger.log('Account access token is invalid.') logger.log('Account access token is invalid.')
return false return false
} }
loggerSuccess.log('Account access token validated.') loggerSuccess.log('Account access token validated.')
return true return true
} else { } else {
loggerSuccess.log('Account access token validated.') loggerSuccess.log('Account access token validated.')
return true return true
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,48 +1,48 @@
// Work in progress // Work in progress
const logger = require('./loggerutil')('%c[DiscordWrapper]', 'color: #7289da; font-weight: bold') const logger = require('./loggerutil')('%c[DiscordWrapper]', 'color: #7289da; font-weight: bold')
const {Client} = require('discord-rpc') const {Client} = require('discord-rpc')
let client let client
let activity let activity
exports.initRPC = function(genSettings, servSettings, initialDetails = 'Waiting for Client..'){ exports.initRPC = function(genSettings, servSettings, initialDetails = 'Waiting for Client..'){
client = new Client({ transport: 'ipc' }) client = new Client({ transport: 'ipc' })
activity = { activity = {
details: initialDetails, details: initialDetails,
state: 'Server: ' + servSettings.shortId, state: 'Server: ' + servSettings.shortId,
largeImageKey: servSettings.largeImageKey, largeImageKey: servSettings.largeImageKey,
largeImageText: servSettings.largeImageText, largeImageText: servSettings.largeImageText,
smallImageKey: genSettings.smallImageKey, smallImageKey: genSettings.smallImageKey,
smallImageText: genSettings.smallImageText, smallImageText: genSettings.smallImageText,
startTimestamp: new Date().getTime(), startTimestamp: new Date().getTime(),
instance: false instance: false
} }
client.on('ready', () => { client.on('ready', () => {
logger.log('Discord RPC Connected') logger.log('Discord RPC Connected')
client.setActivity(activity) client.setActivity(activity)
}) })
client.login({clientId: genSettings.clientId}).catch(error => { client.login({clientId: genSettings.clientId}).catch(error => {
if(error.message.includes('ENOENT')) { if(error.message.includes('ENOENT')) {
logger.log('Unable to initialize Discord Rich Presence, no client detected.') logger.log('Unable to initialize Discord Rich Presence, no client detected.')
} else { } else {
logger.log('Unable to initialize Discord Rich Presence: ' + error.message, error) logger.log('Unable to initialize Discord Rich Presence: ' + error.message, error)
} }
}) })
} }
exports.updateDetails = function(details){ exports.updateDetails = function(details){
activity.details = details activity.details = details
client.setActivity(activity) client.setActivity(activity)
} }
exports.shutdownRPC = function(){ exports.shutdownRPC = function(){
if(!client) return if(!client) return
client.clearActivity() client.clearActivity()
client.destroy() client.destroy()
client = null client = null
activity = null activity = null
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,232 +1,232 @@
const fs = require('fs-extra') const fs = require('fs-extra')
const path = require('path') const path = require('path')
const { shell } = require('electron') const { shell } = require('electron')
// Group #1: File Name (without .disabled, if any) // Group #1: File Name (without .disabled, if any)
// Group #2: File Extension (jar, zip, or litemod) // Group #2: File Extension (jar, zip, or litemod)
// Group #3: If it is disabled (if string 'disabled' is present) // Group #3: If it is disabled (if string 'disabled' is present)
const MOD_REGEX = /^(.+(jar|zip|litemod))(?:\.(disabled))?$/ const MOD_REGEX = /^(.+(jar|zip|litemod))(?:\.(disabled))?$/
const DISABLED_EXT = '.disabled' const DISABLED_EXT = '.disabled'
const SHADER_REGEX = /^(.+)\.zip$/ const SHADER_REGEX = /^(.+)\.zip$/
const SHADER_OPTION = /shaderPack=(.+)/ const SHADER_OPTION = /shaderPack=(.+)/
const SHADER_DIR = 'shaderpacks' const SHADER_DIR = 'shaderpacks'
const SHADER_CONFIG = 'optionsshaders.txt' const SHADER_CONFIG = 'optionsshaders.txt'
/** /**
* Validate that the given directory exists. If not, it is * Validate that the given directory exists. If not, it is
* created. * created.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
*/ */
exports.validateDir = function(dir) { exports.validateDir = function(dir) {
fs.ensureDirSync(dir) fs.ensureDirSync(dir)
} }
/** /**
* Scan for drop-in mods in both the mods folder and version * Scan for drop-in mods in both the mods folder and version
* safe mods folder. * safe mods folder.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
* @param {string} version The minecraft version of the server configuration. * @param {string} version The minecraft version of the server configuration.
* *
* @returns {{fullName: string, name: string, ext: string, disabled: boolean}[]} * @returns {{fullName: string, name: string, ext: string, disabled: boolean}[]}
* An array of objects storing metadata about each discovered mod. * An array of objects storing metadata about each discovered mod.
*/ */
exports.scanForDropinMods = function(modsDir, version) { exports.scanForDropinMods = function(modsDir, version) {
const modsDiscovered = [] const modsDiscovered = []
if(fs.existsSync(modsDir)){ if(fs.existsSync(modsDir)){
let modCandidates = fs.readdirSync(modsDir) let modCandidates = fs.readdirSync(modsDir)
let verCandidates = [] let verCandidates = []
const versionDir = path.join(modsDir, version) const versionDir = path.join(modsDir, version)
if(fs.existsSync(versionDir)){ if(fs.existsSync(versionDir)){
verCandidates = fs.readdirSync(versionDir) verCandidates = fs.readdirSync(versionDir)
} }
for(let file of modCandidates){ for(let file of modCandidates){
const match = MOD_REGEX.exec(file) const match = MOD_REGEX.exec(file)
if(match != null){ if(match != null){
modsDiscovered.push({ modsDiscovered.push({
fullName: match[0], fullName: match[0],
name: match[1], name: match[1],
ext: match[2], ext: match[2],
disabled: match[3] != null disabled: match[3] != null
}) })
} }
} }
for(let file of verCandidates){ for(let file of verCandidates){
const match = MOD_REGEX.exec(file) const match = MOD_REGEX.exec(file)
if(match != null){ if(match != null){
modsDiscovered.push({ modsDiscovered.push({
fullName: path.join(version, match[0]), fullName: path.join(version, match[0]),
name: match[1], name: match[1],
ext: match[2], ext: match[2],
disabled: match[3] != null disabled: match[3] != null
}) })
} }
} }
} }
return modsDiscovered return modsDiscovered
} }
/** /**
* Add dropin mods. * Add dropin mods.
* *
* @param {FileList} files The files to add. * @param {FileList} files The files to add.
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
*/ */
exports.addDropinMods = function(files, modsdir) { exports.addDropinMods = function(files, modsdir) {
exports.validateDir(modsdir) exports.validateDir(modsdir)
for(let f of files) { for(let f of files) {
if(MOD_REGEX.exec(f.name) != null) { if(MOD_REGEX.exec(f.name) != null) {
fs.moveSync(f.path, path.join(modsdir, f.name)) fs.moveSync(f.path, path.join(modsdir, f.name))
} }
} }
} }
/** /**
* Delete a drop-in mod from the file system. * Delete a drop-in mod from the file system.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
* @param {string} fullName The fullName of the discovered mod to delete. * @param {string} fullName The fullName of the discovered mod to delete.
* *
* @returns {boolean} True if the mod was deleted, otherwise false. * @returns {boolean} True if the mod was deleted, otherwise false.
*/ */
exports.deleteDropinMod = function(modsDir, fullName){ exports.deleteDropinMod = function(modsDir, fullName){
const res = shell.moveItemToTrash(path.join(modsDir, fullName)) const res = shell.moveItemToTrash(path.join(modsDir, fullName))
if(!res){ if(!res){
shell.beep() shell.beep()
} }
return res return res
} }
/** /**
* Toggle a discovered mod on or off. This is achieved by either * Toggle a discovered mod on or off. This is achieved by either
* adding or disabling the .disabled extension to the local file. * adding or disabling the .disabled extension to the local file.
* *
* @param {string} modsDir The path to the mods directory. * @param {string} modsDir The path to the mods directory.
* @param {string} fullName The fullName of the discovered mod to toggle. * @param {string} fullName The fullName of the discovered mod to toggle.
* @param {boolean} enable Whether to toggle on or off the mod. * @param {boolean} enable Whether to toggle on or off the mod.
* *
* @returns {Promise.<void>} A promise which resolves when the mod has * @returns {Promise.<void>} A promise which resolves when the mod has
* been toggled. If an IO error occurs the promise will be rejected. * been toggled. If an IO error occurs the promise will be rejected.
*/ */
exports.toggleDropinMod = function(modsDir, fullName, enable){ exports.toggleDropinMod = function(modsDir, fullName, enable){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const oldPath = path.join(modsDir, fullName) const oldPath = path.join(modsDir, fullName)
const newPath = path.join(modsDir, enable ? fullName.substring(0, fullName.indexOf(DISABLED_EXT)) : fullName + DISABLED_EXT) const newPath = path.join(modsDir, enable ? fullName.substring(0, fullName.indexOf(DISABLED_EXT)) : fullName + DISABLED_EXT)
fs.rename(oldPath, newPath, (err) => { fs.rename(oldPath, newPath, (err) => {
if(err){ if(err){
reject(err) reject(err)
} else { } else {
resolve() resolve()
} }
}) })
}) })
} }
/** /**
* Check if a drop-in mod is enabled. * Check if a drop-in mod is enabled.
* *
* @param {string} fullName The fullName of the discovered mod to toggle. * @param {string} fullName The fullName of the discovered mod to toggle.
* @returns {boolean} True if the mod is enabled, otherwise false. * @returns {boolean} True if the mod is enabled, otherwise false.
*/ */
exports.isDropinModEnabled = function(fullName){ exports.isDropinModEnabled = function(fullName){
return !fullName.endsWith(DISABLED_EXT) return !fullName.endsWith(DISABLED_EXT)
} }
/** /**
* Scan for shaderpacks inside the shaderpacks folder. * Scan for shaderpacks inside the shaderpacks folder.
* *
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
* *
* @returns {{fullName: string, name: string}[]} * @returns {{fullName: string, name: string}[]}
* An array of objects storing metadata about each discovered shaderpack. * An array of objects storing metadata about each discovered shaderpack.
*/ */
exports.scanForShaderpacks = function(instanceDir){ exports.scanForShaderpacks = function(instanceDir){
const shaderDir = path.join(instanceDir, SHADER_DIR) const shaderDir = path.join(instanceDir, SHADER_DIR)
const packsDiscovered = [{ const packsDiscovered = [{
fullName: 'OFF', fullName: 'OFF',
name: 'Off (Default)' name: 'Off (Default)'
}] }]
if(fs.existsSync(shaderDir)){ if(fs.existsSync(shaderDir)){
let modCandidates = fs.readdirSync(shaderDir) let modCandidates = fs.readdirSync(shaderDir)
for(let file of modCandidates){ for(let file of modCandidates){
const match = SHADER_REGEX.exec(file) const match = SHADER_REGEX.exec(file)
if(match != null){ if(match != null){
packsDiscovered.push({ packsDiscovered.push({
fullName: match[0], fullName: match[0],
name: match[1] name: match[1]
}) })
} }
} }
} }
return packsDiscovered return packsDiscovered
} }
/** /**
* Read the optionsshaders.txt file to locate the current * Read the optionsshaders.txt file to locate the current
* enabled pack. If the file does not exist, OFF is returned. * enabled pack. If the file does not exist, OFF is returned.
* *
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
* *
* @returns {string} The file name of the enabled shaderpack. * @returns {string} The file name of the enabled shaderpack.
*/ */
exports.getEnabledShaderpack = function(instanceDir){ exports.getEnabledShaderpack = function(instanceDir){
exports.validateDir(instanceDir) exports.validateDir(instanceDir)
const optionsShaders = path.join(instanceDir, SHADER_CONFIG) const optionsShaders = path.join(instanceDir, SHADER_CONFIG)
if(fs.existsSync(optionsShaders)){ if(fs.existsSync(optionsShaders)){
const buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'}) const buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'})
const match = SHADER_OPTION.exec(buf) const match = SHADER_OPTION.exec(buf)
if(match != null){ if(match != null){
return match[1] return match[1]
} else { } else {
console.warn('WARNING: Shaderpack regex failed.') console.warn('WARNING: Shaderpack regex failed.')
} }
} }
return 'OFF' return 'OFF'
} }
/** /**
* Set the enabled shaderpack. * Set the enabled shaderpack.
* *
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
* @param {string} pack the file name of the shaderpack. * @param {string} pack the file name of the shaderpack.
*/ */
exports.setEnabledShaderpack = function(instanceDir, pack){ exports.setEnabledShaderpack = function(instanceDir, pack){
exports.validateDir(instanceDir) exports.validateDir(instanceDir)
const optionsShaders = path.join(instanceDir, SHADER_CONFIG) const optionsShaders = path.join(instanceDir, SHADER_CONFIG)
let buf let buf
if(fs.existsSync(optionsShaders)){ if(fs.existsSync(optionsShaders)){
buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'}) buf = fs.readFileSync(optionsShaders, {encoding: 'utf-8'})
buf = buf.replace(SHADER_OPTION, `shaderPack=${pack}`) buf = buf.replace(SHADER_OPTION, `shaderPack=${pack}`)
} else { } else {
buf = `shaderPack=${pack}` buf = `shaderPack=${pack}`
} }
fs.writeFileSync(optionsShaders, buf, {encoding: 'utf-8'}) fs.writeFileSync(optionsShaders, buf, {encoding: 'utf-8'})
} }
/** /**
* Add shaderpacks. * Add shaderpacks.
* *
* @param {FileList} files The files to add. * @param {FileList} files The files to add.
* @param {string} instanceDir The path to the server instance directory. * @param {string} instanceDir The path to the server instance directory.
*/ */
exports.addShaderpacks = function(files, instanceDir) { exports.addShaderpacks = function(files, instanceDir) {
const p = path.join(instanceDir, SHADER_DIR) const p = path.join(instanceDir, SHADER_DIR)
exports.validateDir(p) exports.validateDir(p)
for(let f of files) { for(let f of files) {
if(SHADER_REGEX.exec(f.name) != null) { if(SHADER_REGEX.exec(f.name) != null) {
fs.moveSync(f.path, path.join(p, f.name)) fs.moveSync(f.path, path.join(p, f.name))
} }
} }
} }

View File

@ -1,5 +1,5 @@
'use strict' 'use strict'
const getFromEnv = parseInt(process.env.ELECTRON_IS_DEV, 10) === 1 const getFromEnv = parseInt(process.env.ELECTRON_IS_DEV, 10) === 1
const isEnvSet = 'ELECTRON_IS_DEV' in process.env const isEnvSet = 'ELECTRON_IS_DEV' in process.env
module.exports = isEnvSet ? getFromEnv : (process.defaultApp || /node_modules[\\/]electron[\\/]/.test(process.execPath)) module.exports = isEnvSet ? getFromEnv : (process.defaultApp || /node_modules[\\/]electron[\\/]/.test(process.execPath))

View File

@ -1,21 +1,21 @@
const fs = require('fs-extra') const fs = require('fs-extra')
const path = require('path') const path = require('path')
let lang let lang
exports.loadLanguage = function(id){ exports.loadLanguage = function(id){
lang = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.json`))) || {} lang = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.json`))) || {}
} }
exports.query = function(id){ exports.query = function(id){
let query = id.split('.') let query = id.split('.')
let res = lang let res = lang
for(let q of query){ for(let q of query){
res = res[q] res = res[q]
} }
return res === lang ? {} : res return res === lang ? {} : res
} }
exports.queryJS = function(id){ exports.queryJS = function(id){
return exports.query(`js.${id}`) return exports.query(`js.${id}`)
} }

View File

@ -1,32 +1,32 @@
class LoggerUtil { class LoggerUtil {
constructor(prefix, style){ constructor(prefix, style){
this.prefix = prefix this.prefix = prefix
this.style = style this.style = style
} }
log(){ log(){
console.log.apply(null, [this.prefix, this.style, ...arguments]) console.log.apply(null, [this.prefix, this.style, ...arguments])
} }
info(){ info(){
console.info.apply(null, [this.prefix, this.style, ...arguments]) console.info.apply(null, [this.prefix, this.style, ...arguments])
} }
warn(){ warn(){
console.warn.apply(null, [this.prefix, this.style, ...arguments]) console.warn.apply(null, [this.prefix, this.style, ...arguments])
} }
debug(){ debug(){
console.debug.apply(null, [this.prefix, this.style, ...arguments]) console.debug.apply(null, [this.prefix, this.style, ...arguments])
} }
error(){ error(){
console.error.apply(null, [this.prefix, this.style, ...arguments]) console.error.apply(null, [this.prefix, this.style, ...arguments])
} }
} }
module.exports = function (prefix, style){ module.exports = function (prefix, style){
return new LoggerUtil(prefix, style) return new LoggerUtil(prefix, style)
} }

View File

@ -1,271 +1,271 @@
/** /**
* Mojang * Mojang
* *
* This module serves as a minimal wrapper for Mojang's REST api. * This module serves as a minimal wrapper for Mojang's REST api.
* *
* @module mojang * @module mojang
*/ */
// Requirements // Requirements
const request = require('request') const request = require('request')
const logger = require('./loggerutil')('%c[Mojang]', 'color: #a02d2a; font-weight: bold') const logger = require('./loggerutil')('%c[Mojang]', 'color: #a02d2a; font-weight: bold')
// Constants // Constants
const minecraftAgent = { const minecraftAgent = {
name: 'Minecraft', name: 'Minecraft',
version: 1 version: 1
} }
const authpath = 'https://authserver.mojang.com' const authpath = 'https://authserver.mojang.com'
const statuses = [ const statuses = [
{ {
service: 'sessionserver.mojang.com', service: 'sessionserver.mojang.com',
status: 'grey', status: 'grey',
name: 'Multiplayer Session Service', name: 'Multiplayer Session Service',
essential: true essential: true
}, },
{ {
service: 'authserver.mojang.com', service: 'authserver.mojang.com',
status: 'grey', status: 'grey',
name: 'Authentication Service', name: 'Authentication Service',
essential: true essential: true
}, },
{ {
service: 'textures.minecraft.net', service: 'textures.minecraft.net',
status: 'grey', status: 'grey',
name: 'Minecraft Skins', name: 'Minecraft Skins',
essential: false essential: false
}, },
{ {
service: 'api.mojang.com', service: 'api.mojang.com',
status: 'grey', status: 'grey',
name: 'Public API', name: 'Public API',
essential: false essential: false
}, },
{ {
service: 'minecraft.net', service: 'minecraft.net',
status: 'grey', status: 'grey',
name: 'Minecraft.net', name: 'Minecraft.net',
essential: false essential: false
}, },
{ {
service: 'account.mojang.com', service: 'account.mojang.com',
status: 'grey', status: 'grey',
name: 'Mojang Accounts Website', name: 'Mojang Accounts Website',
essential: false essential: false
} }
] ]
// Functions // Functions
/** /**
* Converts a Mojang status color to a hex value. Valid statuses * Converts a Mojang status color to a hex value. Valid statuses
* are 'green', 'yellow', 'red', and 'grey'. Grey is a custom status * are 'green', 'yellow', 'red', and 'grey'. Grey is a custom status
* to our project which represents an unknown status. * to our project which represents an unknown status.
* *
* @param {string} status A valid status code. * @param {string} status A valid status code.
* @returns {string} The hex color of the status code. * @returns {string} The hex color of the status code.
*/ */
exports.statusToHex = function(status){ exports.statusToHex = function(status){
switch(status.toLowerCase()){ switch(status.toLowerCase()){
case 'green': case 'green':
return '#a5c325' return '#a5c325'
case 'yellow': case 'yellow':
return '#eac918' return '#eac918'
case 'red': case 'red':
return '#c32625' return '#c32625'
case 'grey': case 'grey':
default: default:
return '#848484' return '#848484'
} }
} }
/** /**
* Retrieves the status of Mojang's services. * Retrieves the status of Mojang's services.
* The response is condensed into a single object. Each service is * The response is condensed into a single object. Each service is
* a key, where the value is an object containing a status and name * a key, where the value is an object containing a status and name
* property. * property.
* *
* @see http://wiki.vg/Mojang_API#API_Status * @see http://wiki.vg/Mojang_API#API_Status
*/ */
exports.status = function(){ exports.status = function(){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.get('https://status.mojang.com/check', request.get('https://status.mojang.com/check',
{ {
json: true, json: true,
timeout: 2500 timeout: 2500
}, },
function(error, response, body){ function(error, response, body){
if(error || response.statusCode !== 200){ if(error || response.statusCode !== 200){
logger.warn('Unable to retrieve Mojang status.') logger.warn('Unable to retrieve Mojang status.')
logger.debug('Error while retrieving Mojang statuses:', error) logger.debug('Error while retrieving Mojang statuses:', error)
//reject(error || response.statusCode) //reject(error || response.statusCode)
for(let i=0; i<statuses.length; i++){ for(let i=0; i<statuses.length; i++){
statuses[i].status = 'grey' statuses[i].status = 'grey'
} }
resolve(statuses) resolve(statuses)
} else { } else {
for(let i=0; i<body.length; i++){ for(let i=0; i<body.length; i++){
const key = Object.keys(body[i])[0] const key = Object.keys(body[i])[0]
inner: inner:
for(let j=0; j<statuses.length; j++){ for(let j=0; j<statuses.length; j++){
if(statuses[j].service === key) { if(statuses[j].service === key) {
statuses[j].status = body[i][key] statuses[j].status = body[i][key]
break inner break inner
} }
} }
} }
resolve(statuses) resolve(statuses)
} }
}) })
}) })
} }
/** /**
* Authenticate a user with their Mojang credentials. * Authenticate a user with their Mojang credentials.
* *
* @param {string} username The user's username, this is often an email. * @param {string} username The user's username, this is often an email.
* @param {string} password The user's password. * @param {string} password The user's password.
* @param {string} clientToken The launcher's Client Token. * @param {string} clientToken The launcher's Client Token.
* @param {boolean} requestUser Optional. Adds user object to the reponse. * @param {boolean} requestUser Optional. Adds user object to the reponse.
* @param {Object} agent Optional. Provided by default. Adds user info to the response. * @param {Object} agent Optional. Provided by default. Adds user info to the response.
* *
* @see http://wiki.vg/Authentication#Authenticate * @see http://wiki.vg/Authentication#Authenticate
*/ */
exports.authenticate = function(username, password, clientToken, requestUser = true, agent = minecraftAgent){ exports.authenticate = function(username, password, clientToken, requestUser = true, agent = minecraftAgent){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const body = { const body = {
agent, agent,
username, username,
password, password,
requestUser requestUser
} }
if(clientToken != null){ if(clientToken != null){
body.clientToken = clientToken body.clientToken = clientToken
} }
request.post(authpath + '/authenticate', request.post(authpath + '/authenticate',
{ {
json: true, json: true,
body body
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during authentication.', error) logger.error('Error during authentication.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 200){ if(response.statusCode === 200){
resolve(body) resolve(body)
} else { } else {
reject(body || {code: 'ENOTFOUND'}) reject(body || {code: 'ENOTFOUND'})
} }
} }
}) })
}) })
} }
/** /**
* Validate an access token. This should always be done before launching. * Validate an access token. This should always be done before launching.
* The client token should match the one used to create the access token. * The client token should match the one used to create the access token.
* *
* @param {string} accessToken The access token to validate. * @param {string} accessToken The access token to validate.
* @param {string} clientToken The launcher's client token. * @param {string} clientToken The launcher's client token.
* *
* @see http://wiki.vg/Authentication#Validate * @see http://wiki.vg/Authentication#Validate
*/ */
exports.validate = function(accessToken, clientToken){ exports.validate = function(accessToken, clientToken){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(authpath + '/validate', request.post(authpath + '/validate',
{ {
json: true, json: true,
body: { body: {
accessToken, accessToken,
clientToken clientToken
} }
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during validation.', error) logger.error('Error during validation.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 403){ if(response.statusCode === 403){
resolve(false) resolve(false)
} else { } else {
// 204 if valid // 204 if valid
resolve(true) resolve(true)
} }
} }
}) })
}) })
} }
/** /**
* Invalidates an access token. The clientToken must match the * Invalidates an access token. The clientToken must match the
* token used to create the provided accessToken. * token used to create the provided accessToken.
* *
* @param {string} accessToken The access token to invalidate. * @param {string} accessToken The access token to invalidate.
* @param {string} clientToken The launcher's client token. * @param {string} clientToken The launcher's client token.
* *
* @see http://wiki.vg/Authentication#Invalidate * @see http://wiki.vg/Authentication#Invalidate
*/ */
exports.invalidate = function(accessToken, clientToken){ exports.invalidate = function(accessToken, clientToken){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(authpath + '/invalidate', request.post(authpath + '/invalidate',
{ {
json: true, json: true,
body: { body: {
accessToken, accessToken,
clientToken clientToken
} }
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during invalidation.', error) logger.error('Error during invalidation.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 204){ if(response.statusCode === 204){
resolve() resolve()
} else { } else {
reject(body) reject(body)
} }
} }
}) })
}) })
} }
/** /**
* Refresh a user's authentication. This should be used to keep a user logged * Refresh a user's authentication. This should be used to keep a user logged
* in without asking them for their credentials again. A new access token will * in without asking them for their credentials again. A new access token will
* be generated using a recent invalid access token. See Wiki for more info. * be generated using a recent invalid access token. See Wiki for more info.
* *
* @param {string} accessToken The old access token. * @param {string} accessToken The old access token.
* @param {string} clientToken The launcher's client token. * @param {string} clientToken The launcher's client token.
* @param {boolean} requestUser Optional. Adds user object to the reponse. * @param {boolean} requestUser Optional. Adds user object to the reponse.
* *
* @see http://wiki.vg/Authentication#Refresh * @see http://wiki.vg/Authentication#Refresh
*/ */
exports.refresh = function(accessToken, clientToken, requestUser = true){ exports.refresh = function(accessToken, clientToken, requestUser = true){
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post(authpath + '/refresh', request.post(authpath + '/refresh',
{ {
json: true, json: true,
body: { body: {
accessToken, accessToken,
clientToken, clientToken,
requestUser requestUser
} }
}, },
function(error, response, body){ function(error, response, body){
if(error){ if(error){
logger.error('Error during refresh.', error) logger.error('Error during refresh.', error)
reject(error) reject(error)
} else { } else {
if(response.statusCode === 200){ if(response.statusCode === 200){
resolve(body) resolve(body)
} else { } else {
reject(body) reject(body)
} }
} }
}) })
}) })
} }

View File

@ -1,69 +1,69 @@
const {ipcRenderer} = require('electron') const {ipcRenderer} = require('electron')
const fs = require('fs-extra') const fs = require('fs-extra')
const os = require('os') 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 DistroManager = require('./distromanager')
const LangLoader = require('./langloader') const LangLoader = require('./langloader')
const logger = require('./loggerutil')('%c[Preloader]', 'color: #a02d2a; font-weight: bold') const logger = require('./loggerutil')('%c[Preloader]', 'color: #a02d2a; font-weight: bold')
logger.log('Loading..') logger.log('Loading..')
// Load ConfigManager // Load ConfigManager
ConfigManager.load() ConfigManager.load()
// Load Strings // Load Strings
LangLoader.loadLanguage('en_US') LangLoader.loadLanguage('en_US')
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.getServer(ConfigManager.getSelectedServer()) == null){
logger.log('Determining default selected server..') logger.log('Determining default selected server..')
ConfigManager.setSelectedServer(data.getMainServer().getID()) ConfigManager.setSelectedServer(data.getMainServer().getID())
ConfigManager.save() ConfigManager.save()
} }
} }
ipcRenderer.send('distributionIndexDone', data != null) ipcRenderer.send('distributionIndexDone', data != null)
} }
// Ensure Distribution is downloaded and cached. // Ensure Distribution is downloaded and cached.
DistroManager.pullRemote().then((data) => { DistroManager.pullRemote().then((data) => {
logger.log('Loaded distribution index.') logger.log('Loaded distribution index.')
onDistroLoad(data) onDistroLoad(data)
}).catch((err) => { }).catch((err) => {
logger.log('Failed to load distribution index.') logger.log('Failed to load distribution index.')
logger.error(err) logger.error(err)
logger.log('Attempting to load an older version of the distribution index.') logger.log('Attempting to load an older version of the distribution index.')
// Try getting a local copy, better than nothing. // Try getting a local copy, better than nothing.
DistroManager.pullLocal().then((data) => { DistroManager.pullLocal().then((data) => {
logger.log('Successfully loaded an older version of the distribution index.') logger.log('Successfully loaded an older version of the distribution index.')
onDistroLoad(data) onDistroLoad(data)
}).catch((err) => { }).catch((err) => {
logger.log('Failed to load an older version of the distribution index.') logger.log('Failed to load an older version of the distribution index.')
logger.log('Application cannot run.') logger.log('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){
logger.warn('Error while cleaning natives directory', err) logger.warn('Error while cleaning natives directory', err)
} else { } else {
logger.log('Cleaned natives directory.') logger.log('Cleaned natives directory.')
} }
}) })

File diff suppressed because it is too large Load Diff

View File

@ -1,300 +1,300 @@
/** /**
* Script for login.ejs * Script for login.ejs
*/ */
// Validation Regexes. // Validation Regexes.
const validUsername = /^[a-zA-Z0-9_]{1,16}$/ const validUsername = /^[a-zA-Z0-9_]{1,16}$/
const basicEmail = /^\S+@\S+\.\S+$/ const basicEmail = /^\S+@\S+\.\S+$/
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i //const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
// Login Elements // Login Elements
const loginCancelContainer = document.getElementById('loginCancelContainer') const loginCancelContainer = document.getElementById('loginCancelContainer')
const loginCancelButton = document.getElementById('loginCancelButton') const loginCancelButton = document.getElementById('loginCancelButton')
const loginEmailError = document.getElementById('loginEmailError') const loginEmailError = document.getElementById('loginEmailError')
const loginUsername = document.getElementById('loginUsername') const loginUsername = document.getElementById('loginUsername')
const loginPasswordError = document.getElementById('loginPasswordError') const loginPasswordError = document.getElementById('loginPasswordError')
const loginPassword = document.getElementById('loginPassword') const loginPassword = document.getElementById('loginPassword')
const checkmarkContainer = document.getElementById('checkmarkContainer') const checkmarkContainer = document.getElementById('checkmarkContainer')
const loginRememberOption = document.getElementById('loginRememberOption') const loginRememberOption = document.getElementById('loginRememberOption')
const loginButton = document.getElementById('loginButton') const loginButton = document.getElementById('loginButton')
const loginForm = document.getElementById('loginForm') const loginForm = document.getElementById('loginForm')
// Control variables. // Control variables.
let lu = false, lp = false let lu = false, lp = false
const loggerLogin = LoggerUtil('%c[Login]', 'color: #000668; font-weight: bold') const loggerLogin = LoggerUtil('%c[Login]', 'color: #000668; font-weight: bold')
/** /**
* Show a login error. * Show a login error.
* *
* @param {HTMLElement} element The element on which to display the error. * @param {HTMLElement} element The element on which to display the error.
* @param {string} value The error text. * @param {string} value The error text.
*/ */
function showError(element, value){ function showError(element, value){
element.innerHTML = value element.innerHTML = value
element.style.opacity = 1 element.style.opacity = 1
} }
/** /**
* Shake a login error to add emphasis. * Shake a login error to add emphasis.
* *
* @param {HTMLElement} element The element to shake. * @param {HTMLElement} element The element to shake.
*/ */
function shakeError(element){ function shakeError(element){
if(element.style.opacity == 1){ if(element.style.opacity == 1){
element.classList.remove('shake') element.classList.remove('shake')
void element.offsetWidth void element.offsetWidth
element.classList.add('shake') element.classList.add('shake')
} }
} }
/** /**
* Validate that an email field is neither empty nor invalid. * Validate that an email field is neither empty nor invalid.
* *
* @param {string} value The email value. * @param {string} value The email value.
*/ */
function validateEmail(value){ function validateEmail(value){
if(value){ if(value){
if(!basicEmail.test(value) && !validUsername.test(value)){ if(!basicEmail.test(value) && !validUsername.test(value)){
showError(loginEmailError, Lang.queryJS('login.error.invalidValue')) showError(loginEmailError, Lang.queryJS('login.error.invalidValue'))
loginDisabled(true) loginDisabled(true)
lu = false lu = false
} else { } else {
loginEmailError.style.opacity = 0 loginEmailError.style.opacity = 0
lu = true lu = true
if(lp){ if(lp){
loginDisabled(false) loginDisabled(false)
} }
} }
} else { } else {
lu = false lu = false
showError(loginEmailError, Lang.queryJS('login.error.requiredValue')) showError(loginEmailError, Lang.queryJS('login.error.requiredValue'))
loginDisabled(true) loginDisabled(true)
} }
} }
/** /**
* Validate that the password field is not empty. * Validate that the password field is not empty.
* *
* @param {string} value The password value. * @param {string} value The password value.
*/ */
function validatePassword(value){ function validatePassword(value){
if(value){ if(value){
loginPasswordError.style.opacity = 0 loginPasswordError.style.opacity = 0
lp = true lp = true
if(lu){ if(lu){
loginDisabled(false) loginDisabled(false)
} }
} else { } else {
lp = false lp = false
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue')) showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
loginDisabled(true) loginDisabled(true)
} }
} }
// Emphasize errors with shake when focus is lost. // Emphasize errors with shake when focus is lost.
loginUsername.addEventListener('focusout', (e) => { loginUsername.addEventListener('focusout', (e) => {
validateEmail(e.target.value) validateEmail(e.target.value)
shakeError(loginEmailError) shakeError(loginEmailError)
}) })
loginPassword.addEventListener('focusout', (e) => { loginPassword.addEventListener('focusout', (e) => {
validatePassword(e.target.value) validatePassword(e.target.value)
shakeError(loginPasswordError) shakeError(loginPasswordError)
}) })
// Validate input for each field. // Validate input for each field.
loginUsername.addEventListener('input', (e) => { loginUsername.addEventListener('input', (e) => {
validateEmail(e.target.value) validateEmail(e.target.value)
}) })
loginPassword.addEventListener('input', (e) => { loginPassword.addEventListener('input', (e) => {
validatePassword(e.target.value) validatePassword(e.target.value)
}) })
/** /**
* Enable or disable the login button. * Enable or disable the login button.
* *
* @param {boolean} v True to enable, false to disable. * @param {boolean} v True to enable, false to disable.
*/ */
function loginDisabled(v){ function loginDisabled(v){
if(loginButton.disabled !== v){ if(loginButton.disabled !== v){
loginButton.disabled = v loginButton.disabled = v
} }
} }
/** /**
* Enable or disable loading elements. * Enable or disable loading elements.
* *
* @param {boolean} v True to enable, false to disable. * @param {boolean} v True to enable, false to disable.
*/ */
function loginLoading(v){ function loginLoading(v){
if(v){ if(v){
loginButton.setAttribute('loading', v) loginButton.setAttribute('loading', v)
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn')) loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn'))
} else { } else {
loginButton.removeAttribute('loading') loginButton.removeAttribute('loading')
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login')) loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login'))
} }
} }
/** /**
* Enable or disable login form. * Enable or disable login form.
* *
* @param {boolean} v True to enable, false to disable. * @param {boolean} v True to enable, false to disable.
*/ */
function formDisabled(v){ function formDisabled(v){
loginDisabled(v) loginDisabled(v)
loginCancelButton.disabled = v loginCancelButton.disabled = v
loginUsername.disabled = v loginUsername.disabled = v
loginPassword.disabled = v loginPassword.disabled = v
if(v){ if(v){
checkmarkContainer.setAttribute('disabled', v) checkmarkContainer.setAttribute('disabled', v)
} else { } else {
checkmarkContainer.removeAttribute('disabled') checkmarkContainer.removeAttribute('disabled')
} }
loginRememberOption.disabled = v loginRememberOption.disabled = v
} }
/** /**
* Parses an error and returns a user-friendly title and description * Parses an error and returns a user-friendly title and description
* for our error overlay. * for our error overlay.
* *
* @param {Error | {cause: string, error: string, errorMessage: string}} err A Node.js * @param {Error | {cause: string, error: string, errorMessage: string}} err A Node.js
* error or Mojang error response. * error or Mojang error response.
*/ */
function resolveError(err){ function resolveError(err){
// Mojang Response => err.cause | err.error | err.errorMessage // Mojang Response => err.cause | err.error | err.errorMessage
// Node error => err.code | err.message // Node error => err.code | err.message
if(err.cause != null && err.cause === 'UserMigratedException') { if(err.cause != null && err.cause === 'UserMigratedException') {
return { return {
title: Lang.queryJS('login.error.userMigrated.title'), title: Lang.queryJS('login.error.userMigrated.title'),
desc: Lang.queryJS('login.error.userMigrated.desc') desc: Lang.queryJS('login.error.userMigrated.desc')
} }
} else { } else {
if(err.error != null){ if(err.error != null){
if(err.error === 'ForbiddenOperationException'){ if(err.error === 'ForbiddenOperationException'){
if(err.errorMessage != null){ if(err.errorMessage != null){
if(err.errorMessage === 'Invalid credentials. Invalid username or password.'){ if(err.errorMessage === 'Invalid credentials. Invalid username or password.'){
return { return {
title: Lang.queryJS('login.error.invalidCredentials.title'), title: Lang.queryJS('login.error.invalidCredentials.title'),
desc: Lang.queryJS('login.error.invalidCredentials.desc') desc: Lang.queryJS('login.error.invalidCredentials.desc')
} }
} else if(err.errorMessage === 'Invalid credentials.'){ } else if(err.errorMessage === 'Invalid credentials.'){
return { return {
title: Lang.queryJS('login.error.rateLimit.title'), title: Lang.queryJS('login.error.rateLimit.title'),
desc: Lang.queryJS('login.error.rateLimit.desc') desc: Lang.queryJS('login.error.rateLimit.desc')
} }
} }
} }
} }
} else { } else {
// Request errors (from Node). // Request errors (from Node).
if(err.code != null){ if(err.code != null){
if(err.code === 'ENOENT'){ if(err.code === 'ENOENT'){
// No Internet. // No Internet.
return { return {
title: Lang.queryJS('login.error.noInternet.title'), title: Lang.queryJS('login.error.noInternet.title'),
desc: Lang.queryJS('login.error.noInternet.desc') desc: Lang.queryJS('login.error.noInternet.desc')
} }
} else if(err.code === 'ENOTFOUND'){ } else if(err.code === 'ENOTFOUND'){
// Could not reach server. // Could not reach server.
return { return {
title: Lang.queryJS('login.error.authDown.title'), title: Lang.queryJS('login.error.authDown.title'),
desc: Lang.queryJS('login.error.authDown.desc') desc: Lang.queryJS('login.error.authDown.desc')
} }
} }
} }
} }
} }
if(err.message != null){ if(err.message != null){
if(err.message === 'NotPaidAccount'){ if(err.message === 'NotPaidAccount'){
return { return {
title: Lang.queryJS('login.error.notPaid.title'), title: Lang.queryJS('login.error.notPaid.title'),
desc: Lang.queryJS('login.error.notPaid.desc') desc: Lang.queryJS('login.error.notPaid.desc')
} }
} else { } else {
// Unknown error with request. // Unknown error with request.
return { return {
title: Lang.queryJS('login.error.unknown.title'), title: Lang.queryJS('login.error.unknown.title'),
desc: err.message desc: err.message
} }
} }
} else { } else {
// Unknown Mojang error. // Unknown Mojang error.
return { return {
title: err.error, title: err.error,
desc: err.errorMessage desc: err.errorMessage
} }
} }
} }
let loginViewOnSuccess = VIEWS.landing let loginViewOnSuccess = VIEWS.landing
let loginViewOnCancel = VIEWS.settings let loginViewOnCancel = VIEWS.settings
let loginViewCancelHandler let loginViewCancelHandler
function loginCancelEnabled(val){ function loginCancelEnabled(val){
if(val){ if(val){
$(loginCancelContainer).show() $(loginCancelContainer).show()
} else { } else {
$(loginCancelContainer).hide() $(loginCancelContainer).hide()
} }
} }
loginCancelButton.onclick = (e) => { loginCancelButton.onclick = (e) => {
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => { switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
loginUsername.value = '' loginUsername.value = ''
loginPassword.value = '' loginPassword.value = ''
loginCancelEnabled(false) loginCancelEnabled(false)
if(loginViewCancelHandler != null){ if(loginViewCancelHandler != null){
loginViewCancelHandler() loginViewCancelHandler()
loginViewCancelHandler = null loginViewCancelHandler = null
} }
}) })
} }
// Disable default form behavior. // Disable default form behavior.
loginForm.onsubmit = () => { return false } loginForm.onsubmit = () => { return false }
// Bind login button behavior. // Bind login button behavior.
loginButton.addEventListener('click', () => { loginButton.addEventListener('click', () => {
// Disable form. // Disable form.
formDisabled(true) formDisabled(true)
// Show loading stuff. // Show loading stuff.
loginLoading(true) loginLoading(true)
AuthManager.addAccount(loginUsername.value, loginPassword.value).then((value) => { AuthManager.addAccount(loginUsername.value, loginPassword.value).then((value) => {
updateSelectedAccount(value) updateSelectedAccount(value)
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success')) loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
$('.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, () => {
// Temporary workaround // Temporary workaround
if(loginViewOnSuccess === VIEWS.settings){ if(loginViewOnSuccess === VIEWS.settings){
prepareSettings() 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.
loginViewCancelHandler = null // Reset this for good measure. loginViewCancelHandler = null // Reset this for good measure.
loginUsername.value = '' loginUsername.value = ''
loginPassword.value = '' loginPassword.value = ''
$('.circle-loader').toggleClass('load-complete') $('.circle-loader').toggleClass('load-complete')
$('.checkmark').toggle() $('.checkmark').toggle()
loginLoading(false) loginLoading(false)
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login')) loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
formDisabled(false) formDisabled(false)
}) })
}, 1000) }, 1000)
}).catch((err) => { }).catch((err) => {
loginLoading(false) loginLoading(false)
const errF = resolveError(err) const errF = resolveError(err)
setOverlayContent(errF.title, errF.desc, Lang.queryJS('login.tryAgain')) setOverlayContent(errF.title, errF.desc, Lang.queryJS('login.tryAgain'))
setOverlayHandler(() => { setOverlayHandler(() => {
formDisabled(false) formDisabled(false)
toggleOverlay(false) toggleOverlay(false)
}) })
toggleOverlay(true) toggleOverlay(true)
loggerLogin.log('Error while logging in.', err) loggerLogin.log('Error while logging in.', err)
}) })
}) })

View File

@ -1,318 +1,318 @@
/** /**
* Script for overlay.ejs * Script for overlay.ejs
*/ */
/* Overlay Wrapper Functions */ /* Overlay Wrapper Functions */
/** /**
* Check to see if the overlay is visible. * Check to see if the overlay is visible.
* *
* @returns {boolean} Whether or not the overlay is visible. * @returns {boolean} Whether or not the overlay is visible.
*/ */
function isOverlayVisible(){ function isOverlayVisible(){
return document.getElementById('main').hasAttribute('overlay') return document.getElementById('main').hasAttribute('overlay')
} }
let overlayHandlerContent let overlayHandlerContent
/** /**
* Overlay keydown handler for a non-dismissable overlay. * Overlay keydown handler for a non-dismissable overlay.
* *
* @param {KeyboardEvent} e The keydown event. * @param {KeyboardEvent} e The keydown event.
*/ */
function overlayKeyHandler (e){ function overlayKeyHandler (e){
if(e.key === 'Enter' || e.key === 'Escape'){ if(e.key === 'Enter' || e.key === 'Escape'){
document.getElementById(overlayHandlerContent).getElementsByClassName('overlayKeybindEnter')[0].click() document.getElementById(overlayHandlerContent).getElementsByClassName('overlayKeybindEnter')[0].click()
} }
} }
/** /**
* Overlay keydown handler for a dismissable overlay. * Overlay keydown handler for a dismissable overlay.
* *
* @param {KeyboardEvent} e The keydown event. * @param {KeyboardEvent} e The keydown event.
*/ */
function overlayKeyDismissableHandler (e){ function overlayKeyDismissableHandler (e){
if(e.key === 'Enter'){ if(e.key === 'Enter'){
document.getElementById(overlayHandlerContent).getElementsByClassName('overlayKeybindEnter')[0].click() document.getElementById(overlayHandlerContent).getElementsByClassName('overlayKeybindEnter')[0].click()
} else if(e.key === 'Escape'){ } else if(e.key === 'Escape'){
document.getElementById(overlayHandlerContent).getElementsByClassName('overlayKeybindEsc')[0].click() document.getElementById(overlayHandlerContent).getElementsByClassName('overlayKeybindEsc')[0].click()
} }
} }
/** /**
* Bind overlay keydown listeners for escape and exit. * Bind overlay keydown listeners for escape and exit.
* *
* @param {boolean} state Whether or not to add new event listeners. * @param {boolean} state Whether or not to add new event listeners.
* @param {string} content The overlay content which will be shown. * @param {string} content The overlay content which will be shown.
* @param {boolean} dismissable Whether or not the overlay is dismissable * @param {boolean} dismissable Whether or not the overlay is dismissable
*/ */
function bindOverlayKeys(state, content, dismissable){ function bindOverlayKeys(state, content, dismissable){
overlayHandlerContent = content overlayHandlerContent = content
document.removeEventListener('keydown', overlayKeyHandler) document.removeEventListener('keydown', overlayKeyHandler)
document.removeEventListener('keydown', overlayKeyDismissableHandler) document.removeEventListener('keydown', overlayKeyDismissableHandler)
if(state){ if(state){
if(dismissable){ if(dismissable){
document.addEventListener('keydown', overlayKeyDismissableHandler) document.addEventListener('keydown', overlayKeyDismissableHandler)
} else { } else {
document.addEventListener('keydown', overlayKeyHandler) document.addEventListener('keydown', overlayKeyHandler)
} }
} }
} }
/** /**
* Toggle the visibility of the overlay. * Toggle the visibility of the overlay.
* *
* @param {boolean} toggleState True to display, false to hide. * @param {boolean} toggleState True to display, false to hide.
* @param {boolean} dismissable Optional. True to show the dismiss option, otherwise false. * @param {boolean} dismissable Optional. True to show the dismiss option, otherwise false.
* @param {string} content Optional. The content div to be shown. * @param {string} content Optional. The content div to be shown.
*/ */
function toggleOverlay(toggleState, dismissable = false, content = 'overlayContent'){ function toggleOverlay(toggleState, dismissable = false, content = 'overlayContent'){
if(toggleState == null){ if(toggleState == null){
toggleState = !document.getElementById('main').hasAttribute('overlay') toggleState = !document.getElementById('main').hasAttribute('overlay')
} }
if(typeof dismissable === 'string'){ if(typeof dismissable === 'string'){
content = dismissable content = dismissable
dismissable = false dismissable = false
} }
bindOverlayKeys(toggleState, content, dismissable) bindOverlayKeys(toggleState, content, dismissable)
if(toggleState){ if(toggleState){
document.getElementById('main').setAttribute('overlay', true) document.getElementById('main').setAttribute('overlay', true)
// Make things untabbable. // Make things untabbable.
$('#main *').attr('tabindex', '-1') $('#main *').attr('tabindex', '-1')
$('#' + content).parent().children().hide() $('#' + content).parent().children().hide()
$('#' + content).show() $('#' + content).show()
if(dismissable){ if(dismissable){
$('#overlayDismiss').show() $('#overlayDismiss').show()
} else { } else {
$('#overlayDismiss').hide() $('#overlayDismiss').hide()
} }
$('#overlayContainer').fadeIn({ $('#overlayContainer').fadeIn({
duration: 250, duration: 250,
start: () => { start: () => {
if(getCurrentView() === VIEWS.settings){ if(getCurrentView() === VIEWS.settings){
document.getElementById('settingsContainer').style.backgroundColor = 'transparent' document.getElementById('settingsContainer').style.backgroundColor = 'transparent'
} }
} }
}) })
} else { } else {
document.getElementById('main').removeAttribute('overlay') document.getElementById('main').removeAttribute('overlay')
// Make things tabbable. // Make things tabbable.
$('#main *').removeAttr('tabindex') $('#main *').removeAttr('tabindex')
$('#overlayContainer').fadeOut({ $('#overlayContainer').fadeOut({
duration: 250, duration: 250,
start: () => { start: () => {
if(getCurrentView() === VIEWS.settings){ if(getCurrentView() === VIEWS.settings){
document.getElementById('settingsContainer').style.backgroundColor = 'rgba(0, 0, 0, 0.50)' document.getElementById('settingsContainer').style.backgroundColor = 'rgba(0, 0, 0, 0.50)'
} }
}, },
complete: () => { complete: () => {
$('#' + content).parent().children().hide() $('#' + content).parent().children().hide()
$('#' + content).show() $('#' + content).show()
if(dismissable){ if(dismissable){
$('#overlayDismiss').show() $('#overlayDismiss').show()
} else { } else {
$('#overlayDismiss').hide() $('#overlayDismiss').hide()
} }
} }
}) })
} }
} }
function toggleServerSelection(toggleState){ function toggleServerSelection(toggleState){
prepareServerSelectionList() prepareServerSelectionList()
toggleOverlay(toggleState, true, 'serverSelectContent') toggleOverlay(toggleState, true, 'serverSelectContent')
} }
/** /**
* Set the content of the overlay. * Set the content of the overlay.
* *
* @param {string} title Overlay title text. * @param {string} title Overlay title text.
* @param {string} description Overlay description text. * @param {string} description Overlay description text.
* @param {string} acknowledge Acknowledge button text. * @param {string} acknowledge Acknowledge button text.
* @param {string} dismiss Dismiss button text. * @param {string} dismiss Dismiss button text.
*/ */
function setOverlayContent(title, description, acknowledge, dismiss = 'Dismiss'){ function setOverlayContent(title, description, acknowledge, dismiss = 'Dismiss'){
document.getElementById('overlayTitle').innerHTML = title document.getElementById('overlayTitle').innerHTML = title
document.getElementById('overlayDesc').innerHTML = description document.getElementById('overlayDesc').innerHTML = description
document.getElementById('overlayAcknowledge').innerHTML = acknowledge document.getElementById('overlayAcknowledge').innerHTML = acknowledge
document.getElementById('overlayDismiss').innerHTML = dismiss document.getElementById('overlayDismiss').innerHTML = dismiss
} }
/** /**
* Set the onclick handler of the overlay acknowledge button. * Set the onclick handler of the overlay acknowledge button.
* If the handler is null, a default handler will be added. * If the handler is null, a default handler will be added.
* *
* @param {function} handler * @param {function} handler
*/ */
function setOverlayHandler(handler){ function setOverlayHandler(handler){
if(handler == null){ if(handler == null){
document.getElementById('overlayAcknowledge').onclick = () => { document.getElementById('overlayAcknowledge').onclick = () => {
toggleOverlay(false) toggleOverlay(false)
} }
} else { } else {
document.getElementById('overlayAcknowledge').onclick = handler document.getElementById('overlayAcknowledge').onclick = handler
} }
} }
/** /**
* Set the onclick handler of the overlay dismiss button. * Set the onclick handler of the overlay dismiss button.
* If the handler is null, a default handler will be added. * If the handler is null, a default handler will be added.
* *
* @param {function} handler * @param {function} handler
*/ */
function setDismissHandler(handler){ function setDismissHandler(handler){
if(handler == null){ if(handler == null){
document.getElementById('overlayDismiss').onclick = () => { document.getElementById('overlayDismiss').onclick = () => {
toggleOverlay(false) toggleOverlay(false)
} }
} else { } else {
document.getElementById('overlayDismiss').onclick = handler document.getElementById('overlayDismiss').onclick = handler
} }
} }
/* Server Select View */ /* Server Select View */
document.getElementById('serverSelectConfirm').addEventListener('click', () => { document.getElementById('serverSelectConfirm').addEventListener('click', () => {
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 = DistroManager.getDistribution().getServer(listings[i].getAttribute('servid'))
updateSelectedServer(serv) updateSelectedServer(serv)
refreshServerStatus(true) refreshServerStatus(true)
toggleOverlay(false) toggleOverlay(false)
return return
} }
} }
// 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 = DistroManager.getDistribution().getServer(listings[i].getAttribute('servid'))
updateSelectedServer(serv) updateSelectedServer(serv)
toggleOverlay(false) toggleOverlay(false)
} }
}) })
document.getElementById('accountSelectConfirm').addEventListener('click', () => { document.getElementById('accountSelectConfirm').addEventListener('click', () => {
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')){
const authAcc = ConfigManager.setSelectedAccount(listings[i].getAttribute('uuid')) const authAcc = ConfigManager.setSelectedAccount(listings[i].getAttribute('uuid'))
ConfigManager.save() ConfigManager.save()
updateSelectedAccount(authAcc) updateSelectedAccount(authAcc)
toggleOverlay(false) toggleOverlay(false)
validateSelectedAccount() validateSelectedAccount()
return return
} }
} }
// 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 authAcc = ConfigManager.setSelectedAccount(listings[0].getAttribute('uuid')) const authAcc = ConfigManager.setSelectedAccount(listings[0].getAttribute('uuid'))
ConfigManager.save() ConfigManager.save()
updateSelectedAccount(authAcc) updateSelectedAccount(authAcc)
toggleOverlay(false) toggleOverlay(false)
validateSelectedAccount() validateSelectedAccount()
} }
}) })
// Bind server select cancel button. // Bind server select cancel button.
document.getElementById('serverSelectCancel').addEventListener('click', () => { document.getElementById('serverSelectCancel').addEventListener('click', () => {
toggleOverlay(false) toggleOverlay(false)
}) })
document.getElementById('accountSelectCancel').addEventListener('click', () => { document.getElementById('accountSelectCancel').addEventListener('click', () => {
$('#accountSelectContent').fadeOut(250, () => { $('#accountSelectContent').fadeOut(250, () => {
$('#overlayContent').fadeIn(250) $('#overlayContent').fadeIn(250)
}) })
}) })
function setServerListingHandlers(){ function setServerListingHandlers(){
const listings = Array.from(document.getElementsByClassName('serverListing')) const listings = Array.from(document.getElementsByClassName('serverListing'))
listings.map((val) => { listings.map((val) => {
val.onclick = e => { val.onclick = e => {
if(val.hasAttribute('selected')){ if(val.hasAttribute('selected')){
return return
} }
const cListings = document.getElementsByClassName('serverListing') const cListings = document.getElementsByClassName('serverListing')
for(let i=0; i<cListings.length; i++){ for(let i=0; i<cListings.length; i++){
if(cListings[i].hasAttribute('selected')){ if(cListings[i].hasAttribute('selected')){
cListings[i].removeAttribute('selected') cListings[i].removeAttribute('selected')
} }
} }
val.setAttribute('selected', '') val.setAttribute('selected', '')
document.activeElement.blur() document.activeElement.blur()
} }
}) })
} }
function setAccountListingHandlers(){ function setAccountListingHandlers(){
const listings = Array.from(document.getElementsByClassName('accountListing')) const listings = Array.from(document.getElementsByClassName('accountListing'))
listings.map((val) => { listings.map((val) => {
val.onclick = e => { val.onclick = e => {
if(val.hasAttribute('selected')){ if(val.hasAttribute('selected')){
return return
} }
const cListings = document.getElementsByClassName('accountListing') const cListings = document.getElementsByClassName('accountListing')
for(let i=0; i<cListings.length; i++){ for(let i=0; i<cListings.length; i++){
if(cListings[i].hasAttribute('selected')){ if(cListings[i].hasAttribute('selected')){
cListings[i].removeAttribute('selected') cListings[i].removeAttribute('selected')
} }
} }
val.setAttribute('selected', '') val.setAttribute('selected', '')
document.activeElement.blur() document.activeElement.blur()
} }
}) })
} }
function populateServerListings(){ function populateServerListings(){
const distro = DistroManager.getDistribution() const distro = DistroManager.getDistribution()
const giaSel = ConfigManager.getSelectedServer() const giaSel = ConfigManager.getSelectedServer()
const servers = distro.getServers() const servers = distro.getServers()
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.getID()}" ${serv.getID() === giaSel ? 'selected' : ''}>
<img class="serverListingImg" src="${serv.getIcon()}"/> <img class="serverListingImg" src="${serv.getIcon()}"/>
<div class="serverListingDetails"> <div class="serverListingDetails">
<span class="serverListingName">${serv.getName()}</span> <span class="serverListingName">${serv.getName()}</span>
<span class="serverListingDescription">${serv.getDescription()}</span> <span class="serverListingDescription">${serv.getDescription()}</span>
<div class="serverListingInfo"> <div class="serverListingInfo">
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div> <div class="serverListingVersion">${serv.getMinecraftVersion()}</div>
<div class="serverListingRevision">${serv.getVersion()}</div> <div class="serverListingRevision">${serv.getVersion()}</div>
${serv.isMainServer() ? `<div class="serverListingStarWrapper"> ${serv.isMainServer() ? `<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>
</defs> </defs>
<path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/> <path class="cls-1" d="M100.93,65.54C89,62,68.18,55.65,63.54,52.13c2.7-5.23,18.8-19.2,28-27.55C81.36,31.74,63.74,43.87,58.09,45.3c-2.41-5.37-3.61-26.52-4.37-39-.77,12.46-2,33.64-4.36,39-5.7-1.46-23.3-13.57-33.49-20.72,9.26,8.37,25.39,22.36,28,27.55C39.21,55.68,18.47,62,6.52,65.55c12.32-2,33.63-6.06,39.34-4.9-.16,5.87-8.41,26.16-13.11,37.69,6.1-10.89,16.52-30.16,21-33.9,4.5,3.79,14.93,23.09,21,34C70,86.84,61.73,66.48,61.59,60.65,67.36,59.49,88.64,63.52,100.93,65.54Z"/>
<circle class="cls-2" cx="53.73" cy="53.9" r="38"/> <circle class="cls-2" cx="53.73" cy="53.9" r="38"/>
</svg> </svg>
<span class="serverListingStarTooltip">Main Server</span> <span class="serverListingStarTooltip">Main Server</span>
</div>` : ''} </div>` : ''}
</div> </div>
</div> </div>
</button>` </button>`
} }
document.getElementById('serverSelectListScrollable').innerHTML = htmlString document.getElementById('serverSelectListScrollable').innerHTML = htmlString
} }
function populateAccountListings(){ function populateAccountListings(){
const accountsObj = ConfigManager.getAuthAccounts() const accountsObj = ConfigManager.getAuthAccounts()
const accounts = Array.from(Object.keys(accountsObj), v=>accountsObj[v]) const accounts = Array.from(Object.keys(accountsObj), v=>accountsObj[v])
let htmlString = '' let htmlString = ''
for(let i=0; i<accounts.length; i++){ for(let i=0; i<accounts.length; i++){
htmlString += `<button class="accountListing" uuid="${accounts[i].uuid}" ${i===0 ? 'selected' : ''}> htmlString += `<button class="accountListing" uuid="${accounts[i].uuid}" ${i===0 ? 'selected' : ''}>
<img src="https://crafatar.com/renders/head/${accounts[i].uuid}?scale=2&default=MHF_Steve&overlay"> <img src="https://crafatar.com/renders/head/${accounts[i].uuid}?scale=2&default=MHF_Steve&overlay">
<div class="accountListingName">${accounts[i].displayName}</div> <div class="accountListingName">${accounts[i].displayName}</div>
</button>` </button>`
} }
document.getElementById('accountSelectListScrollable').innerHTML = htmlString document.getElementById('accountSelectListScrollable').innerHTML = htmlString
} }
function prepareServerSelectionList(){ function prepareServerSelectionList(){
populateServerListings() populateServerListings()
setServerListingHandlers() setServerListingHandlers()
} }
function prepareAccountSelectionList(){ function prepareAccountSelectionList(){
populateAccountListings() populateAccountListings()
setAccountListingHandlers() setAccountListingHandlers()
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,419 +1,419 @@
/** /**
* Initialize UI functions which depend on internal modules. * Initialize UI functions which depend on internal modules.
* Loaded after core UI functions are initialized in uicore.js. * Loaded after core UI functions are initialized in uicore.js.
*/ */
// Requirements // Requirements
const path = require('path') const path = require('path')
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 DistroManager = require('./assets/js/distromanager')
const Lang = require('./assets/js/langloader') const Lang = require('./assets/js/langloader')
let rscShouldLoad = false let rscShouldLoad = false
let fatalStartupError = false let fatalStartupError = false
// Mapping of each view to their container IDs. // Mapping of each view to their container IDs.
const VIEWS = { const VIEWS = {
landing: '#landingContainer', landing: '#landingContainer',
login: '#loginContainer', login: '#loginContainer',
settings: '#settingsContainer', settings: '#settingsContainer',
welcome: '#welcomeContainer' welcome: '#welcomeContainer'
} }
// The currently shown view container. // The currently shown view container.
let currentView let currentView
/** /**
* Switch launcher views. * Switch launcher views.
* *
* @param {string} current The ID of the current view container. * @param {string} current The ID of the current view container.
* @param {*} next The ID of the next view container. * @param {*} next The ID of the next view container.
* @param {*} currentFadeTime Optional. The fade out time for the current view. * @param {*} currentFadeTime Optional. The fade out time for the current view.
* @param {*} nextFadeTime Optional. The fade in time for the next view. * @param {*} nextFadeTime Optional. The fade in time for the next view.
* @param {*} onCurrentFade Optional. Callback function to execute when the current * @param {*} onCurrentFade Optional. Callback function to execute when the current
* view fades out. * view fades out.
* @param {*} onNextFade Optional. Callback function to execute when the next view * @param {*} onNextFade Optional. Callback function to execute when the next view
* fades in. * fades in.
*/ */
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, () => {
onCurrentFade() onCurrentFade()
$(`${next}`).fadeIn(nextFadeTime, () => { $(`${next}`).fadeIn(nextFadeTime, () => {
onNextFade() onNextFade()
}) })
}) })
} }
/** /**
* Get the currently shown view container. * Get the currently shown view container.
* *
* @returns {string} The currently shown view container. * @returns {string} The currently shown view container.
*/ */
function getCurrentView(){ function getCurrentView(){
return currentView return currentView
} }
function showMainUI(data){ function showMainUI(data){
if(!isDev){ if(!isDev){
loggerAutoUpdater.log('Initializing..') loggerAutoUpdater.log('Initializing..')
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease()) ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
} }
prepareSettings(true) prepareSettings(true)
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) updateSelectedServer(data.getServer(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)'
document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')` document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')`
$('#main').show() $('#main').show()
const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0 const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0
// If this is enabled in a development environment we'll get ratelimited. // If this is enabled in a development environment we'll get ratelimited.
// The relaunch frequency is usually far too high. // The relaunch frequency is usually far too high.
if(!isDev && isLoggedIn){ if(!isDev && isLoggedIn){
validateSelectedAccount() validateSelectedAccount()
} }
if(ConfigManager.isFirstLaunch()){ if(ConfigManager.isFirstLaunch()){
currentView = VIEWS.welcome currentView = VIEWS.welcome
$(VIEWS.welcome).fadeIn(1000) $(VIEWS.welcome).fadeIn(1000)
} else { } else {
if(isLoggedIn){ if(isLoggedIn){
currentView = VIEWS.landing currentView = VIEWS.landing
$(VIEWS.landing).fadeIn(1000) $(VIEWS.landing).fadeIn(1000)
} else { } else {
currentView = VIEWS.login currentView = VIEWS.login
$(VIEWS.login).fadeIn(1000) $(VIEWS.login).fadeIn(1000)
} }
} }
setTimeout(() => { setTimeout(() => {
$('#loadingContainer').fadeOut(500, () => { $('#loadingContainer').fadeOut(500, () => {
$('#loadSpinnerImage').removeClass('rotating') $('#loadSpinnerImage').removeClass('rotating')
}) })
}, 250) }, 250)
}, 750) }, 750)
// Disable tabbing to the news container. // Disable tabbing to the news container.
initNews().then(() => { initNews().then(() => {
$('#newsContainer *').attr('tabindex', '-1') $('#newsContainer *').attr('tabindex', '-1')
}) })
} }
function showFatalStartupError(){ function showFatalStartupError(){
setTimeout(() => { setTimeout(() => {
$('#loadingContainer').fadeOut(250, () => { $('#loadingContainer').fadeOut(250, () => {
document.getElementById('overlayContainer').style.background = 'none' document.getElementById('overlayContainer').style.background = 'none'
setOverlayContent( setOverlayContent(
'Fatal Error: Unable to Load Distribution Index', 'Fatal Error: Unable to Load Distribution Index',
'A connection could not be established to our servers to download the distribution index. No local copies were available to load. <br><br>The distribution index is an essential file which provides the latest server information. The launcher is unable to start without it. Ensure you are connected to the internet and relaunch the application.', 'A connection could not be established to our servers to download the distribution index. No local copies were available to load. <br><br>The distribution index is an essential file which provides the latest server information. The launcher is unable to start without it. Ensure you are connected to the internet and relaunch the application.',
'Close' 'Close'
) )
setOverlayHandler(() => { setOverlayHandler(() => {
const window = remote.getCurrentWindow() const window = remote.getCurrentWindow()
window.close() window.close()
}) })
toggleOverlay(true) toggleOverlay(true)
}) })
}, 750) }, 750)
} }
/** /**
* Common functions to perform after refreshing the distro index. * Common functions to perform after refreshing the distro index.
* *
* @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.getServer(ConfigManager.getSelectedServer()))
refreshServerStatus() refreshServerStatus()
initNews() initNews()
syncModConfigurations(data) syncModConfigurations(data)
} }
/** /**
* Sync the mod configurations with the distro index. * Sync the mod configurations with the distro index.
* *
* @param {Object} data The distro index object. * @param {Object} data The distro index object.
*/ */
function syncModConfigurations(data){ function syncModConfigurations(data){
const syncedCfgs = [] const syncedCfgs = []
for(let serv of data.getServers()){ for(let serv of data.getServers()){
const id = serv.getID() const id = serv.getID()
const mdls = serv.getModules() const mdls = serv.getModules()
const cfg = ConfigManager.getModConfiguration(id) const cfg = ConfigManager.getModConfiguration(id)
if(cfg != null){ if(cfg != null){
const modsOld = cfg.mods const modsOld = cfg.mods
const mods = {} const mods = {}
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.getType()
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
if(!mdl.getRequired().isRequired()){ if(!mdl.getRequired().isRequired()){
const mdlID = mdl.getVersionlessID() const mdlID = mdl.getVersionlessID()
if(modsOld[mdlID] == null){ if(modsOld[mdlID] == null){
mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl) mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl)
} else { } else {
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false) mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false)
} }
} else { } else {
if(mdl.hasSubModules()){ if(mdl.hasSubModules()){
const mdlID = mdl.getVersionlessID() const mdlID = mdl.getVersionlessID()
const v = scanOptionalSubModules(mdl.getSubModules(), mdl) const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
if(typeof v === 'object'){ if(typeof v === 'object'){
if(modsOld[mdlID] == null){ if(modsOld[mdlID] == null){
mods[mdlID] = v mods[mdlID] = v
} else { } else {
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true) mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true)
} }
} }
} }
} }
} }
} }
syncedCfgs.push({ syncedCfgs.push({
id, id,
mods mods
}) })
} else { } else {
const mods = {} const mods = {}
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.getType()
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
if(!mdl.getRequired().isRequired()){ if(!mdl.getRequired().isRequired()){
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
} else { } else {
if(mdl.hasSubModules()){ if(mdl.hasSubModules()){
const v = scanOptionalSubModules(mdl.getSubModules(), mdl) const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
if(typeof v === 'object'){ if(typeof v === 'object'){
mods[mdl.getVersionlessID()] = v mods[mdl.getVersionlessID()] = v
} }
} }
} }
} }
} }
syncedCfgs.push({ syncedCfgs.push({
id, id,
mods mods
}) })
} }
} }
ConfigManager.setModConfigurations(syncedCfgs) ConfigManager.setModConfigurations(syncedCfgs)
ConfigManager.save() ConfigManager.save()
} }
/** /**
* Recursively scan for optional sub modules. If none are found, * Recursively scan for optional sub modules. If none are found,
* this function returns a boolean. If optional sub modules do exist, * this function returns a boolean. If optional sub modules do exist,
* a recursive configuration object is returned. * a recursive configuration object is returned.
* *
* @returns {boolean | Object} The resolved mod configuration. * @returns {boolean | Object} The resolved mod configuration.
*/ */
function scanOptionalSubModules(mdls, origin){ function scanOptionalSubModules(mdls, origin){
if(mdls != null){ if(mdls != null){
const mods = {} const mods = {}
for(let mdl of mdls){ for(let mdl of mdls){
const type = mdl.getType() const type = mdl.getType()
// Optional types. // Optional types.
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
// It is optional. // It is optional.
if(!mdl.getRequired().isRequired()){ if(!mdl.getRequired().isRequired()){
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
} else { } else {
if(mdl.hasSubModules()){ if(mdl.hasSubModules()){
const v = scanOptionalSubModules(mdl.getSubModules(), mdl) const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
if(typeof v === 'object'){ if(typeof v === 'object'){
mods[mdl.getVersionlessID()] = v mods[mdl.getVersionlessID()] = v
} }
} }
} }
} }
} }
if(Object.keys(mods).length > 0){ if(Object.keys(mods).length > 0){
const ret = { const ret = {
mods mods
} }
if(!origin.getRequired().isRequired()){ if(!origin.getRequired().isRequired()){
ret.value = origin.getRequired().isDefault() ret.value = origin.getRequired().isDefault()
} }
return ret return ret
} }
} }
return origin.getRequired().isDefault() return origin.getRequired().isDefault()
} }
/** /**
* Recursively merge an old configuration into a new configuration. * Recursively merge an old configuration into a new configuration.
* *
* @param {boolean | Object} o The old configuration value. * @param {boolean | Object} o The old configuration value.
* @param {boolean | Object} n The new configuration value. * @param {boolean | Object} n The new configuration value.
* @param {boolean} nReq If the new value is a required mod. * @param {boolean} nReq If the new value is a required mod.
* *
* @returns {boolean | Object} The merged configuration. * @returns {boolean | Object} The merged configuration.
*/ */
function mergeModConfiguration(o, n, nReq = false){ function mergeModConfiguration(o, n, nReq = false){
if(typeof o === 'boolean'){ if(typeof o === 'boolean'){
if(typeof n === 'boolean') return o if(typeof n === 'boolean') return o
else if(typeof n === 'object'){ else if(typeof n === 'object'){
if(!nReq){ if(!nReq){
n.value = o n.value = o
} }
return n return n
} }
} else if(typeof o === 'object'){ } else if(typeof o === 'object'){
if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true
else if(typeof n === 'object'){ else if(typeof n === 'object'){
if(!nReq){ if(!nReq){
n.value = typeof o.value !== 'undefined' ? o.value : true n.value = typeof o.value !== 'undefined' ? o.value : true
} }
const newMods = Object.keys(n.mods) const newMods = Object.keys(n.mods)
for(let i=0; i<newMods.length; i++){ for(let i=0; i<newMods.length; i++){
const mod = newMods[i] const mod = newMods[i]
if(o.mods[mod] != null){ if(o.mods[mod] != null){
n.mods[mod] = mergeModConfiguration(o.mods[mod], n.mods[mod]) n.mods[mod] = mergeModConfiguration(o.mods[mod], n.mods[mod])
} }
} }
return n return n
} }
} }
// If for some reason we haven't been able to merge, // If for some reason we haven't been able to merge,
// wipe the old value and use the new one. Just to be safe // wipe the old value and use the new one. Just to be safe
return n return n
} }
function refreshDistributionIndex(remote, onSuccess, onError){ function refreshDistributionIndex(remote, onSuccess, onError){
if(remote){ if(remote){
DistroManager.pullRemote() DistroManager.pullRemote()
.then(onSuccess) .then(onSuccess)
.catch(onError) .catch(onError)
} else { } else {
DistroManager.pullLocal() DistroManager.pullLocal()
.then(onSuccess) .then(onSuccess)
.catch(onError) .catch(onError)
} }
} }
async function validateSelectedAccount(){ async function validateSelectedAccount(){
const selectedAcc = ConfigManager.getSelectedAccount() const selectedAcc = ConfigManager.getSelectedAccount()
if(selectedAcc != null){ if(selectedAcc != null){
const val = await AuthManager.validateSelected() const val = await AuthManager.validateSelected()
if(!val){ if(!val){
ConfigManager.removeAuthAccount(selectedAcc.uuid) ConfigManager.removeAuthAccount(selectedAcc.uuid)
ConfigManager.save() ConfigManager.save()
const accLen = Object.keys(ConfigManager.getAuthAccounts()).length const accLen = Object.keys(ConfigManager.getAuthAccounts()).length
setOverlayContent( setOverlayContent(
'Failed to Refresh Login', 'Failed to Refresh Login',
`We were unable to refresh the login for <strong>${selectedAcc.displayName}</strong>. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`, `We were unable to refresh the login for <strong>${selectedAcc.displayName}</strong>. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`,
'Login', 'Login',
'Select Another Account' 'Select Another Account'
) )
setOverlayHandler(() => { setOverlayHandler(() => {
document.getElementById('loginUsername').value = selectedAcc.username document.getElementById('loginUsername').value = selectedAcc.username
validateEmail(selectedAcc.username) validateEmail(selectedAcc.username)
loginViewOnSuccess = getCurrentView() loginViewOnSuccess = getCurrentView()
loginViewOnCancel = getCurrentView() loginViewOnCancel = getCurrentView()
if(accLen > 0){ if(accLen > 0){
loginViewCancelHandler = () => { loginViewCancelHandler = () => {
ConfigManager.addAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName) ConfigManager.addAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
ConfigManager.save() ConfigManager.save()
validateSelectedAccount() validateSelectedAccount()
} }
loginCancelEnabled(true) loginCancelEnabled(true)
} }
toggleOverlay(false) toggleOverlay(false)
switchView(getCurrentView(), VIEWS.login) switchView(getCurrentView(), VIEWS.login)
}) })
setDismissHandler(() => { setDismissHandler(() => {
if(accLen > 1){ if(accLen > 1){
prepareAccountSelectionList() prepareAccountSelectionList()
$('#overlayContent').fadeOut(250, () => { $('#overlayContent').fadeOut(250, () => {
bindOverlayKeys(true, 'accountSelectContent', true) bindOverlayKeys(true, 'accountSelectContent', true)
$('#accountSelectContent').fadeIn(250) $('#accountSelectContent').fadeIn(250)
}) })
} else { } else {
const accountsObj = ConfigManager.getAuthAccounts() const accountsObj = ConfigManager.getAuthAccounts()
const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v]) const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v])
// This function validates the account switch. // This function validates the account switch.
setSelectedAccount(accounts[0].uuid) setSelectedAccount(accounts[0].uuid)
toggleOverlay(false) toggleOverlay(false)
} }
}) })
toggleOverlay(true, accLen > 0) toggleOverlay(true, accLen > 0)
} else { } else {
return true return true
} }
} else { } else {
return true return true
} }
} }
/** /**
* Temporary function to update the selected account along * Temporary function to update the selected account along
* with the relevent UI elements. * with the relevent UI elements.
* *
* @param {string} uuid The UUID of the account. * @param {string} uuid The UUID of the account.
*/ */
function setSelectedAccount(uuid){ function setSelectedAccount(uuid){
const authAcc = ConfigManager.setSelectedAccount(uuid) const authAcc = ConfigManager.setSelectedAccount(uuid)
ConfigManager.save() ConfigManager.save()
updateSelectedAccount(authAcc) updateSelectedAccount(authAcc)
validateSelectedAccount() validateSelectedAccount()
} }
// Synchronous Listener // Synchronous Listener
document.addEventListener('readystatechange', function(){ document.addEventListener('readystatechange', function(){
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 = DistroManager.getDistribution()
showMainUI(data) showMainUI(data)
} else { } else {
showFatalStartupError() showFatalStartupError()
} }
} }
} }
}, 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', (event, res) => {
if(res) { if(res) {
const data = DistroManager.getDistribution() const data = DistroManager.getDistribution()
syncModConfigurations(data) syncModConfigurations(data)
if(document.readyState === 'interactive' || document.readyState === 'complete'){ if(document.readyState === 'interactive' || document.readyState === 'complete'){
showMainUI(data) showMainUI(data)
} else { } else {
rscShouldLoad = true rscShouldLoad = true
} }
} else { } else {
fatalStartupError = true fatalStartupError = true
if(document.readyState === 'interactive' || document.readyState === 'complete'){ if(document.readyState === 'interactive' || document.readyState === 'complete'){
showFatalStartupError() showFatalStartupError()
} else { } else {
rscShouldLoad = true rscShouldLoad = true
} }
} }
}) })

View File

@ -1,213 +1,213 @@
/** /**
* Core UI functions are initialized in this file. This prevents * Core UI functions are initialized in this file. This prevents
* unexpected errors from breaking the core features. Specifically, * unexpected errors from breaking the core features. Specifically,
* actions in this file should not require the usage of any internal * actions in this file should not require the usage of any internal
* modules, excluding dependencies. * modules, excluding dependencies.
*/ */
// Requirements // Requirements
const $ = require('jquery') const $ = require('jquery')
const {ipcRenderer, remote, shell, webFrame} = require('electron') const {ipcRenderer, remote, shell, webFrame} = require('electron')
const isDev = require('./assets/js/isdev') const isDev = require('./assets/js/isdev')
const LoggerUtil = require('./assets/js/loggerutil') const LoggerUtil = require('./assets/js/loggerutil')
const loggerUICore = LoggerUtil('%c[UICore]', 'color: #000668; font-weight: bold') const loggerUICore = LoggerUtil('%c[UICore]', 'color: #000668; font-weight: bold')
const loggerAutoUpdater = LoggerUtil('%c[AutoUpdater]', 'color: #000668; font-weight: bold') const loggerAutoUpdater = LoggerUtil('%c[AutoUpdater]', 'color: #000668; font-weight: bold')
const loggerAutoUpdaterSuccess = LoggerUtil('%c[AutoUpdater]', 'color: #209b07; font-weight: bold') const loggerAutoUpdaterSuccess = LoggerUtil('%c[AutoUpdater]', 'color: #209b07; font-weight: bold')
// Log deprecation and process warnings. // Log deprecation and process warnings.
process.traceProcessWarnings = true process.traceProcessWarnings = true
process.traceDeprecation = true process.traceDeprecation = true
// Disable eval function. // Disable eval function.
// eslint-disable-next-line // eslint-disable-next-line
window.eval = global.eval = function () { window.eval = global.eval = function () {
throw new Error('Sorry, this app does not support window.eval().') throw new Error('Sorry, this app does not support window.eval().')
} }
// Display warning when devtools window is opened. // Display warning when devtools window is opened.
remote.getCurrentWebContents().on('devtools-opened', () => { remote.getCurrentWebContents().on('devtools-opened', () => {
console.log('%cThe console is dark and full of terrors.', 'color: white; -webkit-text-stroke: 4px #a02d2a; font-size: 60px; font-weight: bold') console.log('%cThe console is dark and full of terrors.', 'color: white; -webkit-text-stroke: 4px #a02d2a; font-size: 60px; font-weight: bold')
console.log('%cIf you\'ve been told to paste something here, you\'re being scammed.', 'font-size: 16px') console.log('%cIf you\'ve been told to paste something here, you\'re being scammed.', 'font-size: 16px')
console.log('%cUnless you know exactly what you\'re doing, close this window.', 'font-size: 16px') console.log('%cUnless you know exactly what you\'re doing, close this window.', 'font-size: 16px')
}) })
// Disable zoom, needed for darwin. // Disable zoom, needed for darwin.
webFrame.setZoomLevel(0) webFrame.setZoomLevel(0)
webFrame.setVisualZoomLevelLimits(1, 1) webFrame.setVisualZoomLevelLimits(1, 1)
// Initialize auto updates in production environments. // Initialize auto updates in production environments.
let updateCheckListener let updateCheckListener
if(!isDev){ if(!isDev){
ipcRenderer.on('autoUpdateNotification', (event, arg, info) => { ipcRenderer.on('autoUpdateNotification', (event, arg, info) => {
switch(arg){ switch(arg){
case 'checking-for-update': case 'checking-for-update':
loggerAutoUpdater.log('Checking for update..') loggerAutoUpdater.log('Checking for update..')
settingsUpdateButtonStatus('Checking for Updates..', true) settingsUpdateButtonStatus('Checking for Updates..', true)
break break
case 'update-available': case 'update-available':
loggerAutoUpdaterSuccess.log('New update available', info.version) loggerAutoUpdaterSuccess.log('New update available', info.version)
if(process.platform === 'darwin'){ 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}.dmg`
showUpdateUI(info) showUpdateUI(info)
} }
populateSettingsUpdateInformation(info) populateSettingsUpdateInformation(info)
break break
case 'update-downloaded': case 'update-downloaded':
loggerAutoUpdaterSuccess.log('Update ' + info.version + ' ready to be installed.') loggerAutoUpdaterSuccess.log('Update ' + info.version + ' ready to be installed.')
settingsUpdateButtonStatus('Install Now', false, () => { settingsUpdateButtonStatus('Install Now', false, () => {
if(!isDev){ if(!isDev){
ipcRenderer.send('autoUpdateAction', 'installUpdateNow') ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
} }
}) })
showUpdateUI(info) showUpdateUI(info)
break break
case 'update-not-available': case 'update-not-available':
loggerAutoUpdater.log('No new update found.') loggerAutoUpdater.log('No new update found.')
settingsUpdateButtonStatus('Check for Updates') settingsUpdateButtonStatus('Check for Updates')
break break
case 'ready': case 'ready':
updateCheckListener = setInterval(() => { updateCheckListener = setInterval(() => {
ipcRenderer.send('autoUpdateAction', 'checkForUpdate') ipcRenderer.send('autoUpdateAction', 'checkForUpdate')
}, 1800000) }, 1800000)
ipcRenderer.send('autoUpdateAction', 'checkForUpdate') ipcRenderer.send('autoUpdateAction', 'checkForUpdate')
break break
case 'realerror': case 'realerror':
if(info != null && info.code != null){ if(info != null && info.code != null){
if(info.code === 'ERR_UPDATER_INVALID_RELEASE_FEED'){ if(info.code === 'ERR_UPDATER_INVALID_RELEASE_FEED'){
loggerAutoUpdater.log('No suitable releases found.') loggerAutoUpdater.log('No suitable releases found.')
} else if(info.code === 'ERR_XML_MISSED_ELEMENT'){ } else if(info.code === 'ERR_XML_MISSED_ELEMENT'){
loggerAutoUpdater.log('No releases found.') loggerAutoUpdater.log('No releases found.')
} else { } else {
loggerAutoUpdater.error('Error during update check..', info) loggerAutoUpdater.error('Error during update check..', info)
loggerAutoUpdater.debug('Error Code:', info.code) loggerAutoUpdater.debug('Error Code:', info.code)
} }
} }
break break
default: default:
loggerAutoUpdater.log('Unknown argument', arg) loggerAutoUpdater.log('Unknown argument', arg)
break break
} }
}) })
} }
/** /**
* Send a notification to the main process changing the value of * Send a notification to the main process changing the value of
* allowPrerelease. If we are running a prerelease version, then * allowPrerelease. If we are running a prerelease version, then
* this will always be set to true, regardless of the current value * this will always be set to true, regardless of the current value
* of val. * of val.
* *
* @param {boolean} val The new allow prerelease value. * @param {boolean} val The new allow prerelease value.
*/ */
function changeAllowPrerelease(val){ function changeAllowPrerelease(val){
ipcRenderer.send('autoUpdateAction', 'allowPrereleaseChange', val) ipcRenderer.send('autoUpdateAction', 'allowPrereleaseChange', val)
} }
function showUpdateUI(info){ function showUpdateUI(info){
//TODO Make this message a bit more informative `${info.version}` //TODO Make this message a bit more informative `${info.version}`
document.getElementById('image_seal_container').setAttribute('update', true) document.getElementById('image_seal_container').setAttribute('update', true)
document.getElementById('image_seal_container').onclick = () => { document.getElementById('image_seal_container').onclick = () => {
/*setOverlayContent('Update Available', 'A new update for the launcher is available. Would you like to install now?', 'Install', 'Later') /*setOverlayContent('Update Available', 'A new update for the launcher is available. Would you like to install now?', 'Install', 'Later')
setOverlayHandler(() => { setOverlayHandler(() => {
if(!isDev){ if(!isDev){
ipcRenderer.send('autoUpdateAction', 'installUpdateNow') ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
} else { } else {
console.error('Cannot install updates in development environment.') console.error('Cannot install updates in development environment.')
toggleOverlay(false) toggleOverlay(false)
} }
}) })
setDismissHandler(() => { setDismissHandler(() => {
toggleOverlay(false) toggleOverlay(false)
}) })
toggleOverlay(true, true)*/ toggleOverlay(true, true)*/
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => { switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
settingsNavItemListener(document.getElementById('settingsNavUpdate'), false) settingsNavItemListener(document.getElementById('settingsNavUpdate'), false)
}) })
} }
} }
/* jQuery Example /* jQuery Example
$(function(){ $(function(){
loggerUICore.log('UICore Initialized'); loggerUICore.log('UICore Initialized');
})*/ })*/
document.addEventListener('readystatechange', function () { document.addEventListener('readystatechange', function () {
if (document.readyState === 'interactive'){ if (document.readyState === 'interactive'){
loggerUICore.log('UICore Initializing..') loggerUICore.log('UICore Initializing..')
// Bind close button. // Bind close button.
Array.from(document.getElementsByClassName('fCb')).map((val) => { Array.from(document.getElementsByClassName('fCb')).map((val) => {
val.addEventListener('click', e => { val.addEventListener('click', e => {
const window = remote.getCurrentWindow() const window = remote.getCurrentWindow()
window.close() window.close()
}) })
}) })
// Bind restore down button. // Bind restore down button.
Array.from(document.getElementsByClassName('fRb')).map((val) => { Array.from(document.getElementsByClassName('fRb')).map((val) => {
val.addEventListener('click', e => { val.addEventListener('click', e => {
const window = remote.getCurrentWindow() const window = remote.getCurrentWindow()
if(window.isMaximized()){ if(window.isMaximized()){
window.unmaximize() window.unmaximize()
} else { } else {
window.maximize() window.maximize()
} }
document.activeElement.blur() document.activeElement.blur()
}) })
}) })
// Bind minimize button. // Bind minimize button.
Array.from(document.getElementsByClassName('fMb')).map((val) => { Array.from(document.getElementsByClassName('fMb')).map((val) => {
val.addEventListener('click', e => { val.addEventListener('click', e => {
const window = remote.getCurrentWindow() const window = remote.getCurrentWindow()
window.minimize() window.minimize()
document.activeElement.blur() document.activeElement.blur()
}) })
}) })
// Remove focus from social media buttons once they're clicked. // Remove focus from social media buttons once they're clicked.
Array.from(document.getElementsByClassName('mediaURL')).map(val => { Array.from(document.getElementsByClassName('mediaURL')).map(val => {
val.addEventListener('click', e => { val.addEventListener('click', e => {
document.activeElement.blur() document.activeElement.blur()
}) })
}) })
} else if(document.readyState === 'complete'){ } else if(document.readyState === 'complete'){
//266.01 //266.01
//170.8 //170.8
//53.21 //53.21
// Bind progress bar length to length of bot wrapper // Bind progress bar length to length of bot wrapper
//const targetWidth = document.getElementById("launch_content").getBoundingClientRect().width //const targetWidth = document.getElementById("launch_content").getBoundingClientRect().width
//const targetWidth2 = document.getElementById("server_selection").getBoundingClientRect().width //const targetWidth2 = document.getElementById("server_selection").getBoundingClientRect().width
//const targetWidth3 = document.getElementById("launch_button").getBoundingClientRect().width //const targetWidth3 = document.getElementById("launch_button").getBoundingClientRect().width
document.getElementById('launch_details').style.maxWidth = 266.01 document.getElementById('launch_details').style.maxWidth = 266.01
document.getElementById('launch_progress').style.width = 170.8 document.getElementById('launch_progress').style.width = 170.8
document.getElementById('launch_details_right').style.maxWidth = 170.8 document.getElementById('launch_details_right').style.maxWidth = 170.8
document.getElementById('launch_progress_label').style.width = 53.21 document.getElementById('launch_progress_label').style.width = 53.21
} }
}, false) }, false)
/** /**
* Open web links in the user's default browser. * Open web links in the user's default browser.
*/ */
$(document).on('click', 'a[href^="http"]', function(event) { $(document).on('click', 'a[href^="http"]', function(event) {
event.preventDefault() event.preventDefault()
shell.openExternal(this.href) shell.openExternal(this.href)
}) })
/** /**
* Opens DevTools window if you hold (ctrl + shift + i). * Opens DevTools window if you hold (ctrl + shift + i).
* This will crash the program if you are using multiple * This will crash the program if you are using multiple
* DevTools, for example the chrome debugger in VS Code. * DevTools, for example the chrome debugger in VS Code.
*/ */
document.addEventListener('keydown', function (e) { document.addEventListener('keydown', function (e) {
if((e.key === 'I' || e.key === 'i') && e.ctrlKey && e.shiftKey){ if((e.key === 'I' || e.key === 'i') && e.ctrlKey && e.shiftKey){
let window = remote.getCurrentWindow() let window = remote.getCurrentWindow()
window.toggleDevTools() window.toggleDevTools()
} }
}) })

View File

@ -1,6 +1,6 @@
/** /**
* Script for welcome.ejs * Script for welcome.ejs
*/ */
document.getElementById('welcomeButton').addEventListener('click', e => { document.getElementById('welcomeButton').addEventListener('click', e => {
switchView(VIEWS.welcome, VIEWS.login) switchView(VIEWS.welcome, VIEWS.login)
}) })

View File

@ -1,65 +1,65 @@
const net = require('net') const net = require('net')
/** /**
* Retrieves the status of a minecraft server. * Retrieves the status of a minecraft server.
* *
* @param {string} address The server address. * @param {string} address The server address.
* @param {number} port Optional. The port of the server. Defaults to 25565. * @param {number} port Optional. The port of the server. Defaults to 25565.
* @returns {Promise.<Object>} A promise which resolves to an object containing * @returns {Promise.<Object>} A promise which resolves to an object containing
* status information. * status information.
*/ */
exports.getStatus = function(address, port = 25565){ exports.getStatus = function(address, port = 25565){
if(port == null || port == ''){ if(port == null || port == ''){
port = 25565 port = 25565
} }
if(typeof port === 'string'){ if(typeof port === 'string'){
port = parseInt(port) port = parseInt(port)
} }
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const socket = net.connect(port, address, () => { const socket = net.connect(port, address, () => {
let buff = Buffer.from([0xFE, 0x01]) let buff = Buffer.from([0xFE, 0x01])
socket.write(buff) socket.write(buff)
}) })
socket.setTimeout(2500, () => { socket.setTimeout(2500, () => {
socket.end() socket.end()
reject({ reject({
code: 'ETIMEDOUT', code: 'ETIMEDOUT',
errno: 'ETIMEDOUT', errno: 'ETIMEDOUT',
address, address,
port port
}) })
}) })
socket.on('data', (data) => { socket.on('data', (data) => {
if(data != null && data != ''){ if(data != null && data != ''){
let server_info = data.toString().split('\x00\x00\x00') let server_info = data.toString().split('\x00\x00\x00')
const NUM_FIELDS = 6 const NUM_FIELDS = 6
if(server_info != null && server_info.length >= NUM_FIELDS){ if(server_info != null && server_info.length >= NUM_FIELDS){
resolve({ resolve({
online: true, online: true,
version: server_info[2].replace(/\u0000/g, ''), version: server_info[2].replace(/\u0000/g, ''),
motd: server_info[3].replace(/\u0000/g, ''), motd: server_info[3].replace(/\u0000/g, ''),
onlinePlayers: server_info[4].replace(/\u0000/g, ''), onlinePlayers: server_info[4].replace(/\u0000/g, ''),
maxPlayers: server_info[5].replace(/\u0000/g,'') maxPlayers: server_info[5].replace(/\u0000/g,'')
}) })
} else { } else {
resolve({ resolve({
online: false online: false
}) })
} }
} }
socket.end() socket.end()
}) })
socket.on('error', (err) => { socket.on('error', (err) => {
socket.destroy() socket.destroy()
reject(err) reject(err)
// ENOTFOUND = Unable to resolve. // ENOTFOUND = Unable to resolve.
// ECONNREFUSED = Unable to connect to port. // ECONNREFUSED = Unable to connect to port.
}) })
}) })
} }

View File

@ -1,49 +1,49 @@
{ {
"html": { "html": {
"avatarOverlay": "Edit" "avatarOverlay": "Modifer"
}, },
"js": { "js": {
"login": { "login": {
"error": { "error": {
"invalidValue": "* Invalid Value", "invalidValue": "* Invalid Value",
"requiredValue": "* Required", "requiredValue": "* Required",
"userMigrated": { "userMigrated": {
"title": "Error During Login:<br>Invalid Credentials", "title": "Error During Login:<br>Invalid Credentials",
"desc": "You've attempted to login with a migrated account. Try again using the account email as the username." "desc": "You've attempted to login with a migrated account. Try again using the account email as the username."
}, },
"invalidCredentials": { "invalidCredentials": {
"title": "Error During Login:<br>Invalid Credentials", "title": "Error During Login:<br>Invalid Credentials",
"desc": "The email or password you've entered is incorrect. Please try again." "desc": "The email or password you've entered is incorrect. Please try again."
}, },
"rateLimit": { "rateLimit": {
"title": "Error During Login:<br>Too Many Attempts", "title": "Error During Login:<br>Too Many Attempts",
"desc": "There have been too many login attempts with this account recently. Please try again later." "desc": "There have been too many login attempts with this account recently. Please try again later."
}, },
"noInternet": { "noInternet": {
"title": "Error During Login:<br>No Internet Connection", "title": "Error During Login:<br>No Internet Connection",
"desc": "You must be connected to the internet in order to login. Please connect and try again." "desc": "You must be connected to the internet in order to login. Please connect and try again."
}, },
"authDown": { "authDown": {
"title": "Error During Login:<br>Authentication Server Offline", "title": "Error During Login:<br>Authentication Server Offline",
"desc": "Mojang's authentication server is currently offline or unreachable. Please wait a bit and try again. You can check the status of the server on <a href=\"https://help.mojang.com/\">Mojang's help portal</a>." "desc": "Mojang's authentication server is currently offline or unreachable. Please wait a bit and try again. You can check the status of the server on <a href=\"https://help.mojang.com/\">Mojang's help portal</a>."
}, },
"notPaid": { "notPaid": {
"title": "Error During Login:<br>Game Not Purchased", "title": "Error During Login:<br>Game Not Purchased",
"desc": "The account you are trying to login with has not purchased a copy of Minecraft.<br>You may purchase a copy on <a href=\"https://minecraft.net/\">Minecraft.net</a>" "desc": "The account you are trying to login with has not purchased a copy of Minecraft.<br>You may purchase a copy on <a href=\"https://minecraft.net/\">Minecraft.net</a>"
}, },
"unknown": { "unknown": {
"title": "Error During Login:<br>Unknown Error" "title": "Error During Login:<br>Unknown Error"
} }
}, },
"login": "LOGIN", "login": "LOGIN",
"loggingIn": "LOGGING IN", "loggingIn": "LOGGING IN",
"success": "SUCCESS", "success": "SUCCESS",
"tryAgain": "Try Again" "tryAgain": "Try Again"
}, },
"landing": { "landing": {
"launch": { "launch": {
"pleaseWait": "Please wait.." "pleaseWait": "Please wait.."
} }
} }
} }
} }

View File

@ -1,33 +1,33 @@
<div id="frameBar"> <div id="frameBar">
<div id="frameResizableTop" class="frameDragPadder"></div> <div id="frameResizableTop" class="frameDragPadder"></div>
<div id="frameMain"> <div id="frameMain">
<div class="frameResizableVert frameDragPadder"></div> <div class="frameResizableVert frameDragPadder"></div>
<%if (process.platform === 'darwin') { %> <%if (process.platform === 'darwin') { %>
<div id="frameContentDarwin"> <div id="frameContentDarwin">
<div id="frameButtonDockDarwin"> <div id="frameButtonDockDarwin">
<button class="frameButtonDarwin fCb" id="frameButtonDarwin_close" tabIndex="-1"></button> <button class="frameButtonDarwin fCb" id="frameButtonDarwin_close" tabIndex="-1"></button>
<button class="frameButtonDarwin fMb" id="frameButtonDarwin_minimize" tabIndex="-1"></button> <button class="frameButtonDarwin fMb" id="frameButtonDarwin_minimize" tabIndex="-1"></button>
<button class="frameButtonDarwin fRb" id="frameButtonDarwin_restoredown" tabIndex="-1"></button> <button class="frameButtonDarwin fRb" id="frameButtonDarwin_restoredown" tabIndex="-1"></button>
</div> </div>
</div> </div>
<% } else{ %> <% } else{ %>
<div id="frameContentWin"> <div id="frameContentWin">
<div id="frameTitleDock"> <div id="frameTitleDock">
<span id="frameTitleText">Helios Launcher</span> <span id="frameTitleText">Launcher Creeponnia</span>
</div> </div>
<div id="frameButtonDockWin"> <div id="frameButtonDockWin">
<button class="frameButton fMb" id="frameButton_minimize" tabIndex="-1"> <button class="frameButton fMb" id="frameButton_minimize" tabIndex="-1">
<svg name="TitleBarMinimize" width="10" height="10" viewBox="0 0 12 12"><rect stroke="#ffffff" fill="#ffffff" width="10" height="1" x="1" y="6"></rect></svg> <svg name="TitleBarMinimize" width="10" height="10" viewBox="0 0 12 12"><rect stroke="#ffffff" fill="#ffffff" width="10" height="1" x="1" y="6"></rect></svg>
</button> </button>
<button class="frameButton fRb" id="frameButton_restoredown" tabIndex="-1"> <button class="frameButton fRb" id="frameButton_restoredown" tabIndex="-1">
<svg name="TitleBarMaximize" width="10" height="10" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="#ffffff" stroke-width="1.4px"></rect></svg> <svg name="TitleBarMaximize" width="10" height="10" viewBox="0 0 12 12"><rect width="9" height="9" x="1.5" y="1.5" fill="none" stroke="#ffffff" stroke-width="1.4px"></rect></svg>
</button> </button>
<button class="frameButton fCb" id="frameButton_close" tabIndex="-1"> <button class="frameButton fCb" id="frameButton_close" tabIndex="-1">
<svg name="TitleBarClose" width="10" height="10" viewBox="0 0 12 12"><polygon stroke="#ffffff" fill="#ffffff" fill-rule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"></polygon></svg> <svg name="TitleBarClose" width="10" height="10" viewBox="0 0 12 12"><polygon stroke="#ffffff" fill="#ffffff" fill-rule="evenodd" points="11 1.576 6.583 6 11 10.424 10.424 11 6 6.583 1.576 11 1 10.424 5.417 6 1 1.576 1.576 1 6 5.417 10.424 1"></polygon></svg>
</button> </button>
</div> </div>
</div> </div>
<% } %> <% } %>
<div class="frameResizableVert frameDragPadder"></div> <div class="frameResizableVert frameDragPadder"></div>
</div> </div>
</div> </div>

View File

@ -1,220 +1,220 @@
<div id="landingContainer" style="display: none;"> <div id="landingContainer" style="display: none;">
<div id="upper"> <div id="upper">
<div id="left"> <div id="left">
<div id="image_seal_container"> <div id="image_seal_container">
<img id="image_seal" src="assets/images/SealCircle.png"/> <img id="image_seal" src="assets/images/SealCircle.png"/>
<div id="updateAvailableTooltip">Update Available</div> <div id="updateAvailableTooltip">Mise à jour disponnible !</div>
</div> </div>
</div> </div>
<div id="content"> <div id="content">
</div> </div>
<div id="right"> <div id="right">
<div id="rightContainer"> <div id="rightContainer">
<div id="user_content"> <div id="user_content">
<span id="user_text">Username</span> <span id="user_text">Pseudo</span>
<div id="avatarContainer"> <div id="avatarContainer">
<button id="avatarOverlay">Edit</button> <button id="avatarOverlay">Modifier</button>
</div> </div>
</div> </div>
<div id="mediaContent"> <div id="mediaContent">
<div id="internalMedia"> <div id="internalMedia">
<div class="mediaContainer" id="settingsMediaContainer"> <div class="mediaContainer" id="settingsMediaContainer">
<button class="mediaButton" id="settingsMediaButton"> <button class="mediaButton" id="settingsMediaButton">
<svg id="settingsSVG" class="mediaSVG" viewBox="0 0 141.36 137.43"> <svg id="settingsSVG" class="mediaSVG" viewBox="0 0 141.36 137.43">
<path d="M70.70475616319865,83.36934004916053 a15.320781354859122,15.320781354859122 0 1 1 14.454501310561755,-15.296030496450625 A14.850515045097694,14.850515045097694 0 0 1 70.70475616319865,83.36934004916053 M123.25082856443602,55.425620905968366 h-12.375429204248078 A45.54157947163293,45.54157947163293 0 0 0 107.21227231573047,46.243052436416285 l8.613298726156664,-9.108315894326587 a9.727087354538993,9.727087354538993 0 0 0 0,-13.167456673319956 l-3.465120177189462,-3.6631270444574313 a8.489544434114185,8.489544434114185 0 0 0 -12.375429204248078,0 l-8.613298726156664,9.108315894326587 A40.442902639482725,40.442902639482725 0 0 0 81.99114759747292,25.427580514871032 V12.532383284044531 a9.108315894326587,9.108315894326587 0 0 0 -8.811305593424633,-9.306322761594556 h-4.950171681699231 a9.108315894326587,9.108315894326587 0 0 0 -8.811305593424633,9.306322761594556 v12.895197230826497 a40.17064319698927,40.17064319698927 0 0 0 -9.331073620003052,4.0591407789933704 l-8.613298726156664,-9.108315894326587 a8.489544434114185,8.489544434114185 0 0 0 -12.375429204248078,0 L25.58394128451018,23.967279868769744 a9.727087354538993,9.727087354538993 0 0 0 0,13.167456673319956 L34.19724001066683,46.243052436416285 a45.07131316187151,45.07131316187151 0 0 0 -3.6631270444574313,9.083565035918088 h-12.375429204248078 a9.083565035918088,9.083565035918088 0 0 0 -8.811305593424633,9.306322761594556 v5.197680265784193 a9.108315894326587,9.108315894326587 0 0 0 8.811305593424633,9.306322761594556 h11.979415469712139 a45.69008462208391,45.69008462208391 0 0 0 4.0591407789933704,10.642869115653347 l-8.613298726156664,9.108315894326587 a9.727087354538993,9.727087354538993 0 0 0 0,13.167456673319956 l3.465120177189462,3.6631270444574313 a8.489544434114185,8.489544434114185 0 0 0 12.375429204248078,0 l8.613298726156664,-9.108315894326587 a40.49240435629971,40.49240435629971 0 0 0 9.331073620003052,4.0591407789933704 v12.895197230826497 a9.083565035918088,9.083565035918088 0 0 0 8.811305593424633,9.306322761594556 h4.950171681699231 A9.083565035918088,9.083565035918088 0 0 0 81.99114759747292,123.68848839660077 V110.79329116577425 a40.78941465720167,40.78941465720167 0 0 0 9.331073620003052,-4.0591407789933704 l8.613298726156664,9.108315894326587 a8.489544434114185,8.489544434114185 0 0 0 12.375429204248078,0 l3.465120177189462,-3.6631270444574313 a9.727087354538993,9.727087354538993 0 0 0 0,-13.167456673319956 l-8.613298726156664,-9.108315894326587 a45.665333763675406,45.665333763675406 0 0 0 4.034389920584874,-10.642869115653347 h12.004166328120636 a9.108315894326587,9.108315894326587 0 0 0 8.811305593424633,-9.306322761594556 v-5.197680265784193 a9.083565035918088,9.083565035918088 0 0 0 -8.811305593424633,-9.306322761594556 " id="svg_3" class=""/> <path d="M70.70475616319865,83.36934004916053 a15.320781354859122,15.320781354859122 0 1 1 14.454501310561755,-15.296030496450625 A14.850515045097694,14.850515045097694 0 0 1 70.70475616319865,83.36934004916053 M123.25082856443602,55.425620905968366 h-12.375429204248078 A45.54157947163293,45.54157947163293 0 0 0 107.21227231573047,46.243052436416285 l8.613298726156664,-9.108315894326587 a9.727087354538993,9.727087354538993 0 0 0 0,-13.167456673319956 l-3.465120177189462,-3.6631270444574313 a8.489544434114185,8.489544434114185 0 0 0 -12.375429204248078,0 l-8.613298726156664,9.108315894326587 A40.442902639482725,40.442902639482725 0 0 0 81.99114759747292,25.427580514871032 V12.532383284044531 a9.108315894326587,9.108315894326587 0 0 0 -8.811305593424633,-9.306322761594556 h-4.950171681699231 a9.108315894326587,9.108315894326587 0 0 0 -8.811305593424633,9.306322761594556 v12.895197230826497 a40.17064319698927,40.17064319698927 0 0 0 -9.331073620003052,4.0591407789933704 l-8.613298726156664,-9.108315894326587 a8.489544434114185,8.489544434114185 0 0 0 -12.375429204248078,0 L25.58394128451018,23.967279868769744 a9.727087354538993,9.727087354538993 0 0 0 0,13.167456673319956 L34.19724001066683,46.243052436416285 a45.07131316187151,45.07131316187151 0 0 0 -3.6631270444574313,9.083565035918088 h-12.375429204248078 a9.083565035918088,9.083565035918088 0 0 0 -8.811305593424633,9.306322761594556 v5.197680265784193 a9.108315894326587,9.108315894326587 0 0 0 8.811305593424633,9.306322761594556 h11.979415469712139 a45.69008462208391,45.69008462208391 0 0 0 4.0591407789933704,10.642869115653347 l-8.613298726156664,9.108315894326587 a9.727087354538993,9.727087354538993 0 0 0 0,13.167456673319956 l3.465120177189462,3.6631270444574313 a8.489544434114185,8.489544434114185 0 0 0 12.375429204248078,0 l8.613298726156664,-9.108315894326587 a40.49240435629971,40.49240435629971 0 0 0 9.331073620003052,4.0591407789933704 v12.895197230826497 a9.083565035918088,9.083565035918088 0 0 0 8.811305593424633,9.306322761594556 h4.950171681699231 A9.083565035918088,9.083565035918088 0 0 0 81.99114759747292,123.68848839660077 V110.79329116577425 a40.78941465720167,40.78941465720167 0 0 0 9.331073620003052,-4.0591407789933704 l8.613298726156664,9.108315894326587 a8.489544434114185,8.489544434114185 0 0 0 12.375429204248078,0 l3.465120177189462,-3.6631270444574313 a9.727087354538993,9.727087354538993 0 0 0 0,-13.167456673319956 l-8.613298726156664,-9.108315894326587 a45.665333763675406,45.665333763675406 0 0 0 4.034389920584874,-10.642869115653347 h12.004166328120636 a9.108315894326587,9.108315894326587 0 0 0 8.811305593424633,-9.306322761594556 v-5.197680265784193 a9.083565035918088,9.083565035918088 0 0 0 -8.811305593424633,-9.306322761594556 " id="svg_3" class=""/>
</svg> </svg>
<div id="settingsTooltip">Settings</div> <div id="settingsTooltip">Réglages</div>
</button> </button>
</div> </div>
</div> </div>
<div class="mediaDivider"></div> <div class="mediaDivider"></div>
<div id="externalMedia"> <div id="externalMedia">
<div class="mediaContainer"> <div class="mediaContainer">
<a href="https://github.com/dscalZi/HeliosLauncher" class="mediaURL" id="linkURL"> <a href="https://github.com/dscalZi/HeliosLauncher" class="mediaURL" id="linkURL">
<svg id="linkSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500"> <svg id="linkSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
<g> <g>
<path d="M75.37,65.51a3.85,3.85,0,0,0-1.73.42,8.22,8.22,0,0,1,.94,3.76A8.36,8.36,0,0,1,66.23,78H46.37a8.35,8.35,0,1,1,0-16.7h9.18a21.51,21.51,0,0,1,6.65-8.72H46.37a17.07,17.07,0,1,0,0,34.15H66.23A17,17,0,0,0,82.77,65.51Z"/> <path d="M75.37,65.51a3.85,3.85,0,0,0-1.73.42,8.22,8.22,0,0,1,.94,3.76A8.36,8.36,0,0,1,66.23,78H46.37a8.35,8.35,0,1,1,0-16.7h9.18a21.51,21.51,0,0,1,6.65-8.72H46.37a17.07,17.07,0,1,0,0,34.15H66.23A17,17,0,0,0,82.77,65.51Z"/>
<path d="M66,73.88a3.85,3.85,0,0,0,1.73-.42,8.22,8.22,0,0,1-.94-3.76,8.36,8.36,0,0,1,8.35-8.35H95A8.35,8.35,0,1,1,95,78H85.8a21.51,21.51,0,0,1-6.65,8.72H95a17.07,17.07,0,0,0,0-34.15H75.13A17,17,0,0,0,58.59,73.88Z"/> <path d="M66,73.88a3.85,3.85,0,0,0,1.73-.42,8.22,8.22,0,0,1-.94-3.76,8.36,8.36,0,0,1,8.35-8.35H95A8.35,8.35,0,1,1,95,78H85.8a21.51,21.51,0,0,1-6.65,8.72H95a17.07,17.07,0,0,0,0-34.15H75.13A17,17,0,0,0,58.59,73.88Z"/>
</g> </g>
</svg> </svg>
</a> </a>
</div> </div>
<div class="mediaContainer"> <div class="mediaContainer">
<a href="#" class="mediaURL" id="twitterURL" disabled> <a href="#" class="mediaURL" id="twitterURL" disabled>
<svg id="twitterSVG" class="mediaSVG" viewBox="0 0 5000 4060" preserveAspectRatio="xMidYMid meet"> <svg id="twitterSVG" class="mediaSVG" viewBox="0 0 5000 4060" preserveAspectRatio="xMidYMid meet">
<g> <g>
<path d="M1210 4048 c-350 -30 -780 -175 -1124 -378 -56 -33 -86 -57 -86 -68 0 -16 7 -17 83 -9 114 12 349 1 493 -22 295 -49 620 -180 843 -341 l54 -38 -49 -7 c-367 -49 -660 -256 -821 -582 -30 -61 -53 -120 -51 -130 3 -16 12 -17 73 -13 97 7 199 5 270 -4 l60 -9 -65 -22 c-341 -117 -609 -419 -681 -769 -18 -88 -26 -226 -13 -239 4 -3 32 7 63 22 68 35 198 77 266 86 28 4 58 9 68 12 10 2 -22 -34 -72 -82 -240 -232 -353 -532 -321 -852 15 -149 79 -347 133 -418 16 -20 17 -19 49 20 377 455 913 795 1491 945 160 41 346 74 485 86 l82 7 -7 -59 c-5 -33 -7 -117 -6 -189 2 -163 31 -286 103 -430 141 -285 422 -504 708 -550 112 -19 333 -19 442 0 180 30 335 108 477 239 l58 54 95 -24 c143 -36 286 -89 427 -160 70 -35 131 -60 135 -56 19 19 -74 209 -151 312 -50 66 -161 178 -216 217 l-30 22 73 -14 c111 -21 257 -63 353 -101 99 -39 99 -39 99 -19 0 57 -237 326 -412 468 l-88 71 6 51 c4 28 1 130 -5 226 -30 440 -131 806 -333 1202 -380 745 -1036 1277 -1823 1477 -243 62 -430 81 -786 78 -134 0 -291 -5 -349 -10z"/> <path d="M1210 4048 c-350 -30 -780 -175 -1124 -378 -56 -33 -86 -57 -86 -68 0 -16 7 -17 83 -9 114 12 349 1 493 -22 295 -49 620 -180 843 -341 l54 -38 -49 -7 c-367 -49 -660 -256 -821 -582 -30 -61 -53 -120 -51 -130 3 -16 12 -17 73 -13 97 7 199 5 270 -4 l60 -9 -65 -22 c-341 -117 -609 -419 -681 -769 -18 -88 -26 -226 -13 -239 4 -3 32 7 63 22 68 35 198 77 266 86 28 4 58 9 68 12 10 2 -22 -34 -72 -82 -240 -232 -353 -532 -321 -852 15 -149 79 -347 133 -418 16 -20 17 -19 49 20 377 455 913 795 1491 945 160 41 346 74 485 86 l82 7 -7 -59 c-5 -33 -7 -117 -6 -189 2 -163 31 -286 103 -430 141 -285 422 -504 708 -550 112 -19 333 -19 442 0 180 30 335 108 477 239 l58 54 95 -24 c143 -36 286 -89 427 -160 70 -35 131 -60 135 -56 19 19 -74 209 -151 312 -50 66 -161 178 -216 217 l-30 22 73 -14 c111 -21 257 -63 353 -101 99 -39 99 -39 99 -19 0 57 -237 326 -412 468 l-88 71 6 51 c4 28 1 130 -5 226 -30 440 -131 806 -333 1202 -380 745 -1036 1277 -1823 1477 -243 62 -430 81 -786 78 -134 0 -291 -5 -349 -10z"/>
</g> </g>
</svg> </svg>
</a> </a>
</div> </div>
<div class="mediaContainer"> <div class="mediaContainer">
<a href="#" class="mediaURL" id="instagramURL" disabled> <a href="#" class="mediaURL" id="instagramURL" disabled>
<svg id="instagramSVG" class="mediaSVG" viewBox="0 0 5040 5040"> <svg id="instagramSVG" class="mediaSVG" viewBox="0 0 5040 5040">
<defs> <defs>
<radialGradient id="instaFill" cx="30%" cy="107%" r="150%"> <radialGradient id="instaFill" cx="30%" cy="107%" r="150%">
<stop offset="0%" stop-color="#fdf497"/> <stop offset="0%" stop-color="#fdf497"/>
<stop offset="5%" stop-color="#fdf497"/> <stop offset="5%" stop-color="#fdf497"/>
<stop offset="45%" stop-color="#fd5949"/> <stop offset="45%" stop-color="#fd5949"/>
<stop offset="60%" stop-color="#d6249f"/> <stop offset="60%" stop-color="#d6249f"/>
<stop offset="90%" stop-color="#285AEB"/> <stop offset="90%" stop-color="#285AEB"/>
</radialGradient> </radialGradient>
</defs> </defs>
<g> <g>
<path d="M1390 5024 c-163 -9 -239 -19 -315 -38 -281 -70 -477 -177 -660 -361 -184 -184 -292 -380 -361 -660 -43 -171 -53 -456 -53 -1445 0 -989 10 -1274 53 -1445 69 -280 177 -476 361 -660 184 -184 380 -292 660 -361 171 -43 456 -53 1445 -53 989 0 1274 10 1445 53 280 69 476 177 660 361 184 184 292 380 361 660 43 171 53 456 53 1445 0 989 -10 1274 -53 1445 -69 280 -177 476 -361 660 -184 184 -380 292 -660 361 -174 44 -454 53 -1470 52 -599 0 -960 -5 -1105 -14z m2230 -473 c58 -6 141 -18 185 -27 397 -78 638 -318 719 -714 37 -183 41 -309 41 -1290 0 -981 -4 -1107 -41 -1290 -81 -395 -319 -633 -714 -714 -183 -37 -309 -41 -1290 -41 -981 0 -1107 4 -1290 41 -397 81 -636 322 -714 719 -33 166 -38 296 -43 1100 -5 796 3 1203 27 1380 67 489 338 758 830 825 47 7 162 15 255 20 250 12 1907 4 2035 -9z"/> <path d="M1390 5024 c-163 -9 -239 -19 -315 -38 -281 -70 -477 -177 -660 -361 -184 -184 -292 -380 -361 -660 -43 -171 -53 -456 -53 -1445 0 -989 10 -1274 53 -1445 69 -280 177 -476 361 -660 184 -184 380 -292 660 -361 171 -43 456 -53 1445 -53 989 0 1274 10 1445 53 280 69 476 177 660 361 184 184 292 380 361 660 43 171 53 456 53 1445 0 989 -10 1274 -53 1445 -69 280 -177 476 -361 660 -184 184 -380 292 -660 361 -174 44 -454 53 -1470 52 -599 0 -960 -5 -1105 -14z m2230 -473 c58 -6 141 -18 185 -27 397 -78 638 -318 719 -714 37 -183 41 -309 41 -1290 0 -981 -4 -1107 -41 -1290 -81 -395 -319 -633 -714 -714 -183 -37 -309 -41 -1290 -41 -981 0 -1107 4 -1290 41 -397 81 -636 322 -714 719 -33 166 -38 296 -43 1100 -5 796 3 1203 27 1380 67 489 338 758 830 825 47 7 162 15 255 20 250 12 1907 4 2035 -9z"/>
<path d="M2355 3819 c-307 -42 -561 -172 -780 -400 -244 -253 -359 -543 -359 -899 0 -361 116 -648 367 -907 262 -269 563 -397 937 -397 374 0 675 128 937 397 251 259 367 546 367 907 0 361 -116 648 -367 907 -197 203 -422 326 -690 378 -101 20 -317 27 -412 14z m400 -509 c275 -88 470 -284 557 -560 20 -65 23 -95 23 -230 0 -135 -3 -165 -23 -230 -88 -278 -284 -474 -562 -562 -65 -20 -95 -23 -230 -23 -135 0 -165 3 -230 23 -278 88 -474 284 -562 562 -20 65 -23 95 -23 230 0 135 3 165 23 230 73 230 219 403 427 507 134 67 212 83 390 79 111 -3 155 -8 210 -26z"/> <path d="M2355 3819 c-307 -42 -561 -172 -780 -400 -244 -253 -359 -543 -359 -899 0 -361 116 -648 367 -907 262 -269 563 -397 937 -397 374 0 675 128 937 397 251 259 367 546 367 907 0 361 -116 648 -367 907 -197 203 -422 326 -690 378 -101 20 -317 27 -412 14z m400 -509 c275 -88 470 -284 557 -560 20 -65 23 -95 23 -230 0 -135 -3 -165 -23 -230 -88 -278 -284 -474 -562 -562 -65 -20 -95 -23 -230 -23 -135 0 -165 3 -230 23 -278 88 -474 284 -562 562 -20 65 -23 95 -23 230 0 135 3 165 23 230 73 230 219 403 427 507 134 67 212 83 390 79 111 -3 155 -8 210 -26z"/>
<path d="M3750 1473 c-29 -11 -66 -38 -106 -77 -70 -71 -94 -126 -94 -221 0 -95 24 -150 94 -221 72 -71 126 -94 225 -94 168 0 311 143 311 311 0 99 -23 154 -94 225 -43 42 -76 66 -110 77 -61 21 -166 21 -226 0z"/> <path d="M3750 1473 c-29 -11 -66 -38 -106 -77 -70 -71 -94 -126 -94 -221 0 -95 24 -150 94 -221 72 -71 126 -94 225 -94 168 0 311 143 311 311 0 99 -23 154 -94 225 -43 42 -76 66 -110 77 -61 21 -166 21 -226 0z"/>
</g> </g>
</svg> </svg>
</a> </a>
</div> </div>
<div class="mediaContainer"> <div class="mediaContainer">
<a href="#" class="mediaURL" id="youtubeURL" disabled> <a href="#" class="mediaURL" id="youtubeURL" disabled>
<svg id="youtubeSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500"> <svg id="youtubeSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
<g> <g>
<path d="M84.8,69.52,65.88,79.76V59.27Zm23.65.59c0-5.14-.79-17.63-3.94-20.57S99,45.86,73.37,45.86s-28,.73-31.14,3.68S38.29,65,38.29,70.11s.79,17.63,3.94,20.57,5.52,3.68,31.14,3.68,28-.74,31.14-3.68,3.94-15.42,3.94-20.57"/> <path d="M84.8,69.52,65.88,79.76V59.27Zm23.65.59c0-5.14-.79-17.63-3.94-20.57S99,45.86,73.37,45.86s-28,.73-31.14,3.68S38.29,65,38.29,70.11s.79,17.63,3.94,20.57,5.52,3.68,31.14,3.68,28-.74,31.14-3.68,3.94-15.42,3.94-20.57"/>
</g> </g>
</svg> </svg>
</a> </a>
</div> </div>
<div class="mediaContainer"> <div class="mediaContainer">
<a href="https://discord.gg/zNWUXdt" class="mediaURL" id="discordURL"> <a href="https://discord.gg/zNWUXdt" class="mediaURL" id="discordURL">
<svg id="discordSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500"> <svg id="discordSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
<g> <g>
<path d="M81.23,78.48a6.14,6.14,0,1,1,6.14-6.14,6.14,6.14,0,0,1-6.14,6.14M60,78.48a6.14,6.14,0,1,1,6.14-6.14A6.14,6.14,0,0,1,60,78.48M104.41,73c-.92-7.7-8.24-22.9-8.24-22.9A43,43,0,0,0,88,45.59a17.88,17.88,0,0,0-8.38-1.27l-.13,1.06a23.52,23.52,0,0,1,5.8,1.95,87.59,87.59,0,0,1,8.17,4.87s-10.32-5.63-22.27-5.63a51.32,51.32,0,0,0-23.2,5.63,87.84,87.84,0,0,1,8.17-4.87,23.57,23.57,0,0,1,5.8-1.95l-.13-1.06a17.88,17.88,0,0,0-8.38,1.27,42.84,42.84,0,0,0-8.21,4.56S37.87,65.35,37,73s-.37,11.54-.37,11.54,4.22,5.68,9.9,7.14,7.7,1.47,7.7,1.47l3.75-4.68a21.22,21.22,0,0,1-4.65-2A24.47,24.47,0,0,1,47.93,82S61.16,88.4,70.68,88.4c10,0,22.75-6.44,22.75-6.44a24.56,24.56,0,0,1-5.35,4.56,21.22,21.22,0,0,1-4.65,2l3.75,4.68s2,0,7.7-1.47,9.89-7.14,9.89-7.14.55-3.85-.37-11.54"/> <path d="M81.23,78.48a6.14,6.14,0,1,1,6.14-6.14,6.14,6.14,0,0,1-6.14,6.14M60,78.48a6.14,6.14,0,1,1,6.14-6.14A6.14,6.14,0,0,1,60,78.48M104.41,73c-.92-7.7-8.24-22.9-8.24-22.9A43,43,0,0,0,88,45.59a17.88,17.88,0,0,0-8.38-1.27l-.13,1.06a23.52,23.52,0,0,1,5.8,1.95,87.59,87.59,0,0,1,8.17,4.87s-10.32-5.63-22.27-5.63a51.32,51.32,0,0,0-23.2,5.63,87.84,87.84,0,0,1,8.17-4.87,23.57,23.57,0,0,1,5.8-1.95l-.13-1.06a17.88,17.88,0,0,0-8.38,1.27,42.84,42.84,0,0,0-8.21,4.56S37.87,65.35,37,73s-.37,11.54-.37,11.54,4.22,5.68,9.9,7.14,7.7,1.47,7.7,1.47l3.75-4.68a21.22,21.22,0,0,1-4.65-2A24.47,24.47,0,0,1,47.93,82S61.16,88.4,70.68,88.4c10,0,22.75-6.44,22.75-6.44a24.56,24.56,0,0,1-5.35,4.56,21.22,21.22,0,0,1-4.65,2l3.75,4.68s2,0,7.7-1.47,9.89-7.14,9.89-7.14.55-3.85-.37-11.54"/>
</g> </g>
</svg> </svg>
</a> </a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="lower"> <div id="lower">
<div id="left"> <div id="left">
<div class="bot_wrapper"> <div class="bot_wrapper">
<div id="content"> <div id="content">
<div id="server_status_wrapper"> <div id="server_status_wrapper">
<span class="bot_label" id="landingPlayerLabel">SERVER</span> <span class="bot_label" id="landingPlayerLabel">SERVER</span>
<span id="player_count">OFFLINE</span> <span id="player_count">OFFLINE</span>
</div> </div>
<div class="bot_divider"></div> <div class="bot_divider"></div>
<div id="mojangStatusWrapper"> <div id="mojangStatusWrapper">
<span class="bot_label">MOJANG STATUS</span> <span class="bot_label">Status Mojang</span>
<span id="mojang_status_icon">&#8226;</span> <span id="mojang_status_icon">&#8226;</span>
<div id="mojangStatusTooltip"> <div id="mojangStatusTooltip">
<div id="mojangStatusTooltipTitle">Services</div> <div id="mojangStatusTooltipTitle">Services</div>
<div id="mojangStatusEssentialContainer"> <div id="mojangStatusEssentialContainer">
<!-- Essential Mojang services are populated here. --> <!-- Essential Mojang services are populated here. -->
</div> </div>
<div id="mojangStatusNEContainer"> <div id="mojangStatusNEContainer">
<div class="mojangStatusNEBar"></div> <div class="mojangStatusNEBar"></div>
<div id="mojangStatusNETitle">Non&nbsp;Essential</div> <div id="mojangStatusNETitle">Non&nbsp;Essential</div>
<div class="mojangStatusNEBar"></div> <div class="mojangStatusNEBar"></div>
</div> </div>
<div id="mojangStatusNonEssentialContainer"> <div id="mojangStatusNonEssentialContainer">
<!-- Non Essential Mojang services are populated here. --> <!-- Non Essential Mojang services are populated here. -->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="center"> <div id="center">
<div class="bot_wrapper"> <div class="bot_wrapper">
<div id="content"> <div id="content">
<button id="newsButton"> <button id="newsButton">
<!--<img src="assets/images/icons/arrow.svg" id="newsButtonSVG"/>--> <!--<img src="assets/images/icons/arrow.svg" id="newsButtonSVG"/>-->
<div id="newsButtonAlert" style="display: none;"></div> <div id="newsButtonAlert" style="display: none;"></div>
<svg id="newsButtonSVG" viewBox="0 0 24.87 13.97"> <svg id="newsButtonSVG" viewBox="0 0 24.87 13.97">
<defs> <defs>
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;}</style> <style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;}</style>
</defs> </defs>
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/> <polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
</svg> </svg>
&#10;<span id="newsButtonText">NEWS</span> &#10;<span id="newsButtonText">ACTUS</span>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<div id="right"> <div id="right">
<div class="bot_wrapper"> <div class="bot_wrapper">
<div id="launch_content"> <div id="launch_content">
<button id="launch_button">PLAY</button> <button id="launch_button">JOUER !</button>
<div class="bot_divider"></div> <div class="bot_divider"></div>
<button id="server_selection_button" class="bot_label">&#8226; No Server Selected</button> <button id="server_selection_button" class="bot_label">&#8226; Aucun modpack séléctionné</button>
</div> </div>
<div id="launch_details"> <div id="launch_details">
<div id="launch_details_left"> <div id="launch_details_left">
<span id="launch_progress_label">0%</span> <span id="launch_progress_label">0%</span>
<div class="bot_divider"></div> <div class="bot_divider"></div>
</div> </div>
<div id="launch_details_right"> <div id="launch_details_right">
<progress id="launch_progress" value="22" max="100"></progress> <progress id="launch_progress" value="22" max="100"></progress>
<span id="launch_details_text" class="bot_label">Please wait..</span> <span id="launch_details_text" class="bot_label">Merci de patienter..</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="newsContainer"> <div id="newsContainer">
<div id="newsContent" article="-1" style="display: none;"> <div id="newsContent" article="-1" style="display: none;">
<div id="newsStatusContainer"> <div id="newsStatusContainer">
<div id="newsStatusContent"> <div id="newsStatusContent">
<div id="newsTitleContainer"> <div id="newsTitleContainer">
<a id="newsArticleTitle" href="#">Lorem Ipsum</a> <a id="newsArticleTitle" href="#">Lorem Ipsum</a>
</div> </div>
<div id="newsMetaContainer"> <div id="newsMetaContainer">
<div id="newsArticleDateWrapper"> <div id="newsArticleDateWrapper">
<span id="newsArticleDate">Mar 15, 44 BC, 9:14 AM</span> <span id="newsArticleDate">Mar 15, 44 BC, 9:14 AM</span>
</div> </div>
<div id="newsArticleAuthorWrapper"> <div id="newsArticleAuthorWrapper">
<span id="newsArticleAuthor">by Cicero</span> <span id="newsArticleAuthor">by Cicero</span>
</div> </div>
<a href="#" id="newsArticleComments">0 Comments</a> <a href="#" id="newsArticleComments">0 Comments</a>
</div> </div>
</div> </div>
<div id="newsNavigationContainer"> <div id="newsNavigationContainer">
<button id="newsNavigateLeft"> <button id="newsNavigateLeft">
<svg id="newsNavigationLeftSVG" viewBox="0 0 24.87 13.97"> <svg id="newsNavigationLeftSVG" viewBox="0 0 24.87 13.97">
<defs> <defs>
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style> <style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style>
</defs> </defs>
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/> <polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
</svg> </svg>
</button> </button>
<span id="newsNavigationStatus">1 of 1</span> <span id="newsNavigationStatus">1 of 1</span>
<button id="newsNavigateRight"> <button id="newsNavigateRight">
<svg id="newsNavigationRightSVG" viewBox="0 0 24.87 13.97"> <svg id="newsNavigationRightSVG" viewBox="0 0 24.87 13.97">
<defs> <defs>
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style> <style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style>
</defs> </defs>
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/> <polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
</svg> </svg>
</button> </button>
</div> </div>
</div> </div>
<div id="newsArticleContainer"> <div id="newsArticleContainer">
<div id="newsArticleContent"> <div id="newsArticleContent">
<div id="newsArticleContentScrollable"> <div id="newsArticleContentScrollable">
<!-- Article Content --> <!-- Article Content -->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="newsErrorContainer"> <div id="newsErrorContainer">
<div id="newsErrorLoading"> <div id="newsErrorLoading">
<span id="nELoadSpan" class="newsErrorContent">Checking for News..</span> <span id="nELoadSpan" class="newsErrorContent">Vérification des News ...</span>
</div> </div>
<div id="newsErrorFailed" style="display: none;"> <div id="newsErrorFailed" style="display: none;">
<span id="nEFailedSpan" class="newsErrorContent">Failed to Load News</span> <span id="nEFailedSpan" class="newsErrorContent">Erreur durant le chargement des News.</span>
<button id="newsErrorRetry">Try Again</button> <button id="newsErrorRetry">Réessayer</button>
</div> </div>
<div id="newsErrorNone" style="display: none;"> <div id="newsErrorNone" style="display: none;">
<span id="nENoneSpan" class="newsErrorContent">No News</span> <span id="nENoneSpan" class="newsErrorContent">Aucunes News :(</span>
</div> </div>
</div> </div>
</div> </div>
<script src="./assets/js/scripts/landing.js"></script> <script src="./assets/js/scripts/landing.js"></script>
</div> </div>

View File

@ -1,65 +1,65 @@
<div id="loginContainer" style="display: none;"> <div id="loginContainer" style="display: none;">
<div id="loginCancelContainer" style="display: none;"> <div id="loginCancelContainer" style="display: none;">
<button id="loginCancelButton"> <button id="loginCancelButton">
<div id="loginCancelIcon">X</div> <div id="loginCancelIcon">X</div>
<span id="loginCancelText">Cancel</span> <span id="loginCancelText">Annuler</span>
</button> </button>
</div> </div>
<div id="loginContent"> <div id="loginContent">
<form id="loginForm"> <form id="loginForm">
<img id="loginImageSeal" src="assets/images/SealCircle.png"/> <img id="loginImageSeal" src="assets/images/SealCircle.png"/>
<span id="loginSubheader">MINECRAFT LOGIN</span> <span id="loginSubheader">Connexion à un compte Minecraft</span>
<div class="loginFieldContainer"> <div class="loginFieldContainer">
<svg id="profileSVG" class="loginSVG" viewBox="40 37 65.36 61.43"> <svg id="profileSVG" class="loginSVG" viewBox="40 37 65.36 61.43">
<g> <g>
<path d="M86.77,58.12A13.79,13.79,0,1,0,73,71.91,13.79,13.79,0,0,0,86.77,58.12M97,103.67a3.41,3.41,0,0,0,3.39-3.84,27.57,27.57,0,0,0-54.61,0,3.41,3.41,0,0,0,3.39,3.84Z"/> <path d="M86.77,58.12A13.79,13.79,0,1,0,73,71.91,13.79,13.79,0,0,0,86.77,58.12M97,103.67a3.41,3.41,0,0,0,3.39-3.84,27.57,27.57,0,0,0-54.61,0,3.41,3.41,0,0,0,3.39,3.84Z"/>
</g> </g>
</svg> </svg>
<span class="loginErrorSpan" id="loginEmailError">* Invalid Value</span> <span class="loginErrorSpan" id="loginEmailError">* Saisie invalide</span>
<input id="loginUsername" class="loginField" type="text" placeholder="EMAIL OR USERNAME"/> <input id="loginUsername" class="loginField" type="text" placeholder="Email ou Pseudo"/>
</div> </div>
<div class="loginFieldContainer"> <div class="loginFieldContainer">
<svg id="lockSVG" class="loginSVG" viewBox="40 32 60.36 70.43"> <svg id="lockSVG" class="loginSVG" viewBox="40 32 60.36 70.43">
<g> <g>
<path d="M86.16,54a16.38,16.38,0,1,0-32,0H44V102.7H96V54Zm-25.9-3.39a9.89,9.89,0,1,1,19.77,0A9.78,9.78,0,0,1,79.39,54H60.89A9.78,9.78,0,0,1,60.26,50.59ZM70,96.2a6.5,6.5,0,0,1-6.5-6.5,6.39,6.39,0,0,1,3.1-5.4V67h6.5V84.11a6.42,6.42,0,0,1,3.39,5.6A6.5,6.5,0,0,1,70,96.2Z"/> <path d="M86.16,54a16.38,16.38,0,1,0-32,0H44V102.7H96V54Zm-25.9-3.39a9.89,9.89,0,1,1,19.77,0A9.78,9.78,0,0,1,79.39,54H60.89A9.78,9.78,0,0,1,60.26,50.59ZM70,96.2a6.5,6.5,0,0,1-6.5-6.5,6.39,6.39,0,0,1,3.1-5.4V67h6.5V84.11a6.42,6.42,0,0,1,3.39,5.6A6.5,6.5,0,0,1,70,96.2Z"/>
</g> </g>
</svg> </svg>
<span class="loginErrorSpan" id="loginPasswordError">* Required</span> <span class="loginErrorSpan" id="loginPasswordError">* Requis</span>
<input id="loginPassword" class="loginField" type="password" placeholder="PASSWORD"/> <input id="loginPassword" class="loginField" type="password" placeholder="Mot de Passe"/>
</div> </div>
<div id="loginOptions"> <div id="loginOptions">
<span class="loginSpanDim"> <span class="loginSpanDim">
<a href="https://my.minecraft.net/en-us/password/forgot/">forgot password?</a> <a href="https://my.minecraft.net/en-us/password/forgot/">Mot de passe oublié ?</a>
</span> </span>
<label id="checkmarkContainer"> <label id="checkmarkContainer">
<input id="loginRememberOption" type="checkbox" checked> <input id="loginRememberOption" type="checkbox" checked>
<span id="loginRememberText" class="loginSpanDim">remember me?</span> <span id="loginRememberText" class="loginSpanDim">Se rappeler ?</span>
<span class="loginCheckmark"></span> <span class="loginCheckmark"></span>
</label> </label>
</div> </div>
<button id="loginButton" disabled> <button id="loginButton" disabled>
<div id="loginButtonContent"> <div id="loginButtonContent">
LOGIN Se Connecter
<svg id="loginSVG" viewBox="0 0 24.87 13.97"> <svg id="loginSVG" viewBox="0 0 24.87 13.97">
<defs> <defs>
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style> <style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style>
</defs> </defs>
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/> <polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
</svg> </svg>
<div class="circle-loader"> <div class="circle-loader">
<div class="checkmark draw"></div> <div class="checkmark draw"></div>
</div> </div>
<!--<div class="spinningCircle" id="loginSpinner"></div>--> <!--<div class="spinningCircle" id="loginSpinner"></div>-->
</div> </div>
</button> </button>
<div id="loginDisclaimer"> <div id="loginDisclaimer">
<span class="loginSpanDim" id="loginRegisterSpan"> <span class="loginSpanDim" id="loginRegisterSpan">
<a href="https://minecraft.net/en-us/store/minecraft/">Need an Account?</a> <a href="https://minecraft.net/en-us/store/minecraft/">Besoin d'un compte ?</a>
</span> </span>
<p class="loginDisclaimerText">Your password is sent directly to mojang and never stored.</p> <p class="loginDisclaimerText">Votre mot de passe est envoyé directement à Mojang et n'est jamais stocké.</p>
<p class="loginDisclaimerText">Helios Launcher is not affiliated with Mojang AB.</p> <p class="loginDisclaimerText">Creeponnia Launcher n'est pas affilié à Mojang AB.</p>
</div> </div>
</form> </form>
</div> </div>
<script src="./assets/js/scripts/login.js"></script> <script src="./assets/js/scripts/login.js"></script>
</div> </div>

View File

@ -1,41 +1,41 @@
<div id="overlayContainer" style="display: none;"> <div id="overlayContainer" style="display: none;">
<div id="serverSelectContent" style="display: none;"> <div id="serverSelectContent" style="display: none;">
<span id="serverSelectHeader">Available Servers</span> <span id="serverSelectHeader">Modpacks disponnibles</span>
<div id="serverSelectList"> <div id="serverSelectList">
<div id="serverSelectListScrollable"> <div id="serverSelectListScrollable">
<!-- Server listings populated here. --> <!-- Server listings populated here. -->
</div> </div>
</div> </div>
<div id="serverSelectActions"> <div id="serverSelectActions">
<button id="serverSelectConfirm" class="overlayKeybindEnter" type="submit">Select</button> <button id="serverSelectConfirm" class="overlayKeybindEnter" type="submit">Séléctionner</button>
<div id="serverSelectCancelWrapper"> <div id="serverSelectCancelWrapper">
<button id="serverSelectCancel" class="overlayKeybindEsc">Cancel</button> <button id="serverSelectCancel" class="overlayKeybindEsc">Annuler</button>
</div> </div>
</div> </div>
</div> </div>
<div id="accountSelectContent" style="display: none;"> <div id="accountSelectContent" style="display: none;">
<span id="accountSelectHeader">Select an Account</span> <span id="accountSelectHeader">Séléctionner un compte</span>
<div id="accountSelectList"> <div id="accountSelectList">
<div id="accountSelectListScrollable"> <div id="accountSelectListScrollable">
<!-- Accounts populated here. --> <!-- Accounts populated here. -->
</div> </div>
</div> </div>
<div id="accountSelectActions"> <div id="accountSelectActions">
<button id="accountSelectConfirm" class="overlayKeybindEnter" type="submit">Select</button> <button id="accountSelectConfirm" class="overlayKeybindEnter" type="submit">Séléctionner</button>
<div id="accountSelectCancelWrapper"> <div id="accountSelectCancelWrapper">
<button id="accountSelectCancel" class="overlayKeybindEsc">Cancel</button> <button id="accountSelectCancel" class="overlayKeybindEsc">Annuler</button>
</div> </div>
</div> </div>
</div> </div>
<div id="overlayContent"> <div id="overlayContent">
<span id="overlayTitle">Lorem Ipsum:<br>Finis Illud</span> <span id="overlayTitle">Lorem Ipsum:<br>Finis Illud</span>
<span id="overlayDesc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud..</span> <span id="overlayDesc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud..</span>
<div id="overlayActionContainer"> <div id="overlayActionContainer">
<button id="overlayAcknowledge" class="overlayKeybindEnter">Conare Iterum</button> <button id="overlayAcknowledge" class="overlayKeybindEnter">Conare Iterum</button>
<div id="overlayDismissWrapper"> <div id="overlayDismissWrapper">
<button id="overlayDismiss" style="display: none;" class="overlayKeybindEsc">Dismiss</button> <button id="overlayDismiss" style="display: none;" class="overlayKeybindEsc">Annuler</button>
</div> </div>
</div> </div>
</div> </div>
<script src="./assets/js/scripts/overlay.js"></script> <script src="./assets/js/scripts/overlay.js"></script>
</div> </div>

View File

@ -1,354 +1,357 @@
<div id="settingsContainer" style="display: none;"> <div id="settingsContainer" style="display: none;">
<div id="settingsContainerLeft"> <div id="settingsContainerLeft">
<div id="settingsNavContainer"> <div id="settingsNavContainer">
<div id="settingsNavHeader"> <div id="settingsNavHeader">
<span id="settingsNavHeaderText">Settings</span> <span id="settingsNavHeaderText">Réglages</span>
</div> </div>
<div id="settingsNavItemsContainer"> <div id="settingsNavItemsContainer">
<div id="settingsNavItemsContent"> <div id="settingsNavItemsContent">
<button class="settingsNavItem" rSc="settingsTabAccount" id="settingsNavAccount" selected>Account</button> <button class="settingsNavItem" rSc="settingsTabAccount" id="settingsNavAccount" selected>Compte</button>
<button class="settingsNavItem" rSc="settingsTabMinecraft">Minecraft</button> <button class="settingsNavItem" rSc="settingsTabMinecraft">Minecraft</button>
<button class="settingsNavItem" rSc="settingsTabMods">Mods</button> <button class="settingsNavItem" rSc="settingsTabMods">Mods</button>
<button class="settingsNavItem" rSc="settingsTabJava">Java</button> <button class="settingsNavItem" rSc="settingsTabJava">Java</button>
<button class="settingsNavItem" rSc="settingsTabLauncher">Launcher</button> <button class="settingsNavItem" rSc="settingsTabLauncher">Launcher</button>
<div class="settingsNavSpacer"></div> <div class="settingsNavSpacer"></div>
<button class="settingsNavItem" rSc="settingsTabAbout">About</button> <button class="settingsNavItem" rSc="settingsTabAbout">A Propos</button>
<button class="settingsNavItem" rSc="settingsTabUpdate" id="settingsNavUpdate">Updates</button> <button class="settingsNavItem" rSc="settingsTabUpdate" id="settingsNavUpdate">Mise à Jour</button>
<div id="settingsNavContentBottom"> <div id="settingsNavContentBottom">
<div class="settingsNavDivider"></div> <div class="settingsNavDivider"></div>
<button id="settingsNavDone">Done</button> <button id="settingsNavDone">Quitter</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="settingsContainerRight"> <div id="settingsContainerRight">
<div id="settingsTabAccount" class="settingsTab"> <div id="settingsTabAccount" class="settingsTab">
<div class="settingsTabHeader"> <div class="settingsTabHeader">
<span class="settingsTabHeaderText">Account Settings</span> <span class="settingsTabHeaderText">Paramètres des comptes Minecraft</span>
<span class="settingsTabHeaderDesc">Add new accounts or manage existing ones.</span> <span class="settingsTabHeaderDesc">Ajouter ou gérer vos comptes Minecraft.</span>
</div> </div>
<div id="settingsAddAccountContainer"> <div id="settingsAddAccountContainer">
<button id="settingsAddAccount"> <button id="settingsAddAccount">
<span id="settingsAddAccountText">&#43; Add Account</span> <span id="settingsAddAccountText">&#43; Ajouter un compte</span>
</button> </button>
</div> </div>
<div id="settingsCurrentAccountsHeader"> <div id="settingsCurrentAccountsHeader">
<span class="settingsFieldTitle">Current Accounts</span> <span class="settingsFieldTitle">Compte Actif</span>
</div> </div>
<div id="settingsCurrentAccounts"> <div id="settingsCurrentAccounts">
<!-- Auth accounts populated here. --> <!-- Auth accounts populated here. -->
</div> </div>
</div> </div>
<div id="settingsTabMinecraft" class="settingsTab" style="display: none;"> <div id="settingsTabMinecraft" class="settingsTab" style="display: none;">
<div class="settingsTabHeader"> <div class="settingsTabHeader">
<span class="settingsTabHeaderText">Minecraft Settings</span> <span class="settingsTabHeaderText">Paramètres de Minecraft</span>
<span class="settingsTabHeaderDesc">Options related to game launch.</span> <span class="settingsTabHeaderDesc">Options relatives au lancement du jeu.</span>
</div> </div>
<div id="settingsGameResolutionContainer"> <div id="settingsGameResolutionContainer">
<span class="settingsFieldTitle">Game Resolution</span> <span class="settingsFieldTitle">Résolution du jeu</span>
<div id="settingsGameResolutionContent"> <div id="settingsGameResolutionContent">
<input type="number" id="settingsGameWidth" min="0" cValue="GameWidth"> <input type="number" id="settingsGameWidth" min="0" cValue="GameWidth">
<div id="settingsGameResolutionCross">&#10006;</div> <div id="settingsGameResolutionCross">&#10006;</div>
<input type="number" id="settingsGameHeight" min="0" cValue="GameHeight"> <input type="number" id="settingsGameHeight" min="0" cValue="GameHeight">
</div> </div>
</div> </div>
<div class="settingsFieldContainer"> <div class="settingsFieldContainer">
<div class="settingsFieldLeft"> <div class="settingsFieldLeft">
<span class="settingsFieldTitle">Launch in fullscreen.</span> <span class="settingsFieldTitle">Lancer en plein écran..</span>
</div> </div>
<div class="settingsFieldRight"> <div class="settingsFieldRight">
<label class="toggleSwitch"> <label class="toggleSwitch">
<input type="checkbox" cValue="Fullscreen"> <input type="checkbox" cValue="Fullscreen">
<span class="toggleSwitchSlider"></span> <span class="toggleSwitchSlider"></span>
</label> </label>
</div> </div>
</div> </div>
<div class="settingsFieldContainer"> <div class="settingsFieldContainer">
<div class="settingsFieldLeft"> <div class="settingsFieldLeft">
<span class="settingsFieldTitle">Automatically connect to the server on launch.</span> <span class="settingsFieldTitle">Se connecter automatiquement au serveur au lancement.</span>
</div> </div>
<div class="settingsFieldRight"> <div class="settingsFieldRight">
<label class="toggleSwitch"> <label class="toggleSwitch">
<input type="checkbox" cValue="AutoConnect"> <input type="checkbox" cValue="AutoConnect">
<span class="toggleSwitchSlider"></span> <span class="toggleSwitchSlider"></span>
</label> </label>
</div> </div>
</div> </div>
<div class="settingsFieldContainer"> <div class="settingsFieldContainer">
<div class="settingsFieldLeft"> <div class="settingsFieldLeft">
<span class="settingsFieldTitle">Launch game process detached from launcher.</span> <span class="settingsFieldTitle">Lancer le jeu séparé du launcher.</span>
<span class="settingsFieldDesc">If the game is not detached, closing the launcher will also close the game.</span> <span class="settingsFieldDesc">Si le jeu n'est pas séparé, fermer le launcher fermera aussi le jeu.</span>
</div> </div>
<div class="settingsFieldRight"> <div class="settingsFieldRight">
<label class="toggleSwitch"> <label class="toggleSwitch">
<input type="checkbox" cValue="LaunchDetached"> <input type="checkbox" cValue="LaunchDetached">
<span class="toggleSwitchSlider"></span> <span class="toggleSwitchSlider"></span>
</label> </label>
</div> </div>
</div> </div>
</div> </div>
<div id="settingsTabMods" class="settingsTab" style="display: none;"> <div id="settingsTabMods" class="settingsTab" style="display: none;">
<div class="settingsTabHeader"> <div class="settingsTabHeader">
<span class="settingsTabHeaderText">Mod Settings</span> <span class="settingsTabHeaderText">Paramètres des Mods</span>
<span class="settingsTabHeaderDesc">Enable or disable mods.</span> <span class="settingsTabHeaderDesc">Activer ou désactiver des Mods.</span>
</div> </div>
<div id="settingsSelServContainer"> <div id="settingsSelServContainer">
<div id="settingsSelServContent"> <div id="settingsSelServContent">
</div> </div>
<div id="settingsSwitchServerContainer"> <div id="settingsSwitchServerContainer">
<div id="settingsSwitchServerContent"> <div id="settingsSwitchServerContent">
<button id="settingsSwitchServerButton">Switch</button> <button id="settingsSwitchServerButton">Changer</button>
</div> </div>
</div> </div>
</div> </div>
<div id="settingsModsContainer"> <div id="settingsModsContainer">
<div id="settingsReqModsContainer"> <div id="settingsOptModsContainer">
<div class="settingsModsHeader">Required Mods</div> <div class="settingsModsHeader">Mods optionnels</div>
<div id="settingsReqModsContent"> <div id="settingsOptModsContent">
</div> </div>
</div> </div>
<div id="settingsOptModsContainer"> <div id="settingsDropinModsContainer">
<div class="settingsModsHeader">Optional Mods</div> <div class="settingsModsHeader">Ajouter des Mods</div>
<div id="settingsOptModsContent"> <button id="settingsDropinFileSystemButton">+ Ajouter des Mods <span id="settingsDropinRefreshNote">(F5 pour rafraîchir)</span></button>
<div id="settingsDropinModsContent">
</div>
</div> </div>
<div id="settingsDropinModsContainer"> </div>
<div class="settingsModsHeader">Drop-in Mods</div> <div id="settingsShadersContainer">
<button id="settingsDropinFileSystemButton">+ Add Mods <span id="settingsDropinRefreshNote">(F5 to Refresh)</span></button> <div class="settingsModsHeader">Shaders</div>
<div id="settingsDropinModsContent"> <div id="settingsShaderpackDesc">Activez ou désactivez les shaders. Veuillez noter que les shaders ne fonctionneront correctement que sur des configurations puissantes. Vous pouvez ajouter des packs personnalisés ici.</div>
<div id="settingsShaderpackWrapper">
</div> <button id="settingsShaderpackButton"> + </button>
</div> <div class="settingsSelectContainer">
<div id="settingsShadersContainer"> <div class="settingsSelectSelected" id="settingsShadersSelected">Séléctionner un Shaders</div>
<div class="settingsModsHeader">Shaderpacks</div> <div class="settingsSelectOptions" id="settingsShadersOptions" hidden>
<div id="settingsShaderpackDesc">Enable or disable shaders. Please note, shaders will only run smoothly on powerful setups. You may add custom packs here.</div>
<div id="settingsShaderpackWrapper"> </div>
<button id="settingsShaderpackButton"> + </button> </div>
<div class="settingsSelectContainer"> </div>
<div class="settingsSelectSelected" id="settingsShadersSelected">Select Shaderpack</div> </div>
<div class="settingsSelectOptions" id="settingsShadersOptions" hidden> <br>
<br>
</div> <div id="settingsReqModsContainer">
</div> <div class="settingsModsHeader">Mods Requis</div>
</div> <div id="settingsReqModsContent">
</div>
</div> </div>
</div> </div>
<div id="settingsTabJava" class="settingsTab" style="display: none;">
<div class="settingsTabHeader"> </div>
<span class="settingsTabHeaderText">Java Settings</span> </div>
<span class="settingsTabHeaderDesc">Manage the Java configuration (advanced).</span> <div id="settingsTabJava" class="settingsTab" style="display: none;">
</div> <div class="settingsTabHeader">
<div id="settingsMemoryContainer"> <span class="settingsTabHeaderText">Paramètres de Java</span>
<div id="settingsMemoryTitle">Memory</div> <span class="settingsTabHeaderDesc">Configurer les paramètres Java (avancé)</span>
<div id="settingsMemoryContent"> </div>
<div id="settingsMemoryContentLeft"> <div id="settingsMemoryContainer">
<div class="settingsMemoryContentItem"> <div id="settingsMemoryTitle">Mémoire</div>
<span class="settingsMemoryHeader">Maximum RAM</span> <div id="settingsMemoryContent">
<div class="settingsMemoryActionContainer"> <div id="settingsMemoryContentLeft">
<div id="settingsMaxRAMRange" class="rangeSlider" cValue="MaxRAM" min="3" max="8" value="3" step="0.5"> <div class="settingsMemoryContentItem">
<div class="rangeSliderBar"></div> <span class="settingsMemoryHeader">RAM maximum</span>
<div class="rangeSliderTrack"></div> <div class="settingsMemoryActionContainer">
</div> <div id="settingsMaxRAMRange" class="rangeSlider" cValue="MaxRAM" min="3" max="8" value="3" step="0.5">
<span id="settingsMaxRAMLabel" class="settingsMemoryLabel">3G</span> <div class="rangeSliderBar"></div>
</div> <div class="rangeSliderTrack"></div>
</div> </div>
<div class="settingsMemoryContentItem"> <span id="settingsMaxRAMLabel" class="settingsMemoryLabel">3G</span>
<span class="settingsMemoryHeader">Minimum RAM</span> </div>
<div class="settingsMemoryActionContainer"> </div>
<div id="settingsMinRAMRange" class="rangeSlider" cValue="MinRAM" min="3" max="8" value="3" step="0.5"> <div class="settingsMemoryContentItem">
<div class="rangeSliderBar"></div> <span class="settingsMemoryHeader">RAM minimum</span>
<div class="rangeSliderTrack"></div> <div class="settingsMemoryActionContainer">
</div> <div id="settingsMinRAMRange" class="rangeSlider" cValue="MinRAM" min="3" max="8" value="3" step="0.5">
<span id="settingsMinRAMLabel" class="settingsMemoryLabel">3G</span> <div class="rangeSliderBar"></div>
</div> <div class="rangeSliderTrack"></div>
</div> </div>
<div id="settingsMemoryDesc">The recommended minimum RAM is 3 gigabytes. Setting the minimum and maximum values to the same value may reduce lag.</div> <span id="settingsMinRAMLabel" class="settingsMemoryLabel">3G</span>
</div> </div>
<div id="settingsMemoryContentRight"> </div>
<div id="settingsMemoryStatus"> <div id="settingsMemoryDesc">La RAM minimale recommandée est de 3Go. Le réglage des valeurs minimum et maximum sur la même valeur peut réduire le lag.</div>
<div class="settingsMemoryStatusContainer"> </div>
<span class="settingsMemoryStatusTitle">Total</span> <div id="settingsMemoryContentRight">
<span id="settingsMemoryTotal" class="settingsMemoryStatusValue">16G</span> <div id="settingsMemoryStatus">
</div> <div class="settingsMemoryStatusContainer">
<div class="settingsMemoryStatusContainer"> <span class="settingsMemoryStatusTitle">Total</span>
<span class="settingsMemoryStatusTitle">Available</span> <span id="settingsMemoryTotal" class="settingsMemoryStatusValue">16G</span>
<span id="settingsMemoryAvail" class="settingsMemoryStatusValue">7.3G</span> </div>
</div> <div class="settingsMemoryStatusContainer">
</div> <span class="settingsMemoryStatusTitle">Disponnible</span>
</div> <span id="settingsMemoryAvail" class="settingsMemoryStatusValue">7.3G</span>
</div> </div>
</div> </div>
<div class="settingsFileSelContainer"> </div>
<div class="settingsFileSelTitle">Java Executable</div> </div>
<div class="settingsFileSelContent"> </div>
<div id="settingsJavaExecDetails">Selected: Java 8 Update 172 (x64)</div> <div class="settingsFileSelContainer">
<div class="settingsFileSelActions"> <div class="settingsFileSelTitle">Executable Java</div>
<div class="settingsFileSelIcon"> <div class="settingsFileSelContent">
<svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001"> <div id="settingsJavaExecDetails">Selected: Java 8 Update 172 (x64)</div>
<g> <div class="settingsFileSelActions">
<path d="M150.99,56.513c-14.093,9.912-30.066,21.147-38.624,39.734c-14.865,32.426,30.418,67.798,32.353,69.288c0.45,0.347,0.988,0.519,1.525,0.519c0.57,0,1.141-0.195,1.605-0.583c0.899-0.752,1.154-2.029,0.614-3.069c-0.164-0.316-16.418-31.888-15.814-54.539c0.214-7.888,11.254-16.837,22.942-26.312c10.705-8.678,22.839-18.514,29.939-30.02c15.586-25.327-1.737-50.231-1.914-50.479c-0.688-0.966-1.958-1.317-3.044-0.84c-1.085,0.478-1.686,1.652-1.438,2.811c0.035,0.164,3.404,16.633-5.97,33.6C169.301,43.634,160.816,49.603,150.99,56.513z"></path> <div class="settingsFileSelIcon">
<path d="M210.365,67.682c0.994-0.749,1.286-2.115,0.684-3.205c-0.602-1.09-1.913-1.571-3.077-1.129c-2.394,0.91-58.627,22.585-58.627,48.776c0,18.053,7.712,27.591,13.343,34.556c2.209,2.731,4.116,5.09,4.744,7.104c1.769,5.804-2.422,16.294-4.184,19.846c-0.508,1.022-0.259,2.259,0.605,3.005c0.467,0.403,1.05,0.607,1.634,0.607c0.497,0,0.996-0.148,1.427-0.448c0.967-0.673,23.63-16.696,19.565-36.001c-1.514-7.337-5.12-12.699-8.302-17.43c-4.929-7.329-8.489-12.624-3.088-22.403C181.419,89.556,210.076,67.899,210.365,67.682z"></path> <svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001">
<path d="M63.99,177.659c-0.964,2.885-0.509,5.75,1.315,8.283c6.096,8.462,27.688,13.123,60.802,13.123c0.002,0,0.003,0,0.004,0c4.487,0,9.224-0.088,14.076-0.262c52.943-1.896,72.58-18.389,73.39-19.09c0.883-0.764,1.119-2.037,0.57-3.067c-0.549-1.029-1.733-1.546-2.864-1.235c-18.645,5.091-53.463,6.898-77.613,6.898c-27.023,0-40.785-1.946-44.154-3.383c1.729-2.374,12.392-6.613,25.605-9.212c1.263-0.248,2.131-1.414,2.006-2.695c-0.125-1.281-1.201-2.258-2.488-2.258C106.893,164.762,68.05,165.384,63.99,177.659z"></path> <g>
<path d="M241.148,160.673c-10.92,0-21.275,5.472-21.711,5.705c-1.01,0.541-1.522,1.699-1.245,2.811c0.278,1.111,1.277,1.892,2.423,1.893c0.232,0.001,23.293,0.189,25.382,13.365c1.85,11.367-21.82,29.785-31.097,35.923c-1.002,0.663-1.391,1.945-0.926,3.052c0.395,0.943,1.314,1.533,2.304,1.533c0.173,0,0.348-0.018,0.522-0.056c2.202-0.47,53.855-11.852,48.394-41.927C261.862,164.541,250.278,160.673,241.148,160.673z"></path> <path d="M150.99,56.513c-14.093,9.912-30.066,21.147-38.624,39.734c-14.865,32.426,30.418,67.798,32.353,69.288c0.45,0.347,0.988,0.519,1.525,0.519c0.57,0,1.141-0.195,1.605-0.583c0.899-0.752,1.154-2.029,0.614-3.069c-0.164-0.316-16.418-31.888-15.814-54.539c0.214-7.888,11.254-16.837,22.942-26.312c10.705-8.678,22.839-18.514,29.939-30.02c15.586-25.327-1.737-50.231-1.914-50.479c-0.688-0.966-1.958-1.317-3.044-0.84c-1.085,0.478-1.686,1.652-1.438,2.811c0.035,0.164,3.404,16.633-5.97,33.6C169.301,43.634,160.816,49.603,150.99,56.513z"></path>
<path d="M205.725,216.69c0.18-0.964-0.221-1.944-1.023-2.506l-12.385-8.675c-0.604-0.423-1.367-0.556-2.076-0.368c-0.129,0.034-13.081,3.438-31.885,5.526c-7.463,0.837-15.822,1.279-24.175,1.279c-18.799,0-31.091-2.209-32.881-3.829c-0.237-0.455-0.162-0.662-0.12-0.777c0.325-0.905,2.068-1.98,3.192-2.405c1.241-0.459,1.91-1.807,1.524-3.073c-0.385-1.266-1.69-2.012-2.978-1.702c-12.424,2.998-18.499,7.191-18.057,12.461c0.785,9.343,22.428,14.139,40.725,15.408c2.631,0.18,5.477,0.272,8.456,0.272c0.002,0,0.003,0,0.005,0c30.425,0,69.429-9.546,69.819-9.643C204.818,218.423,205.544,217.654,205.725,216.69z"></path> <path d="M210.365,67.682c0.994-0.749,1.286-2.115,0.684-3.205c-0.602-1.09-1.913-1.571-3.077-1.129c-2.394,0.91-58.627,22.585-58.627,48.776c0,18.053,7.712,27.591,13.343,34.556c2.209,2.731,4.116,5.09,4.744,7.104c1.769,5.804-2.422,16.294-4.184,19.846c-0.508,1.022-0.259,2.259,0.605,3.005c0.467,0.403,1.05,0.607,1.634,0.607c0.497,0,0.996-0.148,1.427-0.448c0.967-0.673,23.63-16.696,19.565-36.001c-1.514-7.337-5.12-12.699-8.302-17.43c-4.929-7.329-8.489-12.624-3.088-22.403C181.419,89.556,210.076,67.899,210.365,67.682z"></path>
<path d="M112.351,236.745c0.938-0.611,1.354-1.77,1.021-2.838c-0.332-1.068-1.331-1.769-2.453-1.755c-1.665,0.044-16.292,0.704-17.316,10.017c-0.31,2.783,0.487,5.325,2.37,7.556c5.252,6.224,19.428,9.923,43.332,11.31c2.828,0.169,5.7,0.254,8.539,0.254c30.39,0,50.857-9.515,51.714-9.92c0.831-0.393,1.379-1.209,1.428-2.127c0.049-0.917-0.409-1.788-1.193-2.267l-15.652-9.555c-0.543-0.331-1.193-0.441-1.813-0.314c-0.099,0.021-10.037,2.082-25.035,4.119c-2.838,0.385-6.392,0.581-10.562,0.581c-14.982,0-31.646-2.448-34.842-4.05C111.843,237.455,111.902,237.075,112.351,236.745z"></path> <path d="M63.99,177.659c-0.964,2.885-0.509,5.75,1.315,8.283c6.096,8.462,27.688,13.123,60.802,13.123c0.002,0,0.003,0,0.004,0c4.487,0,9.224-0.088,14.076-0.262c52.943-1.896,72.58-18.389,73.39-19.09c0.883-0.764,1.119-2.037,0.57-3.067c-0.549-1.029-1.733-1.546-2.864-1.235c-18.645,5.091-53.463,6.898-77.613,6.898c-27.023,0-40.785-1.946-44.154-3.383c1.729-2.374,12.392-6.613,25.605-9.212c1.263-0.248,2.131-1.414,2.006-2.695c-0.125-1.281-1.201-2.258-2.488-2.258C106.893,164.762,68.05,165.384,63.99,177.659z"></path>
<path d="M133.681,290.018c69.61-0.059,106.971-12.438,114.168-20.228c2.548-2.757,2.823-5.366,2.606-7.07c-0.535-4.194-4.354-6.761-4.788-7.04c-1.045-0.672-2.447-0.496-3.262,0.444c-0.813,0.941-0.832,2.314-0.016,3.253c0.439,0.565,0.693,1.51-0.591,2.795c-2.877,2.687-31.897,10.844-80.215,13.294c-6.619,0.345-13.561,0.519-20.633,0.52c-43.262,0-74.923-5.925-79.079-9.379c1.603-2.301,12.801-5.979,24.711-8.058c1.342-0.234,2.249-1.499,2.041-2.845c-0.208-1.346-1.449-2.273-2.805-2.096c-0.336,0.045-1.475,0.115-2.796,0.195c-19.651,1.2-42.36,3.875-43.545,13.999c-0.36,3.086,0.557,5.886,2.726,8.324c5.307,5.963,20.562,13.891,91.475,13.891C133.68,290.018,133.68,290.018,133.681,290.018z"></path> <path d="M241.148,160.673c-10.92,0-21.275,5.472-21.711,5.705c-1.01,0.541-1.522,1.699-1.245,2.811c0.278,1.111,1.277,1.892,2.423,1.893c0.232,0.001,23.293,0.189,25.382,13.365c1.85,11.367-21.82,29.785-31.097,35.923c-1.002,0.663-1.391,1.945-0.926,3.052c0.395,0.943,1.314,1.533,2.304,1.533c0.173,0,0.348-0.018,0.522-0.056c2.202-0.47,53.855-11.852,48.394-41.927C261.862,164.541,250.278,160.673,241.148,160.673z"></path>
<path d="M261.522,271.985c-0.984-0.455-2.146-0.225-2.881,0.567c-0.103,0.11-10.568,11.054-42.035,17.48c-12.047,2.414-34.66,3.638-67.211,3.638c-32.612,0-63.643-1.283-63.953-1.296c-1.296-0.063-2.405,0.879-2.581,2.155c-0.177,1.276,0.645,2.477,1.897,2.775c0.323,0.077,32.844,7.696,77.31,7.696c21.327,0,42.08-1.733,61.684-5.151c36.553-6.408,39.112-24.533,39.203-25.301C263.082,273.474,262.504,272.44,261.522,271.985z"></path> <path d="M205.725,216.69c0.18-0.964-0.221-1.944-1.023-2.506l-12.385-8.675c-0.604-0.423-1.367-0.556-2.076-0.368c-0.129,0.034-13.081,3.438-31.885,5.526c-7.463,0.837-15.822,1.279-24.175,1.279c-18.799,0-31.091-2.209-32.881-3.829c-0.237-0.455-0.162-0.662-0.12-0.777c0.325-0.905,2.068-1.98,3.192-2.405c1.241-0.459,1.91-1.807,1.524-3.073c-0.385-1.266-1.69-2.012-2.978-1.702c-12.424,2.998-18.499,7.191-18.057,12.461c0.785,9.343,22.428,14.139,40.725,15.408c2.631,0.18,5.477,0.272,8.456,0.272c0.002,0,0.003,0,0.005,0c30.425,0,69.429-9.546,69.819-9.643C204.818,218.423,205.544,217.654,205.725,216.69z"></path>
</g> <path d="M112.351,236.745c0.938-0.611,1.354-1.77,1.021-2.838c-0.332-1.068-1.331-1.769-2.453-1.755c-1.665,0.044-16.292,0.704-17.316,10.017c-0.31,2.783,0.487,5.325,2.37,7.556c5.252,6.224,19.428,9.923,43.332,11.31c2.828,0.169,5.7,0.254,8.539,0.254c30.39,0,50.857-9.515,51.714-9.92c0.831-0.393,1.379-1.209,1.428-2.127c0.049-0.917-0.409-1.788-1.193-2.267l-15.652-9.555c-0.543-0.331-1.193-0.441-1.813-0.314c-0.099,0.021-10.037,2.082-25.035,4.119c-2.838,0.385-6.392,0.581-10.562,0.581c-14.982,0-31.646-2.448-34.842-4.05C111.843,237.455,111.902,237.075,112.351,236.745z"></path>
</svg> <path d="M133.681,290.018c69.61-0.059,106.971-12.438,114.168-20.228c2.548-2.757,2.823-5.366,2.606-7.07c-0.535-4.194-4.354-6.761-4.788-7.04c-1.045-0.672-2.447-0.496-3.262,0.444c-0.813,0.941-0.832,2.314-0.016,3.253c0.439,0.565,0.693,1.51-0.591,2.795c-2.877,2.687-31.897,10.844-80.215,13.294c-6.619,0.345-13.561,0.519-20.633,0.52c-43.262,0-74.923-5.925-79.079-9.379c1.603-2.301,12.801-5.979,24.711-8.058c1.342-0.234,2.249-1.499,2.041-2.845c-0.208-1.346-1.449-2.273-2.805-2.096c-0.336,0.045-1.475,0.115-2.796,0.195c-19.651,1.2-42.36,3.875-43.545,13.999c-0.36,3.086,0.557,5.886,2.726,8.324c5.307,5.963,20.562,13.891,91.475,13.891C133.68,290.018,133.68,290.018,133.681,290.018z"></path>
</div> <path d="M261.522,271.985c-0.984-0.455-2.146-0.225-2.881,0.567c-0.103,0.11-10.568,11.054-42.035,17.48c-12.047,2.414-34.66,3.638-67.211,3.638c-32.612,0-63.643-1.283-63.953-1.296c-1.296-0.063-2.405,0.879-2.581,2.155c-0.177,1.276,0.645,2.477,1.897,2.775c0.323,0.077,32.844,7.696,77.31,7.696c21.327,0,42.08-1.733,61.684-5.151c36.553-6.408,39.112-24.533,39.203-25.301C263.082,273.474,262.504,272.44,261.522,271.985z"></path>
<input class="settingsFileSelVal" id="settingsJavaExecVal" type="text" value="null" cValue="JavaExecutable" disabled> </g>
<button class="settingsFileSelButton" id="settingsJavaExecSel" dialogTitle="Select Java Executable" dialogDirectory="false">Choose File</button> </svg>
</div> </div>
</div> <input class="settingsFileSelVal" id="settingsJavaExecVal" type="text" value="null" cValue="JavaExecutable" disabled>
<div class="settingsFileSelDesc">The Java executable is validated before game launch. <strong>Requires Java 8 x64.</strong><br>The path should end with <strong>bin<%= process.platform === 'win32' ? '\\javaw.exe' : '/java' %></strong>.</div> <button class="settingsFileSelButton" id="settingsJavaExecSel" dialogTitle="Select Java Executable" dialogDirectory="false">Choisir un fichier</button>
</div> </div>
<div id="settingsJVMOptsContainer"> </div>
<div id="settingsJVMOptsTitle">Additional JVM Options</div> <div class="settingsFileSelDesc">L'exécutable Java est validé avant le lancement du jeu. <strong>Java 8 x64 requis</strong><br>Le chemin doit se finir par <strong>bin<%= process.platform === 'win32' ? '\\javaw.exe' : '/java' %></strong>.</div>
<div id="settingsJVMOptsContent"> </div>
<div class="settingsFileSelIcon"> <div id="settingsJVMOptsContainer">
<svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001"> <div id="settingsJVMOptsTitle">Paramètres additionels JVM</div>
<g> <div id="settingsJVMOptsContent">
<path d="M150.99,56.513c-14.093,9.912-30.066,21.147-38.624,39.734c-14.865,32.426,30.418,67.798,32.353,69.288c0.45,0.347,0.988,0.519,1.525,0.519c0.57,0,1.141-0.195,1.605-0.583c0.899-0.752,1.154-2.029,0.614-3.069c-0.164-0.316-16.418-31.888-15.814-54.539c0.214-7.888,11.254-16.837,22.942-26.312c10.705-8.678,22.839-18.514,29.939-30.02c15.586-25.327-1.737-50.231-1.914-50.479c-0.688-0.966-1.958-1.317-3.044-0.84c-1.085,0.478-1.686,1.652-1.438,2.811c0.035,0.164,3.404,16.633-5.97,33.6C169.301,43.634,160.816,49.603,150.99,56.513z"></path> <div class="settingsFileSelIcon">
<path d="M210.365,67.682c0.994-0.749,1.286-2.115,0.684-3.205c-0.602-1.09-1.913-1.571-3.077-1.129c-2.394,0.91-58.627,22.585-58.627,48.776c0,18.053,7.712,27.591,13.343,34.556c2.209,2.731,4.116,5.09,4.744,7.104c1.769,5.804-2.422,16.294-4.184,19.846c-0.508,1.022-0.259,2.259,0.605,3.005c0.467,0.403,1.05,0.607,1.634,0.607c0.497,0,0.996-0.148,1.427-0.448c0.967-0.673,23.63-16.696,19.565-36.001c-1.514-7.337-5.12-12.699-8.302-17.43c-4.929-7.329-8.489-12.624-3.088-22.403C181.419,89.556,210.076,67.899,210.365,67.682z"></path> <svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001">
<path d="M63.99,177.659c-0.964,2.885-0.509,5.75,1.315,8.283c6.096,8.462,27.688,13.123,60.802,13.123c0.002,0,0.003,0,0.004,0c4.487,0,9.224-0.088,14.076-0.262c52.943-1.896,72.58-18.389,73.39-19.09c0.883-0.764,1.119-2.037,0.57-3.067c-0.549-1.029-1.733-1.546-2.864-1.235c-18.645,5.091-53.463,6.898-77.613,6.898c-27.023,0-40.785-1.946-44.154-3.383c1.729-2.374,12.392-6.613,25.605-9.212c1.263-0.248,2.131-1.414,2.006-2.695c-0.125-1.281-1.201-2.258-2.488-2.258C106.893,164.762,68.05,165.384,63.99,177.659z"></path> <g>
<path d="M241.148,160.673c-10.92,0-21.275,5.472-21.711,5.705c-1.01,0.541-1.522,1.699-1.245,2.811c0.278,1.111,1.277,1.892,2.423,1.893c0.232,0.001,23.293,0.189,25.382,13.365c1.85,11.367-21.82,29.785-31.097,35.923c-1.002,0.663-1.391,1.945-0.926,3.052c0.395,0.943,1.314,1.533,2.304,1.533c0.173,0,0.348-0.018,0.522-0.056c2.202-0.47,53.855-11.852,48.394-41.927C261.862,164.541,250.278,160.673,241.148,160.673z"></path> <path d="M150.99,56.513c-14.093,9.912-30.066,21.147-38.624,39.734c-14.865,32.426,30.418,67.798,32.353,69.288c0.45,0.347,0.988,0.519,1.525,0.519c0.57,0,1.141-0.195,1.605-0.583c0.899-0.752,1.154-2.029,0.614-3.069c-0.164-0.316-16.418-31.888-15.814-54.539c0.214-7.888,11.254-16.837,22.942-26.312c10.705-8.678,22.839-18.514,29.939-30.02c15.586-25.327-1.737-50.231-1.914-50.479c-0.688-0.966-1.958-1.317-3.044-0.84c-1.085,0.478-1.686,1.652-1.438,2.811c0.035,0.164,3.404,16.633-5.97,33.6C169.301,43.634,160.816,49.603,150.99,56.513z"></path>
<path d="M205.725,216.69c0.18-0.964-0.221-1.944-1.023-2.506l-12.385-8.675c-0.604-0.423-1.367-0.556-2.076-0.368c-0.129,0.034-13.081,3.438-31.885,5.526c-7.463,0.837-15.822,1.279-24.175,1.279c-18.799,0-31.091-2.209-32.881-3.829c-0.237-0.455-0.162-0.662-0.12-0.777c0.325-0.905,2.068-1.98,3.192-2.405c1.241-0.459,1.91-1.807,1.524-3.073c-0.385-1.266-1.69-2.012-2.978-1.702c-12.424,2.998-18.499,7.191-18.057,12.461c0.785,9.343,22.428,14.139,40.725,15.408c2.631,0.18,5.477,0.272,8.456,0.272c0.002,0,0.003,0,0.005,0c30.425,0,69.429-9.546,69.819-9.643C204.818,218.423,205.544,217.654,205.725,216.69z"></path> <path d="M210.365,67.682c0.994-0.749,1.286-2.115,0.684-3.205c-0.602-1.09-1.913-1.571-3.077-1.129c-2.394,0.91-58.627,22.585-58.627,48.776c0,18.053,7.712,27.591,13.343,34.556c2.209,2.731,4.116,5.09,4.744,7.104c1.769,5.804-2.422,16.294-4.184,19.846c-0.508,1.022-0.259,2.259,0.605,3.005c0.467,0.403,1.05,0.607,1.634,0.607c0.497,0,0.996-0.148,1.427-0.448c0.967-0.673,23.63-16.696,19.565-36.001c-1.514-7.337-5.12-12.699-8.302-17.43c-4.929-7.329-8.489-12.624-3.088-22.403C181.419,89.556,210.076,67.899,210.365,67.682z"></path>
<path d="M112.351,236.745c0.938-0.611,1.354-1.77,1.021-2.838c-0.332-1.068-1.331-1.769-2.453-1.755c-1.665,0.044-16.292,0.704-17.316,10.017c-0.31,2.783,0.487,5.325,2.37,7.556c5.252,6.224,19.428,9.923,43.332,11.31c2.828,0.169,5.7,0.254,8.539,0.254c30.39,0,50.857-9.515,51.714-9.92c0.831-0.393,1.379-1.209,1.428-2.127c0.049-0.917-0.409-1.788-1.193-2.267l-15.652-9.555c-0.543-0.331-1.193-0.441-1.813-0.314c-0.099,0.021-10.037,2.082-25.035,4.119c-2.838,0.385-6.392,0.581-10.562,0.581c-14.982,0-31.646-2.448-34.842-4.05C111.843,237.455,111.902,237.075,112.351,236.745z"></path> <path d="M63.99,177.659c-0.964,2.885-0.509,5.75,1.315,8.283c6.096,8.462,27.688,13.123,60.802,13.123c0.002,0,0.003,0,0.004,0c4.487,0,9.224-0.088,14.076-0.262c52.943-1.896,72.58-18.389,73.39-19.09c0.883-0.764,1.119-2.037,0.57-3.067c-0.549-1.029-1.733-1.546-2.864-1.235c-18.645,5.091-53.463,6.898-77.613,6.898c-27.023,0-40.785-1.946-44.154-3.383c1.729-2.374,12.392-6.613,25.605-9.212c1.263-0.248,2.131-1.414,2.006-2.695c-0.125-1.281-1.201-2.258-2.488-2.258C106.893,164.762,68.05,165.384,63.99,177.659z"></path>
<path d="M133.681,290.018c69.61-0.059,106.971-12.438,114.168-20.228c2.548-2.757,2.823-5.366,2.606-7.07c-0.535-4.194-4.354-6.761-4.788-7.04c-1.045-0.672-2.447-0.496-3.262,0.444c-0.813,0.941-0.832,2.314-0.016,3.253c0.439,0.565,0.693,1.51-0.591,2.795c-2.877,2.687-31.897,10.844-80.215,13.294c-6.619,0.345-13.561,0.519-20.633,0.52c-43.262,0-74.923-5.925-79.079-9.379c1.603-2.301,12.801-5.979,24.711-8.058c1.342-0.234,2.249-1.499,2.041-2.845c-0.208-1.346-1.449-2.273-2.805-2.096c-0.336,0.045-1.475,0.115-2.796,0.195c-19.651,1.2-42.36,3.875-43.545,13.999c-0.36,3.086,0.557,5.886,2.726,8.324c5.307,5.963,20.562,13.891,91.475,13.891C133.68,290.018,133.68,290.018,133.681,290.018z"></path> <path d="M241.148,160.673c-10.92,0-21.275,5.472-21.711,5.705c-1.01,0.541-1.522,1.699-1.245,2.811c0.278,1.111,1.277,1.892,2.423,1.893c0.232,0.001,23.293,0.189,25.382,13.365c1.85,11.367-21.82,29.785-31.097,35.923c-1.002,0.663-1.391,1.945-0.926,3.052c0.395,0.943,1.314,1.533,2.304,1.533c0.173,0,0.348-0.018,0.522-0.056c2.202-0.47,53.855-11.852,48.394-41.927C261.862,164.541,250.278,160.673,241.148,160.673z"></path>
<path d="M261.522,271.985c-0.984-0.455-2.146-0.225-2.881,0.567c-0.103,0.11-10.568,11.054-42.035,17.48c-12.047,2.414-34.66,3.638-67.211,3.638c-32.612,0-63.643-1.283-63.953-1.296c-1.296-0.063-2.405,0.879-2.581,2.155c-0.177,1.276,0.645,2.477,1.897,2.775c0.323,0.077,32.844,7.696,77.31,7.696c21.327,0,42.08-1.733,61.684-5.151c36.553-6.408,39.112-24.533,39.203-25.301C263.082,273.474,262.504,272.44,261.522,271.985z"></path> <path d="M205.725,216.69c0.18-0.964-0.221-1.944-1.023-2.506l-12.385-8.675c-0.604-0.423-1.367-0.556-2.076-0.368c-0.129,0.034-13.081,3.438-31.885,5.526c-7.463,0.837-15.822,1.279-24.175,1.279c-18.799,0-31.091-2.209-32.881-3.829c-0.237-0.455-0.162-0.662-0.12-0.777c0.325-0.905,2.068-1.98,3.192-2.405c1.241-0.459,1.91-1.807,1.524-3.073c-0.385-1.266-1.69-2.012-2.978-1.702c-12.424,2.998-18.499,7.191-18.057,12.461c0.785,9.343,22.428,14.139,40.725,15.408c2.631,0.18,5.477,0.272,8.456,0.272c0.002,0,0.003,0,0.005,0c30.425,0,69.429-9.546,69.819-9.643C204.818,218.423,205.544,217.654,205.725,216.69z"></path>
</g> <path d="M112.351,236.745c0.938-0.611,1.354-1.77,1.021-2.838c-0.332-1.068-1.331-1.769-2.453-1.755c-1.665,0.044-16.292,0.704-17.316,10.017c-0.31,2.783,0.487,5.325,2.37,7.556c5.252,6.224,19.428,9.923,43.332,11.31c2.828,0.169,5.7,0.254,8.539,0.254c30.39,0,50.857-9.515,51.714-9.92c0.831-0.393,1.379-1.209,1.428-2.127c0.049-0.917-0.409-1.788-1.193-2.267l-15.652-9.555c-0.543-0.331-1.193-0.441-1.813-0.314c-0.099,0.021-10.037,2.082-25.035,4.119c-2.838,0.385-6.392,0.581-10.562,0.581c-14.982,0-31.646-2.448-34.842-4.05C111.843,237.455,111.902,237.075,112.351,236.745z"></path>
</svg> <path d="M133.681,290.018c69.61-0.059,106.971-12.438,114.168-20.228c2.548-2.757,2.823-5.366,2.606-7.07c-0.535-4.194-4.354-6.761-4.788-7.04c-1.045-0.672-2.447-0.496-3.262,0.444c-0.813,0.941-0.832,2.314-0.016,3.253c0.439,0.565,0.693,1.51-0.591,2.795c-2.877,2.687-31.897,10.844-80.215,13.294c-6.619,0.345-13.561,0.519-20.633,0.52c-43.262,0-74.923-5.925-79.079-9.379c1.603-2.301,12.801-5.979,24.711-8.058c1.342-0.234,2.249-1.499,2.041-2.845c-0.208-1.346-1.449-2.273-2.805-2.096c-0.336,0.045-1.475,0.115-2.796,0.195c-19.651,1.2-42.36,3.875-43.545,13.999c-0.36,3.086,0.557,5.886,2.726,8.324c5.307,5.963,20.562,13.891,91.475,13.891C133.68,290.018,133.68,290.018,133.681,290.018z"></path>
</div> <path d="M261.522,271.985c-0.984-0.455-2.146-0.225-2.881,0.567c-0.103,0.11-10.568,11.054-42.035,17.48c-12.047,2.414-34.66,3.638-67.211,3.638c-32.612,0-63.643-1.283-63.953-1.296c-1.296-0.063-2.405,0.879-2.581,2.155c-0.177,1.276,0.645,2.477,1.897,2.775c0.323,0.077,32.844,7.696,77.31,7.696c21.327,0,42.08-1.733,61.684-5.151c36.553-6.408,39.112-24.533,39.203-25.301C263.082,273.474,262.504,272.44,261.522,271.985z"></path>
<input id="settingsJVMOptsVal" cValue="JVMOptions" type="text"> </g>
</div> </svg>
<div id="settingsJVMOptsDesc">Options to be provided to the JVM at runtime. <em>-Xms</em> and <em>-Xmx</em> should not be included.<br><a href="https://docs.oracle.com/javase/8/docs/technotes/tools/<%= process.platform === 'win32' ? 'windows' : 'unix' %>/java.html">Available Options for Java 8</a>.</div> </div>
</div> <input id="settingsJVMOptsVal" cValue="JVMOptions" type="text">
</div> </div>
<div id="settingsTabLauncher" class="settingsTab" style="display: none;"> <div id="settingsJVMOptsDesc">Options de lancement pour le JVM. <em>-Xms</em> and <em>-Xmx</em> ne doivent pas êtres inclut.<br><a href="https://docs.oracle.com/javase/8/docs/technotes/tools/<%= process.platform === 'win32' ? 'windows' : 'unix' %>/java.html">Options additionels pour Java 8</a>.</div>
<div class="settingsTabHeader"> </div>
<span class="settingsTabHeaderText">Launcher Settings</span> </div>
<span class="settingsTabHeaderDesc">Options related to the launcher itself.</span> <div id="settingsTabLauncher" class="settingsTab" style="display: none;">
</div> <div class="settingsTabHeader">
<div class="settingsFieldContainer"> <span class="settingsTabHeaderText">Paramètres du Launcher</span>
<div class="settingsFieldLeft"> <span class="settingsTabHeaderDesc">Options relatives au launcher lui même.</span>
<span class="settingsFieldTitle">Allow Pre-Release Updates.</span> </div>
<span class="settingsFieldDesc">Pre-Releases include new features which may have not been fully tested or integrated.<br>This will always be true if you are using a pre-release version.</span> <!-- <div class="settingsFieldContainer">
</div> <div class="settingsFieldLeft">
<div class="settingsFieldRight"> <span class="settingsFieldTitle">Allow Pre-Release Updates.</span>
<label class="toggleSwitch"> <span class="settingsFieldDesc">Pre-Releases include new features which may have not been fully tested or integrated.<br>This will always be true if you are using a pre-release version.</span>
<input type="checkbox" cValue="AllowPrerelease"> </div>
<span class="toggleSwitchSlider"></span> <div class="settingsFieldRight">
</label> <label class="toggleSwitch">
</div> <input type="checkbox" cValue="AllowPrerelease">
</div> <span class="toggleSwitchSlider"></span>
<div class="settingsFileSelContainer"> </label>
<div class="settingsFileSelContent"> </div>
<div class="settingsFieldTitle" id="settingsDataDirTitle">Data Directory</div> </div> -->
<div class="settingsFileSelActions"> <div class="settingsFileSelContainer">
<div class="settingsFileSelIcon"> <div class="settingsFileSelContent">
<svg class="settingsFileSelSVG"> <div class="settingsFieldTitle" id="settingsDataDirTitle">Dossier de données</div>
<g> <div class="settingsFileSelActions">
<path fill="gray" d="m10.044745,5c0,0.917174 -0.746246,1.667588 -1.667588,1.667588l-4.168971,0l-2.501382,0c-0.921009,0 -1.667588,0.750415 -1.667588,1.667588l0,6.670353l0,2.501382c0,0.917174 0.746604,1.667588 1.667588,1.667588l16.675882,0c0.921342,0 1.667588,-0.750415 1.667588,-1.667588l0,-2.501382l0,-8.337941c0,-0.917174 -0.746246,-1.667588 -1.667588,-1.667588l-8.337941,0z"/> <div class="settingsFileSelIcon">
<path fill="gray" d="m1.627815,1.6c-0.921009,0 -1.667588,0.746579 -1.667588,1.667588l0,4.168971l8.337941,0l0,0.833794l11.673118,0l0,-4.168971c0,-0.921009 -0.746246,-1.667588 -1.667588,-1.667588l-8.572237,0c-0.288493,-0.497692 -0.816284,-0.833794 -1.433292,-0.833794l-6.670353,0z"/> <svg class="settingsFileSelSVG">
<path fill="lightgray" d="m10.025276,4c0,0.918984 -0.747719,1.670879 -1.670879,1.670879l-4.177198,0l-2.506319,0c-0.922827,0 -1.670879,0.751896 -1.670879,1.670879l0,6.683517l0,2.506319c0,0.918984 0.748078,1.670879 1.670879,1.670879l16.708794,0c0.923161,0 1.670879,-0.751896 1.670879,-1.670879l0,-2.506319l0,-8.354397c0,-0.918984 -0.747719,-1.670879 -1.670879,-1.670879l-8.354397,0z"/> <g>
</g> <path fill="gray" d="m10.044745,5c0,0.917174 -0.746246,1.667588 -1.667588,1.667588l-4.168971,0l-2.501382,0c-0.921009,0 -1.667588,0.750415 -1.667588,1.667588l0,6.670353l0,2.501382c0,0.917174 0.746604,1.667588 1.667588,1.667588l16.675882,0c0.921342,0 1.667588,-0.750415 1.667588,-1.667588l0,-2.501382l0,-8.337941c0,-0.917174 -0.746246,-1.667588 -1.667588,-1.667588l-8.337941,0z"/>
</svg> <path fill="gray" d="m1.627815,1.6c-0.921009,0 -1.667588,0.746579 -1.667588,1.667588l0,4.168971l8.337941,0l0,0.833794l11.673118,0l0,-4.168971c0,-0.921009 -0.746246,-1.667588 -1.667588,-1.667588l-8.572237,0c-0.288493,-0.497692 -0.816284,-0.833794 -1.433292,-0.833794l-6.670353,0z"/>
</div> <path fill="lightgray" d="m10.025276,4c0,0.918984 -0.747719,1.670879 -1.670879,1.670879l-4.177198,0l-2.506319,0c-0.922827,0 -1.670879,0.751896 -1.670879,1.670879l0,6.683517l0,2.506319c0,0.918984 0.748078,1.670879 1.670879,1.670879l16.708794,0c0.923161,0 1.670879,-0.751896 1.670879,-1.670879l0,-2.506319l0,-8.354397c0,-0.918984 -0.747719,-1.670879 -1.670879,-1.670879l-8.354397,0z"/>
<input class="settingsFileSelVal" type="text" value="null" cValue="DataDirectory" disabled> </g>
<button class="settingsFileSelButton" dialogTitle="Select Data Directory" dialogDirectory="true">Choose Folder</button> </svg>
</div> </div>
</div> <input class="settingsFileSelVal" type="text" value="null" cValue="DataDirectory" disabled>
<div class="settingsFileSelDesc">All game files and local Java installations will be stored in the data directory.<br>Screenshots and world saves are stored in the instance folder for the corresponding server configuration.</div> <button class="settingsFileSelButton" dialogTitle="Select Data Directory" dialogDirectory="true">Choisir un dossier</button>
</div> </div>
</div> </div>
<div id="settingsTabAbout" class="settingsTab" style="display: none;"> <div class="settingsFileSelDesc">Tous les fichiers de jeu et les installations Java locales seront stockés dans le dossier de données. <br> Les captures d'écran et les sauvegardes du monde sont stockées dans le dossier d'instance de la configuration de serveur correspondante.</div>
<div class="settingsTabHeader"> </div>
<span class="settingsTabHeaderText">About</span> </div>
<span class="settingsTabHeaderDesc">View information and release notes for the current version.</span> <div id="settingsTabAbout" class="settingsTab" style="display: none;">
</div> <div class="settingsTabHeader">
<div id="settingsAboutCurrentContainer"> <span class="settingsTabHeaderText">A Propos</span>
<div id="settingsAboutCurrentContent"> <span class="settingsTabHeaderDesc">Afficher les informations et les notes de version de la version actuelle.</span>
<div id="settingsAboutCurrentHeadline"> </div>
<img id="settingsAboutLogo" src="./assets/images/SealCircle.png"> <div id="settingsAboutCurrentContainer">
<span id="settingsAboutTitle">Helios Launcher</span> <div id="settingsAboutCurrentContent">
</div> <div id="settingsAboutCurrentHeadline">
<div id="settingsAboutCurrentVersion"> <img id="settingsAboutLogo" src="./assets/images/SealCircle.png">
<div id="settingsAboutCurrentVersionCheck">&#10003;</div> <span id="settingsAboutTitle">Launcher Creeponnia</span>
<div id="settingsAboutCurrentVersionDetails"> </div>
<span id="settingsAboutCurrentVersionTitle">Stable Release</span> <div id="settingsAboutCurrentVersion">
<div id="settingsAboutCurrentVersionLine"> <div id="settingsAboutCurrentVersionCheck">&#10003;</div>
<span id="settingsAboutCurrentVersionText">Version </span> <div id="settingsAboutCurrentVersionDetails">
<span id="settingsAboutCurrentVersionValue">0.0.1-alpha.12</span> <span id="settingsAboutCurrentVersionTitle">Stable Release</span>
</div> <div id="settingsAboutCurrentVersionLine">
</div> <span id="settingsAboutCurrentVersionText">Version </span>
</div> <span id="settingsAboutCurrentVersionValue">0.0.1-alpha.12</span>
</div> </div>
<div id="settingsAboutButtons"> </div>
<a href="https://github.com/dscalZi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Source (GitHub)</a> </div>
<!-- The following must be included in third-party usage. --> </div>
<!-- <a href="https://github.com/dscalzi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Original Source</a> --> <div id="settingsAboutButtons">
<a href="https://github.com/dscalZi/HeliosLauncher/issues" id="settingsAboutSupportButton" class="settingsAboutButton">Support</a> <a href="https://github.com/dscalZi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Source (GitHub)</a>
<a href="#" id="settingsAboutDevToolsButton" class="settingsAboutButton">DevTools Console</a> <!-- The following must be included in third-party usage. -->
</div> <!-- <a href="https://github.com/dscalzi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Original Source</a> -->
</div> <a href="https://github.com/dscalZi/HeliosLauncher/issues" id="settingsAboutSupportButton" class="settingsAboutButton">Support</a>
<div class="settingsChangelogContainer"> <a href="#" id="settingsAboutDevToolsButton" class="settingsAboutButton">DevTools Console</a>
<div class="settingsChangelogContent"> </div>
<div class="settingsChangelogHeadline"> </div>
<div class="settingsChangelogLabel">Release Notes</div> <div class="settingsChangelogContainer">
<div class="settingsChangelogTitle">Changelog</div> <div class="settingsChangelogContent">
</div> <div class="settingsChangelogHeadline">
<div class="settingsChangelogText"> <div class="settingsChangelogLabel">Release Notes</div>
No Release Notes <div class="settingsChangelogTitle">Changelog</div>
</div> </div>
</div> <div class="settingsChangelogText">
<div class="settingsChangelogActions"> No Release Notes
<a class="settingsChangelogButton settingsAboutButton" href="#">View Release Notes on GitHub</a> </div>
</div> </div>
</div> <div class="settingsChangelogActions">
</div> <a class="settingsChangelogButton settingsAboutButton" href="#">View Release Notes on GitHub</a>
<div id="settingsTabUpdate" class="settingsTab" style="display: none;"> </div>
<div class="settingsTabHeader"> </div>
<span class="settingsTabHeaderText">Launcher Updates</span> </div>
<span class="settingsTabHeaderDesc">Download, install, and review updates for the launcher.</span> <div id="settingsTabUpdate" class="settingsTab" style="display: none;">
</div> <div class="settingsTabHeader">
<div id="settingsUpdateStatusContainer"> <span class="settingsTabHeaderText">Mise à jour du Launcher</span>
<div id="settingsUpdateStatusContent"> <span class="settingsTabHeaderDesc">Téléchargez, installez et passez en revue les mises à jour du lanceur.</span>
<div id="settingsUpdateStatusHeadline"> </div>
<span id="settingsUpdateTitle">You Are Running the Latest Version</span> <div id="settingsUpdateStatusContainer">
</div> <div id="settingsUpdateStatusContent">
<div id="settingsUpdateVersion"> <div id="settingsUpdateStatusHeadline">
<div id="settingsUpdateVersionCheck">&#10003;</div> <span id="settingsUpdateTitle">Vous exécutez la dernière version</span>
<div id="settingsUpdateVersionDetails"> </div>
<span id="settingsUpdateVersionTitle">Stable Release</span> <div id="settingsUpdateVersion">
<div id="settingsUpdateVersionLine"> <div id="settingsUpdateVersionCheck">&#10003;</div>
<span id="settingsUpdateVersionText">Version </span> <div id="settingsUpdateVersionDetails">
<span id="settingsUpdateVersionValue">0.0.1-alpha.18</span> <span id="settingsUpdateVersionTitle">Version Stable</span>
</div> <div id="settingsUpdateVersionLine">
</div> <span id="settingsUpdateVersionText">Version </span>
</div> <span id="settingsUpdateVersionValue">0.0.1-alpha.18</span>
<div id="settingsUpdateActionContainer"> </div>
<button id="settingsUpdateActionButton">Check for Updates</button> </div>
</div> </div>
</div> <div id="settingsUpdateActionContainer">
</div> <button id="settingsUpdateActionButton">Vérifier les mise à jour</button>
<div class="settingsChangelogContainer"> </div>
<div class="settingsChangelogContent"> </div>
<div class="settingsChangelogHeadline"> </div>
<div class="settingsChangelogLabel">What's New</div> <div class="settingsChangelogContainer">
<div class="settingsChangelogTitle">Update Release Notes</div> <div class="settingsChangelogContent">
</div> <div class="settingsChangelogHeadline">
<div class="settingsChangelogText"> <div class="settingsChangelogLabel">Quoi de neuf ?</div>
No Release Notes <div class="settingsChangelogTitle">Patch Note de la mise à jour</div>
</div> </div>
</div> <div class="settingsChangelogText">
</div> Pas de patch note
</div> </div>
</div> </div>
<script src="./assets/js/scripts/settings.js"></script> </div>
</div>
</div>
<script src="./assets/js/scripts/settings.js"></script>
</div> </div>

View File

@ -1,25 +1,25 @@
<div id="welcomeContainer" style="display: none;"> <div id="welcomeContainer" style="display: none;">
<!--<div class="cloudDiv"> <!--<div class="cloudDiv">
<div class="cloudTop"></div> <div class="cloudTop"></div>
<div class="cloudBottom"></div> <div class="cloudBottom"></div>
</div>--> </div>-->
<div id="welcomeContent"> <div id="welcomeContent">
<img id="welcomeImageSeal" src="assets/images/SealCircle.png"/> <img id="welcomeImageSeal" src="assets/images/SealCircle.png"/>
<span id="welcomeHeader">WELCOME TO WESTEROSCRAFT</span> <span id="welcomeHeader">Bienvenue sur Creeponnia</span>
<span id="welcomeDescription">Our mission is to recreate the universe imagined by author George RR Martin in his fantasy series, A Song of Ice and Fire. Through the collaborative effort of thousands of community members, we have sought to create Westeros as accurately and precisely as possible within Minecraft. The world we are creating is yours to explore. Journey from Dorne to Castle Black, and if you arent afraid, beyond the Wall itself, but best not delay. As the words of House Stark ominously warn: Winter is Coming.</span> <span id="welcomeDescription">Our mission is to recreate the universe imagined by author George RR Martin in his fantasy series, A Song of Ice and Fire. Through the collaborative effort of thousands of community members, we have sought to create Westeros as accurately and precisely as possible within Minecraft. The world we are creating is yours to explore. Journey from Dorne to Castle Black, and if you arent afraid, beyond the Wall itself, but best not delay. As the words of House Stark ominously warn: Winter is Coming.</span>
<br> <br>
<span id="welcomeDescCTA">You are just a few clicks away from Westeros.</span> <span id="welcomeDescCTA">Rejoindre le serveur Minecraft !</span>
<button id="welcomeButton"> <button id="welcomeButton">
<div id="welcomeButtonContent"> <div id="welcomeButtonContent">
CONTINUE CONTINUE
<svg id="welcomeSVG" viewBox="0 0 24.87 13.97"> <svg id="welcomeSVG" viewBox="0 0 24.87 13.97">
<defs> <defs>
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style> <style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style>
</defs> </defs>
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/> <polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
</svg> </svg>
</div> </div>
</button> </button>
</div> </div>
<script src="./assets/js/scripts/welcome.js"></script> <script src="./assets/js/scripts/welcome.js"></script>
</div> </div>

134
build.js
View File

@ -1,68 +1,68 @@
const builder = require('electron-builder') const builder = require('electron-builder')
const Platform = builder.Platform const Platform = builder.Platform
function getCurrentPlatform(){ function getCurrentPlatform(){
switch(process.platform){ switch(process.platform){
case 'win32': case 'win32':
return Platform.WINDOWS return Platform.WINDOWS
case 'darwin': case 'darwin':
return Platform.MAC return Platform.MAC
case 'linux': case 'linux':
return Platform.linux return Platform.linux
default: default:
console.error('Cannot resolve current platform!') console.error('Cannot resolve current platform!')
return undefined return undefined
} }
} }
builder.build({ builder.build({
targets: (process.argv[2] != null && Platform[process.argv[2]] != null ? Platform[process.argv[2]] : getCurrentPlatform()).createTarget(), targets: (process.argv[2] != null && Platform[process.argv[2]] != null ? Platform[process.argv[2]] : getCurrentPlatform()).createTarget(),
config: { config: {
appId: 'helioslauncher', appId: 'helioslauncher',
productName: 'Helios Launcher', productName: 'Creeponnia Launcher',
artifactName: '${productName}-setup-${version}.${ext}', artifactName: '${productName}-setup-${version}.${ext}',
copyright: 'Copyright © 2018-2020 Daniel Scalzi', copyright: 'Copyright © 2018-2020 Daniel Scalzi',
directories: { directories: {
buildResources: 'build', buildResources: 'build',
output: 'dist' output: 'dist'
}, },
win: { win: {
target: [ target: [
{ {
target: 'nsis', target: 'nsis',
arch: 'x64' arch: 'x64'
} }
] ]
}, },
nsis: { nsis: {
oneClick: false, oneClick: false,
perMachine: false, perMachine: false,
allowElevation: true, allowElevation: true,
allowToChangeInstallationDirectory: true allowToChangeInstallationDirectory: true
}, },
mac: { mac: {
target: 'dmg', target: 'dmg',
category: 'public.app-category.games' category: 'public.app-category.games'
}, },
linux: { linux: {
target: 'AppImage', target: 'AppImage',
maintainer: 'Daniel Scalzi', maintainer: 'Daniel Scalzi',
vendor: 'Daniel Scalzi', vendor: 'Daniel Scalzi',
synopsis: 'Modded Minecraft Launcher', synopsis: 'Modded Minecraft Launcher',
description: 'Custom launcher which allows users to join modded servers. All mods, configurations, and updates are handled automatically.', description: 'Custom launcher which allows users to join modded servers. All mods, configurations, and updates are handled automatically.',
category: 'Game' category: 'Game'
}, },
compression: 'maximum', compression: 'maximum',
files: [ files: [
'!{dist,.gitignore,.vscode,docs,dev-app-update.yml,.travis.yml,.nvmrc,.eslintrc.json,build.js}' '!{dist,.gitignore,.vscode,docs,dev-app-update.yml,.travis.yml,.nvmrc,.eslintrc.json,build.js}'
], ],
extraResources: [ extraResources: [
'libraries' 'libraries'
], ],
asar: true asar: true
} }
}).then(() => { }).then(() => {
console.log('Build complete!') console.log('Build complete!')
}).catch(err => { }).catch(err => {
console.error('Error during build!', err) console.error('Error during build!', err)
}) })

View File

@ -1,3 +1,3 @@
owner: dscalzi owner: dscalzi
repo: HeliosLauncher repo: HeliosLauncher
provider: github provider: github

View File

@ -1,438 +1,438 @@
# Distribution Index # Distribution Index
You can use [Nebula](https://github.com/dscalzi/Nebula) to automate the generation of a distribution index. You can use [Nebula](https://github.com/dscalzi/Nebula) to automate the generation of a distribution index.
The distribution index is written in JSON. The general format of the index is as posted below. The distribution index is written in JSON. The general format of the index is as posted below.
```json ```json
{ {
"version": "1.0.0", "version": "1.0.0",
"discord": { "discord": {
"clientId": "12334567890123456789", "clientId": "12334567890123456789",
"smallImageText": "WesterosCraft", "smallImageText": "WesterosCraft",
"smallImageKey": "seal-circle" "smallImageKey": "seal-circle"
}, },
"rss": "https://westeroscraft.com/articles/index.rss", "rss": "https://westeroscraft.com/articles/index.rss",
"servers": [ "servers": [
{ {
"id": "Example_Server", "id": "Example_Server",
"name": "WesterosCraft Example Client", "name": "WesterosCraft Example Client",
"description": "Example WesterosCraft server. Connect for fun!", "description": "Example WesterosCraft server. Connect for fun!",
"icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/example_icon.png", "icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/example_icon.png",
"version": "0.0.1", "version": "0.0.1",
"address": "mc.westeroscraft.com:1337", "address": "mc.westeroscraft.com:1337",
"minecraftVersion": "1.11.2", "minecraftVersion": "1.11.2",
"discord": { "discord": {
"shortId": "Example", "shortId": "Example",
"largeImageText": "WesterosCraft Example Server", "largeImageText": "WesterosCraft Example Server",
"largeImageKey": "server-example" "largeImageKey": "server-example"
}, },
"mainServer": true, "mainServer": true,
"autoconnect": true, "autoconnect": true,
"modules": [ "modules": [
"Module Objects Here" "Module Objects Here"
] ]
} }
] ]
} }
``` ```
## Distro Index Object ## Distro Index Object
#### Example #### Example
```JSON ```JSON
{ {
"version": "1.0.0", "version": "1.0.0",
"discord": { "discord": {
"clientId": "12334567890123456789", "clientId": "12334567890123456789",
"smallImageText": "WesterosCraft", "smallImageText": "WesterosCraft",
"smallImageKey": "seal-circle" "smallImageKey": "seal-circle"
}, },
"rss": "https://westeroscraft.com/articles/index.rss", "rss": "https://westeroscraft.com/articles/index.rss",
"servers": [] "servers": []
} }
``` ```
### `DistroIndex.version: string/semver` ### `DistroIndex.version: string/semver`
The version of the index format. Will be used in the future to gracefully push updates. The version of the index format. Will be used in the future to gracefully push updates.
### `DistroIndex.discord: object` ### `DistroIndex.discord: object`
Global settings for [Discord Rich Presence](https://discordapp.com/developers/docs/rich-presence/how-to). Global settings for [Discord Rich Presence](https://discordapp.com/developers/docs/rich-presence/how-to).
**Properties** **Properties**
* `discord.clientId: string` - Client ID for th Application registered with Discord. * `discord.clientId: string` - Client ID for th Application registered with Discord.
* `discord.smallImageText: string` - Tootltip for the `smallImageKey`. * `discord.smallImageText: string` - Tootltip for the `smallImageKey`.
* `discord.smallImageKey: string` - Name of the uploaded image for the small profile artwork. * `discord.smallImageKey: string` - Name of the uploaded image for the small profile artwork.
### `DistroIndex.rss: string/url` ### `DistroIndex.rss: string/url`
A URL to a RSS feed. Used for loading news. A URL to a RSS feed. Used for loading news.
--- ---
## Server Object ## Server Object
#### Example #### Example
```JSON ```JSON
{ {
"id": "Example_Server", "id": "Example_Server",
"name": "WesterosCraft Example Client", "name": "WesterosCraft Example Client",
"description": "Example WesterosCraft server. Connect for fun!", "description": "Example WesterosCraft server. Connect for fun!",
"icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/example_icon.png", "icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/example_icon.png",
"version": "0.0.1", "version": "0.0.1",
"address": "mc.westeroscraft.com:1337", "address": "mc.westeroscraft.com:1337",
"minecraftVersion": "1.11.2", "minecraftVersion": "1.11.2",
"discord": { "discord": {
"shortId": "Example", "shortId": "Example",
"largeImageText": "WesterosCraft Example Server", "largeImageText": "WesterosCraft Example Server",
"largeImageKey": "server-example" "largeImageKey": "server-example"
}, },
"mainServer": true, "mainServer": true,
"autoconnect": true, "autoconnect": true,
"modules": [] "modules": []
} }
``` ```
### `Server.id: string` ### `Server.id: string`
The ID of the server. The launcher saves mod configurations and selected servers by ID. If the ID changes, all data related to the old ID **will be wiped**. The ID of the server. The launcher saves mod configurations and selected servers by ID. If the ID changes, all data related to the old ID **will be wiped**.
### `Server.name: string` ### `Server.name: string`
The name of the server. This is what users see on the UI. The name of the server. This is what users see on the UI.
### `Server.description: string` ### `Server.description: string`
A brief description of the server. Displayed on the UI to provide users more information. A brief description of the server. Displayed on the UI to provide users more information.
### `Server.icon: string/url` ### `Server.icon: string/url`
A URL to the server's icon. Will be displayed on the UI. A URL to the server's icon. Will be displayed on the UI.
### `Server.version: string/semver` ### `Server.version: string/semver`
The version of the server configuration. The version of the server configuration.
### `Server.address: string/url` ### `Server.address: string/url`
The server's IP address. The server's IP address.
### `Server.minecraftVersion: string` ### `Server.minecraftVersion: string`
The version of minecraft that the server is running. The version of minecraft that the server is running.
### `Server.discord: object` ### `Server.discord: object`
Server specific settings used for [Discord Rich Presence](https://discordapp.com/developers/docs/rich-presence/how-to). Server specific settings used for [Discord Rich Presence](https://discordapp.com/developers/docs/rich-presence/how-to).
**Properties** **Properties**
* `discord.shortId: string` - Short ID for the server. Displayed on the second status line as `Server: shortId` * `discord.shortId: string` - Short ID for the server. Displayed on the second status line as `Server: shortId`
* `discord.largeImageText: string` - Ttooltip for the `largeImageKey`. * `discord.largeImageText: string` - Ttooltip for the `largeImageKey`.
* `discord.largeImageKey: string` - Name of the uploaded image for the large profile artwork. * `discord.largeImageKey: string` - Name of the uploaded image for the large profile artwork.
### `Server.mainServer: boolean` ### `Server.mainServer: boolean`
Only one server in the array should have the `mainServer` property enabled. This will tell the launcher that this is the default server to select if either the previously selected server is invalid, or there is no previously selected server. If this field is not defined by any server (avoid this), the first server will be selected as the default. If multiple servers have `mainServer` enabled, the first one the launcher finds will be the effective value. Servers which are not the default may omit this property rather than explicitly setting it to false. Only one server in the array should have the `mainServer` property enabled. This will tell the launcher that this is the default server to select if either the previously selected server is invalid, or there is no previously selected server. If this field is not defined by any server (avoid this), the first server will be selected as the default. If multiple servers have `mainServer` enabled, the first one the launcher finds will be the effective value. Servers which are not the default may omit this property rather than explicitly setting it to false.
### `Server.autoconnect: boolean` ### `Server.autoconnect: boolean`
Whether or not the server can be autoconnected to. If false, the server will not be autoconnected to even when the user has the autoconnect setting enabled. Whether or not the server can be autoconnected to. If false, the server will not be autoconnected to even when the user has the autoconnect setting enabled.
### `Server.modules: Module[]` ### `Server.modules: Module[]`
An array of module objects. An array of module objects.
--- ---
## Module Object ## Module Object
A module is a generic representation of a file required to run the minecraft client. A module is a generic representation of a file required to run the minecraft client.
#### Example #### Example
```JSON ```JSON
{ {
"id": "com.example:artifact:1.0.0@jar.pack.xz", "id": "com.example:artifact:1.0.0@jar.pack.xz",
"name": "Artifact 1.0.0", "name": "Artifact 1.0.0",
"type": "Library", "type": "Library",
"artifact": { "artifact": {
"size": 4231234, "size": 4231234,
"MD5": "7f30eefe5c51e1ae0939dab2051db75f", "MD5": "7f30eefe5c51e1ae0939dab2051db75f",
"url": "http://files.site.com/maven/com/example/artifact/1.0.0/artifact-1.0.0.jar.pack.xz" "url": "http://files.site.com/maven/com/example/artifact/1.0.0/artifact-1.0.0.jar.pack.xz"
}, },
"subModules": [ "subModules": [
{ {
"id": "examplefile", "id": "examplefile",
"name": "Example File", "name": "Example File",
"type": "File", "type": "File",
"artifact": { "artifact": {
"size": 23423, "size": 23423,
"MD5": "169a5e6cf30c2cc8649755cdc5d7bad7", "MD5": "169a5e6cf30c2cc8649755cdc5d7bad7",
"path": "examplefile.txt", "path": "examplefile.txt",
"url": "http://files.site.com/examplefile.txt" "url": "http://files.site.com/examplefile.txt"
} }
} }
] ]
} }
``` ```
The parent module will be stored maven style, it's destination path will be resolved by its id. The sub module has a declared `path`, so that value will be used. The parent module will be stored maven style, it's destination path will be resolved by its id. The sub module has a declared `path`, so that value will be used.
### `Module.id: string` ### `Module.id: string`
The ID of the module. All modules that are not of type `File` **MUST** use a maven identifier. Version information and other metadata is pulled from the identifier. Modules which are stored maven style use the identifier to resolve the destination path. If the `extension` is not provided, it defaults to `jar`. The ID of the module. All modules that are not of type `File` **MUST** use a maven identifier. Version information and other metadata is pulled from the identifier. Modules which are stored maven style use the identifier to resolve the destination path. If the `extension` is not provided, it defaults to `jar`.
**Template** **Template**
`my.group:arifact:version@extension` `my.group:arifact:version@extension`
`my/group/artifact/version/artifact-version.extension` `my/group/artifact/version/artifact-version.extension`
**Example** **Example**
`net.minecraft:launchwrapper:1.12` OR `net.minecraft:launchwrapper:1.12@jar` `net.minecraft:launchwrapper:1.12` OR `net.minecraft:launchwrapper:1.12@jar`
`net/minecraft/launchwrapper/1.12/launchwrapper-1.12.jar` `net/minecraft/launchwrapper/1.12/launchwrapper-1.12.jar`
If the module's artifact does not declare the `path` property, its path will be resolved from the ID. If the module's artifact does not declare the `path` property, its path will be resolved from the ID.
### `Module.name: string` ### `Module.name: string`
The name of the module. Used on the UI. The name of the module. Used on the UI.
### `Module.type: string` ### `Module.type: string`
The type of the module. The type of the module.
### `Module.required: Required` ### `Module.required: Required`
**OPTIONAL** **OPTIONAL**
Defines whether or not the module is required. If omitted, then the module will be required. Defines whether or not the module is required. If omitted, then the module will be required.
Only applicable for modules of type: Only applicable for modules of type:
* `ForgeMod` * `ForgeMod`
* `LiteMod` * `LiteMod`
* `LiteLoader` * `LiteLoader`
### `Module.artifact: Artifact` ### `Module.artifact: Artifact`
The download artifact for the module. The download artifact for the module.
### `Module.subModules: Module[]` ### `Module.subModules: Module[]`
**OPTIONAL** **OPTIONAL**
An array of sub modules declared by this module. Typically, files which require other files are declared as submodules. A quick example would be a mod, and the configuration file for that mod. Submodules can also declare submodules of their own. The file is parsed recursively, so there is no limit. An array of sub modules declared by this module. Typically, files which require other files are declared as submodules. A quick example would be a mod, and the configuration file for that mod. Submodules can also declare submodules of their own. The file is parsed recursively, so there is no limit.
## Artifact Object ## Artifact Object
The format of the module's artifact depends on several things. The most important factor is where the file will be stored. If you are providing a simple file to be placed in the root directory of the client files, you may decided to format the module as the `examplefile` module declared above. This module provides a `path` option, allowing you to directly set where the file will be saved to. Only the `path` will affect the final downloaded file. The format of the module's artifact depends on several things. The most important factor is where the file will be stored. If you are providing a simple file to be placed in the root directory of the client files, you may decided to format the module as the `examplefile` module declared above. This module provides a `path` option, allowing you to directly set where the file will be saved to. Only the `path` will affect the final downloaded file.
Other times, you may want to store the files maven-style, such as with libraries and mods. In this case you must declare the module as the example artifact above. The module `id` will be used to resolve the final path, effectively replacing the `path` property. It must be provided in maven format. More information on this is provided in the documentation for the `id` property. Other times, you may want to store the files maven-style, such as with libraries and mods. In this case you must declare the module as the example artifact above. The module `id` will be used to resolve the final path, effectively replacing the `path` property. It must be provided in maven format. More information on this is provided in the documentation for the `id` property.
The resolved/provided paths are appended to a base path depending on the module's declared type. The resolved/provided paths are appended to a base path depending on the module's declared type.
| Type | Path | | Type | Path |
| ---- | ---- | | ---- | ---- |
| `ForgeHosted` | ({`commonDirectory`}/libraries/{`path` OR resolved}) | | `ForgeHosted` | ({`commonDirectory`}/libraries/{`path` OR resolved}) |
| `LiteLoader` | ({`commonDirectory`}/libraries/{`path` OR resolved}) | | `LiteLoader` | ({`commonDirectory`}/libraries/{`path` OR resolved}) |
| `Library` | ({`commonDirectory`}/libraries/{`path` OR resolved}) | | `Library` | ({`commonDirectory`}/libraries/{`path` OR resolved}) |
| `ForgeMod` | ({`commonDirectory`}/modstore/{`path` OR resolved}) | | `ForgeMod` | ({`commonDirectory`}/modstore/{`path` OR resolved}) |
| `LiteMod` | ({`commonDirectory`}/modstore/{`path` OR resolved}) | | `LiteMod` | ({`commonDirectory`}/modstore/{`path` OR resolved}) |
| `File` | ({`instanceDirectory`}/{`Server.id`}/{`path` OR resolved}) | | `File` | ({`instanceDirectory`}/{`Server.id`}/{`path` OR resolved}) |
The `commonDirectory` and `instanceDirectory` values are stored in the launcher's config.json. The `commonDirectory` and `instanceDirectory` values are stored in the launcher's config.json.
### `Artifact.size: number` ### `Artifact.size: number`
The size of the artifact. The size of the artifact.
### `Artifact.MD5: string` ### `Artifact.MD5: string`
The MD5 hash of the artifact. This will be used to validate local artifacts. The MD5 hash of the artifact. This will be used to validate local artifacts.
### `Artifact.path: string` ### `Artifact.path: string`
**OPTIONAL** **OPTIONAL**
A relative path to where the file will be saved. This is appended to the base path for the module's declared type. A relative path to where the file will be saved. This is appended to the base path for the module's declared type.
If this is not specified, the path will be resolved based on the module's ID. If this is not specified, the path will be resolved based on the module's ID.
### `Artifact.url: string/url` ### `Artifact.url: string/url`
The artifact's download url. The artifact's download url.
## Required Object ## Required Object
### `Required.value: boolean` ### `Required.value: boolean`
**OPTIONAL** **OPTIONAL**
If the module is required. Defaults to true if this property is omited. If the module is required. Defaults to true if this property is omited.
### `Required.def: boolean` ### `Required.def: boolean`
**OPTIONAL** **OPTIONAL**
If the module is enabled by default. Has no effect unless `Required.value` is false. Defaults to true if this property is omited. If the module is enabled by default. Has no effect unless `Required.value` is false. Defaults to true if this property is omited.
--- ---
## Module Types ## Module Types
### ForgeHosted ### ForgeHosted
The module type `ForgeHosted` represents forge itself. Currently, the launcher only supports forge servers, as vanilla servers can be connected to via the mojang launcher. The `Hosted` part is key, this means that the forge module must declare its required libraries as submodules. The module type `ForgeHosted` represents forge itself. Currently, the launcher only supports forge servers, as vanilla servers can be connected to via the mojang launcher. The `Hosted` part is key, this means that the forge module must declare its required libraries as submodules.
Ex. Ex.
```json ```json
{ {
"id": "net.minecraftforge:forge:1.11.2-13.20.1.2429", "id": "net.minecraftforge:forge:1.11.2-13.20.1.2429",
"name": "Minecraft Forge 1.11.2-13.20.1.2429", "name": "Minecraft Forge 1.11.2-13.20.1.2429",
"type": "ForgeHosted", "type": "ForgeHosted",
"artifact": { "artifact": {
"size": 4450992, "size": 4450992,
"MD5": "3fcc9b0104f0261397d3cc897e55a1c5", "MD5": "3fcc9b0104f0261397d3cc897e55a1c5",
"url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.11.2-13.20.1.2429/forge-1.11.2-13.20.1.2429-universal.jar" "url": "http://files.minecraftforge.net/maven/net/minecraftforge/forge/1.11.2-13.20.1.2429/forge-1.11.2-13.20.1.2429-universal.jar"
}, },
"subModules": [ "subModules": [
{ {
"id": "net.minecraft:launchwrapper:1.12", "id": "net.minecraft:launchwrapper:1.12",
"name": "Mojang (LaunchWrapper)", "name": "Mojang (LaunchWrapper)",
"type": "Library", "type": "Library",
"artifact": { "artifact": {
"size": 32999, "size": 32999,
"MD5": "934b2d91c7c5be4a49577c9e6b40e8da", "MD5": "934b2d91c7c5be4a49577c9e6b40e8da",
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/launchwrapper-1.12.jar" "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/launchwrapper-1.12.jar"
} }
} }
] ]
} }
``` ```
All of forge's required libraries are declared in the `version.json` file found in the root of the forge jar file. These libraries MUST be hosted and declared a submodules or forge will not work. All of forge's required libraries are declared in the `version.json` file found in the root of the forge jar file. These libraries MUST be hosted and declared a submodules or forge will not work.
There were plans to add a `Forge` type, in which the required libraries would be resolved by the launcher and downloaded from forge's servers. The forge servers are down at times, however, so this plan was stopped half-implemented. There were plans to add a `Forge` type, in which the required libraries would be resolved by the launcher and downloaded from forge's servers. The forge servers are down at times, however, so this plan was stopped half-implemented.
--- ---
### LiteLoader ### LiteLoader
The module type `LiteLoader` represents liteloader. It is handled as a library and added to the classpath at runtime. Special launch conditions are executed when liteloader is present and enabled. This module can be optional and toggled similarly to `ForgeMod` and `Litemod` modules. The module type `LiteLoader` represents liteloader. It is handled as a library and added to the classpath at runtime. Special launch conditions are executed when liteloader is present and enabled. This module can be optional and toggled similarly to `ForgeMod` and `Litemod` modules.
Ex. Ex.
```json ```json
{ {
"id": "com.mumfrey:liteloader:1.11.2", "id": "com.mumfrey:liteloader:1.11.2",
"name": "Liteloader (1.11.2)", "name": "Liteloader (1.11.2)",
"type": "LiteLoader", "type": "LiteLoader",
"required": { "required": {
"value": false, "value": false,
"def": false "def": false
}, },
"artifact": { "artifact": {
"size": 1685422, "size": 1685422,
"MD5": "3a98b5ed95810bf164e71c1a53be568d", "MD5": "3a98b5ed95810bf164e71c1a53be568d",
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/liteloader-1.11.2.jar" "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/liteloader-1.11.2.jar"
}, },
"subModules": [ "subModules": [
"All LiteMods go here" "All LiteMods go here"
] ]
} }
``` ```
--- ---
### Library ### Library
The module type `Library` represents a library file which will be required to start the minecraft process. Each library module will be dynamically added to the `-cp` (classpath) argument while building the game process. The module type `Library` represents a library file which will be required to start the minecraft process. Each library module will be dynamically added to the `-cp` (classpath) argument while building the game process.
Ex. Ex.
```json ```json
{ {
"id": "net.sf.jopt-simple:jopt-simple:4.6", "id": "net.sf.jopt-simple:jopt-simple:4.6",
"name": "Jopt-simple 4.6", "name": "Jopt-simple 4.6",
"type": "Library", "type": "Library",
"artifact": { "artifact": {
"size": 62477, "size": 62477,
"MD5": "13560a58a79b46b82057686543e8d727", "MD5": "13560a58a79b46b82057686543e8d727",
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/jopt-simple-4.6.jar" "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.11.2/jopt-simple-4.6.jar"
} }
} }
``` ```
--- ---
### ForgeMod ### ForgeMod
The module type `ForgeMod` represents a mod loaded by the Forge Mod Loader (FML). These files are stored maven-style and passed to FML using forge's [Modlist format](https://github.com/MinecraftForge/FML/wiki/New-JSON-Modlist-format). The module type `ForgeMod` represents a mod loaded by the Forge Mod Loader (FML). These files are stored maven-style and passed to FML using forge's [Modlist format](https://github.com/MinecraftForge/FML/wiki/New-JSON-Modlist-format).
Ex. Ex.
```json ```json
{ {
"id": "com.westeroscraft:westerosblocks:3.0.0-beta-6-133", "id": "com.westeroscraft:westerosblocks:3.0.0-beta-6-133",
"name": "WesterosBlocks (3.0.0-beta-6-133)", "name": "WesterosBlocks (3.0.0-beta-6-133)",
"type": "ForgeMod", "type": "ForgeMod",
"artifact": { "artifact": {
"size": 16321712, "size": 16321712,
"MD5": "5a89e2ab18916c18965fc93a0766cc6e", "MD5": "5a89e2ab18916c18965fc93a0766cc6e",
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/WesterosBlocks.jar" "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/WesterosBlocks.jar"
} }
} }
``` ```
--- ---
### LiteMod ### LiteMod
The module type `LiteMod` represents a mod loaded by liteloader. These files are stored maven-style and passed to liteloader using forge's [Modlist format](https://github.com/MinecraftForge/FML/wiki/New-JSON-Modlist-format). Documentation for liteloader's implementation of this can be found on [this issue](http://develop.liteloader.com/liteloader/LiteLoader/issues/34). The module type `LiteMod` represents a mod loaded by liteloader. These files are stored maven-style and passed to liteloader using forge's [Modlist format](https://github.com/MinecraftForge/FML/wiki/New-JSON-Modlist-format). Documentation for liteloader's implementation of this can be found on [this issue](http://develop.liteloader.com/liteloader/LiteLoader/issues/34).
Ex. Ex.
```json ```json
{ {
"id": "com.mumfrey:macrokeybindmod:0.14.4-1.11.2@litemod", "id": "com.mumfrey:macrokeybindmod:0.14.4-1.11.2@litemod",
"name": "Macro/Keybind Mod (0.14.4-1.11.2)", "name": "Macro/Keybind Mod (0.14.4-1.11.2)",
"type": "LiteMod", "type": "LiteMod",
"required": { "required": {
"value": false, "value": false,
"def": false "def": false
}, },
"artifact": { "artifact": {
"size": 1670811, "size": 1670811,
"MD5": "16080785577b391d426c62c8d3138558", "MD5": "16080785577b391d426c62c8d3138558",
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/macrokeybindmod.litemod" "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/mods/macrokeybindmod.litemod"
} }
} }
``` ```
--- ---
### File ### File
The module type `file` represents a generic file required by the client, another module, etc. These files are stored in the server's instance directory. The module type `file` represents a generic file required by the client, another module, etc. These files are stored in the server's instance directory.
Ex. Ex.
```json ```json
{ {
"id": "com.westeroscraft:westeroscraftrp:2017-08-16", "id": "com.westeroscraft:westeroscraftrp:2017-08-16",
"name": "WesterosCraft Resource Pack (2017-08-16)", "name": "WesterosCraft Resource Pack (2017-08-16)",
"type": "file", "type": "file",
"artifact": { "artifact": {
"size": 45241339, "size": 45241339,
"MD5": "ec2d9fdb14d5c2eafe5975a240202f1a", "MD5": "ec2d9fdb14d5c2eafe5975a240202f1a",
"path": "resourcepacks/WesterosCraft.zip", "path": "resourcepacks/WesterosCraft.zip",
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/resourcepacks/WesterosCraft.zip" "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.11.2/resourcepacks/WesterosCraft.zip"
} }
} }
``` ```

File diff suppressed because it is too large Load Diff

458
index.js
View File

@ -1,230 +1,230 @@
// Requirements // Requirements
const { app, BrowserWindow, ipcMain, Menu } = require('electron') const { app, BrowserWindow, ipcMain, Menu } = require('electron')
const autoUpdater = require('electron-updater').autoUpdater const autoUpdater = require('electron-updater').autoUpdater
const ejse = require('ejs-electron') const ejse = require('ejs-electron')
const fs = require('fs') const fs = require('fs')
const isDev = require('./app/assets/js/isdev') const isDev = require('./app/assets/js/isdev')
const path = require('path') const path = require('path')
const semver = require('semver') const semver = require('semver')
const url = require('url') const url = require('url')
// Setup auto updater. // Setup auto updater.
function initAutoUpdater(event, data) { function initAutoUpdater(event, data) {
if(data){ if(data){
autoUpdater.allowPrerelease = true autoUpdater.allowPrerelease = true
} else { } else {
// Defaults to true if application version contains prerelease components (e.g. 0.12.1-alpha.1) // Defaults to true if application version contains prerelease components (e.g. 0.12.1-alpha.1)
// autoUpdater.allowPrerelease = true // autoUpdater.allowPrerelease = true
} }
if(isDev){ if(isDev){
autoUpdater.autoInstallOnAppQuit = false autoUpdater.autoInstallOnAppQuit = false
autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml') autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml')
} }
if(process.platform === 'darwin'){ if(process.platform === 'darwin'){
autoUpdater.autoDownload = false autoUpdater.autoDownload = false
} }
autoUpdater.on('update-available', (info) => { autoUpdater.on('update-available', (info) => {
event.sender.send('autoUpdateNotification', 'update-available', info) event.sender.send('autoUpdateNotification', 'update-available', info)
}) })
autoUpdater.on('update-downloaded', (info) => { autoUpdater.on('update-downloaded', (info) => {
event.sender.send('autoUpdateNotification', 'update-downloaded', info) event.sender.send('autoUpdateNotification', 'update-downloaded', info)
}) })
autoUpdater.on('update-not-available', (info) => { autoUpdater.on('update-not-available', (info) => {
event.sender.send('autoUpdateNotification', 'update-not-available', info) event.sender.send('autoUpdateNotification', 'update-not-available', info)
}) })
autoUpdater.on('checking-for-update', () => { autoUpdater.on('checking-for-update', () => {
event.sender.send('autoUpdateNotification', 'checking-for-update') event.sender.send('autoUpdateNotification', 'checking-for-update')
}) })
autoUpdater.on('error', (err) => { autoUpdater.on('error', (err) => {
event.sender.send('autoUpdateNotification', 'realerror', err) event.sender.send('autoUpdateNotification', 'realerror', err)
}) })
} }
// Open channel to listen for update actions. // Open channel to listen for update actions.
ipcMain.on('autoUpdateAction', (event, arg, data) => { ipcMain.on('autoUpdateAction', (event, arg, data) => {
switch(arg){ switch(arg){
case 'initAutoUpdater': case 'initAutoUpdater':
console.log('Initializing auto updater.') console.log('Initializing auto updater.')
initAutoUpdater(event, data) initAutoUpdater(event, data)
event.sender.send('autoUpdateNotification', 'ready') event.sender.send('autoUpdateNotification', 'ready')
break break
case 'checkForUpdate': case 'checkForUpdate':
autoUpdater.checkForUpdates() autoUpdater.checkForUpdates()
.catch(err => { .catch(err => {
event.sender.send('autoUpdateNotification', 'realerror', err) event.sender.send('autoUpdateNotification', 'realerror', err)
}) })
break break
case 'allowPrereleaseChange': case 'allowPrereleaseChange':
if(!data){ if(!data){
const preRelComp = semver.prerelease(app.getVersion()) const preRelComp = semver.prerelease(app.getVersion())
if(preRelComp != null && preRelComp.length > 0){ if(preRelComp != null && preRelComp.length > 0){
autoUpdater.allowPrerelease = true autoUpdater.allowPrerelease = true
} else { } else {
autoUpdater.allowPrerelease = data autoUpdater.allowPrerelease = data
} }
} else { } else {
autoUpdater.allowPrerelease = data autoUpdater.allowPrerelease = data
} }
break break
case 'installUpdateNow': case 'installUpdateNow':
autoUpdater.quitAndInstall() autoUpdater.quitAndInstall()
break break
default: default:
console.log('Unknown argument', arg) console.log('Unknown argument', arg)
break break
} }
}) })
// Redirect distribution index event from preloader to renderer. // Redirect distribution index event from preloader to renderer.
ipcMain.on('distributionIndexDone', (event, res) => { ipcMain.on('distributionIndexDone', (event, res) => {
event.sender.send('distributionIndexDone', res) event.sender.send('distributionIndexDone', res)
}) })
// Disable hardware acceleration. // Disable hardware acceleration.
// 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 // https://github.com/electron/electron/issues/18397
app.allowRendererProcessReuse = true 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
function createWindow() { function createWindow() {
win = new BrowserWindow({ win = new BrowserWindow({
width: 980, width: 980,
height: 552, height: 552,
icon: getPlatformIcon('SealCircle'), icon: getPlatformIcon('SealCircle'),
frame: false, frame: false,
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, enableRemoteModule: true,
worldSafeExecuteJavaScript: false worldSafeExecuteJavaScript: false
}, },
backgroundColor: '#171614' backgroundColor: '#171614'
}) })
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)))
win.loadURL(url.format({ win.loadURL(url.format({
pathname: path.join(__dirname, 'app', 'app.ejs'), pathname: path.join(__dirname, 'app', 'app.ejs'),
protocol: 'file:', protocol: 'file:',
slashes: true slashes: true
})) }))
/*win.once('ready-to-show', () => { /*win.once('ready-to-show', () => {
win.show() win.show()
})*/ })*/
win.removeMenu() win.removeMenu()
win.resizable = true win.resizable = true
win.on('closed', () => { win.on('closed', () => {
win = null win = null
}) })
} }
function createMenu() { function createMenu() {
if(process.platform === 'darwin') { if(process.platform === 'darwin') {
// Extend default included application menu to continue support for quit keyboard shortcut // Extend default included application menu to continue support for quit keyboard shortcut
let applicationSubMenu = { let applicationSubMenu = {
label: 'Application', label: 'Application',
submenu: [{ submenu: [{
label: 'About Application', label: 'About Application',
selector: 'orderFrontStandardAboutPanel:' selector: 'orderFrontStandardAboutPanel:'
}, { }, {
type: 'separator' type: 'separator'
}, { }, {
label: 'Quit', label: 'Quit',
accelerator: 'Command+Q', accelerator: 'Command+Q',
click: () => { click: () => {
app.quit() app.quit()
} }
}] }]
} }
// New edit menu adds support for text-editing keyboard shortcuts // New edit menu adds support for text-editing keyboard shortcuts
let editSubMenu = { let editSubMenu = {
label: 'Edit', label: 'Edit',
submenu: [{ submenu: [{
label: 'Undo', label: 'Undo',
accelerator: 'CmdOrCtrl+Z', accelerator: 'CmdOrCtrl+Z',
selector: 'undo:' selector: 'undo:'
}, { }, {
label: 'Redo', label: 'Redo',
accelerator: 'Shift+CmdOrCtrl+Z', accelerator: 'Shift+CmdOrCtrl+Z',
selector: 'redo:' selector: 'redo:'
}, { }, {
type: 'separator' type: 'separator'
}, { }, {
label: 'Cut', label: 'Cut',
accelerator: 'CmdOrCtrl+X', accelerator: 'CmdOrCtrl+X',
selector: 'cut:' selector: 'cut:'
}, { }, {
label: 'Copy', label: 'Copy',
accelerator: 'CmdOrCtrl+C', accelerator: 'CmdOrCtrl+C',
selector: 'copy:' selector: 'copy:'
}, { }, {
label: 'Paste', label: 'Paste',
accelerator: 'CmdOrCtrl+V', accelerator: 'CmdOrCtrl+V',
selector: 'paste:' selector: 'paste:'
}, { }, {
label: 'Select All', label: 'Select All',
accelerator: 'CmdOrCtrl+A', accelerator: 'CmdOrCtrl+A',
selector: 'selectAll:' selector: 'selectAll:'
}] }]
} }
// Bundle submenus into a single template and build a menu object with it // Bundle submenus into a single template and build a menu object with it
let menuTemplate = [applicationSubMenu, editSubMenu] let menuTemplate = [applicationSubMenu, editSubMenu]
let menuObject = Menu.buildFromTemplate(menuTemplate) let menuObject = Menu.buildFromTemplate(menuTemplate)
// Assign it to the application // Assign it to the application
Menu.setApplicationMenu(menuObject) Menu.setApplicationMenu(menuObject)
} }
} }
function getPlatformIcon(filename){ function getPlatformIcon(filename){
let ext let ext
switch(process.platform) { switch(process.platform) {
case 'win32': case 'win32':
ext = 'ico' ext = 'ico'
break break
case 'darwin': case 'darwin':
case 'linux': case 'linux':
default: default:
ext = 'png' ext = 'png'
break break
} }
return path.join(__dirname, 'app', 'assets', 'images', `${filename}.${ext}`) return path.join(__dirname, 'app', 'assets', 'images', `${filename}.${ext}`)
} }
app.on('ready', createWindow) app.on('ready', createWindow)
app.on('ready', createMenu) app.on('ready', createMenu)
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
// On macOS it is common for applications and their menu bar // On macOS it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q // to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
app.quit() app.quit()
} }
}) })
app.on('activate', () => { app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the // On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open. // dock icon is clicked and there are no other windows open.
if (win === null) { if (win === null) {
createWindow() createWindow()
} }
}) })

6644
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"name": "helioslauncher", "name": "helioslauncher",
"version": "1.7.0", "version": "1.7.0",
"productName": "Helios Launcher", "productName": "Creeponnia Launcher",
"description": "Modded Minecraft Launcher", "description": "Modded Minecraft Launcher",
"author": "Daniel Scalzi (https://github.com/dscalzi/)", "author": "Daniel Scalzi (https://github.com/dscalzi/)",
"license": "UNLICENSED", "license": "UNLICENSED",