Theme
Launcher ↔ client contract
The launcher and the in-game client talk through two JSON files in the client folder, %USERPROFILE%\WildM\client\ — the folder that holds the framework DLL. The authoritative, shared document is docs/CONTRACT.md (French, maintained by the launcher and client agents, with a change journal); this page is its English summary, checked against the code.
Folders
| Path | Role | Written by |
|---|---|---|
grw-mp/build/ | Client build, copied recursively into the client folder on install | client build (build_wildm.ps1) |
%USERPROFILE%\WildM\client\ | Installed client: dinput8.dll, wildm_inject.exe, LICENSE.txt, plugins\<name>\<name>.asi (+ .ini, lang.ini), logs, ini | launcher (copy) + client (logs, ini, status) |
%USERPROFILE%\WildM\cache\<host>_<httpPort>\ | Resources downloaded from the server | launcher only — the client must not write there |
Written by the client inside the client folder (never in the game folder): logs\*.log (including scripthook.log, scripthook_crash.log, wildm_net.log), scripthook.ini (created on first launch), mods\ (only read if it exists), wildm_status.json and its transient wildm_status.json.tmp.
wildm_connect.json — launcher → client
Written by the launcher just before starting the game, after deleting any previous wildm_status.json.
json
{
"server": { "name": "WildM LAN", "host": "192.168.2.3", "httpPort": 30120, "gamePort": 30121 },
"player": { "name": "Joueur", "account": "pseudoWFX" },
"resourcesDir": "C:\\Users\\…\\WildM\\cache\\192.168.2.3_30120",
"spawn": { "x": -3112.6, "y": 5535.8, "z": 956.0 },
"session": "a-new-uuid-for-each-launch"
}| Field | Notes |
|---|---|
server.host, server.gamePort | Required by the client; without them it stays idle. |
server.name, server.httpPort | Informational. |
player.name | Launcher player name, else the account name, else Joueur. Sent in hello. |
player.account | WFX.re username, or null when no account is linked. |
resourcesDir | The server's resource cache (read-only for the client). |
spawn | From /info.spawn if the server exposes it, else from the first */resource.json in the cache with a spawn; null if neither. The current client does not teleport the player. |
session | crypto.randomUUID() per launch. Everything in wildm_status.json with another session is ignored. |
token (optional, root level) | Not written by the launcher today. If present, wildm_net forwards it in hello. |
Without this file the client does nothing — wildm_net checks every 5 s, writes nothing, and the game behaves exactly as without WildM.
wildm_status.json — client → launcher
Written by wildm_net about once a second ([status] interval_ms, minimum 250), atomically (temp file + MoveFileEx).
json
{
"session": "same uuid as wildm_connect.json",
"updatedAt": 1763112345678,
"phase": "ingame",
"gameState": "Playing",
"server": { "connected": true, "playerId": 3, "players": 5 },
"pos": { "x": -3110.2, "y": 5531.0, "z": 957.4 },
"heading": 1.57,
"hasPos": true,
"playMode": "campaign",
"client": { "framework": "1.0-beta7-wildm1", "pid": 12345 },
"error": ""
}| Field | Meaning |
|---|---|
updatedAt | Milliseconds since 1970. |
phase | booting (game state machine not read yet), menu (menu or lobby), loading (loading / reloading, or in the world without a readable position for less than 10 s), ingame (world loaded and position read, or world loaded for 10 s), error (Ghost War / Mercenaries: WildM pauses and disconnects). |
gameState | The framework's game state name. |
server.connected | TCP established and welcome received. |
server.playerId | Id from welcome (0 = none). |
server.players | Size of the last players list, self included. |
pos, heading, hasPos | Player position (metres), yaw in radians, whether the position was really read. |
playMode | "campaign", "Ghost War", … or "". |
client | Framework version and process id. |
error | In phase: "error": the reason. Otherwise it may carry the last network error (informational). A server {"t":"error","msg":…} is copied here. |
heading, hasPos, playMode and client were added by the client agent (contract journal, 2026-11-14); no field was removed.
How the launcher reads it
Polled every 500 ms during the Loading the world step:
| Situation | Launcher reaction |
|---|---|
| No file for this session yet | Waiting for the client…; after 3 minutes: warning, the game is left running |
phase: "error" | Error, error shown to the player as is |
updatedAt older than 30 s | Error: the client stopped reporting (game closed or frozen) |
phase: "ingame" and server.connected | Success, the launcher window minimises |
phase: "ingame" without connected for 20 s | Warning: in game but not connected |
| Other phases | Progress message (see The loading screen) |
GRW.exe not running (checked every 5 s) | Error: the game closed before reaching the world |
Local debug console (not part of the contract)
plugins\test_plugin\test_plugin.asi listens on 127.0.0.1:9999 (command api → state and position; help lists commands). Its log is logs\scripthook_repl.log. It is a development tool only.