Merge branch 'term' of Maroxy/an-ordinary-launcher into main

This commit is contained in:
nobody 2021-10-23 19:12:22 +00:00 committed by Gogs
commit 66693b0931
25 changed files with 2251 additions and 1541 deletions

View file

@ -68,6 +68,12 @@ function createWindow ()
// mainWindow.webContents.openDevTools(); // mainWindow.webContents.openDevTools();
} }
// Set language on start
if(Genshinlib.getConfig().lang.launcher)
app.commandLine.appendSwitch('lang', Genshinlib.getConfig().lang.launcher);
else
app.commandLine.appendSwitch('lang', 'en-us');
// This method will be called when Electron has finished // This method will be called when Electron has finished
// initialization and is ready to create browser windows. // initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs. // Some APIs can only be used after this event occurs.
@ -81,6 +87,20 @@ app.whenReady().then(() => {
if (BrowserWindow.getAllWindows().length === 0) if (BrowserWindow.getAllWindows().length === 0)
createWindow(); createWindow();
}); });
// This has to be here otherwise webContents is invalid.
ipcMain.on('changelang', (event, args) => {
app.commandLine.appendSwitch('lang', Genshinlib.getConfig().lang.launcher);
mainWindow.webContents.send('changelang', { 'lang': args.lang });
});
ipcMain.on('updateVP', (event, args) => {
mainWindow.webContents.send('updateVP', { 'oldvp': args.oldvp });
});
ipcMain.on('rpcstate', (event, args) => {
mainWindow.webContents.send('rpcstate', {});
});
}); });
// Quit when all windows are closed, except on macOS. There, it's common // Quit when all windows are closed, except on macOS. There, it's common

View file

@ -45,6 +45,7 @@
}, },
"dependencies": { "dependencies": {
"cash-dom": "^8.1.0", "cash-dom": "^8.1.0",
"discord-rpc": "^4.0.1",
"follow-redirects": "^1.14.4" "follow-redirects": "^1.14.4"
} }
} }

View file

@ -11,39 +11,50 @@
<!-- JS scripts --> <!-- JS scripts -->
<script>require('../js/settings.js');</script> <script>require('../js/settings.js');</script>
<title>Settings</title> <title i18id="SettingsTitle"></title>
</head> </head>
<body> <body>
<div class="menu"> <div class="menu">
<div class="menu-item menu-item-active" anchor="general">General</div> <div class="menu-item menu-item-active" anchor="general" i18id="GeneralSettings">General</div>
<div class="menu-item" anchor="runners">Runners</div> <div class="menu-item" anchor="runners" i18id="Runners">Runners</div>
<div class="menu-item" anchor="dxvks">DXVK</div> <div class="menu-item" anchor="dxvks">DXVK</div>
</div> </div>
<div class="settings"> <div class="settings">
<div class="settings-item" id="general"> <div class="settings-item" id="general">
<h2>General</h2> <h2 i18id="GeneralSettings">General</h2>
<hr>
123<br> <h3 i18id="Langs">Language</h3>
123<br> <select class="dropdown-menu" id="language-list">
123<br> <option value="en-us">English (US)</option>
123<br> <option value="zh-cn">中文(简化)(Chinese Simplified)</option>
123<br> <option value="de-de">Deutsch (German)</option>
123<br> <option value="fr-fr">Français (French)</option>
123<br> <option value="id-id">Indonesia (Indonesian)</option>
123<br> <option value="ja-jp">日本語 (Japanese)</option>
123<br> <option value="ko-kr">한국어 (Korean)</option>
123<br> <option value="pt-pt">Português (Portuguese)</option>
123<br> <option value="ru-ru">Pусский (Russian)</option>
123<br> <option value="es-es">Español (Spanish)</option>
123<br> <option value="th-th">ภาษาไทย (Thai)</option>
123<br><br> <option value="zh-tw">中文(繁體)(Chinese Traditional)</option>
<option value="vi-vn">Tiếng Việt (Vietnamese)</option>
Will be made in beta 7 </select>
<br>
<h3 i18id="Voice">Voice Pack</h3>
<select class="dropdown-menu" id="voice-list" disabled>
<option value="en-us">English (US)</option>
<option value="zh-cn">汉语 (Chinese)</option>
<option value="ja-jp">日本語 (Japanese)</option>
<option value="ko-kr">한국어 (Korean)</option>
</select>
<br>
<h3>Discord RPC</h3>
<input type="checkbox" id="drpc" name="drpc">
<br>
</div> </div>
<hr>
<div class="settings-item" id="runners"> <div class="settings-item" id="runners">
<h2>Runners</h2> <h2>Runners</h2>

