Network transport

Usage guide of net.transport: the session layer under every net.* sync kit (WebSocket, WebRTC, direct IP), its settings and defaults, the session service, events, variables and the errors a bad config gives.

Source: module-kits:kits/net_transport/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs net-transportMCP tool: gripforge_docs { "topic": "net-transport" }

The network transport of your game (net.transport) #

The connection layer under every multiplayer kit: how a client reaches the server, how long a silent link is kept, how a dropped player comes back, how fast a peer may talk. For the choice of the sync kit and the server program, read the multiplayer guide. Readable offline: gripforge docs net-transport, or the MCP tool gripforge_docs (topic net-transport).

What it is for #

net.transport owns the configuration of the connection and the status shown to the player. The sync kits (net.state, net.claim, net.authoritative, net.rollback, net.async) ask it for a session and never open a socket themselves. It checks your settings against the table of the network core, fills in the defaults, and hands them to that core: the same Rust core in the browser, in Godot, Unity, Unreal and in the dedicated server. It draws nothing. A game has exactly one transport kit; installing any sync kit brings it in.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "net.transport" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "net.transport",
                              config: { "app": "my-game@1", "url": "wss://play.example.com/gfnet" } }

Write only the keys that differ from the defaults. gripforge kit api net.transport lists every key with its type and bounds.

First example #

<!-- test: kits/game_engine/host/tests/net_kits.rs::a_bad_transport_option_is_named_and_leaves_networking_off --> A wrong setting is named by its path, and networking stays off instead of running half configured:

{ "heartbeatMs": 5, "nope": true, "rate": { "burst": 0.5 } }

The log gets config.transport.heartbeatMs: expected >= 100, config.transport.nope: unknown property and config.transport.rate.burst: expected integer. The service still answers its defaults, and open fails with the same message.

Settings and defaults #

SettingDefaultMeaning
transportautoauto, websocket, webrtc, tcp_udp or enet. auto is the WebSocket on the web (WebRTC when a room is set)
roleclienthost (web only): the page runs the server and accepts the WebRTC clients of room
url""WebSocket address of the server; empty means the host of the page, path /gfnet
host, port, udpPort, path127.0.0.1, 27015, 0, /gfnetaddress of the server for native clients; udpPort 0 is announced by the server
signalUrl, room, iceServers"", "", a public STUN serverWebRTC signalling and relay servers; a production game needs its own TURN server
appgripforge-game@1application id and build: a client of another build is refused. Bump it when two builds can no longer play together
nameunsetplayer name sent in the handshake
fallbacktruenative auto: fall back to the WebSocket bridge when direct IP fails
maxPeers, maxPeersPerIp16, 8server capacity, and sessions per remote address (0 = no cap)
heartbeatMs, timeoutMs, resumeMs1000, 5000, 10000ping period, silence that loses a link, time a dropped peer keeps its id and slot
connectTimeoutMs, welcomeTimeoutMs, handshakeMs3000, 0 (auto), 5000connect, welcome and hello delays
maxMessageBytes, maxViolations65536, 20largest message; invalid messages tolerated before a peer is closed
rate120/s, burst 240, 262144 bytes/sper-peer limits (messagesPerSecond, burst, bytesPerSecond, bytesBurst)
reconnecton, 500 to 8000 ms, 10 tries, jitter 0.25client backoff (enabled, minMs, maxMs, maxTries, jitter); 0 tries is unlimited
relaylimits of the engine bridge (maxPayload, and its own rate)
eventQueueMax4096events kept unread before the oldest are dropped
trustForwardedForfalseread the client address from X-Forwarded-For; only behind a proxy you run

Constraints: heartbeatMs must be below timeoutMs; reconnect.minMs at most reconnect.maxMs; sendSoftBufferBytes at most sendHardBufferBytes; relay.maxPayload at most maxMessageBytes. Keys marked hot in gripforge kit api net.transport can change on a running session; the others apply at the next connection. The remaining keys tune the sockets of a server (listenHost, listenWebSocket, listenTcp, sniffMs, the pending-connection caps, the send buffers) and the direct-IP client (udpHelloMs, udpHelloTries, udpKeepaliveMs).

Services, events, variables #

  • net.transport (service): config() the settings with their defaults, app() the application id of the handshake, open(model, sync, extra?) a session for a sync kit, host(model, sync, physics?) and hosted() the in-page server (role: "host"), listen(callback) and unlisten(id) its events.
  • net.session (service): the session the sync kits plug into.
  • net.connected (event): { id, resumed, transport }, the welcome arrived.
  • net.disconnected (event): { reason, final }; final when no reconnection follows.
  • net.peer (event): { id, on }, another peer joined or left.
  • net.refused (event): { code, msg }, the handshake was refused (version, app, full, mods…).
  • net.overflow (event): { dropped, total, cap }, events were dropped past eventQueueMax.
  • net.status, net.rtt, net.peers (variables): connection state (idle, connecting, connected, reconnecting, closed), smoothed ping in ms, players online. Bind them to a HUD label.

Hooks and modding #

The kit declares no hook and no setting is open to mods: two machines of a match must agree on addresses, limits and rates. With mods applied, the application id sent in the handshake is app followed by ~mods.<fingerprint>, so a peer running other mods is refused with net.refused { code: "mods" }.

Engines #

The web uses WebSocket and WebRTC; Godot, Unity and Unreal use direct IP (tcp_udp; enet is treated as tcp_udp) with the WebSocket bridge as a fallback. role: "host" is available on the web only.

When it does not do what you expect #

  • Networking never starts and the log names config.transport.<key>: that setting is unknown or out of bounds; fix it.
  • open or host fails with a message about net.core: the host does not provide the network core, so no session can open.
  • net.refused with code app: client and server have different app values; with mods: their mods differ.
  • role: "host" without signalUrl and room accepts only the local player (a warning is logged).
  • host says the page already hosts another model: one in-page server per page.
  • per-connection overrides require role client: open was given transport overrides while role is host.

Limits #

No game rules, no matchmaking and no authentication: rooms, lobbies and logins belong to other kits. Rate limits are per peer, not per account. Direct IP needs an open port; the WebSocket bridge works through web proxies.

Versions #

Kit 1.3.1, protocol gfnet/1. 1.3 added the mods fingerprint to the handshake; 1.3.1 lets the caller of host choose the WebRTC room.