From a974836db1cdfb94cc890d1bbcdcc8fbcfcc3ac6 Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Tue, 14 Apr 2026 13:39:48 +0200 Subject: [PATCH] docs: add windows native launch test runbook --- docs/runbook-windows-launch-test.md | 479 ++++++++++++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 docs/runbook-windows-launch-test.md diff --git a/docs/runbook-windows-launch-test.md b/docs/runbook-windows-launch-test.md new file mode 100644 index 0000000..40e2c53 --- /dev/null +++ b/docs/runbook-windows-launch-test.md @@ -0,0 +1,479 @@ +# Runbook: native Windows launch test + +**Audience:** anyone on the team with a Windows 10/11 box and Visual Studio +Build Tools 2022 installed. Primary target is Jakub or kolega 4. + +**Goal:** end-to-end verification that `Metin2Launcher.exe` (from +`jann/metin-launcher`) and `Metin2.exe` (from `metin-server/m2dev-client-src`) +actually work on native Windows. So far the client is only confirmed working +under Linux+Wine (`m2dev-client/docs/linux-wine.md`). A Windows native run +closes that gap before anyone else wastes time tracking Wine-specific +artefacts. + +This runbook is Windows-first by design and aligns with this repo's +`AGENTS.md` (Windows is the canonical target for `m2dev-client-src`). Nothing +here modifies the C++ source — you only build and run. + +**Time budget:** ~2 h from a clean Windows box to "character walking on the +first map". + +--- + +## 0. Scope and non-goals + +Covered: + +- Installing the toolchain +- Cloning both source repos + the runtime client assets +- Building the C++ client (`Metin2.exe`) with MSVC +- Building the launcher (`Metin2Launcher.exe`) with `dotnet publish` +- First launch, login, character create, entering game +- What to capture when anything breaks +- Common Windows-specific pitfalls and their fixes +- How to roll back to a clean client if you break the install +- Where to file findings + +Explicitly NOT covered: + +- Any source-level debugging. If something crashes in C++ land, capture the + logs + dump and file an issue; don't patch. +- Running the server. The live VPS `mt2.jakubkadlec.dev` is what you'll be + connecting to. Do not try to start a local server as part of this test. +- Packaging, signing or distribution. That's a separate flow. + +--- + +## 1. Prerequisites + +Install these on the Windows box **in this order**. Skip items you already +have. + +| Tool | Why | Installer | +| --------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| Visual Studio Build Tools 2022 | MSVC `cl.exe`, Windows SDK, CMake integration | — during install tick **Desktop development with C++** (brings MSVC v143, Windows 11 SDK, CMake). | +| Git for Windows | `git`, `bash`, line-ending handling | | +| .NET 8 SDK (x64) | `dotnet publish` for the launcher | | +| PowerShell 7.4+ | better terminal, required for copy-paste blocks below | | +| (optional) Windows Terminal | Multi-tab terminal, much nicer than conhost | Microsoft Store | + +**Do not install a separate CMake** unless you already use one; the Build +Tools ship a recent CMake and the `Developer PowerShell for VS 2022` shortcut +puts it on `PATH`. + +### Verify the toolchain + +Open **Developer PowerShell for VS 2022** (Start menu → "Developer +PowerShell") and run: + +```powershell +cl # expected: Microsoft (R) C/C++ Optimizing Compiler Version 19.4x +cmake --version # expected: cmake version 3.28+ +git --version +dotnet --list-sdks # must show an 8.0.x entry +``` + +**If any of these fail:** the rest of the runbook won't work. Re-run the +Build Tools installer and tick **Desktop development with C++**. Close and +reopen Developer PowerShell afterwards. + +--- + +## 2. Choose a working directory + +Pick a path that is **NOT under OneDrive, Documents, Desktop, or `C:\Program +Files`**. OneDrive sync mangles pack files and locks them mid-build; +`Program Files` needs admin writes and triggers UAC prompts per-file. + +Recommended: + +```powershell +$root = "C:\dev\metin" +New-Item -ItemType Directory -Force -Path $root | Out-Null +Set-Location $root +``` + +From here on, all path snippets assume `C:\dev\metin` as the root. + +--- + +## 3. Clone the three repos + +All three are on `gitea.jakubkadlec.dev`. You need an SSH key on that +server (same one you use for the rest of the project). If you've never +cloned from Gitea before, use HTTPS + a Gitea personal access token +instead — both work. + +```powershell +Set-Location C:\dev\metin + +# 1) C++ client source (this repo) +git clone ssh://git@gitea.jakubkadlec.dev:2222/metin-server/m2dev-client-src.git + +# 2) C# launcher +git clone ssh://git@gitea.jakubkadlec.dev:2222/jann/metin-launcher.git + +# 3) client runtime assets (packs, bgm, config, log dir, Metin2.exe prebuilt) +# Skip this if you already have a populated client\ folder from an older +# Windows install. +git clone ssh://git@gitea.jakubkadlec.dev:2222/metin-server/m2dev-client.git client +``` + +`m2dev-client` is ~4 GB because it contains the packed assets (`pack\*.pck`, +`bgm\`, `assets\`). Expect the clone to take several minutes. Git LFS is +not used — everything is vanilla git, large files included. + +Expected layout after this step: + +``` +C:\dev\metin\ +├── m2dev-client-src\ ← C++ source, CMakeLists.txt at root +├── metin-launcher\ ← C# source, Launcher.sln at root +└── client\ ← runtime: assets\, pack\, bgm\, config\, log\, Metin2.exe (prebuilt) +``` + +**If `client\Metin2.exe` already works for you** you can skip the C++ build +in step 4 and only replace `Metin2.exe` if step 4 produces a newer one. + +--- + +## 4. Build the C++ client (`Metin2.exe`) + +From **Developer PowerShell for VS 2022** (important — regular PowerShell +won't see `cl.exe`): + +```powershell +Set-Location C:\dev\metin\m2dev-client-src +New-Item -ItemType Directory -Force -Path build | Out-Null +Set-Location build + +cmake .. -G "Visual Studio 17 2022" -A Win32 2>&1 | Tee-Object ..\cmake-configure.log +cmake --build . --config RelWithDebInfo 2>&1 | Tee-Object ..\cmake-build.log +``` + +Notes: + +- `-A Win32` is intentional. The client is 32-bit because of FMOD, Granny 2, + the embedded Python, and decades of assumptions in EterLib. A 64-bit + build will not produce a runnable exe today. +- Use `RelWithDebInfo` so we get a `.pdb` next to the exe for crash dumps. +- If the build fails, the full log is in `cmake-build.log` next to the + build dir. **Attach that file verbatim** when filing the issue — do not + paraphrase. + +**Expected output:** + +``` +C:\dev\metin\m2dev-client-src\build\...\RelWithDebInfo\Metin2.exe +C:\dev\metin\m2dev-client-src\build\...\RelWithDebInfo\Metin2.pdb +``` + +Copy the exe into the runtime client directory, **overwriting** the prebuilt +one (keep a backup): + +```powershell +$client = "C:\dev\metin\client" +Copy-Item $client\Metin2.exe $client\Metin2.exe.backup -ErrorAction SilentlyContinue + +$built = Get-ChildItem -Recurse -Filter Metin2.exe C:\dev\metin\m2dev-client-src\build | + Where-Object { $_.FullName -like "*RelWithDebInfo*" } | Select-Object -First 1 +Copy-Item $built.FullName $client\Metin2.exe -Force +Copy-Item ($built.FullName -replace '\.exe$','.pdb') $client\ -Force +``` + +**If it fails:** + +- *Missing `cl.exe` / `link.exe`*: you're in the wrong shell. Use the + Developer PowerShell shortcut. +- *"Cannot open include file: 'd3d9.h'"*: Windows SDK is missing. Re-run + Build Tools installer and tick the Windows 11 SDK. +- *"LNK2019 unresolved external"* against FMOD / Granny / Python: the + build tree is picking up the wrong vendored lib. Check `extern\` and + `vendor\` subdirs and make sure your checkout is clean (`git status` + should be empty). +- *Build succeeds but no `Metin2.exe`*: check `cmake-build.log` for the + actual target name — upstream may have it under a slightly different + casing. + +--- + +## 5. Build the launcher (`Metin2Launcher.exe`) + +From a **regular** PowerShell 7 window (Developer PowerShell also works, +but `dotnet` doesn't need the MSVC env): + +```powershell +Set-Location C:\dev\metin\metin-launcher + +dotnet publish src\Metin2Launcher\Metin2Launcher.csproj ` + -c Release ` + -r win-x64 ` + --self-contained ` + -p:PublishSingleFile=true ` + -p:IncludeNativeLibrariesForSelfExtract=true ` + 2>&1 | Tee-Object publish.log +``` + +**Expected output:** + +``` +C:\dev\metin\metin-launcher\src\Metin2Launcher\bin\Release\net8.0\win-x64\publish\Metin2Launcher.exe +``` + +The single-file exe is ~80–120 MB because Avalonia + .NET runtime are +bundled. That's normal. + +Copy it next to `Metin2.exe`: + +```powershell +Copy-Item ` + C:\dev\metin\metin-launcher\src\Metin2Launcher\bin\Release\net8.0\win-x64\publish\Metin2Launcher.exe ` + C:\dev\metin\client\Metin2Launcher.exe -Force +``` + +**If it fails:** + +- *"SDK 8.0.x not found"*: install .NET 8 SDK, then reopen the shell. +- *Avalonia / Velopack restore errors*: check internet connectivity, the + build pulls packages from nuget.org. Corporate proxies will need + `NUGET_HTTP_PROXY` or equivalent. +- *`dotnet test` fails* (if you chose to run it): the tests run on Linux + in CI. On Windows they should still pass; if they don't, capture + `publish.log` plus the failing test output and file an issue. + +--- + +## 6. First run — launcher GUI + +```powershell +Set-Location C:\dev\metin\client +.\Metin2Launcher.exe +``` + +**Expected behaviour:** + +1. Avalonia window appears, 900×560 fixed size, with a banner, a status / + progress panel on the left, and a news panel on the right. +2. Launcher attempts to fetch `https://updates.jakubkadlec.dev/manifest.json`. + DNS for that host is currently broken on purpose; the launcher should + time out and fall back to **"Server unreachable — using local client"**. +3. The **Play** button becomes enabled. +4. `C:\dev\metin\client\.updates\launcher.log` is created and starts + getting lines written to it. + +**If the launcher window never shows up:** + +- Run from a terminal and watch stdout — Velopack bootstrapping errors + land on stderr only. Redirect with `.\Metin2Launcher.exe 2>&1 | Tee-Object + launcher-stdout.log`. +- SmartScreen may have quarantined the exe because it's unsigned. Windows + Defender → **Protection history** → Allow. Or right-click the exe → + Properties → **Unblock**. +- If you see `This app can't run on your PC`, you built for the wrong + arch. The launcher is `win-x64` but must be run on 64-bit Windows (it + is; Win32 apps work fine on x64). If you copied a `Metin2.exe` build + instead, you'll see this; re-check step 5. + +**If the status panel stays at "Checking for updates..." forever:** + +- Expected to time out within ~15 s and flip to "Server unreachable". If + it never does, the launcher is stuck in a DNS retry loop. Close it, + grab `.updates\launcher.log`, and file the log — this is a launcher + bug, not a client bug. + +--- + +## 7. Play — reach the game + +1. Click **Play**. `Metin2.exe` should start in a separate process within + a couple of seconds. The launcher window should remain visible (or + minimise, depending on the configured behaviour). +2. **Language bar** appears along the top of the Metin2 window. +3. The **Metin2 logo** screen animates. +4. A **server picker** shows one row: `01. Metin2` / `CH1 NORM`. + - Select it and click OK. +5. Login screen: + - Register a new account (the server allows on-the-fly registration — + use a throwaway ID and password). Or use an existing account if you + have one. + - Proceed to character selection. +6. Create a fresh character of any class, any empire. Confirm. +7. You should land on the first map (Yongbi / Seoungmahn depending on + empire). Move with `WASD`, open the menu with `ESC`, try the chat by + pressing `Enter` and typing a line. + +**Acceptance bar for this runbook:** you reached the first map, you can +move, chat works. Anything beyond that is a nice-to-have. + +**If `Metin2.exe` crashes on click-Play:** + +- Look in `C:\dev\metin\client\log\syserr.txt`. That file is how the + client's legacy error reporter logs crashes. The last dozen lines are + usually enough to classify the failure. +- If Windows shows a `.exe has stopped working` dialog, check **Event + Viewer → Windows Logs → Application** for the Faulting Module entry. +- If it silently exits, the problem is usually missing DirectX runtime + (d3dx9). Install the legacy DirectX End-User Runtimes (June 2010) from + Microsoft. + +**If login fails with "Connection closed":** + +- This is the DNS breakage again. The launcher's fallback path does not + help `Metin2.exe`, which reads its own `serverinfo` file. Check + `C:\dev\metin\client\serverinfo.py` or whatever config points at the + live server's IP. The audit branch has the current public IP of + `mt2.jakubkadlec.dev`. + +--- + +## 8. What to capture and send back + +Regardless of whether it worked or not, collect and attach these to a +Gitea issue in `metin-server/m2dev-client-src` with label `windows-test`: + +| File | Why | +| ------------------------------------------------- | ---------------------------------------------------- | +| `client\.updates\launcher.log` | Launcher side — manifest fetch, update decisions, Play-button flow. | +| `client\log\syserr.txt` | C++ client crashes and asserts. | +| `client\log\packetdump.txt` (if present) | Last packets before disconnect/crash; rare but invaluable for login breaks. | +| `m2dev-client-src\cmake-configure.log` | Build: CMake configuration output. | +| `m2dev-client-src\cmake-build.log` | Build: MSVC compile output. **Verbatim**, not paraphrased. | +| `metin-launcher\publish.log` | Launcher publish output. | +| Screenshots | Any visual glitch, stuck screen, or error dialog. | +| Windows version (`winver`) + MSVC version (`cl`) | Paste at top of issue. | +| GPU + driver version | `dxdiag` → Save All Information → attach `DxDiag.txt`. | + +Zip the whole set: + +```powershell +$stamp = Get-Date -Format "yyyyMMdd-HHmmss" +Compress-Archive -Path ` + C:\dev\metin\client\.updates\launcher.log, ` + C:\dev\metin\client\log\syserr.txt, ` + C:\dev\metin\client\log\packetdump.txt, ` + C:\dev\metin\m2dev-client-src\cmake-configure.log, ` + C:\dev\metin\m2dev-client-src\cmake-build.log, ` + C:\dev\metin\metin-launcher\publish.log ` + -DestinationPath "$env:USERPROFILE\Desktop\windows-test-$stamp.zip" ` + -ErrorAction SilentlyContinue +``` + +Missing files are fine — the `-ErrorAction SilentlyContinue` keeps the +command going if one of them doesn't exist (e.g. `packetdump.txt` on a +successful run). + +--- + +## 9. Windows-specific gotchas + +Distilled from `m2dev-client/docs/linux-wine.md` (Wine oddities that +*also* apply on Windows in different forms) and from general Windows +experience with legacy 32-bit game clients: + +- **Tahoma font.** On fresh Wine prefixes you have to install it; on + Windows it's always present, so this *should* be a non-issue. If text + is missing on the login screen, check `fonts\Tahoma.ttf` is still in + `C:\Windows\Fonts` and hasn't been replaced by a custom font manager. +- **SmartScreen / Defender quarantine.** `Metin2Launcher.exe` and + `Metin2.exe` are unsigned. On first run Windows will warn and may move + them to quarantine. Either sign them (out of scope for this runbook), + or Allow + Unblock per-file in Properties. +- **UAC + `C:\Program Files`.** Don't install there. The client writes + to `log\`, `config\`, `.updates\`, and into its own install dir; UAC + will silently redirect writes to `%LOCALAPPDATA%\VirtualStore` and + you'll chase phantom bugs. +- **OneDrive / Documents / Desktop.** Same reason. OneDrive can lock + files during sync, which corrupts pack reads. Use `C:\dev\metin`. +- **Antivirus with heuristic scanning.** The 32-bit client, the embedded + Python, the unsigned exe, plus FMOD unpacking into temp, together look + like a toy virus to aggressive AVs. If the process is killed mid-load + check the AV quarantine first. +- **DirectX End-User Runtimes.** Modern Windows still doesn't install + the d3dx9 helper DLLs by default. If the launcher works but `Metin2.exe` + silently exits, install the DirectX End-User Runtimes (June 2010) + package from Microsoft. +- **Display scaling.** The client is DPI-unaware. On a 4K laptop with + 150% scaling the window can render as a tiny 900×600 rectangle. Right- + click `Metin2.exe` → Properties → Compatibility → **Change high DPI + settings** → tick "Override high DPI scaling behavior" = System. +- **Windows Firewall prompt on first connect.** The first time + `Metin2.exe` tries to reach port 11000, Defender Firewall will ask. + Allow on private networks at minimum. +- **32-bit vs 64-bit confusion.** The client is strictly 32-bit. If a + Python extension or native DLL is built x64 you'll get a load error + on startup. Check the build arch on every custom DLL. +- **Non-English locale.** The client's Python side assumes certain code + pages. If you run on a system with a non-ASCII username (`C:\Users\ + Jánek`), watch for path encoding issues in `launcher.log`. Use a + plain-ASCII user or set `C:\dev\metin` from the root of the drive. + +--- + +## 10. Rollback / reset to a known state + +If you've made a mess and want to start over without re-cloning 4 GB of +assets: + +```powershell +Set-Location C:\dev\metin\client + +# Restore original Metin2.exe if you kept the backup +if (Test-Path Metin2.exe.backup) { Copy-Item Metin2.exe.backup Metin2.exe -Force } + +# Wipe launcher + updater state +Remove-Item -Recurse -Force .\.updates -ErrorAction SilentlyContinue +Remove-Item -Recurse -Force .\log -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Path .\log | Out-Null + +# Remove the launcher exe; it'll be re-copied from the publish dir next time +Remove-Item .\Metin2Launcher.exe -ErrorAction SilentlyContinue +``` + +The runtime asset tree (`pack\`, `assets\`, `bgm\`) is read-only during +a normal run, so you almost never have to re-pull it. If you do need to +reset everything to HEAD: + +```powershell +Set-Location C:\dev\metin\client +git reset --hard origin/main +git clean -fdx +``` + +**Do NOT** `git clean -fdx` inside `m2dev-client-src\` unless you're ready +to re-download vendored third-party trees that may not be on disk elsewhere. + +--- + +## 11. Where to report findings + +File a new issue in `metin-server/m2dev-client-src` on +`gitea.jakubkadlec.dev`: + +- Title: `windows-test: `, e.g. + `windows-test: launcher OK, Metin2.exe crashes in EterLib on first map`. +- Label: `windows-test`. Create the label if it doesn't exist. +- Body: a short timeline of what you did, which step in this runbook + failed (e.g. "Step 7, after clicking OK in server picker"), and the + zipfile from step 8 attached. +- Assign Jan (`jann`) for triage. For launcher-only issues, cross-link + to `jann/metin-launcher` with the same label. + +If everything worked end-to-end, still file an issue titled +`windows-test: full run PASS ` with the zip attached — we want a +reproducible baseline of a good Windows run on record. + +--- + +## Appendix A — the absolute-minimum fast path + +For when you just want to verify "does it start at all" and don't care +about building from source: + +1. Clone `m2dev-client` → `C:\dev\metin\client`. +2. Download the latest CI artifact of `Metin2Launcher.exe` from + `jann/metin-launcher` releases (once CI is wired; until then, build + it yourself per step 5). +3. Drop the launcher next to `client\Metin2.exe`. +4. Run `Metin2Launcher.exe`. Click Play. Done. + +No MSVC needed. If this path fails but the full build path in steps 4–7 +works, the bug is in the prebuilt binary, not in the source tree.