code:
-- Camera library using the new Transform features in love2d 11.0+
--
-- Copyright © 2019 Pedro Gimeno Fortea
--
-- You can do whatever you want with this software, under the sole condition
-- that this notice and any copyright notices are preserved. It is offered
-- with no warrany, not even implied.

-- Cache some functions into locals
local newTransform = love.math.newTransform
local replaceTransform, applyTransform, push, pop, getWidth, getHeight
local getScissor, intersectScissor, setScissor
local xfSetXf, xfGetMatrix
do
  local lg = love.graphics
  replaceTransform = lg.replaceTransform
  applyTransform = lg.applyTransform
  push = lg.push
  pop = lg.pop
  getWidth = lg.getWidth
  getHeight = lg.getHeight
  getScissor = lg.getScissor
  intersectScissor = lg.intersectScissor
  setScissor = lg.setScissor
  local Xf = debug.getregistry().Transform
  xfSetXf = Xf.setTransformation
  xfGetMatrix = Xf.getMatrix
end

local Camera = {}
local CameraClassMT = {__call = function (c, ...) return c.new(...) end}
local CameraInstanceMT = {__index = Camera}

local function lazyUpdateXf(self)
  if self.dirty then
    self.dirty = false
    local vp = self.vp
    self.matdirty = true
    self.invmatdirty = true
    return xfSetXf(self.xf,
                   vp[1] + (vp[3] or getWidth()) * vp[5],
                   vp[2] + (vp[4] or getHeight()) * vp[6],
                   self.angle, self.zoom, self.zoom, self.x, self.y)
  end
end

local function lazyUpdateMat(self)
  lazyUpdateXf(self)
  if self.matdirty then
    self.matdirty = false
    local mat = self.mat
    local t
    mat[1], mat[2], t, mat[5], mat[3], mat[4], t, mat[6] = xfGetMatrix(self.xf)
  end
end

local function lazyUpdateInvMat(self)
  lazyUpdateMat(self)
  if self.invmatdirty then
    self.invmatdirty = false
    local imat = self.invmat
    local mat = self.mat
    local a11, a12, a21, a22 = mat[1], mat[2], mat[3], mat[4]
    local det = a11*a22 - a12*a21
    imat[1], imat[2], imat[3], imat[4] = a22/det, a12/-det, a21/-det, a11/det
    imat[5] = mat[5]
    imat[6] = mat[6]
  end
end

function Camera:setDirty(dirty)
  self.dirty = dirty ~= false and true or false
end

function Camera:attach(clip)
  lazyUpdateXf(self)
  push()
  local vp = self.vp
  if clip or clip == nil and (vp[1] ~= 0 or vp[2] ~= 0 or vp[3] or vp[4]) then
    local x, y, w, h = getScissor()
    local scissor = self.scissor
    scissor[1] = x
    scissor[2] = y
    scissor[3] = w
    scissor[4] = h
    intersectScissor(vp[1], vp[2], vp[3] or getWidth(), vp[4] or getHeight())
  end
  return replaceTransform(self.xf)
end

function Camera:detach()
  local scissor = self.scissor
  if scissor[1] ~= false then
    setScissor(scissor[1], scissor[2], scissor[3], scissor[4])
    scissor[1] = false
  end
  return pop()
end

function Camera:setPos(x, y)
  self.dirty = self.x ~= x or self.y ~= y or self.dirty
  self.x = x
  self.y = y
end

function Camera:setZoom(zoom)
  self.dirty = self.zoom ~= zoom or self.dirty
  self.zoom = zoom
end

function Camera:setAngle(angle)
  self.dirty = self.angle ~= angle or self.dirty
  self.angle = angle
end

function Camera:setViewport(x, y, w, h, cx, cy)
  x, y = x or 0, y or 0
  w, h = w or false, h or false
  cx, cy = cx or 0.5, cy or 0.5
  if x ~= self.vp[1] or y ~= self.vp[2] or w ~= self.vp[3] or h ~= self.vp[4]
     or cx ~= self.vp[5] or cy ~= self.vp[6]
  then
    self.dirty = true
  end
  local vp = self.vp
  vp[1] = x
  vp[2] = y
  vp[3] = w
  vp[4] = h
  vp[5] = cx
  vp[6] = cy
end

function Camera:toScreen(x, y)
  lazyUpdateMat(self)
  local mat = self.mat
  return mat[1] * x + mat[2] * y + mat[5], mat[3] * x + mat[4] * y + mat[6]
end

function Camera:toWorld(x, y)
  lazyUpdateInvMat(self)
  local imat = self.invmat
  x = x - imat[5]
  y = y - imat[6]
  return imat[1] * x + imat[2] * y, imat[3] * x + imat[4] * y
end

function Camera:getTransform()
  lazyUpdateXf(self)
  return self.xf
end

function Camera:getPos()
  return self.x, self.y
end

function Camera:getX()
  return self.x
end

function Camera:getY()
  return self.y
end

function Camera:getZoom()
  return self.zoom
end

function Camera:getAngle()
  return self.angle
end

function Camera:getViewport()
  local vp = self.vp
  return vp[1], vp[2], vp[3], vp[4], vp[5], vp[6]
end

function Camera:getVPTopLeft()
  local vp = self.vp
  return vp[1], vp[2]
end

function Camera:getVPBottomRight()
  local vp = self.vp
  return vp[1] + (vp[3] or getWidth()), vp[2] + (vp[4] or getHeight())
end

function Camera:getVPFocusPoint()
  local vp = self.vp
  return vp[1] + (vp[3] or getWidth()) * vp[5],
         vp[2] + (vp[4] or getHeight()) * vp[6]
end

function Camera.new(x, y, zoom, angle, vpx, vpy, vpw, vph, cx, cy)
  vpx, vpy = vpx or 0, vpy or 0
  vpw, vph = vpw or false, vph or false
  cx, cy = cx or 0.5, cy or 0.5
  local self = {
    x = x or 0;
    y = y or 0;
    zoom = zoom or 1;
    angle = angle or 0;
    vp = {vpx, vpy, vpw, vph, cx, cy};
    xf = newTransform();
    dirty = true;
    matdirty = true;
    invmatdirty = true;
    scissor = {false,false,false,false};
    mat = {0, 0, 0, 0, 0, 0};
    invmat = {0, 0, 0, 0, 0, 0};
  }
  return setmetatable(self, CameraInstanceMT)
end

return setmetatable(Camera, CameraClassMT)


