mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-11-29 18:38:48 +03:00
2.2.0-beta2
- updated readme; added roadmap and requirements - added patch_anti_logincrash applying - partially fixed input issues - made LauncherUI class to where have moved a lot of code from the index.ts - fixed ETA calculation
This commit is contained in:
parent
377e416825
commit
b8457b9c5a
6 changed files with 247 additions and 275 deletions
22
README.md
22
README.md
|
@ -10,10 +10,19 @@
|
|||
|
||||
| Game version | Launcher version | Patch version |
|
||||
| :---: | :---: | :---: |
|
||||
| 2.2.0 | 2.2.0-beta1 | 2.2.0-testing |
|
||||
| 2.2.0 | 2.2.0-beta2 | 2.2.0-testing |
|
||||
|
||||
Download from [Releases](https://notabug.org/nobody/an-anime-game-launcher/releases)
|
||||
|
||||
# Requirements
|
||||
|
||||
To work this launcher requires
|
||||
|
||||
* wine
|
||||
* winecfg
|
||||
* winetricks
|
||||
* unzip
|
||||
|
||||
# Development
|
||||
|
||||
## Build from source
|
||||
|
@ -28,6 +37,17 @@ npm run build:linux
|
|||
npm start
|
||||
```
|
||||
|
||||
# Roadmap
|
||||
|
||||
To 2.2.0-release1
|
||||
|
||||
* Fix AppImage builds
|
||||
* Make Proton-GE default compatibility tool and fix game input issues
|
||||
* Add additional telemetry checking
|
||||
* Add preferences menu
|
||||
* Add background banners for different languages
|
||||
* Add launcher updates notifications
|
||||
|
||||
<br>
|
||||
|
||||
### Please, try to use "An Anime Game" phrase instead of the real game name to avoid search engines parsing
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "an-anime-game-linux-launcher",
|
||||
"version": "2.2.0-beta1",
|
||||
"version": "2.2.0-beta2",
|
||||
"description": "An Anime Game Linux Launcher",
|
||||
"author": "Nikita Podvirnyy",
|
||||
"license": "GPL-3.0",
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
echo "[NOTE] This patch is not required as of 2021-10-13. However, it might become"
|
||||
echo " necessary afterwards (Friday?). If that's the case, comment the line below."
|
||||
exit 0
|
||||
|
||||
|
||||
# MacOS and *BSD do not have md5sum: use md5 instead
|
||||
if [[ $(uname) == "Darwin" || $(uname) == *"BSD" ]]; then
|
||||
md5sum() {
|
||||
|
@ -41,13 +36,6 @@ echo "[INFO] Patch to fix a login and runtime crash"
|
|||
echo ""
|
||||
|
||||
# ===========================================================
|
||||
echo "[WARNING] Hereby you are violating the game's Terms of Service!"
|
||||
echo " Do you accept the risk and possible consequences?"
|
||||
read -p "Accept? [y/n] " choice
|
||||
|
||||
if [[ ! "$choice" == [JjSsYy]* ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "--- Applying xLua patch"
|
||||
|
|
|
@ -21,6 +21,7 @@ export class Genshinlib
|
|||
public static readonly patchDir: string = path.join(path.dirname(__dirname), 'patch');
|
||||
public static readonly patchJson: string = path.join(this.patchDir, 'patch.json');
|
||||
public static readonly patchSh = path.join(this.patchDir, 'patch.sh');
|
||||
public static readonly patchAntiCrashSh = path.join(this.patchDir, 'patch_anti_logincrash.sh');
|
||||
|
||||
public static readonly launcherDir: string = path.join(os.homedir(), 'genshin-impact-launcher');
|
||||
public static readonly launcherJson: string = path.join(this.launcherDir, 'launcher.json');
|
||||
|
@ -186,13 +187,14 @@ export class Genshinlib
|
|||
'Executing load_times',
|
||||
'Executing load_trebuchet',
|
||||
'Executing load_verdana',
|
||||
'Executing load_webdings'
|
||||
'Executing load_webdings',
|
||||
'Executing load_usetakefocus n'
|
||||
];
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let installationProgress = 0;
|
||||
|
||||
let installerProcess = spawn('winetricks', ['corefonts'], {
|
||||
let installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n'], {
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: path
|
||||
|
@ -221,4 +223,38 @@ export class Genshinlib
|
|||
{
|
||||
return fs.existsSync(path.join(prefixPath, 'drive_c'));
|
||||
}
|
||||
|
||||
public static applyPatch (onFinish: () => void, onData: (data: string) => void)
|
||||
{
|
||||
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
});
|
||||
|
||||
patcherProcess.stdout.on('data', (data: string) => onData(data));
|
||||
|
||||
patcherProcess.on('close', () => {
|
||||
let patcherAntiCrashProcess = spawn('bash', [Genshinlib.patchAntiCrashSh], {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
});
|
||||
|
||||
patcherAntiCrashProcess.stdout.on('data', (data: string) => onData(data));
|
||||
|
||||
patcherAntiCrashProcess.on('close', () => {
|
||||
Genshinlib.setConfig({
|
||||
...Genshinlib.getConfig(),
|
||||
patch: Genshinlib.getPatchInfo()
|
||||
});
|
||||
|
||||
onFinish();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
150
src/ts/LauncherUI.ts
Normal file
150
src/ts/LauncherUI.ts
Normal file
|
@ -0,0 +1,150 @@
|
|||
import $ from 'cash-dom';
|
||||
|
||||
type LauncherState =
|
||||
'patch-unavailable' |
|
||||
'test-patch-available' |
|
||||
'patch-applying' |
|
||||
'game-update-available' |
|
||||
'game-installation-available' |
|
||||
'game-launch-available';
|
||||
|
||||
export class LauncherUI
|
||||
{
|
||||
protected static _launcherState: LauncherState = 'game-launch-available';
|
||||
|
||||
public static get launcherState(): LauncherState
|
||||
{
|
||||
return this._launcherState;
|
||||
}
|
||||
|
||||
public static setState (state: LauncherState)
|
||||
{
|
||||
$('#downloader-panel').css('display', 'none');
|
||||
$('#launch').css('display', 'block');
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case 'patch-unavailable':
|
||||
$('#launch').text('Patch required');
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
|
||||
$('#launch').addClass('hint--top')
|
||||
.addClass('hint--medium');
|
||||
|
||||
$('#launch').attr('data-hint', 'This game version doesn\'t have the anti-cheat patch. Please, wait a few days before it will be created');
|
||||
|
||||
break;
|
||||
|
||||
case 'test-patch-available':
|
||||
$('#launch').text('Apply test patch');
|
||||
|
||||
$('#launch').addClass('button-blue')
|
||||
.addClass('hint--top')
|
||||
.addClass('hint--large');
|
||||
|
||||
$('#launch').attr('data-hint', 'This game version has the anti-cheat patch, but it is in the test phase. You can wait a few days until it will become stable or apply it on your own risc');
|
||||
|
||||
break;
|
||||
|
||||
case 'patch-applying':
|
||||
$('#launch').text('Applying patch');
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
|
||||
break;
|
||||
|
||||
case 'game-update-available':
|
||||
$('#launch').text('Update');
|
||||
|
||||
break;
|
||||
|
||||
case 'game-installation-available':
|
||||
$('#launch').text('Install');
|
||||
|
||||
break;
|
||||
|
||||
case 'game-launch-available':
|
||||
$('#launch').removeAttr('disabled')
|
||||
.removeAttr('data-hint');
|
||||
|
||||
$('#launch').removeClass('button-blue')
|
||||
.removeClass('hint--top')
|
||||
.removeClass('hint--medium')
|
||||
.removeClass('hint--large');
|
||||
|
||||
$('#launch').text('Launch');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
this._launcherState = state;
|
||||
}
|
||||
|
||||
protected static progressBar = {
|
||||
beganAt: 0,
|
||||
prevTime: 0,
|
||||
temp: 0
|
||||
};
|
||||
|
||||
public static initProgressBar (): void
|
||||
{
|
||||
this.progressBar = {
|
||||
beganAt: Date.now(),
|
||||
prevTime: Date.now(),
|
||||
temp: 0
|
||||
};
|
||||
|
||||
$('#downloaded').text('');
|
||||
$('#speed').text('');
|
||||
$('#eta').text('');
|
||||
|
||||
$('#downloader .progress').css('width', '0');
|
||||
|
||||
$('#downloader-panel').css('display', 'block');
|
||||
$('#launch').css('display', 'none');
|
||||
}
|
||||
|
||||
public static updateProgressBar (prefix: string, current: number, total: number, difference: number): void
|
||||
{
|
||||
$('#downloaded').text(`${prefix}: ${ Math.round(current / total * 100) }% (${ (current / 1024 / 1024 / 1024).toFixed(2) } GB / ${ Math.round(total / 1024 / 1024 / 1024).toFixed(2) } GB)`);
|
||||
|
||||
this.progressBar.temp += difference;
|
||||
|
||||
if (Date.now() - this.progressBar.prevTime > 1000)
|
||||
{
|
||||
let elapsed = (Date.now() - this.progressBar.beganAt) / 1000;
|
||||
let eta = Math.round(total * elapsed / current - elapsed);
|
||||
|
||||
let etaHours = Math.floor(eta / 3600),
|
||||
etaMinutes = Math.floor((eta - etaHours * 3600) / 60),
|
||||
etaSeconds = eta - etaHours * 3600 - etaMinutes * 60;
|
||||
|
||||
if (etaHours < 10) // @ts-expect-error
|
||||
etaHours = '0' + etaHours.toString();
|
||||
|
||||
if (etaMinutes < 10) // @ts-expect-error
|
||||
etaMinutes = '0' + etaMinutes.toString();
|
||||
|
||||
if (etaSeconds < 10) // @ts-expect-error
|
||||
etaSeconds = '0' + etaSeconds.toString();
|
||||
|
||||
$('#downloader .progress').css('width', `${ Math.round(current / total * 100) }%`);
|
||||
$('#speed').text(`${ (this.progressBar.temp / (Date.now() - this.progressBar.prevTime) * 1000 / 1024 / 1024).toFixed(2) } MB/s`);
|
||||
$('#eta').text(`ETA: ${etaHours}:${etaMinutes}:${etaSeconds}`);
|
||||
|
||||
this.progressBar.prevTime = Date.now();
|
||||
this.progressBar.temp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static clearProgressBar(): void
|
||||
{
|
||||
$('#downloader-panel').css('display', 'none');
|
||||
$('#launch').css('display', 'block');
|
||||
|
||||
$('#downloaded').text('');
|
||||
$('#speed').text('');
|
||||
$('#eta').text('');
|
||||
|
||||
$('#downloader .progress').css('width', '0');
|
||||
}
|
||||
}
|
296
src/ts/index.ts
296
src/ts/index.ts
|
@ -1,11 +1,12 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { exec, spawn } = require('child_process');
|
||||
const { exec } = require('child_process');
|
||||
const { ipcRenderer } = require('electron');
|
||||
|
||||
import $ from 'cash-dom';
|
||||
|
||||
import { Genshinlib } from './Genshinlib';
|
||||
import { LauncherUI } from './LauncherUI';
|
||||
|
||||
if (!fs.existsSync(Genshinlib.prefixDir))
|
||||
fs.mkdirSync(Genshinlib.prefixDir, { recursive: true });
|
||||
|
@ -16,28 +17,17 @@ $(() => {
|
|||
|
||||
$('body').css('background-image', `url(${ Genshinlib.getBackgroundUri() })`);
|
||||
|
||||
// TODO: create LauncherUI class and move a lot of code there
|
||||
// because it becomes a fucking unfunny joke
|
||||
|
||||
Genshinlib.getData().then(data => {
|
||||
// Update available
|
||||
if (Genshinlib.version != data.game.latest.version)
|
||||
$('#launch').text(Genshinlib.version === null ? 'Install' : 'Update');
|
||||
LauncherUI.setState(Genshinlib.version === null ? 'game-installation-available' : 'game-update-available');
|
||||
|
||||
// Patch version is incorrect
|
||||
else if (Genshinlib.getConfig().patch.version != Genshinlib.getPatchInfo().version)
|
||||
{
|
||||
// Patch is not available
|
||||
if (Genshinlib.getPatchInfo().version !== data.game.latest.version)
|
||||
{
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
$('#launch').text('Patch required');
|
||||
|
||||
$('#launch').addClass('hint--top');
|
||||
$('#launch').addClass('hint--medium');
|
||||
|
||||
$('#launch').attr('data-hint', 'This game version doesn\'t have the anti-cheat patch. Please, wait a few days before it will be created');
|
||||
}
|
||||
LauncherUI.setState('patch-unavailable');
|
||||
|
||||
// Patch available
|
||||
else if (Genshinlib.getPatchInfo().version === data.game.latest.version)
|
||||
|
@ -47,41 +37,15 @@ $(() => {
|
|||
{
|
||||
console.log(`%c> Applying patch...`, 'font-size: 16px');
|
||||
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
$('#launch').text('Applying patch...');
|
||||
LauncherUI.setState('patch-applying');
|
||||
|
||||
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
});
|
||||
|
||||
patcherProcess.stdout.on('data', (data: string) => console.log(data.toString()));
|
||||
|
||||
patcherProcess.on('close', () => {
|
||||
Genshinlib.setConfig({
|
||||
...Genshinlib.getConfig(),
|
||||
patch: Genshinlib.getPatchInfo()
|
||||
});
|
||||
|
||||
$('#launch').removeAttr('disabled');
|
||||
$('#launch').text('Launch');
|
||||
});
|
||||
Genshinlib.applyPatch(() => {
|
||||
LauncherUI.setState('game-launch-available');
|
||||
}, (data) => console.log(data.toString()));
|
||||
}
|
||||
|
||||
// Patch is in testing phase
|
||||
else
|
||||
{
|
||||
$('#launch').text('Apply test patch');
|
||||
|
||||
$('#launch').addClass('button-blue');
|
||||
$('#launch').addClass('hint--top');
|
||||
$('#launch').addClass('hint--large');
|
||||
|
||||
$('#launch').attr('data-hint', 'This game version has the anti-cheat patch, but it is in the test phase. You can wait a few days until it will become stable or apply it on your own risc');
|
||||
}
|
||||
else LauncherUI.setState('test-patch-available');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,28 +55,11 @@ $(() => {
|
|||
{
|
||||
console.log(`%c> Applying patch...`, 'font-size: 16px');
|
||||
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
$('#launch').text('Applying patch...');
|
||||
LauncherUI.setState('patch-applying');
|
||||
|
||||
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
});
|
||||
|
||||
patcherProcess.stdout.on('data', (data: string) => console.log(data.toString()));
|
||||
|
||||
patcherProcess.on('close', () => {
|
||||
Genshinlib.setConfig({
|
||||
...Genshinlib.getConfig(),
|
||||
patch: Genshinlib.getPatchInfo()
|
||||
});
|
||||
|
||||
$('#launch').removeAttr('disabled');
|
||||
$('#launch').text('Launch');
|
||||
});
|
||||
Genshinlib.applyPatch(() => {
|
||||
LauncherUI.setState('game-launch-available');
|
||||
}, (data) => console.log(data.toString()));
|
||||
}
|
||||
|
||||
$('#launch').on('click', async () => {
|
||||
|
@ -168,34 +115,11 @@ $(() => {
|
|||
{
|
||||
console.log(`%c> Applying patch...`, 'font-size: 16px');
|
||||
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
$('#launch').text('Applying patch...');
|
||||
LauncherUI.setState('patch-applying');
|
||||
|
||||
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
});
|
||||
|
||||
patcherProcess.stdout.on('data', (data: string) => console.log(data.toString()));
|
||||
|
||||
patcherProcess.on('close', () => {
|
||||
Genshinlib.setConfig({
|
||||
...Genshinlib.getConfig(),
|
||||
patch: Genshinlib.getPatchInfo()
|
||||
});
|
||||
|
||||
$('#launch').removeClass('button-blue');
|
||||
$('#launch').removeClass('hint--top');
|
||||
$('#launch').removeClass('hint--large');
|
||||
|
||||
$('#launch').removeAttr('disabled');
|
||||
$('#launch').removeAttr('data-hint');
|
||||
|
||||
$('#launch').text('Launch');
|
||||
});
|
||||
Genshinlib.applyPatch(() => {
|
||||
LauncherUI.setState('game-launch-available');
|
||||
}, (data) => console.log(data.toString()));
|
||||
}
|
||||
|
||||
// Installing game
|
||||
|
@ -203,9 +127,6 @@ $(() => {
|
|||
{
|
||||
console.log(`%c> Downloading game data...`, 'font-size: 16px');
|
||||
|
||||
$('#launch').css('display', 'none');
|
||||
$('#downloader-panel').css('display', 'block');
|
||||
|
||||
let diff = {
|
||||
path: data.game.latest.path,
|
||||
name: `latest-${data.game.latest.version}.zip`,
|
||||
|
@ -223,41 +144,14 @@ $(() => {
|
|||
if (fs.existsSync(path.join(Genshinlib.gameDir, diff.name)))
|
||||
fs.unlinkSync(path.join(Genshinlib.gameDir, diff.name));
|
||||
|
||||
let beganAt = Date.now(), prevTime = Date.now(), downloaded = 0;
|
||||
|
||||
/**
|
||||
* Downloading game
|
||||
*/
|
||||
|
||||
LauncherUI.initProgressBar();
|
||||
|
||||
Genshinlib.downloadFile(diff.path, path.join(Genshinlib.launcherDir, diff.name), (current: number, total: number, difference: number) => {
|
||||
$('#downloaded').text(`Downloaded: ${ Math.round(current / total * 100) }% (${ (current / 1024 / 1024 / 1024).toFixed(2) } GB / ${ Math.round(total / 1024 / 1024 / 1024).toFixed(2) } GB)`);
|
||||
|
||||
downloaded += difference;
|
||||
|
||||
if (Date.now() - prevTime > 1000)
|
||||
{
|
||||
let eta = Math.round(total / current * (Date.now() - beganAt) / 1000); // seconds
|
||||
|
||||
let etaHours = Math.floor(eta / 3600),
|
||||
etaMinutes = Math.floor((eta - etaHours * 3600) / 60),
|
||||
etaSeconds = eta - etaHours * 3600 - etaMinutes * 60;
|
||||
|
||||
if (etaHours < 10) // @ts-expect-error
|
||||
etaHours = '0' + etaHours.toString();
|
||||
|
||||
if (etaMinutes < 10) // @ts-expect-error
|
||||
etaMinutes = '0' + etaMinutes.toString();
|
||||
|
||||
if (etaSeconds < 10) // @ts-expect-error
|
||||
etaSeconds = '0' + etaSeconds.toString();
|
||||
|
||||
$('#downloader .progress').css('width', `${ Math.round(current / total * 100) }%`);
|
||||
$('#speed').text(`${ (downloaded / (Date.now() - prevTime) * 1000 / 1024 / 1024).toFixed(2) } MB/s`);
|
||||
$('#eta').text(`ETA: ${etaHours}:${etaMinutes}:${etaSeconds}`);
|
||||
|
||||
prevTime = Date.now();
|
||||
downloaded = 0;
|
||||
}
|
||||
LauncherUI.updateProgressBar('Downloaded', current, total, difference);
|
||||
}).then(() => {
|
||||
/**
|
||||
* Unpacking downloaded game
|
||||
|
@ -265,44 +159,18 @@ $(() => {
|
|||
|
||||
console.log(`%c> Unpacking game data...`, 'font-size: 16px');
|
||||
|
||||
$('#speed').text('');
|
||||
$('#eta').text('');
|
||||
|
||||
if (!fs.existsSync(Genshinlib.gameDir))
|
||||
fs.mkdirSync(Genshinlib.gameDir, { recursive: true });
|
||||
|
||||
let beganAt = Date.now(), prevTime = Date.now(), unpacked = 0;
|
||||
|
||||
LauncherUI.initProgressBar();
|
||||
|
||||
Genshinlib.unzip(path.join(Genshinlib.launcherDir, diff.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
|
||||
$('#downloaded').text(`Unpacking: ${ Math.round(current / total * 100) }% (${ (current / 1024 / 1024 / 1024).toFixed(2) } GB / ${ Math.round(total / 1024 / 1024 / 1024).toFixed(2) } GB)`);
|
||||
|
||||
unpacked += difference;
|
||||
|
||||
if (Date.now() - prevTime > 1000)
|
||||
{
|
||||
let eta = Math.round(total / current * (Date.now() - beganAt) / 1000); // seconds
|
||||
|
||||
let etaHours = Math.floor(eta / 3600),
|
||||
etaMinutes = Math.floor((eta - etaHours * 3600) / 60),
|
||||
etaSeconds = eta - etaHours * 3600 - etaMinutes * 60;
|
||||
|
||||
if (etaHours < 10) // @ts-expect-error
|
||||
etaHours = '0' + etaHours.toString();
|
||||
|
||||
if (etaMinutes < 10) // @ts-expect-error
|
||||
etaMinutes = '0' + etaMinutes.toString();
|
||||
|
||||
if (etaSeconds < 10) // @ts-expect-error
|
||||
etaSeconds = '0' + etaSeconds.toString();
|
||||
|
||||
$('#downloader .progress').css('width', `${ Math.round(current / total * 100) }%`);
|
||||
$('#speed').text(`${ (unpacked / (Date.now() - prevTime) * 1000 / 1024 / 1024).toFixed(2) } MB/s`);
|
||||
$('#eta').text(`ETA: ${etaHours}:${etaMinutes}:${etaSeconds}`);
|
||||
|
||||
prevTime = Date.now();
|
||||
unpacked = 0;
|
||||
}
|
||||
LauncherUI.updateProgressBar('Unpacking', current, total, difference);
|
||||
}).then(() => {
|
||||
/**
|
||||
* Downloading voice data
|
||||
*/
|
||||
|
||||
console.log(`%c> Downloading voice data...`, 'font-size: 16px');
|
||||
|
||||
fs.unlinkSync(path.join(Genshinlib.launcherDir, diff.name));
|
||||
|
@ -317,82 +185,21 @@ $(() => {
|
|||
break;
|
||||
}
|
||||
|
||||
let beganAt = Date.now(), prevTime = Date.now(), downloaded = 0;
|
||||
|
||||
/**
|
||||
* Downloading voice data
|
||||
*/
|
||||
LauncherUI.initProgressBar();
|
||||
|
||||
Genshinlib.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => {
|
||||
$('#downloaded').text(`Downloaded: ${ Math.round(current / total * 100) }% (${ (current / 1024 / 1024 / 1024).toFixed(2) } GB / ${ Math.round(total / 1024 / 1024 / 1024).toFixed(2) } GB)`);
|
||||
|
||||
downloaded += difference;
|
||||
|
||||
if (Date.now() - prevTime > 1000)
|
||||
{
|
||||
let eta = Math.round(total / current * (Date.now() - beganAt) / 1000); // seconds
|
||||
|
||||
let etaHours = Math.floor(eta / 3600),
|
||||
etaMinutes = Math.floor((eta - etaHours * 3600) / 60),
|
||||
etaSeconds = eta - etaHours * 3600 - etaMinutes * 60;
|
||||
|
||||
if (etaHours < 10) // @ts-expect-error
|
||||
etaHours = '0' + etaHours.toString();
|
||||
|
||||
if (etaMinutes < 10) // @ts-expect-error
|
||||
etaMinutes = '0' + etaMinutes.toString();
|
||||
|
||||
if (etaSeconds < 10) // @ts-expect-error
|
||||
etaSeconds = '0' + etaSeconds.toString();
|
||||
|
||||
$('#downloader .progress').css('width', `${ Math.round(current / total * 100) }%`);
|
||||
$('#speed').text(`${ (downloaded / (Date.now() - prevTime) * 1000 / 1024 / 1024).toFixed(2) } MB/s`);
|
||||
$('#eta').text(`ETA: ${etaHours}:${etaMinutes}:${etaSeconds}`);
|
||||
|
||||
prevTime = Date.now();
|
||||
downloaded = 0;
|
||||
}
|
||||
LauncherUI.updateProgressBar('Downloaded', current, total, difference);
|
||||
}).then(() => {
|
||||
/**
|
||||
* Unpacking downloaded game
|
||||
*/
|
||||
|
||||
console.log(`%c> Unpacking voice data...`, 'font-size: 16px');
|
||||
|
||||
$('#speed').text('');
|
||||
$('#eta').text('');
|
||||
console.log(`%c> Unpacking voice data...`, 'font-size: 16px');
|
||||
|
||||
let beganAt = Date.now(), prevTime = Date.now(), unpacked = 0;
|
||||
LauncherUI.initProgressBar();
|
||||
|
||||
Genshinlib.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
|
||||
$('#downloaded').text(`Unpacking: ${ Math.round(current / total * 100) }% (${ (current / 1024 / 1024 / 1024).toFixed(2) } GB / ${ Math.round(total / 1024 / 1024 / 1024).toFixed(2) } GB)`);
|
||||
|
||||
unpacked += difference;
|
||||
|
||||
if (Date.now() - prevTime > 1000)
|
||||
{
|
||||
let eta = Math.round(total / current * (Date.now() - beganAt) / 1000); // seconds
|
||||
|
||||
let etaHours = Math.floor(eta / 3600),
|
||||
etaMinutes = Math.floor((eta - etaHours * 3600) / 60),
|
||||
etaSeconds = eta - etaHours * 3600 - etaMinutes * 60;
|
||||
|
||||
if (etaHours < 10) // @ts-expect-error
|
||||
etaHours = '0' + etaHours.toString();
|
||||
|
||||
if (etaMinutes < 10) // @ts-expect-error
|
||||
etaMinutes = '0' + etaMinutes.toString();
|
||||
|
||||
if (etaSeconds < 10) // @ts-expect-error
|
||||
etaSeconds = '0' + etaSeconds.toString();
|
||||
|
||||
$('#downloader .progress').css('width', `${ Math.round(current / total * 100) }%`);
|
||||
$('#speed').text(`${ (unpacked / (Date.now() - prevTime) * 1000 / 1024 / 1024).toFixed(2) } MB/s`);
|
||||
$('#eta').text(`ETA: ${etaHours}:${etaMinutes}:${etaSeconds}`);
|
||||
|
||||
prevTime = Date.now();
|
||||
unpacked = 0;
|
||||
}
|
||||
LauncherUI.updateProgressBar('Unpacking', current, total, difference);
|
||||
}).then(() => {
|
||||
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));
|
||||
|
||||
|
@ -408,45 +215,16 @@ $(() => {
|
|||
|
||||
console.log(`%c> Applying patch...`, 'font-size: 16px');
|
||||
|
||||
// patch-applying state changes only button text
|
||||
$('#downloaded').text('Applying patch...');
|
||||
|
||||
let patcherProcess = spawn('bash', [Genshinlib.patchSh], {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
});
|
||||
|
||||
patcherProcess.stdout.on('data', (data: string) => console.log(data.toString()));
|
||||
|
||||
patcherProcess.on('close', () => {
|
||||
Genshinlib.setConfig({
|
||||
...Genshinlib.getConfig(),
|
||||
patch: Genshinlib.getPatchInfo()
|
||||
});
|
||||
|
||||
$('#launch').css('display', 'block');
|
||||
$('#downloader-panel').css('display', 'none');
|
||||
|
||||
$('#launch').text('Launch');
|
||||
});
|
||||
Genshinlib.applyPatch(() => {
|
||||
LauncherUI.setState('game-launch-available');
|
||||
}, (data) => console.log(data.toString()));
|
||||
}
|
||||
|
||||
// Patch is not available
|
||||
else
|
||||
{
|
||||
$('#launch').css('display', 'block');
|
||||
$('#downloader-panel').css('display', 'none');
|
||||
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
$('#launch').text('Patch required');
|
||||
|
||||
$('#launch').addClass('hint--top');
|
||||
$('#launch').addClass('hint--medium');
|
||||
|
||||
$('#launch').attr('data-hint', 'This game version doesn\'t have the anti-cheat patch. Please, wait a few days before it will be created');
|
||||
}
|
||||
else LauncherUI.setState('patch-unavailable');
|
||||
});
|
||||
}).catch(err => console.log(err));
|
||||
}).catch(err => console.log(err));
|
||||
|
|
Loading…
Reference in a new issue