480 lines
20 KiB
Markdown
480 lines
20 KiB
Markdown
# 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 ~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: <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 4–7
|
||
works, the bug is in the prebuilt binary, not in the source tree.
|