code:
# No binary files!

*.dll
*.exe
*.sys

# Includes *.bak etc
UnityPlayer.dll.*

# dxvk cache and debug files
*.dxvk-cache
*.log

# version control
*.diff
*.patch

# Script outputs
updater/gi_patch_*

path: .gitignore

license: mit


code:
GAME VERSION 3.1.0 INFORMATION

Refer to the main README.md file for setup instructions.

UnityPlayer.md  : Analysis of UnityPlayer.dll
UserAssembly.md : Analysis of UserAssembly.dll

patch.sh                 : Main game patch script (bash)
patch_anti_logincrash.sh : Additional patch (bash)
patch_revert.sh          : Reverts all patch changes (including old patch data)
patch_files/*            : Files required by the patch script


code:
GAME VERSION 3.2.0 INFORMATION

Refer to the main README.md file for setup instructions.

UnityPlayer.md  : Analysis of UnityPlayer.dll
UserAssembly.md : Analysis of UserAssembly.dll

patch.sh                 : Main game patch script (bash)
patch_anti_logincrash.sh : Additional patch (bash)
patch_revert.sh          : Reverts all patch changes (including old patch data)
patch_files/*            : Files required by the patch script


code:
GAME VERSION 3.3.0 INFORMATION

Refer to the main README.md file for setup instructions.

UnityPlayer.md  : Analysis of UnityPlayer.dll
UserAssembly.md : Analysis of UserAssembly.dll

patch.sh                 : Main game patch script (bash)
patch_anti_logincrash.sh : Additional patch (bash)
patch_revert.sh          : Reverts all patch changes (including old patch data)
patch_files/*            : Files required by the patch script


code:
# UserAssembly 3.3.0

## Resources

 * Yet none

See [1.1.0 UserAssembly](../dev_tools/110_data/UserAssembly.md) for use instructions of pdb/cs files.

## Meta

### OS

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 291812880 bytes (+ 67 MiB)       |
| Modification date | 2022-11-29                       |
| md5sum            | 702671865eba6bd49db2da707cf4b4ef |

### CN

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 291902968 bytes (+ 66 MiB)       |
| Modification date | 2022-11-29                       |
| md5sum            | 3dce9fa8a7874c70575d38c4f839c229 |

## Addresses

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

| Function   | VAddr. OS | VAddr. CN | Description                              |
|------------|-----------|-----------|------------------------------------------|
| login func | 1845d7c80 | 1845dd2b0 | Calls to UnityPlayer [24] indirectly (1) |
| part of ^  | 1845d8101 | 1845dd737 | Validation call #1 (2)                   |
| part of ^  | 1845d8141 | 1845dd777 | Validation call #2 (2)                   |

Detailed explanation:

**1:** See 1.1.0 backtrace log

**2:** Format:

	ptr[RAX] + 0x10 = 0x00
	ptr[RAX] + 0x18 = string length
	ptr[RAX] + 0x20 = UTF-8 string (`\0` terminated)


code:
GAME VERSION 3.4.0 INFORMATION

Refer to the main README.md file for setup instructions.

UnityPlayer.md  : Analysis of UnityPlayer.dll
UserAssembly.md : Analysis of UserAssembly.dll

patch.sh                 : Main game patch script (bash)
patch_anti_logincrash.sh : Additional patch (bash)
patch_revert.sh          : Reverts all patch changes (including old patch data)
patch_files/*            : Files required by the patch script


code:
GAME VERSION 3.5.0 INFORMATION

Refer to the main README.md file for setup instructions.

UnityPlayer.md  : Analysis of UnityPlayer.dll
UserAssembly.md : Analysis of UserAssembly.dll

patch.sh                 : Main game patch script (bash)
patch_anti_logincrash.sh : Additional patch (bash)
patch_revert.sh          : Reverts all patch changes (including old patch data)
patch_files/*            : Files required by the patch script


code:
# UserAssembly 3.5.0

## Resources

 * Yet none

See [1.1.0 UserAssembly](../dev_tools/110_data/UserAssembly.md) for use instructions of pdb/cs files.

## Meta

### OS

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 286048784 bytes                  |
| Modification date | 2023-02-21                       |
| md5sum            | db4b2ba49753be4833c481e8b701f040 |

### CN

| Type              | Value                            |
|-------------------|----------------------------------|
| Size              | 286683128 bytes                  |
| Modification date | 2023-02-21                       |
| md5sum            | 2a047c49ea9e6f817208dcc1cddc41fc |

## Addresses

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

| Function    | VAddr. OS | VAddr. CN | Description                              |
|-------------|-----------|-----------|------------------------------------------|
| login func  | 181bc5f60 | 181bf31f0 | Calls to UnityPlayer [24] indirectly (1) |
| called by ^ | 187b69060 | 187c318d0 | Validation call func                     |

Detailed explanation:

**1:** See 1.1.0 backtrace log


code:
#!/usr/bin/env bash

echo "[WARNING] File path changed. This file will be removed in 3.6.0. Redirecting ..."

DIR=$(dirname "${BASH_SOURCE[0]}")
bash "$DIR/../compat/macos_cpu_skinning.sh"


code:
#!/usr/bin/env bash

echo "Please use the newest revert script."
echo "It will also work on older patch installations."

exit 1


code:
GAME VERSION 3.6.0 INFORMATION

Refer to the main README.md file for setup instructions.

UnityPlayer.md  : Analysis of UnityPlayer.dll
UserAssembly.md : Analysis of UserAssembly.dll

patch.sh                 : Main game patch script (bash)
patch_anti_logincrash.sh : Additional patch (bash)
patch_revert.sh          : Reverts all patch changes (including old patch data)
patch_files/*            : Files required by the patch script


code:
#!/usr/bin/env bash

# DESCRIPTION
#     This is the main patch script to ensure basic game functionality in Wine.
#
# EXIT STATUS
#     0      : The patch was applied successfully.
#     other  : Patch failure. See stdout or stderr output for details.

# Templates for the next patch testing phase
echo " === !! UNTESTED PATCH. CHECK FOR BANS USING A TRASH ACCOUNT !! ==="
echo " ===      REPORT RESULTS TO THE MAIN REPOSITORY. THANK YOU.     ==="
echo ""
echo "If you would like to test this patch, modify this script and remove the line below this one."
exit 1

# 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]}")
DATADIR=$(find . -maxdepth 1 -type d -name "*_Data")
FILE="UnityPlayer.dll"
CEXE1="$DATADIR/upload_crash.exe"
CEXE2="$DATADIR/Plugins/crashreport.exe"
VULKAN1="$DATADIR/Plugins/vulkan-1.dll"
sum=($(md5sum $FILE))
reltype="" # os, cn, bb
block_analytics=1

# original hashes
if [ "${sum}" == "f5e5b679707541a18f986f6808665736" ]; then
	reltype="os"
	echo "--- Applying for: International version"
fi
if [ "${sum}" == "99524118e297b7ae642eeeb176ed9d60" ]; then
	if [ -e "$DATADIR/Plugins/PCGameSDK.dll" ]; then
		reltype="bb"
		echo "--- Applying for: bilibili CN version"
	else
		reltype="cn"
		echo "--- Applying for: miHoYo CN version"
	fi
fi
if [ -z "$reltype" ]; 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

# =========== DO NOT REMOVE START ===========
if [[ -e "$DIR/$FILE" ]]; then
	# There is a good reason for this check. Do not pollute the game directory.
	echo "[ERROR] Invalid patch download directory. Please move all"
	echo "        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 "[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 ""
echo "[WARNING] Hereby you are violating the game's Terms of Service!"
echo "          Do you accept the risk and possible consequences?"
echo "          Use Ctrl+C to abort this script if you are not sure."
read -p "Accept? [y/N] " choice

if [[ ! "$choice" == [JjSsYy]* ]]; then
	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 3.6.0)
# Note: overseauspider is unused in 2.8.0-3.3.0 and 3.6.0
if [[ "$reltype" == "os" ]]; then
	servers=$(cat <<EOF
# Genshin logging servers (do not remove!)
0.0.0.0 sg-public-data-api.hoyoverse.com
0.0.0.0 log-upload-os.hoyoverse.com
0.0.0.0 overseauspider.yuanshen.com

EOF
	)
else
	servers=$(cat <<EOF
# Genshin logging servers (do not remove!)
0.0.0.0 public-data-api.mihoyo.com
0.0.0.0 log-upload.mihoyo.com
0.0.0.0 uspider.yuanshen.com

EOF
	)
fi

if [[ ! "$etc_hosts" == *"$servers"* ]]; then
	echo "[Optional] Block analytics domains via /etc/hosts"
	echo "           The game collects uniquely identifiable information about your system."
	echo "           For details, refer to the official privacy page or the file"
	echo "           '../static/analytics_data.txt' contained in this repository."
	echo "$servers"
	read -r -p "Would you like to block the analytics servers above? [Y/n]: " choice
	if [[ ! "$choice" == [Nn0]* ]]; then
		echo "-- Adding analytics servers"
		echo "$servers" | sudo tee -a /etc/hosts
		if [ $? -ne 0 ]; then
			read -p "--- Failed. Please edit /etc/hosts manually. Enter to continue."
		fi
	else
		block_analytics=0
	fi
else
	echo "--- Analytics servers are already blocked. Skip."
fi

etc_hosts=""
# END OF SUDO DANGER ZONE

echo ""

# No crashes shall be reported!
echo "--- Renaming the crash reporter(s)"

if [ -e "$CEXE1" ]; then
	# Replace existing backups
	mv -f "$CEXE1" "$CEXE1.bak"
fi
if [ -e "$CEXE2" ]; then
	mv -f "$CEXE2" "$CEXE2.bak"
fi
if [ -e "$VULKAN1" ]; then
	echo "--- Workaround for Wine bug 45277"
	mv -f "$VULKAN1" "$VULKAN1.bak"
fi

# Registry entry to add on startup
cp -f "$DIR/patch_files/mhyprot2_running.reg" .

echo "--- Adding launcher script"
cp -f "$DIR/patch_files/launcher.bat" .
if [ "$block_analytics" -eq 0 ]; then
	# Remove the lines related to domain checking
	sed -i "/REM DOMAIN_CHECK_BEGIN/,/REM DOMAIN_CHECK_END/d" "launcher.bat"
fi
if [[ "$reltype" != "os" ]]; then
	# Same thing but different
	sed -i "s/GenshinImpact/YuanShen/g" "launcher.bat"
	sed -i "s/sg-public-data-api.hoyoverse/public-data-api.mihoyo/g" "launcher.bat"
	sed -i "s/log-upload-os.hoyoverse/log-upload.mihoyo/g" "launcher.bat"
	sed -i "s/overseauspider.yuanshen/uspider.yuanshen/g" "launcher.bat"
fi

# 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_${reltype}.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


code:
#!/usr/bin/env bash

# DESCRIPTION
#     This script is called as-is and included with every patch update for historical
#     and compatibility reasons. As of version 3.2.0 this patch is optional. It reduces
#     the CPU usage on kernels with timer frequencies lower than 1000 Hz.
#
# EXIT STATUS
#     0      : The patch was applied successfully or is not needed for this game version.
#     other  : Patch failure. See stdout or stderr output for details.

# Templates for the next patch testing phase
echo "          This is an OPTIONAL patch to reduce CPU usage by disabling mhypbase.dll."
echo "[WARNING]       !! UNTESTED PATCH. CHECK FOR BANS USING A TRASH ACCOUNT !!"
echo ""
echo "If you would like to test this patch, modify this script and remove the line below this one."
exit 0

# 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]}")
DATADIR=$(find . -maxdepth 1 -type d -name "*_Data")
FILE="$DATADIR/Plugins/xlua.dll"
sum=($(md5sum $FILE))
reltype=""

# original hashes
if [ "${sum}" == "a756712e4518f6d193afa475ff083076" ]; then
	reltype="os"
	echo "--- Applying for: International (OS) version"
fi
if [ "${sum}" == "2fc3256dbf25ee5d4f59ed553111e072" ]; then
	reltype="cn"
	echo "--- Applying for: Chinese (CN) version"
fi
if [ -z "$reltype" ]; 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

# =========== DO NOT REMOVE START ===========
if [[ -e "$DIR/$FILE" ]]; then
	# There is a good reason for this check. Do not pollute the game directory.
	echo "[ERROR] Invalid patch download directory. Please move all"
	echo "        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 "[ERROR] xdelta3 application is required"
	exit 1
fi

#echo "[INFO]    Patch to fix a login and runtime crash"

# ===========================================================
echo ""
echo "[WARNING] Hereby you are violating the game's Terms of Service!"
echo "          Do you accept the risk and possible consequences?"
echo "          Use Ctrl+C to abort this script if you are not sure."
read -p "Accept? [y/N] " choice

if [[ ! "$choice" == [JjSsYy]* ]]; then
	exit 1
fi

echo
echo "--- Patching xLua"
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_${reltype}.vcdiff" "$FILE" || xdelta_fail

# Disable by renaming
echo "--- Disabling mhypbase"
mv -f "mhypbase.dll" "mhypbase.dll.bak"

# Done!
echo "==> Patch applied! Enjoy the game."
exit 0


code:
@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 ============

REM DOMAIN_CHECK_BEGIN
SET perr1=1
SET perr2=1
SET perr3=1
SET perr=0

setlocal EnableDelayedExpansion
FOR /f "delims=" %%i IN ('ping -n 1 -w 1 log-upload-os.hoyoverse.com') DO (
	echo %%i | find "[0.0.0.0]" >nul
	IF !ERRORLEVEL! EQU 0 SET "perr1=0"
	echo %%i | find "could not find host" >nul
	IF !ERRORLEVEL! EQU 0 SET "perr1=0"
)
FOR /f "delims=" %%i IN ('ping -n 1 -w 1 sg-public-data-api.hoyoverse.com') DO (
	echo %%i | find "[0.0.0.0]" >nul
	IF !ERRORLEVEL! EQU 0 SET "perr2=0"
	echo %%i | find "could not find host" >nul
	IF !ERRORLEVEL! EQU 0 SET "perr2=0"
)
FOR /f "delims=" %%i IN ('ping -n 1 -w 1 overseauspider.yuanshen.com') DO (
	echo %%i | find "[0.0.0.0]" >nul
	IF !ERRORLEVEL! EQU 0 SET "perr3=0"
	echo %%i | find "could not find host" >nul
	IF !ERRORLEVEL! EQU 0 SET "perr3=0"
)

REM There's no OR operator for "IF"
IF %perr1% EQU 1 SET perr=1
IF %perr2% EQU 1 SET perr=1
IF %perr3% EQU 1 SET perr=1

IF %perr% NEQ 0 (
	REM Show the message to the user
	echo ERROR: You opted to block the analytics servers but they are reachable. Please re-run the patch script. >_error.txt
	notepad _error.txt
	del _error.txt
	exit
)
REM DOMAIN_CHECK_END

REM Try to emulate the game behaviour
copy mhyprot3.sys "%TEMP%\"
copy HoYoKProtect.sys "%WINDIR%\system32\"
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"
)
IF EXIST GenshinImpact_Data\Plugins\crashreport.exe (
	move "GenshinImpact_Data\Plugins\crashreport.exe" "GenshinImpact_Data\Plugins\crashreport.exe.bak"
)

REM ============= Launch the game =============
REM https://docs.unity3d.com/Manual/PlayerCommandLineArguments.html
REM Append the arguments to the command: launcher.bat arg1 arg2 ...

start GenshinImpact.exe %*


code:
#!/usr/bin/env bash

ANCHOR=""
DATADIR=$(find -maxdepth 1 -type d -name "*_Data")

if [ -e "GenshinImpact.exe" ]; then
	ANCHOR="GenshinImpact.exe"
fi
if [ -e "YuanShen.exe" ]; then
	ANCHOR="YuanShen.exe"
fi
if [ -z "$ANCHOR" ]; then
	echo "==> Game executable not found. Wrong directory?"
	exit 1
fi

# Restore files that have a backup
FILE="UnityPlayer.dll"
CEXE1="$DATADIR/upload_crash.exe"
CEXE2="$DATADIR/Plugins/crashreport.exe"
VULKAN1="$DATADIR/Plugins/vulkan-1.dll"
XLUA="$DATADIR/Plugins/xlua.dll"
GGM="$DATADIR/globalgamemanagers"

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

# Reference timestamp to avoid restoring old/invalid backups
ref_timestamp=($(stat $STATFLAGS "$ANCHOR"))

restore_file() {
	# $1 -> File name
	# $2 -> Human readable description
	# $3 -> Overwrite existing file?

	if [ ! -e "$1.bak" ]; then
		echo "--- Nothing to restore for '$1' (no .bak file)"
		return 0
	fi

	if [ -e "$1" -a "$3" != "overwrite" ]; then
		echo "--- $2 is already restored"
		return 0
	fi

	# Do not restore backups from old game versions
	difftime=$(( $ref_timestamp - $(stat $STATFLAGS "$1.bak") ))
	# Strip negative sign is equal to abs()
	if [ ${difftime#-} -gt 3600 ]; then
		echo "--- Backup '$1.bak' is older than the current game version. Ignoring."
		return 1
	fi

	# Restore from backup
	mv -f "$1.bak" "$1"
	echo "--- Restored: $2"
	return 0
}

restore_file "$FILE" "Main patch" overwrite
restore_file "$VULKAN1" "Workaround for Wine bug 45277"
restore_file "$CEXE1" "Crash reporter 1"
restore_file "$CEXE2" "Crash reporter 2"
restore_file "mhypbase.dll" "'Blackbox' DLL"
restore_file "$XLUA" "Anti-logincrash patch" overwrite
restore_file "$GGM" "macOS rendering issue patch" overwrite

echo
echo "--> Removing all newly added files"
# The error messages for inexistent files are intended
rm "launcher.bat"
rm "mhyprot2_running.reg"

# dxvk files
rm *.dxvk-cache
rm *_d3d9.log
rm *_d3d11.log
rm *_dxgi.log

echo "==> Patch reverted."
exit 0


code:
## Credits

Original research: https://www.playonlinux.com/en/app-4228.html

*If you are on this list but do not agree with the license, please open an issue or contact me directly.*

List ordered by first contribution in the project.

User Krock ([PlayOnLinux](https://www.playonlinux.com/en/profil-95230.html), NotABug)

 * Initial Ghidra experiments, self-declared project leader

User timbuntu ([PlayOnLinux](https://www.playonlinux.com/de/profil-95714.html), NotABug)

 * First success on version 1.0.1
 * MITM logs

User geearf2 (Freenode IRC)

 * Providing game data from 25 Oct

User SeppNel ([PlayOnLinux](https://www.playonlinux.com/en/profil-95643.html), NotABug)

 * Windows/Linux comparisons on the same system
 * Network and xLua logs
 * Hash information from a working system

User 0x90 ([PlayOnLinux](https://www.playonlinux.com/en/profil-96196.html))

 * Research about in-memory modifications
 * x64dbg instructions

User Th1nkCh3ck (NotABug)

 * General information research

User humanik12 (unknowncheats)

 * Damn, you dude rock. I almost gave up, but you gave me the final hint and motivation.

User Makksim (NotABug)

 * Summary of the mhyprot2 service behaviour

User tiagop (NotABug, Email)

 * Information collecting about Wine projects

User Kowalski (NotABug)

 * .pdb symbols file

User WerWolv (Discord)

 * Assistance understanding the WinAPI and internals

Various (unknowncheats.me)

 * General game information

User loentar (NotABug)

 * Game updater and patch script

User yagocl (NotABug)

 * Documentation improvements and new instructions

User y0soro (NotABug)

 * Patch for the Chinese game version

User 3Shain (NotABug)

* Investigating macOS support.


code:
# Frequently Asked Questions

Q: Can I get banned if I use this patch?
A: Yes because this is a client modification. However, since the first patch in
December 2020 no bans in relation to this patch were reported.

Q: Why is this project rather difficult to find?
A: Imagine what the game developers could do if they figured out that this patch
circumvents their rootkit service in order to reach Linux compatibility.
To keep the patch working, it is highly recommended to not share this project in public,
despite its MIT license. It is for your own good.

Q: How quickly do patches get released?
A: Usually, the first testing patch is proposed within a day after the official game update
which happens on Wednesday (UTC). To check for issues, the patch is tested until Saturday,
after which the script is updated for normal use.

Q: Where can I use this patch?
A: On GNU/Linux distributions, but it *may* also work on other systems which run Wine.
Windows does not need this patch and is not supported for obvious reasons.

Q: Does the patch work on macOS?
A: Yes, at least since Ventura 13.1, Wine 7.7 (CrossOver) and game version 3.4.0.
Please follow [INSTALLATION.md](INSTALLATION.md) to fix many rendering issues.
Note: the patch script compatibility is currently work in progress.

Q: How can I analyse my gacha wishes?
A: Obtain the URL from the CEF cache.

 1. Open the in-game wish history (table view)
 2. Run `strings *_Data/webCaches/Cache/Cache_Data/data_2 | grep -o "https://.*/e20190909gacha-v2/.*" | tail -n 1`
    from the game installation directory
 3. Copy the URL for use on websites like paimon.moe / genshin-wishes.com / etc.

