docs: add windows native launch test runbook

This commit is contained in:
Jan Nedbal
2026-04-14 13:39:48 +02:00
parent cb0867432e
commit a974836db1

View File

@@ -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 | <https://aka.ms/vs/17/release/vs_BuildTools.exe> — during install tick **Desktop development with C++** (brings MSVC v143, Windows 11 SDK, CMake). |
| Git for Windows | `git`, `bash`, line-ending handling | <https://git-scm.com/download/win> |
| .NET 8 SDK (x64) | `dotnet publish` for the launcher | <https://dotnet.microsoft.com/en-us/download/dotnet/8.0> |
| PowerShell 7.4+ | better terminal, required for copy-paste blocks below | <https://github.com/PowerShell/PowerShell/releases/latest> |
| (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 ~80120 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: <one-line summary>`, 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 <date>` 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 47
works, the bug is in the prebuilt binary, not in the source tree.