2.2.0-beta5

- made settings window
- added runners management. Now you can download some runner like proton-ge
  and run the game with it
- updated README pictures
- removed usused path files
- a lot of small changes and bug fixes
This commit is contained in:
Observer KRypt0n_ 2021-10-22 23:48:43 +02:00
parent 9801cf90df
commit 2ce673367b
No known key found for this signature in database
GPG key ID: DC5D4EC1303465DA
25 changed files with 612 additions and 251 deletions

1
.gitignore vendored
View file

@ -3,4 +3,5 @@ dist
package-lock.json
wineprefix-installation.log
public/css/index.css
public/css/settings.css
public/js

View file

@ -1,6 +1,8 @@
<img src="repository-pics/logo.png">
<img src="repository-pics/launcher.png">
<img src="repository-pics/launcher-main.png">
<img src="repository-pics/launcher-settings.png">
<br><br>
@ -8,7 +10,7 @@
| Game version | Launcher version | Patch version |
| :---: | :---: | :---: |
| 2.2.0 | 2.2.0-beta4 ⚠️ | 2.2.0-stable ✅ |
| 2.2.0 | 2.2.0-beta5 ⚠️ | 2.2.0-stable ✅ |
Download from [Releases](https://notabug.org/nobody/an-anime-game-launcher/releases)
@ -22,6 +24,7 @@ To work this launcher requires
* winecfg
* winetricks
* unzip
* tar
# Development
@ -45,9 +48,9 @@ To 2.2.0-release1
* <s>Parse background banners from the game's API ([issue #1](https://notabug.org/nobody/an-anime-game-launcher/issues/1), [pull request #2](https://notabug.org/nobody/an-anime-game-launcher/pulls/2))</s> *(beta 3)*
* <s>Update launcher logo</s> *(beta 4)*
* <s>Cache launcher background picture ([pull request #6](https://notabug.org/nobody/an-anime-game-launcher/pulls/6))</s> *(beta 4)*
* Make Proton-GE default compatibility tool and fix game input issues
* <s>Make Proton-GE default compatibility tool and fix game input issues</s> (added runners manager) *(beta 5)*
* <s>Add preferences menu</s> *(beta 5)*
* Add additional telemetry checking
* Add preferences menu
* Add launcher updates notifications
* Make automatical patch state parsing

View file

@ -13,12 +13,32 @@ ipcMain.on('notification', (event, args) => {
}).show();
});
ipcMain.handle('open-settings', () => {
const settingsWindow = new BrowserWindow({
width: 900,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
},
icon: path.join(__dirname, 'public', 'images', 'icon64.png'),
autoHideMenuBar: true,
resizable: false,
parent: mainWindow,
modal: true,
show: false
});
settingsWindow.loadFile(path.join(__dirname, 'public', 'html', 'settings.html'));
settingsWindow.once('ready-to-show', () => settingsWindow.show());
});
function createWindow ()
{
// https://www.electronjs.org/docs/latest/api/browser-window/#class-browserwindow
mainWindow = new BrowserWindow ({
width: 1280,
height: 728,
height: 700,
webPreferences: {
nodeIntegration: true,
contextIsolation: false

View file

@ -1,6 +1,6 @@
{
"name": "an-anime-game-linux-launcher",
"version": "2.2.0-beta4",
"version": "2.2.0-beta5",
"description": "An Anime Game Linux Launcher",
"author": "Nikita Podvirnyy <suimin.tu.mu.ga.mi@gmail.com>",
"contributors": [
@ -44,6 +44,7 @@
"typescript": "^4.4.3"
},
"dependencies": {
"cash-dom": "^8.1.0"
"cash-dom": "^8.1.0",
"follow-redirects": "^1.14.4"
}
}

View file

@ -31,6 +31,10 @@
<div id="launchcontent"></div>
<div id="settings">
<img src="../images/gear.png">
</div>
<button class="button" id="launch">Launch</button>
</body>
</html>

53
public/html/settings.html Normal file
View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- CSS styles -->
<link rel="stylesheet" href="../css/settings.css">
<!-- JS scripts -->
<script>require('../js/settings.js');</script>
<title>Settings</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>
<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 6
</div>
<div class="settings-item" id="runners">
<h2>Runners</h2>
<div class="list" id="runners-list"></div>
</div>
</div>
</body>
</html>

BIN
public/images/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 B

BIN
public/images/gear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,129 +0,0 @@
#!/usr/bin/env bash
# MacOS and *BSD do not have md5sum: use md5 instead
if [[ $(uname) == "Darwin" || $(uname) == *"BSD" ]]; then
md5sum() {
md5 -q $@
}
fi
DIR=$(dirname "${BASH_SOURCE[0]}")
FILE="UnityPlayer.dll"
CEXE="GenshinImpact_Data/upload_crash.exe"
sum=($(md5sum $FILE))
if [ "${sum}" != "38746fe5dbdce04311c84b2394f03686" ]; then
# The patch might corrupt invalid/outdated files if this check is skippd.
echo "Wrong file version or patch is already applied"
echo "md5sum: ${sum}" && exit 1
fi
# =========== DO NOT REMOVE START ===========
if [[ -e "$DIR/$FILE" ]]; then
# There is a good reason for this check. Do not pollute the game directory.
echo "Please move all patch files outside the game directory prior executing."
echo " -> See README.md for proper installation instructions" && exit 1
fi
# =========== DO NOT REMOVE END ===========
if ! command -v xdelta3 &>/dev/null; then
echo "xdelta3 application is required"
echo " -> Debian/Ubuntu: apt install xdelta3"
echo " -> Fedora: dnf install xdelta"
echo " -> Arch/Arch-based: pacman -S xdelta3"
echo " -> macOS: \"port install xdelta\" or \"brew install xdelta\""
exit 1
fi
# ===========================================================
echo
echo "--- Setting up blocked servers"
# START OF SUDO DANGER ZONE
etc_hosts="$(cat /etc/hosts)"
# See dev_tools/network.md (up-to-date as of 2.1.0)
servers=$(cat <<EOF
# Genshin logging servers (do not remove!)
0.0.0.0 log-upload-os.mihoyo.com
0.0.0.0 overseauspider.yuanshen.com
EOF
)
if [[ ! "$etc_hosts" == *"$servers"* ]]; then
echo "[MANDATORY] Adding following logging servers to /etc/hosts"
echo " If you really really want to skip this (Ctrl+C),"
echo " PLEASE add the entries manually. Otherwise they will receive"
echo " logs about The Wine project, hence UNCOVERING THIS PATCH!"
echo "$servers" | sudo -k tee -a /etc/hosts
if [ $? -ne 0 ]; then
echo "$servers"
read -p "Please append these lines to your /etc/hosts file now. Enter to continue."
fi
else
echo "--- Logging servers are already blocked. Skip."
fi
servers=$(cat <<EOF
# Optional Unity proxy/cdn servers
0.0.0.0 prd-lender.cdp.internal.unity3d.com
0.0.0.0 thind-prd-knob.data.ie.unity3d.com
0.0.0.0 thind-gke-usc.prd.data.corp.unity3d.com
0.0.0.0 cdp.cloud.unity3d.com
0.0.0.0 remote-config-proxy-prd.uca.cloud.unity3d.com
EOF
)
if [[ ! "$etc_hosts" == *"$servers"* ]]; then
echo "-- Adding proxy/cdn servers"
echo "$servers" | sudo tee -a /etc/hosts
if [ $? -ne 0 ]; then
read -p "--- FAILED to add the servers. Enter to continue."
fi
else
echo "--- Unity proxy/cdn servers are already blocked. Skip."
fi
etc_hosts=""
# END OF SUDO DANGER ZONE
echo ""
# No crashes shall be reported!
echo "--- Renaming the crash reporter"
if [[ -e "$CEXE" ]]; then
# Replace existing backups
mv -f "$CEXE" "$CEXE.bak"
fi
# Registry entry to add on startup
cp -f "$DIR/patch_files/mhyprot2_running.reg" .
# Add launcher & force update to ensure the checks are performed
echo "--- Adding launcher script"
cp -f "$DIR/patch_files/launcher.bat" .
# Do the patch now, replace existing backups (hash confirmed)
echo "--- Patching UnityPlayer"
xdelta_fail() {
mv -vf "$FILE.bak" "$FILE"
exit 1
}
mv -f "$FILE" "$FILE.bak"
# Perform patch or restore .bak on failure
xdelta3 -d -s "$FILE.bak" "$DIR/patch_files/unityplayer_patch.vcdiff" "$FILE" || xdelta_fail
# Done!
echo "==> Patch applied! Enjoy the game."
echo
echo "[NOTICE] Please refrain from sharing this project in public so"
echo " that there can be Linux patches in the future. Thank you."
exit 0

View file

@ -1,54 +0,0 @@
#!/usr/bin/env bash
# MacOS and *BSD do not have md5sum: use md5 instead
if [[ $(uname) == "Darwin" || $(uname) == *"BSD" ]]; then
md5sum() {
md5 -q $@
}
fi
DIR=$(dirname "${BASH_SOURCE[0]}")
FILE="GenshinImpact_Data/Plugins/xlua.dll"
sum=($(md5sum $FILE))
if [ "${sum}" != "526b36c2b8a070db61428b7fe69906a3" ]; then
# The patch might corrupt invalid/outdated files if this check is skippd.
echo "Wrong file version or patch is already applied"
echo "md5sum: ${sum}" && exit 1
fi
# =========== DO NOT REMOVE START ===========
if [[ -e "$DIR/$FILE" ]]; then
# There is a good reason for this check. Do not pollute the game directory.
echo "Please move all patch files outside the game directory prior executing."
echo " -> See README.md for proper installation instructions" && exit 1
fi
# =========== DO NOT REMOVE END ===========
if ! command -v xdelta3 &>/dev/null; then
echo "xdelta3 application is required"
exit 1
fi
echo "[INFO] Patch to fix a login and runtime crash"
echo ""
# ===========================================================
echo
echo "--- Applying xLua patch"
xdelta_fail() {
mv -vf "$FILE.bak" "$FILE"
exit 1
}
mv -f "$FILE" "$FILE.bak"
# Perform patch or restore .bak on failure
xdelta3 -d -s "$FILE.bak" "$DIR/patch_files/xlua_patch.vcdiff" "$FILE" || xdelta_fail
# Done!
echo "==> Patch applied! Enjoy the game."
exit 0

View file

View file

@ -1,36 +0,0 @@
@echo off
REM Notice: This file is overwritten for each patch for safety reasons.
REM Hence, any manual changes will be overwritten by the next patch.
REM ============ AVOID CHANGES HERE ============
SET perr=0
REM Verify that the important hosts are blocked
ping -n 1 -w 1 log-upload-os.mihoyo.com | find "[0.0.0.0]" >nul
IF %ERRORLEVEL% NEQ 0 SET perr=1
ping -n 1 -w 1 overseauspider.yuanshen.com | find "[0.0.0.0]" >nul
IF %ERRORLEVEL% NEQ 0 SET perr=1
IF %perr% NEQ 0 (
REM Show the message to the user
echo ERROR: Crucial domains are not blocked. Please re-run the patch script. >_error.txt
notepad _error.txt
del _error.txt
exit
)
REM Emulate the games behaviour
copy mhyprot2.sys "%TEMP%\"
regedit mhyprot2_running.reg
REM Disable crash reporting
IF EXIST GenshinImpact_Data\upload_crash.exe (
move "GenshinImpact_Data\upload_crash.exe" "GenshinImpact_Data\upload_crash.exe.bak"
)
REM ============= Launch the game =============
REM https://docs.unity3d.com/Manual/CommandLineArguments.html
REM Append the arguments to the command: launcher.bat arg1 arg2 ...
start GenshinImpact.exe %*

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

170
runners.json Normal file
View file

@ -0,0 +1,170 @@
[
{
"title": "Proton-GE",
"runners": [
{
"name": "Proton-6.19-GE-2",
"version": "6.19-GE-2",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.19-GE-2/Proton-6.19-GE-2.tar.gz",
"archive": "tar",
"folder": "Proton-6.19-GE-2",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.19-GE-1",
"version": "6.19-GE-1",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.19-GE-1/Proton-6.19-GE-1.tar.gz",
"archive": "tar",
"folder": "Proton-6.19-GE-1",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.18-GE-2",
"version": "6.18-GE-2",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.18-GE-2/Proton-6.18-GE-2.tar.gz",
"archive": "tar",
"folder": "Proton-6.18-GE-2",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.18-GE-1",
"version": "6.18-GE-1",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.18-GE-1/Proton-6.18-GE-1.tar.gz",
"archive": "tar",
"folder": "Proton-6.18-GE-1",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.16-GE-1",
"version": "6.16-GE-1",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.16-GE-1/Proton-6.16-GE-1.tar.gz",
"archive": "tar",
"folder": "Proton-6.16-GE-1",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.15-GE-2",
"version": "6.15-GE-2",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.15-GE-2/Proton-6.15-GE-2.tar.gz",
"archive": "tar",
"folder": "Proton-6.15-GE-2",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.15-GE-1",
"version": "6.15-GE-1",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.15-GE-1/Proton-6.15-GE-1.tar.gz",
"archive": "tar",
"folder": "Proton-6.15-GE-1",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.14-GE-2",
"version": "6.14-GE-2",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.14-GE-2/Proton-6.14-GE-2.tar.gz",
"archive": "tar",
"folder": "Proton-6.14-GE-2",
"makeFolder": false,
"executable": "files/bin/wine64"
},
{
"name": "Proton-6.14-GE-1",
"version": "6.14-GE-1",
"uri": "https://github.com/GloriousEggroll/proton-ge-custom/releases/download/6.14-GE-1/Proton-6.14-GE-1.tar.gz",
"archive": "tar",
"folder": "Proton-6.14-GE-1",
"makeFolder": false,
"executable": "files/bin/wine64"
}
]
},
{
"title": "Lutris",
"runners": [
{
"name": "Lutris 6.14-4",
"version": "6.14-4",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14-4/wine-lutris-6.14-4-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-6.14-4-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
},
{
"name": "Lutris 6.14-3",
"version": "6.14-3",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14-3/wine-lutris-6.14-3-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-6.14-3-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
},
{
"name": "Lutris 6.14-2",
"version": "6.14-2",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14-2/wine-lutris-6.14-2-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-6.14-2-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
},
{
"name": "Lutris 6.14",
"version": "6.14",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14/wine-lutris-6.14-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-6.14-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
}
]
},
{
"title": "Lutris-fshack",
"runners": [
{
"name": "Lutris-fshack 6.14-4",
"version": "6.14-4-fshack",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14-4/wine-lutris-fshack-6.14-4-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-fshack-6.14-4-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
},
{
"name": "Lutris-fshack 6.14-3",
"version": "6.14-3-fshack",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14-3/wine-lutris-fshack-6.14-3-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-fshack-6.14-3-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
},
{
"name": "Lutris-fshack 6.14-2",
"version": "6.14-2-fshack",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14-2/wine-lutris-fshack-6.14-2-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-fshack-6.14-2-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
},
{
"name": "Lutris-fshack 6.14",
"version": "6.14-fshack",
"uri": "https://github.com/lutris/wine/releases/download/lutris-6.14/wine-lutris-fshack-6.14-x86_64.tar.xz",
"archive": "tar",
"folder": "lutris-fshack-6.14-x86_64",
"makeFolder": false,
"executable": "bin/wine64"
}
]
}
]

View file

@ -46,6 +46,23 @@ body
right: 128px
bottom: 64px
#settings
width: 76px
height: 76px
position: absolute
right: 0
bottom: 0
cursor: pointer
> img
width: 32px
height: 32px
margin: 22px
.progress-bar
padding: 0

100
src/sass/settings.sass Normal file
View file

@ -0,0 +1,100 @@
body
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif
margin: 0
padding: 0
background-color: rgb(245, 246, 251)
.menu
position: absolute
width: 200px
top: 0
bottom: 0
margin: 16px 32px
padding: 12px 16px
background-color: white
border-radius: 16px
.menu-item
display: flex
align-items: center
height: 52px
margin-bottom: 8px
padding: 0 12px
border-radius: 12px
font-size: 18px
cursor: pointer
.menu-item-active,
.menu-item:hover
background-color: #eff2ff
color: #657ef8
.settings
position: absolute
width: 524px
top: 0
bottom: 0
left: 258px
margin: 16px 32px
padding: 0 24px
background-color: white
border-radius: 16px
overflow: auto
.settings-item:last-child
margin-bottom: 24px
.list-item
display: flex
align-items: center
height: 52px
margin-bottom: 8px
padding: 0 12px
border-radius: 12px
background-color: #f1f4f9
font-size: 18px
cursor: pointer
> div
width: 52px
height: 52px
margin-left: auto
display: flex
align-items: center
> img
width: 16px
height: 16px
margin: auto
.list-item:hover,
.list-item-active
background-color: #eff2ff
color: #657ef8
.list-item-disabled
background-color: #f1f4f9 !important
color: #abadbd !important
cursor: default !important
img
filter: invert(70%) sepia(13%) saturate(241%) hue-rotate(196deg) brightness(97%) contrast(91%)

View file

@ -1,11 +1,22 @@
import GIJSON from './GIJSON';
const https = require('https');
const https = require('follow-redirects').https;
const fs = require('fs');
const path = require('path');
const os = require('os');
const { spawn, exec } = require('child_process');
type Runner = {
name: string, // Runner title which will be showed in the list
version: string, // Runner version
uri: string // Downloading URI
archive: 'tar' | 'zip' // Archive type
folder: string, // Folder name where it will be downloaded
makeFolder: boolean, // Do we need to create folder or it is included in archive
executable: string // Path to wine executable inside folder
};
type Config = {
lang: {
launcher: 'en-us' | 'ru-ru' | 'fr-fr' | 'id-id' | 'de-de' | 'es-es' | 'pt-pt' | 'th-th' | 'vi-vn' | 'ko-kr' | 'ja-jp' | 'zh-tw' | 'zh-cn',
@ -19,6 +30,11 @@ type Config = {
patch: {
version: string|null,
state: 'testing' | 'stable'
},
runner: null | {
name: string,
folder: string,
executable: string
}
};
@ -36,9 +52,12 @@ export class Genshinlib
public static readonly prefixDir: string = path.join(this.launcherDir, 'game');
public static readonly gameDir: string = path.join(this.prefixDir, 'drive_c', 'Program Files', 'Genshin Impact');
public static readonly runnersDir: string = path.join(this.launcherDir, 'runners');
protected static versionsUri: string = 'https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?key=gcStgarh&launcher_id=10';
protected static backgroundUri: string = 'https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/content?filter_adv=true&launcher_id=10&language=';
protected static readonly versionsUri: string = 'https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/resource?key=gcStgarh&launcher_id=10';
protected static readonly backgroundUri: string = 'https://sdk-os-static.mihoyo.com/hk4e_global/mdk/launcher/api/content?filter_adv=true&launcher_id=10&language=';
protected static readonly patchUri: string = 'https://notabug.org/Krock/GI-on-Linux/archive/master.zip';
protected static readonly runnersUri: string = 'https://notabug.org/nobody/an-anime-game-launcher/raw/main/runners.json';
public static get version(): Config['version']
{
@ -50,6 +69,17 @@ export class Genshinlib
return this.getConfig().lang;
}
public static getRunners (): Promise<[{ title: string, runners: Runner[] }]>
{
return new Promise((resolve, reject) => {
fetch(this.runnersUri)
.then(response => response.json())
.then(runners => resolve(runners));
});
// return JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'runners.json')));
}
public static getConfig (): Config
{
if (!fs.existsSync(this.launcherJson))
@ -63,7 +93,8 @@ export class Genshinlib
name: null
},
version: null,
patch: null
patch: null,
runner: null
}, null, 4));
return JSON.parse(fs.readFileSync(this.launcherJson));
@ -76,6 +107,14 @@ export class Genshinlib
return this;
}
public static updateConfig (config: any): Genshinlib
{
return this.setConfig({
...this.getConfig(),
...config
});
}
public static async getData (): Promise<any>
{
return new Promise((resolve, reject) => {
@ -89,25 +128,22 @@ export class Genshinlib
return jsondata.message === 'OK' ? resolve(jsondata.data) : reject(null);
});
}).on('error', (err: Error) => {
reject(err);
});
}).on('error', (err: Error) => reject(err));
});
}
public static async getBackgroundUri (): Promise<string>
{
let bg = '';
let background = '';
if (!this.getConfig().background.time || new Date(new Date().setHours(0,0,0,0)).setDate(new Date(new Date().setHours(0,0,0,0)).getDate()).toString() >= this.getConfig().background.time!)
{
await fetch(this.backgroundUri + this.lang.launcher)
.then(res => res.json())
.then(async resdone => {
let oldbg = this.getConfig().background.file;
let prevBackground = this.getConfig().background.file;
this.setConfig({
...this.getConfig(),
this.updateConfig({
background: {
time: new Date(new Date().setHours(0,0,0,0)).setDate(new Date(new Date().setHours(0,0,0,0)).getDate() + 7).toString(),
file: resdone.data.adv.background.replace(/.*\//, '')
@ -115,24 +151,24 @@ export class Genshinlib
});
if (fs.existsSync(path.join(this.launcherDir, this.getConfig().background.file)))
bg = path.join(this.launcherDir, this.getConfig().background.file);
background = path.join(this.launcherDir, this.getConfig().background.file);
else
{
await this.downloadFile(resdone.data.adv.background, path.join(this.launcherDir, this.getConfig().background.file), (current: number, total: number, difference: number) => null).then(() => {
!oldbg ?
!prevBackground ?
console.log('No old background found') :
fs.unlinkSync(path.join(this.launcherDir, oldbg));
fs.unlinkSync(path.join(this.launcherDir, prevBackground));
bg = path.join(this.launcherDir, this.getConfig().background.file);
background = path.join(this.launcherDir, this.getConfig().background.file);
});
};
});
}
else bg = path.join(this.launcherDir, this.getConfig().background.file);
else background = path.join(this.launcherDir, this.getConfig().background.file);
return bg;
return background;
}
public static getPatchInfo (): { version: string, state: 'stable' | 'testing' }
@ -213,7 +249,59 @@ export class Genshinlib
});
}
// WINEPREFIX='/home/observer/genshin-impact-launcher/wineprefix' winetricks corefonts
public static async untar (tarPath: string, unpackedPath: string, progress: (current: number, total: number, difference: number) => void): Promise<void|Error>
{
return new Promise((resolve, reject) => {
let listenerProcess = spawn('tar', ['-tvf', tarPath]),
filesList = '', total = 0;
listenerProcess.stdout.on('data', (data: string) => filesList += data);
listenerProcess.on('close', () => {
let files = filesList.split(/\r\n|\r|\n/).slice(3, -3).map(line => {
line = line.trim();
if (line.slice(-1) == '/')
line = line.slice(0, -1);
let matches = /^[dwxr\-]+ [\w/]+[ ]+(\d+) [0-9\-]+ [0-9\:]+ (.+)/.exec(line);
// TODO: compressedSize?
if (matches)
{
total += parseInt(matches[1]);
return {
path: matches[2],
uncompressedSize: parseInt(matches[1])
};
}
});
let current = 0;
let unpackerProcess = spawn('tar', ['-xvf', tarPath, '-C', unpackedPath]);
unpackerProcess.stdout.on('data', (data: string) => {
data.toString().split(/\r\n|\r|\n/).forEach(line => {
line = line.trim();
files.forEach(file => {
if (file?.path == line)
{
current += file.uncompressedSize; // compressedSize
progress(current, total, file.uncompressedSize); // compressedSize
}
});
});
});
unpackerProcess.on('close', () => resolve());
});
});
}
// 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>
{
let installationSteps = [
@ -267,7 +355,7 @@ export class Genshinlib
public static patchGame (version: string, onFinish: () => void, onData: (data: string) => void)
{
this.downloadFile('https://notabug.org/Krock/GI-on-Linux/archive/master.zip', path.join(this.launcherDir, 'krock.zip'), (current: number, total: number, difference: number) => null).then(() => {
this.downloadFile(this.patchUri, path.join(this.launcherDir, 'krock.zip'), (current: number, total: number, difference: number) => null).then(() => {
this.unzip(path.join(this.launcherDir, 'krock.zip'), this.launcherDir, (current: number, total: number, difference: number) => null).then(() => {
// Delete zip file and assign patch directory.
fs.unlinkSync(path.join(this.launcherDir, 'krock.zip'));

View file

@ -17,7 +17,7 @@ $(() => {
Genshinlib.getBackgroundUri().then(uri => $('body').css('background-image', `url(${ uri })`));
fetch(`https://genshin.mihoyo.com/launcher/10/${ Genshinlib.getConfig().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`)
.then(res => res.text())
.then(body => {
$(body).find('#__layout').appendTo('#launchcontent');
@ -100,13 +100,35 @@ $(() => {
{
console.log(`%c> Starting the game...`, 'font-size: 16px');
exec('wine launcher.bat', {
let wineExeutable = 'wine';
if (Genshinlib.getConfig().runner !== null)
{
wineExeutable = path.join(
Genshinlib.runnersDir,
Genshinlib.getConfig().runner?.folder,
Genshinlib.getConfig().runner?.executable
);
if (!fs.existsSync(wineExeutable))
{
wineExeutable = 'wine';
Genshinlib.updateConfig({
runner: null
});
}
}
console.log(`Wine executable: ${wineExeutable}`);
exec(`${wineExeutable} launcher.bat`, {
cwd: Genshinlib.gameDir,
env: {
...process.env,
WINEPREFIX: Genshinlib.prefixDir
}
}, (err: any, stdout: any, stderr: any) => {
}/*, (err: any, stdout: any, stderr: any) => {
console.log(`%c> Game closed`, 'font-size: 16px');
ipcRenderer.invoke('show-window');
@ -114,7 +136,7 @@ $(() => {
console.log(err);
console.log(stdout);
console.log(stderr);
});
}*/);
ipcRenderer.invoke('hide-window');
}
@ -212,8 +234,7 @@ $(() => {
}).then(() => {
fs.unlinkSync(path.join(Genshinlib.launcherDir, voicePack.name));
Genshinlib.setConfig({
...Genshinlib.getConfig(),
Genshinlib.updateConfig({
version: data.game.latest.version
});
@ -245,5 +266,7 @@ $(() => {
});
}
});
$('#settings').on('click', () => ipcRenderer.invoke('open-settings'));
});
});

95
src/ts/settings.ts Normal file
View file

@ -0,0 +1,95 @@
const fs = require('fs');
const path = require('path');
import $ from 'cash-dom';
import { Genshinlib } from './Genshinlib';
$(() => {
$('.menu-item').on('click', (e) => {
// @ts-expect-error
$('.settings')[0].scrollTop = $(`#${e.target.getAttribute('anchor')}`).offset().top - $('.settings').offset().top - 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;
$('.menu-item').removeClass('menu-item-active');
$(`.menu-item[anchor=${anchor}]`).addClass('menu-item-active');
});
let activeRunner = Genshinlib.getConfig().runner;
Genshinlib.getRunners().then(runners => runners.forEach(category => {
$(`<h3>${category.title}</h3>`).appendTo('#runners-list');
category.runners.forEach(runner => {
let item = $(`<div class="list-item">${runner.name}<div><img src="../images/download.png"></div></div>`).appendTo('#runners-list');
if (fs.existsSync(path.join(Genshinlib.runnersDir, runner.folder)))
{
item.find('div').css('display', 'none');
// I think we shouldn't set runner as active if it is not installed
if (runner.name == activeRunner?.name)
item.addClass('list-item-active');
}
item.find('div').on('click', () => {
if (!item.hasClass('list-item-disabled'))
{
item.addClass('list-item-disabled');
let div = item.find('div');
Genshinlib.downloadFile(runner.uri, path.join(Genshinlib.launcherDir, runner.name), (current: number, total: number, difference: number) => {
div.text(`${ Math.round(current / total * 100) }%`);
}).then(() => {
let unpacker = runner.archive === 'tar' ?
Genshinlib.untar : Genshinlib.unzip;
unpacker(
path.join(Genshinlib.launcherDir, runner.name),
runner.makeFolder ?
path.join(Genshinlib.runnersDir, runner.folder) :
Genshinlib.runnersDir,
(current: number, total: number, difference: number) => {
div.text(`${ Math.round(current / total * 100) }%`);
}
).then(() => {
fs.unlinkSync(path.join(Genshinlib.launcherDir, runner.name));
item.removeClass('list-item-disabled');
div.css('display', 'none');
});
});
}
});
item.on('click', () => {
if (!item.hasClass('list-item-disabled'))
{
while (!item.hasClass('list-item'))
item = item.parent();
if (item.find('div').css('display') === 'none')
{
Genshinlib.updateConfig({
runner: {
name: runner.name,
folder: runner.folder,
executable: runner.executable
}
});
$('#runners-list > .list-item').removeClass('list-item-active');
item.addClass('list-item-active');
}
}
});
});
}));
});

View file

@ -798,6 +798,11 @@
dependencies:
"to-regex-range" "^5.0.1"
"follow-redirects@^1.14.4":
"integrity" "sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g=="
"resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.4.tgz"
"version" "1.14.4"
"fs-extra@^10.0.0":
"integrity" "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ=="
"resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz"