mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-12-23 18:20:19 +03:00
Merge branch 'term' of Maroxy/an-ordinary-launcher into main
This commit is contained in:
commit
66693b0931
25 changed files with 2251 additions and 1541 deletions
20
entry.js
20
entry.js
|
@ -68,6 +68,12 @@ function createWindow ()
|
|||
// 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
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
|
@ -81,6 +87,20 @@ app.whenReady().then(() => {
|
|||
if (BrowserWindow.getAllWindows().length === 0)
|
||||
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
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"cash-dom": "^8.1.0",
|
||||
"discord-rpc": "^4.0.1",
|
||||
"follow-redirects": "^1.14.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,39 +11,50 @@
|
|||
<!-- JS scripts -->
|
||||
<script>require('../js/settings.js');</script>
|
||||
|
||||
<title>Settings</title>
|
||||
<title i18id="SettingsTitle"></title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="menu">
|
||||
<div class="menu-item menu-item-active" anchor="general">General</div>
|
||||
<div class="menu-item" anchor="runners">Runners</div>
|
||||
<div class="menu-item menu-item-active" anchor="general" i18id="GeneralSettings">General</div>
|
||||
<div class="menu-item" anchor="runners" i18id="Runners">Runners</div>
|
||||
<div class="menu-item" anchor="dxvks">DXVK</div>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<div class="settings-item" id="general">
|
||||
<h2>General</h2>
|
||||
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br>
|
||||
123<br><br>
|
||||
|
||||
Will be made in beta 7
|
||||
|
||||
<h2 i18id="GeneralSettings">General</h2>
|
||||
<hr>
|
||||
<h3 i18id="Langs">Language</h3>
|
||||
<select class="dropdown-menu" id="language-list">
|
||||
<option value="en-us">English (US)</option>
|
||||
<option value="zh-cn">中文(简化)(Chinese Simplified)</option>
|
||||
<option value="de-de">Deutsch (German)</option>
|
||||
<option value="fr-fr">Français (French)</option>
|
||||
<option value="id-id">Indonesia (Indonesian)</option>
|
||||
<option value="ja-jp">日本語 (Japanese)</option>
|
||||
<option value="ko-kr">한국어 (Korean)</option>
|
||||
<option value="pt-pt">Português (Portuguese)</option>
|
||||
<option value="ru-ru">Pусский (Russian)</option>
|
||||
<option value="es-es">Español (Spanish)</option>
|
||||
<option value="th-th">ภาษาไทย (Thai)</option>
|
||||
<option value="zh-tw">中文(繁體)(Chinese Traditional)</option>
|
||||
<option value="vi-vn">Tiếng Việt (Vietnamese)</option>
|
||||
</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>
|
||||
|
||||
<hr>
|
||||
<div class="settings-item" id="runners">
|
||||
<h2>Runners</h2>
|
||||
|
||||
|
|
17
public/locales/de.json
Normal file
17
public/locales/de.json
Normal 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
17
public/locales/en-us.json
Normal 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
17
public/locales/en.json
Normal 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
17
public/locales/es.json
Normal 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
17
public/locales/fr.json
Normal 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
17
public/locales/id.json
Normal 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
17
public/locales/ja.json
Normal 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
17
public/locales/ko.json
Normal 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
17
public/locales/pt.json
Normal 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
17
public/locales/ru.json
Normal 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
17
public/locales/th.json
Normal 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
17
public/locales/vi.json
Normal 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
17
public/locales/zh-cn.json
Normal 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
17
public/locales/zh-tw.json
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"Install": "安裝",
|
||||
"Launch": "發射",
|
||||
"Runners": "Runners",
|
||||
"Langs": "語言",
|
||||
"Voice": "語音包",
|
||||
"SettingsTitle": "設置",
|
||||
"GeneralSettings": "一般的",
|
||||
"Downloading": "下載",
|
||||
"Unpack": "Unpacking",
|
||||
"GameDownloaded": "遊戲安裝成功",
|
||||
"ApplyPatch": "Applying patch...",
|
||||
"PatchRequired": "需要補丁",
|
||||
"PatchRequiredHint": "此遊戲版本沒有防作弊補丁。請等待幾天,然後重試。",
|
||||
"TestPatch": "應用測試補丁",
|
||||
"TestPatchHint": "該遊戲版本有一個反作弊補丁,但處於測試階段。您可以等待幾天直到它穩定或自擔風險應用它。"
|
||||
}
|
|
@ -150,6 +150,15 @@
|
|||
"folder": "Proton-6.14-GE-1",
|
||||
"makeFolder": false,
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -99,3 +99,17 @@ body
|
|||
|
||||
img
|
||||
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
|
|
@ -42,6 +42,7 @@ type Config = {
|
|||
folder: string,
|
||||
executable: string
|
||||
},
|
||||
rpc: boolean,
|
||||
dxvk: string|null
|
||||
};
|
||||
|
||||
|
@ -110,11 +111,12 @@ export class Genshinlib
|
|||
},
|
||||
background: {
|
||||
time: null,
|
||||
name: null
|
||||
file: null
|
||||
},
|
||||
version: null,
|
||||
patch: null,
|
||||
runner: null
|
||||
runner: null,
|
||||
rpc: false
|
||||
}, null, 4));
|
||||
|
||||
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
|
||||
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 = [
|
||||
'Executing w_do_call corefonts',
|
||||
|
@ -367,18 +369,32 @@ export class Genshinlib
|
|||
'Executing load_trebuchet',
|
||||
'Executing load_verdana',
|
||||
'Executing load_webdings',
|
||||
'Executing load_usetakefocus n'
|
||||
'Executing load_usetakefocus n',
|
||||
'Executing load_dxvk'
|
||||
];
|
||||
|
||||
return new Promise((resolve) => {
|
||||
let installationProgress = 0;
|
||||
let installerProcess;
|
||||
|
||||
let installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n'], {
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: path
|
||||
}
|
||||
});
|
||||
if (this.getConfig().runner)
|
||||
{
|
||||
installerProcess = spawn('winetricks', ['corefonts', 'usetakefocus=n', 'dxvk191'], {
|
||||
env: {
|
||||
...process.env,
|
||||
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) => {
|
||||
let str = data.toString();
|
||||
|
@ -430,6 +446,16 @@ export class Genshinlib
|
|||
patcherProcess.stdout.on('data', (data: string) => onData(data));
|
||||
|
||||
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.
|
||||
let patcherAntiCrashProcess = exec(`yes | ${path.join(patchDir, 'patch_anti_logincrash.sh')}`, {
|
||||
cwd: this.gameDir,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import $ from 'cash-dom';
|
||||
import i18n from './i18n';
|
||||
|
||||
type LauncherState =
|
||||
'patch-unavailable' |
|
||||
|
@ -17,6 +18,11 @@ export class LauncherUI
|
|||
return this._launcherState;
|
||||
}
|
||||
|
||||
public static refreshLang (langcode: string)
|
||||
{
|
||||
i18n.updatelang(langcode);
|
||||
}
|
||||
|
||||
public static setState (state: LauncherState)
|
||||
{
|
||||
$('#downloader-panel').css('display', 'none');
|
||||
|
@ -25,29 +31,29 @@ export class LauncherUI
|
|||
switch (state)
|
||||
{
|
||||
case 'patch-unavailable':
|
||||
$('#launch').text('Patch required');
|
||||
$('#launch').text(i18n.translate('PatchRequired'));
|
||||
$('#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');
|
||||
$('#launch').attr('data-hint', i18n.translate('PatchRequiredHint'));
|
||||
|
||||
break;
|
||||
|
||||
case 'test-patch-available':
|
||||
$('#launch').text('Apply test patch');
|
||||
$('#launch').text(i18n.translate('TestPatch'));
|
||||
|
||||
$('#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');
|
||||
$('#launch').attr('data-hint', i18n.translate('TestPatchHint'));
|
||||
|
||||
break;
|
||||
|
||||
case 'patch-applying':
|
||||
$('#launch').text('Applying patch');
|
||||
$('#launch').text(i18n.translate('ApplyPatch'));
|
||||
$('#launch').attr('disabled', 'disabled');
|
||||
|
||||
break;
|
||||
|
@ -58,7 +64,7 @@ export class LauncherUI
|
|||
break;
|
||||
|
||||
case 'game-installation-available':
|
||||
$('#launch').text('Install');
|
||||
$('#launch').text(i18n.translate('Install'));
|
||||
|
||||
break;
|
||||
|
||||
|
@ -71,7 +77,7 @@ export class LauncherUI
|
|||
.removeClass('hint--medium')
|
||||
.removeClass('hint--large');
|
||||
|
||||
$('#launch').text('Launch');
|
||||
$('#launch').text(i18n.translate('Launch'));
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
39
src/ts/i18n.ts
Normal file
39
src/ts/i18n.ts
Normal 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);
|
168
src/ts/index.ts
168
src/ts/index.ts
|
@ -1,9 +1,12 @@
|
|||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const discordrpc = require("discord-rpc");
|
||||
const { exec } = require('child_process');
|
||||
const { ipcRenderer } = require('electron');
|
||||
let rpc: any;
|
||||
|
||||
import $ from 'cash-dom';
|
||||
import i18n from './i18n';
|
||||
|
||||
import { Genshinlib } from './Genshinlib';
|
||||
import { LauncherUI } from './LauncherUI';
|
||||
|
@ -11,10 +14,114 @@ import { LauncherUI } from './LauncherUI';
|
|||
if (!fs.existsSync(Genshinlib.prefixDir))
|
||||
fs.mkdirSync(Genshinlib.prefixDir, { recursive: true });
|
||||
|
||||
if (!fs.existsSync(Genshinlib.runnersDir))
|
||||
fs.mkdirSync(Genshinlib.runnersDir, { recursive: true });
|
||||
|
||||
$(() => {
|
||||
if (Genshinlib.version !== null)
|
||||
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 })`));
|
||||
|
||||
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');
|
||||
|
||||
// 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
|
||||
if (Genshinlib.getPatchInfo().version !== data.game.latest.version)
|
||||
|
@ -60,7 +167,7 @@ $(() => {
|
|||
|
||||
// Current patch is in testing phase,
|
||||
// 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');
|
||||
|
||||
|
@ -96,7 +203,7 @@ $(() => {
|
|||
}
|
||||
|
||||
// Launching game
|
||||
if ($('#launch').text() == 'Launch')
|
||||
if ($('#launch').text() == i18n.translate('Launch'))
|
||||
{
|
||||
console.log(`%c> Starting the game...`, 'font-size: 16px');
|
||||
|
||||
|
@ -135,28 +242,45 @@ $(() => {
|
|||
|
||||
console.log(`Wine executable: ${wineExeutable}`);
|
||||
|
||||
exec(`${wineExeutable} launcher.bat`, {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
}/*, (err: any, stdout: any, stderr: any) => {
|
||||
console.log(`%c> Game closed`, 'font-size: 16px');
|
||||
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`, {
|
||||
cwd: Genshinlib.gameDir,
|
||||
env: {
|
||||
...process.env,
|
||||
WINEPREFIX: Genshinlib.prefixDir
|
||||
}
|
||||
}, (err: any, stdout: any, stderr: any) => {
|
||||
console.log(`%c> Game closed`, 'font-size: 16px');
|
||||
|
||||
ipcRenderer.invoke('show-window');
|
||||
|
||||
console.log(err);
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
}*/);
|
||||
if (rpc)
|
||||
rpc.setActivity({
|
||||
details: `Preparing to launch`,
|
||||
largeImageKey: `launcher`,
|
||||
largeImageText: `An Anime Game Launcher`,
|
||||
instance: false,
|
||||
});
|
||||
|
||||
console.log(err);
|
||||
console.log(stdout);
|
||||
console.log(stderr);
|
||||
});
|
||||
|
||||
ipcRenderer.invoke('hide-window');
|
||||
}
|
||||
}
|
||||
|
||||
// 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');
|
||||
|
||||
|
@ -196,7 +320,7 @@ $(() => {
|
|||
LauncherUI.initProgressBar();
|
||||
|
||||
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(() => {
|
||||
/**
|
||||
* Unpacking downloaded game
|
||||
|
@ -210,7 +334,7 @@ $(() => {
|
|||
LauncherUI.initProgressBar();
|
||||
|
||||
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(() => {
|
||||
/**
|
||||
* Downloading voice data
|
||||
|
@ -233,7 +357,7 @@ $(() => {
|
|||
LauncherUI.initProgressBar();
|
||||
|
||||
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(() => {
|
||||
/**
|
||||
* Unpacking downloaded game
|
||||
|
@ -244,7 +368,7 @@ $(() => {
|
|||
LauncherUI.initProgressBar();
|
||||
|
||||
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(() => {
|
||||
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));
|
||||
|
||||
|
@ -260,14 +384,14 @@ $(() => {
|
|||
console.log(`%c> Applying patch...`, 'font-size: 16px');
|
||||
|
||||
// patch-applying state changes only button text
|
||||
$('#downloaded').text('Applying patch...');
|
||||
$('#downloaded').text(i18n.translate('ApplyPatch'));
|
||||
|
||||
Genshinlib.patchGame(data.game.latest.version, () => {
|
||||
LauncherUI.setState('game-launch-available');
|
||||
|
||||
ipcRenderer.send('notification', {
|
||||
title: document.title,
|
||||
body: 'Game was successfully installed'
|
||||
body: i18n.translate('GameDownloaded')
|
||||
});
|
||||
}, (data) => console.log(data.toString()));
|
||||
}
|
||||
|
|
|
@ -1,27 +1,108 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { ipcRenderer } = require('electron');
|
||||
const { exec } = require('child_process');
|
||||
|
||||
import $ from 'cash-dom';
|
||||
import i18n from './i18n';
|
||||
import { Genshinlib } from './Genshinlib';
|
||||
|
||||
$(() => {
|
||||
|
||||
$("*[i18id]").each((i, el) => {
|
||||
el.innerText = i18n.translate(el.getAttribute('i18id')?.toString());
|
||||
});
|
||||
|
||||
$('.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');
|
||||
$(e.target).addClass('menu-item-active');
|
||||
});
|
||||
|
||||
$('.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[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;
|
||||
|
||||
Genshinlib.getRunners().then(runners => {
|
||||
|
|
Loading…
Reference in a new issue