Skip to content

Game server protocol ​

The WildM game server (game-server/server.js) exposes two ports, configured in server.json:

  • HTTP on httpPort (default 30120) — used by the launcher;
  • TCP on gamePort (default 30121) — used by the client in game (wildm_net).

HTTP ​

GET /info ​

json
{
  "name": "WildM LAN",
  "desc": "Serveur de test WildM en réseau local",
  "tags": ["roleplay", "dev"],
  "locale": "FR",
  "players": 0,
  "maxPlayers": 32,
  "host": "192.168.2.3",
  "httpPort": 30120,
  "gamePort": 30121,
  "resources": { "count": 2, "totalSize": 1536, "hash": "3f1c2a9b0d4e5f61" }
}

The launcher requires an integer gamePort (otherwise gamePort manquant). resources.hash is the first 16 hex characters of the sha256 of the manifest's file list. /info does not currently include spawn; the launcher accepts one (info.spawn) if a future server sends it.

GET /resources/manifest ​

json
{
  "files": [
    { "path": "loadscreen/index.html", "size": 1012, "sha256": "…64 hex…" },
    { "path": "wildm-base/resource.json", "size": 524, "sha256": "…" }
  ],
  "totalSize": 1536,
  "hash": "3f1c2a9b0d4e5f61"
}

Paths are relative to resources/, with / separators. The manifest is built once at server start.

GET /resources/file/<path> ​

Streams one file (application/octet-stream, with Content-Length). <path> is URL-encoded per segment. Only paths present in the manifest are served; anything else is 404.

Any other route answers 404.

What the launcher checks ​

  • Each manifest entry must have a safe relative path (no ./.., no characters invalid on Windows, ≤ 240 characters), a 64-hex sha256 and a non-negative integer size — otherwise the whole join fails.
  • Downloads go to <file>.wildm-part, must match the exact size and sha256, and are then renamed.

TCP: JSON lines ​

One JSON object per line, UTF-8, terminated by \n. Lines that do not parse are ignored. A connection that accumulates more than 64 KB without a newline is closed. TCP_NODELAY is set on the server side.

Client → server ​

MessageWhenNotes
{"t":"hello","name":"Joueur"}First message after connectingname is truncated to 24 characters (default Joueur). The client adds "token":"…" when wildm_connect.json has a root token field; the current server ignores it. Only the first hello of a connection counts.
{"t":"pos","x":…,"y":…,"z":…,"h":…}10 Hz while in game (configurable pos_hz, 1–30)Metres (x east, y north, z up); h = heading (yaw) in radians. Non-finite numbers are ignored per field. Ignored before hello.

Server → client ​

MessageWhen
{"t":"welcome","id":3,"spawn":{"x":…,"y":…,"z":…},"name":"WildM LAN"}Reply to hello. id is a per-process counter starting at 1; name is the server name; spawn comes from server.json.
{"t":"players","list":[{"id":1,"name":"…","x":…,"y":…,"z":…,"h":…}]}Broadcast to every connected player every 100 ms (10 Hz). The list includes the receiving player. Positions are 0 until a player's first pos.
{"t":"error","msg":"Serveur plein"}Sent instead of welcome when maxPlayers is reached; the connection is then closed.

When the socket closes or errors, the player is removed from the list.

Scripts (resources with Lua scripts) ​

See Scripting (Lua) for the API. On the wire:

MessageDirectionNotes
{"t":"sres","list":[{"name":"example-scripts","dir":"example-scripts","scripts":[{"path":"example-scripts/client/main.lua","sha256":"…"}]}]}S → CRight after welcome: client scripts (shared first) to run, in order. path is relative to the resource cache; the client refuses a file whose sha256 differs.
{"t":"ev","n":"example:ping","a":[123],"c":1}bothNetwork event: name, JSON arguments, argument count (c, so trailing nils survive). Keys may come in any order. Ignored unless the receiving side called RegisterNetEvent(n). Client → server: 32 KB per line, 50 events/s per player (burst 100).
{"t":"cmd","raw":"npc 2"}C → SA command no client script handled (256 characters max). Runs the server command with source = the player.
{"t":"notify","msg":"Commande inconnue : /x"}S → CMessage shown to the player (unknown command…).

Network entities and state bags ​

See Entities, state bags & permissions for the Lua API. h is in radians; o is the owner's player id (0 = server).

MessageDirectionNotes
{"t":"ent","op":"new","id":3,"k":"veh","m":"kamaz","x":…,"y":…,"z":…,"h":…,"o":1,"sb":{"fuel":80}}S → CEntity entered your zone (400 m). k: veh, ped, obj. pl = this is player J's ped (already drawn, just map the id). ref only for the client that created it.
{"t":"ent","op":"out"|"del","id":3}S → CLeft your zone (remove locally) / deleted for everyone.
{"t":"ent","op":"own","id":3,"o":2}S → CNew owner.
{"t":"ent","op":"tp","id":3,"x":…,"y":…,"z":…,"h":…}S → ownerA server script moved the entity.
{"t":"ents","ts":T,"list":[[id,x,y,z,h,pt],…]}S → C10 Hz, entities in your zone (player peds excluded). Same clock as players.
{"t":"ent","op":"new","ref":7,"k":"veh","m":"quad","x":…,"y":…,"z":…,"h":…}C → SA client script created an entity; answered with new + ref, or {"t":"ent","op":"refused","ref":7}.
{"t":"epos","list":[[id,x,y,z,h],…]}C → S10 Hz, positions of entities you own (ignored for others).
{"t":"ent","op":"drive"|"leave"|"del","id":3}C → SYou drive it (become owner if ≤ 15 m) / got out / delete (owner only).
{"t":"sb","b":"player:2","k":"job","v":{…}}bothState bag value (v missing = removed). Clients may only write their own player: bag and entities they own, never srv_* keys.

Before welcome, the server verifies hello.token (a wft_… ticket from the master, see Master server API) and may answer {"t":"error","msg":…} and close (banned, or account required).

Session example ​

text
C: {"t":"hello","name":"Alex"}
S: {"t":"welcome","id":1,"spawn":{"x":-3112.6,"y":5535.8,"z":956},"name":"WildM LAN"}
C: {"t":"pos","x":-3110.2,"y":5531.0,"z":957.4,"h":1.57}
S: {"t":"players","list":[{"id":1,"name":"Alex","x":-3110.2,"y":5531,"z":957.4,"h":1.57}]}
…

You can test the TCP side by hand with any line-based tool, e.g. ncat 127.0.0.1 30121 and typing a hello line.

Heartbeat ​

The game server also calls the master every 30 s — see Heartbeat & server list and POST /heartbeat.

WildM is an independent community project. It is not affiliated with or endorsed by Ubisoft. Ghost Recon Wildlands is a trademark of Ubisoft Entertainment.