code:
# Troubleshooting

To add new solutions, please open a pull request, issue or contact me directly.

Sorted by appearance from installation (top) to gameplay (bottom).

Many of the solutions mentioned in this document assume knowledge about Wine and
Linux/UNIX shells. These links might help to get a better understanding:

 * Environment variables: https://phoenixnap.com/kb/linux-set-environment-variable
 * WINEPREFIX: https://linuxconfig.org/using-wine-prefixes
 * winetricks script: https://linuxconfig.org/configuring-wine-with-winetricks
     * Respects `WINEPREFIX` and `WINE` environment variables
 * Game (crash) log files: [FAQ.md](FAQ.md)

### List of problematic Wine versions

 * Wine 9.8 - 9.9 (and newer?): Official Genshin-specific launcher crashes due to a Qt5 chromium bug. See Issue #478.
     * Workaround: see [Qt5WebEngineCore_patch.sh](compat/Qt5WebEngineCore_patch.sh)
 * Wine 8.0-rc1: Certain sound effects might not play back
 * Wine 7.5: Broken batch file execution; stuck with `find.exe`. See below or Issue #291
 * Wine 7.3 - 7.5: May require a manual wineprefix update. See below or Issue #273
 * Wine 6.21 (Lutris?): Possible freeze before login screen - Issue #224
 * Wine 6.15 (vanilla): Crash when entering or leaving multiplayer
 * Wine 6.14: Suspected audio playback problems - Issue #218
 * Wine 6.13 and older: RAM growth issue when using the official launcher
 * Wine 6.10: Crash in HID when using a controller - Issue #133
 * Wine 6.0 (staging): Possible stutter issues on AMD graphics - Issue #40
 * Wine 5.19: Occasional crash while preparing media (login screen)
 * Wine 5.3 and older: Missing StartThreadpoolIo implementation

#### Launcher: Game download issues

Download works but launcher freezes/crashes midway:

 * Use a recent Wine version (Wine 6.13+ confirmed working)
 * Use a custom [Update & Patch application](updater/) as an alternative to the official launcher
 * See Issue #28 for details