17
public/locales/de.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Installieren",
"Launch": "Starten",
"Runners": "Runners",
"Langs": "Sprachen",
"Voice": "Sprachpaket",
"SettingsTitle": "Einstellungen",
"GeneralSettings": "Generell",
"Downloading": "wird Heruntergeladen",
"Unpack": "wird Entpackt",
"GameDownloaded": "Spiel würde erfolgreich heruntergeladen",
"ApplyPatch": "Patch wird angewendet",
"PatchRequired": "Patch nicht verfügbar",
"PatchRequiredHint": "Diese Spielversion hat noch kein anti-cheat patch, Bitte warten sie ein paar Tage bevor sie es erneut versuchen.",
"TestPatch": "Test Patch anwenden",
"TestPatchHint": "Diese Spielversion hat ein anti-cheat patch aber es befindet sich noch in der Testphase. Sie können noch ein paar Tage warten bis es Stabil ist oder auf eigenen Risiko den Testpatch anwenden."
}

17
public/locales/en-us.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/en.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/es.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/fr.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/id.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/ja.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "インストール",
"Launch": "打ち上げ",
"Runners": "Runners",
"Langs": "言語",
"Voice": "ボイスパック",
"SettingsTitle": "設定",
"GeneralSettings": "一般",
"Downloading": "ダウンロード中",
"Unpack": "開梱",
"GameDownloaded": "ゲームのインストールに成功しました",
"ApplyPatch": "パッチの適用...",
"PatchRequired": "要パッチ",
"PatchRequiredHint": "このゲームバージョンにはアンチチートパッチがありません。数日待ってから再度お試しください。",
"TestPatch": "テストパッチの適用",
"TestPatchHint": "このゲームバージョンにはアンチチートパッチがありますが、テスト段階にあります。安定するまで数日お待ちいただくか、ご自身の責任で適用してください。"
}

17
public/locales/ko.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/pt.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/ru.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/th.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/vi.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "Install",
"Launch": "Launch",
"Runners": "Runners",
"Langs": "Languages",
"Voice": "Voice Pack",
"SettingsTitle": "Settings",
"GeneralSettings": "General",
"Downloading": "Downloading",
"Unpack": "Unpacking",
"GameDownloaded": "Game was successfully installed",
"ApplyPatch": "Applying patch...",
"PatchRequired": "Patch required",
"PatchRequiredHint": "This game version doesn't have an anti-cheat patch. Please, wait a few days and try again.",
"TestPatch": "Apply test patch",
"TestPatchHint": "This game version has an anti-cheat patch, but it is in the testing phase. You can wait a few days until it is stable or apply it at your own risk."
}

17
public/locales/zh-cn.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "安装",
"Launch": "发射",
"Runners": "Runners",
"Langs": "语言",
"Voice": "语音包",
"SettingsTitle": "设置",
"GeneralSettings": "一般的",
"Downloading": "下载",
"Unpack": "开箱",
"GameDownloaded": "游戏安装成功",
"ApplyPatch": "应用补丁...",
"PatchRequired": "需要补丁",
"PatchRequiredHint": "此游戏版本没有防作弊补丁。请等待几天,然后重试。",
"TestPatch": "应用测试补丁",
"TestPatchHint": "此游戏版本有防作弊补丁,但处于测试阶段。您可以等待几天直到它稳定或自担风险应用它。"
}

17
public/locales/zh-tw.json Normal file
View file

