Compare commits
2 Commits
master
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
|
9b1360b214 | ||
|
2279cb05b7 |
@ -52,15 +52,15 @@
|
|||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": [ "app/assets/js/scripts/*.js" ],
|
"env": {
|
||||||
"rules": {
|
"browser": true,
|
||||||
"no-unused-vars": [
|
"node": false,
|
||||||
0
|
"jquery": true
|
||||||
],
|
},
|
||||||
"no-undef": [
|
"files": [
|
||||||
0
|
"app/assets/js/scripts/*.js",
|
||||||
|
"app/assets/js/renderer/*.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
2
.github/workflows/build.yml
vendored
@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Set up Node
|
- name: Set up Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 18
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2017-2024 Daniel D. Scalzi
|
Copyright (c) 2017-2022 Daniel D. Scalzi
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<p align="center"><img src="./app/assets/images/SealCircle.png" width="150px" height="150px" alt="aventium softworks"></p>
|
<p align="center"><img src="./app/assets/images/SealCircle.png" width="150px" height="150px" alt="aventium softworks"></p>
|
||||||
|
|
||||||
<h1 align="center">ONIMAI.RU MC Launcher</h1>
|
<h1 align="center">Helios Launcher</h1>
|
||||||
|
|
||||||
<em><h5 align="center">(formerly Electron Launcher)</h5></em>
|
<em><h5 align="center">(formerly Electron Launcher)</h5></em>
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ This section details the setup of a basic developmentment environment.
|
|||||||
|
|
||||||
**System Requirements**
|
**System Requirements**
|
||||||
|
|
||||||
* [Node.js][nodejs] v20
|
* [Node.js][nodejs] v18
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -2,8 +2,10 @@
|
|||||||
<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><%= lang('app.title') %></title>
|
||||||
<script src="./assets/js/scripts/uicore.js"></script>
|
<!-- TODO FIXME -->
|
||||||
<script src="./assets/js/scripts/uibinder.js"></script>
|
<script src="../node_modules/jquery/dist/jquery.min.js"></script>
|
||||||
|
<!-- <script type="module" src="./assets/js/scripts/uicore.js"></script>
|
||||||
|
<script type="module" 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 {
|
||||||
@ -25,6 +27,7 @@
|
|||||||
filter: blur(3px) contrast(0.9) brightness(1.0);
|
filter: blur(3px) contrast(0.9) brightness(1.0);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<script type="module" src="./assets/js/renderer/megascript.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body bkid="<%=bkid%>">
|
<body bkid="<%=bkid%>">
|
||||||
<%- include('frame') %>
|
<%- include('frame') %>
|
||||||
|
9
app/assets/@types/preloader.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { api } from '../js/preloader.js'
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
api: typeof api
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
@ -388,17 +388,6 @@ body, button {
|
|||||||
background: rgba(0, 0, 0, 0.50);
|
background: rgba(0, 0, 0, 0.50);
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginOfflineContainer {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
transition: filter 0.25s ease;
|
|
||||||
background: rgba(0, 0, 0, 0.50);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Login cancel button styles. */
|
/* Login cancel button styles. */
|
||||||
#loginCancelContainer {
|
#loginCancelContainer {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 604 KiB After Width: | Height: | Size: 160 KiB |
Before Width: | Height: | Size: 781 KiB After Width: | Height: | Size: 181 KiB |
Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 502 KiB |
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 1.0 MiB |
Before Width: | Height: | Size: 343 KiB After Width: | Height: | Size: 268 KiB |
Before Width: | Height: | Size: 500 KiB After Width: | Height: | Size: 456 KiB |
Before Width: | Height: | Size: 580 KiB After Width: | Height: | Size: 2.6 MiB |
Before Width: | Height: | Size: 312 KiB After Width: | Height: | Size: 5.0 MiB |
Before Width: | Height: | Size: 30 KiB |
@ -1,7 +1,7 @@
|
|||||||
// NOTE FOR THIRD-PARTY
|
// NOTE FOR THIRD-PARTY
|
||||||
// REPLACE THIS CLIENT ID WITH YOUR APPLICATION ID.
|
// REPLACE THIS CLIENT ID WITH YOUR APPLICATION ID.
|
||||||
// SEE https://github.com/dscalzi/HeliosLauncher/blob/master/docs/MicrosoftAuth.md
|
// SEE https://github.com/dscalzi/HeliosLauncher/blob/master/docs/MicrosoftAuth.md
|
||||||
exports.AZURE_CLIENT_ID = '58f2320b-3644-4194-9174-796e17617dd0'
|
exports.AZURE_CLIENT_ID = '1ce6e35a-126f-48fd-97fb-54d143ac6d45'
|
||||||
// SEE NOTE ABOVE.
|
// SEE NOTE ABOVE.
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,122 +12,12 @@
|
|||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
const { RestResponseStatus } = require('helios-core/common')
|
const { RestResponseStatus } = require('helios-core/common')
|
||||||
const { MojangRestAPI, MojangErrorCode } = require('helios-core/mojang')
|
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
||||||
const { MicrosoftAuth, 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 Lang = require('./langloader')
|
|
||||||
|
|
||||||
const log = LoggerUtil.getLogger('AuthManager')
|
const log = LoggerUtil.getLogger('AuthManager')
|
||||||
|
|
||||||
// Error messages
|
|
||||||
|
|
||||||
function microsoftErrorDisplayable(errorCode) {
|
|
||||||
switch (errorCode) {
|
|
||||||
case MicrosoftErrorCode.NO_PROFILE:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.microsoft.error.noProfileTitle'),
|
|
||||||
desc: Lang.queryJS('auth.microsoft.error.noProfileDesc')
|
|
||||||
}
|
|
||||||
case MicrosoftErrorCode.NO_XBOX_ACCOUNT:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.microsoft.error.noXboxAccountTitle'),
|
|
||||||
desc: Lang.queryJS('auth.microsoft.error.noXboxAccountDesc')
|
|
||||||
}
|
|
||||||
case MicrosoftErrorCode.XBL_BANNED:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.microsoft.error.xblBannedTitle'),
|
|
||||||
desc: Lang.queryJS('auth.microsoft.error.xblBannedDesc')
|
|
||||||
}
|
|
||||||
case MicrosoftErrorCode.UNDER_18:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.microsoft.error.under18Title'),
|
|
||||||
desc: Lang.queryJS('auth.microsoft.error.under18Desc')
|
|
||||||
}
|
|
||||||
case MicrosoftErrorCode.UNKNOWN:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.microsoft.error.unknownTitle'),
|
|
||||||
desc: Lang.queryJS('auth.microsoft.error.unknownDesc')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mojangErrorDisplayable(errorCode) {
|
|
||||||
switch(errorCode) {
|
|
||||||
case MojangErrorCode.ERROR_METHOD_NOT_ALLOWED:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.methodNotAllowedTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.methodNotAllowedDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_NOT_FOUND:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.notFoundTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.notFoundDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_USER_MIGRATED:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.accountMigratedTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.accountMigratedDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_INVALID_CREDENTIALS:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.invalidCredentialsTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.invalidCredentialsDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_RATELIMIT:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.tooManyAttemptsTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.tooManyAttemptsDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_INVALID_TOKEN:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.invalidTokenTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.invalidTokenDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_ACCESS_TOKEN_HAS_PROFILE:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.tokenHasProfileTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.tokenHasProfileDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_CREDENTIALS_MISSING:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.credentialsMissingTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.credentialsMissingDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_INVALID_SALT_VERSION:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.invalidSaltVersionTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.invalidSaltVersionDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_UNSUPPORTED_MEDIA_TYPE:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.unsupportedMediaTypeTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.unsupportedMediaTypeDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_GONE:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.accountGoneTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.accountGoneDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_UNREACHABLE:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.unreachableTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.unreachableDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.ERROR_NOT_PAID:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.gameNotPurchasedTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.gameNotPurchasedDesc')
|
|
||||||
}
|
|
||||||
case MojangErrorCode.UNKNOWN:
|
|
||||||
return {
|
|
||||||
title: Lang.queryJS('auth.mojang.error.unknownErrorTitle'),
|
|
||||||
desc: Lang.queryJS('auth.mojang.error.unknownErrorDesc')
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new Error(`Unknown error code: ${errorCode}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,17 +57,6 @@ exports.addMojangAccount = async function(username, password) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.addOfflineAccount = async function(username) {
|
|
||||||
try {
|
|
||||||
const ret = ConfigManager.addOfflineAccount(username)
|
|
||||||
ConfigManager.save()
|
|
||||||
return ret
|
|
||||||
} catch (err){
|
|
||||||
log.error(err)
|
|
||||||
return Promise.reject(mojangErrorDisplayable(MojangErrorCode.UNKNOWN))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 }
|
const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -320,17 +199,6 @@ exports.removeMicrosoftAccount = 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate the selected account with Mojang's authserver. If the account is not valid,
|
* Validate the selected account with Mojang's authserver. If the account is not valid,
|
||||||
* we will attempt to refresh the access token and update that value. If that fails, a
|
* we will attempt to refresh the access token and update that value. If that fails, a
|
@ -1,6 +1,5 @@
|
|||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
const { LoggerUtil } = require('helios-core')
|
const { LoggerUtil } = require('helios-core')
|
||||||
const { randomUUID } = require('crypto')
|
|
||||||
const os = require('os')
|
const os = require('os')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
@ -10,7 +9,9 @@ const sysRoot = process.env.APPDATA || (process.platform == 'darwin' ? process.e
|
|||||||
|
|
||||||
const dataPath = path.join(sysRoot, '.helioslauncher')
|
const dataPath = path.join(sysRoot, '.helioslauncher')
|
||||||
|
|
||||||
const launcherDir = require('@electron/remote').app.getPath('userData')
|
const { app } = require('electron')
|
||||||
|
|
||||||
|
const launcherDir = app.getPath('userData')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the absolute path of the launcher directory.
|
* Retrieve the absolute path of the launcher directory.
|
||||||
@ -350,20 +351,6 @@ exports.addMojangAuthAccount = function(uuid, accessToken, username, displayName
|
|||||||
return config.authenticationDatabase[uuid]
|
return config.authenticationDatabase[uuid]
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.addOfflineAccount = function(username){
|
|
||||||
console.log("Yeah I try to create new offline account")
|
|
||||||
uuid = randomUUID()
|
|
||||||
config.selectedAccount = uuid
|
|
||||||
config.authenticationDatabase[uuid] = {
|
|
||||||
type: 'offline',
|
|
||||||
password: '',
|
|
||||||
username: username.trim(),
|
|
||||||
uuid: uuid.trim(),
|
|
||||||
displayName: username.trim()
|
|
||||||
}
|
|
||||||
return config.authenticationDatabase[uuid]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the tokens of an authenticated microsoft account.
|
* Update the tokens of an authenticated microsoft account.
|
||||||
*
|
*
|
@ -2,7 +2,9 @@ const { DistributionAPI } = require('helios-core/common')
|
|||||||
|
|
||||||
const ConfigManager = require('./configmanager')
|
const ConfigManager = require('./configmanager')
|
||||||
|
|
||||||
exports.REMOTE_DISTRO_URL = 'https://git.onimai.ru/ONIMAI-SMP/distribution/raw/branch/main/distribution.json'
|
// Old WesterosCraft url.
|
||||||
|
// exports.REMOTE_DISTRO_URL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
|
||||||
|
exports.REMOTE_DISTRO_URL = 'https://helios-files.geekcorner.eu.org/distribution.json'
|
||||||
|
|
||||||
const api = new DistributionAPI(
|
const api = new DistributionAPI(
|
||||||
ConfigManager.getLauncherDirectory(),
|
ConfigManager.getLauncherDirectory(),
|
@ -6,7 +6,7 @@ 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 = merge(lang || {}, toml.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'lang', `${id}.toml`))) || {})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.query = function(id, placeHolders){
|
exports.query = function(id, placeHolders){
|
||||||
@ -41,3 +41,7 @@ exports.setupLanguage = function(){
|
|||||||
// Load Custom Language File for Launcher Customizer
|
// Load Custom Language File for Launcher Customizer
|
||||||
exports.loadLanguage('_custom')
|
exports.loadLanguage('_custom')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exports.getLang = () => {
|
||||||
|
return lang
|
||||||
|
}
|
@ -1,67 +1,58 @@
|
|||||||
const {ipcRenderer} = require('electron')
|
const { contextBridge, ipcRenderer } = require('electron')
|
||||||
const fs = require('fs-extra')
|
|
||||||
const os = require('os')
|
|
||||||
const path = require('path')
|
|
||||||
|
|
||||||
const ConfigManager = require('./configmanager')
|
module.exports.api = {
|
||||||
const { DistroAPI } = require('./distromanager')
|
os: {
|
||||||
const LangLoader = require('./langloader')
|
totalmem: () => ipcRenderer.invoke('os.totalmem'),
|
||||||
const { LoggerUtil } = require('helios-core')
|
freemem: () => ipcRenderer.invoke('os.freemem')
|
||||||
// eslint-disable-next-line no-unused-vars
|
},
|
||||||
const { HeliosDistribution } = require('helios-core/common')
|
semver: {
|
||||||
|
prerelease: (version) => ipcRenderer.invoke('semver.prerelease', version)
|
||||||
const logger = LoggerUtil.getLogger('Preloader')
|
},
|
||||||
|
path: {
|
||||||
logger.info('Loading..')
|
join: (...args) => ipcRenderer.invoke('path.join', args)
|
||||||
|
},
|
||||||
// Load ConfigManager
|
app: {
|
||||||
ConfigManager.load()
|
isDev: () => ipcRenderer.invoke('app.isDev'),
|
||||||
|
getVersion: () => ipcRenderer.invoke('app.getVersion')
|
||||||
// Yuck!
|
},
|
||||||
// TODO Fix this
|
shell: {
|
||||||
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
|
openExternal: (url) => ipcRenderer.invoke('shell.openExternal', url),
|
||||||
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
|
openPath: (path) => ipcRenderer.invoke('shell.openPath', path),
|
||||||
|
},
|
||||||
// Load Strings
|
xwindow: {
|
||||||
LangLoader.setupLanguage()
|
close: () => ipcRenderer.invoke('xwindow.close'),
|
||||||
|
setProgressBar: (progress) => ipcRenderer.invoke('xwindow.setProgressBar', progress),
|
||||||
/**
|
toggleDevTools: () => {
|
||||||
*
|
console.log('%cThe console is dark and full of terrors.', 'color: white; -webkit-text-stroke: 4px #a02d2a; font-size: 60px; font-weight: bold')
|
||||||
* @param {HeliosDistribution} data
|
console.log('%cIf you\'ve been told to paste something here, you\'re being scammed.', 'font-size: 16px')
|
||||||
*/
|
console.log('%cUnless you know exactly what you\'re doing, close this window.', 'font-size: 16px')
|
||||||
function onDistroLoad(data){
|
return ipcRenderer.invoke('xwindow.toggleDevTools')
|
||||||
if(data != null){
|
},
|
||||||
|
minimize: () => ipcRenderer.invoke('xwindow.minimize'),
|
||||||
// Resolve the selected server if its value has yet to be set.
|
maximize: () => ipcRenderer.invoke('xwindow.maximize'),
|
||||||
if(ConfigManager.getSelectedServer() == null || data.getServerById(ConfigManager.getSelectedServer()) == null){
|
unmaximize: () => ipcRenderer.invoke('xwindow.unmaximize'),
|
||||||
logger.info('Determining default selected server..')
|
isMaximized: () => ipcRenderer.invoke('xwindow.isMaximized')
|
||||||
ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
|
},
|
||||||
ConfigManager.save()
|
process: {
|
||||||
|
platform: () => ipcRenderer.invoke('process.platform'),
|
||||||
|
arch: () => ipcRenderer.invoke('process.arch')
|
||||||
|
},
|
||||||
|
hc: {
|
||||||
|
type: () => ipcRenderer.invoke('hc.type')
|
||||||
|
},
|
||||||
|
AuthManager: {
|
||||||
|
addMojangAccount: (username, password) => ipcRenderer.invoke('AuthManager.addMojangAccount', username, password),
|
||||||
|
addMicrosoftAccount: (authCode) => ipcRenderer.invoke('AuthManager.addMicrosoftAccount', authCode),
|
||||||
|
removeMojangAccount: (uuid) => ipcRenderer.invoke('AuthManager.removeMojangAccount', uuid),
|
||||||
|
removeMicrosoftAccount: (uuid) => ipcRenderer.invoke('AuthManager.removeMicrosoftAccount', uuid),
|
||||||
|
validateSelected: () => ipcRenderer.invoke('AuthManager.validateSelected')
|
||||||
|
},
|
||||||
|
Lang: {
|
||||||
|
getLang: () => ipcRenderer.invoke('Lang.getLang')
|
||||||
|
},
|
||||||
|
AutoUpdater: {
|
||||||
|
port2: () => ipcRenderer.invoke('AutoUpdater.port2')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ipcRenderer.send('distributionIndexDone', data != null)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure Distribution is downloaded and cached.
|
contextBridge.exposeInMainWorld('api', module.exports.api)
|
||||||
DistroAPI.getDistribution()
|
|
||||||
.then(heliosDistro => {
|
|
||||||
logger.info('Loaded distribution index.')
|
|
||||||
|
|
||||||
onDistroLoad(heliosDistro)
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
logger.info('Failed to load an older version of the distribution index.')
|
|
||||||
logger.info('Application cannot run.')
|
|
||||||
logger.error(err)
|
|
||||||
|
|
||||||
onDistroLoad(null)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Clean up temp dir incase previous launches ended unexpectedly.
|
|
||||||
fs.remove(path.join(os.tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
|
|
||||||
if(err){
|
|
||||||
logger.warn('Error while cleaning natives directory', err)
|
|
||||||
} else {
|
|
||||||
logger.info('Cleaned natives directory.')
|
|
||||||
}
|
|
||||||
})
|
|
@ -12,23 +12,14 @@ const ConfigManager = require('./configmanager')
|
|||||||
|
|
||||||
const logger = LoggerUtil.getLogger('ProcessBuilder')
|
const logger = LoggerUtil.getLogger('ProcessBuilder')
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.rawServer.id)
|
||||||
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 +28,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +40,9 @@ class ProcessBuilder {
|
|||||||
process.throwDeprecation = true
|
process.throwDeprecation = true
|
||||||
this.setupLiteLoader()
|
this.setupLiteLoader()
|
||||||
logger.info('Using liteloader:', this.usingLiteLoader)
|
logger.info('Using liteloader:', this.usingLiteLoader)
|
||||||
this.usingFabricLoader = this.server.modules.some(mdl => mdl.rawModule.type === Type.Fabric)
|
|
||||||
logger.info('Using fabric loader:', this.usingFabricLoader)
|
|
||||||
const modObj = this.resolveModConfiguration(ConfigManager.getModConfiguration(this.server.rawServer.id).mods, this.server.modules)
|
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(!mcVersionAtLeast('1.13', this.server.rawServer.minecraftVersion)){
|
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){
|
||||||
@ -179,7 +166,7 @@ class ProcessBuilder {
|
|||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.rawModule.type
|
const type = mdl.rawModule.type
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
const o = !mdl.getRequired().value
|
const o = !mdl.getRequired().value
|
||||||
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
|
const e = ProcessBuilder.isModEnabled(modCfg[mdl.getVersionlessMavenIdentifier()], mdl.getRequired())
|
||||||
if(!o || (o && e)){
|
if(!o || (o && e)){
|
||||||
@ -191,7 +178,7 @@ class ProcessBuilder {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(type === Type.ForgeMod || type === Type.FabricMod){
|
if(type === Type.ForgeMod){
|
||||||
fMods.push(mdl)
|
fMods.push(mdl)
|
||||||
} else {
|
} else {
|
||||||
lMods.push(mdl)
|
lMods.push(mdl)
|
||||||
@ -207,7 +194,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 +206,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++){
|
||||||
@ -295,21 +282,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.getExtensionlessMavenIdentifier()
|
||||||
}).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',
|
||||||
@ -368,7 +352,7 @@ class ProcessBuilder {
|
|||||||
|
|
||||||
// Java Arguments
|
// Java Arguments
|
||||||
if(process.platform === 'darwin'){
|
if(process.platform === 'darwin'){
|
||||||
args.push('-Xdock:name=onimairu-mc_launcher')
|
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(this.server.rawServer.id))
|
||||||
@ -377,7 +361,7 @@ class ProcessBuilder {
|
|||||||
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,17 +384,17 @@ 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
|
// Debug securejarhandler
|
||||||
// args.push('-Dbsl.debug=true')
|
// args.push('-Dbsl.debug=true')
|
||||||
|
|
||||||
if(this.modManifest.arguments.jvm != null) {
|
if(this.forgeData.arguments.jvm != null) {
|
||||||
for(const argStr of this.modManifest.arguments.jvm) {
|
for(const argStr of this.forgeData.arguments.jvm) {
|
||||||
args.push(argStr
|
args.push(argStr
|
||||||
.replaceAll('${library_directory}', this.libPath)
|
.replaceAll('${library_directory}', this.libPath)
|
||||||
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
|
.replaceAll('${classpath_separator}', ProcessBuilder.getClasspathSeparator())
|
||||||
.replaceAll('${version_name}', this.modManifest.id)
|
.replaceAll('${version_name}', this.forgeData.id)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -419,7 +403,7 @@ class ProcessBuilder {
|
|||||||
|
|
||||||
// Java Arguments
|
// Java Arguments
|
||||||
if(process.platform === 'darwin'){
|
if(process.platform === 'darwin'){
|
||||||
args.push('-Xdock:name=onimairu-mc_launcher')
|
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(this.server.rawServer.id))
|
||||||
@ -427,10 +411,10 @@ class ProcessBuilder {
|
|||||||
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
|
args = args.concat(ConfigManager.getJVMOptions(this.server.rawServer.id))
|
||||||
|
|
||||||
// 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){
|
||||||
@ -487,7 +471,7 @@ 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.rawServer.id
|
||||||
break
|
break
|
||||||
case 'game_directory':
|
case 'game_directory':
|
||||||
@ -497,7 +481,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 +493,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()
|
||||||
@ -538,11 +522,25 @@ class ProcessBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Autoconnect
|
// Autoconnect
|
||||||
|
let isAutoconnectBroken
|
||||||
|
try {
|
||||||
|
isAutoconnectBroken = ProcessBuilder.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)
|
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 +556,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,7 +569,7 @@ 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.rawServer.id
|
||||||
break
|
break
|
||||||
case 'game_directory':
|
case 'game_directory':
|
||||||
@ -581,7 +579,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 +594,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,10 +669,10 @@ class ProcessBuilder {
|
|||||||
classpathArg(mods, tempNativePath){
|
classpathArg(mods, tempNativePath){
|
||||||
let cpArgs = []
|
let cpArgs = []
|
||||||
|
|
||||||
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion) || this.usingFabricLoader) {
|
if(!mcVersionAtLeast('1.17', this.server.rawServer.minecraftVersion)) {
|
||||||
// Add the version.jar to the classpath.
|
// Add the version.jar to the classpath.
|
||||||
// Must not be added to the classpath for Forge 1.17+.
|
// Must not be added to the classpath for Forge 1.17+.
|
||||||
const version = this.vanillaManifest.id
|
const version = this.versionData.id
|
||||||
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
cpArgs.push(path.join(this.commonDir, 'versions', version, version + '.jar'))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,7 +711,7 @@ class ProcessBuilder {
|
|||||||
const nativesRegex = /.+:natives-([^-]+)(?:-(.+))?/
|
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]
|
||||||
@ -832,25 +830,29 @@ class ProcessBuilder {
|
|||||||
const mdls = this.server.modules
|
const mdls = this.server.modules
|
||||||
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.rawModule.type
|
||||||
if(type === Type.ForgeHosted || type === Type.Fabric || type === Type.Library){
|
if(type === Type.ForgeHosted || type === Type.Library){
|
||||||
libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
|
libs[mdl.getVersionlessMavenIdentifier()] = mdl.getPath()
|
||||||
if(mdl.subModules.length > 0){
|
if(mdl.subModules.length > 0){
|
||||||
const res = this._resolveModuleLibraries(mdl)
|
const res = this._resolveModuleLibraries(mdl)
|
||||||
|
if(res.length > 0){
|
||||||
libs = {...libs, ...res}
|
libs = {...libs, ...res}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Check for any libraries in our mod list.
|
//Check for any libraries in our mod list.
|
||||||
for(let i=0; i<mods.length; i++){
|
for(let i=0; i<mods.length; i++){
|
||||||
if(mods.sub_modules != null){
|
if(mods.sub_modules != null){
|
||||||
const res = this._resolveModuleLibraries(mods[i])
|
const res = this._resolveModuleLibraries(mods[i])
|
||||||
|
if(res.length > 0){
|
||||||
libs = {...libs, ...res}
|
libs = {...libs, ...res}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return libs
|
return libs
|
||||||
}
|
}
|
||||||
@ -859,30 +861,50 @@ class ProcessBuilder {
|
|||||||
* Recursively resolve the path of each library required by this module.
|
* Recursively resolve the path of each library required by this module.
|
||||||
*
|
*
|
||||||
* @param {Object} mdl A module object from the server distro index.
|
* @param {Object} mdl A module object from the server distro index.
|
||||||
* @returns {{[id: string]: string}} An object 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.subModules.length > 0){
|
||||||
return {}
|
return []
|
||||||
}
|
}
|
||||||
let libs = {}
|
let libs = []
|
||||||
for(let sm of mdl.subModules){
|
for(let sm of mdl.subModules){
|
||||||
if(sm.rawModule.type === Type.Library){
|
if(sm.rawModule.type === Type.Library){
|
||||||
|
|
||||||
if(sm.rawModule.classpath ?? true) {
|
if(sm.rawModule.classpath ?? true) {
|
||||||
libs[sm.getVersionlessMavenIdentifier()] = sm.getPath()
|
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.subModules.length > 0){
|
||||||
const res = this._resolveModuleLibraries(sm)
|
const res = this._resolveModuleLibraries(sm)
|
||||||
libs = {...libs, ...res}
|
if(res.length > 0){
|
||||||
|
libs = libs.concat(res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return libs
|
return libs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static isAutoconnectBroken(forgeVersion) {
|
||||||
|
|
||||||
|
const minWorking = [31, 2, 15]
|
||||||
|
const verSplit = forgeVersion.split('.').map(v => Number(v))
|
||||||
|
|
||||||
|
if(verSplit[0] === 31) {
|
||||||
|
for(let i=0; i<minWorking.length; i++) {
|
||||||
|
if(verSplit[i] > minWorking[i]) {
|
||||||
|
return false
|
||||||
|
} else if(verSplit[i] < minWorking[i]) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ProcessBuilder
|
module.exports = ProcessBuilder
|
30
app/assets/js/renderer/langrenderer.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// HACK FIXME
|
||||||
|
|
||||||
|
let lang
|
||||||
|
|
||||||
|
export async function loadLanguage() {
|
||||||
|
lang = await window.api.Lang.getLang()
|
||||||
|
}
|
||||||
|
|
||||||
|
export function query(id, placeHolders){
|
||||||
|
let query = id.split('.')
|
||||||
|
let res = lang
|
||||||
|
for(let q of query){
|
||||||
|
res = res[q]
|
||||||
|
}
|
||||||
|
let text = res === lang ? '' : res
|
||||||
|
if (placeHolders) {
|
||||||
|
Object.entries(placeHolders).forEach(([key, value]) => {
|
||||||
|
text = text.replace(`{${key}}`, value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryJS(id, placeHolders){
|
||||||
|
return query(`js.${id}`, placeHolders)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function queryEJS(id, placeHolders){
|
||||||
|
return query(`ejs.${id}`, placeHolders)
|
||||||
|
}
|
3895
app/assets/js/renderer/megascript.js
Normal file
9
app/assets/js/renderer/views.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Mapping of each view to their container IDs.
|
||||||
|
export const VIEWS = {
|
||||||
|
landing: '#landingContainer',
|
||||||
|
loginOptions: '#loginOptionsContainer',
|
||||||
|
login: '#loginContainer',
|
||||||
|
settings: '#settingsContainer',
|
||||||
|
welcome: '#welcomeContainer',
|
||||||
|
waiting: '#waitingContainer'
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
/**
|
/**
|
||||||
* Script for landing.ejs
|
* Script for landing.ejs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { VIEWS } from './views.js'
|
||||||
|
|
||||||
// Requirements
|
// Requirements
|
||||||
const { URL } = require('url')
|
|
||||||
const {
|
const {
|
||||||
MojangRestAPI,
|
MojangRestAPI,
|
||||||
getServerStatus
|
getServerStatus
|
||||||
@ -85,7 +87,7 @@ function setLaunchPercentage(percent){
|
|||||||
* @param {number} percent Percentage (0-100)
|
* @param {number} percent Percentage (0-100)
|
||||||
*/
|
*/
|
||||||
function setDownloadPercentage(percent){
|
function setDownloadPercentage(percent){
|
||||||
remote.getCurrentWindow().setProgressBar(percent/100)
|
xwindow.setProgressBar(percent/100)
|
||||||
setLaunchPercentage(percent)
|
setLaunchPercentage(percent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,7 +404,7 @@ async function downloadJava(effectiveJavaOptions, launchAfter = true) {
|
|||||||
|
|
||||||
// Extract
|
// Extract
|
||||||
// Show installing progress bar.
|
// Show installing progress bar.
|
||||||
remote.getCurrentWindow().setProgressBar(2)
|
xwindow.setProgressBar(2)
|
||||||
|
|
||||||
// Wait for extration to complete.
|
// Wait for extration to complete.
|
||||||
const eLStr = Lang.queryJS('landing.downloadJava.extractingJava')
|
const eLStr = Lang.queryJS('landing.downloadJava.extractingJava')
|
||||||
@ -420,7 +422,7 @@ async function downloadJava(effectiveJavaOptions, launchAfter = true) {
|
|||||||
const newJavaExec = await extractJdk(asset.path)
|
const newJavaExec = await extractJdk(asset.path)
|
||||||
|
|
||||||
// Extraction complete, remove the loading from the OS progress bar.
|
// Extraction complete, remove the loading from the OS progress bar.
|
||||||
remote.getCurrentWindow().setProgressBar(-1)
|
xwindow.setProgressBar(-1)
|
||||||
|
|
||||||
// Extraction completed successfully.
|
// Extraction completed successfully.
|
||||||
ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), newJavaExec)
|
ConfigManager.setJavaExecutable(ConfigManager.getSelectedServer(), newJavaExec)
|
||||||
@ -442,7 +444,7 @@ let hasRPC = false
|
|||||||
// Joined server regex
|
// Joined server regex
|
||||||
// Change this if your server uses something different.
|
// Change this if your server uses something different.
|
||||||
const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
|
const GAME_JOINED_REGEX = /\[.+\]: Sound engine started/
|
||||||
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+|Loading Minecraft .+ with Fabric Loader .+)$/
|
const GAME_LAUNCH_REGEX = /^\[.+\]: (?:MinecraftForge .+ Initialized|ModLauncher .+ starting: .+)$/
|
||||||
const MIN_LINGER = 5000
|
const MIN_LINGER = 5000
|
||||||
|
|
||||||
async function dlAsync(login = true) {
|
async function dlAsync(login = true) {
|
||||||
@ -533,7 +535,7 @@ async function dlAsync(login = true) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove download bar.
|
// Remove download bar.
|
||||||
remote.getCurrentWindow().setProgressBar(-1)
|
xwindow.setProgressBar(-1)
|
||||||
|
|
||||||
fullRepairModule.destroyReceiver()
|
fullRepairModule.destroyReceiver()
|
||||||
|
|
||||||
@ -548,13 +550,13 @@ async function dlAsync(login = true) {
|
|||||||
serv.rawServer.id
|
serv.rawServer.id
|
||||||
)
|
)
|
||||||
|
|
||||||
const modLoaderData = await distributionIndexProcessor.loadModLoaderVersionJson(serv)
|
const forgeData = await distributionIndexProcessor.loadForgeVersionJson(serv)
|
||||||
const versionData = await mojangIndexProcessor.getVersionJson()
|
const versionData = await mojangIndexProcessor.getVersionJson()
|
||||||
|
|
||||||
if(login) {
|
if(login) {
|
||||||
const authUser = ConfigManager.getSelectedAccount()
|
const authUser = ConfigManager.getSelectedAccount()
|
||||||
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
|
loggerLaunchSuite.info(`Sending selected account (${authUser.displayName}) to ProcessBuilder.`)
|
||||||
let pb = new ProcessBuilder(serv, versionData, modLoaderData, authUser, remote.app.getVersion())
|
let pb = new ProcessBuilder(serv, versionData, forgeData, authUser, app.getVersion())
|
||||||
setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame'))
|
setLaunchDetails(Lang.queryJS('landing.dlAsync.launchingGame'))
|
||||||
|
|
||||||
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/
|
// const SERVER_JOINED_REGEX = /\[.+\]: \[CHAT\] [a-zA-Z0-9_]{1,16} joined the game/
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
/**
|
/**
|
||||||
* Script for login.ejs
|
* Script for login.ejs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { VIEWS } from './views.js'
|
||||||
|
|
||||||
// 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+$/
|
||||||
@ -11,6 +14,8 @@ 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 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')
|
||||||
@ -75,7 +80,17 @@ function validateEmail(value){
|
|||||||
* @param {string} value The password value.
|
* @param {string} value The password value.
|
||||||
*/
|
*/
|
||||||
function validatePassword(value){
|
function validatePassword(value){
|
||||||
lp = true;
|
if(value){
|
||||||
|
loginPasswordError.style.opacity = 0
|
||||||
|
lp = true
|
||||||
|
if(lu){
|
||||||
|
loginDisabled(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lp = false
|
||||||
|
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
|
||||||
|
loginDisabled(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emphasize errors with shake when focus is lost.
|
// Emphasize errors with shake when focus is lost.
|
||||||
@ -83,10 +98,17 @@ loginUsername.addEventListener('focusout', (e) => {
|
|||||||
validateEmail(e.target.value)
|
validateEmail(e.target.value)
|
||||||
shakeError(loginEmailError)
|
shakeError(loginEmailError)
|
||||||
})
|
})
|
||||||
|
loginPassword.addEventListener('focusout', (e) => {
|
||||||
|
validatePassword(e.target.value)
|
||||||
|
shakeError(loginPasswordError)
|
||||||
|
})
|
||||||
|
|
||||||
// Validate input for each field.
|
// Validate input for each field.
|
||||||
loginUsername.addEventListener('input', (e) => {
|
loginUsername.addEventListener('input', (e) => {
|
||||||
loginDisabled(false)
|
validateEmail(e.target.value)
|
||||||
|
})
|
||||||
|
loginPassword.addEventListener('input', (e) => {
|
||||||
|
validatePassword(e.target.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,6 +146,7 @@ function formDisabled(v){
|
|||||||
loginDisabled(v)
|
loginDisabled(v)
|
||||||
loginCancelButton.disabled = v
|
loginCancelButton.disabled = v
|
||||||
loginUsername.disabled = v
|
loginUsername.disabled = v
|
||||||
|
loginPassword.disabled = v
|
||||||
if(v){
|
if(v){
|
||||||
checkmarkContainer.setAttribute('disabled', v)
|
checkmarkContainer.setAttribute('disabled', v)
|
||||||
} else {
|
} else {
|
||||||
@ -167,7 +190,7 @@ loginButton.addEventListener('click', () => {
|
|||||||
// Show loading stuff.
|
// Show loading stuff.
|
||||||
loginLoading(true)
|
loginLoading(true)
|
||||||
|
|
||||||
AuthManager.addOfflineAccount(loginUsername.value).then((value) => {
|
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
||||||
updateSelectedAccount(value)
|
updateSelectedAccount(value)
|
||||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
||||||
$('.circle-loader').toggleClass('load-complete')
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
@ -182,6 +205,7 @@ loginButton.addEventListener('click', () => {
|
|||||||
loginCancelEnabled(false) // Reset this for good measure.
|
loginCancelEnabled(false) // Reset this for good measure.
|
||||||
loginViewCancelHandler = null // Reset this for good measure.
|
loginViewCancelHandler = null // Reset this for good measure.
|
||||||
loginUsername.value = ''
|
loginUsername.value = ''
|
||||||
|
loginPassword.value = ''
|
||||||
$('.circle-loader').toggleClass('load-complete')
|
$('.circle-loader').toggleClass('load-complete')
|
||||||
$('.checkmark').toggle()
|
$('.checkmark').toggle()
|
||||||
loginLoading(false)
|
loginLoading(false)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
|
import { VIEWS } from './views.js'
|
||||||
|
|
||||||
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 loginOptionOffline = document.getElementById('loginOptionOffline')
|
|
||||||
const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton')
|
const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton')
|
||||||
|
|
||||||
let loginOptionsCancellable = false
|
let loginOptionsCancellable = false
|
||||||
@ -29,7 +30,7 @@ loginOptionMicrosoft.onclick = (e) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
loginOptionOffline.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
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
* Script for overlay.ejs
|
* Script for overlay.ejs
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { VIEWS } from './views.js'
|
||||||
|
|
||||||
/* Overlay Wrapper Functions */
|
/* Overlay Wrapper Functions */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
// Requirements
|
|
||||||
const os = require('os')
|
|
||||||
const semver = require('semver')
|
|
||||||
|
|
||||||
const DropinModUtil = require('./assets/js/dropinmodutil')
|
import { VIEWS } from './views.js'
|
||||||
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')
|
|
||||||
|
import DropinModUtil from './assets/js/dropinmodutil'
|
||||||
|
import { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } from './assets/js/ipcconstants'
|
||||||
|
|
||||||
const settingsState = {
|
const settingsState = {
|
||||||
invalid: new Set()
|
invalid: new Set()
|
||||||
@ -64,13 +63,14 @@ function bindFileSelectors(){
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)
|
// TODO FIXME
|
||||||
if(!res.canceled) {
|
// const res = await remote.dialog.showOpenDialog(remote.getCurrentWindow(), options)
|
||||||
ele.previousElementSibling.value = res.filePaths[0]
|
// if(!res.canceled) {
|
||||||
if(isJavaExecSel) {
|
// ele.previousElementSibling.value = res.filePaths[0]
|
||||||
await populateJavaExecDetails(ele.previousElementSibling.value)
|
// if(isJavaExecSel) {
|
||||||
}
|
// await populateJavaExecDetails(ele.previousElementSibling.value)
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -342,6 +342,15 @@ settingsNavDone.onclick = () => {
|
|||||||
const msftLoginLogger = LoggerUtil.getLogger('Microsoft Login')
|
const msftLoginLogger = LoggerUtil.getLogger('Microsoft Login')
|
||||||
const msftLogoutLogger = LoggerUtil.getLogger('Microsoft Logout')
|
const msftLogoutLogger = LoggerUtil.getLogger('Microsoft Logout')
|
||||||
|
|
||||||
|
// Bind the add mojang account button.
|
||||||
|
document.getElementById('settingsAddMojangAccount').onclick = (e) => {
|
||||||
|
switchView(getCurrentView(), VIEWS.login, 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, () => {
|
||||||
@ -510,7 +519,7 @@ function processLogOut(val, isLastAccount){
|
|||||||
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGOUT, uuid, isLastAccount)
|
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGOUT, uuid, isLastAccount)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
AuthManager.removeOfflineAccount(uuid).then(() => {
|
AuthManager.removeMojangAccount(uuid).then(() => {
|
||||||
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
||||||
const selAcc = ConfigManager.getSelectedAccount()
|
const selAcc = ConfigManager.getSelectedAccount()
|
||||||
refreshAuthAccountSelected(selAcc.uuid)
|
refreshAuthAccountSelected(selAcc.uuid)
|
||||||
@ -610,8 +619,7 @@ function refreshAuthAccountSelected(uuid){
|
|||||||
}
|
}
|
||||||
|
|
||||||
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.
|
||||||
@ -626,7 +634,6 @@ 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]
|
||||||
@ -658,14 +665,13 @@ function populateAuthAccounts(){
|
|||||||
if(acc.type === 'microsoft') {
|
if(acc.type === 'microsoft') {
|
||||||
microsoftAuthAccountStr += accHtml
|
microsoftAuthAccountStr += accHtml
|
||||||
} else {
|
} else {
|
||||||
offlineAuthAccountStr += accHtml
|
mojangAuthAccountStr += accHtml
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
settingsCurrentMicrosoftAccounts.innerHTML = microsoftAuthAccountStr
|
settingsCurrentMicrosoftAccounts.innerHTML = microsoftAuthAccountStr
|
||||||
//settingsCurrentMojangAccounts.innerHTML = mojangAuthAccountStr
|
settingsCurrentMojangAccounts.innerHTML = mojangAuthAccountStr
|
||||||
settingsCurrentOfflineAccounts.innerHTML = offlineAuthAccountStr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -710,7 +716,7 @@ async function resolveModsForUI(){
|
|||||||
const distro = await DistroAPI.getDistribution()
|
const distro = await DistroAPI.getDistribution()
|
||||||
const servConf = ConfigManager.getModConfiguration(serv)
|
const servConf = ConfigManager.getModConfiguration(serv)
|
||||||
|
|
||||||
const modStr = parseModulesForUI(distro.getServerById(serv).modules, false, servConf.mods)
|
const modStr = await parseModulesForUI(distro.getServerById(serv).modules, 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
|
||||||
@ -723,14 +729,16 @@ async function resolveModsForUI(){
|
|||||||
* @param {boolean} submodules Whether or not we are parsing submodules.
|
* @param {boolean} submodules Whether or not we are parsing submodules.
|
||||||
* @param {Object} servConf The server configuration object for this module level.
|
* @param {Object} servConf The server configuration object for this module level.
|
||||||
*/
|
*/
|
||||||
function parseModulesForUI(mdls, submodules, servConf){
|
async function parseModulesForUI(mdls, submodules, servConf){
|
||||||
|
|
||||||
let reqMods = ''
|
let reqMods = ''
|
||||||
let optMods = ''
|
let optMods = ''
|
||||||
|
|
||||||
|
const Type = await hc.type
|
||||||
|
|
||||||
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.rawModule.type === Type.ForgeMod || mdl.rawModule.type === Type.LiteMod || mdl.rawModule.type === Type.LiteLoader){
|
||||||
|
|
||||||
if(mdl.getRequired().value){
|
if(mdl.getRequired().value){
|
||||||
|
|
||||||
@ -749,7 +757,7 @@ function parseModulesForUI(mdls, submodules, servConf){
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
||||||
${Object.values(parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
|
${Object.values(await parseModulesForUI(mdl.subModules, true, servConf[mdl.getVersionlessMavenIdentifier()])).join('')}
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
@ -773,7 +781,7 @@ function parseModulesForUI(mdls, submodules, servConf){
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
${mdl.subModules.length > 0 ? `<div class="settingsSubModContainer">
|
||||||
${Object.values(parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
|
${Object.values(await parseModulesForUI(mdl.subModules, true, conf.mods)).join('')}
|
||||||
</div>` : ''}
|
</div>` : ''}
|
||||||
</div>`
|
</div>`
|
||||||
|
|
||||||
@ -1397,8 +1405,7 @@ const settingsAboutChangelogButton = settingsTabAbout.getElementsByClassName('se
|
|||||||
|
|
||||||
// Bind the devtools toggle button.
|
// Bind the devtools toggle button.
|
||||||
document.getElementById('settingsAboutDevToolsButton').onclick = (e) => {
|
document.getElementById('settingsAboutDevToolsButton').onclick = (e) => {
|
||||||
let window = remote.getCurrentWindow()
|
xwindow.toggleDevTools()
|
||||||
window.toggleDevTools()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1438,7 +1445,7 @@ function populateVersionInformation(version, valueElement, titleElement, checkEl
|
|||||||
* Retrieve the version information and display it on the UI.
|
* Retrieve the version information and display it on the UI.
|
||||||
*/
|
*/
|
||||||
function populateAboutVersionInformation(){
|
function populateAboutVersionInformation(){
|
||||||
populateVersionInformation(remote.app.getVersion(), document.getElementById('settingsAboutCurrentVersionValue'), document.getElementById('settingsAboutCurrentVersionTitle'), document.getElementById('settingsAboutCurrentVersionCheck'))
|
populateVersionInformation(app.getVersion(), document.getElementById('settingsAboutCurrentVersionValue'), document.getElementById('settingsAboutCurrentVersionTitle'), document.getElementById('settingsAboutCurrentVersionCheck'))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1447,9 +1454,9 @@ function populateAboutVersionInformation(){
|
|||||||
*/
|
*/
|
||||||
function populateReleaseNotes(){
|
function populateReleaseNotes(){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'https://git.onimai.ru/ONIMAI-SMP/Launcher/releases.atom',
|
url: 'https://github.com/dscalzi/HeliosLauncher/releases.atom',
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
const version = 'v' + remote.app.getVersion()
|
const version = 'v' + app.getVersion()
|
||||||
const entries = $(data).find('entry')
|
const entries = $(data).find('entry')
|
||||||
|
|
||||||
for(let i=0; i<entries.length; i++){
|
for(let i=0; i<entries.length; i++){
|
||||||
@ -1531,7 +1538,7 @@ function populateSettingsUpdateInformation(data){
|
|||||||
} else {
|
} else {
|
||||||
settingsUpdateTitle.innerHTML = Lang.queryJS('settings.updates.latestVersionTitle')
|
settingsUpdateTitle.innerHTML = Lang.queryJS('settings.updates.latestVersionTitle')
|
||||||
settingsUpdateChangelogCont.style.display = 'none'
|
settingsUpdateChangelogCont.style.display = 'none'
|
||||||
populateVersionInformation(remote.app.getVersion(), settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
|
populateVersionInformation(app.getVersion(), settingsUpdateVersionValue, settingsUpdateVersionTitle, settingsUpdateVersionCheck)
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.checkForUpdatesButton'), false, () => {
|
settingsUpdateButtonStatus(Lang.queryJS('settings.updates.checkForUpdatesButton'), false, () => {
|
||||||
if(!isDev){
|
if(!isDev){
|
||||||
ipcRenderer.send('autoUpdateAction', 'checkForUpdate')
|
ipcRenderer.send('autoUpdateAction', 'checkForUpdate')
|
||||||
|
@ -2,28 +2,12 @@
|
|||||||
* 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
|
|
||||||
const path = require('path')
|
|
||||||
const { Type } = require('helios-distribution-types')
|
|
||||||
|
|
||||||
const AuthManager = require('./assets/js/authmanager')
|
import { VIEWS } from './views.js'
|
||||||
const ConfigManager = require('./assets/js/configmanager')
|
|
||||||
const { DistroAPI } = require('./assets/js/distromanager')
|
|
||||||
|
|
||||||
let rscShouldLoad = false
|
let rscShouldLoad = false
|
||||||
let fatalStartupError = false
|
let fatalStartupError = false
|
||||||
|
|
||||||
// Mapping of each view to their container IDs.
|
|
||||||
const VIEWS = {
|
|
||||||
landing: '#landingContainer',
|
|
||||||
loginOptions: '#loginOptionsContainer',
|
|
||||||
loginOffline: '#loginOfflineContainer',
|
|
||||||
login: '#loginContainer',
|
|
||||||
settings: '#settingsContainer',
|
|
||||||
welcome: '#welcomeContainer',
|
|
||||||
waiting: '#waitingContainer'
|
|
||||||
}
|
|
||||||
|
|
||||||
// The currently shown view container.
|
// The currently shown view container.
|
||||||
let currentView
|
let currentView
|
||||||
|
|
||||||
@ -120,8 +104,7 @@ function showFatalStartupError(){
|
|||||||
Lang.queryJS('uibinder.startup.closeButton')
|
Lang.queryJS('uibinder.startup.closeButton')
|
||||||
)
|
)
|
||||||
setOverlayHandler(() => {
|
setOverlayHandler(() => {
|
||||||
const window = remote.getCurrentWindow()
|
xwindow.close()
|
||||||
window.close()
|
|
||||||
})
|
})
|
||||||
toggleOverlay(true)
|
toggleOverlay(true)
|
||||||
})
|
})
|
||||||
@ -146,9 +129,10 @@ function onDistroRefresh(data){
|
|||||||
*
|
*
|
||||||
* @param {Object} data The distro index object.
|
* @param {Object} data The distro index object.
|
||||||
*/
|
*/
|
||||||
function syncModConfigurations(data){
|
async function syncModConfigurations(data){
|
||||||
|
|
||||||
const syncedCfgs = []
|
const syncedCfgs = []
|
||||||
|
const Type = await hc.type
|
||||||
|
|
||||||
for(let serv of data.servers){
|
for(let serv of data.servers){
|
||||||
|
|
||||||
@ -164,7 +148,7 @@ function syncModConfigurations(data){
|
|||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.rawModule.type
|
const type = mdl.rawModule.type
|
||||||
|
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
if(!mdl.getRequired().value){
|
if(!mdl.getRequired().value){
|
||||||
const mdlID = mdl.getVersionlessMavenIdentifier()
|
const mdlID = mdl.getVersionlessMavenIdentifier()
|
||||||
if(modsOld[mdlID] == null){
|
if(modsOld[mdlID] == null){
|
||||||
@ -199,7 +183,7 @@ function syncModConfigurations(data){
|
|||||||
|
|
||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.rawModule.type
|
const type = mdl.rawModule.type
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
if(!mdl.getRequired().value){
|
if(!mdl.getRequired().value){
|
||||||
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
} else {
|
} else {
|
||||||
@ -254,7 +238,7 @@ function scanOptionalSubModules(mdls, origin){
|
|||||||
for(let mdl of mdls){
|
for(let mdl of mdls){
|
||||||
const type = mdl.rawModule.type
|
const type = mdl.rawModule.type
|
||||||
// Optional types.
|
// Optional types.
|
||||||
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader || type === Type.FabricMod){
|
if(type === Type.ForgeMod || type === Type.LiteMod || type === Type.LiteLoader){
|
||||||
// It is optional.
|
// It is optional.
|
||||||
if(!mdl.getRequired().value){
|
if(!mdl.getRequired().value){
|
||||||
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
mods[mdl.getVersionlessMavenIdentifier()] = scanOptionalSubModules(mdl.subModules, mdl)
|
||||||
@ -440,7 +424,7 @@ document.addEventListener('readystatechange', async () => {
|
|||||||
ipcRenderer.on('distributionIndexDone', async (event, res) => {
|
ipcRenderer.on('distributionIndexDone', async (event, res) => {
|
||||||
if(res) {
|
if(res) {
|
||||||
const data = await DistroAPI.getDistribution()
|
const data = await DistroAPI.getDistribution()
|
||||||
syncModConfigurations(data)
|
await syncModConfigurations(data)
|
||||||
ensureJavaSettings(data)
|
ensureJavaSettings(data)
|
||||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||||
await showMainUI(data)
|
await showMainUI(data)
|
||||||
@ -463,5 +447,5 @@ async function devModeToggle() {
|
|||||||
const data = await DistroAPI.refreshDistributionOrFallback()
|
const data = await DistroAPI.refreshDistributionOrFallback()
|
||||||
ensureJavaSettings(data)
|
ensureJavaSettings(data)
|
||||||
updateSelectedServer(data.servers[0])
|
updateSelectedServer(data.servers[0])
|
||||||
syncModConfigurations(data)
|
await syncModConfigurations(data)
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { VIEWS } from './views.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core UI functions are initialized in this file. This prevents
|
* Core UI functions are initialized in this file. This prevents
|
||||||
* unexpected errors from breaking the core features. Specifically,
|
* unexpected errors from breaking the core features. Specifically,
|
||||||
@ -5,58 +7,41 @@
|
|||||||
* modules, excluding dependencies.
|
* modules, excluding dependencies.
|
||||||
*/
|
*/
|
||||||
// Requirements
|
// Requirements
|
||||||
const $ = require('jquery')
|
// const { ipcRenderer } = require('electron')
|
||||||
const {ipcRenderer, shell, webFrame} = require('electron')
|
const isDev = await window.api.app.isDev()
|
||||||
const remote = require('@electron/remote')
|
// const { LoggerUtil } = require('helios-core')
|
||||||
const isDev = require('./assets/js/isdev')
|
// const Lang = require('./assets/js/langloader')
|
||||||
const { LoggerUtil } = require('helios-core')
|
|
||||||
const Lang = require('./assets/js/langloader')
|
|
||||||
|
|
||||||
const loggerUICore = LoggerUtil.getLogger('UICore')
|
// const loggerUICore = LoggerUtil.getLogger('UICore')
|
||||||
const loggerAutoUpdater = LoggerUtil.getLogger('AutoUpdater')
|
// const loggerAutoUpdater = LoggerUtil.getLogger('AutoUpdater')
|
||||||
|
|
||||||
// Log deprecation and process warnings.
|
|
||||||
process.traceProcessWarnings = true
|
|
||||||
process.traceDeprecation = true
|
|
||||||
|
|
||||||
// Disable eval function.
|
// Disable eval function.
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
window.eval = global.eval = function () {
|
window.eval = function () {
|
||||||
throw new Error('Sorry, this app does not support window.eval().')
|
throw new Error('Sorry, this app does not support window.eval().')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display warning when devtools window is opened.
|
|
||||||
remote.getCurrentWebContents().on('devtools-opened', () => {
|
|
||||||
console.log('%cThe console is dark and full of terrors.', 'color: white; -webkit-text-stroke: 4px #a02d2a; font-size: 60px; font-weight: bold')
|
|
||||||
console.log('%cIf you\'ve been told to paste something here, you\'re being scammed.', 'font-size: 16px')
|
|
||||||
console.log('%cUnless you know exactly what you\'re doing, close this window.', 'font-size: 16px')
|
|
||||||
})
|
|
||||||
|
|
||||||
// Disable zoom, needed for darwin.
|
|
||||||
webFrame.setZoomLevel(0)
|
|
||||||
webFrame.setVisualZoomLevelLimits(1, 1)
|
|
||||||
|
|
||||||
// Initialize auto updates in production environments.
|
// Initialize auto updates in production environments.
|
||||||
let updateCheckListener
|
let updateCheckListener
|
||||||
if(!isDev){
|
if(!isDev){
|
||||||
ipcRenderer.on('autoUpdateNotification', (event, arg, info) => {
|
ipcRenderer.on('autoUpdateNotification', (event, arg, info) => {
|
||||||
switch(arg){
|
switch(arg){
|
||||||
case 'checking-for-update':
|
case 'checking-for-update':
|
||||||
loggerAutoUpdater.info('Checking for update..')
|
// loggerAutoUpdater.info('Checking for update..')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkingForUpdateButton'), true)
|
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkingForUpdateButton'), true)
|
||||||
break
|
break
|
||||||
case 'update-available':
|
case 'update-available':
|
||||||
loggerAutoUpdater.info('New update available', info.version)
|
// loggerAutoUpdater.info('New update available', info.version)
|
||||||
|
|
||||||
if(process.platform === 'darwin'){
|
if(process.platform() === 'darwin'){
|
||||||
info.darwindownload = `https://git.onimai.ru/ONIMAI-SMP/Launcher/releases/download/v${info.version}/ONIMAI.RU-MC-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`
|
||||||
showUpdateUI(info)
|
showUpdateUI(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
populateSettingsUpdateInformation(info)
|
populateSettingsUpdateInformation(info)
|
||||||
break
|
break
|
||||||
case 'update-downloaded':
|
case 'update-downloaded':
|
||||||
loggerAutoUpdater.info('Update ' + info.version + ' ready to be installed.')
|
// loggerAutoUpdater.info('Update ' + info.version + ' ready to be installed.')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.installNowButton'), false, () => {
|
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.installNowButton'), false, () => {
|
||||||
if(!isDev){
|
if(!isDev){
|
||||||
ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
|
ipcRenderer.send('autoUpdateAction', 'installUpdateNow')
|
||||||
@ -65,7 +50,7 @@ if(!isDev){
|
|||||||
showUpdateUI(info)
|
showUpdateUI(info)
|
||||||
break
|
break
|
||||||
case 'update-not-available':
|
case 'update-not-available':
|
||||||
loggerAutoUpdater.info('No new update found.')
|
// loggerAutoUpdater.info('No new update found.')
|
||||||
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkForUpdatesButton'))
|
settingsUpdateButtonStatus(Lang.queryJS('uicore.autoUpdate.checkForUpdatesButton'))
|
||||||
break
|
break
|
||||||
case 'ready':
|
case 'ready':
|
||||||
@ -77,17 +62,17 @@ 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.info('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.info('No releases found.')
|
||||||
} else {
|
} else {
|
||||||
loggerAutoUpdater.error('Error during update check..', info)
|
// loggerAutoUpdater.error('Error during update check..', info)
|
||||||
loggerAutoUpdater.debug('Error Code:', info.code)
|
// loggerAutoUpdater.debug('Error Code:', info.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
loggerAutoUpdater.info('Unknown argument', arg)
|
// loggerAutoUpdater.info('Unknown argument', arg)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -133,26 +118,22 @@ $(function(){
|
|||||||
loggerUICore.info('UICore Initialized');
|
loggerUICore.info('UICore Initialized');
|
||||||
})*/
|
})*/
|
||||||
|
|
||||||
document.addEventListener('readystatechange', function () {
|
// loggerUICore.info('UICore Initializing..')
|
||||||
if (document.readyState === 'interactive'){
|
|
||||||
loggerUICore.info('UICore Initializing..')
|
|
||||||
|
|
||||||
// Bind close button.
|
// Bind close button.
|
||||||
Array.from(document.getElementsByClassName('fCb')).map((val) => {
|
Array.from(document.getElementsByClassName('fCb')).map((val) => {
|
||||||
val.addEventListener('click', e => {
|
val.addEventListener('click', async e => {
|
||||||
const window = remote.getCurrentWindow()
|
await window.api.xwindow.close()
|
||||||
window.close()
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// Bind restore down button.
|
// Bind restore down button.
|
||||||
Array.from(document.getElementsByClassName('fRb')).map((val) => {
|
Array.from(document.getElementsByClassName('fRb')).map((val) => {
|
||||||
val.addEventListener('click', e => {
|
val.addEventListener('click', async e => {
|
||||||
const window = remote.getCurrentWindow()
|
if(await window.api.xwindow.isMaximized()){
|
||||||
if(window.isMaximized()){
|
await window.api.xwindow.unmaximize()
|
||||||
window.unmaximize()
|
|
||||||
} else {
|
} else {
|
||||||
window.maximize()
|
await window.api.xwindow.maximize()
|
||||||
}
|
}
|
||||||
document.activeElement.blur()
|
document.activeElement.blur()
|
||||||
})
|
})
|
||||||
@ -160,9 +141,9 @@ document.addEventListener('readystatechange', function () {
|
|||||||
|
|
||||||
// Bind minimize button.
|
// Bind minimize button.
|
||||||
Array.from(document.getElementsByClassName('fMb')).map((val) => {
|
Array.from(document.getElementsByClassName('fMb')).map((val) => {
|
||||||
val.addEventListener('click', e => {
|
val.addEventListener('click', async e => {
|
||||||
const window = remote.getCurrentWindow()
|
console.log('hi')
|
||||||
window.minimize()
|
await window.api.xwindow.minimize()
|
||||||
document.activeElement.blur()
|
document.activeElement.blur()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -174,8 +155,6 @@ document.addEventListener('readystatechange', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
} else if(document.readyState === 'complete'){
|
|
||||||
|
|
||||||
//266.01
|
//266.01
|
||||||
//170.8
|
//170.8
|
||||||
//53.21
|
//53.21
|
||||||
@ -189,16 +168,12 @@ document.addEventListener('readystatechange', function () {
|
|||||||
document.getElementById('launch_details_right').style.maxWidth = 170.8
|
document.getElementById('launch_details_right').style.maxWidth = 170.8
|
||||||
document.getElementById('launch_progress_label').style.width = 53.21
|
document.getElementById('launch_progress_label').style.width = 53.21
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}, false)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open web links in the user's default browser.
|
* Open web links in the user's default browser.
|
||||||
*/
|
*/
|
||||||
$(document).on('click', 'a[href^="http"]', function(event) {
|
$(document).on('click', 'a[href^="http"]', async (event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
shell.openExternal(this.href)
|
await window.api.shell.openExternal(this.href)
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -206,9 +181,8 @@ $(document).on('click', 'a[href^="http"]', function(event) {
|
|||||||
* This will crash the program if you are using multiple
|
* This will crash the program if you are using multiple
|
||||||
* DevTools, for example the chrome debugger in VS Code.
|
* DevTools, for example the chrome debugger in VS Code.
|
||||||
*/
|
*/
|
||||||
document.addEventListener('keydown', function (e) {
|
document.addEventListener('keydown', async (e) => {
|
||||||
if((e.key === 'I' || e.key === 'i') && e.ctrlKey && e.shiftKey){
|
if((e.key === 'I' || e.key === 'i') && e.ctrlKey && e.shiftKey){
|
||||||
let window = remote.getCurrentWindow()
|
await window.api.xwindow.toggleDevTools()
|
||||||
window.toggleDevTools()
|
|
||||||
}
|
}
|
||||||
})
|
})
|
9
app/assets/js/scripts/views.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Mapping of each view to their container IDs.
|
||||||
|
export const VIEWS = {
|
||||||
|
landing: '#landingContainer',
|
||||||
|
loginOptions: '#loginOptionsContainer',
|
||||||
|
login: '#loginContainer',
|
||||||
|
settings: '#settingsContainer',
|
||||||
|
welcome: '#welcomeContainer',
|
||||||
|
waiting: '#waitingContainer'
|
||||||
|
}
|
@ -1,3 +1,5 @@
|
|||||||
|
import { VIEWS } from './views.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Script for welcome.ejs
|
* Script for welcome.ejs
|
||||||
*/
|
*/
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
# Custom Language File for Launcher Customizer
|
# Custom Language File for Launcher Customizer
|
||||||
|
|
||||||
[ejs.app]
|
[ejs.app]
|
||||||
title = "ONIMAI.RU MC Launcher"
|
title = "Helios Launcher"
|
||||||
|
|
||||||
[ejs.landing]
|
[ejs.landing]
|
||||||
mediaGitHubURL = "https://onimai.ru"
|
mediaGitHubURL = "https://github.com/dscalzi/HeliosLauncher"
|
||||||
mediaTwitterURL = "#"
|
mediaTwitterURL = "#"
|
||||||
mediaInstagramURL = "#"
|
mediaInstagramURL = "#"
|
||||||
mediaYouTubeURL = "#"
|
mediaYouTubeURL = "#"
|
||||||
mediaDiscordURL = "https://ds.onimai.ru"
|
mediaDiscordURL = "https://discord.gg/zNWUXdt"
|
||||||
|
|
||||||
[ejs.settings]
|
[ejs.settings]
|
||||||
sourceGithubLink = "https://git.onimai.ru/ONIMAI-SMP/Launcher"
|
sourceGithubLink = "https://github.com/dscalZi/HeliosLauncher"
|
||||||
supportLink = "https://git.onimai.ru/ONIMAI-SMP/Launcher/issues"
|
supportLink = "https://github.com/dscalZi/HeliosLauncher/issues"
|
||||||
|
|
||||||
[ejs.welcome]
|
[ejs.welcome]
|
||||||
welcomeHeader = "ДОБРО ПОЖАЛОВАТЬ!"
|
welcomeHeader = "WELCOME TO WESTEROSCRAFT"
|
||||||
welcomeDescription = "Спасибо что скачали наш лаунчер! В первую очередь он предназначен для удобной игры на наших серверах. С данным лаунчером вы сможете не ебаться с ручным обновлением, а обновлять сборку одним нажатием кнопки. Удачной игры"
|
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 = "Пара нажатий и ты на сервере"
|
welcomeDescCTA = "You are just a few clicks away from Westeros."
|
||||||
|
@ -1,317 +1,297 @@
|
|||||||
[ejs.landing]
|
[ejs.landing]
|
||||||
updateAvailableTooltip = "Доступно обновление"
|
updateAvailableTooltip = "Update Available"
|
||||||
usernamePlaceholder = "Имя пользователя"
|
usernamePlaceholder = "Username"
|
||||||
usernameEditButton = "Редактировать"
|
usernameEditButton = "Edit"
|
||||||
settingsTooltip = "Настройки"
|
settingsTooltip = "Settings"
|
||||||
serverStatus = "СЕРВЕР"
|
serverStatus = "SERVER"
|
||||||
serverStatusPlaceholder = "ОФФЛАЙН"
|
serverStatusPlaceholder = "OFFLINE"
|
||||||
mojangStatus = "СТАТУС MOJANG"
|
mojangStatus = "MOJANG STATUS"
|
||||||
mojangStatusTooltipTitle = "Сервисы"
|
mojangStatusTooltipTitle = "Services"
|
||||||
mojangStatusNETitle = "Необязательно"
|
mojangStatusNETitle = "Non Essential"
|
||||||
newsButton = "НОВОСТИ"
|
newsButton = "NEWS"
|
||||||
launchButton = "ИГРАТЬ"
|
launchButton = "PLAY"
|
||||||
launchButtonPlaceholder = "• Сервер не выбран"
|
launchButtonPlaceholder = "• No Server Selected"
|
||||||
launchDetails = "Пожалуйста, подождите.."
|
launchDetails = "Please wait.."
|
||||||
newsNavigationStatus = "{currentPage} из {totalPages}"
|
newsNavigationStatus = "{currentPage} of {totalPages}"
|
||||||
newsErrorLoadSpan = "Проверка новостей.."
|
newsErrorLoadSpan = "Checking for News.."
|
||||||
newsErrorFailedSpan = "Не удалось загрузить новости"
|
newsErrorFailedSpan = "Failed to Load News"
|
||||||
newsErrorRetryButton = "Попробовать снова"
|
newsErrorRetryButton = "Try Again"
|
||||||
newsErrorNoneSpan = "Новостей нет"
|
newsErrorNoneSpan = "No News"
|
||||||
|
|
||||||
[ejs.login]
|
[ejs.login]
|
||||||
loginCancelText = "Отмена"
|
loginCancelText = "Cancel"
|
||||||
loginSubheader = "ВХОД В MINECRAFT"
|
loginSubheader = "MINECRAFT LOGIN"
|
||||||
loginEmailError = "* Неверное значение"
|
loginEmailError = "* Invalid Value"
|
||||||
loginEmailPlaceholder = "EMAIL ИЛИ ИМЯ ПОЛЬЗОВАТЕЛЯ"
|
loginEmailPlaceholder = "EMAIL OR USERNAME"
|
||||||
loginPasswordError = "* Обязательное поле"
|
loginPasswordError = "* Required"
|
||||||
loginPasswordPlaceholder = "ПАРОЛЬ"
|
loginPasswordPlaceholder = "PASSWORD"
|
||||||
loginForgotPasswordLink = "https://minecraft.net/password/forgot/"
|
loginForgotPasswordLink = "https://minecraft.net/password/forgot/"
|
||||||
loginForgotPasswordText = "забыли пароль?"
|
loginForgotPasswordText = "forgot password?"
|
||||||
loginRememberMeText = "запомнить меня?"
|
loginRememberMeText = "remember me?"
|
||||||
loginButtonText = "ВОЙТИ"
|
loginButtonText = "LOGIN"
|
||||||
loginNeedAccountLink = "https://minecraft.net/store/minecraft-java-edition/"
|
loginNeedAccountLink = "https://minecraft.net/store/minecraft-java-edition/"
|
||||||
loginNeedAccountText = "Нужен аккаунт?"
|
loginNeedAccountText = "Need an Account?"
|
||||||
loginPasswordDisclaimer1 = "Ваш пароль отправляется напрямую в Mojang и никогда не сохраняется."
|
loginPasswordDisclaimer1 = "Your password is sent directly to mojang and never stored."
|
||||||
loginPasswordDisclaimer2 = "{appName} не связан с Mojang AB."
|
loginPasswordDisclaimer2 = "{appName} is not affiliated with Mojang AB."
|
||||||
|
|
||||||
[ejs.loginOptions]
|
[ejs.loginOptions]
|
||||||
loginOptionsTitle = "Опции входа"
|
loginOptionsTitle = "Login Options"
|
||||||
loginWithMicrosoft = "Войти через Microsoft"
|
loginWithMicrosoft = "Login with Microsoft"
|
||||||
loginWithMojang = "Войти через Mojang"
|
loginWithMojang = "Login with Mojang"
|
||||||
loginWithOffline = "Вход через Пиратку"
|
cancelButton = "Cancel"
|
||||||
cancelButton = "Отмена"
|
|
||||||
|
|
||||||
[ejs.overlay]
|
[ejs.overlay]
|
||||||
serverSelectHeader = "Доступные серверы"
|
serverSelectHeader = "Available Servers"
|
||||||
serverSelectConfirm = "Выбрать"
|
serverSelectConfirm = "Select"
|
||||||
serverSelectCancel = "Отмена"
|
serverSelectCancel = "Cancel"
|
||||||
accountSelectHeader = "Выберите аккаунт"
|
accountSelectHeader = "Select an Account"
|
||||||
accountSelectConfirm = "Выбрать"
|
accountSelectConfirm = "Select"
|
||||||
accountSelectCancel = "Отмена"
|
accountSelectCancel = "Cancel"
|
||||||
|
|
||||||
[ejs.settings]
|
[ejs.settings]
|
||||||
navHeaderText = "Настройки"
|
navHeaderText = "Settings"
|
||||||
navAccount = "Аккаунт"
|
navAccount = "Account"
|
||||||
navMinecraft = "Minecraft"
|
navMinecraft = "Minecraft"
|
||||||
navMods = "Моды"
|
navMods = "Mods"
|
||||||
navJava = "Java"
|
navJava = "Java"
|
||||||
navLauncher = "Лаунчер"
|
navLauncher = "Launcher"
|
||||||
navAbout = "О программе"
|
navAbout = "About"
|
||||||
navUpdates = "Обновления"
|
navUpdates = "Updates"
|
||||||
navDone = "Готово"
|
navDone = "Done"
|
||||||
tabAccountHeaderText = "Настройки аккаунта"
|
tabAccountHeaderText = "Account Settings"
|
||||||
tabAccountHeaderDesc = "Добавляйте новые аккаунты или управляйте существующими."
|
tabAccountHeaderDesc = "Add new accounts or manage existing ones."
|
||||||
microsoftAccount = "Microsoft"
|
microsoftAccount = "Microsoft"
|
||||||
addMicrosoftAccount = "+ Добавить аккаунт Microsoft"
|
addMicrosoftAccount = "+ Add Microsoft Account"
|
||||||
mojangAccount = "Mojang"
|
mojangAccount = "Mojang"
|
||||||
offlineAccount = "Аккаунт Пиратка"
|
addMojangAccount = "+ Add Mojang Account"
|
||||||
addMojangAccount = "+ Добавить аккаунт Mojang"
|
minecraftTabHeaderText = "Minecraft Settings"
|
||||||
minecraftTabHeaderText = "Настройки Minecraft"
|
minecraftTabHeaderDesc = "Options related to game launch."
|
||||||
minecraftTabHeaderDesc = "Параметры, связанные с запуском игры."
|
gameResolutionTitle = "Game Resolution"
|
||||||
gameResolutionTitle = "Разрешение игры"
|
launchFullscreenTitle = "Launch in fullscreen."
|
||||||
launchFullscreenTitle = "Запуск в полноэкранном режиме."
|
autoConnectTitle = "Automatically connect to the server on launch."
|
||||||
autoConnectTitle = "Автоматически подключаться к серверу при запуске."
|
launchDetachedTitle = "Launch game process detached from launcher."
|
||||||
launchDetachedTitle = "Запускать игру отдельно от лаунчера."
|
launchDetachedDesc = "If the game is not detached, closing the launcher will also close the game."
|
||||||
launchDetachedDesc = "Если игра не запущена отдельно, закрытие лаунчера приведет к закрытию игры."
|
tabModsHeaderText = "Mod Settings"
|
||||||
tabModsHeaderText = "Настройки модов"
|
tabModsHeaderDesc = "Enable or disable mods."
|
||||||
tabModsHeaderDesc = "Включайте или отключайте моды."
|
switchServerButton = "Switch"
|
||||||
switchServerButton = "Сменить сервер"
|
requiredMods = "Required Mods"
|
||||||
requiredMods = "Обязательные моды"
|
optionalMods = "Optional Mods"
|
||||||
optionalMods = "Дополнительные моды"
|
dropinMods = "Drop-in Mods"
|
||||||
dropinMods = "Установленные моды"
|
addMods = "Add Mods"
|
||||||
addMods = "Добавить моды"
|
dropinRefreshNote = "(F5 to Refresh)"
|
||||||
dropinRefreshNote = "(Нажмите F5 для обновления)"
|
shaderpacks = "Shaderpacks"
|
||||||
shaderpacks = "Шейдерпаки"
|
shaderpackDesc = "Enable or disable shaders. Please note, shaders will only run smoothly on powerful setups. You may add custom packs here."
|
||||||
shaderpackDesc = "Включайте или отключайте шейдеры. Учтите, что они требуют мощного компьютера. Вы можете добавлять собственные шейдерпаки здесь."
|
selectShaderpack = "Select Shaderpack"
|
||||||
selectShaderpack = "Выбрать шейдерпак"
|
tabJavaHeaderText = "Java Settings"
|
||||||
tabJavaHeaderText = "Настройки Java"
|
tabJavaHeaderDesc = "Manage the Java configuration (advanced)."
|
||||||
tabJavaHeaderDesc = "Управление конфигурацией Java (для продвинутых пользователей)."
|
memoryTitle = "Memory"
|
||||||
memoryTitle = "Память"
|
maxRAM = "Maximum RAM"
|
||||||
maxRAM = "Максимальный объем RAM"
|
minRAM = "Minimum RAM"
|
||||||
minRAM = "Минимальный объем RAM"
|
memoryDesc = "The recommended minimum RAM is 3 gigabytes. Setting the minimum and maximum values to the same value may reduce lag."
|
||||||
memoryDesc = "Рекомендуемый минимум RAM — 3 ГБ. Установка одинаковых значений для минимума и максимума может снизить лаги."
|
memoryTotalTitle = "Total"
|
||||||
memoryTotalTitle = "Всего"
|
memoryAvailableTitle = "Available"
|
||||||
memoryAvailableTitle = "Доступно"
|
javaExecutableTitle = "Java Executable"
|
||||||
javaExecutableTitle = "Исполняемый файл Java"
|
javaExecSelDialogTitle = "Select Java Executable"
|
||||||
javaExecSelDialogTitle = "Выберите исполняемый файл Java"
|
javaExecSelButtonText = "Choose File"
|
||||||
javaExecSelButtonText = "Выбрать файл"
|
javaExecDesc = "The Java executable is validated before game launch."
|
||||||
javaExecDesc = "Исполняемый файл Java проверяется перед запуском игры."
|
javaPathDesc = "The path should end with <strong>{pathSuffix}</strong>."
|
||||||
javaPathDesc = "Путь должен заканчиваться на <strong>{pathSuffix}</strong>."
|
jvmOptsTitle = "Additional JVM Options"
|
||||||
jvmOptsTitle = "Дополнительные параметры JVM"
|
jvmOptsDesc = "Options to be provided to the JVM at runtime. <em>-Xms</em> and <em>-Xmx</em> should not be included."
|
||||||
jvmOptsDesc = "Опции, передаваемые JVM во время выполнения. <em>-Xms</em> и <em>-Xmx</em> не должны включаться."
|
launcherTabHeaderText = "Launcher Settings"
|
||||||
launcherTabHeaderText = "Настройки лаунчера"
|
launcherTabHeaderDesc = "Options related to the launcher itself."
|
||||||
launcherTabHeaderDesc = "Параметры, связанные с самим лаунчером."
|
allowPrereleaseTitle = "Allow Pre-Release Updates."
|
||||||
allowPrereleaseTitle = "Разрешить обновления предварительных версий."
|
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."
|
||||||
allowPrereleaseDesc = "Предварительные версии включают новые функции, которые могут быть недостаточно протестированы.<br>Этот параметр всегда включен, если вы используете предварительную версию."
|
dataDirectoryTitle = "Data Directory"
|
||||||
dataDirectoryTitle = "Директория данных"
|
selectDataDirectory = "Select Data Directory"
|
||||||
selectDataDirectory = "Выбрать директорию данных"
|
chooseFolder = "Choose Folder"
|
||||||
chooseFolder = "Выбрать папку"
|
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."
|
||||||
dataDirectoryDesc = "Все игровые файлы и локальные установки Java будут храниться в этой директории.<br>Скриншоты и сохранения миров хранятся в папке экземпляра соответствующей конфигурации сервера."
|
aboutTabHeaderText = "About"
|
||||||
aboutTabHeaderText = "О программе"
|
aboutTabHeaderDesc = "View information and release notes for the current version."
|
||||||
aboutTabHeaderDesc = "Просмотр информации и заметок о текущей версии."
|
|
||||||
aboutTitle = "{appName}"
|
aboutTitle = "{appName}"
|
||||||
stableRelease = "Стабильный релиз"
|
stableRelease = "Stable Release"
|
||||||
versionText = "Версия "
|
versionText = "Version "
|
||||||
sourceGithub = "Исходный код (GitHub)"
|
sourceGithub = "Source (GitHub)"
|
||||||
support = "Поддержка"
|
support = "Support"
|
||||||
devToolsConsole = "Консоль DevTools"
|
devToolsConsole = "DevTools Console"
|
||||||
releaseNotes = "Примечания к выпуску"
|
releaseNotes = "Release Notes"
|
||||||
changelog = "История изменений"
|
changelog = "Changelog"
|
||||||
noReleaseNotes = "Нет примечаний к выпуску"
|
noReleaseNotes = "No Release Notes"
|
||||||
viewReleaseNotes = "Просмотреть примечания к выпуску на GitHub"
|
viewReleaseNotes = "View Release Notes on GitHub"
|
||||||
launcherUpdatesHeaderText = "Обновления лаунчера"
|
launcherUpdatesHeaderText = "Launcher Updates"
|
||||||
launcherUpdatesHeaderDesc = "Загрузка, установка и просмотр обновлений лаунчера."
|
launcherUpdatesHeaderDesc = "Download, install, and review updates for the launcher."
|
||||||
checkForUpdates = "Проверить обновления"
|
checkForUpdates = "Check for Updates"
|
||||||
whatsNew = "Что нового"
|
whatsNew = "What's New"
|
||||||
updateReleaseNotes = "Примечания к обновлению"
|
updateReleaseNotes = "Update Release Notes"
|
||||||
|
|
||||||
[ejs.waiting]
|
[ejs.waiting]
|
||||||
waitingText = "Ожидание Microsoft.."
|
waitingText = "Waiting for Microsoft.."
|
||||||
|
|
||||||
[ejs.welcome]
|
[ejs.welcome]
|
||||||
continueButton = "ПРОДОЛЖИТЬ"
|
continueButton = "CONTINUE"
|
||||||
|
|
||||||
|
|
||||||
[js.discord]
|
[js.discord]
|
||||||
waiting = "Ожидание клиента.."
|
waiting = "Waiting for Client.."
|
||||||
state = "Сервер: {shortId}"
|
state = "Server: {shortId}"
|
||||||
|
|
||||||
[js.index]
|
[js.index]
|
||||||
microsoftLoginTitle = "Вход через Microsoft"
|
microsoftLoginTitle = "Microsoft Login"
|
||||||
microsoftLogoutTitle = "Выход из Microsoft"
|
microsoftLogoutTitle = "Microsoft Logout"
|
||||||
|
|
||||||
[js.login]
|
[js.login]
|
||||||
login = "ВОЙТИ"
|
login = "LOGIN"
|
||||||
loggingIn = "ВХОД В СИСТЕМУ"
|
loggingIn = "LOGGING IN"
|
||||||
success = "УСПЕШНО"
|
success = "SUCCESS"
|
||||||
tryAgain = "Попробовать снова"
|
tryAgain = "Try Again"
|
||||||
|
|
||||||
[js.login.error]
|
[js.login.error]
|
||||||
invalidValue = "* Неверное значение"
|
invalidValue = "* Invalid Value"
|
||||||
requiredValue = "* Обязательное поле"
|
requiredValue = "* Required"
|
||||||
|
|
||||||
[js.login.error.unknown]
|
[js.login.error.unknown]
|
||||||
title = "Неизвестная ошибка при входе"
|
title = "Unknown Error During Login"
|
||||||
desc = "Произошла неизвестная ошибка. Подробности можно посмотреть в консоли."
|
desc = "An unknown error has occurred. Please see the console for details."
|
||||||
|
|
||||||
[js.landing.launch]
|
[js.landing.launch]
|
||||||
pleaseWait = "Пожалуйста, подождите.."
|
pleaseWait = "Please wait.."
|
||||||
failureTitle = "Ошибка при запуске"
|
failureTitle = "Error During Launch"
|
||||||
failureText = "Смотрите консоль (CTRL + Shift + I) для подробностей."
|
failureText = "See console (CTRL + Shift + i) for more details."
|
||||||
okay = "ОК"
|
okay = "Okay"
|
||||||
|
|
||||||
[js.landing.selectedAccount]
|
[js.landing.selectedAccount]
|
||||||
noAccountSelected = "Аккаунт не выбран"
|
noAccountSelected = "No Account Selected"
|
||||||
|
|
||||||
[js.landing.selectedServer]
|
[js.landing.selectedServer]
|
||||||
noSelection = "Сервер не выбран"
|
noSelection = "No Server Selected"
|
||||||
loading = "Загрузка.."
|
loading = "Loading.."
|
||||||
|
|
||||||
[js.landing.serverStatus]
|
[js.landing.serverStatus]
|
||||||
server = "СЕРВЕР"
|
server = "SERVER"
|
||||||
offline = "ОФФЛАЙН"
|
offline = "OFFLINE"
|
||||||
players = "ИГРОКИ"
|
players = "PLAYERS"
|
||||||
|
|
||||||
[js.landing.systemScan]
|
[js.landing.systemScan]
|
||||||
checking = "Проверка информации о системе.."
|
checking = "Checking system info.."
|
||||||
noCompatibleJava = "Совместимая<br>установка Java не найдена"
|
noCompatibleJava = "No Compatible<br>Java Installation Found"
|
||||||
installJavaMessage = "Для запуска Minecraft требуется 64-битная версия Java {major}. Установить её сейчас?"
|
installJavaMessage = "In order to launch Minecraft, you need a 64-bit installation of Java {major}. Would you like us to install a copy?"
|
||||||
installJava = "Установить Java"
|
installJava = "Install Java"
|
||||||
installJavaManually = "Установить вручную"
|
installJavaManually = "Install Manually"
|
||||||
javaDownloadPrepare = "Подготовка загрузки Java.."
|
javaDownloadPrepare = "Preparing Java Download.."
|
||||||
javaDownloadFailureTitle = "Ошибка загрузки Java"
|
javaDownloadFailureTitle = "Error During Java Download"
|
||||||
javaDownloadFailureText = "Смотрите консоль (CTRL + Shift + I) для подробностей."
|
javaDownloadFailureText = "See console (CTRL + Shift + i) for more details."
|
||||||
javaRequired = "Для запуска требуется Java"
|
javaRequired = "Java is Required<br>to Launch"
|
||||||
javaRequiredMessage = "Для запуска необходима действительная 64-битная установка Java {major}.<br><br>Пожалуйста, ознакомьтесь с нашим <a href=\"https://github.com/dscalzi/HeliosLauncher/wiki/Java-Management#manually-installing-a-valid-version-of-java\">Руководством по управлению Java</a>, чтобы установить её вручную."
|
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 = "Понял"
|
javaRequiredDismiss = "I Understand"
|
||||||
javaRequiredCancel = "Назад"
|
javaRequiredCancel = "Go Back"
|
||||||
|
|
||||||
[js.landing.downloadJava]
|
[js.landing.downloadJava]
|
||||||
findJdkFailure = "Не удалось найти дистрибутив OpenJDK."
|
findJdkFailure = "Failed to find OpenJDK distribution."
|
||||||
javaDownloadCorruptedError = "Загруженный JDK поврежден, файл может быть испорчен."
|
javaDownloadCorruptedError = "Downloaded JDK has a bad hash, the file may be corrupted."
|
||||||
extractingJava = "Распаковка Java"
|
extractingJava = "Extracting Java"
|
||||||
javaInstalled = "Java установлена!"
|
javaInstalled = "Java Installed!"
|
||||||
|
|
||||||
[js.landing.dlAsync]
|
[js.landing.dlAsync]
|
||||||
loadingServerInfo = "Загрузка информации о сервере.."
|
loadingServerInfo = "Loading server information.."
|
||||||
fatalError = "Критическая ошибка"
|
fatalError = "Fatal Error"
|
||||||
unableToLoadDistributionIndex = "Не удалось загрузить индекс дистрибуции. Смотрите консоль (CTRL + Shift + I) для подробностей."
|
unableToLoadDistributionIndex = "Could not load a copy of the distribution index. See the console (CTRL + Shift + i) for more details."
|
||||||
pleaseWait = "Пожалуйста, подождите.."
|
pleaseWait = "Please wait.."
|
||||||
errorDuringLaunchTitle = "Ошибка при запуске"
|
errorDuringLaunchTitle = "Error During Launch"
|
||||||
seeConsoleForDetails = "Смотрите консоль (CTRL + Shift + I) для подробностей."
|
seeConsoleForDetails = "See console (CTRL + Shift + i) for more details."
|
||||||
validatingFileIntegrity = "Проверка целостности файлов.."
|
validatingFileIntegrity = "Validating file integrity.."
|
||||||
errorDuringFileVerificationTitle = "Ошибка при проверке файлов"
|
errorDuringFileVerificationTitle = "Error During File Verification"
|
||||||
downloadingFiles = "Загрузка файлов.."
|
downloadingFiles = "Downloading files.."
|
||||||
errorDuringFileDownloadTitle = "Ошибка при загрузке файлов"
|
errorDuringFileDownloadTitle = "Error During File Download"
|
||||||
preparingToLaunch = "Подготовка к запуску.."
|
preparingToLaunch = "Preparing to launch.."
|
||||||
launchingGame = "Запуск игры.."
|
launchingGame = "Launching game.."
|
||||||
launchWrapperNotDownloaded = "Основной файл, LaunchWrapper, не был загружен должным образом. В результате игра не может быть запущена.<br><br>Чтобы исправить эту проблему, временно отключите антивирусное ПО и попробуйте снова.<br><br>Если у вас есть время, пожалуйста, <a href=\"https://github.com/dscalzi/HeliosLauncher/issues\">сообщите об этой проблеме</a> и укажите, каким антивирусом вы пользуетесь. Мы постараемся связаться с разработчиками антивируса и решить проблему."
|
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 = "Готово. Наслаждайтесь сервером!"
|
doneEnjoyServer = "Done. Enjoy the server!"
|
||||||
checkConsoleForDetails = "Пожалуйста, проверьте консоль (CTRL + Shift + I) для подробностей."
|
checkConsoleForDetails = "Please check the console (CTRL + Shift + i) for more details."
|
||||||
|
|
||||||
[js.landing.news]
|
[js.landing.news]
|
||||||
checking = "Проверка новостей"
|
checking = "Checking for News"
|
||||||
|
|
||||||
[js.landing.discord]
|
[js.landing.discord]
|
||||||
loading = "Загрузка игры.."
|
loading = "Loading game.."
|
||||||
joining = "Путешествие в Вестерос!"
|
joining = "Sailing to Westeros!"
|
||||||
joined = "Исследование мира!"
|
joined = "Exploring the Realm!"
|
||||||
|
|
||||||
[js.overlay]
|
[js.overlay]
|
||||||
dismiss = "Закрыть"
|
dismiss = "Dismiss"
|
||||||
|
|
||||||
[js.settings.fileSelectors]
|
[js.settings.fileSelectors]
|
||||||
executables = "Исполняемые файлы"
|
executables = "Executables"
|
||||||
allFiles = "Все файлы"
|
allFiles = "All Files"
|
||||||
|
|
||||||
[js.settings.mstfLogin]
|
[js.settings.mstfLogin]
|
||||||
errorTitle = "Что-то пошло не так"
|
errorTitle = "Something Went Wrong"
|
||||||
errorMessage = "Ошибка аутентификации Microsoft. Попробуйте еще раз."
|
errorMessage = "Microsoft authentication failed. Please try again."
|
||||||
okButton = "ОК"
|
okButton = "OK"
|
||||||
|
|
||||||
[js.settings.mstfLogout]
|
[js.settings.mstfLogout]
|
||||||
errorTitle = "Что-то пошло не так"
|
errorTitle = "Something Went Wrong"
|
||||||
errorMessage = "Ошибка выхода из Microsoft. Попробуйте еще раз."
|
errorMessage = "Microsoft logout failed. Please try again."
|
||||||
okButton = "ОК"
|
okButton = "OK"
|
||||||
|
|
||||||
[js.settings.dropinMods]
|
|
||||||
removeButton = "Удалить"
|
|
||||||
deleteFailedTitle = "Ошибка удаления<br>мода {fullName}"
|
|
||||||
deleteFailedMessage = "Убедитесь, что файл не используется, и попробуйте снова."
|
|
||||||
failedToggleTitle = "Ошибка переключения<br>одного или нескольких установленных модов"
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.serverListing]
|
|
||||||
mainServer = "Основной сервер"
|
|
||||||
|
|
||||||
[js.settings.java]
|
|
||||||
selectedJava = "Выбрано: Java {version} ({vendor})"
|
|
||||||
invalidSelection = "Некорректный выбор"
|
|
||||||
requiresJava = "Требуется Java {major} x64."
|
|
||||||
availableOptions = "Доступные версии Java {major} (HotSpot VM)"
|
|
||||||
|
|
||||||
[js.settings.about]
|
|
||||||
preReleaseTitle = "Предварительная версия"
|
|
||||||
stableReleaseTitle = "Стабильная версия"
|
|
||||||
releaseNotesFailed = "Не удалось загрузить примечания к выпуску."
|
|
||||||
|
|
||||||
[js.settings.updates]
|
|
||||||
newReleaseTitle = "Доступно новое обновление"
|
|
||||||
newPreReleaseTitle = "Доступна новая предварительная версия"
|
|
||||||
downloadingButton = "Загрузка.."
|
|
||||||
downloadButton = 'Загрузить с GitHub<span style="font-size: 10px;color: gray;text-shadow: none !important;">Закройте лаунчер и запустите установщик для обновления.</span>'
|
|
||||||
latestVersionTitle = "У вас установлена последняя версия"
|
|
||||||
checkForUpdatesButton = "Проверить обновления"
|
|
||||||
checkingForUpdatesButton = "Проверка обновлений.."
|
|
||||||
|
|
||||||
[js.settings.msftLogin]
|
|
||||||
errorTitle = "Ошибка входа в Microsoft"
|
|
||||||
errorMessage = "Не удалось выполнить аутентификацию в Microsoft. Попробуйте снова."
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.authAccountSelect]
|
[js.settings.authAccountSelect]
|
||||||
selectButton = "Выбрать аккаунт"
|
selectButton = "Select Account"
|
||||||
selectedButton = "Выбранный аккаунт ✔"
|
selectedButton = "Selected Account ✔"
|
||||||
|
|
||||||
[js.settings.authAccountLogout]
|
[js.settings.authAccountLogout]
|
||||||
lastAccountWarningTitle = "Внимание<br>Это ваш последний аккаунт"
|
lastAccountWarningTitle = "Warning<br>This is Your Last Account"
|
||||||
lastAccountWarningMessage = "Для использования лаунчера необходимо быть авторизованным хотя бы в одном аккаунте. После выхода вам придется войти снова.<br><br>Вы уверены, что хотите выйти?"
|
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 = "Я уверен"
|
confirmButton = "I'm Sure"
|
||||||
cancelButton = "Отмена"
|
cancelButton = "Cancel"
|
||||||
|
|
||||||
[js.settings.authAccountPopulate]
|
[js.settings.authAccountPopulate]
|
||||||
username = "Имя пользователя"
|
username = "Username"
|
||||||
uuid = "UUID"
|
uuid = "UUID"
|
||||||
selectAccount = "Выбрать аккаунт"
|
selectAccount = "Select Account"
|
||||||
selectedAccount = "Выбранный аккаунт ✓"
|
selectedAccount = "Selected Account ✓"
|
||||||
logout = "Выйти"
|
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]
|
[js.uibinder.startup]
|
||||||
fatalErrorTitle = "Критическая ошибка: невозможно загрузить индекс дистрибуции"
|
fatalErrorTitle = "Fatal Error: Unable to Load Distribution Index"
|
||||||
fatalErrorMessage = "Не удалось установить соединение с нашими серверами для загрузки индекса дистрибуции. Локальные копии отсутствуют.<br><br>Индекс дистрибуции — это важный файл, который содержит актуальную информацию о сервере. Лаунчер не сможет запуститься без него. Убедитесь, что у вас есть подключение к интернету, и перезапустите приложение."
|
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 = "Закрыть"
|
closeButton = "Close"
|
||||||
|
|
||||||
[js.uibinder.validateAccount]
|
[js.uibinder.validateAccount]
|
||||||
failedMessageTitle = "Ошибка обновления входа"
|
failedMessageTitle = "Failed to Refresh Login"
|
||||||
failedMessage = "Не удалось обновить вход для <strong>{account}</strong>. Пожалуйста, выберите другой аккаунт или войдите снова."
|
failedMessage = "We were unable to refresh the login for <strong>{account}</strong>. Please select another account or login again."
|
||||||
failedMessageSelectAnotherAccount = "Не удалось обновить вход для <strong>{account}</strong>. Пожалуйста, войдите снова."
|
failedMessageSelectAnotherAccount = "We were unable to refresh the login for <strong>{account}</strong>. Please login again."
|
||||||
loginButton = "Войти"
|
loginButton = "Login"
|
||||||
selectAnotherAccountButton = "Выбрать другой аккаунт"
|
selectAnotherAccountButton = "Select Another Account"
|
||||||
|
|
||||||
[js.uicore.autoUpdate]
|
[js.uicore.autoUpdate]
|
||||||
checkingForUpdateButton = "Проверка обновлений..."
|
checkingForUpdateButton = "Checking for Updates..."
|
||||||
installNowButton = "Установить сейчас"
|
installNowButton = "Install Now"
|
||||||
checkForUpdatesButton = "Проверить обновления"
|
checkForUpdatesButton = "Check for Updates"
|
||||||
|
|
||||||
[js.auth.microsoft.error]
|
|
||||||
noProfileTitle = "Ошибка входа:<br>Профиль не настроен"
|
|
||||||
noProfileDesc = "Ваш аккаунт Microsoft еще не имеет профиля Minecraft. Если вы недавно купили игру или активировали ее через Xbox Game Pass, вам нужно настроить профиль на <a href=\"https://minecraft.net/\">Minecraft.net</a>.<br><br>Если вы еще не купили игру, вы можете сделать это на <a href=\"https://minecraft.net/\">Minecraft.net</a>."
|
|
||||||
noXboxAccountTitle = "Ошибка входа:<br>Нет аккаунта Xbox"
|
|
||||||
noXboxAccountDesc = "У вашей учетной записи Microsoft нет привязанного аккаунта Xbox."
|
|
||||||
xblBannedTitle = "Ошибка входа:<br>Xbox Live недоступен"
|
|
||||||
xblBannedDesc = "Ваш аккаунт Microsoft зарегистрирован в стране, где Xbox Live недоступен или заблокирован."
|
|
||||||
under18Title = "Ошибка входа:<br>Требуется родительское разрешение"
|
|
||||||
under18Desc = "Аккаунты пользователей младше 18 лет должны быть добавлены в «Семью» взрослым."
|
|
||||||
unknownTitle = "Неизвестная ошибка входа"
|
|
||||||
unknownDesc = "Произошла неизвестная ошибка. Подробности можно посмотреть в консоли."
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,363 +0,0 @@
|
|||||||
[ejs.landing]
|
|
||||||
updateAvailableTooltip = "Доступно обновление"
|
|
||||||
usernamePlaceholder = "Имя пользователя"
|
|
||||||
usernameEditButton = "Редактировать"
|
|
||||||
settingsTooltip = "Настройки"
|
|
||||||
serverStatus = "СЕРВЕР"
|
|
||||||
serverStatusPlaceholder = "ОФФЛАЙН"
|
|
||||||
mojangStatus = "СТАТУС MOJANG"
|
|
||||||
mojangStatusTooltipTitle = "Сервисы"
|
|
||||||
mojangStatusNETitle = "Необязательно"
|
|
||||||
newsButton = "НОВОСТИ"
|
|
||||||
launchButton = "ИГРАТЬ"
|
|
||||||
launchButtonPlaceholder = "• Сервер не выбран"
|
|
||||||
launchDetails = "Пожалуйста, подождите.."
|
|
||||||
newsNavigationStatus = "{currentPage} из {totalPages}"
|
|
||||||
newsErrorLoadSpan = "Проверка новостей.."
|
|
||||||
newsErrorFailedSpan = "Не удалось загрузить новости"
|
|
||||||
newsErrorRetryButton = "Попробовать снова"
|
|
||||||
newsErrorNoneSpan = "Новостей нет"
|
|
||||||
|
|
||||||
[ejs.login]
|
|
||||||
loginCancelText = "Отмена"
|
|
||||||
loginSubheader = "ВХОД В MINECRAFT"
|
|
||||||
loginEmailError = "* Неверное значение"
|
|
||||||
loginEmailPlaceholder = "EMAIL ИЛИ ИМЯ ПОЛЬЗОВАТЕЛЯ"
|
|
||||||
loginPasswordError = "* Обязательное поле"
|
|
||||||
loginPasswordPlaceholder = "ПАРОЛЬ"
|
|
||||||
loginForgotPasswordLink = "https://minecraft.net/password/forgot/"
|
|
||||||
loginForgotPasswordText = "забыли пароль?"
|
|
||||||
loginRememberMeText = "запомнить меня?"
|
|
||||||
loginButtonText = "ВОЙТИ"
|
|
||||||
loginNeedAccountLink = "https://minecraft.net/store/minecraft-java-edition/"
|
|
||||||
loginNeedAccountText = "Нужен аккаунт?"
|
|
||||||
loginPasswordDisclaimer1 = "Ваш пароль отправляется напрямую в Mojang и никогда не сохраняется."
|
|
||||||
loginPasswordDisclaimer2 = "{appName} не связан с Mojang AB."
|
|
||||||
|
|
||||||
[ejs.loginOptions]
|
|
||||||
loginOptionsTitle = "Опции входа"
|
|
||||||
loginWithMicrosoft = "Войти через Microsoft"
|
|
||||||
loginWithMojang = "Войти через Mojang"
|
|
||||||
cancelButton = "Отмена"
|
|
||||||
|
|
||||||
[ejs.overlay]
|
|
||||||
serverSelectHeader = "Доступные серверы"
|
|
||||||
serverSelectConfirm = "Выбрать"
|
|
||||||
serverSelectCancel = "Отмена"
|
|
||||||
accountSelectHeader = "Выберите аккаунт"
|
|
||||||
accountSelectConfirm = "Выбрать"
|
|
||||||
accountSelectCancel = "Отмена"
|
|
||||||
|
|
||||||
[ejs.settings]
|
|
||||||
navHeaderText = "Настройки"
|
|
||||||
navAccount = "Аккаунт"
|
|
||||||
navMinecraft = "Minecraft"
|
|
||||||
navMods = "Моды"
|
|
||||||
navJava = "Java"
|
|
||||||
navLauncher = "Лаунчер"
|
|
||||||
navAbout = "О программе"
|
|
||||||
navUpdates = "Обновления"
|
|
||||||
navDone = "Готово"
|
|
||||||
tabAccountHeaderText = "Настройки аккаунта"
|
|
||||||
tabAccountHeaderDesc = "Добавляйте новые аккаунты или управляйте существующими."
|
|
||||||
microsoftAccount = "Microsoft"
|
|
||||||
addMicrosoftAccount = "+ Добавить аккаунт Microsoft"
|
|
||||||
mojangAccount = "Mojang"
|
|
||||||
addMojangAccount = "+ Добавить аккаунт Mojang"
|
|
||||||
minecraftTabHeaderText = "Настройки Minecraft"
|
|
||||||
minecraftTabHeaderDesc = "Параметры, связанные с запуском игры."
|
|
||||||
gameResolutionTitle = "Разрешение игры"
|
|
||||||
launchFullscreenTitle = "Запуск в полноэкранном режиме."
|
|
||||||
autoConnectTitle = "Автоматически подключаться к серверу при запуске."
|
|
||||||
launchDetachedTitle = "Запускать игру отдельно от лаунчера."
|
|
||||||
launchDetachedDesc = "Если игра не запущена отдельно, закрытие лаунчера приведет к закрытию игры."
|
|
||||||
tabModsHeaderText = "Настройки модов"
|
|
||||||
tabModsHeaderDesc = "Включайте или отключайте моды."
|
|
||||||
switchServerButton = "Сменить сервер"
|
|
||||||
requiredMods = "Обязательные моды"
|
|
||||||
optionalMods = "Дополнительные моды"
|
|
||||||
dropinMods = "Установленные моды"
|
|
||||||
addMods = "Добавить моды"
|
|
||||||
dropinRefreshNote = "(Нажмите F5 для обновления)"
|
|
||||||
shaderpacks = "Шейдерпаки"
|
|
||||||
shaderpackDesc = "Включайте или отключайте шейдеры. Учтите, что они требуют мощного компьютера. Вы можете добавлять собственные шейдерпаки здесь."
|
|
||||||
selectShaderpack = "Выбрать шейдерпак"
|
|
||||||
tabJavaHeaderText = "Настройки Java"
|
|
||||||
tabJavaHeaderDesc = "Управление конфигурацией Java (для продвинутых пользователей)."
|
|
||||||
memoryTitle = "Память"
|
|
||||||
maxRAM = "Максимальный объем RAM"
|
|
||||||
minRAM = "Минимальный объем RAM"
|
|
||||||
memoryDesc = "Рекомендуемый минимум RAM — 3 ГБ. Установка одинаковых значений для минимума и максимума может снизить лаги."
|
|
||||||
memoryTotalTitle = "Всего"
|
|
||||||
memoryAvailableTitle = "Доступно"
|
|
||||||
javaExecutableTitle = "Исполняемый файл Java"
|
|
||||||
javaExecSelDialogTitle = "Выберите исполняемый файл Java"
|
|
||||||
javaExecSelButtonText = "Выбрать файл"
|
|
||||||
javaExecDesc = "Исполняемый файл Java проверяется перед запуском игры."
|
|
||||||
javaPathDesc = "Путь должен заканчиваться на <strong>{pathSuffix}</strong>."
|
|
||||||
jvmOptsTitle = "Дополнительные параметры JVM"
|
|
||||||
jvmOptsDesc = "Опции, передаваемые JVM во время выполнения. <em>-Xms</em> и <em>-Xmx</em> не должны включаться."
|
|
||||||
launcherTabHeaderText = "Настройки лаунчера"
|
|
||||||
launcherTabHeaderDesc = "Параметры, связанные с самим лаунчером."
|
|
||||||
allowPrereleaseTitle = "Разрешить обновления предварительных версий."
|
|
||||||
allowPrereleaseDesc = "Предварительные версии включают новые функции, которые могут быть недостаточно протестированы.<br>Этот параметр всегда включен, если вы используете предварительную версию."
|
|
||||||
dataDirectoryTitle = "Директория данных"
|
|
||||||
selectDataDirectory = "Выбрать директорию данных"
|
|
||||||
chooseFolder = "Выбрать папку"
|
|
||||||
dataDirectoryDesc = "Все игровые файлы и локальные установки Java будут храниться в этой директории.<br>Скриншоты и сохранения миров хранятся в папке экземпляра соответствующей конфигурации сервера."
|
|
||||||
aboutTabHeaderText = "О программе"
|
|
||||||
aboutTabHeaderDesc = "Просмотр информации и заметок о текущей версии."
|
|
||||||
aboutTitle = "{appName}"
|
|
||||||
stableRelease = "Стабильный релиз"
|
|
||||||
versionText = "Версия "
|
|
||||||
sourceGithub = "Исходный код (GitHub)"
|
|
||||||
support = "Поддержка"
|
|
||||||
devToolsConsole = "Консоль DevTools"
|
|
||||||
releaseNotes = "Примечания к выпуску"
|
|
||||||
changelog = "История изменений"
|
|
||||||
noReleaseNotes = "Нет примечаний к выпуску"
|
|
||||||
viewReleaseNotes = "Просмотреть примечания к выпуску на GitHub"
|
|
||||||
launcherUpdatesHeaderText = "Обновления лаунчера"
|
|
||||||
launcherUpdatesHeaderDesc = "Загрузка, установка и просмотр обновлений лаунчера."
|
|
||||||
checkForUpdates = "Проверить обновления"
|
|
||||||
whatsNew = "Что нового"
|
|
||||||
updateReleaseNotes = "Примечания к обновлению"
|
|
||||||
|
|
||||||
[ejs.waiting]
|
|
||||||
waitingText = "Ожидание Microsoft.."
|
|
||||||
|
|
||||||
[ejs.welcome]
|
|
||||||
continueButton = "ПРОДОЛЖИТЬ"
|
|
||||||
|
|
||||||
[js.discord]
|
|
||||||
waiting = "Ожидание клиента.."
|
|
||||||
state = "Сервер: {shortId}"
|
|
||||||
|
|
||||||
[js.index]
|
|
||||||
microsoftLoginTitle = "Вход через Microsoft"
|
|
||||||
microsoftLogoutTitle = "Выход из Microsoft"
|
|
||||||
|
|
||||||
[js.login]
|
|
||||||
login = "ВОЙТИ"
|
|
||||||
loggingIn = "ВХОД В СИСТЕМУ"
|
|
||||||
success = "УСПЕШНО"
|
|
||||||
tryAgain = "Попробовать снова"
|
|
||||||
|
|
||||||
[js.login.error]
|
|
||||||
invalidValue = "* Неверное значение"
|
|
||||||
requiredValue = "* Обязательное поле"
|
|
||||||
|
|
||||||
[js.login.error.unknown]
|
|
||||||
title = "Неизвестная ошибка при входе"
|
|
||||||
desc = "Произошла неизвестная ошибка. Подробности можно посмотреть в консоли."
|
|
||||||
|
|
||||||
[js.landing.launch]
|
|
||||||
pleaseWait = "Пожалуйста, подождите.."
|
|
||||||
failureTitle = "Ошибка при запуске"
|
|
||||||
failureText = "Смотрите консоль (CTRL + Shift + I) для подробностей."
|
|
||||||
okay = "ОК"
|
|
||||||
|
|
||||||
[js.landing.selectedAccount]
|
|
||||||
noAccountSelected = "Аккаунт не выбран"
|
|
||||||
|
|
||||||
[js.landing.selectedServer]
|
|
||||||
noSelection = "Сервер не выбран"
|
|
||||||
loading = "Загрузка.."
|
|
||||||
|
|
||||||
[js.landing.serverStatus]
|
|
||||||
server = "СЕРВЕР"
|
|
||||||
offline = "ОФФЛАЙН"
|
|
||||||
players = "ИГРОКИ"
|
|
||||||
|
|
||||||
[js.landing.systemScan]
|
|
||||||
checking = "Проверка информации о системе.."
|
|
||||||
noCompatibleJava = "Совместимая<br>установка Java не найдена"
|
|
||||||
installJavaMessage = "Для запуска Minecraft требуется 64-битная версия Java {major}. Установить её сейчас?"
|
|
||||||
installJava = "Установить Java"
|
|
||||||
installJavaManually = "Установить вручную"
|
|
||||||
javaDownloadPrepare = "Подготовка загрузки Java.."
|
|
||||||
javaDownloadFailureTitle = "Ошибка загрузки Java"
|
|
||||||
javaDownloadFailureText = "Смотрите консоль (CTRL + Shift + I) для подробностей."
|
|
||||||
javaRequired = "Для запуска требуется Java"
|
|
||||||
javaRequiredMessage = "Для запуска необходима действительная 64-битная установка Java {major}.<br><br>Пожалуйста, ознакомьтесь с нашим <a href=\"https://github.com/dscalzi/HeliosLauncher/wiki/Java-Management#manually-installing-a-valid-version-of-java\">Руководством по управлению Java</a>, чтобы установить её вручную."
|
|
||||||
javaRequiredDismiss = "Понял"
|
|
||||||
javaRequiredCancel = "Назад"
|
|
||||||
|
|
||||||
[js.landing.downloadJava]
|
|
||||||
findJdkFailure = "Не удалось найти дистрибутив OpenJDK."
|
|
||||||
javaDownloadCorruptedError = "Загруженный JDK поврежден, файл может быть испорчен."
|
|
||||||
extractingJava = "Распаковка Java"
|
|
||||||
javaInstalled = "Java установлена!"
|
|
||||||
|
|
||||||
[js.landing.dlAsync]
|
|
||||||
loadingServerInfo = "Загрузка информации о сервере.."
|
|
||||||
fatalError = "Критическая ошибка"
|
|
||||||
unableToLoadDistributionIndex = "Не удалось загрузить индекс дистрибуции. Смотрите консоль (CTRL + Shift + I) для подробностей."
|
|
||||||
pleaseWait = "Пожалуйста, подождите.."
|
|
||||||
errorDuringLaunchTitle = "Ошибка при запуске"
|
|
||||||
seeConsoleForDetails = "Смотрите консоль (CTRL + Shift + I) для подробностей."
|
|
||||||
validatingFileIntegrity = "Проверка целостности файлов.."
|
|
||||||
errorDuringFileVerificationTitle = "Ошибка при проверке файлов"
|
|
||||||
downloadingFiles = "Загрузка файлов.."
|
|
||||||
errorDuringFileDownloadTitle = "Ошибка при загрузке файлов"
|
|
||||||
preparingToLaunch = "Подготовка к запуску.."
|
|
||||||
launchingGame = "Запуск игры.."
|
|
||||||
launchWrapperNotDownloaded = "Основной файл, LaunchWrapper, не был загружен должным образом. В результате игра не может быть запущена.<br><br>Чтобы исправить эту проблему, временно отключите антивирусное ПО и попробуйте снова.<br><br>Если у вас есть время, пожалуйста, <a href=\"https://github.com/dscalzi/HeliosLauncher/issues\">сообщите об этой проблеме</a> и укажите, каким антивирусом вы пользуетесь. Мы постараемся связаться с разработчиками антивируса и решить проблему."
|
|
||||||
doneEnjoyServer = "Готово. Наслаждайтесь сервером!"
|
|
||||||
checkConsoleForDetails = "Пожалуйста, проверьте консоль (CTRL + Shift + I) для подробностей."
|
|
||||||
|
|
||||||
[js.landing.news]
|
|
||||||
checking = "Проверка новостей"
|
|
||||||
|
|
||||||
[js.landing.discord]
|
|
||||||
loading = "Загрузка игры.."
|
|
||||||
joining = "Путешествие в Вестерос!"
|
|
||||||
joined = "Исследование мира!"
|
|
||||||
|
|
||||||
[js.overlay]
|
|
||||||
dismiss = "Закрыть"
|
|
||||||
|
|
||||||
[js.settings.fileSelectors]
|
|
||||||
executables = "Исполняемые файлы"
|
|
||||||
allFiles = "Все файлы"
|
|
||||||
|
|
||||||
[js.settings.mstfLogin]
|
|
||||||
errorTitle = "Что-то пошло не так"
|
|
||||||
errorMessage = "Ошибка аутентификации Microsoft. Попробуйте еще раз."
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.mstfLogout]
|
|
||||||
errorTitle = "Что-то пошло не так"
|
|
||||||
errorMessage = "Ошибка выхода из Microsoft. Попробуйте еще раз."
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.authAccountLogout]
|
|
||||||
lastAccountWarningTitle = "Внимание<br>Это ваш последний аккаунт"
|
|
||||||
lastAccountWarningMessage = "Для использования лаунчера необходимо быть авторизованным хотя бы в одном аккаунте. После выхода вам придется войти снова.<br><br>Вы уверены, что хотите выйти?"
|
|
||||||
confirmButton = "Я уверен"
|
|
||||||
cancelButton = "Отмена"
|
|
||||||
|
|
||||||
[js.settings.authAccountPopulate]
|
|
||||||
username = "Имя пользователя"
|
|
||||||
uuid = "UUID"
|
|
||||||
selectAccount = "Выбрать аккаунт"
|
|
||||||
selectedAccount = "Выбранный аккаунт ✓"
|
|
||||||
logout = "Выйти"
|
|
||||||
|
|
||||||
[js.settings.dropinMods]
|
|
||||||
removeButton = "Удалить"
|
|
||||||
deleteFailedTitle = "Ошибка удаления<br>мода {fullName}"
|
|
||||||
deleteFailedMessage = "Убедитесь, что файл не используется, и попробуйте снова."
|
|
||||||
failedToggleTitle = "Ошибка переключения<br>одного или нескольких установленных модов"
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.serverListing]
|
|
||||||
mainServer = "Основной сервер"
|
|
||||||
|
|
||||||
[js.settings.java]
|
|
||||||
selectedJava = "Выбрано: Java {version} ({vendor})"
|
|
||||||
invalidSelection = "Некорректный выбор"
|
|
||||||
requiresJava = "Требуется Java {major} x64."
|
|
||||||
availableOptions = "Доступные версии Java {major} (HotSpot VM)"
|
|
||||||
|
|
||||||
[js.settings.about]
|
|
||||||
preReleaseTitle = "Предварительная версия"
|
|
||||||
stableReleaseTitle = "Стабильная версия"
|
|
||||||
releaseNotesFailed = "Не удалось загрузить примечания к выпуску."
|
|
||||||
|
|
||||||
[js.settings.updates]
|
|
||||||
newReleaseTitle = "Доступно новое обновление"
|
|
||||||
newPreReleaseTitle = "Доступна новая предварительная версия"
|
|
||||||
downloadingButton = "Загрузка.."
|
|
||||||
downloadButton = 'Загрузить с GitHub<span style="font-size: 10px;color: gray;text-shadow: none !important;">Закройте лаунчер и запустите установщик для обновления.</span>'
|
|
||||||
latestVersionTitle = "У вас установлена последняя версия"
|
|
||||||
checkForUpdatesButton = "Проверить обновления"
|
|
||||||
checkingForUpdatesButton = "Проверка обновлений.."
|
|
||||||
|
|
||||||
[js.settings.msftLogin]
|
|
||||||
errorTitle = "Ошибка входа в Microsoft"
|
|
||||||
errorMessage = "Не удалось выполнить аутентификацию в Microsoft. Попробуйте снова."
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.authAccountSelect]
|
|
||||||
selectButton = "Выбрать аккаунт"
|
|
||||||
selectedButton = "Выбранный аккаунт ✔"
|
|
||||||
|
|
||||||
[js.settings.authAccountLogout]
|
|
||||||
lastAccountWarningTitle = "Внимание<br>Это ваш последний аккаунт"
|
|
||||||
lastAccountWarningMessage = "Для использования лаунчера необходимо быть авторизованным хотя бы в одном аккаунте. После выхода вам придется войти снова.<br><br>Вы уверены, что хотите выйти?"
|
|
||||||
confirmButton = "Я уверен"
|
|
||||||
cancelButton = "Отмена"
|
|
||||||
|
|
||||||
[js.settings.authAccountPopulate]
|
|
||||||
username = "Имя пользователя"
|
|
||||||
uuid = "UUID"
|
|
||||||
selectAccount = "Выбрать аккаунт"
|
|
||||||
selectedAccount = "Выбранный аккаунт ✓"
|
|
||||||
logout = "Выйти"
|
|
||||||
|
|
||||||
[js.settings.dropinMods]
|
|
||||||
removeButton = "Удалить"
|
|
||||||
deleteFailedTitle = "Ошибка удаления<br>мода {fullName}"
|
|
||||||
deleteFailedMessage = "Убедитесь, что файл не используется, и попробуйте снова."
|
|
||||||
failedToggleTitle = "Ошибка переключения<br>одного или нескольких установленных модов"
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.settings.serverListing]
|
|
||||||
mainServer = "Основной сервер"
|
|
||||||
|
|
||||||
[js.settings.java]
|
|
||||||
selectedJava = "Выбрано: Java {version} ({vendor})"
|
|
||||||
invalidSelection = "Некорректный выбор"
|
|
||||||
requiresJava = "Требуется Java {major} x64."
|
|
||||||
availableOptions = "Доступные версии Java {major} (HotSpot VM)"
|
|
||||||
|
|
||||||
[js.settings.about]
|
|
||||||
preReleaseTitle = "Предварительная версия"
|
|
||||||
stableReleaseTitle = "Стабильная версия"
|
|
||||||
releaseNotesFailed = "Не удалось загрузить примечания к выпуску."
|
|
||||||
|
|
||||||
[js.settings.updates]
|
|
||||||
newReleaseTitle = "Доступно новое обновление"
|
|
||||||
newPreReleaseTitle = "Доступна новая предварительная версия"
|
|
||||||
downloadingButton = "Загрузка.."
|
|
||||||
downloadButton = 'Загрузить с GitHub<span style="font-size: 10px;color: gray;text-shadow: none !important;">Закройте лаунчер и запустите установщик для обновления.</span>'
|
|
||||||
latestVersionTitle = "У вас установлена последняя версия"
|
|
||||||
checkForUpdatesButton = "Проверить обновления"
|
|
||||||
checkingForUpdatesButton = "Проверка обновлений.."
|
|
||||||
|
|
||||||
[js.settings.msftLogin]
|
|
||||||
errorTitle = "Ошибка входа в Microsoft"
|
|
||||||
errorMessage = "Не удалось выполнить аутентификацию в Microsoft. Попробуйте снова."
|
|
||||||
okButton = "ОК"
|
|
||||||
|
|
||||||
[js.uibinder.startup]
|
|
||||||
fatalErrorTitle = "Критическая ошибка: невозможно загрузить индекс дистрибуции"
|
|
||||||
fatalErrorMessage = "Не удалось установить соединение с нашими серверами для загрузки индекса дистрибуции. Локальные копии отсутствуют.<br><br>Индекс дистрибуции — это важный файл, который содержит актуальную информацию о сервере. Лаунчер не сможет запуститься без него. Убедитесь, что у вас есть подключение к интернету, и перезапустите приложение."
|
|
||||||
closeButton = "Закрыть"
|
|
||||||
|
|
||||||
[js.uibinder.validateAccount]
|
|
||||||
failedMessageTitle = "Ошибка обновления входа"
|
|
||||||
failedMessage = "Не удалось обновить вход для <strong>{account}</strong>. Пожалуйста, выберите другой аккаунт или войдите снова."
|
|
||||||
failedMessageSelectAnotherAccount = "Не удалось обновить вход для <strong>{account}</strong>. Пожалуйста, войдите снова."
|
|
||||||
loginButton = "Войти"
|
|
||||||
selectAnotherAccountButton = "Выбрать другой аккаунт"
|
|
||||||
|
|
||||||
[js.uicore.autoUpdate]
|
|
||||||
checkingForUpdateButton = "Проверка обновлений..."
|
|
||||||
installNowButton = "Установить сейчас"
|
|
||||||
checkForUpdatesButton = "Проверить обновления"
|
|
||||||
|
|
||||||
[js.auth.microsoft.error]
|
|
||||||
noProfileTitle = "Ошибка входа:<br>Профиль не настроен"
|
|
||||||
noProfileDesc = "Ваш аккаунт Microsoft еще не имеет профиля Minecraft. Если вы недавно купили игру или активировали ее через Xbox Game Pass, вам нужно настроить профиль на <a href=\"https://minecraft.net/\">Minecraft.net</a>.<br><br>Если вы еще не купили игру, вы можете сделать это на <a href=\"https://minecraft.net/\">Minecraft.net</a>."
|
|
||||||
noXboxAccountTitle = "Ошибка входа:<br>Нет аккаунта Xbox"
|
|
||||||
noXboxAccountDesc = "У вашей учетной записи Microsoft нет привязанного аккаунта Xbox."
|
|
||||||
xblBannedTitle = "Ошибка входа:<br>Xbox Live недоступен"
|
|
||||||
xblBannedDesc = "Ваш аккаунт Microsoft зарегистрирован в стране, где Xbox Live недоступен или заблокирован."
|
|
||||||
under18Title = "Ошибка входа:<br>Требуется родительское разрешение"
|
|
||||||
under18Desc = "Аккаунты пользователей младше 18 лет должны быть добавлены в «Семью» взрослым."
|
|
||||||
unknownTitle = "Неизвестная ошибка входа"
|
|
||||||
unknownDesc = "Произошла неизвестная ошибка. Подробности можно посмотреть в консоли."
|
|
||||||
|
|
||||||
|
|
@ -39,6 +39,53 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mediaContainer">
|
||||||
|
<a href="<%- lang('landing.mediaTwitterURL') %>" class="mediaURL" id="twitterURL">
|
||||||
|
<svg id="twitterSVG" class="mediaSVG" viewBox="0 0 5000 4060" preserveAspectRatio="xMidYMid meet">
|
||||||
|
<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"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="mediaContainer">
|
||||||
|
<a href="<%- lang('landing.mediaInstagramURL') %>" class="mediaURL" id="instagramURL">
|
||||||
|
<svg id="instagramSVG" class="mediaSVG" viewBox="0 0 5040 5040">
|
||||||
|
<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>
|
||||||
|
<path d="M1390 5024 c-163 -9 -239 -19 -315 -38 -281 -70 -477 -177 -660 -361 -184 -184 -292 -380 -361 -660 -43 -171 -53 -456 -53 -1445 0 -989 10 -1274 53 -1445 69 -280 177 -476 361 -660 184 -184 380 -292 660 -361 171 -43 456 -53 1445 -53 989 0 1274 10 1445 53 280 69 476 177 660 361 184 184 292 380 361 660 43 171 53 456 53 1445 0 989 -10 1274 -53 1445 -69 280 -177 476 -361 660 -184 184 -380 292 -660 361 -174 44 -454 53 -1470 52 -599 0 -960 -5 -1105 -14z m2230 -473 c58 -6 141 -18 185 -27 397 -78 638 -318 719 -714 37 -183 41 -309 41 -1290 0 -981 -4 -1107 -41 -1290 -81 -395 -319 -633 -714 -714 -183 -37 -309 -41 -1290 -41 -981 0 -1107 4 -1290 41 -397 81 -636 322 -714 719 -33 166 -38 296 -43 1100 -5 796 3 1203 27 1380 67 489 338 758 830 825 47 7 162 15 255 20 250 12 1907 4 2035 -9z"/>
|
||||||
|
<path d="M2355 3819 c-307 -42 -561 -172 -780 -400 -244 -253 -359 -543 -359 -899 0 -361 116 -648 367 -907 262 -269 563 -397 937 -397 374 0 675 128 937 397 251 259 367 546 367 907 0 361 -116 648 -367 907 -197 203 -422 326 -690 378 -101 20 -317 27 -412 14z m400 -509 c275 -88 470 -284 557 -560 20 -65 23 -95 23 -230 0 -135 -3 -165 -23 -230 -88 -278 -284 -474 -562 -562 -65 -20 -95 -23 -230 -23 -135 0 -165 3 -230 23 -278 88 -474 284 -562 562 -20 65 -23 95 -23 230 0 135 3 165 23 230 73 230 219 403 427 507 134 67 212 83 390 79 111 -3 155 -8 210 -26z"/>
|
||||||
|
<path d="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>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -169,5 +216,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/landing.js"></script>
|
<!-- <script type="module" src="./assets/js/scripts/landing.js"></script> -->
|
||||||
</div>
|
</div>
|
@ -18,7 +18,19 @@
|
|||||||
<span class="loginErrorSpan" id="loginEmailError"><%- lang('login.loginEmailError') %></span>
|
<span class="loginErrorSpan" id="loginEmailError"><%- lang('login.loginEmailError') %></span>
|
||||||
<input id="loginUsername" class="loginField" type="text" placeholder="<%- lang('login.loginEmailPlaceholder') %>"/>
|
<input id="loginUsername" class="loginField" type="text" placeholder="<%- lang('login.loginEmailPlaceholder') %>"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="loginFieldContainer">
|
||||||
|
<svg id="lockSVG" class="loginSVG" viewBox="40 32 60.36 70.43">
|
||||||
|
<g>
|
||||||
|
<path d="M86.16,54a16.38,16.38,0,1,0-32,0H44V102.7H96V54Zm-25.9-3.39a9.89,9.89,0,1,1,19.77,0A9.78,9.78,0,0,1,79.39,54H60.89A9.78,9.78,0,0,1,60.26,50.59ZM70,96.2a6.5,6.5,0,0,1-6.5-6.5,6.39,6.39,0,0,1,3.1-5.4V67h6.5V84.11a6.42,6.42,0,0,1,3.39,5.6A6.5,6.5,0,0,1,70,96.2Z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<span class="loginErrorSpan" id="loginPasswordError"><%- lang('login.loginPasswordError') %></span>
|
||||||
|
<input id="loginPassword" class="loginField" type="password" placeholder="<%- lang('login.loginPasswordPlaceholder') %>"/>
|
||||||
|
</div>
|
||||||
<div id="loginOptions">
|
<div id="loginOptions">
|
||||||
|
<span class="loginSpanDim">
|
||||||
|
<a href="<%- lang('login.loginForgotPasswordLink') %>"><%- lang('login.loginForgotPasswordText') %></a>
|
||||||
|
</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"><%- lang('login.loginRememberMeText') %></span>
|
||||||
@ -49,5 +61,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/login.js"></script>
|
<!-- <script type="module" src="./assets/js/scripts/login.js"></script> -->
|
||||||
</div>
|
</div>
|
@ -15,8 +15,13 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="loginOptionButtonContainer">
|
<div class="loginOptionButtonContainer">
|
||||||
<button id="loginOptionOffline" class="loginOptionButton">
|
<button id="loginOptionMojang" class="loginOptionButton">
|
||||||
<span><%- lang('loginOptions.loginWithOffline') %></span>
|
<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="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" />
|
||||||
|
</svg>
|
||||||
|
<span><%- lang('loginOptions.loginWithMojang') %></span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -25,5 +30,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/loginOptions.js"></script>
|
<!-- <script type="module" src="./assets/js/scripts/loginOptions.js"></script> -->
|
||||||
</div>
|
</div>
|
@ -37,5 +37,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/overlay.js"></script>
|
<!-- <script type="module" src="./assets/js/scripts/overlay.js"></script> -->
|
||||||
</div>
|
</div>
|
@ -52,20 +52,23 @@
|
|||||||
<div class="settingsAuthAccountTypeContainer">
|
<div class="settingsAuthAccountTypeContainer">
|
||||||
<div class="settingsAuthAccountTypeHeader">
|
<div class="settingsAuthAccountTypeHeader">
|
||||||
<div class="settingsAuthAccountTypeHeaderLeft">
|
<div class="settingsAuthAccountTypeHeaderLeft">
|
||||||
<img src="assets/images/lotip22.svg"/>
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 9.677 9.667">
|
||||||
<span><%- lang('settings.offlineAccount') %></span>
|
<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="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>
|
||||||
|
<span><%- lang('settings.mojangAccount') %></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="settingsAuthAccountTypeHeaderRight">
|
<div class="settingsAuthAccountTypeHeaderRight">
|
||||||
<button class="settingsAddAuthAccount" id="settingsAddOfflineAccount"><%- lang('settings.addOfflineAccount') %></button>
|
<button class="settingsAddAuthAccount" id="settingsAddMojangAccount"><%- lang('settings.addMojangAccount') %></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="settingsCurrentAccounts" id="settingsCurrentOfflineAccounts">
|
<div class="settingsCurrentAccounts" id="settingsCurrentMojangAccounts">
|
||||||
<!-- Mojang auth accounts populated here. -->
|
<!-- Mojang auth accounts populated here. -->
|
||||||
</div>
|
</div>
|
||||||
</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"><%- lang('settings.minecraftTabHeaderText') %></span>
|
||||||
@ -386,5 +389,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/settings.js"></script>
|
<!-- <script type="module" src="./assets/js/scripts/settings.js"></script> -->
|
||||||
</div>
|
</div>
|
@ -21,5 +21,5 @@
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<script src="./assets/js/scripts/welcome.js"></script>
|
<!-- <script type="module" src="./assets/js/scripts/welcome.js"></script> -->
|
||||||
</div>
|
</div>
|
BIN
build/icon.png
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 142 KiB |
@ -1,3 +1,3 @@
|
|||||||
owner: ONIMAI-SMP
|
owner: dscalzi
|
||||||
repo: Launcher
|
repo: HeliosLauncher
|
||||||
provider: git.onimai.ru
|
provider: github
|
||||||
|
@ -360,12 +360,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 +408,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 +443,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.
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
appId: 'onimairu-mc_launcher'
|
appId: 'helioslauncher'
|
||||||
productName: 'ONIMAI.RU MC Launcher'
|
productName: 'Helios Launcher'
|
||||||
artifactName: '${productName}-setup-${version}.${ext}'
|
artifactName: '${productName}-setup-${version}.${ext}'
|
||||||
|
|
||||||
copyright: 'Copyright © 2024 ONIMAI.RU'
|
copyright: 'Copyright © 2018-2022 Daniel Scalzi'
|
||||||
|
|
||||||
asar: true
|
asar: true
|
||||||
compression: 'maximum'
|
compression: 'maximum'
|
||||||
@ -39,8 +39,8 @@ mac:
|
|||||||
# Linux Configuration
|
# Linux Configuration
|
||||||
linux:
|
linux:
|
||||||
target: 'AppImage'
|
target: 'AppImage'
|
||||||
maintainer: 'SPAWNRYS'
|
maintainer: 'Daniel Scalzi'
|
||||||
vendor: 'ONIMAI.RU'
|
vendor: 'Daniel Scalzi'
|
||||||
synopsis: 'Modded Minecraft Launcher'
|
synopsis: 'Modded Minecraft Launcher'
|
||||||
description: 'Custom launcher which allows users to join modded servers. All mods, configurations, and updates are handled automatically.'
|
description: 'Custom launcher which allows users to join modded servers. All mods, configurations, and updates are handled automatically.'
|
||||||
category: 'Game'
|
category: 'Game'
|
||||||
|
222
index.js
@ -1,23 +1,104 @@
|
|||||||
const remoteMain = require('@electron/remote/main')
|
|
||||||
remoteMain.initialize()
|
|
||||||
|
|
||||||
// Requirements
|
// Requirements
|
||||||
const { app, BrowserWindow, ipcMain, Menu, shell } = require('electron')
|
const { app, BrowserWindow, ipcMain, Menu, shell } = require('electron')
|
||||||
const autoUpdater = require('electron-updater').autoUpdater
|
const autoUpdater = require('electron-updater').autoUpdater
|
||||||
const ejse = require('ejs-electron')
|
const ejse = require('ejs-electron')
|
||||||
const fs = require('fs')
|
const fs = require('fs-extra')
|
||||||
const isDev = require('./app/assets/js/isdev')
|
|
||||||
const path = require('path')
|
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')
|
|
||||||
|
const { Type } = require('helios-distribution-types')
|
||||||
|
const { totalmem, freemem, tmpdir } = require('node:os')
|
||||||
|
const { prerelease } = require('semver')
|
||||||
|
const { addMojangAccount, addMicrosoftAccount, removeMojangAccount, removeMicrosoftAccount, validateSelected } = require('./app/assets/js/main/authmanager')
|
||||||
|
|
||||||
|
const ConfigManager = require('./app/assets/js/main/configmanager')
|
||||||
|
const { DistroAPI } = require('./app/assets/js/main/distromanager')
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const { HeliosDistribution } = require('helios-core/common')
|
||||||
|
const { LoggerUtil } = require('helios-core')
|
||||||
|
const { getLang, setupLanguage, queryEJS, queryJS } = require('./app/assets/js/main/langloader')
|
||||||
|
|
||||||
|
const logger = LoggerUtil.getLogger('Preloader')
|
||||||
|
|
||||||
|
// Log deprecation and process warnings.
|
||||||
|
process.traceProcessWarnings = true
|
||||||
|
process.traceDeprecation = true
|
||||||
|
|
||||||
|
// Load ConfigManager
|
||||||
|
ConfigManager.load()
|
||||||
|
|
||||||
|
// Yuck!
|
||||||
|
// TODO Fix this
|
||||||
|
DistroAPI['commonDir'] = ConfigManager.getCommonDirectory()
|
||||||
|
DistroAPI['instanceDir'] = ConfigManager.getInstanceDirectory()
|
||||||
|
|
||||||
// Setup Lang
|
// Setup Lang
|
||||||
LangLoader.setupLanguage()
|
setupLanguage()
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {HeliosDistribution} data
|
||||||
|
*/
|
||||||
|
function onDistroLoad(data){
|
||||||
|
if(data != null){
|
||||||
|
|
||||||
|
// Resolve the selected server if its value has yet to be set.
|
||||||
|
if(ConfigManager.getSelectedServer() == null || data.getServerById(ConfigManager.getSelectedServer()) == null){
|
||||||
|
logger.info('Determining default selected server..')
|
||||||
|
ConfigManager.setSelectedServer(data.getMainServer().rawServer.id)
|
||||||
|
ConfigManager.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
win.webContents.send('distributionIndexDone', data != null)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure Distribution is downloaded and cached.
|
||||||
|
DistroAPI.getDistribution()
|
||||||
|
.then(heliosDistro => {
|
||||||
|
logger.info('Loaded distribution index.')
|
||||||
|
|
||||||
|
onDistroLoad(heliosDistro)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
logger.info('Failed to load an older version of the distribution index.')
|
||||||
|
logger.info('Application cannot run.')
|
||||||
|
logger.error(err)
|
||||||
|
|
||||||
|
onDistroLoad(null)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Clean up temp dir incase previous launches ended unexpectedly.
|
||||||
|
fs.remove(path.join(tmpdir(), ConfigManager.getTempNativeFolder()), (err) => {
|
||||||
|
if(err){
|
||||||
|
logger.warn('Error while cleaning natives directory', err)
|
||||||
|
} else {
|
||||||
|
logger.info('Cleaned natives directory.')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const autoUpdateChannel = new MessageChannel()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ORIGINAL BELOW
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Setup auto updater.
|
// Setup auto updater.
|
||||||
function initAutoUpdater(event, data) {
|
function initAutoUpdater(data) {
|
||||||
|
|
||||||
if(data){
|
if(data){
|
||||||
autoUpdater.allowPrerelease = true
|
autoUpdater.allowPrerelease = true
|
||||||
@ -26,7 +107,7 @@ function initAutoUpdater(event, data) {
|
|||||||
// autoUpdater.allowPrerelease = true
|
// autoUpdater.allowPrerelease = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isDev){
|
if(!app.isPackaged){
|
||||||
autoUpdater.autoInstallOnAppQuit = false
|
autoUpdater.autoInstallOnAppQuit = false
|
||||||
autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml')
|
autoUpdater.updateConfigPath = path.join(__dirname, 'dev-app-update.yml')
|
||||||
}
|
}
|
||||||
@ -34,22 +115,77 @@ function initAutoUpdater(event, data) {
|
|||||||
autoUpdater.autoDownload = false
|
autoUpdater.autoDownload = false
|
||||||
}
|
}
|
||||||
autoUpdater.on('update-available', (info) => {
|
autoUpdater.on('update-available', (info) => {
|
||||||
event.sender.send('autoUpdateNotification', 'update-available', info)
|
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'update-available', info])
|
||||||
})
|
})
|
||||||
autoUpdater.on('update-downloaded', (info) => {
|
autoUpdater.on('update-downloaded', (info) => {
|
||||||
event.sender.send('autoUpdateNotification', 'update-downloaded', info)
|
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'update-downloaded', info])
|
||||||
})
|
})
|
||||||
autoUpdater.on('update-not-available', (info) => {
|
autoUpdater.on('update-not-available', (info) => {
|
||||||
event.sender.send('autoUpdateNotification', 'update-not-available', info)
|
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'update-not-available', info])
|
||||||
})
|
})
|
||||||
autoUpdater.on('checking-for-update', () => {
|
autoUpdater.on('checking-for-update', () => {
|
||||||
event.sender.send('autoUpdateNotification', 'checking-for-update')
|
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'checking-for-update'])
|
||||||
})
|
})
|
||||||
autoUpdater.on('error', (err) => {
|
autoUpdater.on('error', (err) => {
|
||||||
event.sender.send('autoUpdateNotification', 'realerror', err)
|
autoUpdateChannel.port1.postMessage(['autoUpdateNotification', 'realerror', err])
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// all on autoupdatechannel
|
||||||
|
[
|
||||||
|
command,
|
||||||
|
arg1,
|
||||||
|
arg2,
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
autoUpdateChannel.port1.on('message', (event) => {
|
||||||
|
const command = event[0]
|
||||||
|
switch(command) {
|
||||||
|
case 'initAutoUpdater':
|
||||||
|
console.log('Initializing auto updater.')
|
||||||
|
initAutoUpdater(event[1])
|
||||||
|
autoUpdateChannel.port1.postMessage([
|
||||||
|
'autoUpdateNotification',
|
||||||
|
'ready'
|
||||||
|
])
|
||||||
|
break
|
||||||
|
case 'checkForUpdate':
|
||||||
|
// TODO Test that error is passed properly
|
||||||
|
autoUpdater.checkForUpdates()
|
||||||
|
.catch(err => {
|
||||||
|
autoUpdateChannel.port1.postMessage([
|
||||||
|
'autoUpdateNotification',
|
||||||
|
'realerror',
|
||||||
|
err
|
||||||
|
])
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'allowPrereleaseChange':
|
||||||
|
if(!event[1]){
|
||||||
|
const preRelComp = semver.prerelease(app.getVersion())
|
||||||
|
if(preRelComp != null && preRelComp.length > 0){
|
||||||
|
autoUpdater.allowPrerelease = true
|
||||||
|
} else {
|
||||||
|
autoUpdater.allowPrerelease = event[1]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
autoUpdater.allowPrerelease = event[1]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'installUpdateNow':
|
||||||
|
autoUpdater.quitAndInstall()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log('Unknown command', command)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Open channel to listen for update actions.
|
// Open channel to listen for update actions.
|
||||||
ipcMain.on('autoUpdateAction', (event, arg, data) => {
|
ipcMain.on('autoUpdateAction', (event, arg, data) => {
|
||||||
switch(arg){
|
switch(arg){
|
||||||
@ -84,10 +220,6 @@ ipcMain.on('autoUpdateAction', (event, arg, data) => {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Redirect distribution index event from preloader to renderer.
|
|
||||||
ipcMain.on('distributionIndexDone', (event, res) => {
|
|
||||||
event.sender.send('distributionIndexDone', res)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Handle trash item.
|
// Handle trash item.
|
||||||
ipcMain.handle(SHELL_OPCODE.TRASH_ITEM, async (event, ...args) => {
|
ipcMain.handle(SHELL_OPCODE.TRASH_ITEM, async (event, ...args) => {
|
||||||
@ -125,7 +257,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: queryJS('index.microsoftLoginTitle'),
|
||||||
backgroundColor: '#222222',
|
backgroundColor: '#222222',
|
||||||
width: 520,
|
width: 520,
|
||||||
height: 600,
|
height: 600,
|
||||||
@ -178,7 +310,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: queryJS('index.microsoftLogoutTitle'),
|
||||||
backgroundColor: '#222222',
|
backgroundColor: '#222222',
|
||||||
width: 520,
|
width: 520,
|
||||||
height: 600,
|
height: 600,
|
||||||
@ -234,15 +366,18 @@ function createWindow() {
|
|||||||
webPreferences: {
|
webPreferences: {
|
||||||
preload: path.join(__dirname, 'app', 'assets', 'js', 'preloader.js'),
|
preload: path.join(__dirname, 'app', 'assets', 'js', 'preloader.js'),
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: false
|
contextIsolation: true
|
||||||
},
|
},
|
||||||
backgroundColor: '#171614'
|
backgroundColor: '#171614'
|
||||||
})
|
})
|
||||||
remoteMain.enable(win.webContents)
|
|
||||||
|
// Disable zoom, needed for darwin.
|
||||||
|
win.webContents.setZoomLevel(0)
|
||||||
|
win.webContents.setVisualZoomLevelLimits(1, 1)
|
||||||
|
|
||||||
const data = {
|
const 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)
|
lang: (str, placeHolders) => queryEJS(str, placeHolders)
|
||||||
}
|
}
|
||||||
Object.entries(data).forEach(([key, val]) => ejse.data(key, val))
|
Object.entries(data).forEach(([key, val]) => ejse.data(key, val))
|
||||||
|
|
||||||
@ -341,8 +476,47 @@ function getPlatformIcon(filename){
|
|||||||
return path.join(__dirname, 'app', 'assets', 'images', `${filename}.${ext}`)
|
return path.join(__dirname, 'app', 'assets', 'images', `${filename}.${ext}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.on('ready', createWindow)
|
app.whenReady().then(() => {
|
||||||
app.on('ready', createMenu)
|
|
||||||
|
ipcMain.handle('os.totalmem', () => totalmem())
|
||||||
|
ipcMain.handle('os.freemem', () => freemem())
|
||||||
|
|
||||||
|
ipcMain.handle('semver.prerelease', (version) => prerelease(version))
|
||||||
|
|
||||||
|
ipcMain.handle('path.join', (...args) => path.join(args))
|
||||||
|
|
||||||
|
ipcMain.handle('app.isDev', () => !app.isPackaged)
|
||||||
|
ipcMain.handle('app.getVersion', () => app.getVersion())
|
||||||
|
|
||||||
|
ipcMain.handle('shell.openExternal', (url) => shell.openExternal(url))
|
||||||
|
ipcMain.handle('shell.openPath', (path) => shell.openPath(path))
|
||||||
|
|
||||||
|
ipcMain.handle('xwindow.close', () => win.close())
|
||||||
|
ipcMain.handle('xwindow.setProgressBar', (progress) => win.setProgressBar(progress))
|
||||||
|
ipcMain.handle('xwindow.toggleDevTools', () => win.webContents.toggleDevTools())
|
||||||
|
ipcMain.handle('xwindow.minimize', () => win.minimize())
|
||||||
|
ipcMain.handle('xwindow.maximize', () => win.maximize())
|
||||||
|
ipcMain.handle('xwindow.unmaximize', () => win.unmaximize())
|
||||||
|
ipcMain.handle('xwindow.isMaximized', () => win.isMaximized())
|
||||||
|
|
||||||
|
ipcMain.handle('process.platform', () => process.platform)
|
||||||
|
ipcMain.handle('process.arch', () => process.arch)
|
||||||
|
|
||||||
|
ipcMain.handle('hc.type', () => Type)
|
||||||
|
|
||||||
|
ipcMain.handle('AuthManager.addMojangAccount', async (username, password) => await addMojangAccount(username, password))
|
||||||
|
ipcMain.handle('AuthManager.addMicrosoftAccount', async (authCode) => await addMicrosoftAccount(authCode))
|
||||||
|
ipcMain.handle('AuthManager.removeMojangAccount', async (uuid) => await removeMojangAccount(uuid))
|
||||||
|
ipcMain.handle('AuthManager.removeMicrosoftAccount', async (uuid) => await removeMicrosoftAccount(uuid))
|
||||||
|
ipcMain.handle('AuthManager.validateSelected', async () => await validateSelected())
|
||||||
|
|
||||||
|
ipcMain.handle('Lang.getLang', () => getLang())
|
||||||
|
|
||||||
|
ipcMain.handle('AutoUpdater.port2', () => autoUpdateChannel.port2)
|
||||||
|
|
||||||
|
createWindow()
|
||||||
|
createMenu()
|
||||||
|
})
|
||||||
|
|
||||||
app.on('window-all-closed', () => {
|
app.on('window-all-closed', () => {
|
||||||
// On macOS it is common for applications and their menu bar
|
// On macOS it is common for applications and their menu bar
|
||||||
|
2581
package-lock.json
generated
38
package.json
@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "onimairu-mc_launcher",
|
"name": "helioslauncher",
|
||||||
"version": "1.0.1",
|
"version": "2.0.5",
|
||||||
"productName": "ONIMAI.RU MC Launcher",
|
"productName": "Helios Launcher",
|
||||||
"description": "Modded Minecraft Launcher",
|
"description": "Modded Minecraft Launcher",
|
||||||
"author": "ONIMAI.RU (https://git.onimai.ru/ONIMAI-SMP/)",
|
"author": "Daniel Scalzi (https://github.com/dscalzi/)",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"homepage": "https://git.onimai.ru/ONIMAI-SMP/Launcher",
|
"homepage": "https://github.com/dscalzi/HeliosLauncher",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://git.onimai.ru/ONIMAI-SMP/Launcher/issues"
|
"url": "https://github.com/dscalzi/HeliosLauncher/issues"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
@ -20,32 +20,32 @@
|
|||||||
"lint": "eslint --config .eslintrc.json ."
|
"lint": "eslint --config .eslintrc.json ."
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "20.x.x"
|
"node": "18.x.x"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.1.2",
|
"@electron/remote": "^2.0.11",
|
||||||
"adm-zip": "^0.5.16",
|
"adm-zip": "^0.5.9",
|
||||||
"discord-rpc-patch": "^4.0.1",
|
"discord-rpc-patch": "^4.0.1",
|
||||||
"ejs": "^3.1.10",
|
"ejs": "^3.1.9",
|
||||||
"ejs-electron": "^3.0.0",
|
"ejs-electron": "^2.1.1",
|
||||||
"electron-updater": "^6.3.9",
|
"electron-updater": "^6.1.4",
|
||||||
"fs-extra": "^11.1.1",
|
"fs-extra": "^11.1.1",
|
||||||
"github-syntax-dark": "^0.5.0",
|
"github-syntax-dark": "^0.5.0",
|
||||||
"got": "^11.8.5",
|
"got": "^11.8.5",
|
||||||
"helios-core": "~2.2.3",
|
"helios-core": "~2.0.5",
|
||||||
"helios-distribution-types": "^1.3.0",
|
"helios-distribution-types": "^1.2.0",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
"lodash.merge": "^4.6.2",
|
"lodash.merge": "^4.6.2",
|
||||||
"semver": "^7.6.3",
|
"semver": "^7.5.4",
|
||||||
"toml": "^3.0.0"
|
"toml": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^33.2.1",
|
"electron": "^26.3.0",
|
||||||
"electron-builder": "^25.1.8",
|
"electron-builder": "^24.6.4",
|
||||||
"eslint": "^8.57.1"
|
"eslint": "^8.50.0"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://git.onimai.ru/ONIMAI-SMP/Launcher.git"
|
"url": "git+https://github.com/dscalzi/HeliosLauncher.git"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|