Q: How do I skip the download of unused voice-over packs?
A: Either remove them in your game settings, or:

 1. Locate the file `audio_lang_*` (where `*` stands for the newest) inside your game data files
 2. Remove the unwanted pack lines (except maybe `English(US)`?)
 3. Save
 4. Navigate to `StreamingAssets/Audio/GeneratedSoundBanks/Windows/`
 5. Remove the pack directories that are no longer contained within `audio_lang_*`
 6. Proceed to download the other game data archives

Q: Where is `output_log.txt`?
A: `WINEPREFIX/drive_c/USERNAME/AppData/LocalLow/miHoYo/Genshin Impact/` where WINEPREFIX
depends on the Wine setup/configuration.

Q: Where can I find crash information?
A: A `crash.dmp` minidump and `error.log` file are saved to `WINEPREFIX/drive_c/USERNAME/Temp/mihoyocrash_*`.
Former can partially be analysed using `winedbg` or `windbg` depending on the progress of Wine.
See also: [TROUBLESHOOTING.md](TROUBLESHOOTING.md#how-to-report-issues)

Q: Where is `WINEPREFIX`?

 * System-wide Wine installation: `~/.wine`
 * Lutris: `~/Games`
 * Steam: in `steamapps`, usually `~/.steam/steam/steamapps/compatdata/ANYNUMBER`


code:
# Game installation instructions

Minimal requirements:

 * Any installation of `wine` >= 5.3 (sooner or later)
 * MS core fonts
     * Ubuntu/Debian: install `ttf-mscorefonts-installer`
     * Arch/Manjaro: install `ttf-ms-fonts`
     * Alternatively: winetricks `corefonts` verb (after wineprefix setup)

Highly recommended:

 * Vulkan-capable graphics card (["How to check?"](TROUBLESHOOTING.md#graphics-bugsissues))

### Table of contents

* [Lutris](#lutris)
* [Steam](#steam)
* [SteamOS](#steamos)
* [Custom](#custom)
* [macOS instructions](#macos-instructions)
* [Bilibili](#bilibili)
* [Controller Configuration](#controller-configuration)

#### Lutris

1. Download the Windows installer from the official site
2. Add the installer binary to your library
3. Set up a wineprefix for the game
    * This is where the game will be installed. 40+ GiB of free space is highly recommended.
    * Grab a recent Wine runner. See [TROUBLESHOOTING](TROUBLESHOOTING.md) for problematic versions
4. Install the components the game needs to run flawlessly
    * Enable DXVK in `Configuration` -> `Runner options` (1.7.3 or newer is recommended)
    * Navigate to `Configuration -> Runner options` -> `DLL overrides` (table) and add the
      entry `avcodec-58.dll` with value `d`. This avoids crashes (see Issue #339)
5. Launch the downloaded installer .exe
    * Use the `Run EXE inside wine prefix` menu action for this.
    * The C++ Redistributable Package is optional. You may cancel it.
    * Download and install the game files.
    * **Once it is done, do not press launch.** Exit the launcher.
6. Apply the patch script: ["how?"](README.md)
7. Change the executable path. `Configuration` -> `Game options`
    * Executable: `launcher.bat`
    * Working directory: select the directory where `GenshinImpact.exe` resides
8. Launch the game

**Important note:**

After setup you might have multiple Wine versions and multiple WINEPREFIX directories
on your system. Hence running the `wine` command from your terminal will use another
environment than Lutris does.

To open a command prompt which uses the correct environment, do either:

 * Games -> Wine options (see bottom status bar or left side) -> `Wine console`
 * Change the `Executable` path to `cmd.exe`

#### Steam

1. Download the official launcher
2. "Add non-Steam game..." -> Browse -> Show all files -> Select the installer executable -> Done
3. Setup proton (if not done using global settings)
    * Navigate: Gear icon -> "Settings" -> "Compatibility"
    * Check "Force compatibility layer ..."
    * Select a recent Proton version
4. Install the launcher and start it
    * The C++ Redistributable Package is optional. You may cancel it.
    * Download and install the game files.
5. Apply the patch script: ["how?"](README.md)
6. Update the target. Gear icon -> "Settings":
    * Target: `explorer.exe`
    * Execution directory: the directory where `GenshinImpact.exe` resides
    * Start options: `%command% /desktop=anyname,1920x1080 cmd /c launcher.bat`
    * Adjust the screen resolution above, if necessary.
7. Play.
    * For CN version + Steam Deck: you might need to [add environment variables](TROUBLESHOOTING.md#game-crashes-on-launch) to start the game.

#### SteamOS

This section is based on the Steam instructions above.

1. The patches may modify `/etc/hosts` which is not writable by default.
     * Option 1: Use `sudo steamos-readonly disable` before running the main patch
       script and make the file system readonly again after completion: `sudo steamos-readonly enable`
         * Note: The changes done by the script might be undone by system updates.
     * Option 2: Allow the analytics domains in the patch script. Refer to [static/analytics_summary.txt](static/analytics_summary.txt)
       for an overview of the collected data.
     * Option 3: Use a semi-isolated container to avoid this problem such as Flatpak.
       For example, the third party launcher "An Anime Game Launcher"
       (see [updater/README.md](updater/README.md) for links) offers such package.
2. For Chinese/Japanese players: (to fix [startup crashes](TROUBLESHOOTING.md#game-crashes-on-launch))
     1. Run the script `compat/steamos_CJ_locale_enabler.sh` to generate the necessary locale
     2. Configure `LC_ALL` as described in [TROUBLESHOOTING.md](TROUBLESHOOTING.md#game-crashes-on-launch)

#### Custom

Script-based approach to use any Wine version on any WINEPREFIX.
If you do not understand what each step is supposed to do, use Lutris instead.

For the final game launch script after the prefix setup, use steps 1, 2 and 6.

	# 1. Specify the path to wine(64)
	#    This can be either system-wide or a custom installation
	WINE="wine64"
	#WINE="/path/to/custom/wine/build/bin/wine64"

	# 2. Specify a WINEPREFIX
	export WINEPREFIX="/absolute/path/to/.prefix/"

	# 3. Create or update WINEPREFIX
	"$WINE" wineboot -u

	# 4. Install DXVK (v1.9.4, for Wine 5.14+)
	#    Use the newest Winetricks script from GitHub
	export WINE
	sh winetricks dxvk194

	# 5. Install the game (if not already done)
	"$WINE" "/path/to/installer.exe"

	# 6. Game launch
	#    Using a virtual desktop with a size of 1920x1080 pixels
	cd "/path/to/Genshin Impact Game"
	export WINEESYNC=1  # requires staging or Proton, see TWEAKS.md
	"$WINE" explorer /desktop=anyname,1920x1080 cmd /c launcher.bat

	# 7. Game update
	#    See `updater/README.md` or attempt to use the official launcher:
	"$WINE" "/path/to/official/launcher.exe"

#### macOS instructions

It's highly recommended to use CrossOver using a recent [DXVK-macOS](https://github.com/Gcenx/DXVK-macOS) version.

 * Note: Confirmed working with DXVK-macOS 1.10.3-47.

MoltenVK does yet not support `VK_EXT_transform_feedback` (see issue #374), which can be
worked around by the following patch. Check the script contents for details.

    bash "/path/to/dawn/compat/macos_cpu_skinning.sh"

To fix further rendering issues on low-end Macs, open or create the file `dxvk.conf` in the game
directory and add the following line: (requires a working DXVK installation)

    dxgi.customDeviceDesc = "AMD Radeon Pro 5300M"

 * Note: CrossOver might come with an old DXVK version which does not handle this option.
 * Note: Setting the device ID and vendor ID does not have any effect.

Confirm whether the changes are in effect:

1. Start the game
2. Open the `*_dxgi.log` file in the game directory
2. The line starting containing `DXVK:` must mention a recent version (e.g. 1.10.3)
3. The line below `Effective configuration:` must mention the GPU specified in `dxvk.conf`.
4. Visual test: compare the in-game graphics

#### Bilibili

**Chinese**

(feel free to translate / 随意翻译)

**English**

Wine Gecko 2.47.2 (and older) cannot render the in-game Bilibili login page.
Whereas the game comes with the Chromium Embedded Framework (CEF), the Bilibili
SDK does not make use of it. Instead it relies on the Internet Explorer libraries.

Known workaround: Check the "Links" section below.

Note: That project is not directly supported by the patch. Please report issues
and questions to its dedicated page.

**Links / 网页链接**

 * Workaround: https://github.com/QiE2035/gs_bili

#### Controller Configuration

*This section should not be documented in this repository.
If you know of a better public place for documentation, please open an issue
so that this information is available to more people.*

Only follow these instructions if the newest Wine version does not already support your controller.

##### Dualsense

*Source: lahvuun, Issue #216*

1. Open `regedit` in your WINEPREFIX
2. Navigate to `HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\winebus`
3. Create a new DWORD, value `0`, named `Enable SDL`
4. If there is yet no success: check the udev rule section below

Caveats: No force feedback or haptics (vibrations)

##### Other

*Source: Alex72, Issue #228*

General idea: specify the environment variable `SDL_GAMECONTROLLERCONFIG=?????`.

Helpful resources to determine the value (`?????`):

 * For permission-related issues: check the udev rule section below
 * General mapping information: [SDL_GameControllerDB](https://github.com/gabomdq/SDL_GameControllerDB)
 * [SDL2 controller test tool](https://github.com/libsdl-org/SDL/blob/main/test/controllermap.c)
    * Required packages: build tools and SDL2
       * Debian/Ubuntu: `libsdl2-dev`
    * Compile with `gcc -o controllermap controllermap.c $(sdl2-config --libs --cflags)`
    * If compiling fails, either:
       * Install a newer SDL2 library
       * or download an older `controllermap.c` file which matches your installed version
 * [SDL2 Gamepad Mapper](https://gitlab.com/ryochan7/sdl2-gamepad-mapper)
 * [AntiMicroX](https://github.com/AntiMicroX/antimicrox)

##### udev rule configuration

Some specific controllers might lack read permission.

 * If [game-devices-udev](https://gitlab.com/fabiscafe/game-devices-udev) lists your controller, install it.
    * Run `udevadm control --reload-rules` or reboot to apply the changes
 * Arch Wiki instructions for other controllers: [Gamepad](https://wiki.archlinux.org/title/Gamepad)

Maybe helpful: `wine control.exe` shows a simple controller/gamepad testing application.


code:
## Game Status v3.6.0

Scroll down for the setup instructions.

<!-- ![Game is playable!](static/LOGO-IF-WORKING.jpg) -->
![Work in progress](static/LOGO-IF-WIP.jpg)

**Supported versions:** International, China (channel 1 and 14)

### Explanation

`mhyprot2.sys` is a kernel service which is and will not be supported by Wine. Problem: it's used as cheat prevention.

**Available solutions:**

 * Wine + patched game (what this project does)
 * Dual-boot to Windows
 * [Use Hyper-V in a Windows VM](https://youtu.be/L1JCCdo1bG4?t=191)
 * Play another game. Format: link, caveats (Proton/Wine rating)
    * Blue Protocol, unreleased, 2023 (N/A)
    * Wuthering Waves, unreleased, 20?? (N/A)
    * [Scarlet Nexus](https://store.steampowered.com/app/775500/SCARLET_NEXUS/), singleplayer (Platinum)
    * [Little Witch Nobeta](https://store.steampowered.com/app/1049890/Little_Witch_Nobeta/) singleplayer (Gold)
    * [Ashen](https://store.steampowered.com/app/649950/Ashen/) (Platinum)
    * [Tower Hunter: Erza's Trial](https://store.steampowered.com/app/844850/Tower_Hunter_Erzas_Trial/) singleplayer, 2D scroller (Platinum)
    * [Haven](https://www.gog.com/game/haven) PEGI 18 (Gold)
    * [Honkai Impact 3rd](https://github.com/an-anime-team/honkers-launcher/releases/latest) (N/A)
    * [Pine](https://www.gog.com/game/pine) no story, singleplayer (Native)
    * Tower of Fantasy (Broken)

### Project rules

 1. miHoYo reserves the right to distribute files. Please do not share any game data in public.
 2. For your own sake: **Please do not share this project in public**.
    * Reduces the risk of this project to be taken down or used against our reverse-engineering efforts
    * Solution: Use indirect/redirect links and private messages
 3. Please do not abuse this project for cheating. We just want to play the game.

For project contributors: Beware that your log files may contain personal information, such as MAC addresses or login data.

#### Applying the workaround

See also: **[Full setup instructions](INSTALLATION.md)** (Lutris, Steam, macOS, custom)

You will need Wine 5.3 or newer. [DXVK](TROUBLESHOOTING.md#graphics-bugsissues) is highly recommended.

Follow the script as instructed. Backups (.bak) are made automatically where needed.
`GAMEVER` stands for the game version, i.e. `3.2.0` becomes `320`.

	# Download the repository (or use the download button)
	git clone https://notabug.org/Krock/dawn --depth 1

	# Tip: Drag&drop the desired directory or file into the terminal to copy its path

	cd "/path/to/Genshin Impact Game"
	bash "/path/to/dawn/GAMEVER/patch.sh"
	# Despite its name, this second patch improves the game performance:
	bash "/path/to/dawn/GAMEVER/patch_anti_logincrash.sh"

	# For macOS only! Fixes model rendering issues
	#bash "/path/to/dawn/compat/macos_cpu_skinning.sh"

	# Please run "launcher.bat" to start the game
	wine cmd /c launcher.bat

**Undo:** The patch can be reverted using `patch_revert.sh` in the same manner.

### [Troubleshooting](TROUBLESHOOTING.md)

Please **do not report any** game issues to an official channel. Your options are:

 * [Troubleshooting](TROUBLESHOOTING.md) page for common issues and solutions
 * Create a [new issue](https://notabug.org/Krock/dawn/issues) here. See also: [closed/solved issues](https://notabug.org/Krock/dawn/issues?state=closed&labels=2029)
 * Post your problem on a Wine/dxvk-specific page

### [Frequently Asked Questions](FAQ.md)

### [Game updater & patch](updater/)

### [Performance & visual tweaks](TWEAKS.md)

### [Credits](CREDITS.md)

License: MIT


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 (vanilla + staging): rare issues caused by child window rendering. See below or Issue #325
 * 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.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`

A `find.exe` command window is shown but never exits:

 * Happens since Wine 7.5 when running `cmd /c launcher.bat` without a terminal.
   Wine spawns a `find.exe` process in a separate window which breaks the batch script.
 * Workaround: Use a virtual desktop or run `wine cmd ...` from a terminal
 * For details, see 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 Wine 7.3 or newer 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.

#### Game no longer works on Windows

 * This is intentional to avoid abuse of this project
 * If you are Dual-Booting, write a batch script to swap the game files as needed

#### StartThreadpoolIo not found in KERNEL32.dll

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

#### 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**

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` (done by patch script)
3. Use a Wine version that includes experimental child window rendering:
     * wine-ge-custom
     * wine-tkg
     * Valve Wine/Proton (Steam)
     * Ways 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

#### 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
 * -9908
     * The downloaded data is corrupt. Try a wired connection.

Extensive permission check: Execute the following command inside your game directory:

 * `find ./ -type d \( ! -writable -or ! -readable \) 2>/dev/null`
 * 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. Seen in game version 1.2.0 to 2.4.0 (?).

This error reappears a few days after each release. It is caused by server-sent bytecode.

Workaround:

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

#### 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
     * Ubuntu/Debian: install `ttf-mscorefonts-installer`
     * Arch/Manjaro: install `ttf-ms-fonts`
     * Alternatively: winetricks `corefonts` verb
 * Re-install dxvk (if present)
 * Try running the game in a virtual desktop
 * 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 (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
 * 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.

 * 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 (if present)
 * 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

These menu buttons are broken since their introduction.
Following workarounds exist:

"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)

#### GPU bottleneck improvements

 * Stutter and low FPS on GPUs with <= 2 GB VRAM
    * For monitoring: `nvidia-smi`/`nvtop` (nVIDIA), `radeontop` (AMD)
    * Use DXVK 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/)


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:
"""
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:
--[[
Sample output: https://pastebin.com/raw/ciay6HXj

File name: "no message" (no extension)

Instructions:
	Symlink this file into the GI working directory
	That's usually where GenshinImpact.exe is.

Function description:
	sb_1184180413  c-call function with args

Hints for modifying this script:
	1) There is mostly no error handling in GI!
	2) Run the script in Lua CLI (i.e. 'lua "no message"') to check for syntax errors
	3) Uncomment functions until you see basic log information again
]]

local HOOK_RECURSIVE = true -- more precise hooks, but may stall the game
local DUMP_ON_XPCALL = true -- xpcall is called once after login. dump _G there

local LH = {} -- file-wide access

local function dump(val, depth, seen)
	depth = depth or 0
	seen = seen or {}
	if seen[val] then return "<CIRCULAR REF>" end
	if depth > 10 then return "<TOO DEEP>" end
	if val == nil then return "nil" end

	local txt = {}
	if type(val) == "table" then
		seen[val] = true
		txt[#txt + 1] = "{"
		for k, v in pairs(val) do
			txt[#txt + 1] = string.rep("\t", depth + 1) ..
				("[\"%s\"] = %s"):format(tostring(k), dump(v, depth + 1, seen))
		end
		txt[#txt + 1] = string.rep("\t", depth) .. "}"
	elseif type(val) == "string" then
		txt[#txt + 1] =  '"' .. val:gsub('\n', "$LF"):gsub('"', '\\"') .. '"'
	else
		txt[#txt + 1] = tostring(val)
	end
	return table.concat(txt, "\n")
end

local sb_c_exec, sb_alt_time = sb_1184180413, os.time
LH.get_time = function()
	if true or not sb_c_exec then
		-- Special func missing (for script dry run)
		return sb_alt_time()
	end
	-- I don't know why, but os.time() yields better results
	return sb_c_exec("GetTickCount64") / 1000
end

local F = io.open("lualog_" .. os.date("%H%M-%S") .. ".txt", "a")
F:write("=== LOG START: " .. os.date() .. "\n")

local start_time = LH.get_time()
local function LOG(msg)
	if LH and LH.get_time then
		F:write(("[%.2f] "):format(LH.get_time() - start_time))
	end
	F:write(msg)
	F:write("\n")
	F:flush() -- Causes delays but that's okay
end

-- HOOK FUNCTIONS
table.unpack = table.unpack or unpack -- Lua compatibility

local function hook_wrapper(func, name, ...)
	-- These must not be logged -> deadlock
	local no_log = (name == "getmetatable" or name == "setmetatable"
		or name == "rawset" or name == "rawget")

	LOG(("> CALL %s = %s"):format(name, no_log and "<>" or dump({...}, 1)))
	local ret_vals = {func(...)}
	LOG(("< RET  %s = %s"):format(name, no_log and "<>" or dump(ret_vals, 1)))

	LH.interval_func()

	if DUMP_ON_XPCALL and name == "xpcall" then
		LOG("=== XPCALL!!")
		LOG(dump(_G))
	end
	return table.unpack(ret_vals)
end

local hooked = {}
local recursion_depth = 0
local function hook_recursive(tb, name, v, path_text, seen)
	path = path or ""
	v = v or tb[name] or tb
	path_text = path_text or ""

	if not seen and recursion_depth > 0 then
		return -- Recursion still ongoing
	end
	seen = seen or {} -- For circular references

	-- If a custom table is provided, hook all functions
	if type(v) == "table" then
		if not HOOK_RECURSIVE and v ~= _G then
			return
		end

		if seen[v] or v == table or v == io or v == math
				or v == package.searchers
				or v == debug or v == string then
			return
		end

		-- Traverse table to hook all functions
		recursion_depth = recursion_depth + 1
		seen[v] = true
		for k2, v2 in pairs(v) do
			if type(v2) == "table" then
				hook_recursive(v, k2, v2, path_text .. k2 .. ".", seen)
			else
				hook_recursive(v, k2, v2, path_text, seen)
			end
		end
		recursion_depth = recursion_depth - 1
		return
	end

	if hooked[v] or type(v) ~= "function" then
		return
	end

	-- Do not hook common functions to avoid recursion
	local k = name
	if k == "tostring" or k == "tonumber" or k == "type" or k == "typeof"
			or k == "ipairs" or k == "pairs" or k == "next" or k == "select"
			or k == "rawget" or k == "getmetatable"
			or k == "print" then
		return
	end
	LOG("HOOK " .. path_text .. name)
	tb[name] = function(...)
		return hook_wrapper(v, path_text .. name, ...)
	end
	hooked[tb[name]] = true
end

-- INTERVAL-TRIGGERED FUNCTIONS

local last_time = 0
local func_locked = false
local my_pcall = pcall -- Not hooked
local my_sethook = debug.sethook

LH.cfuncs = {}
LH.ctimers = {}
LH.interval_func = function()
	if func_locked then return end

	my_sethook(LH.interval_func, "r", 1E10)

	local new_time = LH.get_time()
	if new_time < last_time + 0.1 then
		return
	end
	-- Lock it to avoid recursion deadlocks
	func_locked = true
	last_time = new_time

	hook_recursive(_G)

	LOG("==> Running " .. #LH.cfuncs .. " callbacks")
	for i, func in ipairs(LH.cfuncs) do
		local due = LH.ctimers[i] or 0
		if due <= new_time then
			-- Trigger it!
			local ok, delay = my_pcall(func)
			if not ok then
				LOG("==> Callback error:")
				LOG(delay)
				-- Retry later
				delay = nil
			end

			-- Trigger again in at least X or 10 seconds
			LH.ctimers[i] = new_time + (delay or 13)
		end
	end

	func_locked = false
end

local function reg_interval_func(start_delay, func)
	LH.cfuncs[#LH.cfuncs + 1] = func
	LH.ctimers[#LH.cfuncs] = LH.get_time() + (start_delay or 0)
end

reg_interval_func(0.1, function()
	-- This is pretty huge.
	LOG("=== DUMP OF _G")
	LOG(dump(_G))
	return 99 -- never again
end)

reg_interval_func(0, function()
	if not sb_75657375 then
		return 0 -- Call asap again
	end

	-- Use launch arg "-nolog" to see this (Linux)
	io.stdout:write(">>> CALLING FUNCTIONS\n")

	local ok, pkg = pcall(require, "Hotfix/Hotfix")
	if okg then
		pkg.PrintTime()
		LOG(dump(pkg.GetPatchTable()))
	end

	local ok, console = pcall(require, "Console")
	if ok then
		--[[
			"ConsolePrint"
			"onSocketData"
			"onSocketConnected"
			"socketCrFunc"
		]]
	end
	--[[if xlua then
		xlua.load_assembly("")
	end]]
	return 0.1
end)

-- FINAL: SET HOOK READY, START FUNCS
LH.interval_func()


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).