@ -0,0 +1,17 @@
{
"Install": "安裝",
"Launch": "發射",
"Runners": "Runners",
"Langs": "語言",
"Voice": "語音包",
"SettingsTitle": "設置",
"GeneralSettings": "一般的",
"Downloading": "下載",
"Unpack": "Unpacking",
"GameDownloaded": "遊戲安裝成功",
"ApplyPatch": "Applying patch...",
"PatchRequired": "需要補丁",
"PatchRequiredHint": "此遊戲版本沒有防作弊補丁。請等待幾天,然後重試。",
"TestPatch": "應用測試補丁",
"TestPatchHint": "該遊戲版本有一個反作弊補丁,但處於測試階段。您可以等待幾天直到它穩定或自擔風險應用它。"
}

View file

@ -150,6 +150,15 @@
"folder": "Proton-6.14-GE-1", "folder": "Proton-6.14-GE-1",
"makeFolder": false, "makeFolder": false,
"executable": "files/bin/wine64" "executable": "files/bin/wine64"
},
{
"name": "Proton-5.21-GE-1",
"version": "5.21-GE-1",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/5.21-GE-1/Proton-5.21-GE-1.tar.gz",
"archive": "tar",
"folder": "Proton-5.21-GE-1",
"makeFolder": false,
"executable": "files/bin/wine64"
} }
] ]
} }

View file

@ -99,3 +99,17 @@ body
img img
filter: invert(70%) sepia(13%) saturate(241%) hue-rotate(196deg) brightness(97%) contrast(91%) filter: invert(70%) sepia(13%) saturate(241%) hue-rotate(196deg) brightness(97%) contrast(91%)
.dropdown-menu
display: flex
align-items: center
height: 52px
margin-bottom: 8px
padding: 0 12px
border-radius: 12px
background-color: #f1f4f9
font-size: 18px
cursor: pointer

View file