The memory footprint of `winedevice.exe` grows continuously:

 * Wine bug: see [bug tracker](https://bugs.winehq.org/show_bug.cgi?id=52322)
 * Option 1: Close and re-open the launcher to continue
 * Option 2: Use a custom launcher/[Update & Patch application](updater/)
 * See Issue #118 for details

"Insufficient disk space" issues. Also affected: voice packs from in-game settings

 * Is the game installed in your expected location?
 * Multiple partitions and symlinks might cause the launcher to query the wrong drive
     * Note: `winecfg` might require the environment variable `WINEPREFIX` to be specified.
     * Option 1: Limit drive access. Run `winecfg` -> "Drives"
         * Remove the `Z:` drive and add a new drive using the game installation path.
     * Option 2: Remove the symlinks. Run `winecfg` -> "Desktop Integration" -> "Folders"
         * Select and uncheck each link in the listing
     * Option 3: Try Lutris or a manual Wine setup
 * Last resort: use a [native update application](updater/)

#### Launcher: Failed to unzip game files

1. Check for launcher updates
2. Edit `/path/to/Genshin Impact Game/config.ini`
3. Adjust the line `game_version=X.X.X` to the currently installed version
4. Re-run the launcher to install the update

Alternatively: re-download the entire game. See Issue #28 for direct links.

#### Game does not start at all

1. Check & update the game version in the official launcher
2. Apply the patches as described in `README.md`
3. If the patch scripts did not solve the issue:
    1. Check the Wine log output (terminal or file)
    2. A line containing `err:ntoskrnl:ZwLoadDriver failed to create driver`
       must be one of the last few lines of the log output.
    3. Rename the file `mhypbase.dll` to `mhypbase.dll.bak` and start the game.
       Revert this change if there is no change in behaviour.
    4. This workaround will result in the error "31-4302" after a few days.
       Undo the change and retry to start the game.

If a `find.exe` command window is shown but it never closes:

 * Do not use Wine 7.5. (Issue #291)

#### 'find' or 'start' cannot be found

Alternatively: `notepad.exe` opens on launch, displaying an error message.

Possible causes:

 * Old Lutris Wine package (prior to "lutris-6.4")
 * Incomplete or corrupted WINEPREFIX setup

Solutions:

 * Try another package, such as Proton or stock/vanilla Wine.
 * Use a new WINEPREFIX. Move the game installation.
 * Attempt to repair an existing one using `wineboot -u`
     * This step requires the environment variable `WINEPREFIX` to be specified.

For more details, see Issue #78.

#### Game crashes on launch

1. Ensure the patch is applied
2. Retry without kernel sync (ESYNC, FSYNC, ...)
3. Lutris: disable "Lutris Runtime" ([for reference](https://notabug.org/Krock/dawn/issues/78#issuecomment-24727))

Wine output `CreateDirectory 'C:/users/XXXXX/AppData/LocalLow/XXXX' failed: File not found`:

 * Caused by incorrect encoding of the `%APPDATA%` path due to certain locales.
 * This issue is primarily observed on the Chinese version using Steam
 * In general: use the following environment variables:
     * `LC_ALL=en_US.utf8`
 * For steamOS (Steam Deck):
     1. See [INSTALLATION.md#steamos](INSTALLATION.md#steamos)
 * For Steam (any OS):
     * Navigate to Gear icon -> "Settings"
     * Start options: `LC_ALL=en_US.utf8 %command% /desktop=....`

#### Game crash related to the wineprefix

Wine output log example:

 * `wine: Call from XXXXXX to unimplemented function combase.dll.RoSetErrorReportingFlags, aborting`

This applies to approx. Wine 7.3 (but not Proton). Either:

 * Update your WINEPREFIX using `wineboot -u`
     * Command execution is possible from both, shell and `cmd.exe`.
 * Create a new WINEPREFIX, reinstall DXVK (if possible) and retest
     * The game installation should be located outside any prefix to avoid accidental deletion.

#### StartThreadpoolIo not found in KERNEL32.dll

 * Use Wine 5.3 or newer.
 * For more details, see [Issue#12](https://notabug.org/Krock/dawn/issues/12#issuecomment-22060).

#### Severe performance regression

As of 2024-06-11, the game suffers from a severe performance drop.
This issue is very similar to what was observed before version 3.8.0, where the solution was
to rename `mhypbase.dll` and patch `xlua.dll`.

**Workaround:** turn off the network until the initial logo appears.
Note: The exact sleep duration depends on your system performance.

Script-based solution:

	nmcli n off && sleep 10 && nmcli n on &
	# start the game process here

Version for Steam:

	nmcli n off ; %command% & pid=$! && sleep 7 ; nmcli n on && wait $pid

Wine-Staging 9.10 or newer may suffer from (sys)log spam *when this workaround is not used*.
In that case, the debug channel `sync` should be disabled using environment variables:

	export WINEDEBUG=-sync

#### Password input shows no characters
Applies to game version 4.2.0 and newer.

In stock/vanilla Wine, the password characters do not show up when typing.
This is a font or display issue only. Input your password as usual. Use
`Backspace` or `Ctrl+A` + `Del` to reset the invisible box contents.

#### Login shows a white rectangle

After activating the "Login" button, a white rectangle appears.
If the Captcha does not appear after 20 seconds, check for solutions in
the following Troubleshooting entries:

 * "In-game browser looks weird or crashes the game"
 * "Error 4206"

If you are using MangoHud: hide it using [Shift_R+F12](https://github.com/flightlessmango/MangoHud#keybindings) before logging in.

**Workaround for Vulkan child window rendering** (no longer applicable)

Obsolete since approx. game version 4.1.0.

This section is dedicated to [Wine bug 45277](https://bugs.winehq.org/show_bug.cgi?id=45277).

1. Check whether you are affected by this bug.
     * Try to open the in-game registration page and open the Wine output log.
     * `err:virtual:virtual_setup_exception stack overflow 2128 bytes` (or similar) appears.
     * If there is no similar error message, proceed with other workarounds.
2. Rename or move the file `*_Data/Plugins/vulkan-1.dll`
3. Login
4. Restore the `vulkan-1.dll` to its original state
     * Otherwise you might face error 31-4302 sooner or later.

Alternatively, use a Wine version that includes experimental child window rendering:

 * wine-ge-custom
 * wine-tkg
 * Valve Wine/Proton (Steam)
 * Methods to check or find other supported Wine builds: (experimental)
     * Search for `pXCompositeRedirectWindow` in the repository
     * Check installed versions: `locate "winex11" | xargs -d '\n' grep sync_vk_surface`
     * Individual check: `find -type f -name "winex11*.so" | xargs -d '\n' grep sync_vk_surface"`

#### Bilibili login page not working

See [INSTALLATION.md](INSTALLATION.md#bilibili) for details.

#### Login prompt appears after each game launch

 * Switch between Linux kernels less often
     * For details, see Issue #373
 * Retry using a virtual desktop (Wine feature)

#### Error 4206 or "Connection timed out"

Alternatively: stuck at "Checking for updates..." without any error message

Possible error sources:

 * Faulty DNS server
     * Manually specify DNS addresses in your connection settings
 * Failing IPv4 fallback
     * Edit `/etc/gai.conf` and uncomment `precedence ::ffff:0:0/96  100`
 * Domain(s) blocked by ISP
     * Try a VPN or a different DNS
 * Custom domain block lists (albeit unlikely)
     * Double-check your `/etc/hosts` file

In rare cases, this issue may be weekday-dependent for unknown reasons.

Solutions: tab ["PC client issues"](https://docs.google.com/spreadsheets/d/1I3aaXaNbHm-igAsFwvlCEHr5xyQKO4Wot8TuywsOhxw/htmlview#)

#### Freeze when loading game data

Unknown cause. Please submit ideas to Issue #90

 * Ensure that an audio output device is enabled
 * Run the game using `-nolog`: `??? cmd /c launcher.bat -nolog`
 * Try another graphics driver or setup a clean, new WINEPREFIX

#### Crash after 20 seconds due to sound output

First seen in version 2.1.0 using PulseAudio.

Check whether the terminal output (`WINEDEBUG` value is irrelevant) contains following line:

 * `INFO: OpenAudioDevice failed: Unsupported number of audio channels`

.. and change the sound output settings to Analog Stereo.

#### An error code appears

Common errors and possible causes. `x` stands for any number:

 * -900x (Out of free storage)
     * Check the read and write permissions of the entire game
       directory, and the `Persistent` sub-directory in particular
     * Try the workaround from error code -9907 below.
 * -9907 (Insufficient space on disk)
     * May occur when installing the game and Wineprefix on separate drives
     * Solution: Open `winecfg` of the game Wineprefix and re-assign the `Z:` drive
       path to the game's installation directory or add a separate drive letter.
     * Alternative: Move the Wineprefix to the game installation drive
     * Duplicate of "Insufficient disk space" in the launcher section.
 * -9908
     * The downloaded data is corrupt. Try a wired connection.
 * 31-4302 (failed checksum)
     * The game (PE) binary files do not in their original state.
       Perform a file integrity check using the launcher. Also run
       [updater/find_surplus_binaries.sh](updater/find_surplus_binaries.sh) to find
       any relevant binary files that are not part of the game.
     * Try a new WINEPREFIX. This will require you to set up DXVK again
       (see [INSTALLATION.md](INSTALLATION.md) or the section "Graphics bugs/issues").
     * If the error still occurs after trying all of the above: please open a new issue.

Extensive permission check for -9xxx errors:

1. Open a terminal in your game installation directory
2. `find ./ -type d \( ! -writable -or ! -readable \) 2>/dev/null`
3. Files that are listed in the terminal output need manual permission correction
     * An empty command output indicates proper file permissions.

If the game is located on an NTFS partition: [Valve/Proton Wiki](https://github.com/ValveSoftware/Proton/wiki/Using-a-NTFS-disk-with-Linux-and-Windows)

#### White screen freeze when entering the door
... plus error log "*err:virtual:virtual_setup_exception stack overflow*".

Obsolete since version 3.8.0. Seen from game version 1.2.0 to 2.4.0 (?) and
from 3.1.0 to 3.7.0 when renaming `mhypbase.dll` without additional patches.

#### 数据异常，请重新登录游戏 | Data error, please log in again.
(error message upon login)

Mostly found on Apple M1 devices. Unknown cause. Inputs are welcome in Issue #401.

See also: YAAGL project

#### Crash when initially loading the world (7 symbols)
... + `error.log` message containing `XAudio2_7.dll caused an Access Violation (0xc0000005)`

Rare occurrence related to an audio failure. Observed in Wine 5.22 and newer.

1. Restart the game
2. Check for music and button sound effects

This crash might also occur when WineD3D is used rather than DXVK.

 * Check the [setup instructions](INSTALLATION.md) again

#### Random game crashes (generic)

If other Windows games work well:

 * Perform a file integrity check using the game launcher
 * You might need to reapply the patch afterwards.

If other Windows games have issues as well:

 * Ensure that DXVK, your GPU - and Vulkan packages are working properly.
   See section "Weak graphics, slow game" for further instructions.

#### In-game browser looks weird or crashes the game

 * Install the required MS core fonts
     * See [INSTALLATION.md](INSTALLATION.md)
 * Re-install DXVK (if present)
 * Try running the game in a virtual desktop (Wine feature)
 * Delete and create a new wineprefix after moving the game files to a safe location
     * For System-wide Wine: you will need to reinstall customizations such as DXVK.

Other font installations might work as well as long Fontconfig can use them as fallback.

#### ZFGameBrowser crash message box

This section is dedicated to "ZFGameBrowser has stopped working" (or similar) message boxes.

 * Ignore and restore the game window
 * For input issues: try the virtual desktop (Wine feature, see below)

For more details, see Issue #29.

#### Graphics bugs/issues

Check whether your GPU supports Vulkan: [unofficial list](https://vulkan.gpuinfo.org/), [Intel](https://www.intel.com/content/www/us/en/support/articles/000005524/graphics.html), [nVIDIA](https://developer.nvidia.com/vulkan-driver), [AMD](https://www.amd.com/en/technologies/vulkan#paragraph-218601)

DXVK setup instructions:

 * Custom script:
     * Download [winetricks](https://github.com/Winetricks/winetricks/)
     * `export WINEPREFIX=/absolute/path/` (if needed)
     * `sh winetricks`
     * Install the DLL package `dxvk` (newest, or 1.7.3 for Proton 5.13)
 * Lutris: Configure -> Runner options -> "Enable DXVK" and specify the version
 * Proton: See [setup instructions](INSTALLATION.md#steam)
 * PlayOnLinux: (outdated DXVK?)
     * Configure game -> Install components -> [Latest DXVK version]

To confirm whether DXVK is working, check the section "Game is on an LSD trip".

Advanced GPU + Vulkan driver health check:

1. Many common distributions come with a GPU driver selection in the system settings.
   Use that before "going down the rabbit hole".
2. See section "How to report issues" for driver information commands
3. Look up your GPU on [TechPowerUp](https://www.techpowerup.com/gpu-specs/) to know the architecture,
   such as "Pascal" (nVIDIA), "RDNA" (AMD), etc.
4. Driver verification: [Arch Wiki: Xorg](https://wiki.archlinux.org/title/xorg#Driver_installation)
5. Vulkan verification: [Arch Wiki: Vulkan](https://wiki.archlinux.org/title/Vulkan#Installation)
6. DXVK check: see section "Game is on an LSD trip".

#### Game is on an LSD trip

(This means that surfaces have very distinct colors)

This issue is often caused by an outdated or missing DXVK installation.

How to check (general approach):

 * Launch with the environment variable `DXVK_HUD=version,devinfo,fps`
     * A HUD must appear in the top left corner
 * Check whether version 1.7.3 or newer is shown
     * Note: DXVK 2.x requires a GPU (and driver) capable of Vulkan 1.3 or newer.
       If that requirement is not met, use DXVK 1.x.
 * Alternatively, following lines in the terminal output indicate lack of DXVK:
     * `fixme:d3d11:wined3dformat_from_dxgi_format`
     * `fixme:d3d:wined3d_check_device_multisample_type`
     * `fixme:d3d_shader:print_glsl_info_log`
 * For installation hints check the section "Graphics bugs/issues" above.

Intel iGPU specific issues:

 * Update Mesa to a recent version, newer is better
 * See [Release Notes](https://docs.mesa3d.org/relnotes.html) for "ANV" mentions and fixes
 * See Issue #152 for the original report.

In case software rendering, i.e. `llvmpipe` is used by accident. This mostly happens on AMD GPUs.

Alternatively: error message "Couldn't switch to requested monitor resolution"

1. Check whether software rendering is used
     * Either: search for `lavapipe` in the terminal output upon launch
     * Or: search for `Device name` + `llvmpipe` in [`output_log.txt`](FAQ.md) after launch
2. Install proper Vulkan packages:
     * Check tutorials, such as [LinuxConfig](https://linuxconfig.org/install-and-test-vulkan-on-linux) or [Arch Wiki](https://wiki.archlinux.org/title/Vulkan#Installation)
     * Advanced users: check the section "Graphics bugs/issues" above.
3. Repeat step 1 to confirm your changes

#### Stripe artifacts appear during longer game sessions

This can be caused by filled VRAM, hence relevant for cards with VRAM <= 2 GB.

 * Depending on the case, this can be avoided by using wine-staging with these
environment variables:
     * `STAGING_SHARED_MEMORY=1`
     * `STAGING_WRITECOPY=1`
 * Alternatively, lower the in-game setting "Render Resolution".

(wine-staging method tested with a GTX 650 Ti Boost, 2 GB)

#### Mouse/keyboard input issues

Easiest solution: Use a virtual desktop (Wine feature).

 * Custom script: `wine explorer /desktop=anyname,1920x1080 cmd /c launcher.bat`
     * Adjust the resolution numbers to your needs
 * Steam + Proton: See [setup instructions](INSTALLATION.md#steam)
 * Lutris: Go to "Runner options" -> Enable "Windowed (virtual desktop)"

Alternative solutions without a virtual desktop:

 * Use Wine-Staging 7.8 or newer (`_NET_ACTIVE_WINDOW` patch)
 * winecfg -> Check "Automatically capture the mouse in full-screen windows"
 * `WINEPREFIX="/path/to/prefix" winetricks usetakefocus=n`
     * Lutris already does this by default.

General Unity3D-specific workaround for ignored inputs after focus loss:

 * Use `Alt+Enter` to toggle to windowed mode
 * Drag the window, focus the desktop, focus the game window (again)
 * When the title bar indicates focus, switch back to fullscreen mode

See also: search engine query `unity wine focus`

#### Too high mouse sensitivity

This workaround is meant for overall high mouse sensitivity.
In case this issue occurs only after switching between workspaces, check the sections below.

Disable `MouseWarpOverride` using Winetricks:

	WINEPREFIX="/path/to/prefix" winetricks mwo=disable

#### Alt + Mouse click not working

Cinnamon users:

 * Workaround: Disable the window move & resize feature
     * See [Linux Mint forums](https://forums.linuxmint.com/viewtopic.php?t=264172)

Xfce4 users:

 * Same solution as in the `causes the view to "spin"` issue below

#### Switching between workspaces causes the view to "spin"

Change the in-game resolution setting:

1. Focus the (virtual) desktop
2. Focus the game window again. The title bar must be marked as active (blue).
3. Change the resolution back to fullscreen

Alternative: use Proton.

#### Wrong window resolution

If the in-game settings are not accessible, do one of the following:

 * Append following arguments after `launcher.bat`:
     * `-screen-width XXX -screen-height YYY -screen-fullscreen 1`
 * Alternative: `-show-screen-selector` to change the settings on startup
 * Alternative: change the virtual desktop's size (Wine feature, if used)
 * Alternative: use regedit to change the keys in `HKCU\Software\...`

See also: [Unity CLI args](https://docs.unity3d.com/Manual/CommandLineArguments.html)

#### Weak graphics, slow game

For performance improving tweaks see [TWEAKS.md](TWEAKS.md).

This may also be caused by software rendering. Check the section "Game is on an LSD trip" above.

**For hybrid graphics (dGPU + iGPU) in laptops:**

1. Use the environment variable `DXVK_HUD=version,devinfo,fps`
2. If the dGPU (such as nVIDIA or AMD) is shown, go to the section "Game is on an LSD trip".
3. If the iGPU (Intel or AMD integrated) is shown:
     * For nVIDIA: Launch Wine with [`prime-run`](https://wiki.archlinux.org/title/PRIME#PRIME_render_offload)
     * ^ If `pvkrun` does not work, uninstall [`bumblebee`](https://wiki.archlinux.org/title/Bumblebee) prior to installing `prime-run`
     * For AMD: Use the environment variable `PRIME_RUN=1`
4. Repeat the check in step 1

Consider to run your game manager (if present) directly from the dGPU to make sure that
other games benefit from the discrete GPU performance as well.

**Note:** If Lutris is used, environment variables can be specified in the `System options` tab

#### Stutters

**General stutters**

DXVK needs to compile and cache (`*.dxvk-cache` files) shaders that are required in the game.
It might take a while to build up the cache until the stutters reduce.

Try Esync or Fsync for further improvements: [TWEAKS.md#esync](TWEAKS.md#esync)

**Stutters specific to Radeon RX 6000 series**

Caused by:

 * Less recent Mesa drivers (<= Y2022)
 * Displays with adaptive sync support

Workaround: [TWEAKS.md#amd-gpu-performance-tweaks](WEAKS.md#amd-gpu-performance-tweaks)

#### Locale-specific keyboard layout not working

Upon input, question mark signs (`?`) appear rather than the typed characters.

Gnome: Move the locale-specific layout to second place

  * [Example configuration](https://notabug.org/attachments/3994e09e-e7a1-4c34-83a1-87c5e421375b)

Change the environment variable `LANG` to your locale

 * Run `locale -a` to pick your native language (referenced as `your_LOCALE.utf8` below)
     * Custom script: `LANG=your_LOCALE.utf8 wine ....`
     * Lutris: Configure -> "System options" -> Add `LANG`, `your_LOCALE.utf8`
       to the environment variables
         * See also: [forum discussion with instructions](https://forums.lutris.net/t/solved-need-help-launching-a-game-with-custom-locale/6404)
     * Steam: Add `LANG=your_LOCALE.utf8` in front of the "Start options" input box.
         * e.g. `LANG=ja_JP.utf8 %command% /desktop=anyname,800x600 ....`

Custom script: if the problem persists, create or update a WINEPREFIX using your locale

 * `WINEPREFIX=/path/to/wineprefix/ LANG=your_LOCALE.utf8 /path/to/wineboot -u` (untested)

#### Voiced cutscenes lack audio playback

 * Ensure that `faudio` is installed (Ubuntu: `libfaudio0`)
     * See also: [official Wine setup instructions](https://wiki.winehq.org/Download)
 * Try another, newer Wine version

#### "Feedback" and "Special Event" buttons crash Wine

Stock/vanilla Wine can yet not handle URLs of this length yet. They cause a stack
corruption which in turn crashes the game. The following workarounds exist:

Use a Wine build that contains crash fixing patches:

 * Wine-GE 8-16 (or newer)
 * Proton-GE 8-16 (or newer)

"Feedback" button:

1. For Gacha analytics: check [FAQ.md](FAQ.md) for alternatives
2. Check your in-game mail. It should contain a working URL.
     * Important: `zfgamebrowser.exe` must *still* be running (default)
3. If there is no mail, wait for the reminder (arrives a few days).

"Special Event" button:

1. Check the in-game browser for event links.
     * This is unreliable and might crash Wine in some cases
2. Obtain the link from official channels or community. (e.g. Twitter)

#### Frequent crashes due to avcodec-58

Check whether this issue applies to you:

1. Wait for the game to crash.
2. Scroll to the bottom of `output_log.txt` (see [FAQ.md](FAQ.md))
3. `(avcodec-58)` is mentioned in the stack trace section

Solution: Disable the library.

 * Lutris: See [INSTALLATION.md](INSTALLATION.md)
 * Custom script: Use the environment variable `WINEDLLOVERRIDES=avcodec-58.dll=d`

#### Crash when joining co-op

See "White screen freeze when entering the door".

### Information sources

 * [PlayOnLinux](https://www.playonlinux.com/en/app-4228.html)
 * [NotABug issue tracker](https://notabug.org/Krock/dawn/issues)

### How to report issues

Please upload long log files to an external service such as:

 * https://pastecord.com/
 * https://paste.debian.net/
 * https://pastebin.com/
 * https://dpaste.com/

Following information can help to speed up the troubleshooting process:

1. What are you using: custom script, Lutris, Steam, other?
2. Did you follow the [installation instructions](INSTALLATION.md)?
3. For setup issues: provide the WINEDEBUG terminal output
     * Custom script: `wine ????? 2>debug.txt` (redirect stderr to a new file)
     * Lutris: [Obtaining log output for games](https://github.com/lutris/docs/blob/master/ProvidingLogs%26SystemInfo.md#obtaining-log-output-for-games)
     * Steam: start Steam from the terminal: `PROTON_LOG=1 steam`
          * Log files are saved to `$HOME/steam-*.log`
4. For in-game crashes: provide its crash information
     * The file paths can be found in [FAQ.md](FAQ.md).
       Note: Wine-internal crashes might not generate a new dump in the Temp directory.
     * `output_log.txt`: DLL listing and stack backtrace at the end of the file
     * `error.log`: lines until (and including) `Bytes at CS:EIP:` are the most helpful
5. Collect and provide GPU driver information
     * GPU driver: `lspci -v | grep "VGA" -A 15`
     * General overview: `inxi -Ga`
     * Vulkan driver: `vulkaninfo --summary` or `vulkaninfo | grep DRIVER_ID -A 3`


code:
# Tweaks

This file lists some configuration file tweaks, performance tweaks, visual tweaks, and the likes of making your game run better.

## Performance tweaks

Please keep in mind that the minimal specifications also apply for Linux. Do not expect a performance gain compared to Windows native.

As of game version 3.2.0, it is recommended to apply the secondary patch to noticeably
lower the CPU usage. Please check Issue #195 and the script source for details.

	bash "/path/to/dawn/GAMEVER/patch_anti_logincrash.sh"

#### DXVK

Check whether the latest DXVK version is installed in your `WINEPREFIX`:

* Use default `WINEDEBUG` (no `-all`!) and check the (terminal) output
* `output_log.txt` ([what?](FAQ.md)) should mention DXVK

Setup instructions: [TROUBLESHOOTING.md](TROUBLESHOOTING.md#graphics-bugsissues)

#### Esync

Esync will sometimes work faster than Fsync on some specific game/machine combinations ([see here](https://flightlessmango.com/benchmarks/Esync_vs_Fsync)).

Please note that the official Wine builds do not come with Esync support.
One of the following builds is required:

**Lutris:**

 * Select game -> Configure -> Runner options -> "Enable Esync"
 * See also: [Official tutorial](https://github.com/lutris/docs/blob/master/HowToEsync.md)

**Proton:**

 * Enabled by default when running from the Steam library

**wine-staging or custom build:**

 * Add `export WINEESYNC=1` to your script prior to launching the game

If you have access to the terminal output (or logs), look out for
`esync: up and running.` mentions to confirm that it's working.

#### AMD GPU performance tweaks

This section is about reducing choppy framerates on amdgpu + radv.
According to Issue #321 the GPU might not boost the clocks properly.

*Note: This also affects other games and might be fixed in future driver updates.*

 * Hardware configuration (`amdgpu` driver specific)
     * Note: The kernel settings are not persistent and will reset on reboot.
     * For details: [amdgpu kernel documentation](https://kernel.org/doc/html/latest/gpu/amdgpu/thermal.html#power-dpm-force-performance-level)
     * `echo 1 | sudo tee /sys/class/drm/card0/device/pp_power_profile_mode`
         * Improves performance on adaptive sync displays
     * `echo high | sudo tee /sys/class/drm/card0/device/power_dpm_force_performance_level`
         * Might not be needed any more for recent driver versions.
     * For `gamemode` users:
         1. Edit the configuration file.
         2. Add the line `amd_performance_level=high` to the `[gpu]` configuration section.
 * Game settings
     * Render Resolution: 1.0
     * Shadow Quality: Low
     * Volumetric Fog: Off
     * V-Sync: On (avoids tearing)

For Arch Linux: Steam installs the dependencies `amdvlk` and `lib32-amdvlk` by default.
This might cause performance or game startup issues in general. To use RADV (provided by Mesa),
uninstall both libraries. Run a Vulkan verification test after rebooting.

 * For details, see [Vulkan, Arch Wiki](https://wiki.archlinux.org/title/Vulkan)

#### GPU bottleneck improvements

 * Stutter and low FPS on GPUs with <= 2 GB VRAM
    * For monitoring: `nvidia-smi`/`nvtop` (nVIDIA), `radeontop` (AMD), `corectrl` (AMD)
    * Use a DXVK 1.X.X version, 1.9.4 or newer (memory management improvements)
    * In-game setting: Change "Render Resolution" to 0.8 or lower
        * This setting changes the texture resolution, resulting in less VRAM usage
    * Disable Anti-Aliasing (less blur)
    * Close `zfgamebrowser.exe` to free approx. 60 MB (after DXVK 1.9.4)
 * In-game setting: Disable "Volumetric Fog". Introduces more lag than what's worth it
 * In-game setting: Lower "Shadow Quality". May improve the frame rates
 * Create a file named `dxvk.conf` where `GenshinImpact.exe` resides. Example options for vsync-less (mailbox mode), tearing-free, low latency gameplay:

```
# Change to 3 for triple buffering (improves performance at the cost of latency)
dxgi.numBackBuffers = 2
dxgi.syncInterval = 0
dxgi.tearFree = True
# More performance
d3d11.constantBufferRangeCheck = False
d3d11.relaxedBarriers = True
d3d11.invariantPosition = False
d3d11.zeroWorkgroupMemory = False
```

Also the environment variable `DXVK_ASYNC=1` might help to reduce stutters. This
feature is not available by default and requires a [special DXVK patch](https://github.com/Sporif/dxvk-async).

#### FSR - FidelityFX Super Resolution

FSR is an image upscaler which can improve game performance.
See [AMD website](https://www.amd.com/en/technologies/radeon-software-fidelityfx-super-resolution) for details.

The following two sections each describe a method to get FSR running.

##### FSR with Gamescope

Links for reference:

 * [gamescope project site](https://github.com/Plagman/gamescope)
 * [LinuxReviews testing report](https://linuxreviews.org/Gamescope)

**Caveats:**

 * Requires a native window (no virtual desktop)
 * At the time of writing, it requires recent driver packages.
     * Pleas refer to the project site for details
 * Causes input lag and mouse cursor behaviour is not ideal
 * Package not present in some distributions' repositories

To benefit from improvements in newer Wine/Proton versions, gamescope is
designed as a long-term solution.

General features:

 * Graphic environment independent
 * Custom upscaling / downscaling of any game running inside of it
 * UI integration in some game launchers, such as Lutris

Command line example:

	# General syntax
	gamescope -w <game_visible_width> -h <game_visible_height> -W <final_window_width> -H <final_window_height> -U -f -- <command>
	# Example for upscaling 1080p -> 1440p
	gamescope -w 1920 -h 1080  -W 2560 -H 1440 -U -f -- wine cmd /c launcher.bat -window-mode exclusive

 * Notes
     * `-f` means Gamescope window will be fullscreen at startup.
       You want that for Variable Refresh Rate (Free/G/Sync).
     * `Super + F` can be used to switch between Fullscreen/Window for Gamescope output.
     * Once windowed, Gamescope output can be resized but blackbars may appear
     * Please refer to the project site for further tweaking

##### FSR bundled with Wine

**Caveats:**

 * Requires a native window (no virtual desktop)
 * Resolution changes must be done in windowed mode or by command line arguments
    * Use `Alt+Enter` to switch between windowed and fullscreen

Wine builds known to embed the feature at this moment are:

 * proton-ge-custom
 * wine-ge-custom
 * Kron4ek's Wine builds
     * Supported versions to be checked.

Required command line arguments:

 * Append `-window-mode exclusive` after `launcher.bat`
    * Example: `??? cmd /c launcher.bat -window-mode exclusive`

Configuration via environment variables: (example values are the default)

 * `WINE_FULLSCREEN_FSR=1` -> enables FSR
 * `WINE_FULLSCREEN_FSR_MODE=balanced`
    * One of `ultra`, `quality`, `balanced` or `performance`
 * `WINE_FULLSCREEN_FSR_STRENGTH=2` -> values from 0 (sharp) to 5 (blurry)
 * Instructions:
    * Steam: adjust the `Target` box. Example: `FOO=1 BAR=1 cmd.exe`
    * Lutris: add rows to `Configuration` -> `System options` -> `Environment variables`

Checking whether FSR is enabled:

1. Specify the environment variable `WINEDEBUG=trace+fshack`.
2. The line `trace:fshack:fs_hack_is_fsr is_fsr: TRUE` must appear in the Wine output.

#### Loading times

This is an optimization for installations on a slow drive.
You may make Linux' file caching to RAM more aggressive in order reduce loading
times for repetitive actions.

1. Open `/etc/sysctl.conf` with an editor like `nano` with sudo.
2. Add the line `vm.vfs_cache_pressure = 10`. Save and exit.
3. Run `sudo sysctl -p` to reload the kernel configuration.

## Visual tweaks

#### Benchmark

* Set the environment variable `DXVK_HUD` to `fps,frametimes`
* For a fancier display, try [MangoHud](https://github.com/flightlessmango/MangoHud) instead.

#### Post Processing using vkBasalt

[vkBasalt](https://github.com/DadSchoorse/vkBasalt) offers cool shaders and re-shade-like features.

1. Disable in-game antialiasing
2. Create a file named `vkBasalt.conf` in the directory where `GenshinImpact.exe` resides.
3. Relevant information and examples:
    * Detailed descriptions: [official `vkBasalt.conf`](https://github.com/DadSchoorse/vkBasalt/blob/master/config/vkBasalt.conf)
    * Presets by notahuman: [Releases page](https://notabug.org/notahuman/presets/releases)
    * Other user-provided presets: [static/](static/)

repo_name: ElecDashi/dawn

license: mit


code:
#!/usr/bin/env bash

# DESCRIPTION
#     This script corrects an error within Qt5 Chromium library used by the
#     official "classic" Genshin launcher across (almost?) all versions.
#     This script is needed since approx. Wine 9.8.
#
#     How to use: Execute this script within your launcher installation directory.
#     Example:    bash /path/to/repo/compat/Qt5WebEngineCore_patch.sh
#
# IMPLEMENTATION DETAILS
#     This patch adds an additional `if (sacl == nullptr) return ERROR_SUCCCESS;`
#     check in between the following lines: https://github.com/qt/qtwebengine-chromium/blob/69-based/chromium/sandbox/win/src/restricted_token_utils.cc#L289-L291
#
# EXIT STATUS
#     0      : The patch was applied successfully or is not needed by your system.
#     other  : Patch failure. See stdout or stderr output for details.

DIR=$(dirname "${BASH_SOURCE[0]}")
FILE="Qt5WebEngineCore.dll"

if [ ! -e "$FILE" ]; then
	echo "[ERROR] File '$FILE' not found. Please check the script usage notes."
fi

sum=($(md5sum $FILE))

if [[ "$sum" != "6c3e89dfd553a91055959f5f21584931" ]]; then
	# The patch might corrupt invalid/outdated files if this check is skippd.
	echo "[ERROR] Wrong file version or the patch is already applied"
	echo " -> md5sum: ${sum}" && exit 1
fi

if ! command -v xdelta3 &>/dev/null; then
	echo "[ERROR] 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 "--- Patching $FILE"

xdelta_fail() {
	mv -vf "$FILE.bak" "$FILE"
	exit 1
}

mv -f "$FILE" "$FILE.bak"
xdelta3 -d -s "$FILE.bak" "$DIR/Qt5WebEngineCore_patch.vcdiff" "$FILE" || xdelta_fail

echo "==> Patch applied successfully"
exit 0


code:
## Setup-specific scripts

This directory is a collection of game version independent scripts specific
to a certain operating system or setup.

**Note:** It is generally recommended that scripts be proofread before execution.

See the script content for details. Scripts that are user-oriented contain a
Manpage-style explanation of its purpose.


code:
#!/usr/bin/env bash
# DESCRIPTION
#     Extracts the gacha URL from the Chromium Embedded Framework cache.
#     The file paths are detected automatically based on the game process ID
#     and executable path.
#
# NOTES
#     This script currently returns the last URL in the cache file, which
#     usually works but is not entirely reliable.
#
# EXIT STATUS
#     0 on success

set -e
GIPATH="."

function get_path_from_pid() {
	# tee eats the status value
	_pid=$(pgrep -f -- "GenshinImpact.exe" | tee | head -1)
	if [ -z "$_pid" ]; then
		_pid=$(pgrep -f -- "YuanShen.exe" | tee | head -1)
	fi
	[ -z "$_pid" ] && echo "Game process not found" && exit 1
	GIPATH=$(pwdx "$_pid")
	GIPATH=${GIPATH#*\ } # remove leading "pid: "
}

get_path_from_pid

# Get the most recently modified "data_2" file: ISO timestamp + absolute path
CACHEFILE=$(find "$GIPATH" -type f -wholename '*/Cache_Data/data_2' -printf "%T+ %p\n" | sort | tail -n 1)
CACHEFILE=${CACHEFILE#*\ } # remove leading timestamp
echo "Found cache file: $CACHEFILE"
echo "===== Matching links:"

strings "$CACHEFILE" | grep -o "https://public-operation-hk4e-sg.hoyoverse.com/gacha_info/api/getGachaLog.*end_id=0" | tail -n1


code:
"""
MIT License

Copyright (c) 2022 zeroday0619 <zeroday0619_dev@outlook.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""

import os
import glob
import logging
import re # regex
import zipfile
from shutil import copyfile, copytree

logging.basicConfig(format=logging.BASIC_FORMAT, level=logging.INFO)
logger = logging.getLogger("lutris_packaging.py")

# Newest patch has the "patch.sh" script inside
def get_patch_ver():
    files = glob.glob("../???/patch.sh")
    assert len(files) == 1, "Found too many patch versions"
    match = re.match(".*/(\d+)/.*", files[0])
    return match.group(1)

work_dir = os.getcwd()
patch_version = get_patch_ver()
logger.info(f"Packing for version {patch_version}")

# Destination directory for zipping
dst_dir = f"{work_dir}/gi_patch_{patch_version}"
dst_dir_files = f"{dst_dir}/patch_files"

# Patch source files
src_dir = f"{work_dir}/../{patch_version}"
src_dir_files = f"{src_dir}/patch_files"

def my_mkdir(path):
    if not os.path.exists(path):
        logger.info(f"create dir -> {path}")
        os.makedirs(path)
    else:
        logger.warning(f"already exist -> {path}")

class CreateDirFaild(OSError):
    pass

def mkdir_gi_patch():
    try:
        my_mkdir(dst_dir)
        my_mkdir(dst_dir_files)
    except OSError:
        raise CreateDirFaild()

def my_copyfile(src, dst):
    src_rel = os.path.relpath(src)
    dst_rel = os.path.relpath(dst)
    logger.info(f"copy {src_rel} -> {dst_rel}")
    copyfile(f"{src}", f"{dst}")

def copy_gi_patch():
    if not os.path.exists(src_dir):
        logger.error(f"Directory is not found -> {src_dir}")
        raise NotADirectoryError()

    my_copyfile(f"{src_dir}/patch.sh", f"{dst_dir}/patch.sh")
    my_copyfile(f"{src_dir}/patch_anti_logincrash.sh", f"{dst_dir}/patch_anti_logincrash.sh")
    my_copyfile(f"{src_dir}/patch_revert.sh", f"{dst_dir}/patch_revert.sh")

    copytree(src_dir_files, dst_dir_files, dirs_exist_ok=True)
    logger.info(f"copy {src_dir_files} -> {dst_dir_files}")

# Scripts for integration with the Lutris configuration file
template_apatch="""#!/bin/bash
DRIVE_C="$(pwd)/.."

cd "$DRIVE_C/Program Files/Genshin Impact/Genshin Impact game/"
bash "$DRIVE_C/gi_patch/patch.sh"
bash "$DRIVE_C/gi_patch/patch_anti_logincrash.sh"
echo "Press enter to close this window..."
read a
"""

template_rpatch="""#!/bin/bash
DRIVE_C="$(pwd)/.."

cd "$DRIVE_C/Program Files/Genshin Impact/Genshin Impact game/"
bash "$DRIVE_C/gi_patch/patch_revert.sh"
echo "Press enter to close this window..."
read a
"""

def opener(path, flags):
    return os.open(path, flags, 0o777)

def create_scripts():
    os.umask(0) # why is this needed?

    if not os.path.exists(f'{dst_dir}/ex_apatch.sh'):
        logger.info(f"create scripts -> {dst_dir}/ex_apatch.sh")
        with open(f'{dst_dir}/ex_apatch.sh', 'a', opener=opener) as ex_apatch:
            ex_apatch.write(template_apatch)
    else:
        logger.warning(f"already exist -> {dst_dir}/ex_apatch.sh")

    if not os.path.exists(f'{dst_dir}/ex_rpatch.sh'):
        logger.info(f"create scripts -> {dst_dir}/ex_rpatch.sh")
        with open(f'{dst_dir}/ex_rpatch.sh', 'a', opener=opener) as ex_rpatch:
            ex_rpatch.write(template_rpatch)
    else:
        logger.warning(f"already exist -> {dst_dir}/ex_rpatch.sh")

def compression():
    logger.info("Compression start")
    zip_f = zipfile.ZipFile(f"gi_patch_{patch_version}.zip", "w")
    os.chdir(dst_dir)
    for (path, dir, files) in os.walk(dst_dir):
        for file in files:
            logger.info(f"Add to archive: {os.path.relpath(path, dst_dir)}/{file}")
            zip_f.write(os.path.join(os.path.relpath(path, dst_dir), file), compress_type=zipfile.ZIP_DEFLATED)
    zip_f.close()
    logger.info(f"Compression complete: gi_patch_{patch_version}.zip")

mkdir_gi_patch()
copy_gi_patch()
create_scripts()
compression()


code:
#!/usr/bin/env bash

# DESCRIPTION
#     This script corrects most (but not all) model rendering issues on macOS
#     (Metal API, MoltenVK) by computing skinned meshes by the CPU instead of GPU.
#
# EXIT STATUS
#     0      : The patch was applied successfully or is not needed by your system.
#     other  : Patch failure. See stdout or stderr output for details.
#
# AUTHOR
#     3Shain (2023)

if ! [[ $(uname) == "Darwin" ]]; then
	echo "You do not need this patch if you are not on macOS."
	exit 0
fi

DIR=$(dirname "${BASH_SOURCE[0]}")
DATADIR=$(find . -maxdepth 1 -type d -name "*_Data")
GGM="$DATADIR/globalgamemanagers"
PATTERN="67616d657300000001"

match=$(xxd -p -c 100000000 < "$GGM" | grep -o "$PATTERN")
if [ -z "$match" ]; then
	echo "[ERROR] Incompatible file or the patch is already applied."
	exit 1
fi

echo "--- Patching globalgamemanagers"

mv -f "$GGM" "$GGM.bak"
# Universal for both CN and OS game builds
xxd -p -c 100000000 < "$GGM.bak" | sed "s/${PATTERN}/67616d657300000000/" | xxd -r -p > "$GGM"

# 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


code:
#!/usr/bin/env bash

# DESCRIPTION
#     Applies to: SteamOS, Chinese and Japanese keyboard layout
#     This script enables the Chinese and Japanese locale files and regenerates them.
#
# NOTES
#     The changes done by this script might be undone by system updates.
#
# AUTHOR
#     Bluefissure (2023)

sudo steamos-readonly disable
sudo pacman-key --init
sudo pacman-key --populate archlinux

# Update glibc
sudo pacman -S glibc

# Enable (uncomment) the locale
sudo sed -i "s%#ja_JP.UTF-8 UTF-8%ja_JP.UTF-8 UTF-8%" /etc/locale.gen
sudo sed -i "s%#zh_CN.UTF-8 UTF-8%zh_CN.UTF-8 UTF-8%" /etc/locale.gen

# Regenerate all enabled locale
sudo locale-gen
sudo steamos-readonly enable

echo "Next steps:"
echo "1. In Steam: use the start options 'LANG=ja_JP.UTF-8 %command%' or 'LANG=zh_CN.UTF-8 %command%'"
echo "2. Restart steamOS before starting the game"


code:
# UnityPlayer 1.1.0

## Meta

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 33929328 bytes                   |
| Modification date | 2020-11-03                       |
| md5sum            | a85caddc4d1e5838f404956e99995d27 |

## Addresses

Warning: Address is not the same as the byte offset in the binary.

| # | Type       | Address   | Description                            |
|---|------------|-----------|----------------------------------------|
|  1| func       | 1814cee00 | mhyprot2.sys init                      |
|  ^| PUSH 40 55 | 1814ce7b0 | Patch: `3C` (RET), function skip       |
|  2| func       | tba       | Anticheat check routine (1)            |
|  ^| crash      | 181d71fc3 | Access violation when skipping mhyprot2|
|  ^| MOV 8B 28  | 181d71fc3 | Patch: `31 D2` (EDX=0)                 |
|  3| func       | ??        | Service control (unclear)              |
|  ^| ptr        | ??        | Pointer to service control function    |
|  4| func       | 180e638b0 | Windows version getter                 |
|  5| func       | 1807eb580 | printf("...", ...) to terminal         |
|  6| func       | 180e67e03 | === OUTPUTING STACK TRACE === function |
| 23| func       | 1814d9fe0 | Checks a single file file (integrity)  |
| 24| func       | 1814e4480 | Checks multiple files (integrity, 2)   |

Detailed explanation:

**1:** Earliest known OP-Code of this function. Is executed approx. 10 seconds after the "Warning" screen was shown.

**2:** See [backtrace](raw/backtrace_crypt.txt) log

* Uses `CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED`


code:
# UserAssembly 1.1.0

## Resources

 * [global-metadata.dat](https://www.unknowncheats.me/forum/downloads.php?do=file&id=31548) (decrypted)
 * [global-metadata.pdb](https://notabug.org/Kowalski/GI-on-Linux/src/master/110/symbols/UserAssembly.7z)

Sorted by ease-to-use.

#### global-metadata.pdb

**Does not work on Linux**

Read-to-use debugging symbols, thanks to Kowalski.

Ghidra:

 * Linux: not supported
 * Windows: obtain the `msdia140.dll` file (2017 and 2019 Build Tools surely have it)
    * See `PATH/TO/ghidra/docs/README_PDB.html`

x64dbg:

 * Not tested yet. Should work.

#### *.cpp / *.h Headers

1. Download `global-metadata.dat`
2. Decode it using [Il2CppInspector](https://notabug.org/Krock/GI-on-Linux/src/master/TOOLS.md#il2cppinspector) (instructions)
3. `cpp/appdata/` will be generated along with a Python script
4. Proceed as described in [their README](https://github.com/djkaty/Il2CppInspector/blob/master/README.md)

Ghidra (not tested): change `MAXMEM` passed to `ghidraRun`. It will require more than 3 GiB.

#### *.cs Headers

Debugging symbols as *.cs or *.cpp from `global-metadata.dat`

1. Download `global-metadata.dat`
2. Decode it using [Il2CppDumper](https://notabug.org/Krock/GI-on-Linux/src/master/TOOLS.md#il2cppinspector) (instructions)
    * The official version does only work partially
    * Error thrown after generating `dump.cs`
3. Read `dump.cs` and look out for the VA (Virtual Address) numbers

## Meta

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 119925872 bytes                  |
| Modification date | 2020-11-03                       |
| md5sum            | 265e3191d082bdcac55eee8afe1a9a81 |

## Addresses

Warning: Address is not the same as the byte offset in the binary.

| Function                                    | Address  | Description                              |
|---------------------------------------------|----------|------------------------------------------|
| void JDOLLLDKIAH:Tick()                     | 1818F1080| Main game loop                           |
| void MLEIPCMPDNB:KKKFPCEAECG()              | 1810E21D0| irrelevant, error display func           |
| bool EMDOOJFMAFO:IIMKPKFHPBK(PKLNHBKFINC)   | 180F3EA50| irrelevant, error display func           |
| void EMDOOJFMAFO:CBMHKMIGHAP(DKIMLPCIKJE)   | 180F316E0| Displays error obj DKIMLPCIKJE           |
| HashAlgorithm.ComputeHash(Stream)           | 182EC2900| irrelevant                               |
| NativeMethods.GetProcAddress(IntPtr, string)| 183B02A70|                                          |
| static void (ref byte[], int)               | 18267e970| UDP enc/dec function (1)                 |
|                                             |          |                                          |
| RetChecksumInvalid = 31                     |  const   | Error 31-XXXX                            |
| LOGIN_PLAYER_LOGIN__FAIL = 4302             |  const   | Error XX-4302                            |
|                                             |          |                                          |
| void FNOBHGHDEFL(string, uint = 0)          | 1818e5a40| Calls to UnityPlayer [24] indirectly (2) |
| void FMIMJHLBKHF()                          | 180f39020| Game / scene manager function ^  related |
| part of JDOLLLDKIAH:FNOBHGHDEFL             | 1818e5f54| Is called on every door entering (3)     |

Detailed explanation:

**1:** According to humanik12 this function was located at UserAssembly+0x1640860 in version 1.0.1.
Searching for similar bytes led to this identical-looking function.

Calls to this function: (according to Cheat Engine)

 * 1x after the initial "warning" screen
 * 1x after clicking "Start" (after server selector)
 * ~8x after entering the door, until the error message is shown

**2:** See [backtrace](raw/backtrace_crypt.txt) log

**3:** Is called on both, modified and clean clients. Earlier code collects system information.

#### Error stack backtrace

**Stack backtrace of 31-4302, sent to the logging server:** (version 1.1.0)

	MoleMole.SuperDebug:LogToServerInternal(Boolean, String, LogType, Boolean, Int32, Int32)
	MoleMole.SuperDebug:LogToServer(LogType, String, Boolean, Int32, Boolean, Int32)
	MoleMole.SuperDebug:VeryImportantError(String, Boolean, Int32, Int32)
	EMDOOJFMAFO:CBMHKMIGHAP(DKIMLPCIKJE)
	EMDOOJFMAFO:IIMKPKFHPBK(PKLNHBKFINC)
	PHPNKGGINJA:ENLPMLLNNPL(PKLNHBKFINC, Boolean&)
	JDOLLLDKIAH:BELMLPGKIND(PKLNHBKFINC)
	System.Func`2:Invoke(T)
	MLEIPCMPDNB:KKKFPCEAECG() -> UserAssembly 1810E21D0
	JDOLLLDKIAH:Tick() -> UserAssembly, 0x1818F1080
	MoleMole.GameManager:MCDBNNFBPFM()
	MoleMole.GameManager:Update()

Function name source: `global-metadata.dat`


code:
===== Part 1

Sysinternals' ProcMon

DLL               Memory offset     Size
---------------------------------------------
crypt32.dll       0x7ffb5df60000    0x15d000
UnityPlayer.dll   0x7ffb3ab90000    0x2124000
UserAssembly.dll  0x7ffb2b9a0000    0x74ae000

N°  DLL name          Memory offset    Call VA     Function start VA + Description
----------------------------------------------------------------------------------
<nt internals>
22  crypt32.dll       0x7ffb5df616a9      [CryptQueryObject]
23  UnityPlayer.dll   0x7ffb3c069b7d   1814d9b77   1814d9fe0  Checks 1 file
24  UnityPlayer.dll   0x7ffb3c0748d7   1814e48d2   1814e4480  Checks multiple files
25  UnityPlayer.dll   0x7ffb3c979aea  ?181de9aea      ??      Obfuscated
26  UnityPlayer.dll   0x7ffb3b54e300   1809be2fa  ?1809be2ed  Poiner call in RAM
27  UserAssembly.dll  0x7ffb2d285e86   1818e5e81   1818e5a40  JDOLLLDKIAH_FNOBHGHDEFL login, record user data
28  UserAssembly.dll  0x7ffb2c8d914f   180f3914a   180f39020  EMDOOJFMAFO_FMIMJHLBKHF scene manager, void() func
29  UserAssembly.dll  0x7ffb2c8f22f2   180f522ed   180f52220  EMDOOJFMAFO_OLKFFMFKDGG scene manager, void() func
30  UserAssembly.dll  0x7ffb2d4d3508   181b33506   181b33380  NBHFAFPNMFJ_TData_LPECKINONOE_System_Object__Invoke (indirect function call)
31  UserAssembly.dll  0x7ffb2cfe090e   181640909   1816405d0  HBDCEMPPDBC_BLOEOBAFLDM action handler
32  UserAssembly.dll  0x7ffb2c8e6637   180f46632   180f45ea0  EMDOOJFMAFO_JNCDIEGFDOM scene manager, game manager
33  UserAssembly.dll  0x7ffb2c8deb4c  ~180F3EB4C     ??
34  UserAssembly.dll  0x7ffb2dbf4941   18225493f   1822547d0  PHPNKGGINJA_ENLPMLLNNPL GlobalManager function
35  UserAssembly.dll  0x7ffb2d28245b
36  UserAssembly.dll  0x7ffb2dc37037
<main game loop etc>

N°  DLL name          Memory offset    Call VA     Function start VA + Description
----------------------------------------------------------------------------------
<nt internals>
14  KernelBase.dll   0x7ffb5e3b78c6       [CreateFileW]
15  UnityPlayer.dll  0x7ffb3c00ce5f
16  UnityPlayer.dll  0x7ffb3c00c699
17  UnityPlayer.dll  0x7ffb3c00d175
18  UnityPlayer.dll  0x7ffb3c014952
19  UnityPlayer.dll  0x7ffb3bffb28b
20  UnityPlayer.dll  0x7ffb3bffb310
21  UnityPlayer.dll  0x7ffb3c069363
22  UnityPlayer.dll  0x7ffb3c069ed8
23  UnityPlayer.dll  0x7ffb3c069ffd    1814d9ff8    1814d9fe0  Checks 1 file
24  UnityPlayer.dll (0x7ffb3c0748d7)
<same as N° 24 above>

===== Part 2

"Memory viewer" -> "UserAssembly.dll+1000"
"Exception Breakpoint" -> "Break on Access"
REQUIRES UNITYPLAYER FILE WHICH DOES NOT DISABLE THE MHYPROT SERVICE

DLL/Symbol         Call VA
---------------------------
bcrypt.BCryptHashData  1877
rsaenh.dll           1835FB
CRYPTSP.dll          1820C4
UnityPlayer.dll   1814DD270
UnityPlayer.dll   1814EDADF
UnityPlayer.dll   1814E42D5 // start 1814e4030 HASH
UnityPlayer.dll   181DE9AB3
UnityPlayer.dll   1809BE300
UserAssembly.dll  1818E5E39 // JDOLLLDKIAH_FNOBHGHDEFL login, record user data
UserAssembly.dll  180F3914F // EMDOOJFMAFO_FMIMJHLBKHF scene manager
UserAssembly.dll  180F522F2 // EMDOOJFMAFO_OLKFFMFKDGG
UserAssembly.dll  181B33508
UserAssembly.dll  18164090E // HBDCEMPPDBC_BLOEOBAFLDM
UserAssembly.dll  180F46637 // EMDOOJFMAFO_JNCDIEGFDOM
UserAssembly.dll  180F3EB4C
UserAssembly.dll  182254941
UserAssembly.dll  1818E245B
UserAssembly.dll  182297037 // Func_2_Object_UInt64__Invoke
<main game loop etc>


code:
# xLua 1.0.1 + 1.1.0

## Sources

 * `lua_injection.sh` Patch script for Lua
 	* Contain patch description
 * `lua_injection.lua` Custom script that is run 2x
    * first: while showing the startup logo (just few functions)
    * second: after showing the warning screen (API is available here)
    * Has to be named `no message`
    * Must be located in GI's working directory

## Meta

md5sum: 2ec35c55430c7fcd3b313df8cd105d9e

## Addresses

See `lua_injection.sh`

## API

See also:

 * [comment issue#4](https://notabug.org/Krock/GI-on-Linux/issues/4#issuecomment-22288) summary
 * [InjectFix](https://github.com/Tencent/InjectFix) repository
 * [xLua source](https://github.com/Tencent/xLua) if you're curious

This part does not document the entire API. Dump `_G` using the script (~400 KiB)

Honorable mentions:

 * `sb_1184180413("FUNCTION", args, ...)`
    * Executes any C function
 * `package.loaded["Hotfix/Hotfix"]`
    * Delayed. Available shortly after login screen
    * Function `HotfixDispatch(??)` might be interesting


code:
# Journal for 1.1.0

### Service

The [`mhyprot2.sys`](mhyprot2.md) service is started in [`UnityPlayer.dll`](UnityPlayer.md), and hash-checked against modifications when entering the door.

### Checksum = Error 31

UnityPlayer checks the following files:

 * All `*.exe`, `*.dll`, `*.sys` files (recursively)

What does it do?

1. You click the door after logging in
2. UserAssembly jumps -> UnityPlayer
3. For each file:
	1. call `CryptQueryObject`
	2. what does it to?
4. Returns to -> UserAssembly
5. Probably sends it over the network

![Process information](https://i.postimg.cc/rF348zG9/grafik.png)

### Network

Detailed information: [network.md](network.md)

1. A large majority of packets has the same length when comparing Windows and Linux.
2. Game data is transferred using UDP, security stuff seems to be done using TLSv1.2.
3. The Linux client begins loading the game data over UDP, but opens a connection to the logging server to report the error.

Note: All error messages are reported to them. I blocked the logging servers for now, just to be safe.

Error messages also contain a stack backtrace, see [UserAssembly](UserAssembly.md).


code:
This directory contains files relevant to the patch development.

Relevant game changes:

1.0.1
	(accidental) 10 day "no-service" period

1.1.0
	"sc stop" & "sc delete" are no longer run on login

1.2.0
	xLua: Introduction of the sb_* check

1.3.0
	xLua: lparser.c is no longer included
	UserAssembly: Modified login function
	UnityPlayer: Random crash on certain systems (patched)

1.3.2
	UnityPlayer: Random crash fixed

1.4.0
	(no relevant changes)

1.5.0
	Patch: Removal of old/unnecessary patches. (checkout c50c174)
	UnityPlayer: "10 second" delayed crash no longer happens
	UnityPlayer: Various runtime and startup crashes

1.5.1
	UnityPlayer: Crashes fixed

1.6.0
	New library: HDiffPatch
	Launcher: Obfuscated web request params
	Removed crash logging of non-crashy events (startup)

1.6.1
	(no relevant changes)

2.0.0
	Crash report directory format changed from "crash_*" to "mihoyocrash_*"

2.1.0
2.2.0
	(no relevant changes)

2.3.0
	Patch: Removal of old/unnecessary patches. (checkout 32d6ee4)
	xLua: sb_* check is not called any more

2.4.0
	New library: mhypbase.dll (more anti-debugger code)
	Introduction of "query_security_file"
	UnityPlayer: "10 second" delayed crash occurs again, but on startup

2.5.0
	Moved library: mhypbase.dll (exists temporarily only)
	New binaries: mhyprot3.Sys (+ garbage), Plugins/crashreport.exe, Plugins/metakeeper.dll
	UnityPlayer: delayed crash is gone again
	Partial use of HDiffPatch for game updates

2.6.0
	(no relevant changes)

2.7.0
	Moved library: mhypbase.dll (exists again permanently)
	Removed libraries: InControlNative.dll, XInputInterface64.dll
	New binary: blueReporter.exe (BSoD reporter)

2.8.0
	Removed libraries: d3dcompiler_43.dll, sqlite3.dll, widevinecdmadapter.dll
	New libraries: MiHoYoMTRSDK.dll, vk_swiftshader.dll, vulkan-1.dll
		-> Vulkan child window rendering breaks certain Wine versions
	Patch: Correction of the computer system information.

3.0.0
	Removed library: metakeeper.dll
	New libraries: kcp.dll
		Astrolabe.dll: telemetry and game logging (unused?, JSON HTTP POST)
		Telemetry.dll: (almost the same library again)

3.1.0
	Removed library: mhyprot2.sys
	Unknown starting time of mhyprot3 -> add to registry regardless
	Patch: Optional analytics server blocking. Removal of unused Unity3D block lists.
	Patch: Secondary patch to reduce CPU usage on kernels with tick rates < 1 kHz

3.2.0
	Patch: Removal of patches 2.1.0 - 3.0.0. (checkout dbfe761)
	(no relevant changes)

3.3.0
	New libraries: mailbox.dll, HoYoKProtect.sys
	Patch process: CE approach broken

3.4.0
	(no relevant changes)

3.5.0
	Optional Kernel driver (?). Needs clarification.
	CN server: device-specific "Data error, please log in again." upon login

3.6.0
	(no relevant changes)

3.7.0
	xlua.dll statically linked into UserAssembly.dll
	xLua: sb_* check is not called any more
	Game is playable patchless after a few days

3.8.0
	Game is playable from day 0 via Wine/Proton/CrossOver

4.0.0
	VRAM leak in menus
	New "BundleDownload" progress logging to the uspider domain
	New "UserBehavior" logging (system specifications)

4.0.1
	Fixed VRAM leak

4.1.0
	Removed mhyprot3.sys
	Patch: Removal of patches 3.1.0 - 3.8.0. (checkout b404916)

4.2.0
	New library: APMLog.dll
	Removed bluereporter.exe

4.3.0
	New library: xxHash (in UserAssembly.dll)
	New file: Managed/Metadata/startup-metadata.dat
		+ Native/Data/Metadata/startup-metadata.dat

4.4.0
	(no relevant changes)

4.5.0
	Launcher: "sophon_chunk" delta patching A/B test

4.6.0
	(no relevant changes)

4.7.0
	2024-06-11: High CPU usage returns due to a new security file (via HTTPS)

4.8.0
	Deprecated "resource" JSON (launcher fade-out)
	UnityPlayer.dll and UserAssembly.dll statically linked into the main game binary
	2024-07-18: "query_security_file" on startup, yet no excessive CPU usage
	2024-07-22: High CPU usage returns due to a new security file
		"*.exe:GMS000000[NNN].log" is generated, "driverError.log" not updated.

5.0.0
	Patch: Removal of directories 4.0.0 - 4.6.0. (checkout f642d34)
	New library: AccountPlatNative.dll (multiple hoyo domains)
		bundles TapTap login webpage (CN), OpenSSL, libcurl
		references to HoYoSDKBridge.dll (N/A on OSRel)
	2024-08-28: "query_security_file" on startup, yet no excessive CPU usage


code:
# Tools

This file lists useful applications to debug and modify the game code.

Helpful articles:

 * https://www.apriorit.com/dev-blog/367-anti-reverse-engineering-protection-techniques-to-use-before-releasing-software
 * https://blog.usejournal.com/reverse-engineering-of-a-mobile-game-part-2-they-updated-we-dumped-memory-27046efdfb85

## General tips before starting

1. Rename or replace "upload_crash.exe", just to make sure
2. Add the logging servers to your /etc/hosts file (see network.md)

## Misc

Small tools that might come handy.

 * vbindiff - Binary difference viewer
 * xdelta3 - Binary patch generator (cross-platform)
    * Make patch: `-e -s ORIG MOD PATCH.vcdiff`
    * Apply patch: `-d -s BAK PATCH.vcdiff MOD`
 * [PE Tools](https://github.com/petoolse/petools/) - File header editor
    * Change and enlarge executable code sections
    * Alternative: Ghidra's "Memory Map" dialogue

## Ghidra

Use: Decompile and patch UnityPlayer.dll, C code preview

Link: https://ghidra-sre.org/

**Hints:**

 * Hotkey "G": Jump to address
 * Hotkey "Ctrl+Shift+G": Patch instruction
     * Add labels to addresses for JMP/LEA autocompletion
 * Export modified dll as PE/Win32
 * Script "EditBytesScript.java": Edit bytes directly, assign a shortcut
 * "Memory Map": Edit PE headers to append code to free spots in/after the file

## Il2CppInspector

Use: decrypted `global-metadata.dat` + `UserAssembly.dll` => debug information

Link: https://github.com/djkaty/Il2CppInspector

**Hints**:

 * GUI does currently not work in Wine
 * `WINEDEBUG=-all wine Il2CppInspector-cli.exe -m global-metadata.dat -i UserAssembly.dll -t Ghidra --unity-version 2017.4.30f1`
 * Requires at least 2.5 GiB free RAM
 * Takes a LOOOONG TIME to execute
    * `Generate C# code: 2'296.42 sec`
 * May be used to import into Ghidra or IDA Pro

### Il2CppDumper (fork)

A fork of the Il2CppInspector subcomponent.

Link: https://github.com/kagurazakasanae/Il2CppDumper-YuanShen

**Hints:**

 * Creates `dump.cs` for manual lookup
    * `VA: 0x18xxxxxxx` is the virtual memory address
 * Fails to generate data for direct Ghidra import

## Cheat Engine (CE)

Use: Set breakpoints, rudimentary backtraces

Link: https://www.cheatengine.org/downloads.php

*Only works partially on Linux!*

*Partially broken as of v3.3.0*

**Required settings:**

  * Edit -> Settings -> Debugger Options
     * Use "VEH Debugger"
     * Use "Page exceptions" (optional, only specifies the defaults)

Optional: copy & paste the x86_64 binary and rename it. That *might* avoid detection.

**"Debug" instructions:**

1. Run GI in suspend mode -> [PowerShell script](https://www.unknowncheats.me/forum/other-mmorpg-and-strategy/418492-genshin-impact-64.html)
    * Linux: use [suspend_start utility exe](suspend_start/)
2. CE: Open process GenshinImpact using "Attach to process"
3. "Memory View"
4. Go to address. (Ctrl+G) -> "UnityPlayer.dll+(7 hex chars ¹)"
5. Set Exception breakpoint
6. When `mhyprot2` is running, suspend_start cannot stop the application any more.
    *  Try [Process Hacker](https://processhacker.sourceforge.io/downloads.php) (as admin) -> "Resume"
7. Hope that the breakpoint works and check the backtrace

¹) The 7 digits correspond to the virtual memory offset, but with the first byte removed. 0x181234567 becomes 0x1234567

## x64dbg

Use: Debug processes, disassebling and memory modifications

Link: https://x64dbg.com/

*Currently does not work in Wine*

**Anti-anti-debug:** (thanks to 0x90, POL thread)

 * Standard PEB check (IsDebuggerPresent() etc)
    * `gs:[60]+2 = 0` (x64 `BeingDebugged` flag)
    * `gs:[60]+bc = 0` (x64 mask `0x70` indicates debugging)
 * CheckRemoteDebuggerPresent
    * `RDX = 0`
    * `RCX = 0`
 * NtQueryInformationProcess -> `RDX = 0x7 // RDX = 0x1e`
 * NtClose -> `RCX = 0xDEADCODE`
 * NtSetInformationThread -> `RDX = 0x11`

Alternatively: [ScyllaHide plugin](https://github.com/x64dbg/ScyllaHide)

 * Even when attaching to a process using the plugin, it is still detected as a debugger. Solutions?

Alternatively: TitanHide (see Issue#7 for binaries)

 * I cannot get this to run. Maybe you can get better results.

## mitmproxy

Use: Capture all TCP/TLS data

Link: https://mitmproxy.org/

**Hints:**

1. Run `mitmdump -w output_file.mitm` (regular user is okay)
2. `export {http,https,ftp}_proxy="http://127.0.0.1:8080"`
    * Windows: Change the network adaptor settings to use your IP as proxy
3. Run Genshin Impact
4. Replay logs: `mitmproxy -nr output_file.mitm`

## dnstop

Use: Capture DNS lookups for packets that mitmproxy cannot catch

1. `dnstop -l 4 NETDEVNAME`
1. Hotkey 4 for deeper domain resolving

## Other attempts

#### Linux CLI

`WINEDEBUG=+relay`

Wine 5.19, UnityPlayer 1.0.1:

	Backtrace:
	=>0 0x000000007b638000 EntryPoint+0x3a0() in kernel32 (0x00000000050cfe58)
	  1 0x00000001808637b8 EntryPoint+0xfeae9208() in unityplayer (0x00000000050cfe58)
	  2 0x000000007b631e09 EntryPoint+0xffffffffffffffff() in kernel32 (0x00000000050cfe58)
	  3 0x000000007bc4b5cf EntryPoint+0xffffffffffffffff() in ntdll (0x00000000050cfe58)
	  4 0x000000007b601b66 EntryPoint+0xffffffffffffffff() in kernel32 (0x0000000000000000)
	  5 0x000000007bc5e9b3 EntryPoint+0xffffffffffffffff() in ntdll (0x0000000000000000)
	0x000000007b638000 EntryPoint+0x3a0 in kernel32: addb	(%rax),%al

`winedbg`

Detected as debugger

`gdb --args wine ...`

Cannot debug due to SIGTRAP being spammed on purpose.

Process stalls when SIGTRAP is ignored:

	handle SIGTRAP nostop
	handle SIGTRAP noprint


code:
# mhyprot2 1.0.1 + 1.1.0

## Meta

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 1362048 bytes (+92168 to 1.0.0)  |
| Modification date | 2020-10-14                       |
| md5sum            | 6b2df08bacf640cc2ac6f20c76af07ee |

## Addresses

Warning: Address is not the same as the byte offset in the binary.

| # | Type     | Address | Description                     |
|---|----------|---------|---------------------------------|
| 1 |          | 0       | Unknown                         |

The mid 95% portion of the file is entirely program code.

## Behaviour

See also: https://github.com/leeza007/evil-mhyprot-cli

What "mhyprot2" registers:

1. PsSetCreateProcessNotifyRoutineEx
2. PsSetLoadImageNotifyRoutine
3. PsSetCreateThreadNotifyRoutine

What "mhyprot2" does:

1. Hides its process handle by ObRegisterCallbacks
2. Observing for csrss.exe injection.
3. Remove the process/thread object from all handle tables.
4. Write logs into `c:\windows\kmlog.log`
    * Example when GI crashes after the warning screen: https://pastebin.com/raw/XQkkZcJE

This service **was** disabled and removed by xLua before showing the login screen.

It no longer appears in 1.1.0 logs, hence the service continues to run after login (proof needed).

	> CALL sb_1184180413 = {
		[1] = {address to CreateProcessA()}
		[2] = 0
		[3] = "sc stop mhyprot2"
		{...}
	}
	< OUT  sb_1184180413 = {
		[1] = 1.0
	}
	> CALL sb_1184180413 = {
		[1] = {address to CreateProcessA()}
		[2] = 0
		[3] = "sc delete mhyprot2"
		{...}
	}
	< OUT  sb_1184180413 = {
		[1] = 1.0
	}


code:
# Network 1.1.0 Analysis

Headings are ordered by stage of the game.

Non-relevant addresses are censored after the second full stop (ex. `static.google.*` (just in case).

Sources:

 * mitmproxy: [1.0.1 Linux vs Windows](https://drive.google.com/file/d/1NRxE6aLqpsRAMOfMbDAgU8KkRzFpgHIR/view?usp=sharing)

### Hosts to block

See `patch.sh` of the current version.

### 1 Launcher

Connection type: entirely TCP / TLSv1.2

DNS requests:

 * `sdk-os-static.mihoyo.*`
 * `log-upload-os.*`
 * `api-static.mihoyo.*` Game update information (trigger by launcher button)
 * `webstatic.*`
 * `genshin.mihoyo.*`

### 2 Startup & login

Connection type: TCP/TLSv1.2 and TCP/HTTP

DNS requests, sorted by appearance:

 * `dispatchosglobal.*` Server listing (required, error 4201)
 * `osasiadispatch.*` Asia server
 * `oseurodispatch.*` Europa server
 * `osusadispatch.*` USA server
 * `webstatic-sea.mihoyo.*` In-game news (optional, deprecated)
 * `webstatic.h*` tbc, Possibly in-game news (optional)
 * `apm-log-upload(-os).*`: Yet unknown (>= 4.2.0)
 * `log-upload(-os).*` Log server (optional, < 4.2.0)

 * `hk4e-sdk-os.h*` Central login and sales server (required)
 * `hk4e-api-os.h*` Announcements, alerts (optional)
 * `(hk4e-)sdk-os(-static).h*` Authentication/login related data
 * `sdk-os-static.h*` Accessed at late game / exit

List of logging domains for general system information: (optional)

 * `ys-log-upload(-os).*` after login (>= 4.0.0)
 * `overseauspider.*` before login
    * To report kernel driver loading errors. No Wine specifics included.
 * `(os)uspider.*` after login (>= 4.2.0)
 * `(sg-)public-data-api.*` before login (< 3.7.0, >= 4.1.0)
 * `sdk-log-upload(-os).*` before login (>= 5.0.0)

Login (captcha) servers:

 * `static.geetest.com` Image-based captcha
 * `api-na.geetest.com` Image-based captcha
 * `status.geotrust.com`
 * `account.h*` Game/special central account server
 * `api-account-os.h*`
 * `abtest-api-data-sg.h*`

In addition to a few unity3d hosts which have no effect when blacklisted in `/etc/hosts`.

#### Driver error log

POST request to `/log` when `mhypbase.dll` is present.

 * Host: `overseauspider.*` or `uspider.*`
 * Data:

______
	{
		"deviceModel": "possibly unique GUID",
		(....)
		"errorCategory":"MHYpBase",
		"logStr":"HoYoDriverInter",
		"stackTrace":"[onInstallDriverError] Status=0Error=0State=0"
	}
______

### 3 Game data loader

Connection type: UDP

Untouched section until it becomes necessary.

* `autopatchhk.yuanshen.*` "Persistent" data updates

### 4 Gameplay

* `autopatchhk.yuanshen.*` Presumably xLua/HotFix patch server
* `minor-api.m*` / `minor-api-os.h*` "apm" reporting (`Telemetry.dll`)
    * Yet unused. Unknown trigger.

### 5 Crash reporter

Connection type: TCP/HTTP

POST request to `/log`:

 * Host: `overseauspider.yuanshen.*` or `uspider.yuanshen.*`
 * Data:

______
	{
	  "userName": "Test",    /* Constant */
	  "time": "YYYY-MM-DD hh:mm:ss.0000",
	  "frame": "",           /* Unclear, perhaps game frame count */
	  "stackTrace": "Log::Logger() ....", /* Partially readable backtrace */
	  "logStr": "[Login] OnPlayerLoginRsp: 31", /* Error 31-4302 or .. */
	  "logStr": "[Login] OnGetPlayerTokenRsp: 21", /* Error 21-4301 aka BANNED */
	  "logType": "Error",
	  "deviceName": "NX",    /* Unclear */
	  "deviceModel": "Wine (The Wine Project)",
	  "operatingSystem": "Windows 10  (10.0...",
	   /* ^ Data from HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion  */
	  "version": "1.0_rel OSRELWin1.0.1_...", /* Game version (bottom left) */
	  "exceptionSerialNum": "0",
	  "pos": "",             /* Unclear, perhaps position on the map */
	  "guid": "sha256 hash",
	  /* ^ Data from HKEY_CURRENT_USER\Software\miHoYoSDK\ MIHOYOSDK_DEVICE_ID */
	  "errorCode": "Default",
	  "errorCodeToPlatform": 4302, /* Error 31-4302 or .. */
	  "errorCodeToPlatform": 4301, /* Error 21-4301 aka BANNED */
	  "serverName": "os_euro"  /* European server */
	}
______

Answer, status 200 OK:

	{
	  "code": 0
	}


code:
### Suspend Start

This application runs an application in suspended mode and allows resuming/suspending afterwards.

Compilers for Linux:

  * Tiny C compiler: https://bellard.org/tcc/
  * winegcc (requires "wine-*-dev" package)

Compiling:

    wine tcc -Wall suspend_start.c

Running:

    wine suspend_start.exe "C:/path/to/GenshinImpact.exe"


code:
#include <stdio.h>
#include <windows.h>

// SuspendThread or ResumeThread
typedef DWORD threadfunc_t(HANDLE);

#if 1 // TinyCC compatibility
	#define TH32CS_SNAPTHREAD 0x00000004

	typedef struct {
		DWORD dwSize;
		DWORD cntUsage;
		DWORD th32ThreadID;
		DWORD th32OwnerProcessID;
		LONG  tpBasePri;
		LONG  tpDeltaPri;
		DWORD dwFlags;
	} THREADENTRY32;
	typedef THREADENTRY32 *LPTHREADENTRY32;

	HANDLE CreateToolhelp32Snapshot(DWORD, DWORD);
	BOOL Thread32First(HANDLE, LPTHREADENTRY32);
	BOOL Thread32Next(HANDLE, LPTHREADENTRY32);
#endif

// https://stackoverflow.com/questions/11010165/how-to-suspend-resume-a-process-in-windows
BOOL ThreadAction(DWORD pid, threadfunc_t action)
{
	BOOL found = FALSE;
	// Ignore Wine warnings
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);

	THREADENTRY32 entry;
	entry.dwSize = sizeof(THREADENTRY32);

	Thread32First(snapshot, &entry);
	do {
		if (entry.th32OwnerProcessID != pid)
		continue;

		found = TRUE;
		HANDLE thread = OpenThread(THREAD_ALL_ACCESS, FALSE,
			entry.th32ThreadID);

		if (action(thread) == -1)
			printf("Action failed. TID=%d, Error=%d\n", thread, GetLastError());

		CloseHandle(thread);
	} while (Thread32Next(snapshot, &entry));

	CloseHandle(snapshot);
	return found; // As long the thread lives
}

int main(int argc, char *argv[])
{
	if (argc < 2) {
		puts("Usage: suspend_start.exe \"C:/path/to/app.exe\" [\"args ...\"]");
		return 1;
	}

	// https://docs.microsoft.com/en-us/windows/win32/procthread/creating-processes
	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	memset(&si, 0, sizeof(si));
	memset(&pi, 0, sizeof(pi));

	BOOL success = CreateProcessA(
		argv[1], // Application name
		argc >= 3 ? argv[2] : NULL,
		NULL, NULL, // Security
		FALSE,
		CREATE_SUSPENDED,
		NULL,
		NULL, // Current directory. Is it needed?
		&si, &pi
	);

	if (!success) {
		puts("Failed to start app. Path not found?");
		return 1;
	}

	printf("Success! Handle=%p, PID=%d, TID=%d\n", pi.hProcess, pi.dwProcessId, pi.dwThreadId);
	for (int i = 0; TRUE; ++i) {
		printf("% 4d | Proc suspended. ENTER to resume\n", i);
		getchar();
		if (!ThreadAction(pi.dwProcessId, ResumeThread))
			break;

		printf("% 4d | Proc resumed. ENTER to suspend\n", i);
		getchar();
		if (!ThreadAction(pi.dwProcessId, SuspendThread))
			break;
	}
	puts("END. Lost process.");
	return 0;
}


code:
Overview of analytics data sent to the known logging servers

The game does also collect some of this data over UDP, however
if you prefer to minimize the footprint, the patch script can
can used to block some of the analytics data.

Linux/Wine-specific

 * Driver initialization error message
 * Crash reports containing "The Wine Project"

Unique identifiers

 * MAC address (first Ethernet adapter)
 * Game-specific system hash ("Open ID")

CPU

 * Core count
 * Frequency
 * Name

GPU

 * Model ID and name
 * Vendor ID and name
 * API version (e.g. "Direct3D 11.0 (level ??.?)")
 * Total VRAM size

Mainboard

 * Model name
 * Vendor name
 * RAM size (/used)

Other

 * OS version (e.g. "Windows 10 (10.0.????) 64bit") (depends on winecfg)
 * System hostname
 * Screen dimensions
 * Storage size (/used)

Known Linux-specific data that is leaked nonetheless (via UDP)

 * The existence of `winevulkan.dll`
 * Invalid file signatures on all system DLLs


code:
# Basic sharpening preset by yagocl
# Hotkey: Insert

# Note: smaa will make in-game text blurry.  If you don't mind losing some crispness
# from the image, remove smaa from here and use the in-game antialiasing.
# In-game SMAA and TAA are really blurry, so make sure to turn up casSharpness to
# something like 0.7
effects = cas:smaa

reshadeTexturePath = "/usr/share/reshade/textures"
reshadeIncludePath = "/usr/share/reshade/shaders"
depthCapture = off

#toggleKey toggles the effects on/off
toggleKey = Home

casSharpness = 0.3
dlsSharpness = 0.2
dlsDenoise = 0.2
smaaThreshold = 0.2
smaaMaxSearchSteps = 8
smaaMaxSearchStepsDiag = 6
smaaCornerRounding = 80


code:
HDiffPatch copy
---------------

Build:    linux64
Version:  4.1.2, commit e9390b7
Checksum: 2f0885c3c0044ed0d860521a60c2a270

Source code: https://github.com/sisong/HDiffPatch/

path: updater/HDiffPatch/README


code:
## Game installation and updating

Pick an application from the list below that suits your preferences.
Each of them is capable of installing and updating the game. Additional features
such as automated patching might or might not be included.

 * The official launcher
     * Note: Wine 8.7 or newer should be used to avoid a memory leak in `winedevice.exe`
     * See [INSTALLATION.md](../INSTALLATION.md) for further instructions.
 * [Paimon Launcher](https://notabug.org/loentar/paimon-launcher)
 * [An Anime Game Launcher](https://github.com/an-anime-team/an-anime-game-launcher)
 * [Yet another anime game launcher](https://github.com/3Shain/yet-another-anime-game-launcher) (macOS)
 * `update_gi.sh` (CLI only, described below)

## Updater implementation in Bash

This section documents the script `update_gi.sh`. The other scripts located in
this directory have a short explanation in their file content.

The following steps are automated:

1. Check for game updates
2. Download the game files
3. Revert any previously applied patches
4. Install or update the game files
5. Apply the newest patch

### Requirements

This script requires following applications:

 * `bash` (update and patch script)
 * `7za` (archive extracting)
 * `jq` (JSON parsing)
 * Either `aria2c`, `wget`, `curl` or `axel` (file download)
 * `xdelta3` (patch script, obsolete)

### Usage instructions

The current working directory (`pwd`) specifies the update or installation path.

Example + syntax:

	cd "/path/to/game/directory/"
	bash "/path/to/dawn/updater/update_gi.sh" [OPTIONS ...]

List of OPTIONS:

 * `--help`: Shows a short help text
 * `install`: Switches from the "update" to "installation" mode
     * By default, an update will be performed in the current directory
 * `nodelete`: Keeps the downloaded archives after the installation or update.
 * `predownload`: Checks and downloads pre-download-game archives
     * To perform the update afterwards, re-run the update script without the `predownload` option.

If errors occur after updating the game files, [re-run the patch scripts manually](../#applying-the-workaround).

#### New installation

Use the `install` command line option to install the newest game version to
an **empty** directory.

Example:

	# Create a new directory in HOME (~) for the installation
	mkdir -p "$HOME/Genshin Impact Game"
	cd "$HOME/Genshin Impact Game/"

	bash "/path/to/dawn/updater/update_gi.sh" install

#### Game update

Updates the game in the working directory to the newest version.

**Important:** If the official launcher was used for the installation, ensure that the
current working directory (`pwd`) contains `GenshinImpact.exe` but not `launcher.exe`.

Example:

	# Update game located in HOME
	cd "$HOME/Genshin Impact Game/"
	bash "/path/to/dawn/updater/update_gi.sh"

For advanced users: `perform_update.sh` can be used to manually apply downloaded archives


code:
#!/usr/bin/env bash

# Utility script to check the game sanity
# As of now, this script does not repair files.
#
# Usage: ./check_integrity.sh FILENAME quick
#    FILENAME : Checksum file e.g. "pkg_version" of the game or voiceover pack
#    "quick"  : Skips md5 checks for more speed but is less reliable

set -e

# ======== Functions

fatal() {
	echo
	for arg in "$@"; do
		echo "  *  $arg" >&2
	done
	echo

	exit 1
}

on_file_mismatch() {
	# 1 = Error Msg, 2 = Filepath
	>&2 echo "$2"
	>&2 echo "    * $1"
}

if [[ $(uname) == "Darwin" || $(uname) == *"BSD" ]]; then
	STATFLAGS="-f %z"
	md5sum() {
		md5 -q $@
	}
else
	STATFLAGS="-c %s"
fi

check_single() {
	# 1 = filepath
	filepath="$1"
	checksum="$2"
	filesize="$3"
	#echo "Testing: $filepath $checksum $filesize"
	if [ ! -e "$filepath" ]; then
		on_file_mismatch "Missing" "$filepath"
		return
	fi

	local size=$(stat $STATFLAGS "$filepath")
	if [ "$size" -ne "$filesize" ]; then
		on_file_mismatch "Size mismatch: $size != $filesize" "$filepath"
		return
	fi

	if [ "$CHECK_MD5" -eq 1 ]; then
		sum=($(md5sum "$filepath"))
		if [ "$sum" != "$checksum" ]; then
			on_file_mismatch "Checksum error: $sum != $checksum" "$filepath"
			return
		fi
	fi
}

# ======== Evaluated variables

MASTER_FILE="$1"
CHECK_MD5=1
JOBS=4

[ ! -e "$MASTER_FILE" ] && fatal \
	"Checksum file $MASTER_FILE not found."

if [ "$2" == "quick" ]; then
	CHECK_MD5=0
	echo "--- Mode: Quick file size checking (fast, less reliable)"
else
	echo "--- Mode: Detailed md5 checking (slow, most reliable)"
fi

echo ""

# This is faster than running "jq" on each line
# outputs a string in form of "Direcotry/File.ext|abc123|10001"
per_line_data=$(jq -r "[.remoteName, .md5, .fileSize] | join(\"|\")" "$MASTER_FILE")

i=0
total=$(echo "$per_line_data" | wc -l)

while IFS='|' read -r filepath checksum filesize; do
	i=$((i + 1))

	while [ $(jobs | wc -l) -gt $JOBS ]; do
		sleep 0.1
	done

	check_single "$filepath" "$checksum" "$filesize" &

	# Log file names every now and then
	if [ $((i % 500)) == 0 ]; then
		percent=$((i * 100 / total))
		echo "--- Progress: ${percent}% (${i} / ${total})"
	fi
done <<< "$per_line_data"

while [ $(jobs | wc -l) -gt 1 ]; do
	sleep 0.1
done

echo ""
echo "==> DONE"

exit 0


code:
#!/usr/bin/env bash

# Read-only utility script to check for leftover binary files from past installations.
# This might be helpful to narrow down possible causes of the error 31-4302.
#
# Usage: ./find_surplus_finaries.sh
#    Execute the script within the game installation directory.

per_line_data=$(jq -r "[.remoteName] | join(\"\")" "pkg_version")
pefiles=$(find . \( -iname '*.exe' -o -iname '*.sys' -o -iname '*.dll' \))

count_total=0
count_bad=0
while read -r filename; do
	filename=${filename##./}
	if [[ ! "$per_line_data" == *"$filename"* ]]; then
		echo "Culprit: $filename"
		count_bad=$((count_bad + 1))
	fi
	count_total=$((count_total + 1))
done <<< "$pefiles"

echo "Done. Checked ${count_total} files. ${count_bad} bad file(s)."


code:
#!/usr/bin/env bash

# Utility script to unzip an archive to $PWD and process HDiffPatch updates
# md5 archive sanity checks must be done by the caller function/application
#
# Usage: ./perform_update.sh "/path/to/archive.zip"

# Exit on error.
set -e

fatal() {
	echo
	for arg in "$@"; do
		echo "  *  $arg" >&2
	done
	echo

	exit 1
}

do_cleanup() {
	# Old patch files
	find . -type f -name "*.hdiff" | while read -r filename; do
		rm "$filename"
	done

	# Prevent deleting of the possibly necessary files in case of full update.
	rm -f "deletefiles.txt"
	rm -f "hdifffiles.txt"
}

# ======== Evaluated variables
THIS_PATH=$(realpath "$(dirname "$0")")
HDIFF_APP="${THIS_PATH}/HDiffPatch/hpatchz"
ZIP_FILE="$1"

# ======== Sanity checks
[ ! -e "config.ini" ] && fatal \
	"Game information file not found."
[ ! -e "$ZIP_FILE" ] && fatal \
	"Archive '${ZIP_FILE}' not found."
chmod +x "$HDIFF_APP"

# ======== Preparation
do_cleanup

# ======== Unzipping
short_name=$(basename "${ZIP_FILE}")
echo "--- Installing ${short_name} ... "

# macOS has a different version of stat
if [ $(uname) = "Darwin" ]; then
	SIZEFLAGS="-f %z"
else
	SIZEFLAGS="-c %s"
fi

# unzip returns status code 1 for empty zip files
if [ $(stat $SIZEFLAGS "${ZIP_FILE}") -lt 42 ]; then
	echo "    Empty zip file. Skipping."
	exit 0
fi
# Overwrite + Progress bar
7za x -aoa -bsp1 -- "${ZIP_FILE}"
echo ""

# ======== *.hdiff files
set +e # to capture "$?"
hdiff_files=$(find . -type f -name "*.hdiff")
while read -r diffname; do
	if [ -z "$diffname" ]; then
		continue
	fi

	realname="${diffname::-6}" # trim ".hdiff"
	if [ -e "$realname" ]; then
		echo "--- Patching file ${realname}"
		output=$("$HDIFF_APP" -f "$realname" "$diffname" "${realname}.tmp_hdiff")
		if [ $? -eq 0 ]; then
			mv -f "${realname}.tmp_hdiff" "$realname"
		else
			echo "$output"
			rm -f "${realname}.tmp_hdiff" # just in case
		fi
	else
		# let the game re-download
		echo "--- [WARNING] HDiff source not found: ${realname}"
	fi
	rm "$diffname"
done <<< "$hdiff_files"
set -e

# ======== deletefiles.txt
if [ -f "deletefiles.txt" ]; then
	while read -r filename; do
		filename=$(echo "${filename}" | tr -d '\r\n')
		# Safety check. File must be within the game directory.
		[ ! -f "${filename}" ] && continue;

		filepath_abs=$(readlink -nf "${PWD}/${filename}")
		case "$filepath_abs" in
			("$PWD"/*)
				echo "--- Removing old file: ${filename}"
				rm -f "$filepath_abs"
				continue
				;;
		esac
		echo "--- [WARNING] Attempt to remove: ${filename}"
	done < "deletefiles.txt"
fi

# ======== Final cleanup
do_cleanup

exit 0


code:
# Generated files
__pycache__/
tmp/
manifest_pb2.py


code:
# Sophon updater

**WARNING: WORK IN PROGRESS. THIS SCRIPT IS CURRENTLY NOT READY FOR PRODUCTION USE**

## Setup

### 1. Python requirements

Python 3.8 or newer is required (`zstandard` library)

    pip install -r requirements.txt

### 2. Generate `manifest_pb2.py`

1. Required system package
	* Ubuntu/Debian: protobuf-compiler
2. Generate
	* `$ protoc --python_out=. manifest.proto`

## Usage

THIS MAY CHANGE AT ANY TIME WITHOUT FURTHER NOTICE

    python updater.py [...]

**Command-line arguments**

	-h : Shows the help dialogue

## Developer notes

See `updaterpy` heading


code:
/*
	Information kindly provided by EternalStudentDesuKa
*/

syntax = "proto3";

message Manifest {
	repeated FileInfo files = 1;
}

message FileInfo {
	string filename = 1; // Path to the file relative to the game directory
	repeated ChunkInfo chunks = 2;
	int32 flags = 3;     // 0 for files, 64 for directories. No other values were ever observed
	int32 size = 4;      // Size of the entire file
	string md5 = 5;      // MD5 checksum of the entire file
}

message ChunkInfo {
	string chunk_id = 1;
	string md5 = 2;               // MD5 checksum of the uncompressed chunk data
	uint64 offset = 3;            // Offset at which this chunk should be put into the resulting file
	uint32 compressed_size = 4;   // Size of the compressed chunk
	uint32 uncompressed_size = 5; // Size of the uncompressed chunk
	uint64 xxhash = 6;            // Xxhash checksum of the compressed chunk data
}


code:
protobuf==3.20.*
zstandard