mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2025-02-16 23:31:29 +03:00
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:
parent
9801cf90df
commit
2ce673367b
25 changed files with 612 additions and 251 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -3,4 +3,5 @@ dist
|
|||
package-lock.json
|
||||
wineprefix-installation.log
|
||||
public/css/index.css
|
||||
public/css/settings.css
|
||||
public/js
|
11
README.md
11
README.md
|
@ -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
|
||||
|
||||
|
|
22
entry.js
22
entry.js
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
53
public/html/settings.html
Normal 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
BIN
public/images/download.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 654 B |
BIN
public/images/gear.png
Normal file
BIN
public/images/gear.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -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
|
|
@ -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
|
0
public/patch/patch_files/.gitkeep
Normal file
0
public/patch/patch_files/.gitkeep
Normal 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.
Binary file not shown.
Binary file not shown.
BIN
repository-pics/launcher-main.png
Normal file
BIN
repository-pics/launcher-main.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
BIN
repository-pics/launcher-settings.png
Normal file
BIN
repository-pics/launcher-settings.png
Normal file
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
170
runners.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
|
@ -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
100
src/sass/settings.sass
Normal 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%)
|
|
@ -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'));
|
||||
|
|
|
@ -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
95
src/ts/settings.ts
Normal 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');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}));
|
||||
});
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Reference in a new issue