@ -42,6 +42,7 @@ type Config = {
folder: string, folder: string,
executable: string executable: string
}, },
rpc: boolean,
dxvk: string|null dxvk: string|null
}; };
@ -110,11 +111,12 @@ export class Genshinlib
}, },
background: { background: {
time: null, time: null,
name: null file: null
}, },
version: null, version: null,
patch: null, patch: null,
runner: null runner: null,
rpc: false
}, null, 4)); }, null, 4));
return JSON.parse(fs.readFileSync(this.launcherJson)); return JSON.parse(fs.readFileSync(this.launcherJson));
@ -352,7 +354,7 @@ export class Genshinlib
} }
// WINEPREFIX='/home/observer/genshin-impact-launcher/wineprefix' winetricks corefonts usetakefocus=n // WINEPREFIX='/home/observer/genshin-impact-launcher/wineprefix' winetricks corefonts usetakefocus=n
public static async installPrefix (path: string, progress: (output: string, current: number, total: number) => void): Promise<void> public static async installPrefix (prefixpath: string, progress: (output: string, current: number, total: number) => void): Promise<void>
{ {
let installationSteps = [ let installationSteps = [
'Executing w_do_call corefonts', 'Executing w_do_call corefonts',
@ -367,18 +369,32 @@ export class Genshinlib
'Executing load_trebuchet', 'Executing load_trebuchet',
'Executing load_verdana', 'Executing load_verdana',
'Executing load_webdings', 'Executing load_webdings',
'Executing load_usetakefocus n' 'Executing load_usetakefocus n',
'Executing load_dxvk'
]; ];
return new Promise((resolve) => { return new Promise((resolve) => {
let installationProgress = 0; let installationProgress = 0;
let installerProcess;
let installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n'], { if (this.getConfig().runner)
{
installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n', 'dxvk191'], {
env: { env: {
...process.env, ...process.env,
WINEPREFIX: path WINEPREFIX: prefixpath,
WINE: path.join(this.runnersDir, this.getConfig().runner?.folder, this.getConfig().runner?.executable)
} }
}); });
}
else {
installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n'], {
env: {
...process.env,
WINEPREFIX: prefixpath
}
});
}
installerProcess.stdout.on('data', (data: string) => { installerProcess.stdout.on('data', (data: string) => {
let str = data.toString(); let str = data.toString();
@ -430,6 +446,16 @@ export class Genshinlib
patcherProcess.stdout.on('data', (data: string) => onData(data)); patcherProcess.stdout.on('data', (data: string) => onData(data));
patcherProcess.on('close', () => { patcherProcess.on('close', () => {
// Make sure that launcher.bat exists if not run patch.sh again.
if (!path.join(this.gameDir, 'launcher.bat'))
exec(`yes yes | ${path.join(patchDir, 'patch.sh')}`, {
cwd: this.gameDir,
env: {
...process.env,
WINEPREFIX: this.prefixDir
}
});
// Execute the patch file with "yes" in the beginning to agree to the choice. // Execute the patch file with "yes" in the beginning to agree to the choice.
let patcherAntiCrashProcess = exec(`yes | ${path.join(patchDir, 'patch_anti_logincrash.sh')}`, { let patcherAntiCrashProcess = exec(`yes | ${path.join(patchDir, 'patch_anti_logincrash.sh')}`, {
cwd: this.gameDir, cwd: this.gameDir,

View file

@ -1,4 +1,5 @@
import $ from 'cash-dom'; import $ from 'cash-dom';
import i18n from './i18n';
type LauncherState = type LauncherState =
'patch-unavailable' | 'patch-unavailable' |
@ -17,6 +18,11 @@ export class LauncherUI
return this._launcherState; return this._launcherState;
} }
public static refreshLang (langcode: string)
{
i18n.updatelang(langcode);
}
public static setState (state: LauncherState) public static setState (state: LauncherState)
{ {
$('#downloader-panel').css('display', 'none'); $('#downloader-panel').css('display', 'none');
@ -25,29 +31,29 @@ export class LauncherUI
switch (state) switch (state)
{ {
case 'patch-unavailable': case 'patch-unavailable':
$('#launch').text('Patch required'); $('#launch').text(i18n.translate('PatchRequired'));
$('#launch').attr('disabled', 'disabled'); $('#launch').attr('disabled', 'disabled');
$('#launch').addClass('hint--top') $('#launch').addClass('hint--top')
.addClass('hint--medium'); .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'); $('#launch').attr('data-hint', i18n.translate('PatchRequiredHint'));
break; break;
case 'test-patch-available': case 'test-patch-available':
$('#launch').text('Apply test patch'); $('#launch').text(i18n.translate('TestPatch'));
$('#launch').addClass('button-blue') $('#launch').addClass('button-blue')
.addClass('hint--top') .addClass('hint--top')
.addClass('hint--large'); .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'); $('#launch').attr('data-hint', i18n.translate('TestPatchHint'));
break; break;
case 'patch-applying': case 'patch-applying':
$('#launch').text('Applying patch'); $('#launch').text(i18n.translate('ApplyPatch'));
$('#launch').attr('disabled', 'disabled'); $('#launch').attr('disabled', 'disabled');
break; break;
@ -58,7 +64,7 @@ export class LauncherUI
break; break;
case 'game-installation-available': case 'game-installation-available':
$('#launch').text('Install'); $('#launch').text(i18n.translate('Install'));
break; break;
@ -71,7 +77,7 @@ export class LauncherUI
.removeClass('hint--medium') .removeClass('hint--medium')
.removeClass('hint--large'); .removeClass('hint--large');
$('#launch').text('Launch'); $('#launch').text(i18n.translate('Launch'));
break; break;
} }

39
src/ts/i18n.ts Normal file
View file

@ -0,0 +1,39 @@
const path = require("path");
const fs = require('fs');
let loadedLanguage: any;
function i18n(): any {
if(fs.existsSync(path.join(path.dirname(__dirname), 'locales', navigator.language.toLowerCase() + '.json'))) {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', navigator.language.toLowerCase() + '.json'), 'utf8'));
}
else {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', 'en.json'), 'utf8'));
}
};
i18n.prototype.translate = function(phrase: any) {
let translation = loadedLanguage[phrase];
if(translation === undefined) {
translation = phrase;
}
return translation
}
i18n.prototype.updatelang = function(newlang: string) {
// Test if the locale is the same string so if it's de-de or id-id remove -de or -id like navigator.language does.
let samecode = new RegExp(`(${newlang.toLowerCase().replace(/-.*$/, '')}.*){2}`, 'g');
samecode.test(newlang.toLowerCase()) ? newlang = newlang.toLowerCase().replace(/-.*$/, '') : newlang = newlang.toLowerCase();
if (newlang == 'ja-jp') newlang = 'ja';
if (newlang == 'vi-vn') newlang = 'vi';
if(fs.existsSync(path.join(path.dirname(__dirname), 'locales', newlang + '.json'))) {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', newlang + '.json'), 'utf8'));
}
else {
loadedLanguage = JSON.parse(fs.readFileSync(path.join(path.dirname(__dirname), 'locales', 'en.json'), 'utf8'));
}
}
export default new (i18n as any);

View file

@ -1,9 +1,12 @@
const path = require('path'); const path = require('path');
const fs = require('fs'); const fs = require('fs');
const discordrpc = require("discord-rpc");
const { exec } = require('child_process'); const { exec } = require('child_process');
const { ipcRenderer } = require('electron'); const { ipcRenderer } = require('electron');
let rpc: any;
import $ from 'cash-dom'; import $ from 'cash-dom';
import i18n from './i18n';
import { Genshinlib } from './Genshinlib'; import { Genshinlib } from './Genshinlib';
import { LauncherUI } from './LauncherUI'; import { LauncherUI } from './LauncherUI';
@ -11,10 +14,114 @@ import { LauncherUI } from './LauncherUI';
if (!fs.existsSync(Genshinlib.prefixDir)) if (!fs.existsSync(Genshinlib.prefixDir))
fs.mkdirSync(Genshinlib.prefixDir, { recursive: true }); fs.mkdirSync(Genshinlib.prefixDir, { recursive: true });
if (!fs.existsSync(Genshinlib.runnersDir))
fs.mkdirSync(Genshinlib.runnersDir, { recursive: true });
$(() => { $(() => {
if (Genshinlib.version !== null) if (Genshinlib.version !== null)
document.title = 'Genshin Impact Linux Launcher - ' + Genshinlib.version; document.title = 'Genshin Impact Linux Launcher - ' + Genshinlib.version;
if (Genshinlib.getConfig().rpc) {
rpc = new discordrpc.Client({ transport: "ipc" });
rpc.login({ clientId: '901534333360304168' }).catch(console.error);
rpc.on('ready', () => {
rpc.setActivity({
details: `Preparing to launch`,
largeImageKey: `launcher`,
largeImageText: `An Anime Game Launcher`,
instance: false,
});
});
}
LauncherUI.setState('game-launch-available');
ipcRenderer.on('changelang', (event: void, data: any) => {
Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${ uri })`));
LauncherUI.refreshLang(data.lang);
LauncherUI.setState(LauncherUI.launcherState);
});
ipcRenderer.on('rpcstate', (event: void, data: any) => {
if(!rpc) {
rpc = new discordrpc.Client({ transport: "ipc" });
rpc.login({ clientId: '901534333360304168' }).catch(console.error);
rpc.on('ready', () => {
rpc.setActivity({
details: `Preparing to launch`,
largeImageKey: `launcher`,
largeImageText: `An Anime Game Launcher`,
instance: false,
});
});
if (!Genshinlib.getConfig().rpc)
Genshinlib.updateConfig({
rpc: true
});
} else {
rpc.clearActivity();
rpc.destroy();
rpc = false;
Genshinlib.updateConfig({
rpc: false
});
}
});
ipcRenderer.on('updateVP', (event: void, remotedata: any) => {
Genshinlib.getData().then(data => {
LauncherUI.initProgressBar();
let voicePack = data.game.latest.voice_packs[1]; // en-us
let old;
for (let i = 0; i < data.game.latest.voice_packs.length; ++i)
if (data.game.latest.voice_packs[i].language == Genshinlib.lang.voice)
{
voicePack = data.game.latest.voice_packs[i];
break;
}
for (let i = 0; i < data.game.latest.voice_packs.length; ++i)
if (data.game.latest.voice_packs[i].language == remotedata.oldvp)
{
old = data.game.latest.voice_packs[i];
break;
}
let oldstring = old.name.replace(`_${data.game.latest.version}.zip`, '');
// Check if the directory and file exists to prevent errors.
if (fs.existsSync(path.join(Genshinlib.gameDir, oldstring + '_pkg_version')))
fs.rmSync(path.join(Genshinlib.gameDir, oldstring + '_pkg_version'));
if (fs.existsSync(path.join(Genshinlib.gameDir, 'GenshinImpact_Data', 'StreamingAssets', 'Audio', 'GeneratedSoundBanks', 'Windows', oldstring.replace('Audio_', ''))))
fs.rmSync(path.join(Genshinlib.gameDir, 'GenshinImpact_Data', 'StreamingAssets', 'Audio', 'GeneratedSoundBanks', 'Windows', oldstring.replace('Audio_', '')), { recursive: true });
console.log(`%c> Downloading voice data...`, 'font-size: 16px');
// For some reason this keeps breaking and locking up most of the time.
Genshinlib.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(i18n.translate('Downloading'), current, total, difference);
}).then(() => {
console.log(`%c> Unpacking voice data...`, 'font-size: 16px');
LauncherUI.initProgressBar();
Genshinlib.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar(i18n.translate('Unpack'), current, total, difference);
}).then(() => {
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));
LauncherUI.setState('game-launch-available');
})
});
});
});
Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${ uri })`)); Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${ uri })`));
fetch(`https://genshin.mihoyo.com/launcher/10/${Genshinlib.lang.launcher}?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`) fetch(`https://genshin.mihoyo.com/launcher/10/${Genshinlib.lang.launcher}?api_url=https%3A%2F%2Fapi-os-takumi.mihoyo.com%2Fhk4e_global&prev=false`)
@ -32,7 +139,7 @@ $(() => {
LauncherUI.setState(Genshinlib.version === null ? 'game-installation-available' : 'game-update-available'); LauncherUI.setState(Genshinlib.version === null ? 'game-installation-available' : 'game-update-available');
// Patch version is incorrect // Patch version is incorrect
else if (Genshinlib.getConfig().patch.version != Genshinlib.getPatchInfo().version) else if (Genshinlib.getConfig().patch && Genshinlib.getConfig().patch.version != Genshinlib.getPatchInfo().version)
{ {
// Patch is not available // Patch is not available
if (Genshinlib.getPatchInfo().version !== data.game.latest.version) if (Genshinlib.getPatchInfo().version !== data.game.latest.version)
@ -60,7 +167,7 @@ $(() => {
// Current patch is in testing phase, // Current patch is in testing phase,
// but stable is available // but stable is available
else if (Genshinlib.getConfig().patch.version == Genshinlib.getPatchInfo().version && Genshinlib.getConfig().patch.state == 'testing' && Genshinlib.getPatchInfo().state == 'stable') else if (Genshinlib.getConfig().patch && Genshinlib.getConfig().patch.version == Genshinlib.getPatchInfo().version && Genshinlib.getConfig().patch.state == 'testing' && Genshinlib.getPatchInfo().state == 'stable')
{ {
console.log(`%c> Applying patch...`, 'font-size: 16px'); console.log(`%c> Applying patch...`, 'font-size: 16px');
@ -96,7 +203,7 @@ $(() => {
} }
// Launching game // Launching game
if ($('#launch').text() == 'Launch') if ($('#launch').text() == i18n.translate('Launch'))
{ {
console.log(`%c> Starting the game...`, 'font-size: 16px'); console.log(`%c> Starting the game...`, 'font-size: 16px');
@ -135,28 +242,45 @@ $(() => {
console.log(`Wine executable: ${wineExeutable}`); console.log(`Wine executable: ${wineExeutable}`);
if (rpc)
rpc.setActivity({
details: `In-Game`,
largeImageKey: `game`,
largeImageText: `An Anime Game Launcher`,
startTimestamp: parseInt(new Date().setDate(new Date().getDate()).toString()),
instance: false,
});
exec(`${wineExeutable} launcher.bat`, { exec(`${wineExeutable} launcher.bat`, {
cwd: Genshinlib.gameDir, cwd: Genshinlib.gameDir,
env: { env: {
...process.env, ...process.env,
WINEPREFIX: Genshinlib.prefixDir WINEPREFIX: Genshinlib.prefixDir
} }
}/*, (err: any, stdout: any, stderr: any) => { }, (err: any, stdout: any, stderr: any) => {
console.log(`%c> Game closed`, 'font-size: 16px'); console.log(`%c> Game closed`, 'font-size: 16px');
ipcRenderer.invoke('show-window'); ipcRenderer.invoke('show-window');
if (rpc)
rpc.setActivity({
details: `Preparing to launch`,
largeImageKey: `launcher`,
largeImageText: `An Anime Game Launcher`,
instance: false,
});
console.log(err); console.log(err);
console.log(stdout); console.log(stdout);
console.log(stderr); console.log(stderr);
}*/); });
ipcRenderer.invoke('hide-window'); ipcRenderer.invoke('hide-window');
} }
} }
// Apply test patch // Apply test patch
else if ($('#launch').text() == 'Apply test patch') else if ($('#launch').text() == i18n.translate('TestPatch'))
{ {
console.log(`%c> Applying patch...`, 'font-size: 16px'); console.log(`%c> Applying patch...`, 'font-size: 16px');
@ -196,7 +320,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.downloadFile(diff.path, path.join(Genshinlib.launcherDir, diff.name), (current: number, total: number, difference: number) => { Genshinlib.downloadFile(diff.path, path.join(Genshinlib.launcherDir, diff.name), (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar('Downloaded', current, total, difference); LauncherUI.updateProgressBar(i18n.translate('Downloading'), current, total, difference);
}).then(() => { }).then(() => {
/** /**
* Unpacking downloaded game * Unpacking downloaded game
@ -210,7 +334,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.unzip(path.join(Genshinlib.launcherDir, diff.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { Genshinlib.unzip(path.join(Genshinlib.launcherDir, diff.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar('Unpacking', current, total, difference); LauncherUI.updateProgressBar(i18n.translate('Unpack'), current, total, difference);
}).then(() => { }).then(() => {
/** /**
* Downloading voice data * Downloading voice data
@ -233,7 +357,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => { Genshinlib.downloadFile(voicePack.path, path.join(Genshinlib.launcherDir, voicePack.name), (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar('Downloaded', current, total, difference); LauncherUI.updateProgressBar(i18n.translate('Downloading'), current, total, difference);
}).then(() => { }).then(() => {
/** /**
* Unpacking downloaded game * Unpacking downloaded game
@ -244,7 +368,7 @@ $(() => {
LauncherUI.initProgressBar(); LauncherUI.initProgressBar();
Genshinlib.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => { Genshinlib.unzip(path.join(Genshinlib.launcherDir, voicePack.name), Genshinlib.gameDir, (current: number, total: number, difference: number) => {
LauncherUI.updateProgressBar('Unpacking', current, total, difference); LauncherUI.updateProgressBar(i18n.translate('Unpack'), current, total, difference);
}).then(() => { }).then(() => {
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name)); fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));
@ -260,14 +384,14 @@ $(() => {
console.log(`%c> Applying patch...`, 'font-size: 16px'); console.log(`%c> Applying patch...`, 'font-size: 16px');
// patch-applying state changes only button text // patch-applying state changes only button text
$('#downloaded').text('Applying patch...'); $('#downloaded').text(i18n.translate('ApplyPatch'));
Genshinlib.patchGame(data.game.latest.version, () => { Genshinlib.patchGame(data.game.latest.version, () => {
LauncherUI.setState('game-launch-available'); LauncherUI.setState('game-launch-available');
ipcRenderer.send('notification', { ipcRenderer.send('notification', {
title: document.title, title: document.title,
body: 'Game was successfully installed' body: i18n.translate('GameDownloaded')
}); });
}, (data) => console.log(data.toString())); }, (data) => console.log(data.toString()));
} }

View file

@ -1,27 +1,108 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const { ipcRenderer } = require('electron');
const { exec } = require('child_process'); const { exec } = require('child_process');
import $ from 'cash-dom'; import $ from 'cash-dom';
import i18n from './i18n';
import { Genshinlib } from './Genshinlib'; import { Genshinlib } from './Genshinlib';
$(() => { $(() => {
$("*[i18id]").each((i, el) => {
el.innerText = i18n.translate(el.getAttribute('i18id')?.toString());
});
$('.menu-item').on('click', (e) => { $('.menu-item').on('click', (e) => {
// @ts-expect-error $('.settings')[0]!.scrollTop = document.getElementById(e.target.getAttribute('anchor'))!.offsetTop - 16;
$('.settings')[0].scrollTop = document.getElementById(e.target.getAttribute('anchor')).offsetTop - 16;
$('.menu-item').removeClass('menu-item-active'); $('.menu-item').removeClass('menu-item-active');
$(e.target).addClass('menu-item-active'); $(e.target).addClass('menu-item-active');
}); });
$('.settings').on('scroll', () => { $('.settings').on('scroll', () => {
// @ts-expect-error let anchor = $('.settings-item').filter((index, item) => $(item).offset()!.top < 264).last()[0]!.id;
let anchor = $('.settings-item').filter((index, item) => $(item).offset().top < 264).last()[0].id;
$('.menu-item').removeClass('menu-item-active'); $('.menu-item').removeClass('menu-item-active');
$(`.menu-item[anchor=${anchor}]`).addClass('menu-item-active'); $(`.menu-item[anchor=${anchor}]`).addClass('menu-item-active');
}); });
// Select the saved options in launcher.json on load.
$(`#voice-list option[value="${Genshinlib.getConfig().lang.voice}"]`).prop('selected', true);
if (Genshinlib.getConfig().rpc)
$(`#drpc`).prop('checked', true);
$(`#language-list option[value="${Genshinlib.getConfig().lang.launcher}"]`).prop('selected', true);
$('#drpc').on('change', (e) => {
if ($("#drpc").is(':checked'))
{
ipcRenderer.send('rpcstate', {});
}
else
{
ipcRenderer.send('rpcstate', {});
}
})
$('#voice-list').on('change', (e) => {
let activeVP = Genshinlib.getConfig().lang.voice;
if (activeVP != e.target.value)
{
Genshinlib.updateConfig({
lang: {
launcher: Genshinlib.getConfig().lang.launcher,
voice: e.target.value
}
});
ipcRenderer.send('updateVP', { 'oldvp': activeVP });
$(`#voice-list option[value="${activeVP}"]`).removeProp('selected');
$(`#voice-list option[value="${e.target.value}"]`).prop('selected', true);
}
else
{
console.log('VP can\' be changed to the already set language');
}
});
$('#language-list').on('change', (e) => {
let activeLNG = Genshinlib.getConfig().lang.launcher;
if (activeLNG != e.target.value)
{
Genshinlib.updateConfig({
lang: {
launcher: e.target.value,
voice: Genshinlib.getConfig().lang.voice
}
});
// This is required as the file name changes on the API but since we don't call the API before checking if the time is null or expired we set time to null here.
Genshinlib.updateConfig({
background: {
time: null,
file: Genshinlib.getConfig().background.file
}
});
// Send language updates
i18n.updatelang(e.target.value);
ipcRenderer.send('changelang', { 'lang': e.target.value });
$("*[i18id]").each((i, el) => {
el.innerText = i18n.translate(el.getAttribute('i18id')?.toString());
});
$(`#language-list option[value="${activeLNG}"]`).removeProp('selected');
$(`#language-list option[value="${e.target.value}"]`).prop('selected', true);
}
else
{
console.log('New language can\' be changed to the already set language');
}
});
let activeRunner = Genshinlib.getConfig().runner; let activeRunner = Genshinlib.getConfig().runner;
Genshinlib.getRunners().then(runners => { Genshinlib.getRunners().then(runners => {

3091
yarn.lock

File diff suppressed because it is too large Load diff