From 0aa8361f090f4240e879c87009476d6a408f3b5a Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Tue, 14 Apr 2026 10:23:04 +0200 Subject: [PATCH 1/2] docs: add Linux Wine runtime guide Document the interim path for running the Windows client on Linux via Wine, verified to reach character selection on Fedora 41 with Wine 10 Staging. Main gotcha: winetricks tahoma is mandatory because the client hard-codes Tahoma as the UI font, and without it all text renders invisibly even though layouts are correct. --- docs/linux-wine.md | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 docs/linux-wine.md diff --git a/docs/linux-wine.md b/docs/linux-wine.md new file mode 100644 index 00000000..079ab275 --- /dev/null +++ b/docs/linux-wine.md @@ -0,0 +1,91 @@ +# Running the client on Linux with Wine + +This is an interim path for playing and testing on Linux while a native Linux port is a longer-term goal. Wine runs the unmodified Windows build of `Metin2.exe` / `Metin2_Debug.exe` directly. Verified to reach the character selection screen on Fedora 41 with Wine 10 Staging; other modern distros should work the same. + +Use this when you want to: + +- Smoke-test the Windows binary without rebooting into Windows +- Develop server-side with a live client connected from the same machine +- Run a dev loop without owning a Windows install + +## Requirements + +- A recent Wine (10.x Staging tested, 9.x stable should work). Older than 8 may be rough on D3D9. +- `winetricks` for installing MSVC runtime, D3DX9 helper DLLs, core fonts, and Tahoma +- A copy of the client deploy folder (the one containing `Metin2.exe`, `Metin2_Debug.exe`, `assets/`, `pack/`, `bgm/`, `config/`, `log/`). The whole folder is ~4.3 GB. +- ~7 GB free disk for the writable client copy plus the Wine prefix + +On Fedora: + +```bash +sudo dnf install -y wine winetricks +``` + +On Debian/Ubuntu (use the WineHQ repo for a modern version): + +```bash +sudo apt install -y wine winetricks +``` + +## One-shot setup + +The easiest way is the helper script in this repo: + +```bash +./scripts/setup-wine-prefix.sh /path/to/windows/client ~/metin-wine +``` + +This will: + +1. Copy the client folder to `~/metin-wine/client` (needs to be on a writable filesystem, so an NTFS read-only mount won't do). +2. Create a fresh Wine prefix at `~/metin-wine/prefix`. +3. Install `vcrun2022`, `d3dx9`, `corefonts`, and `tahoma` via winetricks. +4. Print the launch command. + +See the script itself for exact steps if you prefer to run them manually. + +## Why Tahoma is required + +The client hard-codes Tahoma as its UI font. On Windows this is invisible because Tahoma ships with the OS; on a fresh Wine prefix it's missing, and the result is that the login screen renders layouts and backgrounds correctly but **all text is invisible**. You can reach the server picker and character selection, you just can't read anything. Installing Tahoma via `winetricks tahoma` fixes it in one shot. + +If the login screen looks right but has no readable text, this is what you're seeing. + +## Launching + +After setup, the launch command is just: + +```bash +cd ~/metin-wine/client +WINEPREFIX=~/metin-wine/prefix wine Metin2.exe +``` + +Use `Metin2_Debug.exe` instead of `Metin2.exe` if you want more verbose client-side logging via `OutputDebugString`. Wine will echo those to stderr when `WINEDEBUG` includes `+seh` or you pass `+outputdebugstring`. For normal play use `-all,+err`. + +## Logs and debug output + +Useful `WINEDEBUG` settings: + +- `WINEDEBUG=-all,+err` — quiet, only real errors. Use this for normal play. +- `WINEDEBUG=-all,+loaddll,+module,+err` — shows which DLLs Wine loads, handy when the client crashes early with a missing DLL. +- `WINEDEBUG=-all,+err,+seh` — captures the client's own `OutputDebugString` calls via SEH, which is how metin2's internal logging surfaces. Very noisy but useful when diagnosing client-side issues ("CResource::Load file not exist X", "CPythonNonPlayer::LoadNonPlayerData", etc.). + +Redirect to a file and grep the signal out of the noise: + +```bash +WINEDEBUG=-all,+err,+seh wine Metin2_Debug.exe >wine-run.log 2>&1 +grep -E 'OutputDebugString[AW] "' wine-run.log | sed 's/.*OutputDebugString[AW] //' | sort -u +``` + +The client also writes its own logs to `log/` inside the client folder. Those are plain text and more readable than the Wine SEH traces. + +## Known quirks + +- **Wayland:** works via XWayland, no special config. If the window opens minimized or off-screen, `Alt+Tab` to find it. +- **Read-only NTFS mount:** don't try to launch from a read-only mount of your Windows partition. The client creates and writes `log/`, `config/`, and cache files; on a read-only FS the launch will be confusing. Always copy to a writable location first. `setup-wine-prefix.sh` does this for you. +- **DXVK render state warnings:** lines like `D3D9DeviceEx::SetRenderState: Unhandled render state 163` in the log are harmless. DXVK doesn't implement every legacy D3D9 render state, but the ones metin2 cares about all work. +- **SEH dispatch spam:** `dispatch_exception code=4001000a` / `4001000c` are how Windows signals `OutputDebugStringW` / `OutputDebugStringA`. They're soft exceptions, not errors. They only show up if you enable `+seh` in `WINEDEBUG`. +- **First launch is slower:** DXVK compiles its shader pipelines on first run and writes a state cache. Subsequent launches are noticeably faster. + +## When to stop using Wine + +This guide is for the interim. The longer-term plan is a native Linux build of the client with a free-software replacement for Granny2 animation runtime. Until that lands, Wine is the way. From dd0643137f42790d023d520cfc91de9f970203bd Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Tue, 14 Apr 2026 10:23:04 +0200 Subject: [PATCH 2/2] scripts: add wine prefix setup script Idempotent helper that copies the client to a writable location, creates a fresh Wine prefix, and installs the required winetricks verbs (vcrun2022, d3dx9, corefonts, tahoma). Re-running on an existing target skips already-done steps. --- scripts/setup-wine-prefix.sh | 97 ++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100755 scripts/setup-wine-prefix.sh diff --git a/scripts/setup-wine-prefix.sh b/scripts/setup-wine-prefix.sh new file mode 100755 index 00000000..56b80d76 --- /dev/null +++ b/scripts/setup-wine-prefix.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Set up a Wine prefix for running the Metin2 client on Linux. +# Idempotent: re-running on an existing prefix skips steps that are already done. +# +# Usage: +# ./scripts/setup-wine-prefix.sh +# +# Example: +# ./scripts/setup-wine-prefix.sh /mnt/windows_c/Users/me/metin/client ~/metin-wine +# +# Result layout: +# /client/ — writable copy of the client deploy folder +# /prefix/ — Wine prefix with required runtime deps installed + +set -euo pipefail + +if [[ $# -lt 2 ]]; then + echo "usage: $0 " >&2 + echo " source-client-dir: path containing Metin2.exe, assets/, pack/, etc." >&2 + echo " target-dir: directory to create (holds client/ and prefix/)" >&2 + exit 2 +fi + +SRC=$1 +DEST=$2 + +if [[ ! -f "$SRC/Metin2.exe" && ! -f "$SRC/Metin2_Debug.exe" ]]; then + echo "error: $SRC does not look like a client folder (no Metin2.exe or Metin2_Debug.exe)" >&2 + exit 1 +fi + +for tool in wine winetricks; do + if ! command -v "$tool" >/dev/null 2>&1; then + echo "error: $tool not found in PATH. Install it via your package manager." >&2 + exit 1 + fi +done + +CLIENT_DIR=$DEST/client +PREFIX_DIR=$DEST/prefix + +mkdir -p "$DEST" + +if [[ -d "$CLIENT_DIR" && -f "$CLIENT_DIR/Metin2.exe" ]] || [[ -d "$CLIENT_DIR" && -f "$CLIENT_DIR/Metin2_Debug.exe" ]]; then + echo "[1/3] client already present at $CLIENT_DIR, skipping copy" +else + echo "[1/3] copying client from $SRC to $CLIENT_DIR (this can take a minute)" + cp -a "$SRC" "$CLIENT_DIR" +fi + +export WINEPREFIX=$PREFIX_DIR +export WINEARCH=win64 + +if [[ -f "$PREFIX_DIR/system.reg" ]]; then + echo "[2/3] wine prefix already exists at $PREFIX_DIR, skipping wineboot" +else + echo "[2/3] creating wine prefix at $PREFIX_DIR" + mkdir -p "$PREFIX_DIR" + wineboot --init >/dev/null 2>&1 || true +fi + +# vcrun2022 — MSVC 2015-2022 runtime, required because the client is an MSVC build +# d3dx9 — D3DX9 helper DLLs (Wine implements d3d9 but not the d3dx9 helpers) +# corefonts — Arial/Courier/Times/etc., needed by some UI elements +# tahoma — the client hard-codes Tahoma as the UI font; without it, all text renders invisibly +VERBS=(vcrun2022 d3dx9 corefonts tahoma) +TO_INSTALL=() +for v in "${VERBS[@]}"; do + case $v in + vcrun2022) + if [[ -f "$PREFIX_DIR/drive_c/windows/system32/msvcp140.dll" ]]; then continue; fi ;; + d3dx9) + if [[ -f "$PREFIX_DIR/drive_c/windows/system32/d3dx9_43.dll" ]]; then continue; fi ;; + corefonts) + if [[ -f "$PREFIX_DIR/drive_c/windows/Fonts/arial.ttf" ]]; then continue; fi ;; + tahoma) + if [[ -f "$PREFIX_DIR/drive_c/windows/Fonts/tahoma.ttf" ]]; then continue; fi ;; + esac + TO_INSTALL+=("$v") +done + +if [[ ${#TO_INSTALL[@]} -eq 0 ]]; then + echo "[3/3] all winetricks verbs already installed" +else + echo "[3/3] installing winetricks verbs: ${TO_INSTALL[*]}" + winetricks -q "${TO_INSTALL[@]}" +fi + +echo +echo "done. to launch:" +echo +echo " cd $CLIENT_DIR" +echo " WINEPREFIX=$PREFIX_DIR wine Metin2.exe" +echo +echo "or with verbose client logging:" +echo +echo " WINEPREFIX=$PREFIX_DIR WINEDEBUG=-all,+err,+seh wine Metin2_Debug.exe"