Compare commits
22 Commits
master
...
map-on-sin
Author | SHA1 | Date | |
---|---|---|---|
7eadc721cf | |||
b477da8e58 | |||
27765e89ef | |||
9e71cfbbb9 | |||
a079b8a23e | |||
c5038dd4c1 | |||
f774e9a67b | |||
31ab6f15dd | |||
960214efdf | |||
f1bc1ab719 | |||
30b3f804c9 | |||
cd757112b3 | |||
0dffb86577 | |||
d2dec49dcc | |||
b038b30ec6 | |||
9c69a99f7e | |||
1330e01484 | |||
9d37b49c79 | |||
1496696694 | |||
b6a2e7ae8c | |||
2bd2bc33a2 | |||
a4204d1f07 |
@ -1,11 +1,11 @@
|
|||||||
{
|
{
|
||||||
"env": {
|
"env": {
|
||||||
"es2022": true,
|
"es2017": true,
|
||||||
"node": true
|
"node": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": "eslint:recommended",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2022,
|
"ecmaVersion": 2019,
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
|
13
.github/workflows/build.yml
vendored
13
.github/workflows/build.yml
vendored
@ -6,24 +6,21 @@ jobs:
|
|||||||
release:
|
release:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-latest, ubuntu-latest, windows-latest]
|
os: [macos-latest, ubuntu-latest, windows-latest]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check out Git repository
|
- name: Check out Git repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 16
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: 3.x
|
||||||
|
|
||||||
@ -33,6 +30,6 @@ jobs:
|
|||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GH_TOKEN: ${{ secrets.github_token }}
|
||||||
run: npm run dist
|
run: npm run dist
|
||||||
shell: bash
|
shell: bash
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<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/github/actions/workflow/status/dscalzi/HeliosLauncher/build.yml?branch=master&style=for-the-badge" alt="gh actions">](https://github.com/dscalzi/HeliosLauncher/actions) [<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="winter-is-coming"></p>
|
[<p align="center"><img src="https://img.shields.io/github/workflow/status/dscalzi/HeliosLauncher/Build.svg?style=for-the-badge" alt="gh actions">](https://github.com/dscalzi/HeliosLauncher/actions) [<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="winter-is-coming"></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>
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ This section details the setup of a basic developmentment environment.
|
|||||||
|
|
||||||
**System Requirements**
|
**System Requirements**
|
||||||
|
|
||||||
* [Node.js][nodejs] v18
|
* [Node.js][nodejs] v16
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
104
app/app.ejs
104
app/app.ejs
@ -1,49 +1,57 @@
|
|||||||
<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><%= lang('app.title') %></title>
|
<title>Helios 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('waiting') %>
|
<%- include('loginOffline') %>
|
||||||
<%- include('loginOptions') %>
|
<%- include('waiting') %>
|
||||||
<%- include('settings') %>
|
<%- include('loginOptions') %>
|
||||||
<%- include('landing') %>
|
<%- include('settings') %>
|
||||||
</div>
|
<%- include('landing') %>
|
||||||
<%- include('overlay') %>
|
<%- include('dynmap') %>
|
||||||
<div id="loadingContainer">
|
</div>
|
||||||
<div id="loadingContent">
|
<%- include('overlay') %>
|
||||||
<div id="loadSpinnerContainer">
|
<div id="loadingContainer">
|
||||||
<img id="loadCenterImage" src="assets/images/LoadingSeal.png">
|
<div id="loadingContent">
|
||||||
<img id="loadSpinnerImage" class="rotating" src="assets/images/LoadingText.png">
|
<div id="loadSpinnerContainer">
|
||||||
</div>
|
<img id="loadCenterImage" src="assets/images/LoadingSeal.png">
|
||||||
</div>
|
<img id="loadSpinnerImage" class="rotating" src="assets/images/LoadingText.png">
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// Load language
|
||||||
|
for(let key of Object.keys(Lang.query('html'))){
|
||||||
|
document.getElementById(key).innerHTML = Lang.query(`html.${key}`)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
@ -450,6 +450,79 @@ body, button {
|
|||||||
transition: 0.25s ease;
|
transition: 0.25s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* loginOffline cancel button styles. */
|
||||||
|
#loginOfflineCancelContainer {
|
||||||
|
position: absolute;
|
||||||
|
top: 5%;
|
||||||
|
right: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* loginOffline cancel button styles. */
|
||||||
|
#loginOfflineCancelButton {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: 0.25s ease;
|
||||||
|
}
|
||||||
|
#loginOfflineCancelButton:hover #loginOfflineCancelIcon,
|
||||||
|
#loginOfflineCancelButton:hover #loginOfflineCancelText,
|
||||||
|
#loginOfflineCancelButton:focus #loginOfflineCancelIcon,
|
||||||
|
#loginOfflineCancelButton:focus #loginOfflineCancelText {
|
||||||
|
text-shadow: 0px 0px 20px white;
|
||||||
|
}
|
||||||
|
#loginOfflineCancelButton:hover #loginOfflineCancelIcon,
|
||||||
|
#loginOfflineCancelButton:focus #loginOfflineCancelIcon {
|
||||||
|
box-shadow: 0px 0px 20px white;
|
||||||
|
}
|
||||||
|
#loginOfflineCancelButton:active #loginOfflineCancelIcon,
|
||||||
|
#loginOfflineCancelButton:active #loginOfflineCancelText {
|
||||||
|
text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75);
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
border-color: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
#loginOfflineCancelButton:active #loginOfflineCancelIcon {
|
||||||
|
box-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
#loginOfflineCancelButton:disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
#loginOfflineCancelButton:disabled #loginOfflineCancelIcon,
|
||||||
|
#loginOfflineCancelButton:disabled #loginOfflineCancelText {
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
border-color: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The X in a circle icon for the cancel button. */
|
||||||
|
#loginOfflineCancelIcon {
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 1px solid white;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
font-size: 19px;
|
||||||
|
line-height: 30px;
|
||||||
|
margin: 0 auto;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
transition: 0.25s ease;
|
||||||
|
}
|
||||||
|
/* Text for the loginOffline cancel button. */
|
||||||
|
#loginOfflineCancelText {
|
||||||
|
font-size: 15px;
|
||||||
|
transition: 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Login content wrapper. */
|
/* Login content wrapper. */
|
||||||
#loginContent {
|
#loginContent {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -498,7 +571,7 @@ body, button {
|
|||||||
/* Header on login view. */
|
/* Header on login view. */
|
||||||
#loginSubheader {
|
#loginSubheader {
|
||||||
font-family: 'Avenir Medium';
|
font-family: 'Avenir Medium';
|
||||||
margin-bottom: 25px;
|
margin-bottom: 15px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@ -518,6 +591,7 @@ body, button {
|
|||||||
fill: #fff;
|
fill: #fff;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
padding-bottom: 0.7em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Span which displays errors related to login field content. */
|
/* Span which displays errors related to login field content. */
|
||||||
@ -560,17 +634,19 @@ body, button {
|
|||||||
.loginField {
|
.loginField {
|
||||||
font-family: 'Avenir Book';
|
font-family: 'Avenir Book';
|
||||||
background: none;
|
background: none;
|
||||||
border-width: 1.5px 0px 0px 0px;
|
border-width: 1px 1px 1px 1px;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
border-radius: 5px;
|
||||||
|
backdrop-filter: blur(5px);
|
||||||
width: 250px;
|
width: 250px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 15px;
|
||||||
border-color: #fff;
|
border-color: #3e3e3e;
|
||||||
color: rgba(255, 255, 255, 0.75);
|
color: rgba(255, 255, 255, 0.75);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 7.5px;
|
padding: 7.5px;
|
||||||
font-size: 10px;
|
font-size: 14px;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
}
|
}
|
||||||
.loginField:focus {
|
.loginField:focus {
|
||||||
@ -674,6 +750,72 @@ body, button {
|
|||||||
display: initial;
|
display: initial;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Login Offline button styles. */
|
||||||
|
#loginOfflineButton {
|
||||||
|
background: none;
|
||||||
|
font-weight: bold;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
border: none;
|
||||||
|
padding: 15px 5px;
|
||||||
|
margin: 10px 0px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
right: -20px;
|
||||||
|
transition: 0.5s ease;
|
||||||
|
}
|
||||||
|
#loginOfflineutton:disabled {
|
||||||
|
color: rgba(255, 255, 255, 0.75);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
#loginOfflineButton[loading] {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
#loginOfflineButton:hover,
|
||||||
|
#loginOfflineButton:focus {
|
||||||
|
text-shadow: 0px 0px 20px #fff;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#loginOfflineButton:active {
|
||||||
|
color: #c7c7c7;
|
||||||
|
text-shadow: 0px 0px 20px #c7c7c7;
|
||||||
|
}
|
||||||
|
#loginSVG {
|
||||||
|
-webkit-transform: translate3d(0, 0, 0);
|
||||||
|
overflow: visible;
|
||||||
|
transform: rotate(90deg);
|
||||||
|
margin-left: 20px;
|
||||||
|
transition: 0.25s ease;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
#loginOfflineButton:hover #loginSVG,
|
||||||
|
#loginOfflineButton:focus #loginSVG {
|
||||||
|
-webkit-filter: drop-shadow(0px 0px 2px #fff);
|
||||||
|
}
|
||||||
|
#loginOfflineButton:active #loginSVG .arrowLine {
|
||||||
|
stroke: #c7c7c7;
|
||||||
|
}
|
||||||
|
#loginOfflineButton:active #loginSVG {
|
||||||
|
-webkit-filter: drop-shadow(0px 0px 2px #c7c7c7);
|
||||||
|
}
|
||||||
|
#loginOfflineButton:disabled #loginSVG .arrowLine {
|
||||||
|
stroke: rgba(255, 255, 255, 0.75);
|
||||||
|
}
|
||||||
|
|
||||||
|
#loginOfflineButtonContent {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#loginOfflineButton .circle-loader,
|
||||||
|
#loginOfflineButton[loading] #loginSVG {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#loginOfflineButton[loading] .circle-loader,
|
||||||
|
#loginOfflineButton #loginSVG {
|
||||||
|
display: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.circle-loader {
|
.circle-loader {
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
@ -1228,59 +1370,6 @@ body, button {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Selected server content container */
|
|
||||||
.settingsSelServContainer {
|
|
||||||
background: rgba(0, 0, 0, 0.25);
|
|
||||||
width: 75%;
|
|
||||||
border-radius: 3px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin: 15px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Div which will be populated with the selected server's information. */
|
|
||||||
.settingsSelServContent {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
padding: 5px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Wrapper container for the switch server button. */
|
|
||||||
.settingsSwitchServerContainer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Button to switch server configurations on the mods tab. */
|
|
||||||
.settingsSwitchServerButton {
|
|
||||||
opacity: 0;
|
|
||||||
border: 1px solid rgb(255, 255, 255);
|
|
||||||
color: rgb(255, 255, 255);
|
|
||||||
background: none;
|
|
||||||
font-size: 12px;
|
|
||||||
border-radius: 3px;
|
|
||||||
font-family: 'Avenir Medium';
|
|
||||||
transition: 0.25s ease;
|
|
||||||
cursor: pointer;
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
.settingsSwitchServerButton:hover,
|
|
||||||
.settingsSwitchServerButton:focus {
|
|
||||||
box-shadow: 0px 0px 20px rgb(255, 255, 255);
|
|
||||||
background: rgba(255, 255, 255, 0.25);
|
|
||||||
}
|
|
||||||
.settingsSwitchServerButton:active {
|
|
||||||
box-shadow: 0px 0px 20px rgb(187, 187, 187);
|
|
||||||
background: rgba(187, 187, 187, 0.25);
|
|
||||||
border: 1px solid rgb(187, 187, 187);
|
|
||||||
color: rgb(187, 187, 187);
|
|
||||||
}
|
|
||||||
.settingsSelServContainer:hover .settingsSwitchServerButton {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove spin button from number inputs. */
|
/* Remove spin button from number inputs. */
|
||||||
#settingsContainer input[type=number]::-webkit-inner-spin-button {
|
#settingsContainer input[type=number]::-webkit-inner-spin-button {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
@ -1691,6 +1780,59 @@ input:checked + .toggleSwitchSlider:before {
|
|||||||
* Settings View (Mods Tab)
|
* Settings View (Mods Tab)
|
||||||
* * */
|
* * */
|
||||||
|
|
||||||
|
/* Selected server content container */
|
||||||
|
#settingsSelServContainer {
|
||||||
|
background: rgba(0, 0, 0, 0.25);
|
||||||
|
width: 75%;
|
||||||
|
border-radius: 3px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin: 15px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Div which will be populated with the selected server's information. */
|
||||||
|
#settingsSelServContent {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper container for the switch server button. */
|
||||||
|
#settingsSwitchServerContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button to switch server configurations on the mods tab. */
|
||||||
|
#settingsSwitchServerButton {
|
||||||
|
opacity: 0;
|
||||||
|
border: 1px solid rgb(255, 255, 255);
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
background: none;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-family: 'Avenir Medium';
|
||||||
|
transition: 0.25s ease;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#settingsSwitchServerButton:hover,
|
||||||
|
#settingsSwitchServerButton:focus {
|
||||||
|
box-shadow: 0px 0px 20px rgb(255, 255, 255);
|
||||||
|
background: rgba(255, 255, 255, 0.25);
|
||||||
|
}
|
||||||
|
#settingsSwitchServerButton:active {
|
||||||
|
box-shadow: 0px 0px 20px rgb(187, 187, 187);
|
||||||
|
background: rgba(187, 187, 187, 0.25);
|
||||||
|
border: 1px solid rgb(187, 187, 187);
|
||||||
|
color: rgb(187, 187, 187);
|
||||||
|
}
|
||||||
|
#settingsSelServContainer:hover #settingsSwitchServerButton {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Main content container for the mod elements. */
|
/* Main content container for the mod elements. */
|
||||||
#settingsModsContainer {
|
#settingsModsContainer {
|
||||||
width: 75%;
|
width: 75%;
|
||||||
@ -3772,7 +3914,6 @@ input:checked + .toggleSwitchSlider:before {
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
line-height: 10px;
|
line-height: 10px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Content container for the server listing's information. */
|
/* Content container for the server listing's information. */
|
||||||
@ -3965,4 +4106,53 @@ input:checked + .toggleSwitchSlider:before {
|
|||||||
/* Class which is applied when the spinner image is spinning. */
|
/* Class which is applied when the spinner image is spinning. */
|
||||||
.rotating {
|
.rotating {
|
||||||
animation: rotating 10s linear infinite;
|
animation: rotating 10s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Custom patches *
|
||||||
|
* *
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
/* iframe patch for full size window. */
|
||||||
|
#iframecontainer {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dynmapiframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#mapsvg {
|
||||||
|
-webkit-filter: invert(100%); /* safari 6.0 - 9.0 */
|
||||||
|
filter: invert(100%);
|
||||||
|
transition: 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map icon hover effect */
|
||||||
|
#newsButton:hover #mapsvg,
|
||||||
|
#newsButton:focus #mapsvg {
|
||||||
|
filter:invert(100%) drop-shadow(0 0 0.75rem white);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return from map button */
|
||||||
|
.FloatingButtonContainer {
|
||||||
|
position: absolute;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
left: 22em;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return from map button style */
|
||||||
|
#dynmapDoneButton {
|
||||||
|
background-color: #222222;
|
||||||
|
width: 100px;
|
||||||
|
border-radius: 0px 0px 10px 10px;
|
||||||
|
border-color: #333333;
|
||||||
}
|
}
|
298
app/assets/distribution.json
Normal file
298
app/assets/distribution.json
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
{
|
||||||
|
"version": "1.0.0",
|
||||||
|
"discord": {
|
||||||
|
"clientId": "385581240906022916",
|
||||||
|
"smallImageText": "WesterosCraft",
|
||||||
|
"smallImageKey": "seal-circle"
|
||||||
|
},
|
||||||
|
"java": {
|
||||||
|
"oracle": "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"
|
||||||
|
},
|
||||||
|
"rss": "https://westeroscraft.com/articles/index.rss",
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"id": "SkirdaTesting-1.12.2",
|
||||||
|
"name": "Skirda Test Server",
|
||||||
|
"description": "Сплошные баги блять",
|
||||||
|
"icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-prod.png",
|
||||||
|
"version": "4.6.5",
|
||||||
|
"address": "192.168.88.228:35012",
|
||||||
|
"minecraftVersion": "1.12.2",
|
||||||
|
"discord": {
|
||||||
|
"shortId": "Skirda Minecraft Server",
|
||||||
|
"largeImageText": "Skirda 1.12.2 Minecraft Server",
|
||||||
|
"largeImageKey": "skirda-testing"
|
||||||
|
},
|
||||||
|
"mainServer": false,
|
||||||
|
"autoconnect": true,
|
||||||
|
"modules": [
|
||||||
|
{
|
||||||
|
"id": "net.minecraftforge:forge:1.12.2-14.23.5.2847",
|
||||||
|
"name": "Minecraft Forge",
|
||||||
|
"type": "ForgeHosted",
|
||||||
|
"artifact": {
|
||||||
|
"size": 4884700,
|
||||||
|
"MD5": "90734a5a713e24902d24c45c15caa42c",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/forge-1.12.2-14.23.5.2847-universal.jar"
|
||||||
|
},
|
||||||
|
"subModules": [
|
||||||
|
{
|
||||||
|
"id": "net.minecraft:launchwrapper:1.12",
|
||||||
|
"name": "Mojang (LaunchWrapper)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 32999,
|
||||||
|
"MD5": "934b2d91c7c5be4a49577c9e6b40e8da",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/launchwrapper-1.12.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.ow2.asm:asm-all:5.2",
|
||||||
|
"name": "Mojang (ASM)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 247787,
|
||||||
|
"MD5": "f5ad16c7f0338b541978b0430d51dc83",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/asm-all-5.2.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "jline:jline:2.13",
|
||||||
|
"name": "Mojang (jline)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 248566,
|
||||||
|
"MD5": "f251ba666cccb260ff7215b2cbeee8d4",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jline-2.13.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-library:2.11.1@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-library)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 1474672,
|
||||||
|
"MD5": "379c15c4f724421c6d5d7aecedaf87a6",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-library-2.11.1.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-compiler:2.11.1@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-compiler)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 3076920,
|
||||||
|
"MD5": "7d89e952f2d5c74577310cd2c28e3f20",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-compiler-2.11.1.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-actors-migration_2.11:1.1.0@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-actors-migration)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 21324,
|
||||||
|
"MD5": "04e3428b2600ace33c7ae2bf1f6c0a4c",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-actors-migration_2.11-1.1.0.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-continuations-library)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 7956,
|
||||||
|
"MD5": "ed9b1d27aba8ac4090a3749c4dfc895a",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-library_2.11-1.0.2.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-continuations-plugin)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 46140,
|
||||||
|
"MD5": "a8232db22a72a981de6b1399eb86dff7",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-plugin_2.11.1-1.0.2.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-parser-combinators)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 85568,
|
||||||
|
"MD5": "2e50a7df17680daadacca69f07f8a16d",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-parser-combinators_2.11-1.0.1.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-reflect:2.11.1@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-reflect)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 1070312,
|
||||||
|
"MD5": "84e5dc81c10e2bd74c579c9d0332fdd9",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-reflect-2.11.1.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-swing_2.11:1.0.1",
|
||||||
|
"name": "Minecraft Forge (scala-swing)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 736795,
|
||||||
|
"MD5": "1d360289e697022a3f57abaad344b28f",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-swing_2.11-1.0.1.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.scala-lang:scala-xml_2.11:1.0.2@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (scala-xml)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 217812,
|
||||||
|
"MD5": "cc891b094a4c32dedc56bfefe9b072ff",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-xml_2.11-1.0.2.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "com.typesafe.akka:akka-actor_2.11:2.3.3@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (akka-actor)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 746612,
|
||||||
|
"MD5": "25cb22c3078e9fb3f7a861c912924862",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/akka-actor_2.11-2.3.3.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "com.typesafe:config:1.2.1@jar.pack.xz",
|
||||||
|
"name": "Minecraft Forge (typesafe-config)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 56636,
|
||||||
|
"MD5": "10ec4ccabc4e68aac9cf87165ead5d7d",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/config-1.2.1.jar.pack.xz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "lzma:lzma:0.0.1",
|
||||||
|
"name": "Mojang (LZMA)",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 5762,
|
||||||
|
"MD5": "a3e3c3186e41c4a1a3027ba2bb23cdc6",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/lzma-0.0.1.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "net.sf.trove4j:trove4j:3.0.3",
|
||||||
|
"name": "Trove4J",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 2523218,
|
||||||
|
"MD5": "8fc4d4e0129244f9fd39650c5f30feb2",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/trove4j-3.0.3.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "java3d:vecmath:1.5.2",
|
||||||
|
"name": "Vecmath",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 318956,
|
||||||
|
"MD5": "e5d2b7f46c4800a32f62ce75676a5710",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/vecmath-1.5.2.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "net.sf.jopt-simple:jopt-simple:5.0.3",
|
||||||
|
"name": "Jopt-simple",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 78175,
|
||||||
|
"MD5": "0a5ec84e23df9d7cfb4063bc55f2744c",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jopt-simple-5.0.3.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.apache.maven:maven-artifact:3.5.3",
|
||||||
|
"name": "maven-artifact",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 54961,
|
||||||
|
"MD5": "7741ebf29690ee7d9dde9cf4376347fc",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/maven-artifact-3.5.3.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "net.minecraftforge:MercuriusUpdater:1.12.2",
|
||||||
|
"name": "MercuriusUpdater",
|
||||||
|
"type": "Library",
|
||||||
|
"artifact": {
|
||||||
|
"size": 15098,
|
||||||
|
"MD5": "6eb9e61097bee3103a2fdc42746b76a4",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/MercuriusUpdater-1.12.2.jar"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "net.optifine:optifine:1.12.2_HD_U_F5",
|
||||||
|
"name": "Optifine",
|
||||||
|
"type": "ForgeMod",
|
||||||
|
"artifact": {
|
||||||
|
"size": 2598821,
|
||||||
|
"MD5": "043ac1db6f7441ea4cf31bcb621aff0b",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/OptiFine.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mezz:jei:1.12.2-4.14.3.242",
|
||||||
|
"name": "JustEnoughItems",
|
||||||
|
"type": "ForgeMod",
|
||||||
|
"artifact": {
|
||||||
|
"size": 620682,
|
||||||
|
"MD5": "ae6d0e6e873ef6c20f41097dc7fee8c6",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/jei.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "xaeros:minimap:1.12.2-20.15.0",
|
||||||
|
"name": "XaerosMinimap",
|
||||||
|
"type": "ForgeMod",
|
||||||
|
"required": {
|
||||||
|
"value": false
|
||||||
|
},
|
||||||
|
"artifact": {
|
||||||
|
"size": 528849,
|
||||||
|
"MD5": "cc12cfe20febd1404345f5339e522cda",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/Xaeros_Minimap.jar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "options.txt",
|
||||||
|
"name": "Default Client Options",
|
||||||
|
"type": "File",
|
||||||
|
"artifact": {
|
||||||
|
"size": 1973,
|
||||||
|
"path": "options.txt",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/options-1.12.2.txt"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "servers.dat",
|
||||||
|
"name": "Saved Client Servers",
|
||||||
|
"type": "File",
|
||||||
|
"artifact": {
|
||||||
|
"size": 84,
|
||||||
|
"MD5": "71d99e229d7d2b8d2a6423e46832a4b8",
|
||||||
|
"path": "servers.dat",
|
||||||
|
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/servers.dat"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
71
app/assets/js/assetexec.js
Normal file
71
app/assets/js/assetexec.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
let target = require('./assetguard')[process.argv[2]]
|
||||||
|
if(target == null){
|
||||||
|
process.send({context: 'error', data: null, error: 'Invalid class name'})
|
||||||
|
console.error('Invalid class name passed to argv[2], cannot continue.')
|
||||||
|
process.exit(1)
|
||||||
|
}
|
||||||
|
let tracker = new target(...(process.argv.splice(3)))
|
||||||
|
|
||||||
|
//const tracker = new AssetGuard(process.argv[2], process.argv[3])
|
||||||
|
console.log('AssetExec Started')
|
||||||
|
|
||||||
|
// Temporary for debug purposes.
|
||||||
|
process.on('unhandledRejection', r => console.log(r))
|
||||||
|
|
||||||
|
let percent = 0
|
||||||
|
function assignListeners(){
|
||||||
|
tracker.on('validate', (data) => {
|
||||||
|
process.send({context: 'validate', data})
|
||||||
|
})
|
||||||
|
tracker.on('progress', (data, acc, total) => {
|
||||||
|
const currPercent = parseInt((acc/total) * 100)
|
||||||
|
if (currPercent !== percent) {
|
||||||
|
percent = currPercent
|
||||||
|
process.send({context: 'progress', data, value: acc, total, percent})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
tracker.on('complete', (data, ...args) => {
|
||||||
|
process.send({context: 'complete', data, args})
|
||||||
|
})
|
||||||
|
tracker.on('error', (data, error) => {
|
||||||
|
process.send({context: 'error', data, error})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
assignListeners()
|
||||||
|
|
||||||
|
process.on('message', (msg) => {
|
||||||
|
if(msg.task === 'execute'){
|
||||||
|
const func = msg.function
|
||||||
|
let nS = tracker[func] // Nonstatic context
|
||||||
|
let iS = target[func] // Static context
|
||||||
|
if(typeof nS === 'function' || typeof iS === 'function'){
|
||||||
|
const f = typeof nS === 'function' ? nS : iS
|
||||||
|
const res = f.apply(f === nS ? tracker : null, msg.argsArr)
|
||||||
|
if(res instanceof Promise){
|
||||||
|
res.then((v) => {
|
||||||
|
process.send({result: v, context: func})
|
||||||
|
}).catch((err) => {
|
||||||
|
process.send({result: err.message || err, context: func})
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
process.send({result: res, context: func})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
process.send({context: 'error', data: null, error: `Function ${func} not found on ${process.argv[2]}`})
|
||||||
|
}
|
||||||
|
} else if(msg.task === 'changeContext'){
|
||||||
|
target = require('./assetguard')[msg.class]
|
||||||
|
if(target == null){
|
||||||
|
process.send({context: 'error', data: null, error: `Invalid class ${msg.class}`})
|
||||||
|
} else {
|
||||||
|
tracker = new target(...(msg.args))
|
||||||
|
assignListeners()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('disconnect', () => {
|
||||||
|
console.log('AssetExec Disconnected')
|
||||||
|
process.exit(0)
|
||||||
|
})
|
1872
app/assets/js/assetguard.js
Normal file
1872
app/assets/js/assetguard.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,7 @@ const { RestResponseStatus } = require('helios-core/common')
|
|||||||
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
||||||
const { MicrosoftAuth, microsoftErrorDisplayable, MicrosoftErrorCode } = require('helios-core/microsoft')
|
const { MicrosoftAuth, microsoftErrorDisplayable, MicrosoftErrorCode } = require('helios-core/microsoft')
|
||||||
const { AZURE_CLIENT_ID } = require('./ipcconstants')
|
const { AZURE_CLIENT_ID } = require('./ipcconstants')
|
||||||
|
const { async } = require('node-stream-zip')
|
||||||
|
|
||||||
const log = LoggerUtil.getLogger('AuthManager')
|
const log = LoggerUtil.getLogger('AuthManager')
|
||||||
|
|
||||||
@ -57,6 +58,11 @@ exports.addMojangAccount = async function(username, password) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.addOfflineAccount = async function(usernameOffline){
|
||||||
|
//TODO: check for forbidden symbols and lenght!!
|
||||||
|
ConfigManager.addOfflineAccount(usernameOffline)
|
||||||
|
}
|
||||||
|
|
||||||
const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 }
|
const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -181,6 +187,17 @@ exports.removeMojangAccount = async function(uuid){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.removeOfflineAccount = async function(uuid){
|
||||||
|
try {
|
||||||
|
ConfigManager.removeAuthAccount(uuid)
|
||||||
|
ConfigManager.save()
|
||||||
|
return Promise.resolve()
|
||||||
|
} catch (err){
|
||||||
|
log.error('Error while removing account', err)
|
||||||
|
return Promise.reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a Microsoft account. It is expected that the caller will invoke the OAuth logout
|
* Remove a Microsoft account. It is expected that the caller will invoke the OAuth logout
|
||||||
* through the ipc renderer.
|
* through the ipc renderer.
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
|
const { uuid } = require('discord-rpc-patch/src/util')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const { LoggerUtil } = require('helios-core')
|
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('ConfigManager')
|
const logger = require('./loggerutil')('%c[ConfigManager]', 'color: #a02d2a; font-weight: bold')
|
||||||
|
|
||||||
const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME)
|
const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME)
|
||||||
|
// TODO change
|
||||||
const dataPath = path.join(sysRoot, '.helioslauncher')
|
const dataPath = path.join(sysRoot, '.helioslauncher')
|
||||||
|
|
||||||
const launcherDir = require('@electron/remote').app.getPath('userData')
|
// Forked processes do not have access to electron, so we have this workaround.
|
||||||
|
const launcherDir = process.env.CONFIG_DIRECT_PATH || require('@electron/remote').app.getPath('userData')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the absolute path of the launcher directory.
|
* Retrieve the absolute path of the launcher directory.
|
||||||
@ -43,30 +44,24 @@ const configPath = path.join(exports.getLauncherDirectory(), 'config.json')
|
|||||||
const configPathLEGACY = path.join(dataPath, 'config.json')
|
const configPathLEGACY = path.join(dataPath, 'config.json')
|
||||||
const firstLaunch = !fs.existsSync(configPath) && !fs.existsSync(configPathLEGACY)
|
const firstLaunch = !fs.existsSync(configPath) && !fs.existsSync(configPathLEGACY)
|
||||||
|
|
||||||
exports.getAbsoluteMinRAM = function(ram){
|
exports.getAbsoluteMinRAM = function(){
|
||||||
if(ram?.minimum != null) {
|
|
||||||
return ram.minimum/1024
|
|
||||||
} else {
|
|
||||||
// Legacy behavior
|
|
||||||
const mem = os.totalmem()
|
|
||||||
return mem >= (6*1073741824) ? 3 : 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.getAbsoluteMaxRAM = function(ram){
|
|
||||||
const mem = os.totalmem()
|
const mem = os.totalmem()
|
||||||
const gT16 = mem-(16*1073741824)
|
return mem >= 6000000000 ? 3 : 2
|
||||||
return Math.floor((mem-(gT16 > 0 ? (Number.parseInt(gT16/8) + (16*1073741824)/4) : mem/4))/1073741824)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveSelectedRAM(ram) {
|
exports.getAbsoluteMaxRAM = function(){
|
||||||
if(ram?.recommended != null) {
|
const mem = os.totalmem()
|
||||||
return `${ram.recommended}M`
|
const gT16 = mem-16000000000
|
||||||
} else {
|
return Math.floor((mem-1000000000-(gT16 > 0 ? (Number.parseInt(gT16/8) + 16000000000/4) : mem/4))/1000000000)
|
||||||
// Legacy behavior
|
}
|
||||||
const mem = os.totalmem()
|
|
||||||
return mem >= (8*1073741824) ? '4G' : (mem >= (6*1073741824) ? '3G' : '2G')
|
function resolveMaxRAM(){
|
||||||
}
|
const mem = os.totalmem()
|
||||||
|
return mem >= 8000000000 ? '4G' : (mem >= 6000000000 ? '3G' : '2G')
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveMinRAM(){
|
||||||
|
return resolveMaxRAM()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,6 +72,17 @@ function resolveSelectedRAM(ram) {
|
|||||||
*/
|
*/
|
||||||
const DEFAULT_CONFIG = {
|
const DEFAULT_CONFIG = {
|
||||||
settings: {
|
settings: {
|
||||||
|
java: {
|
||||||
|
minRAM: resolveMinRAM(),
|
||||||
|
maxRAM: resolveMaxRAM(), // Dynamic
|
||||||
|
executable: null,
|
||||||
|
jvmOptions: [
|
||||||
|
'-XX:+UseConcMarkSweepGC',
|
||||||
|
'-XX:+CMSIncrementalMode',
|
||||||
|
'-XX:-UseAdaptiveSizePolicy',
|
||||||
|
'-Xmn128M'
|
||||||
|
],
|
||||||
|
},
|
||||||
game: {
|
game: {
|
||||||
resWidth: 1280,
|
resWidth: 1280,
|
||||||
resHeight: 720,
|
resHeight: 720,
|
||||||
@ -98,8 +104,7 @@ const DEFAULT_CONFIG = {
|
|||||||
selectedServer: null, // Resolved
|
selectedServer: null, // Resolved
|
||||||
selectedAccount: null,
|
selectedAccount: null,
|
||||||
authenticationDatabase: {},
|
authenticationDatabase: {},
|
||||||
modConfigurations: [],
|
modConfigurations: []
|
||||||
javaConfig: {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let config = null
|
let config = null
|
||||||
@ -140,8 +145,8 @@ exports.load = function(){
|
|||||||
doValidate = true
|
doValidate = true
|
||||||
} catch (err){
|
} catch (err){
|
||||||
logger.error(err)
|
logger.error(err)
|
||||||
logger.info('Configuration file contains malformed JSON or is corrupt.')
|
logger.log('Configuration file contains malformed JSON or is corrupt.')
|
||||||
logger.info('Generating a new configuration file.')
|
logger.log('Generating a new configuration file.')
|
||||||
fs.ensureDirSync(path.join(configPath, '..'))
|
fs.ensureDirSync(path.join(configPath, '..'))
|
||||||
config = DEFAULT_CONFIG
|
config = DEFAULT_CONFIG
|
||||||
exports.save()
|
exports.save()
|
||||||
@ -151,7 +156,7 @@ exports.load = function(){
|
|||||||
exports.save()
|
exports.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info('Successfully Loaded')
|
logger.log('Successfully Loaded')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -173,7 +178,7 @@ function validateKeySet(srcObj, destObj){
|
|||||||
if(srcObj == null){
|
if(srcObj == null){
|
||||||
srcObj = {}
|
srcObj = {}
|
||||||
}
|
}
|
||||||
const validationBlacklist = ['authenticationDatabase', 'javaConfig']
|
const validationBlacklist = ['authenticationDatabase']
|
||||||
const keys = Object.keys(srcObj)
|
const keys = Object.keys(srcObj)
|
||||||
for(let i=0; i<keys.length; i++){
|
for(let i=0; i<keys.length; i++){
|
||||||
if(typeof destObj[keys[i]] === 'undefined'){
|
if(typeof destObj[keys[i]] === 'undefined'){
|
||||||
@ -349,6 +354,19 @@ exports.addMojangAuthAccount = function(uuid, accessToken, username, displayName
|
|||||||
return config.authenticationDatabase[uuid]
|
return config.authenticationDatabase[uuid]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.addOfflineAccount = function(usernameOffline){
|
||||||
|
fake_uuid = usernameOffline
|
||||||
|
config.selectedAccount = fake_uuid
|
||||||
|
accessToken = ""
|
||||||
|
config.authenticationDatabase[fake_uuid] = {
|
||||||
|
type: 'offline',
|
||||||
|
accessToken,
|
||||||
|
username: usernameOffline.trim(),
|
||||||
|
uuid: fake_uuid.trim(),
|
||||||
|
displayName: usernameOffline.trim()
|
||||||
|
}
|
||||||
|
return config.authenticationDatabase[fake_uuid]
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Update the tokens of an authenticated microsoft account.
|
* Update the tokens of an authenticated microsoft account.
|
||||||
*
|
*
|
||||||
@ -507,66 +525,16 @@ exports.setModConfiguration = function(serverid, configuration){
|
|||||||
|
|
||||||
// Java Settings
|
// Java Settings
|
||||||
|
|
||||||
function defaultJavaConfig(effectiveJavaOptions, ram) {
|
|
||||||
if(effectiveJavaOptions.suggestedMajor > 8) {
|
|
||||||
return defaultJavaConfig17(ram)
|
|
||||||
} else {
|
|
||||||
return defaultJavaConfig8(ram)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultJavaConfig8(ram) {
|
|
||||||
return {
|
|
||||||
minRAM: resolveSelectedRAM(ram),
|
|
||||||
maxRAM: resolveSelectedRAM(ram),
|
|
||||||
executable: null,
|
|
||||||
jvmOptions: [
|
|
||||||
'-XX:+UseConcMarkSweepGC',
|
|
||||||
'-XX:+CMSIncrementalMode',
|
|
||||||
'-XX:-UseAdaptiveSizePolicy',
|
|
||||||
'-Xmn128M'
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function defaultJavaConfig17(ram) {
|
|
||||||
return {
|
|
||||||
minRAM: resolveSelectedRAM(ram),
|
|
||||||
maxRAM: resolveSelectedRAM(ram),
|
|
||||||
executable: null,
|
|
||||||
jvmOptions: [
|
|
||||||
'-XX:+UnlockExperimentalVMOptions',
|
|
||||||
'-XX:+UseG1GC',
|
|
||||||
'-XX:G1NewSizePercent=20',
|
|
||||||
'-XX:G1ReservePercent=20',
|
|
||||||
'-XX:MaxGCPauseMillis=50',
|
|
||||||
'-XX:G1HeapRegionSize=32M'
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure a java config property is set for the given server.
|
|
||||||
*
|
|
||||||
* @param {string} serverid The server id.
|
|
||||||
* @param {*} mcVersion The minecraft version of the server.
|
|
||||||
*/
|
|
||||||
exports.ensureJavaConfig = function(serverid, effectiveJavaOptions, ram) {
|
|
||||||
if(!Object.prototype.hasOwnProperty.call(config.javaConfig, serverid)) {
|
|
||||||
config.javaConfig[serverid] = defaultJavaConfig(effectiveJavaOptions, ram)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the minimum amount of memory for JVM initialization. This value
|
* Retrieve the minimum amount of memory for JVM initialization. This value
|
||||||
* contains the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
* contains the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
||||||
* 1024 MegaBytes, etc.
|
* 1024 MegaBytes, etc.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
* @param {boolean} def Optional. If true, the default value will be returned.
|
||||||
* @returns {string} The minimum amount of memory for JVM initialization.
|
* @returns {string} The minimum amount of memory for JVM initialization.
|
||||||
*/
|
*/
|
||||||
exports.getMinRAM = function(serverid){
|
exports.getMinRAM = function(def = false){
|
||||||
return config.javaConfig[serverid].minRAM
|
return !def ? config.settings.java.minRAM : DEFAULT_CONFIG.settings.java.minRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -574,11 +542,10 @@ exports.getMinRAM = function(serverid){
|
|||||||
* contain the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
* contain the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
||||||
* 1024 MegaBytes, etc.
|
* 1024 MegaBytes, etc.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
|
||||||
* @param {string} minRAM The new minimum amount of memory for JVM initialization.
|
* @param {string} minRAM The new minimum amount of memory for JVM initialization.
|
||||||
*/
|
*/
|
||||||
exports.setMinRAM = function(serverid, minRAM){
|
exports.setMinRAM = function(minRAM){
|
||||||
config.javaConfig[serverid].minRAM = minRAM
|
config.settings.java.minRAM = minRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -586,11 +553,11 @@ exports.setMinRAM = function(serverid, minRAM){
|
|||||||
* contains the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
* contains the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
||||||
* 1024 MegaBytes, etc.
|
* 1024 MegaBytes, etc.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
* @param {boolean} def Optional. If true, the default value will be returned.
|
||||||
* @returns {string} The maximum amount of memory for JVM initialization.
|
* @returns {string} The maximum amount of memory for JVM initialization.
|
||||||
*/
|
*/
|
||||||
exports.getMaxRAM = function(serverid){
|
exports.getMaxRAM = function(def = false){
|
||||||
return config.javaConfig[serverid].maxRAM
|
return !def ? config.settings.java.maxRAM : resolveMaxRAM()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -598,11 +565,10 @@ exports.getMaxRAM = function(serverid){
|
|||||||
* contain the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
* contain the units of memory. For example, '5G' = 5 GigaBytes, '1024M' =
|
||||||
* 1024 MegaBytes, etc.
|
* 1024 MegaBytes, etc.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
|
||||||
* @param {string} maxRAM The new maximum amount of memory for JVM initialization.
|
* @param {string} maxRAM The new maximum amount of memory for JVM initialization.
|
||||||
*/
|
*/
|
||||||
exports.setMaxRAM = function(serverid, maxRAM){
|
exports.setMaxRAM = function(maxRAM){
|
||||||
config.javaConfig[serverid].maxRAM = maxRAM
|
config.settings.java.maxRAM = maxRAM
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -610,21 +576,19 @@ exports.setMaxRAM = function(serverid, maxRAM){
|
|||||||
*
|
*
|
||||||
* This is a resolved configuration value and defaults to null until externally assigned.
|
* This is a resolved configuration value and defaults to null until externally assigned.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
|
||||||
* @returns {string} The path of the Java Executable.
|
* @returns {string} The path of the Java Executable.
|
||||||
*/
|
*/
|
||||||
exports.getJavaExecutable = function(serverid){
|
exports.getJavaExecutable = function(){
|
||||||
return config.javaConfig[serverid].executable
|
return config.settings.java.executable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the path of the Java Executable.
|
* Set the path of the Java Executable.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
|
||||||
* @param {string} executable The new path of the Java Executable.
|
* @param {string} executable The new path of the Java Executable.
|
||||||
*/
|
*/
|
||||||
exports.setJavaExecutable = function(serverid, executable){
|
exports.setJavaExecutable = function(executable){
|
||||||
config.javaConfig[serverid].executable = executable
|
config.settings.java.executable = executable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -632,11 +596,11 @@ exports.setJavaExecutable = function(serverid, executable){
|
|||||||
* such as memory allocation, will be dynamically resolved and will not be included
|
* such as memory allocation, will be dynamically resolved and will not be included
|
||||||
* in this value.
|
* in this value.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
* @param {boolean} def Optional. If true, the default value will be returned.
|
||||||
* @returns {Array.<string>} An array of the additional arguments for JVM initialization.
|
* @returns {Array.<string>} An array of the additional arguments for JVM initialization.
|
||||||
*/
|
*/
|
||||||
exports.getJVMOptions = function(serverid){
|
exports.getJVMOptions = function(def = false){
|
||||||
return config.javaConfig[serverid].jvmOptions
|
return !def ? config.settings.java.jvmOptions : DEFAULT_CONFIG.settings.java.jvmOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -644,12 +608,11 @@ exports.getJVMOptions = function(serverid){
|
|||||||
* such as memory allocation, will be dynamically resolved and should not be
|
* such as memory allocation, will be dynamically resolved and should not be
|
||||||
* included in this value.
|
* included in this value.
|
||||||
*
|
*
|
||||||
* @param {string} serverid The server id.
|
|
||||||
* @param {Array.<string>} jvmOptions An array of the new additional arguments for JVM
|
* @param {Array.<string>} jvmOptions An array of the new additional arguments for JVM
|
||||||
* initialization.
|
* initialization.
|
||||||
*/
|
*/
|
||||||
exports.setJVMOptions = function(serverid, jvmOptions){
|
exports.setJVMOptions = function(jvmOptions){
|
||||||
config.javaConfig[serverid].jvmOptions = jvmOptions
|
config.settings.java.jvmOptions = jvmOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Game Settings
|
// Game Settings
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
// Work in progress
|
// Work in progress
|
||||||
const { LoggerUtil } = require('helios-core')
|
const logger = require('./loggerutil')('%c[DiscordWrapper]', 'color: #7289da; font-weight: bold')
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('DiscordWrapper')
|
const {Client} = require('discord-rpc-patch')
|
||||||
|
|
||||||
const { Client } = require('discord-rpc-patch')
|
|
||||||
|
|
||||||
const Lang = require('./langloader')
|
|
||||||
|
|
||||||
let client
|
let client
|
||||||
let activity
|
let activity
|
||||||
|
|
||||||
exports.initRPC = function(genSettings, servSettings, initialDetails = Lang.queryJS('discord.waiting')){
|
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: Lang.queryJS('discord.state', {shortId: servSettings.shortId}),
|
state: 'Server: ' + servSettings.shortId,
|
||||||
largeImageKey: servSettings.largeImageKey,
|
largeImageKey: servSettings.largeImageKey,
|
||||||
largeImageText: servSettings.largeImageText,
|
largeImageText: servSettings.largeImageText,
|
||||||
smallImageKey: genSettings.smallImageKey,
|
smallImageKey: genSettings.smallImageKey,
|
||||||
@ -25,15 +21,15 @@ exports.initRPC = function(genSettings, servSettings, initialDetails = Lang.quer
|
|||||||
}
|
}
|
||||||
|
|
||||||
client.on('ready', () => {
|
client.on('ready', () => {
|
||||||
logger.info('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.info('Unable to initialize Discord Rich Presence, no client detected.')
|
logger.log('Unable to initialize Discord Rich Presence, no client detected.')
|
||||||
} else {
|
} else {
|
||||||
logger.info('Unable to initialize Discord Rich Presence: ' + error.message, error)
|
logger.log('Unable to initialize Discord Rich Presence: ' + error.message, error)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,612 @@
|
|||||||
const { DistributionAPI } = require('helios-core/common')
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const request = require('request')
|
||||||
|
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
|
const logger = require('./loggerutil')('%c[DistroManager]', 'color: #a02d2a; font-weight: bold')
|
||||||
|
|
||||||
// Old WesterosCraft url.
|
/**
|
||||||
// exports.REMOTE_DISTRO_URL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
|
* Represents the download information
|
||||||
exports.REMOTE_DISTRO_URL = 'https://helios-files.geekcorner.eu.org/distribution.json'
|
* for a specific module.
|
||||||
|
*/
|
||||||
|
class Artifact {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON object into an Artifact.
|
||||||
|
*
|
||||||
|
* @param {Object} json A JSON object representing an Artifact.
|
||||||
|
*
|
||||||
|
* @returns {Artifact} The parsed Artifact.
|
||||||
|
*/
|
||||||
|
static fromJSON(json){
|
||||||
|
return Object.assign(new Artifact(), json)
|
||||||
|
}
|
||||||
|
|
||||||
const api = new DistributionAPI(
|
/**
|
||||||
ConfigManager.getLauncherDirectory(),
|
* Get the MD5 hash of the artifact. This value may
|
||||||
null, // Injected forcefully by the preloader.
|
* be undefined for artifacts which are not to be
|
||||||
null, // Injected forcefully by the preloader.
|
* validated and updated.
|
||||||
exports.REMOTE_DISTRO_URL,
|
*
|
||||||
false
|
* @returns {string} The MD5 hash of the Artifact or undefined.
|
||||||
)
|
*/
|
||||||
|
getHash(){
|
||||||
|
return this.MD5
|
||||||
|
}
|
||||||
|
|
||||||
exports.DistroAPI = api
|
/**
|
||||||
|
* @returns {number} The download size of the artifact.
|
||||||
|
*/
|
||||||
|
getSize(){
|
||||||
|
return this.size
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The download url of the artifact.
|
||||||
|
*/
|
||||||
|
getURL(){
|
||||||
|
return this.url
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The artifact's destination path.
|
||||||
|
*/
|
||||||
|
getPath(){
|
||||||
|
return this.path
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
exports.Artifact
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a the requirement status
|
||||||
|
* of a module.
|
||||||
|
*/
|
||||||
|
class Required {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON object into a Required object.
|
||||||
|
*
|
||||||
|
* @param {Object} json A JSON object representing a Required object.
|
||||||
|
*
|
||||||
|
* @returns {Required} The parsed Required object.
|
||||||
|
*/
|
||||||
|
static fromJSON(json){
|
||||||
|
if(json == null){
|
||||||
|
return new Required(true, true)
|
||||||
|
} else {
|
||||||
|
return new Required(json.value == null ? true : json.value, json.def == null ? true : json.def)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(value, def){
|
||||||
|
this.value = value
|
||||||
|
this.default = def
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default value for a required object. If a module
|
||||||
|
* is not required, this value determines whether or not
|
||||||
|
* it is enabled by default.
|
||||||
|
*
|
||||||
|
* @returns {boolean} The default enabled value.
|
||||||
|
*/
|
||||||
|
isDefault(){
|
||||||
|
return this.default
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean} Whether or not the module is required.
|
||||||
|
*/
|
||||||
|
isRequired(){
|
||||||
|
return this.value
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
exports.Required
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a module.
|
||||||
|
*/
|
||||||
|
class Module {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON object into a Module.
|
||||||
|
*
|
||||||
|
* @param {Object} json A JSON object representing a Module.
|
||||||
|
* @param {string} serverid The ID of the server to which this module belongs.
|
||||||
|
*
|
||||||
|
* @returns {Module} The parsed Module.
|
||||||
|
*/
|
||||||
|
static fromJSON(json, serverid){
|
||||||
|
return new Module(json.id, json.name, json.type, json.required, json.artifact, json.subModules, serverid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the default extension for a specific module type.
|
||||||
|
*
|
||||||
|
* @param {string} type The type of the module.
|
||||||
|
*
|
||||||
|
* @return {string} The default extension for the given type.
|
||||||
|
*/
|
||||||
|
static _resolveDefaultExtension(type){
|
||||||
|
switch (type) {
|
||||||
|
case exports.Types.Library:
|
||||||
|
case exports.Types.ForgeHosted:
|
||||||
|
case exports.Types.LiteLoader:
|
||||||
|
case exports.Types.ForgeMod:
|
||||||
|
return 'jar'
|
||||||
|
case exports.Types.LiteMod:
|
||||||
|
return 'litemod'
|
||||||
|
case exports.Types.File:
|
||||||
|
default:
|
||||||
|
return 'jar' // There is no default extension really.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(id, name, type, required, artifact, subModules, serverid) {
|
||||||
|
this.identifier = id
|
||||||
|
this.type = type
|
||||||
|
this._resolveMetaData()
|
||||||
|
this.name = name
|
||||||
|
this.required = Required.fromJSON(required)
|
||||||
|
this.artifact = Artifact.fromJSON(artifact)
|
||||||
|
this._resolveArtifactPath(artifact.path, serverid)
|
||||||
|
this._resolveSubModules(subModules, serverid)
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveMetaData(){
|
||||||
|
try {
|
||||||
|
|
||||||
|
const m0 = this.identifier.split('@')
|
||||||
|
|
||||||
|
this.artifactExt = m0[1] || Module._resolveDefaultExtension(this.type)
|
||||||
|
|
||||||
|
const m1 = m0[0].split(':')
|
||||||
|
|
||||||
|
this.artifactClassifier = m1[3] || undefined
|
||||||
|
this.artifactVersion = m1[2] || '???'
|
||||||
|
this.artifactID = m1[1] || '???'
|
||||||
|
this.artifactGroup = m1[0] || '???'
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
// Improper identifier
|
||||||
|
logger.error('Improper ID for module', this.identifier, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveArtifactPath(artifactPath, serverid){
|
||||||
|
const pth = artifactPath == null ? path.join(...this.getGroup().split('.'), this.getID(), this.getVersion(), `${this.getID()}-${this.getVersion()}${this.artifactClassifier != undefined ? `-${this.artifactClassifier}` : ''}.${this.getExtension()}`) : artifactPath
|
||||||
|
|
||||||
|
switch (this.type){
|
||||||
|
case exports.Types.Library:
|
||||||
|
case exports.Types.ForgeHosted:
|
||||||
|
case exports.Types.LiteLoader:
|
||||||
|
this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'libraries', pth)
|
||||||
|
break
|
||||||
|
case exports.Types.ForgeMod:
|
||||||
|
case exports.Types.LiteMod:
|
||||||
|
this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'modstore', pth)
|
||||||
|
break
|
||||||
|
case exports.Types.VersionManifest:
|
||||||
|
this.artifact.path = path.join(ConfigManager.getCommonDirectory(), 'versions', this.getIdentifier(), `${this.getIdentifier()}.json`)
|
||||||
|
break
|
||||||
|
case exports.Types.File:
|
||||||
|
default:
|
||||||
|
this.artifact.path = path.join(ConfigManager.getInstanceDirectory(), serverid, pth)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveSubModules(json, serverid){
|
||||||
|
const arr = []
|
||||||
|
if(json != null){
|
||||||
|
for(let sm of json){
|
||||||
|
arr.push(Module.fromJSON(sm, serverid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.subModules = arr.length > 0 ? arr : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The full, unparsed module identifier.
|
||||||
|
*/
|
||||||
|
getIdentifier(){
|
||||||
|
return this.identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The name of the module.
|
||||||
|
*/
|
||||||
|
getName(){
|
||||||
|
return this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Required} The required object declared by this module.
|
||||||
|
*/
|
||||||
|
getRequired(){
|
||||||
|
return this.required
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Artifact} The artifact declared by this module.
|
||||||
|
*/
|
||||||
|
getArtifact(){
|
||||||
|
return this.artifact
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The maven identifier of this module's artifact.
|
||||||
|
*/
|
||||||
|
getID(){
|
||||||
|
return this.artifactID
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The maven group of this module's artifact.
|
||||||
|
*/
|
||||||
|
getGroup(){
|
||||||
|
return this.artifactGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The identifier without he version or extension.
|
||||||
|
*/
|
||||||
|
getVersionlessID(){
|
||||||
|
return this.getGroup() + ':' + this.getID()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The identifier without the extension.
|
||||||
|
*/
|
||||||
|
getExtensionlessID(){
|
||||||
|
return this.getIdentifier().split('@')[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The version of this module's artifact.
|
||||||
|
*/
|
||||||
|
getVersion(){
|
||||||
|
return this.artifactVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The classifier of this module's artifact
|
||||||
|
*/
|
||||||
|
getClassifier(){
|
||||||
|
return this.artifactClassifier
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The extension of this module's artifact.
|
||||||
|
*/
|
||||||
|
getExtension(){
|
||||||
|
return this.artifactExt
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean} Whether or not this module has sub modules.
|
||||||
|
*/
|
||||||
|
hasSubModules(){
|
||||||
|
return this.subModules != null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Array.<Module>} An array of sub modules.
|
||||||
|
*/
|
||||||
|
getSubModules(){
|
||||||
|
return this.subModules
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The type of the module.
|
||||||
|
*/
|
||||||
|
getType(){
|
||||||
|
return this.type
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
exports.Module
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a server configuration.
|
||||||
|
*/
|
||||||
|
class Server {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON object into a Server.
|
||||||
|
*
|
||||||
|
* @param {Object} json A JSON object representing a Server.
|
||||||
|
*
|
||||||
|
* @returns {Server} The parsed Server object.
|
||||||
|
*/
|
||||||
|
static fromJSON(json){
|
||||||
|
|
||||||
|
const mdls = json.modules
|
||||||
|
json.modules = []
|
||||||
|
|
||||||
|
const serv = Object.assign(new Server(), json)
|
||||||
|
serv._resolveModules(mdls)
|
||||||
|
|
||||||
|
return serv
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveModules(json){
|
||||||
|
const arr = []
|
||||||
|
for(let m of json){
|
||||||
|
arr.push(Module.fromJSON(m, this.getID()))
|
||||||
|
}
|
||||||
|
this.modules = arr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The ID of the server.
|
||||||
|
*/
|
||||||
|
getID(){
|
||||||
|
return this.id
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The name of the server.
|
||||||
|
*/
|
||||||
|
getName(){
|
||||||
|
return this.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The description of the server.
|
||||||
|
*/
|
||||||
|
getDescription(){
|
||||||
|
return this.description
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The URL of the server's icon.
|
||||||
|
*/
|
||||||
|
getIcon(){
|
||||||
|
return this.icon
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The version of the server configuration.
|
||||||
|
*/
|
||||||
|
getVersion(){
|
||||||
|
return this.version
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The IP address of the server.
|
||||||
|
*/
|
||||||
|
getAddress(){
|
||||||
|
return this.address
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The minecraft version of the server.
|
||||||
|
*/
|
||||||
|
getMinecraftVersion(){
|
||||||
|
return this.minecraftVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean} Whether or not this server is the main
|
||||||
|
* server. The main server is selected by the launcher when
|
||||||
|
* no valid server is selected.
|
||||||
|
*/
|
||||||
|
isMainServer(){
|
||||||
|
return this.mainServer
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean} Whether or not the server is autoconnect.
|
||||||
|
* by default.
|
||||||
|
*/
|
||||||
|
isAutoConnect(){
|
||||||
|
return this.autoconnect
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Array.<Module>} An array of modules for this server.
|
||||||
|
*/
|
||||||
|
getModules(){
|
||||||
|
return this.modules
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
exports.Server
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the Distribution Index.
|
||||||
|
*/
|
||||||
|
class DistroIndex {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a JSON object into a DistroIndex.
|
||||||
|
*
|
||||||
|
* @param {Object} json A JSON object representing a DistroIndex.
|
||||||
|
*
|
||||||
|
* @returns {DistroIndex} The parsed Server object.
|
||||||
|
*/
|
||||||
|
static fromJSON(json){
|
||||||
|
|
||||||
|
const servers = json.servers
|
||||||
|
json.servers = []
|
||||||
|
|
||||||
|
const distro = Object.assign(new DistroIndex(), json)
|
||||||
|
distro._resolveServers(servers)
|
||||||
|
distro._resolveMainServer()
|
||||||
|
|
||||||
|
return distro
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveServers(json){
|
||||||
|
const arr = []
|
||||||
|
for(let s of json){
|
||||||
|
arr.push(Server.fromJSON(s))
|
||||||
|
}
|
||||||
|
this.servers = arr
|
||||||
|
}
|
||||||
|
|
||||||
|
_resolveMainServer(){
|
||||||
|
|
||||||
|
for(let serv of this.servers){
|
||||||
|
if(serv.mainServer){
|
||||||
|
this.mainServer = serv.id
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no server declares default_selected, default to the first one declared.
|
||||||
|
this.mainServer = (this.servers.length > 0) ? this.servers[0].getID() : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The version of the distribution index.
|
||||||
|
*/
|
||||||
|
getVersion(){
|
||||||
|
return this.version
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string} The URL to the news RSS feed.
|
||||||
|
*/
|
||||||
|
getRSS(){
|
||||||
|
return this.rss
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Array.<Server>} An array of declared server configurations.
|
||||||
|
*/
|
||||||
|
getServers(){
|
||||||
|
return this.servers
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a server configuration by its ID. If it does not
|
||||||
|
* exist, null will be returned.
|
||||||
|
*
|
||||||
|
* @param {string} id The ID of the server.
|
||||||
|
*
|
||||||
|
* @returns {Server} The server configuration with the given ID or null.
|
||||||
|
*/
|
||||||
|
getServer(id){
|
||||||
|
for(let serv of this.servers){
|
||||||
|
if(serv.id === id){
|
||||||
|
return serv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the main server.
|
||||||
|
*
|
||||||
|
* @returns {Server} The main server.
|
||||||
|
*/
|
||||||
|
getMainServer(){
|
||||||
|
return this.mainServer != null ? this.getServer(this.mainServer) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
exports.DistroIndex
|
||||||
|
|
||||||
|
exports.Types = {
|
||||||
|
Library: 'Library',
|
||||||
|
ForgeHosted: 'ForgeHosted',
|
||||||
|
Forge: 'Forge', // Unimplemented
|
||||||
|
LiteLoader: 'LiteLoader',
|
||||||
|
ForgeMod: 'ForgeMod',
|
||||||
|
LiteMod: 'LiteMod',
|
||||||
|
File: 'File',
|
||||||
|
VersionManifest: 'VersionManifest'
|
||||||
|
}
|
||||||
|
|
||||||
|
let DEV_MODE = false
|
||||||
|
|
||||||
|
const DISTRO_PATH = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json')
|
||||||
|
const DEV_PATH = path.join(ConfigManager.getLauncherDirectory(), 'dev_distribution.json')
|
||||||
|
|
||||||
|
let data = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise.<DistroIndex>}
|
||||||
|
*/
|
||||||
|
exports.pullRemote = function(){
|
||||||
|
if(DEV_MODE){
|
||||||
|
return exports.pullLocal()
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
//const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
|
||||||
|
const distroURL = "https://skirda.gregbrzezinski.com/distribution.json"
|
||||||
|
//const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/'
|
||||||
|
const opts = {
|
||||||
|
url: distroURL,
|
||||||
|
timeout: 2500
|
||||||
|
}
|
||||||
|
const distroDest = path.join(ConfigManager.getLauncherDirectory(), 'distribution.json')
|
||||||
|
request(opts, (error, resp, body) => {
|
||||||
|
if(!error){
|
||||||
|
|
||||||
|
try {
|
||||||
|
data = DistroIndex.fromJSON(JSON.parse(body))
|
||||||
|
} catch (e) {
|
||||||
|
reject(e)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFile(distroDest, body, 'utf-8', (err) => {
|
||||||
|
if(!err){
|
||||||
|
resolve(data)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reject(error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Promise.<DistroIndex>}
|
||||||
|
*/
|
||||||
|
exports.pullLocal = function(){
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fs.readFile(DEV_MODE ? DEV_PATH : DISTRO_PATH, 'utf-8', (err, d) => {
|
||||||
|
if(!err){
|
||||||
|
data = DistroIndex.fromJSON(JSON.parse(d))
|
||||||
|
resolve(data)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
reject(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.setDevMode = function(value){
|
||||||
|
if(value){
|
||||||
|
logger.log('Developer mode enabled.')
|
||||||
|
logger.log('If you don\'t know what that means, revert immediately.')
|
||||||
|
} else {
|
||||||
|
logger.log('Developer mode disabled.')
|
||||||
|
}
|
||||||
|
DEV_MODE = value
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.isDevMode = function(){
|
||||||
|
return DEV_MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {DistroIndex}
|
||||||
|
*/
|
||||||
|
exports.getDistribution = function(){
|
||||||
|
return data
|
||||||
|
}
|
@ -1,43 +1,21 @@
|
|||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const toml = require('toml')
|
|
||||||
const merge = require('lodash.merge')
|
|
||||||
|
|
||||||
let lang
|
let lang
|
||||||
|
|
||||||
exports.loadLanguage = function(id){
|
exports.loadLanguage = function(id){
|
||||||
lang = merge(lang || {}, toml.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.toml`))) || {})
|
lang = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'lang', `${id}.json`))) || {}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.query = function(id, placeHolders){
|
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]
|
||||||
}
|
}
|
||||||
let text = res === lang ? '' : res
|
return res === lang ? {} : res
|
||||||
if (placeHolders) {
|
|
||||||
Object.entries(placeHolders).forEach(([key, value]) => {
|
|
||||||
text = text.replace(`{${key}}`, value)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.queryJS = function(id, placeHolders){
|
exports.queryJS = function(id){
|
||||||
return exports.query(`js.${id}`, placeHolders)
|
return exports.query(`js.${id}`)
|
||||||
}
|
|
||||||
|
|
||||||
exports.queryEJS = function(id, placeHolders){
|
|
||||||
return exports.query(`ejs.${id}`, placeHolders)
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.setupLanguage = function(){
|
|
||||||
// Load Language Files
|
|
||||||
exports.loadLanguage('en_US')
|
|
||||||
// Uncomment this when translations are ready
|
|
||||||
//exports.loadLanguage('xx_XX')
|
|
||||||
|
|
||||||
// Load Custom Language File for Launcher Customizer
|
|
||||||
exports.loadLanguage('_custom')
|
|
||||||
}
|
}
|
32
app/assets/js/loggerutil.js
Normal file
32
app/assets/js/loggerutil.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
class LoggerUtil {
|
||||||
|
|
||||||
|
constructor(prefix, style){
|
||||||
|
this.prefix = prefix
|
||||||
|
this.style = style
|
||||||
|
}
|
||||||
|
|
||||||
|
log(){
|
||||||
|
console.log.apply(null, [this.prefix, this.style, ...arguments])
|
||||||
|
}
|
||||||
|
|
||||||
|
info(){
|
||||||
|
console.info.apply(null, [this.prefix, this.style, ...arguments])
|
||||||
|
}
|
||||||
|
|
||||||
|
warn(){
|
||||||
|
console.warn.apply(null, [this.prefix, this.style, ...arguments])
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(){
|
||||||
|
console.debug.apply(null, [this.prefix, this.style, ...arguments])
|
||||||
|
}
|
||||||
|
|
||||||
|
error(){
|
||||||
|
console.error.apply(null, [this.prefix, this.style, ...arguments])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function (prefix, style){
|
||||||
|
return new LoggerUtil(prefix, style)
|
||||||
|
}
|
@ -1,41 +1,28 @@
|
|||||||
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 { DistroAPI } = require('./distromanager')
|
const DistroManager = require('./distromanager')
|
||||||
const LangLoader = require('./langloader')
|
const LangLoader = require('./langloader')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const logger = require('./loggerutil')('%c[Preloader]', 'color: #a02d2a; font-weight: bold')
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
const { HeliosDistribution } = require('helios-core/common')
|
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('Preloader')
|
logger.log('Loading..')
|
||||||
|
|
||||||
logger.info('Loading..')
|
|
||||||
|
|
||||||
// Load ConfigManager
|
// Load ConfigManager
|
||||||
ConfigManager.load()
|
ConfigManager.load()
|
||||||
|
|
||||||
// Yuck!
|
|
||||||
// TODO Fix this
|
|
||||||
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
|
|
||||||
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
|
|
||||||
|
|
||||||
// Load Strings
|
// Load Strings
|
||||||
LangLoader.setupLanguage()
|
LangLoader.loadLanguage('en_US')
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {HeliosDistribution} data
|
|
||||||
*/
|
|
||||||
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.getServerById(ConfigManager.getSelectedServer()) == null){
|
if(ConfigManager.getSelectedServer() == null || data.getServer(ConfigManager.getSelectedServer()) == null){
|
||||||
logger.info('Determining default selected server..')
|
logger.log('Determining default selected server..')
|
||||||
ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
|
ConfigManager.setSelectedServer(data.getMainServer().getID())
|
||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,25 +30,40 @@ function onDistroLoad(data){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure Distribution is downloaded and cached.
|
// Ensure Distribution is downloaded and cached.
|
||||||
DistroAPI.getDistribution()
|
DistroManager.pullRemote().then((data) => {
|
||||||
.then(heliosDistro => {
|
logger.log('Loaded distribution index.')
|
||||||
logger.info('Loaded distribution index.')
|
|
||||||
|
|
||||||
onDistroLoad(heliosDistro)
|
onDistroLoad(data)
|
||||||
})
|
|
||||||
.catch(err => {
|
}).catch((err) => {
|
||||||
logger.info('Failed to load an older version of the distribution index.')
|
logger.log('Failed to load distribution index.')
|
||||||
logger.info('Application cannot run.')
|
logger.error(err)
|
||||||
|
|
||||||
|
logger.log('Attempting to load an older version of the distribution index.')
|
||||||
|
// Try getting a local copy, better than nothing.
|
||||||
|
DistroManager.pullLocal().then((data) => {
|
||||||
|
logger.log('Successfully loaded an older version of the distribution index.')
|
||||||
|
|
||||||
|
onDistroLoad(data)
|
||||||
|
|
||||||
|
|
||||||
|
}).catch((err) => {
|
||||||
|
|
||||||
|
logger.log('Failed to load an older version of the distribution index.')
|
||||||
|
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.info('Cleaned natives directory.')
|
logger.log('Cleaned natives directory.')
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -2,33 +2,25 @@ const AdmZip = require('adm-zip')
|
|||||||
const child_process = require('child_process')
|
const child_process = require('child_process')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const { LoggerUtil } = require('helios-core')
|
|
||||||
const { getMojangOS, isLibraryCompatible, mcVersionAtLeast } = require('helios-core/common')
|
|
||||||
const { Type } = require('helios-distribution-types')
|
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
const { URL } = require('url')
|
||||||
|
|
||||||
|
const { Util, Library } = require('./assetguard')
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
|
const DistroManager = require('./distromanager')
|
||||||
|
const LoggerUtil = require('./loggerutil')
|
||||||
|
|
||||||
const logger = LoggerUtil.getLogger('ProcessBuilder')
|
const logger = LoggerUtil('%c[ProcessBuilder]', 'color: #003996; font-weight: bold')
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Only forge and fabric are top level mod loaders.
|
|
||||||
*
|
|
||||||
* Forge 1.13+ launch logic is similar to fabrics, for now using usingFabricLoader flag to
|
|
||||||
* change minor details when needed.
|
|
||||||
*
|
|
||||||
* Rewrite of this module may be needed in the future.
|
|
||||||
*/
|
|
||||||
class ProcessBuilder {
|
class ProcessBuilder {
|
||||||
|
|
||||||
constructor(distroServer, vanillaManifest, modManifest, authUser, launcherVersion){
|
constructor(distroServer, versionData, forgeData, authUser, launcherVersion){
|
||||||
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.rawServer.id)
|
this.gameDir = path.join(ConfigManager.getInstanceDirectory(), distroServer.getID())
|
||||||
this.commonDir = ConfigManager.getCommonDirectory()
|
this.commonDir = ConfigManager.getCommonDirectory()
|
||||||
this.server = distroServer
|
this.server = distroServer
|
||||||
this.vanillaManifest = vanillaManifest
|
this.versionData = versionData
|
||||||
this.modManifest = modManifest
|
this.forgeData = forgeData
|
||||||
this.authUser = authUser
|
this.authUser = authUser
|
||||||
this.launcherVersion = launcherVersion
|
this.launcherVersion = launcherVersion
|
||||||
this.forgeModListFile = path.join(this.gameDir, 'forgeMods.list') // 1.13+
|
this.forgeModListFile = path.join(this.gameDir, 'forgeMods.list') // 1.13+
|
||||||
@ -37,7 +29,6 @@ class ProcessBuilder {
|
|||||||
this.libPath = path.join(this.commonDir, 'libraries')
|
this.libPath = path.join(this.commonDir, 'libraries')
|
||||||
|
|
||||||
this.usingLiteLoader = false
|
this.usingLiteLoader = false
|
||||||
this.usingFabricLoader = false
|
|
||||||
this.llPath = null
|
this.llPath = null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,14 +40,11 @@ class ProcessBuilder {
|
|||||||
const tempNativePath = path.join(os.tmpdir(), ConfigManager.getTempNativeFolder(), crypto.pseudoRandomBytes(16).toString('hex'))
|
const tempNativePath = path.join(os.tmpdir(), ConfigManager.getTempNativeFolder(), crypto.pseudoRandomBytes(16).toString('hex'))
|
||||||
process.throwDeprecation = true
|
process.throwDeprecation = true
|
||||||
this.setupLiteLoader()
|
this.setupLiteLoader()
|
||||||
logger.info('Using liteloader:', this.usingLiteLoader)
|
logger.log('Using liteloader:', this.usingLiteLoader)
|
||||||
this.usingFabricLoader = this.server.modules.some(mdl => mdl.rawModule.type === Type.Fabric)
|
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.getID()).mods, this.server.getModules())
|
||||||
logger.info('Using fabric loader:', this.usingFabricLoader)
|
|
||||||
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules)
|
|
||||||
|
|
||||||
// Mod list below 1.13
|
// Mod list below 1.13
|
||||||
// Fabric only supports 1.14+
|
if(!Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
|
||||||
if(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
|
||||||
this.constructJSONModList('forge', modObj.fMods, true)
|
this.constructJSONModList('forge', modObj.fMods, true)
|
||||||
if(this.usingLiteLoader){
|
if(this.usingLiteLoader){
|
||||||
this.constructJSONModList('liteloader', modObj.lMods, true)
|
this.constructJSONModList('liteloader', modObj.lMods, true)
|
||||||
@ -66,14 +54,14 @@ class ProcessBuilder {
|
|||||||
const uberModArr = modObj.fMods.concat(modObj.lMods)
|
const uberModArr = modObj.fMods.concat(modObj.lMods)
|
||||||
let args = this.constructJVMArguments(uberModArr, tempNativePath)
|
let args = this.constructJVMArguments(uberModArr, tempNativePath)
|
||||||
|
|
||||||
if(mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
|
||||||
//args = args.concat(this.constructModArguments(modObj.fMods))
|
//args = args.concat(this.constructModArguments(modObj.fMods))
|
||||||
args = args.concat(this.constructModList(modObj.fMods))
|
args = args.concat(this.constructModList(modObj.fMods))
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('Launch Arguments:', args)
|
logger.log('Launch Arguments:', args)
|
||||||
|
|
||||||
const child = child_process.spawn(ConfigManager.getJavaExecutable(this.server.rawServer.id), args, {
|
const child = child_process.spawn(ConfigManager.getJavaExecutable(), args, {
|
||||||
cwd: this.gameDir,
|
cwd: this.gameDir,
|
||||||
detached: ConfigManager.getLaunchDetached()
|
detached: ConfigManager.getLaunchDetached()
|
||||||
})
|
})
|
||||||
@ -85,20 +73,22 @@ class ProcessBuilder {
|
|||||||
child.stdout.setEncoding('utf8')
|
child.stdout.setEncoding('utf8')
|
||||||
child.stderr.setEncoding('utf8')
|
child.stderr.setEncoding('utf8')
|
||||||
|
|
||||||
|
const loggerMCstdout = LoggerUtil('%c[Minecraft]', 'color: #36b030; font-weight: bold')
|
||||||
|
const loggerMCstderr = LoggerUtil('%c[Minecraft]', 'color: #b03030; font-weight: bold')
|
||||||
|
|
||||||
child.stdout.on('data', (data) => {
|
child.stdout.on('data', (data) => {
|
||||||
data.trim().split('\n').forEach(x => console.log(`\x1b[32m[Minecraft]\x1b[0m ${x}`))
|
loggerMCstdout.log(data)
|
||||||
|
|
||||||
})
|
})
|
||||||
child.stderr.on('data', (data) => {
|
child.stderr.on('data', (data) => {
|
||||||
data.trim().split('\n').forEach(x => console.log(`\x1b[31m[Minecraft]\x1b[0m ${x}`))
|
loggerMCstderr.log(data)
|
||||||
})
|
})
|
||||||
child.on('close', (code, signal) => {
|
child.on('close', (code, signal) => {
|
||||||
logger.info('Exited with code', code)
|
logger.log('Exited with code', code)
|
||||||
fs.remove(tempNativePath, (err) => {
|
fs.remove(tempNativePath, (err) => {
|
||||||
if(err){
|
if(err){
|
||||||
logger.warn('Error while deleting temp dir', err)
|
logger.warn('Error while deleting temp dir', err)
|
||||||
} else {
|
} else {
|
||||||
logger.info('Temp dir deleted successfully.')
|
logger.log('Temp dir deleted successfully.')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -106,16 +96,6 @@ class ProcessBuilder {
|
|||||||
return child
|
return child
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the platform specific classpath separator. On windows, this is a semicolon.
|
|
||||||
* On Unix, this is a colon.
|
|
||||||
*
|
|
||||||
* @returns {string} The classpath separator for the current operating system.
|
|
||||||
*/
|
|
||||||
static getClasspathSeparator() {
|
|
||||||
return process.platform === 'win32' ? ';' : ':'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if an optional mod is enabled from its configuration value. If the
|
* Determine if an optional mod is enabled from its configuration value. If the
|
||||||
* configuration value is null, the required object will be used to
|
* configuration value is null, the required object will be used to
|
||||||
@ -134,7 +114,7 @@ class ProcessBuilder {
|
|||||||
* @returns {boolean} True if the mod is enabled, false otherwise.
|
* @returns {boolean} True if the mod is enabled, false otherwise.
|
||||||
*/
|
*/
|
||||||
static isModEnabled(modCfg, required = null){
|
static isModEnabled(modCfg, required = null){
|
||||||
return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.def : true
|
return modCfg != null ? ((typeof modCfg === 'boolean' && modCfg) || (typeof modCfg === 'object' && (typeof modCfg.value !== 'undefined' ? modCfg.value : true))) : required != null ? required.isDefault() : true
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,20 +124,20 @@ class ProcessBuilder {
|
|||||||
* mod. It must not be declared as a submodule.
|
* mod. It must not be declared as a submodule.
|
||||||
*/
|
*/
|
||||||
setupLiteLoader(){
|
setupLiteLoader(){
|
||||||
for(let ll of this.server.modules){
|
for(let ll of this.server.getModules()){
|
||||||
if(ll.rawModule.type === Type.LiteLoader){
|
if(ll.getType() === DistroManager.Types.LiteLoader){
|
||||||
if(!ll.getRequired().value){
|
if(!ll.getRequired().isRequired()){
|
||||||
const modCfg = ConfigManager.getModConfiguration(this.server.rawServer.id).mods
|
const modCfg = ConfigManager.getModConfiguration(this.server.getID()).mods
|
||||||
if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessMavenIdentifier()], ll.getRequired())){
|
if(ProcessBuilder.isModEnabled(modCfg[ll.getVersionlessID()], ll.getRequired())){
|
||||||
if(fs.existsSync(ll.getPath())){
|
if(fs.existsSync(ll.getArtifact().getPath())){
|
||||||
this.usingLiteLoader = true
|
this.usingLiteLoader = true
|
||||||
this.llPath = ll.getPath()
|
this.llPath = ll.getArtifact().getPath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(fs.existsSync(ll.getPath())){
|
if(fs.existsSync(ll.getArtifact().getPath())){
|
||||||
this.usingLiteLoader = true
|
this.usingLiteLoader = true
|
||||||
this.llPath = ll.getPath()
|
this.llPath = ll.getArtifact().getPath()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -178,20 +158,20 @@ class ProcessBuilder {
|
|||||||
let lMods = []
|
let lMods = []
|
||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.rawModule.type
|
const type = mdl.getType()
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||||
const o = !mdl.getRequired().value
|
const o = !mdl.getRequired().isRequired()
|
||||||
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
|
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessID()], mdl.getRequired())
|
||||||
if(!o || (o && e)){
|
if(!o || (o && e)){
|
||||||
if(mdl.subModules.length > 0){
|
if(mdl.hasSubModules()){
|
||||||
const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessMavenIdentifier()].mods, mdl.subModules)
|
const v = this.resolveModConfiguration(modCfg[mdl.getVersionlessID()].mods, mdl.getSubModules())
|
||||||
fMods = fMods.concat(v.fMods)
|
fMods = fMods.concat(v.fMods)
|
||||||
lMods = lMods.concat(v.lMods)
|
lMods = lMods.concat(v.lMods)
|
||||||
if(type === Type.LiteLoader){
|
if(mdl.type === DistroManager.Types.LiteLoader){
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(type === Type.ForgeMod || type === Type.FabricMod){
|
if(mdl.type === DistroManager.Types.ForgeMod){
|
||||||
fMods.push(mdl)
|
fMods.push(mdl)
|
||||||
} else {
|
} else {
|
||||||
lMods.push(mdl)
|
lMods.push(mdl)
|
||||||
@ -207,7 +187,7 @@ class ProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_lteMinorVersion(version) {
|
_lteMinorVersion(version) {
|
||||||
return Number(this.modManifest.id.split('-')[0].split('.')[1]) <= Number(version)
|
return Number(this.forgeData.id.split('-')[0].split('.')[1]) <= Number(version)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,7 +199,7 @@ class ProcessBuilder {
|
|||||||
if(this._lteMinorVersion(9)) {
|
if(this._lteMinorVersion(9)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const ver = this.modManifest.id.split('-')[2]
|
const ver = this.forgeData.id.split('-')[2]
|
||||||
const pts = ver.split('.')
|
const pts = ver.split('.')
|
||||||
const min = [14, 23, 3, 2655]
|
const min = [14, 23, 3, 2655]
|
||||||
for(let i=0; i<pts.length; i++){
|
for(let i=0; i<pts.length; i++){
|
||||||
@ -254,11 +234,11 @@ class ProcessBuilder {
|
|||||||
const ids = []
|
const ids = []
|
||||||
if(type === 'forge'){
|
if(type === 'forge'){
|
||||||
for(let mod of mods){
|
for(let mod of mods){
|
||||||
ids.push(mod.getExtensionlessMavenIdentifier())
|
ids.push(mod.getExtensionlessID())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for(let mod of mods){
|
for(let mod of mods){
|
||||||
ids.push(mod.getMavenIdentifier())
|
ids.push(mod.getExtensionlessID() + '@' + mod.getExtension())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modList.modRef = ids
|
modList.modRef = ids
|
||||||
@ -278,7 +258,7 @@ class ProcessBuilder {
|
|||||||
// */
|
// */
|
||||||
// constructModArguments(mods){
|
// constructModArguments(mods){
|
||||||
// const argStr = mods.map(mod => {
|
// const argStr = mods.map(mod => {
|
||||||
// return mod.getExtensionlessMavenIdentifier()
|
// return mod.getExtensionlessID()
|
||||||
// }).join(',')
|
// }).join(',')
|
||||||
|
|
||||||
// if(argStr){
|
// if(argStr){
|
||||||
@ -295,21 +275,18 @@ class ProcessBuilder {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct the mod argument list for forge 1.13 and Fabric
|
* Construct the mod argument list for forge 1.13
|
||||||
*
|
*
|
||||||
* @param {Array.<Object>} mods An array of mods to add to the mod list.
|
* @param {Array.<Object>} mods An array of mods to add to the mod list.
|
||||||
*/
|
*/
|
||||||
constructModList(mods) {
|
constructModList(mods) {
|
||||||
const writeBuffer = mods.map(mod => {
|
const writeBuffer = mods.map(mod => {
|
||||||
return this.usingFabricLoader ? mod.getPath() : mod.getExtensionlessMavenIdentifier()
|
return mod.getExtensionlessID()
|
||||||
}).join('\n')
|
}).join('\n')
|
||||||
|
|
||||||
if(writeBuffer) {
|
if(writeBuffer) {
|
||||||
fs.writeFileSync(this.forgeModListFile, writeBuffer, 'UTF-8')
|
fs.writeFileSync(this.forgeModListFile, writeBuffer, 'UTF-8')
|
||||||
return this.usingFabricLoader ? [
|
return [
|
||||||
'--fabric.addMods',
|
|
||||||
`@${this.forgeModListFile}`
|
|
||||||
] : [
|
|
||||||
'--fml.mavenRoots',
|
'--fml.mavenRoots',
|
||||||
path.join('..', '..', 'common', 'modstore'),
|
path.join('..', '..', 'common', 'modstore'),
|
||||||
'--fml.modLists',
|
'--fml.modLists',
|
||||||
@ -322,15 +299,13 @@ class ProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_processAutoConnectArg(args){
|
_processAutoConnectArg(args){
|
||||||
if(ConfigManager.getAutoConnect() && this.server.rawServer.autoconnect){
|
if(ConfigManager.getAutoConnect() && this.server.isAutoConnect()){
|
||||||
if(mcVersionAtLeast('1.20', this.server.rawServer.minecraftVersion)){
|
const serverURL = new URL('my://' + this.server.getAddress())
|
||||||
args.push('--quickPlayMultiplayer')
|
args.push('--server')
|
||||||
args.push(`${this.server.hostname}:${this.server.port}`)
|
args.push(serverURL.hostname)
|
||||||
} else {
|
if(serverURL.port){
|
||||||
args.push('--server')
|
|
||||||
args.push(this.server.hostname)
|
|
||||||
args.push('--port')
|
args.push('--port')
|
||||||
args.push(this.server.port)
|
args.push(serverURL.port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -343,7 +318,7 @@ class ProcessBuilder {
|
|||||||
* @returns {Array.<string>} An array containing the full JVM arguments for this process.
|
* @returns {Array.<string>} An array containing the full JVM arguments for this process.
|
||||||
*/
|
*/
|
||||||
constructJVMArguments(mods, tempNativePath){
|
constructJVMArguments(mods, tempNativePath){
|
||||||
if(mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
if(Util.mcVersionAtLeast('1.13', this.server.getMinecraftVersion())){
|
||||||
return this._constructJVMArguments113(mods, tempNativePath)
|
return this._constructJVMArguments113(mods, tempNativePath)
|
||||||
} else {
|
} else {
|
||||||
return this._constructJVMArguments112(mods, tempNativePath)
|
return this._constructJVMArguments112(mods, tempNativePath)
|
||||||
@ -364,20 +339,20 @@ class ProcessBuilder {
|
|||||||
|
|
||||||
// Classpath Argument
|
// Classpath Argument
|
||||||
args.push('-cp')
|
args.push('-cp')
|
||||||
args.push(this.classpathArg(mods, tempNativePath).join(ProcessBuilder.getClasspathSeparator()))
|
args.push(this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':'))
|
||||||
|
|
||||||
// Java Arguments
|
// Java Arguments
|
||||||
if(process.platform === 'darwin'){
|
if(process.platform === 'darwin'){
|
||||||
args.push('-Xdock:name=HeliosLauncher')
|
args.push('-Xdock:name=HeliosLauncher')
|
||||||
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
||||||
}
|
}
|
||||||
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.rawServer.id))
|
args.push('-Xmx' + ConfigManager.getMaxRAM())
|
||||||
args.push('-Xms' + ConfigManager.getMinRAM(this.server.rawServer.id))
|
args.push('-Xms' + ConfigManager.getMinRAM())
|
||||||
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
|
args = args.concat(ConfigManager.getJVMOptions())
|
||||||
args.push('-Djava.library.path=' + tempNativePath)
|
args.push('-Djava.library.path=' + tempNativePath)
|
||||||
|
|
||||||
// Main Java Class
|
// Main Java Class
|
||||||
args.push(this.modManifest.mainClass)
|
args.push(this.forgeData.mainClass)
|
||||||
|
|
||||||
// Forge Arguments
|
// Forge Arguments
|
||||||
args = args.concat(this._resolveForgeArgs())
|
args = args.concat(this._resolveForgeArgs())
|
||||||
@ -400,20 +375,7 @@ class ProcessBuilder {
|
|||||||
const argDiscovery = /\${*(.*)}/
|
const argDiscovery = /\${*(.*)}/
|
||||||
|
|
||||||
// JVM Arguments First
|
// JVM Arguments First
|
||||||
let args = this.vanillaManifest.arguments.jvm
|
let args = this.versionData.arguments.jvm
|
||||||
|
|
||||||
// Debug securejarhandler
|
|
||||||
// args.push('-Dbsl.debug=true')
|
|
||||||
|
|
||||||
if(this.modManifest.arguments.jvm != null) {
|
|
||||||
for(const argStr of this.modManifest.arguments.jvm) {
|
|
||||||
args.push(argStr
|
|
||||||
.replaceAll('${library_directory}', this.libPath)
|
|
||||||
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
|
|
||||||
.replaceAll('${version_name}', this.modManifest.id)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
|
//args.push('-Dlog4j.configurationFile=D:\\WesterosCraft\\game\\common\\assets\\log_configs\\client-1.12.xml')
|
||||||
|
|
||||||
@ -422,15 +384,15 @@ class ProcessBuilder {
|
|||||||
args.push('-Xdock:name=HeliosLauncher')
|
args.push('-Xdock:name=HeliosLauncher')
|
||||||
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
args.push('-Xdock:icon=' + path.join(__dirname, '..', 'images', 'minecraft.icns'))
|
||||||
}
|
}
|
||||||
args.push('-Xmx' + ConfigManager.getMaxRAM(this.server.rawServer.id))
|
args.push('-Xmx' + ConfigManager.getMaxRAM())
|
||||||
args.push('-Xms' + ConfigManager.getMinRAM(this.server.rawServer.id))
|
args.push('-Xms' + ConfigManager.getMinRAM())
|
||||||
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
|
args = args.concat(ConfigManager.getJVMOptions())
|
||||||
|
|
||||||
// Main Java Class
|
// Main Java Class
|
||||||
args.push(this.modManifest.mainClass)
|
args.push(this.forgeData.mainClass)
|
||||||
|
|
||||||
// Vanilla Arguments
|
// Vanilla Arguments
|
||||||
args = args.concat(this.vanillaManifest.arguments.game)
|
args = args.concat(this.versionData.arguments.game)
|
||||||
|
|
||||||
for(let i=0; i<args.length; i++){
|
for(let i=0; i<args.length; i++){
|
||||||
if(typeof args[i] === 'object' && args[i].rules != null){
|
if(typeof args[i] === 'object' && args[i].rules != null){
|
||||||
@ -438,7 +400,7 @@ class ProcessBuilder {
|
|||||||
let checksum = 0
|
let checksum = 0
|
||||||
for(let rule of args[i].rules){
|
for(let rule of args[i].rules){
|
||||||
if(rule.os != null){
|
if(rule.os != null){
|
||||||
if(rule.os.name === getMojangOS()
|
if(rule.os.name === Library.mojangFriendlyOS()
|
||||||
&& (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){
|
&& (rule.os.version == null || new RegExp(rule.os.version).test(os.release))){
|
||||||
if(rule.action === 'allow'){
|
if(rule.action === 'allow'){
|
||||||
checksum++
|
checksum++
|
||||||
@ -487,8 +449,8 @@ class ProcessBuilder {
|
|||||||
val = this.authUser.displayName.trim()
|
val = this.authUser.displayName.trim()
|
||||||
break
|
break
|
||||||
case 'version_name':
|
case 'version_name':
|
||||||
//val = vanillaManifest.id
|
//val = versionData.id
|
||||||
val = this.server.rawServer.id
|
val = this.server.getID()
|
||||||
break
|
break
|
||||||
case 'game_directory':
|
case 'game_directory':
|
||||||
val = this.gameDir
|
val = this.gameDir
|
||||||
@ -497,7 +459,7 @@ class ProcessBuilder {
|
|||||||
val = path.join(this.commonDir, 'assets')
|
val = path.join(this.commonDir, 'assets')
|
||||||
break
|
break
|
||||||
case 'assets_index_name':
|
case 'assets_index_name':
|
||||||
val = this.vanillaManifest.assets
|
val = this.versionData.assets
|
||||||
break
|
break
|
||||||
case 'auth_uuid':
|
case 'auth_uuid':
|
||||||
val = this.authUser.uuid.trim()
|
val = this.authUser.uuid.trim()
|
||||||
@ -509,7 +471,7 @@ class ProcessBuilder {
|
|||||||
val = this.authUser.type === 'microsoft' ? 'msa' : 'mojang'
|
val = this.authUser.type === 'microsoft' ? 'msa' : 'mojang'
|
||||||
break
|
break
|
||||||
case 'version_type':
|
case 'version_type':
|
||||||
val = this.vanillaManifest.type
|
val = this.versionData.type
|
||||||
break
|
break
|
||||||
case 'resolution_width':
|
case 'resolution_width':
|
||||||
val = ConfigManager.getGameWidth()
|
val = ConfigManager.getGameWidth()
|
||||||
@ -527,7 +489,7 @@ class ProcessBuilder {
|
|||||||
val = args[i].replace(argDiscovery, this.launcherVersion)
|
val = args[i].replace(argDiscovery, this.launcherVersion)
|
||||||
break
|
break
|
||||||
case 'classpath':
|
case 'classpath':
|
||||||
val = this.classpathArg(mods, tempNativePath).join(ProcessBuilder.getClasspathSeparator())
|
val = this.classpathArg(mods, tempNativePath).join(process.platform === 'win32' ? ';' : ':')
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if(val != null){
|
if(val != null){
|
||||||
@ -538,11 +500,25 @@ class ProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Autoconnect
|
// Autoconnect
|
||||||
this._processAutoConnectArg(args)
|
let isAutoconnectBroken
|
||||||
|
try {
|
||||||
|
isAutoconnectBroken = Util.isAutoconnectBroken(this.forgeData.id.split('-')[2])
|
||||||
|
} catch(err) {
|
||||||
|
logger.error(err)
|
||||||
|
logger.error('Forge version format changed.. assuming autoconnect works.')
|
||||||
|
logger.debug('Forge version:', this.forgeData.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isAutoconnectBroken) {
|
||||||
|
logger.error('Server autoconnect disabled on Forge 1.15.2 for builds earlier than 31.2.15 due to OpenGL Stack Overflow issue.')
|
||||||
|
logger.error('Please upgrade your Forge version to at least 31.2.15!')
|
||||||
|
} else {
|
||||||
|
this._processAutoConnectArg(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Forge Specific Arguments
|
// Forge Specific Arguments
|
||||||
args = args.concat(this.modManifest.arguments.game)
|
args = args.concat(this.forgeData.arguments.game)
|
||||||
|
|
||||||
// Filter null values
|
// Filter null values
|
||||||
args = args.filter(arg => {
|
args = args.filter(arg => {
|
||||||
@ -558,7 +534,7 @@ class ProcessBuilder {
|
|||||||
* @returns {Array.<string>} An array containing the arguments required by forge.
|
* @returns {Array.<string>} An array containing the arguments required by forge.
|
||||||
*/
|
*/
|
||||||
_resolveForgeArgs(){
|
_resolveForgeArgs(){
|
||||||
const mcArgs = this.modManifest.minecraftArguments.split(' ')
|
const mcArgs = this.forgeData.minecraftArguments.split(' ')
|
||||||
const argDiscovery = /\${*(.*)}/
|
const argDiscovery = /\${*(.*)}/
|
||||||
|
|
||||||
// Replace the declared variables with their proper values.
|
// Replace the declared variables with their proper values.
|
||||||
@ -571,8 +547,8 @@ class ProcessBuilder {
|
|||||||
val = this.authUser.displayName.trim()
|
val = this.authUser.displayName.trim()
|
||||||
break
|
break
|
||||||
case 'version_name':
|
case 'version_name':
|
||||||
//val = vanillaManifest.id
|
//val = versionData.id
|
||||||
val = this.server.rawServer.id
|
val = this.server.getID()
|
||||||
break
|
break
|
||||||
case 'game_directory':
|
case 'game_directory':
|
||||||
val = this.gameDir
|
val = this.gameDir
|
||||||
@ -581,7 +557,7 @@ class ProcessBuilder {
|
|||||||
val = path.join(this.commonDir, 'assets')
|
val = path.join(this.commonDir, 'assets')
|
||||||
break
|
break
|
||||||
case 'assets_index_name':
|
case 'assets_index_name':
|
||||||
val = this.vanillaManifest.assets
|
val = this.versionData.assets
|
||||||
break
|
break
|
||||||
case 'auth_uuid':
|
case 'auth_uuid':
|
||||||
val = this.authUser.uuid.trim()
|
val = this.authUser.uuid.trim()
|
||||||
@ -596,7 +572,7 @@ class ProcessBuilder {
|
|||||||
val = '{}'
|
val = '{}'
|
||||||
break
|
break
|
||||||
case 'version_type':
|
case 'version_type':
|
||||||
val = this.vanillaManifest.type
|
val = this.versionData.type
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if(val != null){
|
if(val != null){
|
||||||
@ -671,13 +647,9 @@ class ProcessBuilder {
|
|||||||
classpathArg(mods, tempNativePath){
|
classpathArg(mods, tempNativePath){
|
||||||
let cpArgs = []
|
let cpArgs = []
|
||||||
|
|
||||||
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion) || this.usingFabricLoader) {
|
// Add the version.jar to the classpath.
|
||||||
// Add the version.jar to the classpath.
|
const version = this.versionData.id
|
||||||
// Must not be added to the classpath for Forge 1.17+.
|
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
||||||
const version = this.vanillaManifest.id
|
|
||||||
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if(this.usingLiteLoader){
|
if(this.usingLiteLoader){
|
||||||
cpArgs.push(this.llPath)
|
cpArgs.push(this.llPath)
|
||||||
@ -710,31 +682,34 @@ class ProcessBuilder {
|
|||||||
* @returns {{[id: string]: string}} An object containing the paths of each library mojang declares.
|
* @returns {{[id: string]: string}} An object containing the paths of each library mojang declares.
|
||||||
*/
|
*/
|
||||||
_resolveMojangLibraries(tempNativePath){
|
_resolveMojangLibraries(tempNativePath){
|
||||||
const nativesRegex = /.+:natives-([^-]+)(?:-(.+))?/
|
|
||||||
const libs = {}
|
const libs = {}
|
||||||
|
|
||||||
const libArr = this.vanillaManifest.libraries
|
const libArr = this.versionData.libraries
|
||||||
fs.ensureDirSync(tempNativePath)
|
fs.ensureDirSync(tempNativePath)
|
||||||
for(let i=0; i<libArr.length; i++){
|
for(let i=0; i<libArr.length; i++){
|
||||||
const lib = libArr[i]
|
const lib = libArr[i]
|
||||||
if(isLibraryCompatible(lib.rules, lib.natives)){
|
if(Library.validateRules(lib.rules, lib.natives)){
|
||||||
|
if(lib.natives == null){
|
||||||
// Pre-1.19 has a natives object.
|
const dlInfo = lib.downloads
|
||||||
if(lib.natives != null) {
|
const artifact = dlInfo.artifact
|
||||||
|
const to = path.join(this.libPath, artifact.path)
|
||||||
|
const versionIndependentId = lib.name.substring(0, lib.name.lastIndexOf(':'))
|
||||||
|
libs[versionIndependentId] = to
|
||||||
|
} else {
|
||||||
// Extract the native library.
|
// Extract the native library.
|
||||||
const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/']
|
const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/']
|
||||||
const artifact = lib.downloads.classifiers[lib.natives[getMojangOS()].replace('${arch}', process.arch.replace('x', ''))]
|
const artifact = lib.downloads.classifiers[lib.natives[Library.mojangFriendlyOS()].replace('${arch}', process.arch.replace('x', ''))]
|
||||||
|
|
||||||
// Location of native zip.
|
// Location of native zip.
|
||||||
const to = path.join(this.libPath, artifact.path)
|
const to = path.join(this.libPath, artifact.path)
|
||||||
|
|
||||||
let zip = new AdmZip(to)
|
let zip = new AdmZip(to)
|
||||||
let zipEntries = zip.getEntries()
|
let zipEntries = zip.getEntries()
|
||||||
|
|
||||||
// Unzip the native zip.
|
// Unzip the native zip.
|
||||||
for(let i=0; i<zipEntries.length; i++){
|
for(let i=0; i<zipEntries.length; i++){
|
||||||
const fileName = zipEntries[i].entryName
|
const fileName = zipEntries[i].entryName
|
||||||
|
|
||||||
let shouldExclude = false
|
let shouldExclude = false
|
||||||
|
|
||||||
// Exclude noted files.
|
// Exclude noted files.
|
||||||
@ -752,68 +727,9 @@ class ProcessBuilder {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 1.19+ logic
|
|
||||||
else if(lib.name.includes('natives-')) {
|
|
||||||
|
|
||||||
const regexTest = nativesRegex.exec(lib.name)
|
|
||||||
// const os = regexTest[1]
|
|
||||||
const arch = regexTest[2] ?? 'x64'
|
|
||||||
|
|
||||||
if(arch != process.arch) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the native library.
|
|
||||||
const exclusionArr = lib.extract != null ? lib.extract.exclude : ['META-INF/', '.git', '.sha1']
|
|
||||||
const artifact = lib.downloads.artifact
|
|
||||||
|
|
||||||
// Location of native zip.
|
|
||||||
const to = path.join(this.libPath, artifact.path)
|
|
||||||
|
|
||||||
let zip = new AdmZip(to)
|
|
||||||
let zipEntries = zip.getEntries()
|
|
||||||
|
|
||||||
// Unzip the native zip.
|
|
||||||
for(let i=0; i<zipEntries.length; i++){
|
|
||||||
if(zipEntries[i].isDirectory) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileName = zipEntries[i].entryName
|
|
||||||
|
|
||||||
let shouldExclude = false
|
|
||||||
|
|
||||||
// Exclude noted files.
|
|
||||||
exclusionArr.forEach(function(exclusion){
|
|
||||||
if(fileName.indexOf(exclusion) > -1){
|
|
||||||
shouldExclude = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const extractName = fileName.includes('/') ? fileName.substring(fileName.lastIndexOf('/')) : fileName
|
|
||||||
|
|
||||||
// Extract the file.
|
|
||||||
if(!shouldExclude){
|
|
||||||
fs.writeFile(path.join(tempNativePath, extractName), zipEntries[i].getData(), (err) => {
|
|
||||||
if(err){
|
|
||||||
logger.error('Error while extracting native library:', err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// No natives
|
|
||||||
else {
|
|
||||||
const dlInfo = lib.downloads
|
|
||||||
const artifact = dlInfo.artifact
|
|
||||||
const to = path.join(this.libPath, artifact.path)
|
|
||||||
const versionIndependentId = lib.name.substring(0, lib.name.lastIndexOf(':'))
|
|
||||||
libs[versionIndependentId] = to
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,15 +745,15 @@ class ProcessBuilder {
|
|||||||
* @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
|
* @returns {{[id: string]: string}} An object containing the paths of each library this server requires.
|
||||||
*/
|
*/
|
||||||
_resolveServerLibraries(mods){
|
_resolveServerLibraries(mods){
|
||||||
const mdls = this.server.modules
|
const mdls = this.server.getModules()
|
||||||
let libs = {}
|
let libs = {}
|
||||||
|
|
||||||
// Locate Forge/Fabric/Libraries
|
// Locate Forge/Libraries
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.rawModule.type
|
const type = mdl.getType()
|
||||||
if(type === Type.ForgeHosted || type === Type.Fabric || type === Type.Library){
|
if(type === DistroManager.Types.ForgeHosted || type === DistroManager.Types.Library){
|
||||||
libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
|
libs[mdl.getVersionlessID()] = mdl.getArtifact().getPath()
|
||||||
if(mdl.subModules.length > 0){
|
if(mdl.hasSubModules()){
|
||||||
const res = this._resolveModuleLibraries(mdl)
|
const res = this._resolveModuleLibraries(mdl)
|
||||||
if(res.length > 0){
|
if(res.length > 0){
|
||||||
libs = {...libs, ...res}
|
libs = {...libs, ...res}
|
||||||
@ -866,20 +782,17 @@ class ProcessBuilder {
|
|||||||
* @returns {Array.<string>} An array containing the paths of each library this module requires.
|
* @returns {Array.<string>} An array containing the paths of each library this module requires.
|
||||||
*/
|
*/
|
||||||
_resolveModuleLibraries(mdl){
|
_resolveModuleLibraries(mdl){
|
||||||
if(!mdl.subModules.length > 0){
|
if(!mdl.hasSubModules()){
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
let libs = []
|
let libs = []
|
||||||
for(let sm of mdl.subModules){
|
for(let sm of mdl.getSubModules()){
|
||||||
if(sm.rawModule.type === Type.Library){
|
if(sm.getType() === DistroManager.Types.Library){
|
||||||
|
libs.push(sm.getArtifact().getPath())
|
||||||
if(sm.rawModule.classpath ?? true) {
|
|
||||||
libs.push(sm.getPath())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If this module has submodules, we need to resolve the libraries for those.
|
// If this module has submodules, we need to resolve the libraries for those.
|
||||||
// To avoid unnecessary recursive calls, base case is checked here.
|
// To avoid unnecessary recursive calls, base case is checked here.
|
||||||
if(mdl.subModules.length > 0){
|
if(mdl.hasSubModules()){
|
||||||
const res = this._resolveModuleLibraries(sm)
|
const res = this._resolveModuleLibraries(sm)
|
||||||
if(res.length > 0){
|
if(res.length > 0){
|
||||||
libs = libs.concat(res)
|
libs = libs.concat(res)
|
||||||
|
3
app/assets/js/scripts/dynmap.js
Normal file
3
app/assets/js/scripts/dynmap.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dynmapDoneButton.addEventListener('click', () => {
|
||||||
|
switchView(getCurrentView(), VIEWS.landing)
|
||||||
|
})
|
File diff suppressed because it is too large
Load Diff
@ -1,234 +1,239 @@
|
|||||||
/**
|
/**
|
||||||
* 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 = LoggerUtil1('%c[Login]', 'color: #000668; font-weight: bold')
|
||||||
/**
|
|
||||||
* Show a login error.
|
|
||||||
*
|
/**
|
||||||
* @param {HTMLElement} element The element on which to display the error.
|
* Show a login error.
|
||||||
* @param {string} value The error text.
|
*
|
||||||
*/
|
* @param {HTMLElement} element The element on which to display the error.
|
||||||
function showError(element, value){
|
* @param {string} value The error text.
|
||||||
element.innerHTML = value
|
*/
|
||||||
element.style.opacity = 1
|
function showError(element, value){
|
||||||
}
|
element.innerHTML = value
|
||||||
|
element.style.opacity = 1
|
||||||
/**
|
}
|
||||||
* Shake a login error to add emphasis.
|
|
||||||
*
|
/**
|
||||||
* @param {HTMLElement} element The element to shake.
|
* Shake a login error to add emphasis.
|
||||||
*/
|
*
|
||||||
function shakeError(element){
|
* @param {HTMLElement} element The element to shake.
|
||||||
if(element.style.opacity == 1){
|
*/
|
||||||
element.classList.remove('shake')
|
function shakeError(element){
|
||||||
void element.offsetWidth
|
if(element.style.opacity == 1){
|
||||||
element.classList.add('shake')
|
element.classList.remove('shake')
|
||||||
}
|
void element.offsetWidth
|
||||||
}
|
element.classList.add('shake')
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Validate that an email field is neither empty nor invalid.
|
|
||||||
*
|
/**
|
||||||
* @param {string} value The email value.
|
* Validate that an email field is neither empty nor invalid.
|
||||||
*/
|
*
|
||||||
function validateEmail(value){
|
* @param {string} value The email value.
|
||||||
if(value){
|
*/
|
||||||
if(!basicEmail.test(value) && !validUsername.test(value)){
|
function validateEmail(value){
|
||||||
showError(loginEmailError, Lang.queryJS('login.error.invalidValue'))
|
if(value){
|
||||||
loginDisabled(true)
|
if(!basicEmail.test(value) && !validUsername.test(value)){
|
||||||
lu = false
|
showError(loginEmailError, Lang.queryJS('login.error.invalidValue'))
|
||||||
} else {
|
loginDisabled(true)
|
||||||
loginEmailError.style.opacity = 0
|
lu = false
|
||||||
lu = true
|
} else {
|
||||||
if(lp){
|
loginEmailError.style.opacity = 0
|
||||||
loginDisabled(false)
|
lu = true
|
||||||
}
|
if(lp){
|
||||||
}
|
loginDisabled(false)
|
||||||
} else {
|
}
|
||||||
lu = false
|
}
|
||||||
showError(loginEmailError, Lang.queryJS('login.error.requiredValue'))
|
} else {
|
||||||
loginDisabled(true)
|
lu = false
|
||||||
}
|
showError(loginEmailError, Lang.queryJS('login.error.requiredValue'))
|
||||||
}
|
loginDisabled(true)
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Validate that the password field is not empty.
|
|
||||||
*
|
/**
|
||||||
* @param {string} value The password value.
|
* Validate that the password field is not empty.
|
||||||
*/
|
*
|
||||||
function validatePassword(value){
|
* @param {string} value The password value.
|
||||||
if(value){
|
*/
|
||||||
loginPasswordError.style.opacity = 0
|
function validatePassword(value){
|
||||||
lp = true
|
if(value){
|
||||||
if(lu){
|
loginPasswordError.style.opacity = 0
|
||||||
loginDisabled(false)
|
lp = true
|
||||||
}
|
if(lu){
|
||||||
} else {
|
loginDisabled(false)
|
||||||
lp = false
|
}
|
||||||
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
|
} else {
|
||||||
loginDisabled(true)
|
lp = false
|
||||||
}
|
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
|
||||||
}
|
loginDisabled(true)
|
||||||
|
}
|
||||||
// Emphasize errors with shake when focus is lost.
|
}
|
||||||
loginUsername.addEventListener('focusout', (e) => {
|
|
||||||
validateEmail(e.target.value)
|
// Emphasize errors with shake when focus is lost.
|
||||||
shakeError(loginEmailError)
|
loginUsername.addEventListener('focusout', (e) => {
|
||||||
})
|
validateEmail(e.target.value)
|
||||||
loginPassword.addEventListener('focusout', (e) => {
|
shakeError(loginEmailError)
|
||||||
validatePassword(e.target.value)
|
})
|
||||||
shakeError(loginPasswordError)
|
loginPassword.addEventListener('focusout', (e) => {
|
||||||
})
|
validatePassword(e.target.value)
|
||||||
|
shakeError(loginPasswordError)
|
||||||
// Validate input for each field.
|
})
|
||||||
loginUsername.addEventListener('input', (e) => {
|
|
||||||
validateEmail(e.target.value)
|
// Validate input for each field.
|
||||||
})
|
loginUsername.addEventListener('input', (e) => {
|
||||||
loginPassword.addEventListener('input', (e) => {
|
validateEmail(e.target.value)
|
||||||
validatePassword(e.target.value)
|
})
|
||||||
})
|
loginPassword.addEventListener('input', (e) => {
|
||||||
|
validatePassword(e.target.value)
|
||||||
/**
|
})
|
||||||
* Enable or disable the login button.
|
|
||||||
*
|
/**
|
||||||
* @param {boolean} v True to enable, false to disable.
|
* Enable or disable the login button.
|
||||||
*/
|
*
|
||||||
function loginDisabled(v){
|
* @param {boolean} v True to enable, false to disable.
|
||||||
if(loginButton.disabled !== v){
|
*/
|
||||||
loginButton.disabled = v
|
function loginDisabled(v){
|
||||||
}
|
if(loginButton.disabled !== v){
|
||||||
}
|
loginButton.disabled = v
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Enable or disable loading elements.
|
|
||||||
*
|
/**
|
||||||
* @param {boolean} v True to enable, false to disable.
|
* Enable or disable loading elements.
|
||||||
*/
|
*
|
||||||
function loginLoading(v){
|
* @param {boolean} v True to enable, false to disable.
|
||||||
if(v){
|
*/
|
||||||
loginButton.setAttribute('loading', v)
|
function loginLoading(v){
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn'))
|
if(v){
|
||||||
} else {
|
loginButton.setAttribute('loading', v)
|
||||||
loginButton.removeAttribute('loading')
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn'))
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login'))
|
} else {
|
||||||
}
|
loginButton.removeAttribute('loading')
|
||||||
}
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login'))
|
||||||
|
}
|
||||||
/**
|
}
|
||||||
* Enable or disable login form.
|
|
||||||
*
|
/**
|
||||||
* @param {boolean} v True to enable, false to disable.
|
* Enable or disable login form.
|
||||||
*/
|
*
|
||||||
function formDisabled(v){
|
* @param {boolean} v True to enable, false to disable.
|
||||||
loginDisabled(v)
|
*/
|
||||||
loginCancelButton.disabled = v
|
function formDisabled(v){
|
||||||
loginUsername.disabled = v
|
loginDisabled(v)
|
||||||
loginPassword.disabled = v
|
loginCancelButton.disabled = v
|
||||||
if(v){
|
loginUsername.disabled = v
|
||||||
checkmarkContainer.setAttribute('disabled', v)
|
loginPassword.disabled = v
|
||||||
} else {
|
if(v){
|
||||||
checkmarkContainer.removeAttribute('disabled')
|
checkmarkContainer.setAttribute('disabled', v)
|
||||||
}
|
} else {
|
||||||
loginRememberOption.disabled = v
|
checkmarkContainer.removeAttribute('disabled')
|
||||||
}
|
}
|
||||||
|
loginRememberOption.disabled = v
|
||||||
let loginViewOnSuccess = VIEWS.landing
|
}
|
||||||
let loginViewOnCancel = VIEWS.settings
|
|
||||||
let loginViewCancelHandler
|
let loginViewOnSuccess = VIEWS.landing
|
||||||
|
let loginViewOnCancel = VIEWS.settings
|
||||||
function loginCancelEnabled(val){
|
let loginViewCancelHandler
|
||||||
if(val){
|
|
||||||
$(loginCancelContainer).show()
|
function loginCancelEnabled(val){
|
||||||
} else {
|
if(val){
|
||||||
$(loginCancelContainer).hide()
|
$(loginCancelContainer).show()
|
||||||
}
|
} else {
|
||||||
}
|
$(loginCancelContainer).hide()
|
||||||
|
}
|
||||||
loginCancelButton.onclick = (e) => {
|
}
|
||||||
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
|
|
||||||
loginUsername.value = ''
|
loginCancelButton.onclick = (e) => {
|
||||||
loginPassword.value = ''
|
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
|
||||||
loginCancelEnabled(false)
|
loginUsername.value = ''
|
||||||
if(loginViewCancelHandler != null){
|
loginPassword.value = ''
|
||||||
loginViewCancelHandler()
|
loginCancelEnabled(false)
|
||||||
loginViewCancelHandler = null
|
if(loginViewCancelHandler != null){
|
||||||
}
|
loginViewCancelHandler()
|
||||||
})
|
loginViewCancelHandler = null
|
||||||
}
|
}
|
||||||
|
})
|
||||||
// Disable default form behavior.
|
}
|
||||||
loginForm.onsubmit = () => { return false }
|
|
||||||
|
// Disable default form behavior.
|
||||||
// Bind login button behavior.
|
loginForm.onsubmit = () => { return false }
|
||||||
loginButton.addEventListener('click', () => {
|
|
||||||
// Disable form.
|
// Bind login button behavior.
|
||||||
formDisabled(true)
|
loginButton.addEventListener('click', () => {
|
||||||
|
// Disable form.
|
||||||
// Show loading stuff.
|
formDisabled(true)
|
||||||
loginLoading(true)
|
|
||||||
|
// Show loading stuff.
|
||||||
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
loginLoading(true)
|
||||||
updateSelectedAccount(value)
|
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
||||||
$('.circle-loader').toggleClass('load-complete')
|
updateSelectedAccount(value)
|
||||||
$('.checkmark').toggle()
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
||||||
setTimeout(() => {
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, async () => {
|
$('.checkmark').toggle()
|
||||||
// Temporary workaround
|
setTimeout(() => {
|
||||||
if(loginViewOnSuccess === VIEWS.settings){
|
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => {
|
||||||
await prepareSettings()
|
// Temporary workaround
|
||||||
}
|
if(loginViewOnSuccess === VIEWS.settings){
|
||||||
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
prepareSettings()
|
||||||
loginCancelEnabled(false) // Reset this for good measure.
|
}
|
||||||
loginViewCancelHandler = null // Reset this for good measure.
|
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
||||||
loginUsername.value = ''
|
loginCancelEnabled(false) // Reset this for good measure.
|
||||||
loginPassword.value = ''
|
loginViewCancelHandler = null // Reset this for good measure.
|
||||||
$('.circle-loader').toggleClass('load-complete')
|
loginUsername.value = ''
|
||||||
$('.checkmark').toggle()
|
loginPassword.value = ''
|
||||||
loginLoading(false)
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
|
$('.checkmark').toggle()
|
||||||
formDisabled(false)
|
loginLoading(false)
|
||||||
})
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
|
||||||
}, 1000)
|
formDisabled(false)
|
||||||
}).catch((displayableError) => {
|
})
|
||||||
loginLoading(false)
|
}, 1000)
|
||||||
|
}).catch((displayableError) => {
|
||||||
let actualDisplayableError
|
loginLoading(false)
|
||||||
if(isDisplayableError(displayableError)) {
|
|
||||||
msftLoginLogger.error('Error while logging in.', displayableError)
|
let actualDisplayableError
|
||||||
actualDisplayableError = displayableError
|
if(isDisplayableError(displayableError)) {
|
||||||
} else {
|
msftLoginLogger.error('Error while logging in.', displayableError)
|
||||||
// Uh oh.
|
actualDisplayableError = displayableError
|
||||||
msftLoginLogger.error('Unhandled error during login.', displayableError)
|
} else {
|
||||||
actualDisplayableError = Lang.queryJS('login.error.unknown')
|
// Uh oh.
|
||||||
}
|
msftLoginLogger.error('Unhandled error during login.', displayableError)
|
||||||
|
actualDisplayableError = {
|
||||||
setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain'))
|
title: 'Unknown Error During Login',
|
||||||
setOverlayHandler(() => {
|
desc: 'An unknown error has occurred. Please see the console for details.'
|
||||||
formDisabled(false)
|
}
|
||||||
toggleOverlay(false)
|
}
|
||||||
})
|
|
||||||
toggleOverlay(true)
|
setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain'))
|
||||||
})
|
setOverlayHandler(() => {
|
||||||
|
formDisabled(false)
|
||||||
|
toggleOverlay(false)
|
||||||
|
})
|
||||||
|
toggleOverlay(true)
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
39
app/assets/js/scripts/loginOffline.js
Normal file
39
app/assets/js/scripts/loginOffline.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
const loggerOfflineLogin = LoggerUtil1('%c[LoginOffline]', 'color: #000668; font-weight: bold')
|
||||||
|
|
||||||
|
const loginOfflineButton = document.getElementById('loginOfflineButton')
|
||||||
|
const loginOfflineCancelContainer = document.getElementById('loginOfflineCancelContainer')
|
||||||
|
const loginOfflineCancelButton = document.getElementById('loginOfflineCancelButton')
|
||||||
|
|
||||||
|
function loginOfflineDisabled(v){
|
||||||
|
if(loginOfflineButton.disabled !== v){
|
||||||
|
loginOfflineButton.disabled = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function formOfflineDisabled(v){
|
||||||
|
loginOfflineDisabled(v)
|
||||||
|
loginOfflineUsername.disabled = v
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
loginOfflineButton.addEventListener('click', () => {
|
||||||
|
formOfflineDisabled(true)
|
||||||
|
AuthManager.addOfflineAccount(loginOfflineUsername.value).then((value) =>{
|
||||||
|
switchView(VIEWS.loginOffline, VIEWS.landing, 500, 500)
|
||||||
|
|
||||||
|
})
|
||||||
|
loginOfflineUsername = ''
|
||||||
|
})
|
||||||
|
|
||||||
|
loginOfflineCancelButton.addEventListener('click', () => {
|
||||||
|
if (Object.keys(ConfigManager.getAuthAccounts()).length === 0) {
|
||||||
|
loginOfflineUsername.value = ''
|
||||||
|
switchView(VIEWS.loginOffline, VIEWS.loginOptions, 500, 500)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
loginOfflineUsername.value = ''
|
||||||
|
switchView(VIEWS.loginOffline, VIEWS.landing, 500, 500)
|
||||||
|
}
|
||||||
|
})
|
@ -1,50 +1,45 @@
|
|||||||
const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer')
|
const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer')
|
||||||
const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft')
|
const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft')
|
||||||
const loginOptionMojang = document.getElementById('loginOptionMojang')
|
const loginOptionMojang = document.getElementById('loginOptionMojang')
|
||||||
const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton')
|
const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton')
|
||||||
|
|
||||||
let loginOptionsCancellable = false
|
let loginOptionsCancellable = true
|
||||||
|
|
||||||
let loginOptionsViewOnLoginSuccess
|
let loginOptionsViewOnLoginSuccess
|
||||||
let loginOptionsViewOnLoginCancel
|
let loginOptionsViewOnLoginCancel
|
||||||
let loginOptionsViewOnCancel
|
let loginOptionsViewOnCancel
|
||||||
let loginOptionsViewCancelHandler
|
let loginOptionsViewCancelHandler
|
||||||
|
|
||||||
function loginOptionsCancelEnabled(val){
|
function loginOptionsCancelEnabled(val){
|
||||||
if(val){
|
if(val){
|
||||||
$(loginOptionsCancelContainer).show()
|
$(loginOptionsCancelContainer).show()
|
||||||
} else {
|
} else {
|
||||||
$(loginOptionsCancelContainer).hide()
|
$(loginOptionsCancelContainer).hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginOptionMicrosoft.onclick = (e) => {
|
loginOptionMicrosoft.onclick = (e) => {
|
||||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||||
ipcRenderer.send(
|
ipcRenderer.send(
|
||||||
MSFT_OPCODE.OPEN_LOGIN,
|
MSFT_OPCODE.OPEN_LOGIN,
|
||||||
loginOptionsViewOnLoginSuccess,
|
loginOptionsViewOnLoginSuccess,
|
||||||
loginOptionsViewOnLoginCancel
|
loginOptionsViewOnLoginCancel
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
loginOptionMojang.onclick = (e) => {
|
loginOptionMojang.onclick = (e) => {
|
||||||
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
||||||
loginViewOnSuccess = loginOptionsViewOnLoginSuccess
|
loginViewOnSuccess = loginOptionsViewOnLoginSuccess
|
||||||
loginViewOnCancel = loginOptionsViewOnLoginCancel
|
loginViewOnCancel = loginOptionsViewOnLoginCancel
|
||||||
loginCancelEnabled(true)
|
loginCancelEnabled(true)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
loginOptionsCancelButton.onclick = (e) => {
|
loginOptionOffline.onclick = (e) => {
|
||||||
switchView(getCurrentView(), loginOptionsViewOnCancel, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.loginOffline, 500, 500, () => {
|
||||||
// Clear login values (Mojang login)
|
loginViewOnSuccess = loginOptionsViewOnLoginSuccess
|
||||||
// No cleanup needed for Microsoft.
|
loginViewOnCancel = loginOptionsViewOnLoginCancel
|
||||||
loginUsername.value = ''
|
loginCancelEnabled(true)
|
||||||
loginPassword.value = ''
|
})
|
||||||
if(loginOptionsViewCancelHandler != null){
|
}
|
||||||
loginOptionsViewCancelHandler()
|
|
||||||
loginOptionsViewCancelHandler = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
@ -117,8 +117,8 @@ function toggleOverlay(toggleState, dismissable = false, content = 'overlayConte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleServerSelection(toggleState){
|
function toggleServerSelection(toggleState){
|
||||||
await prepareServerSelectionList()
|
prepareServerSelectionList()
|
||||||
toggleOverlay(toggleState, true, 'serverSelectContent')
|
toggleOverlay(toggleState, true, 'serverSelectContent')
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ async function toggleServerSelection(toggleState){
|
|||||||
* @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 = Lang.queryJS('overlay.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
|
||||||
@ -171,11 +171,11 @@ function setDismissHandler(handler){
|
|||||||
|
|
||||||
/* Server Select View */
|
/* Server Select View */
|
||||||
|
|
||||||
document.getElementById('serverSelectConfirm').addEventListener('click', async () => {
|
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 = (await DistroAPI.getDistribution()).getServerById(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)
|
||||||
@ -184,13 +184,13 @@ document.getElementById('serverSelectConfirm').addEventListener('click', async (
|
|||||||
}
|
}
|
||||||
// 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 = (await DistroAPI.getDistribution()).getServerById(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', async () => {
|
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')){
|
||||||
@ -198,7 +198,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', async
|
|||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
updateSelectedAccount(authAcc)
|
updateSelectedAccount(authAcc)
|
||||||
if(getCurrentView() === VIEWS.settings) {
|
if(getCurrentView() === VIEWS.settings) {
|
||||||
await prepareSettings()
|
prepareSettings()
|
||||||
}
|
}
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
validateSelectedAccount()
|
validateSelectedAccount()
|
||||||
@ -211,7 +211,7 @@ document.getElementById('accountSelectConfirm').addEventListener('click', async
|
|||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
updateSelectedAccount(authAcc)
|
updateSelectedAccount(authAcc)
|
||||||
if(getCurrentView() === VIEWS.settings) {
|
if(getCurrentView() === VIEWS.settings) {
|
||||||
await prepareSettings()
|
prepareSettings()
|
||||||
}
|
}
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
validateSelectedAccount()
|
validateSelectedAccount()
|
||||||
@ -267,21 +267,21 @@ function setAccountListingHandlers(){
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function populateServerListings(){
|
function populateServerListings(){
|
||||||
const distro = await DistroAPI.getDistribution()
|
const distro = DistroManager.getDistribution()
|
||||||
const giaSel = ConfigManager.getSelectedServer()
|
const giaSel = ConfigManager.getSelectedServer()
|
||||||
const servers = distro.servers
|
const servers = distro.getServers()
|
||||||
let htmlString = ''
|
let htmlString = ''
|
||||||
for(const serv of servers){
|
for(const serv of servers){
|
||||||
htmlString += `<button class="serverListing" servid="${serv.rawServer.id}" ${serv.rawServer.id === giaSel ? 'selected' : ''}>
|
htmlString += `<button class="serverListing" servid="${serv.getID()}" ${serv.getID() === giaSel ? 'selected' : ''}>
|
||||||
<img class="serverListingImg" src="${serv.rawServer.icon}"/>
|
<img class="serverListingImg" src="${serv.getIcon()}"/>
|
||||||
<div class="serverListingDetails">
|
<div class="serverListingDetails">
|
||||||
<span class="serverListingName">${serv.rawServer.name}</span>
|
<span class="serverListingName">${serv.getName()}</span>
|
||||||
<span class="serverListingDescription">${serv.rawServer.description}</span>
|
<span class="serverListingDescription">${serv.getDescription()}</span>
|
||||||
<div class="serverListingInfo">
|
<div class="serverListingInfo">
|
||||||
<div class="serverListingVersion">${serv.rawServer.minecraftVersion}</div>
|
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div>
|
||||||
<div class="serverListingRevision">${serv.rawServer.version}</div>
|
<div class="serverListingRevision">${serv.getVersion()}</div>
|
||||||
${serv.rawServer.mainServer ? `<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>
|
||||||
@ -289,7 +289,7 @@ async function populateServerListings(){
|
|||||||
<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">${Lang.queryJS('settings.serverListing.mainServer')}</span>
|
<span class="serverListingStarTooltip">Main Server</span>
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -313,8 +313,8 @@ function populateAccountListings(){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function prepareServerSelectionList(){
|
function prepareServerSelectionList(){
|
||||||
await populateServerListings()
|
populateServerListings()
|
||||||
setServerListingHandlers()
|
setServerListingHandlers()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
const os = require('os')
|
const os = require('os')
|
||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
|
|
||||||
|
const { JavaGuard } = require('./assets/js/assetguard')
|
||||||
const DropinModUtil = require('./assets/js/dropinmodutil')
|
const DropinModUtil = require('./assets/js/dropinmodutil')
|
||||||
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')
|
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')
|
||||||
|
|
||||||
@ -59,8 +60,8 @@ function bindFileSelectors(){
|
|||||||
|
|
||||||
if(isJavaExecSel && process.platform === 'win32') {
|
if(isJavaExecSel && process.platform === 'win32') {
|
||||||
options.filters = [
|
options.filters = [
|
||||||
{ name: Lang.queryJS('settings.fileSelectors.executables'), extensions: ['exe'] },
|
{ name: 'Executables', extensions: ['exe'] },
|
||||||
{ name: Lang.queryJS('settings.fileSelectors.allFiles'), extensions: ['*'] }
|
{ name: 'All Files', extensions: ['*'] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ function bindFileSelectors(){
|
|||||||
if(!res.canceled) {
|
if(!res.canceled) {
|
||||||
ele.previousElementSibling.value = res.filePaths[0]
|
ele.previousElementSibling.value = res.filePaths[0]
|
||||||
if(isJavaExecSel) {
|
if(isJavaExecSel) {
|
||||||
await populateJavaExecDetails(ele.previousElementSibling.value)
|
populateJavaExecDetails(ele.previousElementSibling.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -122,54 +123,48 @@ function initSettingsValidators(){
|
|||||||
/**
|
/**
|
||||||
* Load configuration values onto the UI. This is an automated process.
|
* Load configuration values onto the UI. This is an automated process.
|
||||||
*/
|
*/
|
||||||
async function initSettingsValues(){
|
function initSettingsValues(){
|
||||||
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
|
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
|
||||||
|
Array.from(sEls).map((v, index, arr) => {
|
||||||
for(const v of sEls) {
|
|
||||||
const cVal = v.getAttribute('cValue')
|
const cVal = v.getAttribute('cValue')
|
||||||
const serverDependent = v.hasAttribute('serverDependent') // Means the first argument is the server id.
|
|
||||||
const gFn = ConfigManager['get' + cVal]
|
const gFn = ConfigManager['get' + cVal]
|
||||||
const gFnOpts = []
|
|
||||||
if(serverDependent) {
|
|
||||||
gFnOpts.push(ConfigManager.getSelectedServer())
|
|
||||||
}
|
|
||||||
if(typeof gFn === 'function'){
|
if(typeof gFn === 'function'){
|
||||||
if(v.tagName === 'INPUT'){
|
if(v.tagName === 'INPUT'){
|
||||||
if(v.type === 'number' || v.type === 'text'){
|
if(v.type === 'number' || v.type === 'text'){
|
||||||
// Special Conditions
|
// Special Conditions
|
||||||
if(cVal === 'JavaExecutable'){
|
if(cVal === 'JavaExecutable'){
|
||||||
v.value = gFn.apply(null, gFnOpts)
|
populateJavaExecDetails(v.value)
|
||||||
await populateJavaExecDetails(v.value)
|
v.value = gFn()
|
||||||
} else if (cVal === 'DataDirectory'){
|
} else if (cVal === 'DataDirectory'){
|
||||||
v.value = gFn.apply(null, gFnOpts)
|
v.value = gFn()
|
||||||
} else if(cVal === 'JVMOptions'){
|
} else if(cVal === 'JVMOptions'){
|
||||||
v.value = gFn.apply(null, gFnOpts).join(' ')
|
v.value = gFn().join(' ')
|
||||||
} else {
|
} else {
|
||||||
v.value = gFn.apply(null, gFnOpts)
|
v.value = gFn()
|
||||||
}
|
}
|
||||||
} else if(v.type === 'checkbox'){
|
} else if(v.type === 'checkbox'){
|
||||||
v.checked = gFn.apply(null, gFnOpts)
|
v.checked = gFn()
|
||||||
}
|
}
|
||||||
} else if(v.tagName === 'DIV'){
|
} else if(v.tagName === 'DIV'){
|
||||||
if(v.classList.contains('rangeSlider')){
|
if(v.classList.contains('rangeSlider')){
|
||||||
// Special Conditions
|
// Special Conditions
|
||||||
if(cVal === 'MinRAM' || cVal === 'MaxRAM'){
|
if(cVal === 'MinRAM' || cVal === 'MaxRAM'){
|
||||||
let val = gFn.apply(null, gFnOpts)
|
let val = gFn()
|
||||||
if(val.endsWith('M')){
|
if(val.endsWith('M')){
|
||||||
val = Number(val.substring(0, val.length-1))/1024
|
val = Number(val.substring(0, val.length-1))/1000
|
||||||
} else {
|
} else {
|
||||||
val = Number.parseFloat(val)
|
val = Number.parseFloat(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
v.setAttribute('value', val)
|
v.setAttribute('value', val)
|
||||||
} else {
|
} else {
|
||||||
v.setAttribute('value', Number.parseFloat(gFn.apply(null, gFnOpts)))
|
v.setAttribute('value', Number.parseFloat(gFn()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -179,31 +174,22 @@ function saveSettingsValues(){
|
|||||||
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
|
const sEls = document.getElementById('settingsContainer').querySelectorAll('[cValue]')
|
||||||
Array.from(sEls).map((v, index, arr) => {
|
Array.from(sEls).map((v, index, arr) => {
|
||||||
const cVal = v.getAttribute('cValue')
|
const cVal = v.getAttribute('cValue')
|
||||||
const serverDependent = v.hasAttribute('serverDependent') // Means the first argument is the server id.
|
|
||||||
const sFn = ConfigManager['set' + cVal]
|
const sFn = ConfigManager['set' + cVal]
|
||||||
const sFnOpts = []
|
|
||||||
if(serverDependent) {
|
|
||||||
sFnOpts.push(ConfigManager.getSelectedServer())
|
|
||||||
}
|
|
||||||
if(typeof sFn === 'function'){
|
if(typeof sFn === 'function'){
|
||||||
if(v.tagName === 'INPUT'){
|
if(v.tagName === 'INPUT'){
|
||||||
if(v.type === 'number' || v.type === 'text'){
|
if(v.type === 'number' || v.type === 'text'){
|
||||||
// Special Conditions
|
// Special Conditions
|
||||||
if(cVal === 'JVMOptions'){
|
if(cVal === 'JVMOptions'){
|
||||||
if(!v.value.trim()) {
|
if(!v.value.trim()) {
|
||||||
sFnOpts.push([])
|
sFn([])
|
||||||
sFn.apply(null, sFnOpts)
|
|
||||||
} else {
|
} else {
|
||||||
sFnOpts.push(v.value.trim().split(/\s+/))
|
sFn(v.value.trim().split(/\s+/))
|
||||||
sFn.apply(null, sFnOpts)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sFnOpts.push(v.value)
|
sFn(v.value)
|
||||||
sFn.apply(null, sFnOpts)
|
|
||||||
}
|
}
|
||||||
} else if(v.type === 'checkbox'){
|
} else if(v.type === 'checkbox'){
|
||||||
sFnOpts.push(v.checked)
|
sFn(v.checked)
|
||||||
sFn.apply(null, sFnOpts)
|
|
||||||
// Special Conditions
|
// Special Conditions
|
||||||
if(cVal === 'AllowPrerelease'){
|
if(cVal === 'AllowPrerelease'){
|
||||||
changeAllowPrerelease(v.checked)
|
changeAllowPrerelease(v.checked)
|
||||||
@ -215,16 +201,14 @@ function saveSettingsValues(){
|
|||||||
if(cVal === 'MinRAM' || cVal === 'MaxRAM'){
|
if(cVal === 'MinRAM' || cVal === 'MaxRAM'){
|
||||||
let val = Number(v.getAttribute('value'))
|
let val = Number(v.getAttribute('value'))
|
||||||
if(val%1 > 0){
|
if(val%1 > 0){
|
||||||
val = val*1024 + 'M'
|
val = val*1000 + 'M'
|
||||||
} else {
|
} else {
|
||||||
val = val + 'G'
|
val = val + 'G'
|
||||||
}
|
}
|
||||||
|
|
||||||
sFnOpts.push(val)
|
sFn(val)
|
||||||
sFn.apply(null, sFnOpts)
|
|
||||||
} else {
|
} else {
|
||||||
sFnOpts.push(v.getAttribute('value'))
|
sFn(v.getAttribute('value'))
|
||||||
sFn.apply(null, sFnOpts)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,17 +305,13 @@ function settingsSaveDisabled(v){
|
|||||||
settingsNavDone.disabled = v
|
settingsNavDone.disabled = v
|
||||||
}
|
}
|
||||||
|
|
||||||
function fullSettingsSave() {
|
/* Closes the settings view and saves all data. */
|
||||||
|
settingsNavDone.onclick = () => {
|
||||||
saveSettingsValues()
|
saveSettingsValues()
|
||||||
saveModConfiguration()
|
saveModConfiguration()
|
||||||
ConfigManager.save()
|
ConfigManager.save()
|
||||||
saveDropinModConfiguration()
|
saveDropinModConfiguration()
|
||||||
saveShaderpackSettings()
|
saveShaderpackSettings()
|
||||||
}
|
|
||||||
|
|
||||||
/* Closes the settings view and saves all data. */
|
|
||||||
settingsNavDone.onclick = () => {
|
|
||||||
fullSettingsSave()
|
|
||||||
switchView(getCurrentView(), VIEWS.landing)
|
switchView(getCurrentView(), VIEWS.landing)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,6 +331,14 @@ document.getElementById('settingsAddMojangAccount').onclick = (e) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById('settingsAddOfflineAccount').onclick = (e) => {
|
||||||
|
switchView(getCurrentView(), VIEWS.loginOffline, 500, 500, () => {
|
||||||
|
loginViewOnCancel = VIEWS.settings
|
||||||
|
loginViewOnSuccess = VIEWS.settings
|
||||||
|
loginCancelEnabled(true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Bind the add microsoft account button.
|
// Bind the add microsoft account button.
|
||||||
document.getElementById('settingsAddMicrosoftAccount').onclick = (e) => {
|
document.getElementById('settingsAddMicrosoftAccount').onclick = (e) => {
|
||||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||||
@ -374,9 +362,9 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
|
|||||||
|
|
||||||
// Unexpected error.
|
// Unexpected error.
|
||||||
setOverlayContent(
|
setOverlayContent(
|
||||||
Lang.queryJS('settings.msftLogin.errorTitle'),
|
'Something Went Wrong',
|
||||||
Lang.queryJS('settings.msftLogin.errorMessage'),
|
'Microsoft authentication failed. Please try again.',
|
||||||
Lang.queryJS('settings.msftLogin.okButton')
|
'OK'
|
||||||
)
|
)
|
||||||
setOverlayHandler(() => {
|
setOverlayHandler(() => {
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
@ -391,17 +379,17 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
|
|||||||
if (Object.prototype.hasOwnProperty.call(queryMap, 'error')) {
|
if (Object.prototype.hasOwnProperty.call(queryMap, 'error')) {
|
||||||
switchView(getCurrentView(), viewOnClose, 500, 500, () => {
|
switchView(getCurrentView(), viewOnClose, 500, 500, () => {
|
||||||
// TODO Dont know what these errors are. Just show them I guess.
|
// TODO Dont know what these errors are. Just show them I guess.
|
||||||
// This is probably if you messed up the app registration with Azure.
|
// This is probably if you messed up the app registration with Azure.
|
||||||
let error = queryMap.error // Error might be 'access_denied' ?
|
|
||||||
let errorDesc = queryMap.error_description
|
|
||||||
console.log('Error getting authCode, is Azure application registered correctly?')
|
console.log('Error getting authCode, is Azure application registered correctly?')
|
||||||
console.log(error)
|
console.log(error)
|
||||||
console.log(errorDesc)
|
console.log(error_description)
|
||||||
console.log('Full query map: ', queryMap)
|
console.log('Full query map', queryMap)
|
||||||
|
let error = queryMap.error // Error might be 'access_denied' ?
|
||||||
|
let errorDesc = queryMap.error_description
|
||||||
setOverlayContent(
|
setOverlayContent(
|
||||||
error,
|
error,
|
||||||
errorDesc,
|
errorDesc,
|
||||||
Lang.queryJS('settings.msftLogin.okButton')
|
'OK'
|
||||||
)
|
)
|
||||||
setOverlayHandler(() => {
|
setOverlayHandler(() => {
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
@ -416,8 +404,8 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
|
|||||||
const authCode = queryMap.code
|
const authCode = queryMap.code
|
||||||
AuthManager.addMicrosoftAccount(authCode).then(value => {
|
AuthManager.addMicrosoftAccount(authCode).then(value => {
|
||||||
updateSelectedAccount(value)
|
updateSelectedAccount(value)
|
||||||
switchView(getCurrentView(), viewOnClose, 500, 500, async () => {
|
switchView(getCurrentView(), viewOnClose, 500, 500, () => {
|
||||||
await prepareSettings()
|
prepareSettings()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((displayableError) => {
|
.catch((displayableError) => {
|
||||||
@ -429,7 +417,10 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGIN, (_, ...arguments_) => {
|
|||||||
} else {
|
} else {
|
||||||
// Uh oh.
|
// Uh oh.
|
||||||
msftLoginLogger.error('Unhandled error during login.', displayableError)
|
msftLoginLogger.error('Unhandled error during login.', displayableError)
|
||||||
actualDisplayableError = Lang.queryJS('login.error.unknown')
|
actualDisplayableError = {
|
||||||
|
title: 'Unknown Error During Login',
|
||||||
|
desc: 'An unknown error has occurred. Please see the console for details.'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchView(getCurrentView(), viewOnClose, 500, 500, () => {
|
switchView(getCurrentView(), viewOnClose, 500, 500, () => {
|
||||||
@ -458,11 +449,11 @@ function bindAuthAccountSelect(){
|
|||||||
for(let i=0; i<selectBtns.length; i++){
|
for(let i=0; i<selectBtns.length; i++){
|
||||||
if(selectBtns[i].hasAttribute('selected')){
|
if(selectBtns[i].hasAttribute('selected')){
|
||||||
selectBtns[i].removeAttribute('selected')
|
selectBtns[i].removeAttribute('selected')
|
||||||
selectBtns[i].innerHTML = Lang.queryJS('settings.authAccountSelect.selectButton')
|
selectBtns[i].innerHTML = 'Select Account'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val.setAttribute('selected', '')
|
val.setAttribute('selected', '')
|
||||||
val.innerHTML = Lang.queryJS('settings.authAccountSelect.selectedButton')
|
val.innerHTML = 'Selected Account ✔'
|
||||||
setSelectedAccount(val.closest('.settingsAuthAccount').getAttribute('uuid'))
|
setSelectedAccount(val.closest('.settingsAuthAccount').getAttribute('uuid'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -480,10 +471,10 @@ function bindAuthAccountLogOut(){
|
|||||||
if(Object.keys(ConfigManager.getAuthAccounts()).length === 1){
|
if(Object.keys(ConfigManager.getAuthAccounts()).length === 1){
|
||||||
isLastAccount = true
|
isLastAccount = true
|
||||||
setOverlayContent(
|
setOverlayContent(
|
||||||
Lang.queryJS('settings.authAccountLogout.lastAccountWarningTitle'),
|
'Warning<br>This is Your Last Account',
|
||||||
Lang.queryJS('settings.authAccountLogout.lastAccountWarningMessage'),
|
'In order to use the launcher you must be logged into at least one account. You will need to login again after.<br><br>Are you sure you want to log out?',
|
||||||
Lang.queryJS('settings.authAccountLogout.confirmButton'),
|
'I\'m Sure',
|
||||||
Lang.queryJS('settings.authAccountLogout.cancelButton')
|
'Cancel'
|
||||||
)
|
)
|
||||||
setOverlayHandler(() => {
|
setOverlayHandler(() => {
|
||||||
processLogOut(val, isLastAccount)
|
processLogOut(val, isLastAccount)
|
||||||
@ -518,6 +509,24 @@ function processLogOut(val, isLastAccount){
|
|||||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||||
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGOUT, uuid, isLastAccount)
|
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGOUT, uuid, isLastAccount)
|
||||||
})
|
})
|
||||||
|
} if(targetAcc.type === 'offline') {
|
||||||
|
AuthManager.removeOfflineAccount(uuid).then(() => {
|
||||||
|
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
||||||
|
const selAcc = ConfigManager.getSelectedAccount()
|
||||||
|
refreshAuthAccountSelected(selAcc.uuid)
|
||||||
|
updateSelectedAccount(selAcc)
|
||||||
|
//validateSelectedAccount()
|
||||||
|
}
|
||||||
|
if(isLastAccount) {
|
||||||
|
loginOptionsCancelEnabled(false)
|
||||||
|
loginOptionsViewOnLoginSuccess = VIEWS.settings
|
||||||
|
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||||
|
switchView(getCurrentView(), VIEWS.loginOptions)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
$(parent).fadeOut(250, () => {
|
||||||
|
parent.remove()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
AuthManager.removeMojangAccount(uuid).then(() => {
|
AuthManager.removeMojangAccount(uuid).then(() => {
|
||||||
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
||||||
@ -552,9 +561,9 @@ ipcRenderer.on(MSFT_OPCODE.REPLY_LOGOUT, (_, ...arguments_) => {
|
|||||||
|
|
||||||
// Unexpected error.
|
// Unexpected error.
|
||||||
setOverlayContent(
|
setOverlayContent(
|
||||||
Lang.queryJS('settings.msftLogout.errorTitle'),
|
'Something Went Wrong',
|
||||||
Lang.queryJS('settings.msftLogout.errorMessage'),
|
'Microsoft logout failed. Please try again.',
|
||||||
Lang.queryJS('settings.msftLogout.okButton')
|
'OK'
|
||||||
)
|
)
|
||||||
setOverlayHandler(() => {
|
setOverlayHandler(() => {
|
||||||
toggleOverlay(false)
|
toggleOverlay(false)
|
||||||
@ -608,18 +617,19 @@ function refreshAuthAccountSelected(uuid){
|
|||||||
const selBtn = val.getElementsByClassName('settingsAuthAccountSelect')[0]
|
const selBtn = val.getElementsByClassName('settingsAuthAccountSelect')[0]
|
||||||
if(uuid === val.getAttribute('uuid')){
|
if(uuid === val.getAttribute('uuid')){
|
||||||
selBtn.setAttribute('selected', '')
|
selBtn.setAttribute('selected', '')
|
||||||
selBtn.innerHTML = Lang.queryJS('settings.authAccountSelect.selectedButton')
|
selBtn.innerHTML = 'Selected Account ✔'
|
||||||
} else {
|
} else {
|
||||||
if(selBtn.hasAttribute('selected')){
|
if(selBtn.hasAttribute('selected')){
|
||||||
selBtn.removeAttribute('selected')
|
selBtn.removeAttribute('selected')
|
||||||
}
|
}
|
||||||
selBtn.innerHTML = Lang.queryJS('settings.authAccountSelect.selectButton')
|
selBtn.innerHTML = 'Select Account'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const settingsCurrentMicrosoftAccounts = document.getElementById('settingsCurrentMicrosoftAccounts')
|
const settingsCurrentMicrosoftAccounts = document.getElementById('settingsCurrentMicrosoftAccounts')
|
||||||
const settingsCurrentMojangAccounts = document.getElementById('settingsCurrentMojangAccounts')
|
const settingsCurrentMojangAccounts = document.getElementById('settingsCurrentMojangAccounts')
|
||||||
|
const settingsCurrentOfflineAccounts = document.getElementById('settingsCurrentOfflineAccounts')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add auth account elements for each one stored in the authentication database.
|
* Add auth account elements for each one stored in the authentication database.
|
||||||
@ -634,6 +644,7 @@ function populateAuthAccounts(){
|
|||||||
|
|
||||||
let microsoftAuthAccountStr = ''
|
let microsoftAuthAccountStr = ''
|
||||||
let mojangAuthAccountStr = ''
|
let mojangAuthAccountStr = ''
|
||||||
|
let offlineAuthAccountStr = ''
|
||||||
|
|
||||||
authKeys.forEach((val) => {
|
authKeys.forEach((val) => {
|
||||||
const acc = authAccounts[val]
|
const acc = authAccounts[val]
|
||||||
@ -645,18 +656,18 @@ function populateAuthAccounts(){
|
|||||||
<div class="settingsAuthAccountRight">
|
<div class="settingsAuthAccountRight">
|
||||||
<div class="settingsAuthAccountDetails">
|
<div class="settingsAuthAccountDetails">
|
||||||
<div class="settingsAuthAccountDetailPane">
|
<div class="settingsAuthAccountDetailPane">
|
||||||
<div class="settingsAuthAccountDetailTitle">${Lang.queryJS('settings.authAccountPopulate.username')}</div>
|
<div class="settingsAuthAccountDetailTitle">Username</div>
|
||||||
<div class="settingsAuthAccountDetailValue">${acc.displayName}</div>
|
<div class="settingsAuthAccountDetailValue">${acc.displayName}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsAuthAccountDetailPane">
|
<div class="settingsAuthAccountDetailPane">
|
||||||
<div class="settingsAuthAccountDetailTitle">${Lang.queryJS('settings.authAccountPopulate.uuid')}</div>
|
<div class="settingsAuthAccountDetailTitle">UUID</div>
|
||||||
<div class="settingsAuthAccountDetailValue">${acc.uuid}</div>
|
<div class="settingsAuthAccountDetailValue">${acc.uuid}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsAuthAccountActions">
|
<div class="settingsAuthAccountActions">
|
||||||
<button class="settingsAuthAccountSelect" ${selectedUUID === acc.uuid ? 'selected>' + Lang.queryJS('settings.authAccountPopulate.selectedAccount') : '>' + Lang.queryJS('settings.authAccountPopulate.selectAccount')}</button>
|
<button class="settingsAuthAccountSelect" ${selectedUUID === acc.uuid ? 'selected>Selected Account ✔' : '>Select Account'}</button>
|
||||||
<div class="settingsAuthAccountWrapper">
|
<div class="settingsAuthAccountWrapper">
|
||||||
<button class="settingsAuthAccountLogOut">${Lang.queryJS('settings.authAccountPopulate.logout')}</button>
|
<button class="settingsAuthAccountLogOut">Log Out</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -664,6 +675,8 @@ function populateAuthAccounts(){
|
|||||||
|
|
||||||
if(acc.type === 'microsoft') {
|
if(acc.type === 'microsoft') {
|
||||||
microsoftAuthAccountStr += accHtml
|
microsoftAuthAccountStr += accHtml
|
||||||
|
} if (acc.type === 'offline') {
|
||||||
|
offlineAuthAccountStr += accHtml
|
||||||
} else {
|
} else {
|
||||||
mojangAuthAccountStr += accHtml
|
mojangAuthAccountStr += accHtml
|
||||||
}
|
}
|
||||||
@ -672,6 +685,7 @@ function populateAuthAccounts(){
|
|||||||
|
|
||||||
settingsCurrentMicrosoftAccounts.innerHTML = microsoftAuthAccountStr
|
settingsCurrentMicrosoftAccounts.innerHTML = microsoftAuthAccountStr
|
||||||
settingsCurrentMojangAccounts.innerHTML = mojangAuthAccountStr
|
settingsCurrentMojangAccounts.innerHTML = mojangAuthAccountStr
|
||||||
|
settingsCurrentOfflineAccounts.innerHTML = offlineAuthAccountStr
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -710,13 +724,13 @@ const settingsModsContainer = document.getElementById('settingsModsContainer')
|
|||||||
/**
|
/**
|
||||||
* Resolve and update the mods on the UI.
|
* Resolve and update the mods on the UI.
|
||||||
*/
|
*/
|
||||||
async function resolveModsForUI(){
|
function resolveModsForUI(){
|
||||||
const serv = ConfigManager.getSelectedServer()
|
const serv = ConfigManager.getSelectedServer()
|
||||||
|
|
||||||
const distro = await DistroAPI.getDistribution()
|
const distro = DistroManager.getDistribution()
|
||||||
const servConf = ConfigManager.getModConfiguration(serv)
|
const servConf = ConfigManager.getModConfiguration(serv)
|
||||||
|
|
||||||
const modStr = parseModulesForUI(distro.getServerById(serv).modules, false, servConf.mods)
|
const modStr = parseModulesForUI(distro.getServer(serv).getModules(), false, servConf.mods)
|
||||||
|
|
||||||
document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods
|
document.getElementById('settingsReqModsContent').innerHTML = modStr.reqMods
|
||||||
document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods
|
document.getElementById('settingsOptModsContent').innerHTML = modStr.optMods
|
||||||
@ -736,17 +750,17 @@ function parseModulesForUI(mdls, submodules, servConf){
|
|||||||
|
|
||||||
for(const mdl of mdls){
|
for(const mdl of mdls){
|
||||||
|
|
||||||
if(mdl.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader || mdl.rawModule.type === Type.FabricMod){
|
if(mdl.getType() === DistroManager.Types.ForgeMod || mdl.getType() === DistroManager.Types.LiteMod || mdl.getType() === DistroManager.Types.LiteLoader){
|
||||||
|
|
||||||
if(mdl.getRequired().value){
|
if(mdl.getRequired().isRequired()){
|
||||||
|
|
||||||
reqMods += `<div id="${mdl.getVersionlessMavenIdentifier()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" enabled>
|
reqMods += `<div id="${mdl.getVersionlessID()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" enabled>
|
||||||
<div class="settingsModContent">
|
<div class="settingsModContent">
|
||||||
<div class="settingsModMainWrapper">
|
<div class="settingsModMainWrapper">
|
||||||
<div class="settingsModStatus"></div>
|
<div class="settingsModStatus"></div>
|
||||||
<div class="settingsModDetails">
|
<div class="settingsModDetails">
|
||||||
<span class="settingsModName">${mdl.rawModule.name}</span>
|
<span class="settingsModName">${mdl.getName()}</span>
|
||||||
<span class="settingsModVersion">v${mdl.mavenComponents.version}</span>
|
<span class="settingsModVersion">v${mdl.getVersion()}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="toggleSwitch" reqmod>
|
<label class="toggleSwitch" reqmod>
|
||||||
@ -754,32 +768,32 @@ function parseModulesForUI(mdls, submodules, servConf){
|
|||||||
<span class="toggleSwitchSlider"></span>
|
<span class="toggleSwitchSlider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
${mdl.hasSubModules() ? `<div class="settingsSubModContainer">
|
||||||
${Object.values(parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
|
${Object.values(parseModulesForUI(mdl.getSubModules(), true, servConf[mdl.getVersionlessID()])).join('')}
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const conf = servConf[mdl.getVersionlessMavenIdentifier()]
|
const conf = servConf[mdl.getVersionlessID()]
|
||||||
const val = typeof conf === 'object' ? conf.value : conf
|
const val = typeof conf === 'object' ? conf.value : conf
|
||||||
|
|
||||||
optMods += `<div id="${mdl.getVersionlessMavenIdentifier()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" ${val ? 'enabled' : ''}>
|
optMods += `<div id="${mdl.getVersionlessID()}" class="settingsBaseMod settings${submodules ? 'Sub' : ''}Mod" ${val ? 'enabled' : ''}>
|
||||||
<div class="settingsModContent">
|
<div class="settingsModContent">
|
||||||
<div class="settingsModMainWrapper">
|
<div class="settingsModMainWrapper">
|
||||||
<div class="settingsModStatus"></div>
|
<div class="settingsModStatus"></div>
|
||||||
<div class="settingsModDetails">
|
<div class="settingsModDetails">
|
||||||
<span class="settingsModName">${mdl.rawModule.name}</span>
|
<span class="settingsModName">${mdl.getName()}</span>
|
||||||
<span class="settingsModVersion">v${mdl.mavenComponents.version}</span>
|
<span class="settingsModVersion">v${mdl.getVersion()}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="toggleSwitch">
|
<label class="toggleSwitch">
|
||||||
<input type="checkbox" formod="${mdl.getVersionlessMavenIdentifier()}" ${val ? 'checked' : ''}>
|
<input type="checkbox" formod="${mdl.getVersionlessID()}" ${val ? 'checked' : ''}>
|
||||||
<span class="toggleSwitchSlider"></span>
|
<span class="toggleSwitchSlider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
${mdl.hasSubModules() ? `<div class="settingsSubModContainer">
|
||||||
${Object.values(parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
|
${Object.values(parseModulesForUI(mdl.getSubModules(), true, conf.mods)).join('')}
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
@ -855,10 +869,10 @@ let CACHE_DROPIN_MODS
|
|||||||
* Resolve any located drop-in mods for this server and
|
* Resolve any located drop-in mods for this server and
|
||||||
* populate the results onto the UI.
|
* populate the results onto the UI.
|
||||||
*/
|
*/
|
||||||
async function resolveDropinModsForUI(){
|
function resolveDropinModsForUI(){
|
||||||
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
||||||
CACHE_SETTINGS_MODS_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.rawServer.id, 'mods')
|
CACHE_SETTINGS_MODS_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.getID(), 'mods')
|
||||||
CACHE_DROPIN_MODS = DropinModUtil.scanForDropinMods(CACHE_SETTINGS_MODS_DIR, serv.rawServer.minecraftVersion)
|
CACHE_DROPIN_MODS = DropinModUtil.scanForDropinMods(CACHE_SETTINGS_MODS_DIR, serv.getMinecraftVersion())
|
||||||
|
|
||||||
let dropinMods = ''
|
let dropinMods = ''
|
||||||
|
|
||||||
@ -870,7 +884,7 @@ async function resolveDropinModsForUI(){
|
|||||||
<div class="settingsModDetails">
|
<div class="settingsModDetails">
|
||||||
<span class="settingsModName">${dropin.name}</span>
|
<span class="settingsModName">${dropin.name}</span>
|
||||||
<div class="settingsDropinRemoveWrapper">
|
<div class="settingsDropinRemoveWrapper">
|
||||||
<button class="settingsDropinRemoveButton" remmod="${dropin.fullName}">${Lang.queryJS('settings.dropinMods.removeButton')}</button>
|
<button class="settingsDropinRemoveButton" remmod="${dropin.fullName}">Remove</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -898,9 +912,9 @@ function bindDropinModsRemoveButton(){
|
|||||||
document.getElementById(fullName).remove()
|
document.getElementById(fullName).remove()
|
||||||
} else {
|
} else {
|
||||||
setOverlayContent(
|
setOverlayContent(
|
||||||
Lang.queryJS('settings.dropinMods.deleteFailedTitle', { fullName }),
|
`Failed to Delete<br>Drop-in Mod ${fullName}`,
|
||||||
Lang.queryJS('settings.dropinMods.deleteFailedMessage'),
|
'Make sure the file is not in use and try again.',
|
||||||
Lang.queryJS('settings.dropinMods.okButton')
|
'Okay'
|
||||||
)
|
)
|
||||||
setOverlayHandler(null)
|
setOverlayHandler(null)
|
||||||
toggleOverlay(true)
|
toggleOverlay(true)
|
||||||
@ -931,12 +945,12 @@ function bindDropinModFileSystemButton(){
|
|||||||
fsBtn.removeAttribute('drag')
|
fsBtn.removeAttribute('drag')
|
||||||
}
|
}
|
||||||
|
|
||||||
fsBtn.ondrop = async e => {
|
fsBtn.ondrop = e => {
|
||||||
fsBtn.removeAttribute('drag')
|
fsBtn.removeAttribute('drag')
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
DropinModUtil.addDropinMods(e.dataTransfer.files, CACHE_SETTINGS_MODS_DIR)
|
DropinModUtil.addDropinMods(e.dataTransfer.files, CACHE_SETTINGS_MODS_DIR)
|
||||||
await reloadDropinMods()
|
reloadDropinMods()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -953,9 +967,9 @@ function saveDropinModConfiguration(){
|
|||||||
DropinModUtil.toggleDropinMod(CACHE_SETTINGS_MODS_DIR, dropin.fullName, dropinUIEnabled).catch(err => {
|
DropinModUtil.toggleDropinMod(CACHE_SETTINGS_MODS_DIR, dropin.fullName, dropinUIEnabled).catch(err => {
|
||||||
if(!isOverlayVisible()){
|
if(!isOverlayVisible()){
|
||||||
setOverlayContent(
|
setOverlayContent(
|
||||||
Lang.queryJS('settings.dropinMods.failedToggleTitle'),
|
'Failed to Toggle<br>One or More Drop-in Mods',
|
||||||
err.message,
|
err.message,
|
||||||
Lang.queryJS('settings.dropinMods.okButton')
|
'Okay'
|
||||||
)
|
)
|
||||||
setOverlayHandler(null)
|
setOverlayHandler(null)
|
||||||
toggleOverlay(true)
|
toggleOverlay(true)
|
||||||
@ -968,18 +982,18 @@ function saveDropinModConfiguration(){
|
|||||||
|
|
||||||
// Refresh the drop-in mods when F5 is pressed.
|
// Refresh the drop-in mods when F5 is pressed.
|
||||||
// Only active on the mods tab.
|
// Only active on the mods tab.
|
||||||
document.addEventListener('keydown', async (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if(getCurrentView() === VIEWS.settings && selectedSettingsTab === 'settingsTabMods'){
|
if(getCurrentView() === VIEWS.settings && selectedSettingsTab === 'settingsTabMods'){
|
||||||
if(e.key === 'F5'){
|
if(e.key === 'F5'){
|
||||||
await reloadDropinMods()
|
reloadDropinMods()
|
||||||
saveShaderpackSettings()
|
saveShaderpackSettings()
|
||||||
await resolveShaderpacksForUI()
|
resolveShaderpacksForUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
async function reloadDropinMods(){
|
function reloadDropinMods(){
|
||||||
await resolveDropinModsForUI()
|
resolveDropinModsForUI()
|
||||||
bindDropinModsRemoveButton()
|
bindDropinModsRemoveButton()
|
||||||
bindDropinModFileSystemButton()
|
bindDropinModFileSystemButton()
|
||||||
bindModsToggleSwitch()
|
bindModsToggleSwitch()
|
||||||
@ -994,9 +1008,9 @@ let CACHE_SELECTED_SHADERPACK
|
|||||||
/**
|
/**
|
||||||
* Load shaderpack information.
|
* Load shaderpack information.
|
||||||
*/
|
*/
|
||||||
async function resolveShaderpacksForUI(){
|
function resolveShaderpacksForUI(){
|
||||||
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
||||||
CACHE_SETTINGS_INSTANCE_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.rawServer.id)
|
CACHE_SETTINGS_INSTANCE_DIR = path.join(ConfigManager.getInstanceDirectory(), serv.getID())
|
||||||
CACHE_SHADERPACKS = DropinModUtil.scanForShaderpacks(CACHE_SETTINGS_INSTANCE_DIR)
|
CACHE_SHADERPACKS = DropinModUtil.scanForShaderpacks(CACHE_SETTINGS_INSTANCE_DIR)
|
||||||
CACHE_SELECTED_SHADERPACK = DropinModUtil.getEnabledShaderpack(CACHE_SETTINGS_INSTANCE_DIR)
|
CACHE_SELECTED_SHADERPACK = DropinModUtil.getEnabledShaderpack(CACHE_SETTINGS_INSTANCE_DIR)
|
||||||
|
|
||||||
@ -1055,13 +1069,13 @@ function bindShaderpackButton() {
|
|||||||
spBtn.removeAttribute('drag')
|
spBtn.removeAttribute('drag')
|
||||||
}
|
}
|
||||||
|
|
||||||
spBtn.ondrop = async e => {
|
spBtn.ondrop = e => {
|
||||||
spBtn.removeAttribute('drag')
|
spBtn.removeAttribute('drag')
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
DropinModUtil.addShaderpacks(e.dataTransfer.files, CACHE_SETTINGS_INSTANCE_DIR)
|
DropinModUtil.addShaderpacks(e.dataTransfer.files, CACHE_SETTINGS_INSTANCE_DIR)
|
||||||
saveShaderpackSettings()
|
saveShaderpackSettings()
|
||||||
await resolveShaderpacksForUI()
|
resolveShaderpacksForUI()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1070,40 +1084,36 @@ function bindShaderpackButton() {
|
|||||||
/**
|
/**
|
||||||
* Load the currently selected server information onto the mods tab.
|
* Load the currently selected server information onto the mods tab.
|
||||||
*/
|
*/
|
||||||
async function loadSelectedServerOnModsTab(){
|
function loadSelectedServerOnModsTab(){
|
||||||
const serv = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
const serv = DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer())
|
||||||
|
|
||||||
for(const el of document.getElementsByClassName('settingsSelServContent')) {
|
document.getElementById('settingsSelServContent').innerHTML = `
|
||||||
el.innerHTML = `
|
<img class="serverListingImg" src="${serv.getIcon()}"/>
|
||||||
<img class="serverListingImg" src="${serv.rawServer.icon}"/>
|
<div class="serverListingDetails">
|
||||||
<div class="serverListingDetails">
|
<span class="serverListingName">${serv.getName()}</span>
|
||||||
<span class="serverListingName">${serv.rawServer.name}</span>
|
<span class="serverListingDescription">${serv.getDescription()}</span>
|
||||||
<span class="serverListingDescription">${serv.rawServer.description}</span>
|
<div class="serverListingInfo">
|
||||||
<div class="serverListingInfo">
|
<div class="serverListingVersion">${serv.getMinecraftVersion()}</div>
|
||||||
<div class="serverListingVersion">${serv.rawServer.minecraftVersion}</div>
|
<div class="serverListingRevision">${serv.getVersion()}</div>
|
||||||
<div class="serverListingRevision">${serv.rawServer.version}</div>
|
${serv.isMainServer() ? `<div class="serverListingStarWrapper">
|
||||||
${serv.rawServer.mainServer ? `<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">${Lang.queryJS('settings.serverListing.mainServer')}</span>
|
</div>` : ''}
|
||||||
</div>` : ''}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`
|
</div>
|
||||||
}
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind functionality to the server switch button.
|
// Bind functionality to the server switch button.
|
||||||
Array.from(document.getElementsByClassName('settingsSwitchServerButton')).forEach(el => {
|
document.getElementById('settingsSwitchServerButton').addEventListener('click', (e) => {
|
||||||
el.addEventListener('click', async e => {
|
e.target.blur()
|
||||||
e.target.blur()
|
toggleServerSelection(true)
|
||||||
await toggleServerSelection(true)
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1116,28 +1126,28 @@ function saveAllModConfigurations(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to refresh the current tab whenever the selected
|
* Function to refresh the mods tab whenever the selected
|
||||||
* server is changed.
|
* server is changed.
|
||||||
*/
|
*/
|
||||||
function animateSettingsTabRefresh(){
|
function animateModsTabRefresh(){
|
||||||
$(`#${selectedSettingsTab}`).fadeOut(500, async () => {
|
$('#settingsTabMods').fadeOut(500, () => {
|
||||||
await prepareSettings()
|
prepareModsTab()
|
||||||
$(`#${selectedSettingsTab}`).fadeIn(500)
|
$('#settingsTabMods').fadeIn(500)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the Mods tab for display.
|
* Prepare the Mods tab for display.
|
||||||
*/
|
*/
|
||||||
async function prepareModsTab(first){
|
function prepareModsTab(first){
|
||||||
await resolveModsForUI()
|
resolveModsForUI()
|
||||||
await resolveDropinModsForUI()
|
resolveDropinModsForUI()
|
||||||
await resolveShaderpacksForUI()
|
resolveShaderpacksForUI()
|
||||||
bindDropinModsRemoveButton()
|
bindDropinModsRemoveButton()
|
||||||
bindDropinModFileSystemButton()
|
bindDropinModFileSystemButton()
|
||||||
bindShaderpackButton()
|
bindShaderpackButton()
|
||||||
bindModsToggleSwitch()
|
bindModsToggleSwitch()
|
||||||
await loadSelectedServerOnModsTab()
|
loadSelectedServerOnModsTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1152,8 +1162,16 @@ const settingsMinRAMLabel = document.getElementById('settingsMinRAMLabel')
|
|||||||
const settingsMemoryTotal = document.getElementById('settingsMemoryTotal')
|
const settingsMemoryTotal = document.getElementById('settingsMemoryTotal')
|
||||||
const settingsMemoryAvail = document.getElementById('settingsMemoryAvail')
|
const settingsMemoryAvail = document.getElementById('settingsMemoryAvail')
|
||||||
const settingsJavaExecDetails = document.getElementById('settingsJavaExecDetails')
|
const settingsJavaExecDetails = document.getElementById('settingsJavaExecDetails')
|
||||||
const settingsJavaReqDesc = document.getElementById('settingsJavaReqDesc')
|
|
||||||
const settingsJvmOptsLink = document.getElementById('settingsJvmOptsLink')
|
// Store maximum memory values.
|
||||||
|
const SETTINGS_MAX_MEMORY = ConfigManager.getAbsoluteMaxRAM()
|
||||||
|
const SETTINGS_MIN_MEMORY = ConfigManager.getAbsoluteMinRAM()
|
||||||
|
|
||||||
|
// Set the max and min values for the ranged sliders.
|
||||||
|
settingsMaxRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
|
||||||
|
settingsMaxRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY)
|
||||||
|
settingsMinRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
|
||||||
|
settingsMinRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY )
|
||||||
|
|
||||||
// Bind on change event for min memory container.
|
// Bind on change event for min memory container.
|
||||||
settingsMinRAMRange.onchange = (e) => {
|
settingsMinRAMRange.onchange = (e) => {
|
||||||
@ -1165,7 +1183,7 @@ settingsMinRAMRange.onchange = (e) => {
|
|||||||
// Get reference to range bar.
|
// Get reference to range bar.
|
||||||
const bar = e.target.getElementsByClassName('rangeSliderBar')[0]
|
const bar = e.target.getElementsByClassName('rangeSliderBar')[0]
|
||||||
// Calculate effective total memory.
|
// Calculate effective total memory.
|
||||||
const max = os.totalmem()/1073741824
|
const max = (os.totalmem()-1000000000)/1000000000
|
||||||
|
|
||||||
// Change range bar color based on the selected value.
|
// Change range bar color based on the selected value.
|
||||||
if(sMinV >= max/2){
|
if(sMinV >= max/2){
|
||||||
@ -1197,7 +1215,7 @@ settingsMaxRAMRange.onchange = (e) => {
|
|||||||
// Get reference to range bar.
|
// Get reference to range bar.
|
||||||
const bar = e.target.getElementsByClassName('rangeSliderBar')[0]
|
const bar = e.target.getElementsByClassName('rangeSliderBar')[0]
|
||||||
// Calculate effective total memory.
|
// Calculate effective total memory.
|
||||||
const max = os.totalmem()/1073741824
|
const max = (os.totalmem()-1000000000)/1000000000
|
||||||
|
|
||||||
// Change range bar color based on the selected value.
|
// Change range bar color based on the selected value.
|
||||||
if(sMaxV >= max/2){
|
if(sMaxV >= max/2){
|
||||||
@ -1325,8 +1343,8 @@ function updateRangedSlider(element, value, notch){
|
|||||||
* Display the total and available RAM.
|
* Display the total and available RAM.
|
||||||
*/
|
*/
|
||||||
function populateMemoryStatus(){
|
function populateMemoryStatus(){
|
||||||
settingsMemoryTotal.innerHTML = Number((os.totalmem()-1073741824)/1073741824).toFixed(1) + 'G'
|
settingsMemoryTotal.innerHTML = Number((os.totalmem()-1000000000)/1000000000).toFixed(1) + 'G'
|
||||||
settingsMemoryAvail.innerHTML = Number(os.freemem()/1073741824).toFixed(1) + 'G'
|
settingsMemoryAvail.innerHTML = Number(os.freemem()/1000000000).toFixed(1) + 'G'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1335,61 +1353,28 @@ function populateMemoryStatus(){
|
|||||||
*
|
*
|
||||||
* @param {string} execPath The executable path to populate against.
|
* @param {string} execPath The executable path to populate against.
|
||||||
*/
|
*/
|
||||||
async function populateJavaExecDetails(execPath){
|
function populateJavaExecDetails(execPath){
|
||||||
const server = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
const jg = new JavaGuard(DistroManager.getDistribution().getServer(ConfigManager.getSelectedServer()).getMinecraftVersion())
|
||||||
|
jg._validateJavaBinary(execPath).then(v => {
|
||||||
const details = await validateSelectedJvm(ensureJavaDirIsRoot(execPath), server.effectiveJavaOptions.supported)
|
if(v.valid){
|
||||||
|
const vendor = v.vendor != null ? ` (${v.vendor})` : ''
|
||||||
if(details != null) {
|
if(v.version.major < 9) {
|
||||||
settingsJavaExecDetails.innerHTML = Lang.queryJS('settings.java.selectedJava', { version: details.semverStr, vendor: details.vendor })
|
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major} Update ${v.version.update} (x${v.arch})${vendor}`
|
||||||
} else {
|
} else {
|
||||||
settingsJavaExecDetails.innerHTML = Lang.queryJS('settings.java.invalidSelection')
|
settingsJavaExecDetails.innerHTML = `Selected: Java ${v.version.major}.${v.version.minor}.${v.version.revision} (x${v.arch})${vendor}`
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
settingsJavaExecDetails.innerHTML = 'Invalid Selection'
|
||||||
function populateJavaReqDesc(server) {
|
}
|
||||||
settingsJavaReqDesc.innerHTML = Lang.queryJS('settings.java.requiresJava', { major: server.effectiveJavaOptions.suggestedMajor })
|
})
|
||||||
}
|
|
||||||
|
|
||||||
function populateJvmOptsLink(server) {
|
|
||||||
const major = server.effectiveJavaOptions.suggestedMajor
|
|
||||||
settingsJvmOptsLink.innerHTML = Lang.queryJS('settings.java.availableOptions', { major: major })
|
|
||||||
if(major >= 12) {
|
|
||||||
settingsJvmOptsLink.href = `https://docs.oracle.com/en/java/javase/${major}/docs/specs/man/java.html#extra-options-for-java`
|
|
||||||
}
|
|
||||||
else if(major >= 11) {
|
|
||||||
settingsJvmOptsLink.href = 'https://docs.oracle.com/en/java/javase/11/tools/java.html#GUID-3B1CE181-CD30-4178-9602-230B800D4FAE'
|
|
||||||
}
|
|
||||||
else if(major >= 9) {
|
|
||||||
settingsJvmOptsLink.href = `https://docs.oracle.com/javase/${major}/tools/java.htm`
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
settingsJvmOptsLink.href = `https://docs.oracle.com/javase/${major}/docs/technotes/tools/${process.platform === 'win32' ? 'windows' : 'unix'}/java.html`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function bindMinMaxRam(server) {
|
|
||||||
// Store maximum memory values.
|
|
||||||
const SETTINGS_MAX_MEMORY = ConfigManager.getAbsoluteMaxRAM(server.rawServer.javaOptions?.ram)
|
|
||||||
const SETTINGS_MIN_MEMORY = ConfigManager.getAbsoluteMinRAM(server.rawServer.javaOptions?.ram)
|
|
||||||
|
|
||||||
// Set the max and min values for the ranged sliders.
|
|
||||||
settingsMaxRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
|
|
||||||
settingsMaxRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY)
|
|
||||||
settingsMinRAMRange.setAttribute('max', SETTINGS_MAX_MEMORY)
|
|
||||||
settingsMinRAMRange.setAttribute('min', SETTINGS_MIN_MEMORY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the Java tab for display.
|
* Prepare the Java tab for display.
|
||||||
*/
|
*/
|
||||||
async function prepareJavaTab(){
|
function prepareJavaTab(){
|
||||||
const server = (await DistroAPI.getDistribution()).getServerById(ConfigManager.getSelectedServer())
|
bindRangeSlider()
|
||||||
bindMinMaxRam(server)
|
|
||||||
bindRangeSlider(server)
|
|
||||||
populateMemoryStatus()
|
populateMemoryStatus()
|
||||||
populateJavaReqDesc(server)
|
|
||||||
populateJvmOptsLink(server)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1430,11 +1415,11 @@ function isPrerelease(version){
|
|||||||
function populateVersionInformation(version, valueElement, titleElement, checkElement){
|
function populateVersionInformation(version, valueElement, titleElement, checkElement){
|
||||||
valueElement.innerHTML = version
|
valueElement.innerHTML = version
|
||||||
if(isPrerelease(version)){
|
if(isPrerelease(version)){
|
||||||
titleElement.innerHTML = Lang.queryJS('settings.about.preReleaseTitle')
|
titleElement.innerHTML = 'Pre-release'
|
||||||
titleElement.style.color = '#ff886d'
|
titleElement.style.color = '#ff886d'
|
||||||
checkElement.style.background = '#ff886d'
|
checkElement.style.background = '#ff886d'
|
||||||
} else {
|
} else {
|
||||||
titleElement.innerHTML = Lang.queryJS('settings.about.stableReleaseTitle')
|
titleElement.innerHTML = 'Stable Release'
|
||||||
titleElement.style.color = null
|
titleElement.style.color = null
|
||||||
checkElement.style.background = null
|
checkElement.style.background = null
|
||||||
}
|
}
|
||||||
@ -1473,7 +1458,7 @@ function populateReleaseNotes(){
|
|||||||
},
|
},
|
||||||
timeout: 2500
|
timeout: 2500
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
settingsAboutChangelogText.innerHTML = Lang.queryJS('settings.about.releaseNotesFailed')
|
settingsAboutChangelogText.innerHTML = 'Failed to load release notes.'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1521,27 +1506,27 @@ function settingsUpdateButtonStatus(text, disabled = false, handler = null){
|
|||||||
*/
|
*/
|
||||||
function populateSettingsUpdateInformation(data){
|
function populateSettingsUpdateInformation(data){
|
||||||
if(data != null){
|
if(data != null){
|
||||||
settingsUpdateTitle.innerHTML = isPrerelease(data.version) ? Lang.queryJS('settings.updates.newPreReleaseTitle') : Lang.queryJS('settings.updates.newReleaseTitle')
|
settingsUpdateTitle.innerHTML = `New ${isPrerelease(data.version) ? 'Pre-release' : 'Release'} Available`
|
||||||
settingsUpdateChangelogCont.style.display = null
|
settingsUpdateChangelogCont.style.display = null
|
||||||
settingsUpdateChangelogTitle.innerHTML = data.releaseName
|
settingsUpdateChangelogTitle.innerHTML = data.releaseName
|
||||||
settingsUpdateChangelogText.innerHTML = data.releaseNotes
|
settingsUpdateChangelogText.innerHTML = data.releaseNotes
|
||||||
populateVersionInformation(data.version, settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
|
populateVersionInformation(data.version, settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
|
||||||
|
|
||||||
if(process.platform === 'darwin'){
|
if(process.platform === 'darwin'){
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.downloadButton'), false, () => {
|
settingsUpdateButtonStatus('Download from GitHub<span style="font-size: 10px;color: gray;text-shadow: none !important;">Close the launcher and run the dmg to update.</span>', false, () => {
|
||||||
shell.openExternal(data.darwindownload)
|
shell.openExternal(data.darwindownload)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.downloadingButton'), true)
|
settingsUpdateButtonStatus('Downloading..', true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
settingsUpdateTitle.innerHTML = Lang.queryJS('settings.updates.latestVersionTitle')
|
settingsUpdateTitle.innerHTML = 'You Are Running the Latest Version'
|
||||||
settingsUpdateChangelogCont.style.display = 'none'
|
settingsUpdateChangelogCont.style.display = 'none'
|
||||||
populateVersionInformation(remote.app.getVersion(), settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
|
populateVersionInformation(remote.app.getVersion(), settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.checkForUpdatesButton'), false, () => {
|
settingsUpdateButtonStatus('Check for Updates', false, () => {
|
||||||
if(!isDev){
|
if(!isDev){
|
||||||
ipcRenderer.send('autoUpdateAction', 'checkForUpdate')
|
ipcRenderer.send('autoUpdateAction', 'checkForUpdate')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.checkingForUpdatesButton'), true)
|
settingsUpdateButtonStatus('Checking for Updates..', true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1565,19 +1550,19 @@ function prepareUpdateTab(data = null){
|
|||||||
*
|
*
|
||||||
* @param {boolean} first Whether or not it is the first load.
|
* @param {boolean} first Whether or not it is the first load.
|
||||||
*/
|
*/
|
||||||
async function prepareSettings(first = false) {
|
function prepareSettings(first = false) {
|
||||||
if(first){
|
if(first){
|
||||||
setupSettingsTabs()
|
setupSettingsTabs()
|
||||||
initSettingsValidators()
|
initSettingsValidators()
|
||||||
prepareUpdateTab()
|
prepareUpdateTab()
|
||||||
} else {
|
} else {
|
||||||
await prepareModsTab()
|
prepareModsTab()
|
||||||
}
|
}
|
||||||
await initSettingsValues()
|
initSettingsValues()
|
||||||
prepareAccountsTab()
|
prepareAccountsTab()
|
||||||
await prepareJavaTab()
|
prepareJavaTab()
|
||||||
prepareAboutTab()
|
prepareAboutTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the settings UI on startup.
|
// Prepare the settings UI on startup.
|
||||||
//prepareSettings(true)
|
//prepareSettings(true)
|
@ -1,466 +1,455 @@
|
|||||||
/**
|
/**
|
||||||
* 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 { Type } = require('helios-distribution-types')
|
|
||||||
|
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 { DistroAPI } = require('./assets/js/distromanager')
|
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',
|
||||||
loginOptions: '#loginOptionsContainer',
|
loginOptions: '#loginOptionsContainer',
|
||||||
login: '#loginContainer',
|
login: '#loginContainer',
|
||||||
settings: '#settingsContainer',
|
loginOffline: '#loginOfflineContainer',
|
||||||
welcome: '#welcomeContainer',
|
settings: '#settingsContainer',
|
||||||
waiting: '#waitingContainer'
|
welcome: '#welcomeContainer',
|
||||||
}
|
waiting: '#waitingContainer',
|
||||||
|
dynmap: '#dynmapContainer'
|
||||||
// The currently shown view container.
|
}
|
||||||
let currentView
|
|
||||||
|
// The currently shown view container.
|
||||||
/**
|
let currentView
|
||||||
* Switch launcher views.
|
|
||||||
*
|
/**
|
||||||
* @param {string} current The ID of the current view container.
|
* Switch launcher views.
|
||||||
* @param {*} next The ID of the next view container.
|
*
|
||||||
* @param {*} currentFadeTime Optional. The fade out time for the current view.
|
* @param {string} current The ID of the current view container.
|
||||||
* @param {*} nextFadeTime Optional. The fade in time for the next view.
|
* @param {*} next The ID of the next view container.
|
||||||
* @param {*} onCurrentFade Optional. Callback function to execute when the current
|
* @param {*} currentFadeTime Optional. The fade out time for the current view.
|
||||||
* view fades out.
|
* @param {*} nextFadeTime Optional. The fade in time for the next view.
|
||||||
* @param {*} onNextFade Optional. Callback function to execute when the next view
|
* @param {*} onCurrentFade Optional. Callback function to execute when the current
|
||||||
* fades in.
|
* view fades out.
|
||||||
*/
|
* @param {*} onNextFade Optional. Callback function to execute when the next view
|
||||||
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
|
* fades in.
|
||||||
currentView = next
|
*/
|
||||||
$(`${current}`).fadeOut(currentFadeTime, async () => {
|
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
|
||||||
await onCurrentFade()
|
currentView = next
|
||||||
$(`${next}`).fadeIn(nextFadeTime, async () => {
|
$(`${current}`).fadeOut(currentFadeTime, () => {
|
||||||
await onNextFade()
|
onCurrentFade()
|
||||||
})
|
$(`${next}`).fadeIn(nextFadeTime, () => {
|
||||||
})
|
onNextFade()
|
||||||
}
|
})
|
||||||
|
})
|
||||||
/**
|
}
|
||||||
* Get the currently shown view container.
|
|
||||||
*
|
/**
|
||||||
* @returns {string} The currently shown view container.
|
* Get the currently shown view container.
|
||||||
*/
|
*
|
||||||
function getCurrentView(){
|
* @returns {string} The currently shown view container.
|
||||||
return currentView
|
*/
|
||||||
}
|
function getCurrentView(){
|
||||||
|
return currentView
|
||||||
async function showMainUI(data){
|
}
|
||||||
|
|
||||||
if(!isDev){
|
function showMainUI(data){
|
||||||
loggerAutoUpdater.info('Initializing..')
|
|
||||||
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
|
if(!isDev){
|
||||||
}
|
loggerAutoUpdater.log('Initializing..')
|
||||||
|
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
|
||||||
await prepareSettings(true)
|
}
|
||||||
updateSelectedServer(data.getServerById(ConfigManager.getSelectedServer()))
|
|
||||||
refreshServerStatus()
|
prepareSettings(true)
|
||||||
setTimeout(() => {
|
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
||||||
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
refreshServerStatus()
|
||||||
document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')`
|
setTimeout(() => {
|
||||||
$('#main').show()
|
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
||||||
|
document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')`
|
||||||
const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0
|
$('#main').show()
|
||||||
|
|
||||||
// If this is enabled in a development environment we'll get ratelimited.
|
const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0
|
||||||
// The relaunch frequency is usually far too high.
|
|
||||||
if(!isDev && isLoggedIn){
|
// If this is enabled in a development environment we'll get ratelimited.
|
||||||
validateSelectedAccount()
|
// The relaunch frequency is usually far too high.
|
||||||
}
|
//if(!isDev && isLoggedIn){
|
||||||
|
if(isLoggedIn){
|
||||||
if(ConfigManager.isFirstLaunch()){
|
validateSelectedAccount()
|
||||||
currentView = VIEWS.welcome
|
}
|
||||||
$(VIEWS.welcome).fadeIn(1000)
|
|
||||||
} else {
|
if(ConfigManager.isFirstLaunch()){
|
||||||
if(isLoggedIn){
|
currentView = VIEWS.welcome
|
||||||
currentView = VIEWS.landing
|
$(VIEWS.welcome).fadeIn(1000)
|
||||||
$(VIEWS.landing).fadeIn(1000)
|
} else {
|
||||||
} else {
|
if(isLoggedIn){
|
||||||
loginOptionsCancelEnabled(false)
|
currentView = VIEWS.landing
|
||||||
loginOptionsViewOnLoginSuccess = VIEWS.landing
|
$(VIEWS.landing).fadeIn(1000)
|
||||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
} else {
|
||||||
currentView = VIEWS.loginOptions
|
loginOptionsCancelEnabled(false)
|
||||||
$(VIEWS.loginOptions).fadeIn(1000)
|
loginOptionsViewOnLoginSuccess = VIEWS.landing
|
||||||
}
|
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||||
}
|
currentView = VIEWS.loginOptions
|
||||||
|
$(VIEWS.loginOptions).fadeIn(1000)
|
||||||
setTimeout(() => {
|
}
|
||||||
$('#loadingContainer').fadeOut(500, () => {
|
}
|
||||||
$('#loadSpinnerImage').removeClass('rotating')
|
|
||||||
})
|
setTimeout(() => {
|
||||||
}, 250)
|
$('#loadingContainer').fadeOut(500, () => {
|
||||||
|
$('#loadSpinnerImage').removeClass('rotating')
|
||||||
}, 750)
|
})
|
||||||
// Disable tabbing to the news container.
|
}, 250)
|
||||||
initNews().then(() => {
|
|
||||||
$('#newsContainer *').attr('tabindex', '-1')
|
}, 750)
|
||||||
})
|
// Disable tabbing to the news container.
|
||||||
}
|
// initNews().then(() => {
|
||||||
|
// $('#newsContainer *').attr('tabindex', '-1')
|
||||||
function showFatalStartupError(){
|
// })
|
||||||
setTimeout(() => {
|
}
|
||||||
$('#loadingContainer').fadeOut(250, () => {
|
|
||||||
document.getElementById('overlayContainer').style.background = 'none'
|
function showFatalStartupError(){
|
||||||
setOverlayContent(
|
setTimeout(() => {
|
||||||
Lang.queryJS('uibinder.startup.fatalErrorTitle'),
|
$('#loadingContainer').fadeOut(250, () => {
|
||||||
Lang.queryJS('uibinder.startup.fatalErrorMessage'),
|
document.getElementById('overlayContainer').style.background = 'none'
|
||||||
Lang.queryJS('uibinder.startup.closeButton')
|
setOverlayContent(
|
||||||
)
|
'Fatal Error: Unable to Load Distribution Index',
|
||||||
setOverlayHandler(() => {
|
'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.',
|
||||||
const window = remote.getCurrentWindow()
|
'Close'
|
||||||
window.close()
|
)
|
||||||
})
|
setOverlayHandler(() => {
|
||||||
toggleOverlay(true)
|
const window = remote.getCurrentWindow()
|
||||||
})
|
window.close()
|
||||||
}, 750)
|
})
|
||||||
}
|
toggleOverlay(true)
|
||||||
|
})
|
||||||
/**
|
}, 750)
|
||||||
* Common functions to perform after refreshing the distro index.
|
}
|
||||||
*
|
|
||||||
* @param {Object} data The distro index object.
|
/**
|
||||||
*/
|
* Common functions to perform after refreshing the distro index.
|
||||||
function onDistroRefresh(data){
|
*
|
||||||
updateSelectedServer(data.getServerById(ConfigManager.getSelectedServer()))
|
* @param {Object} data The distro index object.
|
||||||
refreshServerStatus()
|
*/
|
||||||
initNews()
|
function onDistroRefresh(data){
|
||||||
syncModConfigurations(data)
|
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
||||||
ensureJavaSettings(data)
|
refreshServerStatus()
|
||||||
}
|
initNews()
|
||||||
|
syncModConfigurations(data)
|
||||||
/**
|
}
|
||||||
* Sync the mod configurations with the distro index.
|
|
||||||
*
|
/**
|
||||||
* @param {Object} data The distro index object.
|
* Sync the mod configurations with the distro index.
|
||||||
*/
|
*
|
||||||
function syncModConfigurations(data){
|
* @param {Object} data The distro index object.
|
||||||
|
*/
|
||||||
const syncedCfgs = []
|
function syncModConfigurations(data){
|
||||||
|
|
||||||
for(let serv of data.servers){
|
const syncedCfgs = []
|
||||||
|
|
||||||
const id = serv.rawServer.id
|
for(let serv of data.getServers()){
|
||||||
const mdls = serv.modules
|
|
||||||
const cfg = ConfigManager.getModConfiguration(id)
|
const id = serv.getID()
|
||||||
|
const mdls = serv.getModules()
|
||||||
if(cfg != null){
|
const cfg = ConfigManager.getModConfiguration(id)
|
||||||
|
|
||||||
const modsOld = cfg.mods
|
if(cfg != null){
|
||||||
const mods = {}
|
|
||||||
|
const modsOld = cfg.mods
|
||||||
for(let mdl of mdls){
|
const mods = {}
|
||||||
const type = mdl.rawModule.type
|
|
||||||
|
for(let mdl of mdls){
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
const type = mdl.getType()
|
||||||
if(!mdl.getRequired().value){
|
|
||||||
const mdlID = mdl.getVersionlessMavenIdentifier()
|
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||||
if(modsOld[mdlID] == null){
|
if(!mdl.getRequired().isRequired()){
|
||||||
mods[mdlID] = scanOptionalSubModules(mdl.subModules, mdl)
|
const mdlID = mdl.getVersionlessID()
|
||||||
} else {
|
if(modsOld[mdlID] == null){
|
||||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.subModules, mdl), false)
|
mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||||
}
|
} else {
|
||||||
} else {
|
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false)
|
||||||
if(mdl.subModules.length > 0){
|
}
|
||||||
const mdlID = mdl.getVersionlessMavenIdentifier()
|
} else {
|
||||||
const v = scanOptionalSubModules(mdl.subModules, mdl)
|
if(mdl.hasSubModules()){
|
||||||
if(typeof v === 'object'){
|
const mdlID = mdl.getVersionlessID()
|
||||||
if(modsOld[mdlID] == null){
|
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||||
mods[mdlID] = v
|
if(typeof v === 'object'){
|
||||||
} else {
|
if(modsOld[mdlID] == null){
|
||||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true)
|
mods[mdlID] = v
|
||||||
}
|
} else {
|
||||||
}
|
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
syncedCfgs.push({
|
}
|
||||||
id,
|
|
||||||
mods
|
syncedCfgs.push({
|
||||||
})
|
id,
|
||||||
|
mods
|
||||||
} else {
|
})
|
||||||
|
|
||||||
const mods = {}
|
} else {
|
||||||
|
|
||||||
for(let mdl of mdls){
|
const mods = {}
|
||||||
const type = mdl.rawModule.type
|
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
for(let mdl of mdls){
|
||||||
if(!mdl.getRequired().value){
|
const type = mdl.getType()
|
||||||
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||||
} else {
|
if(!mdl.getRequired().isRequired()){
|
||||||
if(mdl.subModules.length > 0){
|
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||||
const v = scanOptionalSubModules(mdl.subModules, mdl)
|
} else {
|
||||||
if(typeof v === 'object'){
|
if(mdl.hasSubModules()){
|
||||||
mods[mdl.getVersionlessMavenIdentifier()] = v
|
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||||
}
|
if(typeof v === 'object'){
|
||||||
}
|
mods[mdl.getVersionlessID()] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
syncedCfgs.push({
|
}
|
||||||
id,
|
|
||||||
mods
|
syncedCfgs.push({
|
||||||
})
|
id,
|
||||||
|
mods
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
}
|
||||||
ConfigManager.setModConfigurations(syncedCfgs)
|
}
|
||||||
ConfigManager.save()
|
|
||||||
}
|
ConfigManager.setModConfigurations(syncedCfgs)
|
||||||
|
ConfigManager.save()
|
||||||
/**
|
}
|
||||||
* Ensure java configurations are present for the available servers.
|
|
||||||
*
|
/**
|
||||||
* @param {Object} data The distro index object.
|
* Recursively scan for optional sub modules. If none are found,
|
||||||
*/
|
* this function returns a boolean. If optional sub modules do exist,
|
||||||
function ensureJavaSettings(data) {
|
* a recursive configuration object is returned.
|
||||||
|
*
|
||||||
// Nothing too fancy for now.
|
* @returns {boolean | Object} The resolved mod configuration.
|
||||||
for(const serv of data.servers){
|
*/
|
||||||
ConfigManager.ensureJavaConfig(serv.rawServer.id, serv.effectiveJavaOptions, serv.rawServer.javaOptions?.ram)
|
function scanOptionalSubModules(mdls, origin){
|
||||||
}
|
if(mdls != null){
|
||||||
|
const mods = {}
|
||||||
ConfigManager.save()
|
|
||||||
}
|
for(let mdl of mdls){
|
||||||
|
const type = mdl.getType()
|
||||||
/**
|
// Optional types.
|
||||||
* Recursively scan for optional sub modules. If none are found,
|
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||||
* this function returns a boolean. If optional sub modules do exist,
|
// It is optional.
|
||||||
* a recursive configuration object is returned.
|
if(!mdl.getRequired().isRequired()){
|
||||||
*
|
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||||
* @returns {boolean | Object} The resolved mod configuration.
|
} else {
|
||||||
*/
|
if(mdl.hasSubModules()){
|
||||||
function scanOptionalSubModules(mdls, origin){
|
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||||
if(mdls != null){
|
if(typeof v === 'object'){
|
||||||
const mods = {}
|
mods[mdl.getVersionlessID()] = v
|
||||||
|
}
|
||||||
for(let mdl of mdls){
|
}
|
||||||
const type = mdl.rawModule.type
|
}
|
||||||
// Optional types.
|
}
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
}
|
||||||
// It is optional.
|
|
||||||
if(!mdl.getRequired().value){
|
if(Object.keys(mods).length > 0){
|
||||||
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
const ret = {
|
||||||
} else {
|
mods
|
||||||
if(mdl.hasSubModules()){
|
}
|
||||||
const v = scanOptionalSubModules(mdl.subModules, mdl)
|
if(!origin.getRequired().isRequired()){
|
||||||
if(typeof v === 'object'){
|
ret.value = origin.getRequired().isDefault()
|
||||||
mods[mdl.getVersionlessMavenIdentifier()] = v
|
}
|
||||||
}
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return origin.getRequired().isDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Object.keys(mods).length > 0){
|
/**
|
||||||
const ret = {
|
* Recursively merge an old configuration into a new configuration.
|
||||||
mods
|
*
|
||||||
}
|
* @param {boolean | Object} o The old configuration value.
|
||||||
if(!origin.getRequired().value){
|
* @param {boolean | Object} n The new configuration value.
|
||||||
ret.value = origin.getRequired().def
|
* @param {boolean} nReq If the new value is a required mod.
|
||||||
}
|
*
|
||||||
return ret
|
* @returns {boolean | Object} The merged configuration.
|
||||||
}
|
*/
|
||||||
}
|
function mergeModConfiguration(o, n, nReq = false){
|
||||||
return origin.getRequired().def
|
if(typeof o === 'boolean'){
|
||||||
}
|
if(typeof n === 'boolean') return o
|
||||||
|
else if(typeof n === 'object'){
|
||||||
/**
|
if(!nReq){
|
||||||
* Recursively merge an old configuration into a new configuration.
|
n.value = o
|
||||||
*
|
}
|
||||||
* @param {boolean | Object} o The old configuration value.
|
return n
|
||||||
* @param {boolean | Object} n The new configuration value.
|
}
|
||||||
* @param {boolean} nReq If the new value is a required mod.
|
} else if(typeof o === 'object'){
|
||||||
*
|
if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true
|
||||||
* @returns {boolean | Object} The merged configuration.
|
else if(typeof n === 'object'){
|
||||||
*/
|
if(!nReq){
|
||||||
function mergeModConfiguration(o, n, nReq = false){
|
n.value = typeof o.value !== 'undefined' ? o.value : true
|
||||||
if(typeof o === 'boolean'){
|
}
|
||||||
if(typeof n === 'boolean') return o
|
|
||||||
else if(typeof n === 'object'){
|
const newMods = Object.keys(n.mods)
|
||||||
if(!nReq){
|
for(let i=0; i<newMods.length; i++){
|
||||||
n.value = o
|
|
||||||
}
|
const mod = newMods[i]
|
||||||
return n
|
if(o.mods[mod] != null){
|
||||||
}
|
n.mods[mod] = mergeModConfiguration(o.mods[mod], n.mods[mod])
|
||||||
} else if(typeof o === 'object'){
|
}
|
||||||
if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true
|
}
|
||||||
else if(typeof n === 'object'){
|
|
||||||
if(!nReq){
|
return n
|
||||||
n.value = typeof o.value !== 'undefined' ? o.value : true
|
}
|
||||||
}
|
}
|
||||||
|
// If for some reason we haven't been able to merge,
|
||||||
const newMods = Object.keys(n.mods)
|
// wipe the old value and use the new one. Just to be safe
|
||||||
for(let i=0; i<newMods.length; i++){
|
return n
|
||||||
|
}
|
||||||
const mod = newMods[i]
|
|
||||||
if(o.mods[mod] != null){
|
function refreshDistributionIndex(remote, onSuccess, onError){
|
||||||
n.mods[mod] = mergeModConfiguration(o.mods[mod], n.mods[mod])
|
if(remote){
|
||||||
}
|
DistroManager.pullRemote()
|
||||||
}
|
.then(onSuccess)
|
||||||
|
.catch(onError)
|
||||||
return n
|
} else {
|
||||||
}
|
DistroManager.pullLocal()
|
||||||
}
|
.then(onSuccess)
|
||||||
// If for some reason we haven't been able to merge,
|
.catch(onError)
|
||||||
// wipe the old value and use the new one. Just to be safe
|
}
|
||||||
return n
|
}
|
||||||
}
|
|
||||||
|
async function validateSelectedAccount(){
|
||||||
async function validateSelectedAccount(){
|
const selectedAcc = ConfigManager.getSelectedAccount()
|
||||||
const selectedAcc = ConfigManager.getSelectedAccount()
|
if(selectedAcc != null && selectedAcc.type != 'offline'){
|
||||||
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',
|
||||||
Lang.queryJS('uibinder.validateAccount.failedMessageTitle'),
|
`We were unable to refresh the login for <strong>${selectedAcc.displayName}</strong>. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`,
|
||||||
accLen > 0
|
'Login',
|
||||||
? Lang.queryJS('uibinder.validateAccount.failedMessage', { 'account': selectedAcc.displayName })
|
'Select Another Account'
|
||||||
: Lang.queryJS('uibinder.validateAccount.failedMessageSelectAnotherAccount', { 'account': selectedAcc.displayName }),
|
)
|
||||||
Lang.queryJS('uibinder.validateAccount.loginButton'),
|
setOverlayHandler(() => {
|
||||||
Lang.queryJS('uibinder.validateAccount.selectAnotherAccountButton')
|
|
||||||
)
|
const isMicrosoft = selectedAcc.type === 'microsoft'
|
||||||
setOverlayHandler(() => {
|
|
||||||
|
if(isMicrosoft) {
|
||||||
const isMicrosoft = selectedAcc.type === 'microsoft'
|
// Empty for now
|
||||||
|
} else {
|
||||||
if(isMicrosoft) {
|
// Mojang
|
||||||
// Empty for now
|
// For convenience, pre-populate the username of the account.
|
||||||
} else {
|
document.getElementById('loginUsername').value = selectedAcc.username
|
||||||
// Mojang
|
validateEmail(selectedAcc.username)
|
||||||
// For convenience, pre-populate the username of the account.
|
}
|
||||||
document.getElementById('loginUsername').value = selectedAcc.username
|
|
||||||
validateEmail(selectedAcc.username)
|
loginOptionsViewOnLoginSuccess = getCurrentView()
|
||||||
}
|
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||||
|
|
||||||
loginOptionsViewOnLoginSuccess = getCurrentView()
|
if(accLen > 0) {
|
||||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
loginOptionsViewOnCancel = getCurrentView()
|
||||||
|
loginOptionsViewCancelHandler = () => {
|
||||||
if(accLen > 0) {
|
if(isMicrosoft) {
|
||||||
loginOptionsViewOnCancel = getCurrentView()
|
ConfigManager.addMicrosoftAuthAccount(
|
||||||
loginOptionsViewCancelHandler = () => {
|
selectedAcc.uuid,
|
||||||
if(isMicrosoft) {
|
selectedAcc.accessToken,
|
||||||
ConfigManager.addMicrosoftAuthAccount(
|
selectedAcc.username,
|
||||||
selectedAcc.uuid,
|
selectedAcc.expiresAt,
|
||||||
selectedAcc.accessToken,
|
selectedAcc.microsoft.access_token,
|
||||||
selectedAcc.username,
|
selectedAcc.microsoft.refresh_token,
|
||||||
selectedAcc.expiresAt,
|
selectedAcc.microsoft.expires_at
|
||||||
selectedAcc.microsoft.access_token,
|
)
|
||||||
selectedAcc.microsoft.refresh_token,
|
} else {
|
||||||
selectedAcc.microsoft.expires_at
|
ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
|
||||||
)
|
}
|
||||||
} else {
|
ConfigManager.save()
|
||||||
ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
|
validateSelectedAccount()
|
||||||
}
|
}
|
||||||
ConfigManager.save()
|
loginOptionsCancelEnabled(true)
|
||||||
validateSelectedAccount()
|
} else {
|
||||||
}
|
loginOptionsCancelEnabled(false)
|
||||||
loginOptionsCancelEnabled(true)
|
}
|
||||||
} else {
|
toggleOverlay(false)
|
||||||
loginOptionsCancelEnabled(false)
|
switchView(getCurrentView(), VIEWS.loginOptions)
|
||||||
}
|
})
|
||||||
toggleOverlay(false)
|
setDismissHandler(() => {
|
||||||
switchView(getCurrentView(), VIEWS.loginOptions)
|
if(accLen > 1){
|
||||||
})
|
prepareAccountSelectionList()
|
||||||
setDismissHandler(() => {
|
$('#overlayContent').fadeOut(250, () => {
|
||||||
if(accLen > 1){
|
bindOverlayKeys(true, 'accountSelectContent', true)
|
||||||
prepareAccountSelectionList()
|
$('#accountSelectContent').fadeIn(250)
|
||||||
$('#overlayContent').fadeOut(250, () => {
|
})
|
||||||
bindOverlayKeys(true, 'accountSelectContent', true)
|
} else {
|
||||||
$('#accountSelectContent').fadeIn(250)
|
const accountsObj = ConfigManager.getAuthAccounts()
|
||||||
})
|
const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v])
|
||||||
} else {
|
// This function validates the account switch.
|
||||||
const accountsObj = ConfigManager.getAuthAccounts()
|
setSelectedAccount(accounts[0].uuid)
|
||||||
const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v])
|
toggleOverlay(false)
|
||||||
// This function validates the account switch.
|
}
|
||||||
setSelectedAccount(accounts[0].uuid)
|
})
|
||||||
toggleOverlay(false)
|
toggleOverlay(true, accLen > 0)
|
||||||
}
|
} else {
|
||||||
})
|
return true
|
||||||
toggleOverlay(true, accLen > 0)
|
}
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return true
|
|
||||||
}
|
/**
|
||||||
}
|
* Temporary function to update the selected account along
|
||||||
|
* with the relevent UI elements.
|
||||||
/**
|
*
|
||||||
* Temporary function to update the selected account along
|
* @param {string} uuid The UUID of the account.
|
||||||
* with the relevent UI elements.
|
*/
|
||||||
*
|
function setSelectedAccount(uuid){
|
||||||
* @param {string} uuid The UUID of the account.
|
const authAcc = ConfigManager.setSelectedAccount(uuid)
|
||||||
*/
|
ConfigManager.save()
|
||||||
function setSelectedAccount(uuid){
|
updateSelectedAccount(authAcc)
|
||||||
const authAcc = ConfigManager.setSelectedAccount(uuid)
|
if (ConfigManager.getAuthAccounts[uuid].type !== 'offline'){
|
||||||
ConfigManager.save()
|
validateSelectedAccount()
|
||||||
updateSelectedAccount(authAcc)
|
}
|
||||||
validateSelectedAccount()
|
}
|
||||||
}
|
|
||||||
|
// Synchronous Listener
|
||||||
// Synchronous Listener
|
document.addEventListener('readystatechange', function(){
|
||||||
document.addEventListener('readystatechange', async () => {
|
|
||||||
|
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 = await DistroAPI.getDistribution()
|
showMainUI(data)
|
||||||
await 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', async (event, res) => {
|
if(res) {
|
||||||
if(res) {
|
const data = DistroManager.getDistribution()
|
||||||
const data = await DistroAPI.getDistribution()
|
syncModConfigurations(data)
|
||||||
syncModConfigurations(data)
|
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||||
ensureJavaSettings(data)
|
showMainUI(data)
|
||||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
} else {
|
||||||
await showMainUI(data)
|
rscShouldLoad = true
|
||||||
} else {
|
}
|
||||||
rscShouldLoad = true
|
} else {
|
||||||
}
|
fatalStartupError = true
|
||||||
} else {
|
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||||
fatalStartupError = true
|
showFatalStartupError()
|
||||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
} else {
|
||||||
showFatalStartupError()
|
rscShouldLoad = true
|
||||||
} else {
|
}
|
||||||
rscShouldLoad = true
|
}
|
||||||
}
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// Util for development
|
|
||||||
async function devModeToggle() {
|
|
||||||
DistroAPI.toggleDevMode(true)
|
|
||||||
const data = await DistroAPI.refreshDistributionOrFallback()
|
|
||||||
ensureJavaSettings(data)
|
|
||||||
updateSelectedServer(data.servers[0])
|
|
||||||
syncModConfigurations(data)
|
|
||||||
}
|
|
||||||
|
@ -10,10 +10,11 @@ const {ipcRenderer, shell, webFrame} = require('electron')
|
|||||||
const remote = require('@electron/remote')
|
const remote = require('@electron/remote')
|
||||||
const isDev = require('./assets/js/isdev')
|
const isDev = require('./assets/js/isdev')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
const Lang = require('./assets/js/langloader')
|
const LoggerUtil1 = require('./assets/js/loggerutil')
|
||||||
|
|
||||||
const loggerUICore = LoggerUtil.getLogger('UICore')
|
const loggerUICore = LoggerUtil1('%c[UICore]', 'color: #000668; font-weight: bold')
|
||||||
const loggerAutoUpdater = LoggerUtil.getLogger('AutoUpdater')
|
const loggerAutoUpdater = LoggerUtil1('%c[AutoUpdater]', 'color: #000668; font-weight: bold')
|
||||||
|
const loggerAutoUpdaterSuccess = LoggerUtil1('%c[AutoUpdater]', 'color: #209b07; font-weight: bold')
|
||||||
|
|
||||||
// Log deprecation and process warnings.
|
// Log deprecation and process warnings.
|
||||||
process.traceProcessWarnings = true
|
process.traceProcessWarnings = true
|
||||||
@ -42,11 +43,11 @@ 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.info('Checking for update..')
|
loggerAutoUpdater.log('Checking for update..')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkingForUpdateButton'), true)
|
settingsUpdateButtonStatus('Checking for Updates..', true)
|
||||||
break
|
break
|
||||||
case 'update-available':
|
case 'update-available':
|
||||||
loggerAutoUpdater.info('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}/Helios-Launcher-setup-${info.version}${process.arch === 'arm64' ? '-arm64' : '-x64'}.dmg`
|
info.darwindownload = `https://github.com/dscalzi/HeliosLauncher/releases/download/v${info.version}/Helios-Launcher-setup-${info.version}${process.arch === 'arm64' ? '-arm64' : '-x64'}.dmg`
|
||||||
@ -56,8 +57,8 @@ if(!isDev){
|
|||||||
populateSettingsUpdateInformation(info)
|
populateSettingsUpdateInformation(info)
|
||||||
break
|
break
|
||||||
case 'update-downloaded':
|
case 'update-downloaded':
|
||||||
loggerAutoUpdater.info('Update ' + info.version + ' ready to be installed.')
|
loggerAutoUpdaterSuccess.log('Update ' + info.version + ' ready to be installed.')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.installNowButton'), false, () => {
|
settingsUpdateButtonStatus('Install Now', false, () => {
|
||||||
if(!isDev){
|
if(!isDev){
|
||||||
ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
|
ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
|
||||||
}
|
}
|
||||||
@ -65,8 +66,8 @@ if(!isDev){
|
|||||||
showUpdateUI(info)
|
showUpdateUI(info)
|
||||||
break
|
break
|
||||||
case 'update-not-available':
|
case 'update-not-available':
|
||||||
loggerAutoUpdater.info('No new update found.')
|
loggerAutoUpdater.log('No new update found.')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkForUpdatesButton'))
|
settingsUpdateButtonStatus('Check for Updates')
|
||||||
break
|
break
|
||||||
case 'ready':
|
case 'ready':
|
||||||
updateCheckListener = setInterval(() => {
|
updateCheckListener = setInterval(() => {
|
||||||
@ -77,9 +78,9 @@ if(!isDev){
|
|||||||
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.info('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.info('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)
|
||||||
@ -87,7 +88,7 @@ if(!isDev){
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
loggerAutoUpdater.info('Unknown argument', arg)
|
loggerAutoUpdater.log('Unknown argument', arg)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -130,12 +131,12 @@ function showUpdateUI(info){
|
|||||||
|
|
||||||
/* jQuery Example
|
/* jQuery Example
|
||||||
$(function(){
|
$(function(){
|
||||||
loggerUICore.info('UICore Initialized');
|
loggerUICore.log('UICore Initialized');
|
||||||
})*/
|
})*/
|
||||||
|
|
||||||
document.addEventListener('readystatechange', function () {
|
document.addEventListener('readystatechange', function () {
|
||||||
if (document.readyState === 'interactive'){
|
if (document.readyState === 'interactive'){
|
||||||
loggerUICore.info('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) => {
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
# Custom Language File for Launcher Customizer
|
|
||||||
|
|
||||||
[ejs.app]
|
|
||||||
title = "Helios Launcher"
|
|
||||||
|
|
||||||
[ejs.landing]
|
|
||||||
mediaGitHubURL = "https://github.com/dscalzi/HeliosLauncher"
|
|
||||||
mediaTwitterURL = "#"
|
|
||||||
mediaInstagramURL = "#"
|
|
||||||
mediaYouTubeURL = "#"
|
|
||||||
mediaDiscordURL = "https://discord.gg/zNWUXdt"
|
|
||||||
|
|
||||||
[ejs.settings]
|
|
||||||
sourceGithubLink = "https://github.com/dscalZi/HeliosLauncher"
|
|
||||||
supportLink = "https://github.com/dscalZi/HeliosLauncher/issues"
|
|
||||||
|
|
||||||
[ejs.welcome]
|
|
||||||
welcomeHeader = "WELCOME TO WESTEROSCRAFT"
|
|
||||||
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 aren’t afraid, beyond the Wall itself, but best not delay. As the words of House Stark ominously warn: Winter is Coming."
|
|
||||||
welcomeDescCTA = "You are just a few clicks away from Westeros."
|
|
49
app/assets/lang/en_US.json
Normal file
49
app/assets/lang/en_US.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"html": {
|
||||||
|
"avatarOverlay": "Edit"
|
||||||
|
},
|
||||||
|
"js": {
|
||||||
|
"login": {
|
||||||
|
"error": {
|
||||||
|
"invalidValue": "* Invalid Value",
|
||||||
|
"requiredValue": "* Required",
|
||||||
|
"userMigrated": {
|
||||||
|
"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."
|
||||||
|
},
|
||||||
|
"invalidCredentials": {
|
||||||
|
"title": "Error During Login:<br>Invalid Credentials",
|
||||||
|
"desc": "The email or password you've entered is incorrect. Please try again."
|
||||||
|
},
|
||||||
|
"rateLimit": {
|
||||||
|
"title": "Error During Login:<br>Too Many Attempts",
|
||||||
|
"desc": "There have been too many login attempts with this account recently. Please try again later."
|
||||||
|
},
|
||||||
|
"noInternet": {
|
||||||
|
"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."
|
||||||
|
},
|
||||||
|
"authDown": {
|
||||||
|
"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>."
|
||||||
|
},
|
||||||
|
"notPaid": {
|
||||||
|
"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>"
|
||||||
|
},
|
||||||
|
"unknown": {
|
||||||
|
"title": "Error During Login:<br>Unknown Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"login": "LOGIN",
|
||||||
|
"loggingIn": "LOGGING IN",
|
||||||
|
"success": "SUCCESS",
|
||||||
|
"tryAgain": "Try Again"
|
||||||
|
},
|
||||||
|
"landing": {
|
||||||
|
"launch": {
|
||||||
|
"pleaseWait": "Please wait.."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,297 +0,0 @@
|
|||||||
[ejs.landing]
|
|
||||||
updateAvailableTooltip = "Update Available"
|
|
||||||
usernamePlaceholder = "Username"
|
|
||||||
usernameEditButton = "Edit"
|
|
||||||
settingsTooltip = "Settings"
|
|
||||||
serverStatus = "SERVER"
|
|
||||||
serverStatusPlaceholder = "OFFLINE"
|
|
||||||
mojangStatus = "MOJANG STATUS"
|
|
||||||
mojangStatusTooltipTitle = "Services"
|
|
||||||
mojangStatusNETitle = "Non Essential"
|
|
||||||
newsButton = "NEWS"
|
|
||||||
launchButton = "PLAY"
|
|
||||||
launchButtonPlaceholder = "• No Server Selected"
|
|
||||||
launchDetails = "Please wait.."
|
|
||||||
newsNavigationStatus = "{currentPage} of {totalPages}"
|
|
||||||
newsErrorLoadSpan = "Checking for News.."
|
|
||||||
newsErrorFailedSpan = "Failed to Load News"
|
|
||||||
newsErrorRetryButton = "Try Again"
|
|
||||||
newsErrorNoneSpan = "No News"
|
|
||||||
|
|
||||||
[ejs.login]
|
|
||||||
loginCancelText = "Cancel"
|
|
||||||
loginSubheader = "MINECRAFT LOGIN"
|
|
||||||
loginEmailError = "* Invalid Value"
|
|
||||||
loginEmailPlaceholder = "EMAIL OR USERNAME"
|
|
||||||
loginPasswordError = "* Required"
|
|
||||||
loginPasswordPlaceholder = "PASSWORD"
|
|
||||||
loginForgotPasswordLink = "https://minecraft.net/password/forgot/"
|
|
||||||
loginForgotPasswordText = "forgot password?"
|
|
||||||
loginRememberMeText = "remember me?"
|
|
||||||
loginButtonText = "LOGIN"
|
|
||||||
loginNeedAccountLink = "https://minecraft.net/store/minecraft-java-edition/"
|
|
||||||
loginNeedAccountText = "Need an Account?"
|
|
||||||
loginPasswordDisclaimer1 = "Your password is sent directly to mojang and never stored."
|
|
||||||
loginPasswordDisclaimer2 = "{appName} is not affiliated with Mojang AB."
|
|
||||||
|
|
||||||
[ejs.loginOptions]
|
|
||||||
loginOptionsTitle = "Login Options"
|
|
||||||
loginWithMicrosoft = "Login with Microsoft"
|
|
||||||
loginWithMojang = "Login with Mojang"
|
|
||||||
cancelButton = "Cancel"
|
|
||||||
|
|
||||||
[ejs.overlay]
|
|
||||||
serverSelectHeader = "Available Servers"
|
|
||||||
serverSelectConfirm = "Select"
|
|
||||||
serverSelectCancel = "Cancel"
|
|
||||||
accountSelectHeader = "Select an Account"
|
|
||||||
accountSelectConfirm = "Select"
|
|
||||||
accountSelectCancel = "Cancel"
|
|
||||||
|
|
||||||
[ejs.settings]
|
|
||||||
navHeaderText = "Settings"
|
|
||||||
navAccount = "Account"
|
|
||||||
navMinecraft = "Minecraft"
|
|
||||||
navMods = "Mods"
|
|
||||||
navJava = "Java"
|
|
||||||
navLauncher = "Launcher"
|
|
||||||
navAbout = "About"
|
|
||||||
navUpdates = "Updates"
|
|
||||||
navDone = "Done"
|
|
||||||
tabAccountHeaderText = "Account Settings"
|
|
||||||
tabAccountHeaderDesc = "Add new accounts or manage existing ones."
|
|
||||||
microsoftAccount = "Microsoft"
|
|
||||||
addMicrosoftAccount = "+ Add Microsoft Account"
|
|
||||||
mojangAccount = "Mojang"
|
|
||||||
addMojangAccount = "+ Add Mojang Account"
|
|
||||||
minecraftTabHeaderText = "Minecraft Settings"
|
|
||||||
minecraftTabHeaderDesc = "Options related to game launch."
|
|
||||||
gameResolutionTitle = "Game Resolution"
|
|
||||||
launchFullscreenTitle = "Launch in fullscreen."
|
|
||||||
autoConnectTitle = "Automatically connect to the server on launch."
|
|
||||||
launchDetachedTitle = "Launch game process detached from launcher."
|
|
||||||
launchDetachedDesc = "If the game is not detached, closing the launcher will also close the game."
|
|
||||||
tabModsHeaderText = "Mod Settings"
|
|
||||||
tabModsHeaderDesc = "Enable or disable mods."
|
|
||||||
switchServerButton = "Switch"
|
|
||||||
requiredMods = "Required Mods"
|
|
||||||
optionalMods = "Optional Mods"
|
|
||||||
dropinMods = "Drop-in Mods"
|
|
||||||
addMods = "Add Mods"
|
|
||||||
dropinRefreshNote = "(F5 to Refresh)"
|
|
||||||
shaderpacks = "Shaderpacks"
|
|
||||||
shaderpackDesc = "Enable or disable shaders. Please note, shaders will only run smoothly on powerful setups. You may add custom packs here."
|
|
||||||
selectShaderpack = "Select Shaderpack"
|
|
||||||
tabJavaHeaderText = "Java Settings"
|
|
||||||
tabJavaHeaderDesc = "Manage the Java configuration (advanced)."
|
|
||||||
memoryTitle = "Memory"
|
|
||||||
maxRAM = "Maximum RAM"
|
|
||||||
minRAM = "Minimum RAM"
|
|
||||||
memoryDesc = "The recommended minimum RAM is 3 gigabytes. Setting the minimum and maximum values to the same value may reduce lag."
|
|
||||||
memoryTotalTitle = "Total"
|
|
||||||
memoryAvailableTitle = "Available"
|
|
||||||
javaExecutableTitle = "Java Executable"
|
|
||||||
javaExecSelDialogTitle = "Select Java Executable"
|
|
||||||
javaExecSelButtonText = "Choose File"
|
|
||||||
javaExecDesc = "The Java executable is validated before game launch."
|
|
||||||
javaPathDesc = "The path should end with <strong>{pathSuffix}</strong>."
|
|
||||||
jvmOptsTitle = "Additional JVM Options"
|
|
||||||
jvmOptsDesc = "Options to be provided to the JVM at runtime. <em>-Xms</em> and <em>-Xmx</em> should not be included."
|
|
||||||
launcherTabHeaderText = "Launcher Settings"
|
|
||||||
launcherTabHeaderDesc = "Options related to the launcher itself."
|
|
||||||
allowPrereleaseTitle = "Allow Pre-Release Updates."
|
|
||||||
allowPrereleaseDesc = "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."
|
|
||||||
dataDirectoryTitle = "Data Directory"
|
|
||||||
selectDataDirectory = "Select Data Directory"
|
|
||||||
chooseFolder = "Choose Folder"
|
|
||||||
dataDirectoryDesc = "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."
|
|
||||||
aboutTabHeaderText = "About"
|
|
||||||
aboutTabHeaderDesc = "View information and release notes for the current version."
|
|
||||||
aboutTitle = "{appName}"
|
|
||||||
stableRelease = "Stable Release"
|
|
||||||
versionText = "Version "
|
|
||||||
sourceGithub = "Source (GitHub)"
|
|
||||||
support = "Support"
|
|
||||||
devToolsConsole = "DevTools Console"
|
|
||||||
releaseNotes = "Release Notes"
|
|
||||||
changelog = "Changelog"
|
|
||||||
noReleaseNotes = "No Release Notes"
|
|
||||||
viewReleaseNotes = "View Release Notes on GitHub"
|
|
||||||
launcherUpdatesHeaderText = "Launcher Updates"
|
|
||||||
launcherUpdatesHeaderDesc = "Download, install, and review updates for the launcher."
|
|
||||||
checkForUpdates = "Check for Updates"
|
|
||||||
whatsNew = "What's New"
|
|
||||||
updateReleaseNotes = "Update Release Notes"
|
|
||||||
|
|
||||||
[ejs.waiting]
|
|
||||||
waitingText = "Waiting for Microsoft.."
|
|
||||||
|
|
||||||
[ejs.welcome]
|
|
||||||
continueButton = "CONTINUE"
|
|
||||||
|
|
||||||
|
|
||||||
[js.discord]
|
|
||||||
waiting = "Waiting for Client.."
|
|
||||||
state = "Server: {shortId}"
|
|
||||||
|
|
||||||
[js.index]
|
|
||||||
microsoftLoginTitle = "Microsoft Login"
|
|
||||||
microsoftLogoutTitle = "Microsoft Logout"
|
|
||||||
|
|
||||||
[js.login]
|
|
||||||
login = "LOGIN"
|
|
||||||
loggingIn = "LOGGING IN"
|
|
||||||
success = "SUCCESS"
|
|
||||||
tryAgain = "Try Again"
|
|
||||||
|
|
||||||
[js.login.error]
|
|
||||||
invalidValue = "* Invalid Value"
|
|
||||||
requiredValue = "* Required"
|
|
||||||
|
|
||||||
[js.login.error.unknown]
|
|
||||||
title = "Unknown Error During Login"
|
|
||||||
desc = "An unknown error has occurred. Please see the console for details."
|
|
||||||
|
|
||||||
[js.landing.launch]
|
|
||||||
pleaseWait = "Please wait.."
|
|
||||||
failureTitle = "Error During Launch"
|
|
||||||
failureText = "See console (CTRL + Shift + i) for more details."
|
|
||||||
okay = "Okay"
|
|
||||||
|
|
||||||
[js.landing.selectedAccount]
|
|
||||||
noAccountSelected = "No Account Selected"
|
|
||||||
|
|
||||||
[js.landing.selectedServer]
|
|
||||||
noSelection = "No Server Selected"
|
|
||||||
loading = "Loading.."
|
|
||||||
|
|
||||||
[js.landing.serverStatus]
|
|
||||||
server = "SERVER"
|
|
||||||
offline = "OFFLINE"
|
|
||||||
players = "PLAYERS"
|
|
||||||
|
|
||||||
[js.landing.systemScan]
|
|
||||||
checking = "Checking system info.."
|
|
||||||
noCompatibleJava = "No Compatible<br>Java Installation Found"
|
|
||||||
installJavaMessage = "In order to launch Minecraft, you need a 64-bit installation of Java {major}. Would you like us to install a copy?"
|
|
||||||
installJava = "Install Java"
|
|
||||||
installJavaManually = "Install Manually"
|
|
||||||
javaDownloadPrepare = "Preparing Java Download.."
|
|
||||||
javaDownloadFailureTitle = "Error During Java Download"
|
|
||||||
javaDownloadFailureText = "See console (CTRL + Shift + i) for more details."
|
|
||||||
javaRequired = "Java is Required<br>to Launch"
|
|
||||||
javaRequiredMessage = 'A valid x64 installation of Java {major} is required to launch.<br><br>Please refer to our <a href="https://github.com/dscalzi/HeliosLauncher/wiki/Java-Management#manually-installing-a-valid-version-of-java">Java Management Guide</a> for instructions on how to manually install Java.'
|
|
||||||
javaRequiredDismiss = "I Understand"
|
|
||||||
javaRequiredCancel = "Go Back"
|
|
||||||
|
|
||||||
[js.landing.downloadJava]
|
|
||||||
findJdkFailure = "Failed to find OpenJDK distribution."
|
|
||||||
javaDownloadCorruptedError = "Downloaded JDK has a bad hash, the file may be corrupted."
|
|
||||||
extractingJava = "Extracting Java"
|
|
||||||
javaInstalled = "Java Installed!"
|
|
||||||
|
|
||||||
[js.landing.dlAsync]
|
|
||||||
loadingServerInfo = "Loading server information.."
|
|
||||||
fatalError = "Fatal Error"
|
|
||||||
unableToLoadDistributionIndex = "Could not load a copy of the distribution index. See the console (CTRL + Shift + i) for more details."
|
|
||||||
pleaseWait = "Please wait.."
|
|
||||||
errorDuringLaunchTitle = "Error During Launch"
|
|
||||||
seeConsoleForDetails = "See console (CTRL + Shift + i) for more details."
|
|
||||||
validatingFileIntegrity = "Validating file integrity.."
|
|
||||||
errorDuringFileVerificationTitle = "Error During File Verification"
|
|
||||||
downloadingFiles = "Downloading files.."
|
|
||||||
errorDuringFileDownloadTitle = "Error During File Download"
|
|
||||||
preparingToLaunch = "Preparing to launch.."
|
|
||||||
launchingGame = "Launching game.."
|
|
||||||
launchWrapperNotDownloaded = "The main file, LaunchWrapper, failed to download properly. As a result, the game cannot launch.<br><br>To fix this issue, temporarily turn off your antivirus software and launch the game again.<br><br>If you have time, please <a href=\"https://github.com/dscalzi/HeliosLauncher/issues\">submit an issue</a> and let us know what antivirus software you use. We'll contact them and try to straighten things out."
|
|
||||||
doneEnjoyServer = "Done. Enjoy the server!"
|
|
||||||
checkConsoleForDetails = "Please check the console (CTRL + Shift + i) for more details."
|
|
||||||
|
|
||||||
[js.landing.news]
|
|
||||||
checking = "Checking for News"
|
|
||||||
|
|
||||||
[js.landing.discord]
|
|
||||||
loading = "Loading game.."
|
|
||||||
joining = "Sailing to Westeros!"
|
|
||||||
joined = "Exploring the Realm!"
|
|
||||||
|
|
||||||
[js.overlay]
|
|
||||||
dismiss = "Dismiss"
|
|
||||||
|
|
||||||
[js.settings.fileSelectors]
|
|
||||||
executables = "Executables"
|
|
||||||
allFiles = "All Files"
|
|
||||||
|
|
||||||
[js.settings.mstfLogin]
|
|
||||||
errorTitle = "Something Went Wrong"
|
|
||||||
errorMessage = "Microsoft authentication failed. Please try again."
|
|
||||||
okButton = "OK"
|
|
||||||
|
|
||||||
[js.settings.mstfLogout]
|
|
||||||
errorTitle = "Something Went Wrong"
|
|
||||||
errorMessage = "Microsoft logout failed. Please try again."
|
|
||||||
okButton = "OK"
|
|
||||||
|
|
||||||
[js.settings.authAccountSelect]
|
|
||||||
selectButton = "Select Account"
|
|
||||||
selectedButton = "Selected Account ✔"
|
|
||||||
|
|
||||||
[js.settings.authAccountLogout]
|
|
||||||
lastAccountWarningTitle = "Warning<br>This is Your Last Account"
|
|
||||||
lastAccountWarningMessage = "In order to use the launcher you must be logged into at least one account. You will need to login again after.<br><br>Are you sure you want to log out?"
|
|
||||||
confirmButton = "I'm Sure"
|
|
||||||
cancelButton = "Cancel"
|
|
||||||
|
|
||||||
[js.settings.authAccountPopulate]
|
|
||||||
username = "Username"
|
|
||||||
uuid = "UUID"
|
|
||||||
selectAccount = "Select Account"
|
|
||||||
selectedAccount = "Selected Account ✓"
|
|
||||||
logout = "Log Out"
|
|
||||||
|
|
||||||
[js.settings.dropinMods]
|
|
||||||
removeButton = "Remove"
|
|
||||||
deleteFailedTitle = "Failed to Delete<br>Drop-in Mod {fullName}"
|
|
||||||
deleteFailedMessage = "Make sure the file is not in use and try again."
|
|
||||||
failedToggleTitle = "Failed to Toggle<br>One or More Drop-in Mods"
|
|
||||||
okButton = "Okay"
|
|
||||||
|
|
||||||
[js.settings.serverListing]
|
|
||||||
mainServer = "Main Server"
|
|
||||||
|
|
||||||
[js.settings.java]
|
|
||||||
selectedJava = "Selected: Java {version} ({vendor})"
|
|
||||||
invalidSelection = "Invalid Selection"
|
|
||||||
requiresJava = "Requires Java {major} x64."
|
|
||||||
availableOptions = "Available Options for Java {major} (HotSpot VM)"
|
|
||||||
|
|
||||||
[js.settings.about]
|
|
||||||
preReleaseTitle = "Pre-release"
|
|
||||||
stableReleaseTitle = "Stable Release"
|
|
||||||
releaseNotesFailed = "Failed to load release notes."
|
|
||||||
|
|
||||||
[js.settings.updates]
|
|
||||||
newReleaseTitle = "New Release Available"
|
|
||||||
newPreReleaseTitle = "New Pre-release Available"
|
|
||||||
downloadingButton = "Downloading.."
|
|
||||||
downloadButton = 'Download from GitHub<span style="font-size: 10px;color: gray;text-shadow: none !important;">Close the launcher and run the dmg to update.</span>'
|
|
||||||
latestVersionTitle = "You Are Running the Latest Version"
|
|
||||||
checkForUpdatesButton = "Check for Updates"
|
|
||||||
checkingForUpdatesButton = "Checking for Updates.."
|
|
||||||
|
|
||||||
[js.uibinder.startup]
|
|
||||||
fatalErrorTitle = "Fatal Error: Unable to Load Distribution Index"
|
|
||||||
fatalErrorMessage = "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."
|
|
||||||
closeButton = "Close"
|
|
||||||
|
|
||||||
[js.uibinder.validateAccount]
|
|
||||||
failedMessageTitle = "Failed to Refresh Login"
|
|
||||||
failedMessage = "We were unable to refresh the login for <strong>{account}</strong>. Please select another account or login again."
|
|
||||||
failedMessageSelectAnotherAccount = "We were unable to refresh the login for <strong>{account}</strong>. Please login again."
|
|
||||||
loginButton = "Login"
|
|
||||||
selectAnotherAccountButton = "Select Another Account"
|
|
||||||
|
|
||||||
[js.uicore.autoUpdate]
|
|
||||||
checkingForUpdateButton = "Checking for Updates..."
|
|
||||||
installNowButton = "Install Now"
|
|
||||||
checkForUpdatesButton = "Check for Updates"
|
|
22
app/dynmap.ejs
Normal file
22
app/dynmap.ejs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<div id="dynmapContainer" style="display: none;">
|
||||||
|
<div class="FloatingButtonContainer" id="center">
|
||||||
|
<div class="bot_wrapper">
|
||||||
|
<div id="content">
|
||||||
|
<button id="dynmapDoneButton"> <!-- Rename all elements to dynmapEtc -->
|
||||||
|
<div id="newsButtonAlert" style="display: none;"></div>
|
||||||
|
<svg id="newsButtonSVG" viewBox="0 0 24.87 13.97">
|
||||||
|
<defs>
|
||||||
|
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;}</style>
|
||||||
|
</defs>
|
||||||
|
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
|
||||||
|
</svg>
|
||||||
|
<span id="newsButtonText">MAP</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="iframecontainer">
|
||||||
|
<iframe id="dynmapiframe" src="https://minemap.gregbrzezinski.com" frameborder="0"></iframe>
|
||||||
|
</div>
|
||||||
|
<script src="./assets/js/scripts/dynmap.js"></script>
|
||||||
|
</div>
|
@ -13,7 +13,7 @@
|
|||||||
<% } else{ %>
|
<% } else{ %>
|
||||||
<div id="frameContentWin">
|
<div id="frameContentWin">
|
||||||
<div id="frameTitleDock">
|
<div id="frameTitleDock">
|
||||||
<span id="frameTitleText"><%= lang('app.title') %></span>
|
<span id="frameTitleText">Helios Launcher</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">
|
||||||
|
111
app/landing.ejs
111
app/landing.ejs
@ -3,7 +3,7 @@
|
|||||||
<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"><%- lang('landing.updateAvailableTooltip') %></div>
|
<div id="updateAvailableTooltip">Update Available</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="content">
|
<div id="content">
|
||||||
@ -11,9 +11,9 @@
|
|||||||
<div id="right">
|
<div id="right">
|
||||||
<div id="rightContainer">
|
<div id="rightContainer">
|
||||||
<div id="user_content">
|
<div id="user_content">
|
||||||
<span id="user_text"><%- lang('landing.usernamePlaceholder') %></span>
|
<span id="user_text">Username</span>
|
||||||
<div id="avatarContainer">
|
<div id="avatarContainer">
|
||||||
<button id="avatarOverlay"><%- lang('landing.usernameEditButton') %></button>
|
<button id="avatarOverlay">Edit</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mediaContent">
|
<div id="mediaContent">
|
||||||
@ -23,24 +23,33 @@
|
|||||||
<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"><%- lang('landing.settingsTooltip') %></div>
|
<div id="settingsTooltip">Settings</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- map integration button
|
||||||
|
<div class="mediaContainer" id="mapMediaContainer">
|
||||||
|
<button class="mediaButton" id="mapMediaButton">
|
||||||
|
<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=""/>
|
||||||
|
</svg>
|
||||||
|
<div id="settingsTooltip">Map</div>
|
||||||
|
</button>
|
||||||
|
</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="<%- lang('landing.mediaGitHubURL') %>" class="mediaURL" id="linkURL">
|
<a href="https://discord.gg/JwKaVJG" class="mediaURL" id="discordURL">
|
||||||
<svg id="linkSVG" 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="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="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="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="<%- lang('landing.mediaTwitterURL') %>" class="mediaURL" id="twitterURL">
|
<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"/>
|
||||||
@ -49,39 +58,11 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="mediaContainer">
|
<div class="mediaContainer">
|
||||||
<a href="<%- lang('landing.mediaInstagramURL') %>" class="mediaURL" id="instagramURL">
|
<a href="https://github.com/dscalzi/HeliosLauncher" class="mediaURL" id="linkURL">
|
||||||
<svg id="instagramSVG" class="mediaSVG" viewBox="0 0 5040 5040">
|
<svg id="linkSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
||||||
<defs>
|
|
||||||
<radialGradient id="instaFill" cx="30%" cy="107%" r="150%">
|
|
||||||
<stop offset="0%" stop-color="#fdf497"/>
|
|
||||||
<stop offset="5%" stop-color="#fdf497"/>
|
|
||||||
<stop offset="45%" stop-color="#fd5949"/>
|
|
||||||
<stop offset="60%" stop-color="#d6249f"/>
|
|
||||||
<stop offset="90%" stop-color="#285AEB"/>
|
|
||||||
</radialGradient>
|
|
||||||
</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="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="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="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="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>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="mediaContainer">
|
|
||||||
<a href="<%- lang('landing.mediaYouTubeURL') %>" class="mediaURL" id="youtubeURL">
|
|
||||||
<svg id="youtubeSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
|
||||||
<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"/>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="mediaContainer">
|
|
||||||
<a href="<%- lang('landing.mediaDiscordURL') %>" class="mediaURL" id="discordURL">
|
|
||||||
<svg id="discordSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
|
||||||
<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"/>
|
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
@ -96,21 +77,21 @@
|
|||||||
<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"><%- lang('landing.serverStatus') %></span>
|
<span class="bot_label" id="landingPlayerLabel">SERVER</span>
|
||||||
<span id="player_count"><%- lang('landing.serverStatusPlaceholder') %></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"><%- lang('landing.mojangStatus') %></span>
|
<span class="bot_label">MOJANG STATUS</span>
|
||||||
<span id="mojang_status_icon">•</span>
|
<span id="mojang_status_icon">•</span>
|
||||||
<div id="mojangStatusTooltip">
|
<div id="mojangStatusTooltip">
|
||||||
<div id="mojangStatusTooltipTitle"><%- lang('landing.mojangStatusTooltipTitle') %></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"><%- lang('landing.mojangStatusNETitle') %></div>
|
<div id="mojangStatusNETitle">Non Essential</div>
|
||||||
<div class="mojangStatusNEBar"></div>
|
<div class="mojangStatusNEBar"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="mojangStatusNonEssentialContainer">
|
<div id="mojangStatusNonEssentialContainer">
|
||||||
@ -125,25 +106,20 @@
|
|||||||
<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"/>-->
|
|
||||||
<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 xmlns="http://www.w3.org/2000/svg" id="mapsvg" viewBox="0 0 24 24" width="20" height="20"><path d="M12,0A12,12,0,1,0,24,12,12.013,12.013,0,0,0,12,0ZM22,12a9.938,9.938,0,0,1-1.662,5.508l-1.192-1.193A.5.5,0,0,1,19,15.962V15a3,3,0,0,0-3-3H13a1,1,0,0,1-1-1v-.5a.5.5,0,0,1,.5-.5A2.5,2.5,0,0,0,15,7.5v-1a.5.5,0,0,1,.5-.5h1.379a2.516,2.516,0,0,0,1.767-.732l.377-.377A9.969,9.969,0,0,1,22,12Zm-19.951.963,3.158,3.158A2.978,2.978,0,0,0,7.329,17H10a1,1,0,0,1,1,1v3.949A10.016,10.016,0,0,1,2.049,12.963ZM13,21.949V18a3,3,0,0,0-3-3H7.329a1,1,0,0,1-.708-.293L2.163,10.249A9.978,9.978,0,0,1,17.456,3.63l-.224.224A.507.507,0,0,1,16.879,4H15.5A2.5,2.5,0,0,0,13,6.5v1a.5.5,0,0,1-.5.5A2.5,2.5,0,0,0,10,10.5V11a3,3,0,0,0,3,3h3a1,1,0,0,1,1,1v.962a2.516,2.516,0,0,0,.732,1.767l1.337,1.337A9.971,9.971,0,0,1,13,21.949Z"/></svg>
|
||||||
<defs>
|
<span id="newsButtonText">MAP</span>
|
||||||
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;}</style>
|
|
||||||
</defs>
|
|
||||||
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
|
|
||||||
</svg>
|
|
||||||
<span id="newsButtonText"><%- lang('landing.newsButton') %></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"><%- lang('landing.launchButton') %></button>
|
<button id="launch_button">PLAY</button>
|
||||||
<div class="bot_divider"></div>
|
<div class="bot_divider"></div>
|
||||||
<button id="server_selection_button" class="bot_label"><%- lang('landing.launchButtonPlaceholder') %></button>
|
<button id="server_selection_button" class="bot_label">• No Server Selected</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="launch_details">
|
<div id="launch_details">
|
||||||
<div id="launch_details_left">
|
<div id="launch_details_left">
|
||||||
@ -152,14 +128,17 @@
|
|||||||
</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"><%- lang('landing.launchDetails') %></span>
|
<span id="launch_details_text" class="bot_label">Please wait..</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="iframecontainer">
|
||||||
|
<!--<iframe id="dynmapiframe" src="https://minemap.gregbrzezinski.com" frameborder="0"></iframe>-->
|
||||||
|
</div>
|
||||||
|
<!-- <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">
|
||||||
@ -184,7 +163,7 @@
|
|||||||
<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"><%- lang('landing.newsNavigationStatus', { currentPage: 1, totalPages: 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>
|
||||||
@ -198,23 +177,23 @@
|
|||||||
<div id="newsArticleContainer">
|
<div id="newsArticleContainer">
|
||||||
<div id="newsArticleContent">
|
<div id="newsArticleContent">
|
||||||
<div id="newsArticleContentScrollable">
|
<div id="newsArticleContentScrollable">
|
||||||
<!-- 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"><%- lang('landing.newsErrorLoadSpan') %></span>
|
<span id="nELoadSpan" class="newsErrorContent">Checking for News..</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="newsErrorFailed" style="display: none;">
|
<div id="newsErrorFailed" style="display: none;">
|
||||||
<span id="nEFailedSpan" class="newsErrorContent"><%- lang('landing.newsErrorFailedSpan') %></span>
|
<span id="nEFailedSpan" class="newsErrorContent">Failed to Load News</span>
|
||||||
<button id="newsErrorRetry"><%- lang('landing.newsErrorRetryButton') %></button>
|
<button id="newsErrorRetry">Try Again</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="newsErrorNone" style="display: none;">
|
<div id="newsErrorNone" style="display: none;">
|
||||||
<span id="nENoneSpan" class="newsErrorContent"><%- lang('landing.newsErrorNoneSpan') %></span>
|
<span id="nENoneSpan" class="newsErrorContent">No 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>
|
@ -2,21 +2,21 @@
|
|||||||
<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"><%- lang('login.loginCancelText') %></span>
|
<span id="loginCancelText">Cancel</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"><%- lang('login.loginSubheader') %></span>
|
<span id="loginSubheader">MINECRAFT LOGIN</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"><%- lang('login.loginEmailError') %></span>
|
<span class="loginErrorSpan" id="loginEmailError">* Invalid Value</span>
|
||||||
<input id="loginUsername" class="loginField" type="text" placeholder="<%- lang('login.loginEmailPlaceholder') %>"/>
|
<input id="loginUsername" class="loginField" type="text" placeholder="EMAIL OR USERNAME"/>
|
||||||
</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">
|
||||||
@ -24,22 +24,22 @@
|
|||||||
<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"><%- lang('login.loginPasswordError') %></span>
|
<span class="loginErrorSpan" id="loginPasswordError">* Required</span>
|
||||||
<input id="loginPassword" class="loginField" type="password" placeholder="<%- lang('login.loginPasswordPlaceholder') %>"/>
|
<input id="loginPassword" class="loginField" type="password" placeholder="PASSWORD"/>
|
||||||
</div>
|
</div>
|
||||||
<div id="loginOptions">
|
<div id="loginOptions">
|
||||||
<span class="loginSpanDim">
|
<span class="loginSpanDim">
|
||||||
<a href="<%- lang('login.loginForgotPasswordLink') %>"><%- lang('login.loginForgotPasswordText') %></a>
|
<a href="https://minecraft.net/password/forgot/">forgot password?</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"><%- lang('login.loginRememberMeText') %></span>
|
<span id="loginRememberText" class="loginSpanDim">remember me?</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">
|
||||||
<%- lang('login.loginButtonText') %>
|
LOGIN
|
||||||
<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>
|
||||||
@ -54,10 +54,10 @@
|
|||||||
</button>
|
</button>
|
||||||
<div id="loginDisclaimer">
|
<div id="loginDisclaimer">
|
||||||
<span class="loginSpanDim" id="loginRegisterSpan">
|
<span class="loginSpanDim" id="loginRegisterSpan">
|
||||||
<a href="<%- lang('login.loginNeedAccountLink') %>"><%- lang('login.loginNeedAccountText') %></a>
|
<a href="https://minecraft.net/store/minecraft-java-edition/">Need an Account?</a>
|
||||||
</span>
|
</span>
|
||||||
<p class="loginDisclaimerText"><%- lang('login.loginPasswordDisclaimer1') %></p>
|
<p class="loginDisclaimerText">Your password is sent directly to mojang and never stored.</p>
|
||||||
<p class="loginDisclaimerText"><%- lang('login.loginPasswordDisclaimer2', { appName: lang('app.title') }) %></p>
|
<p class="loginDisclaimerText">Helios Launcher is not affiliated with Mojang AB.</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
31
app/loginOffline.ejs
Normal file
31
app/loginOffline.ejs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<div id="loginOfflineContainer" style="display: none;">
|
||||||
|
<div id="loginOfflineCancelContainer" > <!--Delete style="" as temp fix-->
|
||||||
|
<button id="loginOfflineCancelButton">
|
||||||
|
<div id="loginOfflineCancelIcon">X</div>
|
||||||
|
<span id="loginOfflineCancelText">Cancel</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div id="loginContent">
|
||||||
|
<form id="loginForm" style="margin-top: 2.5em;">
|
||||||
|
<span id="loginSubheader">OFFLINE LOGIN</span>
|
||||||
|
<div class="loginFieldContainer">
|
||||||
|
<input id="loginOfflineUsername" class="loginField" type="text" placeholder="USERNAME"/>
|
||||||
|
</div>
|
||||||
|
<button id="loginOfflineButton" class="loginButton" enabled>
|
||||||
|
<div id="loginOfflineButtonContent">
|
||||||
|
LOGIN
|
||||||
|
<svg id="loginSVG" viewBox="0 0 24.87 13.97">
|
||||||
|
<defs>
|
||||||
|
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style>
|
||||||
|
</defs>
|
||||||
|
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
|
||||||
|
</svg>
|
||||||
|
<div class="circle-loader">
|
||||||
|
<div class="checkmark draw"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<script src="./assets/js/scripts/loginOffline.js"></script>
|
||||||
|
</div>
|
@ -1,34 +1,39 @@
|
|||||||
<div id="loginOptionsContainer" style="display: none;">
|
<div id="loginOptionsContainer" style="display: none;">
|
||||||
<div id="loginOptionsContent">
|
<div id="loginOptionsContent">
|
||||||
<div class="loginOptionsMainContent">
|
<div class="loginOptionsMainContent">
|
||||||
<h2><%- lang('loginOptions.loginOptionsTitle') %></h2>
|
<h2>Login Options</h2>
|
||||||
<div class="loginOptionActions">
|
<div class="loginOptionActions">
|
||||||
<div class="loginOptionButtonContainer">
|
<div class="loginOptionButtonContainer">
|
||||||
<button id="loginOptionMicrosoft" class="loginOptionButton">
|
<button id="loginOptionMicrosoft" class="loginOptionButton">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 23 23">
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 23 23">
|
||||||
<path fill="#f35325" d="M1 1h10v10H1z" />
|
<path fill="#f35325" d="M1 1h10v10H1z" />
|
||||||
<path fill="#81bc06" d="M12 1h10v10H12z" />
|
<path fill="#81bc06" d="M12 1h10v10H12z" />
|
||||||
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
||||||
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span><%- lang('loginOptions.loginWithMicrosoft') %></span>
|
<span>Login with Microsoft</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="loginOptionButtonContainer">
|
<div class="loginOptionButtonContainer">
|
||||||
<button id="loginOptionMojang" class="loginOptionButton">
|
<button id="loginOptionMojang" class="loginOptionButton">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 9.677 9.667">
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 9.677 9.667">
|
||||||
<path d="M-26.332-12.098h2.715c-1.357.18-2.574 1.23-2.715 2.633z" fill="#fff" />
|
<path d="M-26.332-12.098h2.715c-1.357.18-2.574 1.23-2.715 2.633z" fill="#fff" />
|
||||||
<path d="M2.598.022h7.07L9.665 7c-.003 1.334-1.113 2.46-2.402 2.654H0V2.542C.134 1.2 1.3.195 2.598.022z" fill="#db2331" />
|
<path d="M2.598.022h7.07L9.665 7c-.003 1.334-1.113 2.46-2.402 2.654H0V2.542C.134 1.2 1.3.195 2.598.022z" fill="#db2331" />
|
||||||
<path d="M1.54 2.844c.314-.76 1.31-.46 1.954-.528.785-.083 1.503.272 2.1.758l.164-.9c.327.345.587.756.964 1.052.28.254.655-.342.86-.013.42.864.408 1.86.54 2.795l-.788-.373C6.9 4.17 5.126 3.052 3.656 3.685c-1.294.592-1.156 2.65.06 3.255 1.354.703 2.953.51 4.405.292-.07.42-.34.87-.834.816l-4.95.002c-.5.055-.886-.413-.838-.89l.04-4.315z" fill="#fff" />
|
<path d="M1.54 2.844c.314-.76 1.31-.46 1.954-.528.785-.083 1.503.272 2.1.758l.164-.9c.327.345.587.756.964 1.052.28.254.655-.342.86-.013.42.864.408 1.86.54 2.795l-.788-.373C6.9 4.17 5.126 3.052 3.656 3.685c-1.294.592-1.156 2.65.06 3.255 1.354.703 2.953.51 4.405.292-.07.42-.34.87-.834.816l-4.95.002c-.5.055-.886-.413-.838-.89l.04-4.315z" fill="#fff" />
|
||||||
</svg>
|
</svg>
|
||||||
<span><%- lang('loginOptions.loginWithMojang') %></span>
|
<span>Login with Mojang</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="loginOptionButtonContainer">
|
||||||
<div id="loginOptionCancelContainer" style="display: none;">
|
<button id="loginOptionOffline" class="loginOptionButton">
|
||||||
<button id="loginOptionCancelButton"><%- lang('loginOptions.cancelButton') %></button>
|
<span>Proceed Offline</span>
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/loginOptions.js"></script>
|
<!--<div id="loginOptionCancelContainer" style="display: none;">
|
||||||
|
<button id="loginOptionCancelButton">Cancel</button>
|
||||||
|
</div>-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="./assets/js/scripts/loginOptions.js"></script>
|
||||||
</div>
|
</div>
|
@ -1,29 +1,29 @@
|
|||||||
<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"><%- lang('overlay.serverSelectHeader') %></span>
|
<span id="serverSelectHeader">Available Servers</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"><%- lang('overlay.serverSelectConfirm') %></button>
|
<button id="serverSelectConfirm" class="overlayKeybindEnter" type="submit">Select</button>
|
||||||
<div id="serverSelectCancelWrapper">
|
<div id="serverSelectCancelWrapper">
|
||||||
<button id="serverSelectCancel" class="overlayKeybindEsc"><%- lang('overlay.serverSelectCancel') %></button>
|
<button id="serverSelectCancel" class="overlayKeybindEsc">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="accountSelectContent" style="display: none;">
|
<div id="accountSelectContent" style="display: none;">
|
||||||
<span id="accountSelectHeader"><%- lang('overlay.accountSelectHeader') %></span>
|
<span id="accountSelectHeader">Select an Account</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"><%- lang('overlay.accountSelectConfirm') %></button>
|
<button id="accountSelectConfirm" class="overlayKeybindEnter" type="submit">Select</button>
|
||||||
<div id="accountSelectCancelWrapper">
|
<div id="accountSelectCancelWrapper">
|
||||||
<button id="accountSelectCancel" class="overlayKeybindEsc"><%- lang('overlay.accountSelectCancel') %></button>
|
<button id="accountSelectCancel" class="overlayKeybindEsc">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
191
app/settings.ejs
191
app/settings.ejs
@ -2,21 +2,21 @@
|
|||||||
<div id="settingsContainerLeft">
|
<div id="settingsContainerLeft">
|
||||||
<div id="settingsNavContainer">
|
<div id="settingsNavContainer">
|
||||||
<div id="settingsNavHeader">
|
<div id="settingsNavHeader">
|
||||||
<span id="settingsNavHeaderText"><%- lang('settings.navHeaderText') %></span>
|
<span id="settingsNavHeaderText">Settings</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsNavItemsContainer">
|
<div id="settingsNavItemsContainer">
|
||||||
<div id="settingsNavItemsContent">
|
<div id="settingsNavItemsContent">
|
||||||
<button class="settingsNavItem" rSc="settingsTabAccount" id="settingsNavAccount" selected><%- lang('settings.navAccount') %></button>
|
<button class="settingsNavItem" rSc="settingsTabAccount" id="settingsNavAccount" selected>Account</button>
|
||||||
<button class="settingsNavItem" rSc="settingsTabMinecraft"><%- lang('settings.navMinecraft') %></button>
|
<button class="settingsNavItem" rSc="settingsTabMinecraft">Minecraft</button>
|
||||||
<button class="settingsNavItem" rSc="settingsTabMods"><%- lang('settings.navMods') %></button>
|
<button class="settingsNavItem" rSc="settingsTabMods">Mods</button>
|
||||||
<button class="settingsNavItem" rSc="settingsTabJava"><%- lang('settings.navJava') %></button>
|
<button class="settingsNavItem" rSc="settingsTabJava">Java</button>
|
||||||
<button class="settingsNavItem" rSc="settingsTabLauncher"><%- lang('settings.navLauncher') %></button>
|
<button class="settingsNavItem" rSc="settingsTabLauncher">Launcher</button>
|
||||||
<div class="settingsNavSpacer"></div>
|
<div class="settingsNavSpacer"></div>
|
||||||
<button class="settingsNavItem" rSc="settingsTabAbout"><%- lang('settings.navAbout') %></button>
|
<button class="settingsNavItem" rSc="settingsTabAbout">About</button>
|
||||||
<button class="settingsNavItem" rSc="settingsTabUpdate" id="settingsNavUpdate"><%- lang('settings.navUpdates') %></button>
|
<button class="settingsNavItem" rSc="settingsTabUpdate" id="settingsNavUpdate">Updates</button>
|
||||||
<div id="settingsNavContentBottom">
|
<div id="settingsNavContentBottom">
|
||||||
<div class="settingsNavDivider"></div>
|
<div class="settingsNavDivider"></div>
|
||||||
<button id="settingsNavDone"><%- lang('settings.navDone') %></button>
|
<button id="settingsNavDone">Done</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -25,8 +25,8 @@
|
|||||||
<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"><%- lang('settings.tabAccountHeaderText') %></span>
|
<span class="settingsTabHeaderText">Account Settings</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.tabAccountHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">Add new accounts or manage existing ones.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsAuthAccountTypeContainer">
|
<div class="settingsAuthAccountTypeContainer">
|
||||||
<div class="settingsAuthAccountTypeHeader">
|
<div class="settingsAuthAccountTypeHeader">
|
||||||
@ -37,10 +37,10 @@
|
|||||||
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
||||||
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
||||||
</svg>
|
</svg>
|
||||||
<span><%- lang('settings.microsoftAccount') %></span>
|
<span>Microsoft</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsAuthAccountTypeHeaderRight">
|
<div class="settingsAuthAccountTypeHeaderRight">
|
||||||
<button class="settingsAddAuthAccount" id="settingsAddMicrosoftAccount"><%- lang('settings.addMicrosoftAccount') %></button>
|
<button class="settingsAddAuthAccount" id="settingsAddMicrosoftAccount">+ Add Microsoft Account</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -57,10 +57,10 @@
|
|||||||
<path d="M2.598.022h7.07L9.665 7c-.003 1.334-1.113 2.46-2.402 2.654H0V2.542C.134 1.2 1.3.195 2.598.022z" fill="#db2331" />
|
<path d="M2.598.022h7.07L9.665 7c-.003 1.334-1.113 2.46-2.402 2.654H0V2.542C.134 1.2 1.3.195 2.598.022z" fill="#db2331" />
|
||||||
<path d="M1.54 2.844c.314-.76 1.31-.46 1.954-.528.785-.083 1.503.272 2.1.758l.164-.9c.327.345.587.756.964 1.052.28.254.655-.342.86-.013.42.864.408 1.86.54 2.795l-.788-.373C6.9 4.17 5.126 3.052 3.656 3.685c-1.294.592-1.156 2.65.06 3.255 1.354.703 2.953.51 4.405.292-.07.42-.34.87-.834.816l-4.95.002c-.5.055-.886-.413-.838-.89l.04-4.315z" fill="#fff" />
|
<path d="M1.54 2.844c.314-.76 1.31-.46 1.954-.528.785-.083 1.503.272 2.1.758l.164-.9c.327.345.587.756.964 1.052.28.254.655-.342.86-.013.42.864.408 1.86.54 2.795l-.788-.373C6.9 4.17 5.126 3.052 3.656 3.685c-1.294.592-1.156 2.65.06 3.255 1.354.703 2.953.51 4.405.292-.07.42-.34.87-.834.816l-4.95.002c-.5.055-.886-.413-.838-.89l.04-4.315z" fill="#fff" />
|
||||||
</svg>
|
</svg>
|
||||||
<span><%- lang('settings.mojangAccount') %></span>
|
<span>Mojang</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsAuthAccountTypeHeaderRight">
|
<div class="settingsAuthAccountTypeHeaderRight">
|
||||||
<button class="settingsAddAuthAccount" id="settingsAddMojangAccount"><%- lang('settings.addMojangAccount') %></button>
|
<button class="settingsAddAuthAccount" id="settingsAddMojangAccount">+ Add Mojang Account</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -68,14 +68,29 @@
|
|||||||
<!-- Mojang auth accounts populated here. -->
|
<!-- Mojang auth accounts populated here. -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="settingsAuthAccountTypeContainer">
|
||||||
|
<div class="settingsAuthAccountTypeHeader">
|
||||||
|
<div class="settingsAuthAccountTypeHeaderLeft">
|
||||||
|
<svg width="22px" height="22px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Home"><path d="M62,21v39c0,1.1-0.9,2-2,2H4c-1.1,0-2-0.9-2-2V21c0-0.7,0.4-1.4,1-1.7l28-17c0.6-0.4,1.4-0.4,2.1,0l28,17 C61.6,19.6,62,20.3,62,21z" fill="#3F51B5"/><g><path d="M44,42v18c0,1.1-0.9,2-2,2H22c-1.1,0-2-0.9-2-2V42c0-6.6,5.4-12,12-12S44,35.4,44,42z" fill="#FFC10A"/></g></g><g id="Camera"/><g id="Mail"/><g id="Print"/><g id="Save"/><g id="Folder"/><g id="Search"/><g id="User"/><g id="Pin"/><g id="Calendar"/><g id="Gallery"/><g id="time"/><g id="Pin_1_"/><g id="Setting"/><g id="Player"/><g id="Lock"/><g id="Trash_Can"/><g id="Notification"/><g id="Record"/><g id="Shopping_Bag"/></svg>
|
||||||
|
<span>Offline</span>
|
||||||
|
</div>
|
||||||
|
<div class="settingsAuthAccountTypeHeaderRight">
|
||||||
|
<button class="settingsAddAuthAccount" id="settingsAddOfflineAccount">+ Add Offline Account</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="settingsCurrentAccounts" id="settingsCurrentOfflineAccounts">
|
||||||
|
<!-- Offline 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"><%- lang('settings.minecraftTabHeaderText') %></span>
|
<span class="settingsTabHeaderText">Minecraft Settings</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.minecraftTabHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">Options related to game launch.</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsGameResolutionContainer">
|
<div id="settingsGameResolutionContainer">
|
||||||
<span class="settingsFieldTitle"><%- lang('settings.gameResolutionTitle') %></span>
|
<span class="settingsFieldTitle">Game Resolution</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">✖</div>
|
<div id="settingsGameResolutionCross">✖</div>
|
||||||
@ -84,7 +99,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldContainer">
|
<div class="settingsFieldContainer">
|
||||||
<div class="settingsFieldLeft">
|
<div class="settingsFieldLeft">
|
||||||
<span class="settingsFieldTitle"><%- lang('settings.launchFullscreenTitle') %></span>
|
<span class="settingsFieldTitle">Launch in fullscreen.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldRight">
|
<div class="settingsFieldRight">
|
||||||
<label class="toggleSwitch">
|
<label class="toggleSwitch">
|
||||||
@ -95,7 +110,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldContainer">
|
<div class="settingsFieldContainer">
|
||||||
<div class="settingsFieldLeft">
|
<div class="settingsFieldLeft">
|
||||||
<span class="settingsFieldTitle"><%- lang('settings.autoConnectTitle') %></span>
|
<span class="settingsFieldTitle">Automatically connect to the server on launch.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldRight">
|
<div class="settingsFieldRight">
|
||||||
<label class="toggleSwitch">
|
<label class="toggleSwitch">
|
||||||
@ -106,8 +121,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldContainer">
|
<div class="settingsFieldContainer">
|
||||||
<div class="settingsFieldLeft">
|
<div class="settingsFieldLeft">
|
||||||
<span class="settingsFieldTitle"><%- lang('settings.launchDetachedTitle') %></span>
|
<span class="settingsFieldTitle">Launch game process detached from launcher.</span>
|
||||||
<span class="settingsFieldDesc"><%- lang('settings.launchDetachedDesc') %></span>
|
<span class="settingsFieldDesc">If the game is not detached, closing the launcher will also close the game.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldRight">
|
<div class="settingsFieldRight">
|
||||||
<label class="toggleSwitch">
|
<label class="toggleSwitch">
|
||||||
@ -119,46 +134,46 @@
|
|||||||
</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"><%- lang('settings.tabModsHeaderText') %></span>
|
<span class="settingsTabHeaderText">Mod Settings</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.tabModsHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">Enable or disable mods.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsSelServContainer">
|
<div id="settingsSelServContainer">
|
||||||
<div class="settingsSelServContent">
|
<div id="settingsSelServContent">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsSwitchServerContainer">
|
<div id="settingsSwitchServerContainer">
|
||||||
<div class="settingsSwitchServerContent">
|
<div id="settingsSwitchServerContent">
|
||||||
<button class="settingsSwitchServerButton"><%- lang('settings.switchServerButton') %></button>
|
<button id="settingsSwitchServerButton">Switch</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsModsContainer">
|
<div id="settingsModsContainer">
|
||||||
<div id="settingsReqModsContainer">
|
<div id="settingsReqModsContainer">
|
||||||
<div class="settingsModsHeader"><%- lang('settings.requiredMods') %></div>
|
<div class="settingsModsHeader">Required Mods</div>
|
||||||
<div id="settingsReqModsContent">
|
<div id="settingsReqModsContent">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsOptModsContainer">
|
<div id="settingsOptModsContainer">
|
||||||
<div class="settingsModsHeader"><%- lang('settings.optionalMods') %></div>
|
<div class="settingsModsHeader">Optional Mods</div>
|
||||||
<div id="settingsOptModsContent">
|
<div id="settingsOptModsContent">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsDropinModsContainer">
|
<div id="settingsDropinModsContainer">
|
||||||
<div class="settingsModsHeader"><%- lang('settings.dropinMods') %></div>
|
<div class="settingsModsHeader">Drop-in Mods</div>
|
||||||
<button id="settingsDropinFileSystemButton"><%- lang('settings.addMods') %> <span id="settingsDropinRefreshNote"><%- lang('settings.dropinRefreshNote') %></span></button>
|
<button id="settingsDropinFileSystemButton">+ Add Mods <span id="settingsDropinRefreshNote">(F5 to Refresh)</span></button>
|
||||||
<div id="settingsDropinModsContent">
|
<div id="settingsDropinModsContent">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsShadersContainer">
|
<div id="settingsShadersContainer">
|
||||||
<div class="settingsModsHeader"><%- lang('settings.shaderpacks') %></div>
|
<div class="settingsModsHeader">Shaderpacks</div>
|
||||||
<div id="settingsShaderpackDesc"><%- lang('settings.shaderpackDesc') %></div>
|
<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 id="settingsShaderpackWrapper">
|
||||||
<button id="settingsShaderpackButton"> + </button>
|
<button id="settingsShaderpackButton"> + </button>
|
||||||
<div class="settingsSelectContainer">
|
<div class="settingsSelectContainer">
|
||||||
<div class="settingsSelectSelected" id="settingsShadersSelected"><%- lang('settings.selectShaderpack') %></div>
|
<div class="settingsSelectSelected" id="settingsShadersSelected">Select Shaderpack</div>
|
||||||
<div class="settingsSelectOptions" id="settingsShadersOptions" hidden>
|
<div class="settingsSelectOptions" id="settingsShadersOptions" hidden>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@ -169,27 +184,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="settingsTabJava" class="settingsTab" style="display: none;">
|
<div id="settingsTabJava" class="settingsTab" style="display: none;">
|
||||||
<div class="settingsTabHeader">
|
<div class="settingsTabHeader">
|
||||||
<span class="settingsTabHeaderText"><%- lang('settings.tabJavaHeaderText') %></span>
|
<span class="settingsTabHeaderText">Java Settings</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.tabJavaHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">Manage the Java configuration (advanced).</span>
|
||||||
</div>
|
|
||||||
<div class="settingsSelServContainer">
|
|
||||||
<div class="settingsSelServContent">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="settingsSwitchServerContainer">
|
|
||||||
<div class="settingsSwitchServerContent">
|
|
||||||
<button class="settingsSwitchServerButton"><%- lang('settings.switchServerButton') %></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsMemoryContainer">
|
<div id="settingsMemoryContainer">
|
||||||
<div id="settingsMemoryTitle"><%- lang('settings.memoryTitle') %></div>
|
<div id="settingsMemoryTitle">Memory</div>
|
||||||
<div id="settingsMemoryContent">
|
<div id="settingsMemoryContent">
|
||||||
<div id="settingsMemoryContentLeft">
|
<div id="settingsMemoryContentLeft">
|
||||||
<div class="settingsMemoryContentItem">
|
<div class="settingsMemoryContentItem">
|
||||||
<span class="settingsMemoryHeader"><%- lang('settings.maxRAM') %></span>
|
<span class="settingsMemoryHeader">Maximum RAM</span>
|
||||||
<div class="settingsMemoryActionContainer">
|
<div class="settingsMemoryActionContainer">
|
||||||
<div id="settingsMaxRAMRange" class="rangeSlider" cValue="MaxRAM" serverDependent min="3" max="8" value="3" step="0.5">
|
<div id="settingsMaxRAMRange" class="rangeSlider" cValue="MaxRAM" min="3" max="8" value="3" step="0.5">
|
||||||
<div class="rangeSliderBar"></div>
|
<div class="rangeSliderBar"></div>
|
||||||
<div class="rangeSliderTrack"></div>
|
<div class="rangeSliderTrack"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -197,25 +202,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsMemoryContentItem">
|
<div class="settingsMemoryContentItem">
|
||||||
<span class="settingsMemoryHeader"><%- lang('settings.minRAM') %></span>
|
<span class="settingsMemoryHeader">Minimum RAM</span>
|
||||||
<div class="settingsMemoryActionContainer">
|
<div class="settingsMemoryActionContainer">
|
||||||
<div id="settingsMinRAMRange" class="rangeSlider" cValue="MinRAM" serverDependent min="3" max="8" value="3" step="0.5">
|
<div id="settingsMinRAMRange" class="rangeSlider" cValue="MinRAM" min="3" max="8" value="3" step="0.5">
|
||||||
<div class="rangeSliderBar"></div>
|
<div class="rangeSliderBar"></div>
|
||||||
<div class="rangeSliderTrack"></div>
|
<div class="rangeSliderTrack"></div>
|
||||||
</div>
|
</div>
|
||||||
<span id="settingsMinRAMLabel" class="settingsMemoryLabel">3G</span>
|
<span id="settingsMinRAMLabel" class="settingsMemoryLabel">3G</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsMemoryDesc"><%- lang('settings.memoryDesc') %></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>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsMemoryContentRight">
|
<div id="settingsMemoryContentRight">
|
||||||
<div id="settingsMemoryStatus">
|
<div id="settingsMemoryStatus">
|
||||||
<div class="settingsMemoryStatusContainer">
|
<div class="settingsMemoryStatusContainer">
|
||||||
<span class="settingsMemoryStatusTitle"><%- lang('settings.memoryTotalTitle') %></span>
|
<span class="settingsMemoryStatusTitle">Total</span>
|
||||||
<span id="settingsMemoryTotal" class="settingsMemoryStatusValue">16G</span>
|
<span id="settingsMemoryTotal" class="settingsMemoryStatusValue">16G</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsMemoryStatusContainer">
|
<div class="settingsMemoryStatusContainer">
|
||||||
<span class="settingsMemoryStatusTitle"><%- lang('settings.memoryAvailableTitle') %></span>
|
<span class="settingsMemoryStatusTitle">Available</span>
|
||||||
<span id="settingsMemoryAvail" class="settingsMemoryStatusValue">7.3G</span>
|
<span id="settingsMemoryAvail" class="settingsMemoryStatusValue">7.3G</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -223,9 +228,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFileSelContainer">
|
<div class="settingsFileSelContainer">
|
||||||
<div class="settingsFileSelTitle"><%- lang('settings.javaExecutableTitle') %></div>
|
<div class="settingsFileSelTitle">Java Executable</div>
|
||||||
<div class="settingsFileSelContent">
|
<div class="settingsFileSelContent">
|
||||||
<div id="settingsJavaExecDetails"><!-- Invalid Selection --></div>
|
<div id="settingsJavaExecDetails">Selected: Java 8 Update 172 (x64)</div>
|
||||||
<div class="settingsFileSelActions">
|
<div class="settingsFileSelActions">
|
||||||
<div class="settingsFileSelIcon">
|
<div class="settingsFileSelIcon">
|
||||||
<svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001">
|
<svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001">
|
||||||
@ -241,14 +246,14 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<input class="settingsFileSelVal" id="settingsJavaExecVal" type="text" value="null" cValue="JavaExecutable" serverDependent disabled>
|
<input class="settingsFileSelVal" id="settingsJavaExecVal" type="text" value="null" cValue="JavaExecutable" disabled>
|
||||||
<button class="settingsFileSelButton" id="settingsJavaExecSel" dialogTitle="<%- lang('settings.javaExecSelDialogTitle') %>" dialogDirectory="false"><%- lang('settings.javaExecSelButtonText') %></button>
|
<button class="settingsFileSelButton" id="settingsJavaExecSel" dialogTitle="Select Java Executable" dialogDirectory="false">Choose File</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFileSelDesc"><%- lang('settings.javaExecDesc') %> <strong id="settingsJavaReqDesc"><!-- Requires Java 8 x64. --></strong><br><%- lang('settings.javaPathDesc', {'pathSuffix': `bin${process.platform === 'win32' ? '\\javaw.exe' : '/java'}`}) %></div>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsJVMOptsContainer">
|
<div id="settingsJVMOptsContainer">
|
||||||
<div id="settingsJVMOptsTitle"><%- lang('settings.jvmOptsTitle') %></div>
|
<div id="settingsJVMOptsTitle">Additional JVM Options</div>
|
||||||
<div id="settingsJVMOptsContent">
|
<div id="settingsJVMOptsContent">
|
||||||
<div class="settingsFileSelIcon">
|
<div class="settingsFileSelIcon">
|
||||||
<svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001">
|
<svg class="settingsFileSelSVG" x="0px" y="0px" viewBox="0 0 305.001 305.001">
|
||||||
@ -264,20 +269,20 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<input id="settingsJVMOptsVal" cValue="JVMOptions" serverDependent type="text">
|
<input id="settingsJVMOptsVal" cValue="JVMOptions" type="text">
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsJVMOptsDesc"><%- lang('settings.jvmOptsDesc') %><br><a href="#" id="settingsJvmOptsLink"><!-- Available Options --></a></div>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsTabLauncher" class="settingsTab" style="display: none;">
|
<div id="settingsTabLauncher" class="settingsTab" style="display: none;">
|
||||||
<div class="settingsTabHeader">
|
<div class="settingsTabHeader">
|
||||||
<span class="settingsTabHeaderText"><%- lang('settings.launcherTabHeaderText') %></span>
|
<span class="settingsTabHeaderText">Launcher Settings</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.launcherTabHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">Options related to the launcher itself.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFieldContainer">
|
<div class="settingsFieldContainer">
|
||||||
<div class="settingsFieldLeft">
|
<div class="settingsFieldLeft">
|
||||||
<span class="settingsFieldTitle"><%- lang('settings.allowPrereleaseTitle') %></span>
|
<span class="settingsFieldTitle">Allow Pre-Release Updates.</span>
|
||||||
<span class="settingsFieldDesc"><%- lang('settings.allowPrereleaseDesc') %></span>
|
<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>
|
</div>
|
||||||
<div class="settingsFieldRight">
|
<div class="settingsFieldRight">
|
||||||
<label class="toggleSwitch">
|
<label class="toggleSwitch">
|
||||||
@ -288,7 +293,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="settingsFileSelContainer">
|
<div class="settingsFileSelContainer">
|
||||||
<div class="settingsFileSelContent">
|
<div class="settingsFileSelContent">
|
||||||
<div class="settingsFieldTitle" id="settingsDataDirTitle"><%- lang('settings.dataDirectoryTitle') %></div>
|
<div class="settingsFieldTitle" id="settingsDataDirTitle">Data Directory</div>
|
||||||
<div class="settingsFileSelActions">
|
<div class="settingsFileSelActions">
|
||||||
<div class="settingsFileSelIcon">
|
<div class="settingsFileSelIcon">
|
||||||
<svg class="settingsFileSelSVG">
|
<svg class="settingsFileSelSVG">
|
||||||
@ -300,90 +305,90 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<input class="settingsFileSelVal" type="text" value="null" cValue="DataDirectory" disabled>
|
<input class="settingsFileSelVal" type="text" value="null" cValue="DataDirectory" disabled>
|
||||||
<button class="settingsFileSelButton" dialogTitle="<%- lang('settings.selectDataDirectory') %>" dialogDirectory="true"><%- lang('settings.chooseFolder') %></button>
|
<button class="settingsFileSelButton" dialogTitle="Select Data Directory" dialogDirectory="true">Choose Folder</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsFileSelDesc"><%- lang('settings.dataDirectoryDesc') %></div>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsTabAbout" class="settingsTab" style="display: none;">
|
<div id="settingsTabAbout" class="settingsTab" style="display: none;">
|
||||||
<div class="settingsTabHeader">
|
<div class="settingsTabHeader">
|
||||||
<span class="settingsTabHeaderText"><%- lang('settings.aboutTabHeaderText') %></span>
|
<span class="settingsTabHeaderText">About</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.aboutTabHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">View information and release notes for the current version.</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsAboutCurrentContainer">
|
<div id="settingsAboutCurrentContainer">
|
||||||
<div id="settingsAboutCurrentContent">
|
<div id="settingsAboutCurrentContent">
|
||||||
<div id="settingsAboutCurrentHeadline">
|
<div id="settingsAboutCurrentHeadline">
|
||||||
<img id="settingsAboutLogo" src="./assets/images/SealCircle.png">
|
<img id="settingsAboutLogo" src="./assets/images/SealCircle.png">
|
||||||
<span id="settingsAboutTitle"><%- lang('settings.aboutTitle', { appName: lang('app.title') }) %></span>
|
<span id="settingsAboutTitle">Helios Launcher</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsAboutCurrentVersion">
|
<div id="settingsAboutCurrentVersion">
|
||||||
<div id="settingsAboutCurrentVersionCheck">✓</div>
|
<div id="settingsAboutCurrentVersionCheck">✓</div>
|
||||||
<div id="settingsAboutCurrentVersionDetails">
|
<div id="settingsAboutCurrentVersionDetails">
|
||||||
<span id="settingsAboutCurrentVersionTitle"><%- lang('settings.stableRelease') %></span>
|
<span id="settingsAboutCurrentVersionTitle">Stable Release</span>
|
||||||
<div id="settingsAboutCurrentVersionLine">
|
<div id="settingsAboutCurrentVersionLine">
|
||||||
<span id="settingsAboutCurrentVersionText"><%- lang('settings.versionText') %></span>
|
<span id="settingsAboutCurrentVersionText">Version </span>
|
||||||
<span id="settingsAboutCurrentVersionValue">0.0.1-alpha.18</span>
|
<span id="settingsAboutCurrentVersionValue">0.0.1-alpha.12</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsAboutButtons">
|
<div id="settingsAboutButtons">
|
||||||
<a href="<%- lang('settings.sourceGithubLink') %>" id="settingsAboutSourceButton" class="settingsAboutButton"><%- lang('settings.sourceGithub') %></a>
|
<a href="https://github.com/dscalZi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Source (GitHub)</a>
|
||||||
<!-- The following must be included in third-party usage. -->
|
<!-- The following must be included in third-party usage. -->
|
||||||
<!-- <a href="https://github.com/dscalzi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Original Source</a> -->
|
<!-- <a href="https://github.com/dscalzi/HeliosLauncher" id="settingsAboutSourceButton" class="settingsAboutButton">Original Source</a> -->
|
||||||
<a href="<%- lang('settings.supportLink') %>" id="settingsAboutSupportButton" class="settingsAboutButton"><%- lang('settings.support') %></a>
|
<a href="https://github.com/dscalZi/HeliosLauncher/issues" id="settingsAboutSupportButton" class="settingsAboutButton">Support</a>
|
||||||
<a href="#" id="settingsAboutDevToolsButton" class="settingsAboutButton"><%- lang('settings.devToolsConsole') %></a>
|
<a href="#" id="settingsAboutDevToolsButton" class="settingsAboutButton">DevTools Console</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsChangelogContainer">
|
<div class="settingsChangelogContainer">
|
||||||
<div class="settingsChangelogContent">
|
<div class="settingsChangelogContent">
|
||||||
<div class="settingsChangelogHeadline">
|
<div class="settingsChangelogHeadline">
|
||||||
<div class="settingsChangelogLabel"><%- lang('settings.releaseNotes') %></div>
|
<div class="settingsChangelogLabel">Release Notes</div>
|
||||||
<div class="settingsChangelogTitle"><%- lang('settings.changelog') %></div>
|
<div class="settingsChangelogTitle">Changelog</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsChangelogText">
|
<div class="settingsChangelogText">
|
||||||
<%- lang('settings.noReleaseNotes') %>
|
No Release Notes
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsChangelogActions">
|
<div class="settingsChangelogActions">
|
||||||
<a class="settingsChangelogButton settingsAboutButton" href="#"><%- lang('settings.viewReleaseNotes') %></a>
|
<a class="settingsChangelogButton settingsAboutButton" href="#">View Release Notes on GitHub</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsTabUpdate" class="settingsTab" style="display: none;">
|
<div id="settingsTabUpdate" class="settingsTab" style="display: none;">
|
||||||
<div class="settingsTabHeader">
|
<div class="settingsTabHeader">
|
||||||
<span class="settingsTabHeaderText"><%- lang('settings.launcherUpdatesHeaderText') %></span>
|
<span class="settingsTabHeaderText">Launcher Updates</span>
|
||||||
<span class="settingsTabHeaderDesc"><%- lang('settings.launcherUpdatesHeaderDesc') %></span>
|
<span class="settingsTabHeaderDesc">Download, install, and review updates for the launcher.</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsUpdateStatusContainer">
|
<div id="settingsUpdateStatusContainer">
|
||||||
<div id="settingsUpdateStatusContent">
|
<div id="settingsUpdateStatusContent">
|
||||||
<div id="settingsUpdateStatusHeadline">
|
<div id="settingsUpdateStatusHeadline">
|
||||||
<span id="settingsUpdateTitle"><!-- You Are Running the Latest Version --></span>
|
<span id="settingsUpdateTitle">You Are Running the Latest Version</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsUpdateVersion">
|
<div id="settingsUpdateVersion">
|
||||||
<div id="settingsUpdateVersionCheck">✓</div>
|
<div id="settingsUpdateVersionCheck">✓</div>
|
||||||
<div id="settingsUpdateVersionDetails">
|
<div id="settingsUpdateVersionDetails">
|
||||||
<span id="settingsUpdateVersionTitle"><%- lang('settings.stableRelease') %></span>
|
<span id="settingsUpdateVersionTitle">Stable Release</span>
|
||||||
<div id="settingsUpdateVersionLine">
|
<div id="settingsUpdateVersionLine">
|
||||||
<span id="settingsUpdateVersionText"><%- lang('settings.versionText') %> </span>
|
<span id="settingsUpdateVersionText">Version </span>
|
||||||
<span id="settingsUpdateVersionValue">0.0.1-alpha.18</span>
|
<span id="settingsUpdateVersionValue">0.0.1-alpha.18</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="settingsUpdateActionContainer">
|
<div id="settingsUpdateActionContainer">
|
||||||
<button id="settingsUpdateActionButton"><%- lang('settings.checkForUpdates') %></button>
|
<button id="settingsUpdateActionButton">Check for Updates</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsChangelogContainer">
|
<div class="settingsChangelogContainer">
|
||||||
<div class="settingsChangelogContent">
|
<div class="settingsChangelogContent">
|
||||||
<div class="settingsChangelogHeadline">
|
<div class="settingsChangelogHeadline">
|
||||||
<div class="settingsChangelogLabel"><%- lang('settings.whatsNew') %></div>
|
<div class="settingsChangelogLabel">What's New</div>
|
||||||
<div class="settingsChangelogTitle"><%- lang('settings.updateReleaseNotes') %></div>
|
<div class="settingsChangelogTitle">Update Release Notes</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsChangelogText">
|
<div class="settingsChangelogText">
|
||||||
<%- lang('settings.noReleaseNotes') %>
|
No Release Notes
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div id="waitingContent">
|
<div id="waitingContent">
|
||||||
<div class="waitingSpinner"></div>
|
<div class="waitingSpinner"></div>
|
||||||
<div id="waitingTextContainer">
|
<div id="waitingTextContainer">
|
||||||
<h2><%- lang('waiting.waitingText') %></h2>
|
<h2>Waiting for Microsoft..</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -5,13 +5,13 @@
|
|||||||
</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"><%- lang('welcome.welcomeHeader') %></span>
|
<span id="welcomeHeader">WELCOME TO WESTEROSCRAFT</span>
|
||||||
<span id="welcomeDescription"><%- lang('welcome.welcomeDescription') %></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 aren’t 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"><%- lang('welcome.welcomeDescCTA') %></span>
|
<span id="welcomeDescCTA">You are just a few clicks away from Westeros.</span>
|
||||||
<button id="welcomeButton">
|
<button id="welcomeButton">
|
||||||
<div id="welcomeButtonContent">
|
<div id="welcomeButtonContent">
|
||||||
<%- lang('welcome.continueButton') %>
|
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>
|
||||||
|
@ -18,35 +18,18 @@ Authenticating with Microsoft is fully supported by Helios Launcher.
|
|||||||
- Select **Mobile and desktop applications**.
|
- Select **Mobile and desktop applications**.
|
||||||
- Choose `https://login.microsoftonline.com/common/oauth2/nativeclient` as the **Redirect URI**.
|
- Choose `https://login.microsoftonline.com/common/oauth2/nativeclient` as the **Redirect URI**.
|
||||||
- Select **Configure** to finish adding the platform.
|
- Select **Configure** to finish adding the platform.
|
||||||
8. Go to **Credentials & secrets**.
|
|
||||||
- Select **Client secrets**.
|
|
||||||
- Click **New client secret**.
|
|
||||||
- Set a description.
|
|
||||||
- Click **Add**.
|
|
||||||
- Don't copy the client secret, adding one is just a requirement from Microsoft.
|
|
||||||
8. Navigate back to **Overview**.
|
8. Navigate back to **Overview**.
|
||||||
9. Copy **Application (client) ID**.
|
9. Copy **Application (client) ID**.
|
||||||
|
|
||||||
|
|
||||||
|
Reference: https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
|
||||||
|
|
||||||
## Adding the Azure Client ID to Helios Launcher.
|
## Adding the Azure Client ID to Helios Launcher.
|
||||||
|
|
||||||
In `app/assets/js/ipcconstants.js` you'll find **`AZURE_CLIENT_ID`**. Set it to your application's id.
|
In `app/assets/js/ipcconstants.js` you'll find **`AZURE_CLIENT_ID`**. Set it to your application's id.
|
||||||
|
|
||||||
Note: Azure Client ID is NOT a secret value and **can** be stored in git. Reference: https://stackoverflow.com/questions/57306964/are-azure-active-directorys-tenantid-and-clientid-considered-secrets
|
Note: Azure Client ID is NOT a secret value and **can** be stored in git. Reference: https://stackoverflow.com/questions/57306964/are-azure-active-directorys-tenantid-and-clientid-considered-secrets
|
||||||
|
|
||||||
Then relaunch your app, and login. You'll be greeted with an error message, because the app isn't whitelisted yet. Microsoft needs some activity on the app before whitelisting it. __Trying to log in before requesting whitelist is mandatory.__
|
|
||||||
|
|
||||||
## Requesting whitelisting from Microsoft
|
|
||||||
|
|
||||||
1. Ensure you have completed every step of this doc page.
|
|
||||||
2. Fill [this form](https://aka.ms/mce-reviewappid) with the required information. Remember this is a new appID for approval. You can find both the Client ID and the Tenant ID on the overview page in the Azure Portal.
|
|
||||||
3. Give Microsoft some time to review your app.
|
|
||||||
4. Once you have received Microsoft's approval, allow up to 24 hours for the changes to apply.
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
You can now authenticate with Microsoft through the launcher.
|
You can now authenticate with Microsoft through the launcher.
|
||||||
|
|
||||||
References:
|
|
||||||
- https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app
|
|
||||||
- https://help.minecraft.net/hc/en-us/articles/16254801392141
|
|
156
docs/distro.md
156
docs/distro.md
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
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 most up to date and accurate descriptions of the distribution spec can be viewed in [helios-distribution-types](https://github.com/dscalzi/helios-distribution-types).
|
|
||||||
|
|
||||||
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
|
||||||
@ -145,122 +143,12 @@ Only one server in the array should have the `mainServer` property enabled. This
|
|||||||
|
|
||||||
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.javaOptions: JavaOptions`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
Sever-specific Java options. If not provided, defaults are used by the client.
|
|
||||||
|
|
||||||
### `Server.modules: Module[]`
|
### `Server.modules: Module[]`
|
||||||
|
|
||||||
An array of module objects.
|
An array of module objects.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## JavaOptions Object
|
|
||||||
|
|
||||||
Server-specific Java options.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
```JSON
|
|
||||||
{
|
|
||||||
"supported": ">=17",
|
|
||||||
"suggestedMajor": 17,
|
|
||||||
"platformOptions": [
|
|
||||||
{
|
|
||||||
"platform": "darwin",
|
|
||||||
"architecture": "arm64",
|
|
||||||
"distribution": "CORRETTO"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"ram": {
|
|
||||||
"recommended": 3072,
|
|
||||||
"minimum": 2048
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `JavaOptions.platformOptions: JavaPlatformOptions[]`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
Platform-specific java rules for this server configuration. Validation rules will be delegated to the client for any undefined properties. Java validation can be configured for specific platforms and architectures. The most specific ruleset will be applied.
|
|
||||||
|
|
||||||
Maxtrix Precedence (Highest - Lowest)
|
|
||||||
- Current platform, current architecture (ex. win32 x64).
|
|
||||||
- Current platform, any architecture (ex. win32).
|
|
||||||
- Java Options base properties.
|
|
||||||
- Client logic (default logic in the client).
|
|
||||||
|
|
||||||
Properties:
|
|
||||||
|
|
||||||
- `platformOptions.platform: string` - The platform that this validation matrix applies to.
|
|
||||||
- `platformOptions.architecture: string` - Optional. The architecture that this validation matrix applies to. If omitted, applies to all architectures.
|
|
||||||
- `platformOptions.distribution: string` - Optional. See `JavaOptions.distribution`.
|
|
||||||
- `platformOptions.supported: string` - Optional. See `JavaOptions.supported`.
|
|
||||||
- `platformOptions.suggestedMajor: number` - Optional. See `JavaOptions.suggestedMajor`.
|
|
||||||
|
|
||||||
### `JavaOptions.ram: object`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
This allows you to require a minimum and recommended amount of RAM per server instance. The minimum is the smallest value the user can select in the settings slider. The recommended value will be the default value selected for that server. These values are specified in megabytes and must be an interval of 512. This allows configuration in intervals of half gigabytes. In the above example, the recommended ram value is 3 GB (3072 MB) and the minimum is 2 GB (2048 MB).
|
|
||||||
|
|
||||||
- `ram.recommended: number` - The recommended amount of RAM in megabytes. Must be an interval of 512.
|
|
||||||
- `ram.minimum: number` - The absolute minimum amount of RAM in megabytes. Must be an interval of 512.
|
|
||||||
|
|
||||||
### `JavaOptions.distribution: string`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
Preferred JDK distribution to download if no applicable installation could be found. If omitted, the client will decide (decision may be platform-specific).
|
|
||||||
|
|
||||||
### `JavaOptions.supported: string`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
A semver range of supported JDK versions.
|
|
||||||
|
|
||||||
Java version syntax is platform dependent.
|
|
||||||
|
|
||||||
JDK 8 and prior
|
|
||||||
```
|
|
||||||
1.{major}.{minor}_{patch}-b{build}
|
|
||||||
Ex. 1.8.0_152-b16
|
|
||||||
```
|
|
||||||
|
|
||||||
JDK 9+
|
|
||||||
```
|
|
||||||
{major}.{minor}.{patch}+{build}
|
|
||||||
Ex. 11.0.12+7
|
|
||||||
```
|
|
||||||
|
|
||||||
For processing, all versions will be translated into a semver compliant string. JDK 9+ is already semver. For versions 8 and below, `1.{major}.{minor}_{patch}-b{build}` will be translated to `{major}.{minor}.{patch}+{build}`.
|
|
||||||
|
|
||||||
If specified, you must also specify suggestedMajor.
|
|
||||||
|
|
||||||
If omitted, the client will decide based on the game version.
|
|
||||||
|
|
||||||
### `JavaOptions.suggestedMajor: number`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
The suggested major Java version. The suggested major should comply with the version range specified by supported, if defined. This will be used in messages displayed to the end user, and to automatically fetch a Java version.
|
|
||||||
|
|
||||||
NOTE If supported is specified, suggestedMajor must be set. The launcher's default value may not comply with your custom major supported range.
|
|
||||||
|
|
||||||
Common use case:
|
|
||||||
- supported: '>=17.x'
|
|
||||||
- suggestedMajor: 17
|
|
||||||
|
|
||||||
More involved:
|
|
||||||
- supported: '>=16 <20'
|
|
||||||
- suggestedMajor: 17
|
|
||||||
|
|
||||||
Given a wider support range, it becomes necessary to specify which major version in the range is the suggested.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 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.
|
||||||
@ -320,12 +208,6 @@ The name of the module. Used on the UI.
|
|||||||
|
|
||||||
The type of the module.
|
The type of the module.
|
||||||
|
|
||||||
### `Module.classpath: boolean`
|
|
||||||
|
|
||||||
**OPTIONAL**
|
|
||||||
|
|
||||||
If the module is of type `Library`, whether the library should be added to the classpath. Defaults to true.
|
|
||||||
|
|
||||||
### `Module.required: Required`
|
### `Module.required: Required`
|
||||||
|
|
||||||
**OPTIONAL**
|
**OPTIONAL**
|
||||||
@ -360,12 +242,10 @@ The resolved/provided paths are appended to a base path depending on the module'
|
|||||||
| Type | Path |
|
| Type | Path |
|
||||||
| ---- | ---- |
|
| ---- | ---- |
|
||||||
| `ForgeHosted` | ({`commonDirectory`}/libraries/{`path` OR resolved}) |
|
| `ForgeHosted` | ({`commonDirectory`}/libraries/{`path` OR resolved}) |
|
||||||
| `Fabric` | ({`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}) |
|
||||||
| `FabricMod` | ({`commonDirectory`}/mods/fabric/{`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.
|
||||||
@ -410,7 +290,7 @@ If the module is enabled by default. Has no effect unless `Required.value` is fa
|
|||||||
|
|
||||||
### ForgeHosted
|
### ForgeHosted
|
||||||
|
|
||||||
The module type `ForgeHosted` represents forge itself. Currently, the launcher only supports modded 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.
|
||||||
|
|
||||||
@ -445,40 +325,6 @@ There were plans to add a `Forge` type, in which the required libraries would be
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Fabric
|
|
||||||
|
|
||||||
The module type `Fabric` represents the fabric mod loader. Currently, the launcher only supports modded servers, as vanilla servers can be connected to via the mojang launcher.
|
|
||||||
|
|
||||||
Ex.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "net.fabricmc:fabric-loader:0.15.0",
|
|
||||||
"name": "Fabric (fabric-loader)",
|
|
||||||
"type": "Fabric",
|
|
||||||
"artifact": {
|
|
||||||
"size": 1196222,
|
|
||||||
"MD5": "a43d5a142246801343b6cedef1c102c4",
|
|
||||||
"url": "http://localhost:8080/repo/lib/net/fabricmc/fabric-loader/0.15.0/fabric-loader-0.15.0.jar"
|
|
||||||
},
|
|
||||||
"subModules": [
|
|
||||||
{
|
|
||||||
"id": "1.20.1-fabric-0.15.0",
|
|
||||||
"name": "Fabric (version.json)",
|
|
||||||
"type": "VersionManifest",
|
|
||||||
"artifact": {
|
|
||||||
"size": 2847,
|
|
||||||
"MD5": "69a2bd43452325ba1bc882fa0904e054",
|
|
||||||
"url": "http://localhost:8080/repo/versions/1.20.1-fabric-0.15.0/1.20.1-fabric-0.15.0.json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Fabric works similarly to Forge 1.13+.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 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.
|
||||||
|
14
index.js
14
index.js
@ -11,10 +11,6 @@ const path = require('path')
|
|||||||
const semver = require('semver')
|
const semver = require('semver')
|
||||||
const { pathToFileURL } = require('url')
|
const { pathToFileURL } = require('url')
|
||||||
const { AZURE_CLIENT_ID, MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR, SHELL_OPCODE } = require('./app/assets/js/ipcconstants')
|
const { AZURE_CLIENT_ID, MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR, SHELL_OPCODE } = require('./app/assets/js/ipcconstants')
|
||||||
const LangLoader = require('./app/assets/js/langloader')
|
|
||||||
|
|
||||||
// Setup Lang
|
|
||||||
LangLoader.setupLanguage()
|
|
||||||
|
|
||||||
// Setup auto updater.
|
// Setup auto updater.
|
||||||
function initAutoUpdater(event, data) {
|
function initAutoUpdater(event, data) {
|
||||||
@ -125,7 +121,7 @@ ipcMain.on(MSFT_OPCODE.OPEN_LOGIN, (ipcEvent, ...arguments_) => {
|
|||||||
msftAuthViewSuccess = arguments_[0]
|
msftAuthViewSuccess = arguments_[0]
|
||||||
msftAuthViewOnClose = arguments_[1]
|
msftAuthViewOnClose = arguments_[1]
|
||||||
msftAuthWindow = new BrowserWindow({
|
msftAuthWindow = new BrowserWindow({
|
||||||
title: LangLoader.queryJS('index.microsoftLoginTitle'),
|
title: 'Microsoft Login',
|
||||||
backgroundColor: '#222222',
|
backgroundColor: '#222222',
|
||||||
width: 520,
|
width: 520,
|
||||||
height: 600,
|
height: 600,
|
||||||
@ -178,7 +174,7 @@ ipcMain.on(MSFT_OPCODE.OPEN_LOGOUT, (ipcEvent, uuid, isLastAccount) => {
|
|||||||
msftLogoutSuccess = false
|
msftLogoutSuccess = false
|
||||||
msftLogoutSuccessSent = false
|
msftLogoutSuccessSent = false
|
||||||
msftLogoutWindow = new BrowserWindow({
|
msftLogoutWindow = new BrowserWindow({
|
||||||
title: LangLoader.queryJS('index.microsoftLogoutTitle'),
|
title: 'Microsoft Logout',
|
||||||
backgroundColor: '#222222',
|
backgroundColor: '#222222',
|
||||||
width: 520,
|
width: 520,
|
||||||
height: 600,
|
height: 600,
|
||||||
@ -240,11 +236,7 @@ function createWindow() {
|
|||||||
})
|
})
|
||||||
remoteMain.enable(win.webContents)
|
remoteMain.enable(win.webContents)
|
||||||
|
|
||||||
const data = {
|
ejse.data('bkid', Math.floor((Math.random() * fs.readdirSync(path.join(__dirname, 'app', 'assets', 'images', 'backgrounds')).length)))
|
||||||
bkid: Math.floor((Math.random() * fs.readdirSync(path.join(__dirname, 'app', 'assets', 'images', 'backgrounds')).length)),
|
|
||||||
lang: (str, placeHolders) => LangLoader.queryEJS(str, placeHolders)
|
|
||||||
}
|
|
||||||
Object.entries(data).forEach(([key, val]) => ejse.data(key, val))
|
|
||||||
|
|
||||||
win.loadURL(pathToFileURL(path.join(__dirname, 'app', 'app.ejs')).toString())
|
win.loadURL(pathToFileURL(path.join(__dirname, 'app', 'app.ejs')).toString())
|
||||||
|
|
||||||
|
12357
package-lock.json
generated
12357
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "helioslauncher",
|
"name": "helioslauncher",
|
||||||
"version": "2.1.0",
|
"version": "1.9.0",
|
||||||
"productName": "Helios Launcher",
|
"productName": "Helios Launcher",
|
||||||
"description": "Modded Minecraft Launcher",
|
"description": "Modded Minecraft Launcher",
|
||||||
"author": "Daniel Scalzi (https://github.com/dscalzi/)",
|
"author": "Daniel Scalzi (https://github.com/dscalzi/)",
|
||||||
@ -20,29 +20,33 @@
|
|||||||
"lint": "eslint --config .eslintrc.json ."
|
"lint": "eslint --config .eslintrc.json ."
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18.x.x"
|
"node": "16.x.x"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.1.0",
|
"@electron/remote": "^2.0.8",
|
||||||
"adm-zip": "^0.5.9",
|
"adm-zip": "^0.5.9",
|
||||||
|
"async": "^3.2.4",
|
||||||
"discord-rpc-patch": "^4.0.1",
|
"discord-rpc-patch": "^4.0.1",
|
||||||
"ejs": "^3.1.9",
|
"ejs": "^3.1.8",
|
||||||
"ejs-electron": "^2.1.1",
|
"ejs-electron": "^2.1.1",
|
||||||
"electron-updater": "^6.1.7",
|
"electron-updater": "^5.0.5",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^10.1.0",
|
||||||
"github-syntax-dark": "^0.5.0",
|
"github-syntax-dark": "^0.5.0",
|
||||||
"got": "^11.8.5",
|
"got": "^11.8.5",
|
||||||
"helios-core": "~2.1.0",
|
"helios-core": "~0.1.0",
|
||||||
"helios-distribution-types": "^1.3.0",
|
"jquery": "^3.6.0",
|
||||||
"jquery": "^3.7.1",
|
"node-stream-zip": "^1.15.0",
|
||||||
"lodash.merge": "^4.6.2",
|
"request": "^2.88.2",
|
||||||
"semver": "^7.5.4",
|
"semver": "^7.3.7",
|
||||||
"toml": "^3.0.0"
|
"tar-fs": "^2.1.1",
|
||||||
|
"winreg": "^1.2.4",
|
||||||
|
"7zip-bin": "^5.2.0"
|
||||||
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^27.1.3",
|
"electron": "^19.0.10",
|
||||||
"electron-builder": "^24.9.1",
|
"electron-builder": "^23.1.0",
|
||||||
"eslint": "^8.55.0"
|
"eslint": "^8.20.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
Loading…
Reference in New Issue
Block a user