FAForever / FAForever/server

Custom game hosting: server accepts `game_host` but never acts on the `GameState Lobby` relay — game stays closed/hosted_at:null, no HostGame sent

Offen
#1,099 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
Vorherrschende Sprache
Python
Sterne
72
Forks
84
Ø Merge
5 Std. 11 Min.
Gemergte PRs (30 T.)
1

Beschreibung

## Summary

Hosting (and joining) custom games fails: the client hangs at "connecting" forever. Matchmaker games work normally.

With client TRACE logging enabled I captured the full lobby protocol in plaintext. The client sends `{"command":"GameState","args":["Lobby"],"target":"game"}` correctly, the websocket is demonstrably healthy in both directions, but the server never responds with `HostGame` and never transitions the game out of `state: closed` / `hosted_at: null`.

Because this only affects `init_mode: 0` (custom) games and **not** matchmaker (`init_mode: 1`, which does not require the server→client `HostGame`/`JoinGame` GPGNet command), the problem is isolated to the server's handling of the `GameState Lobby` relay for custom games.

## Environment

- Client version: `2026.4.1` (`downlords-faf-client`)
- Affected accounts: `RaidenBoson` (id `454005`) and `ASoft` (id `450602`)
- Reproduced on **two different machines**, on **two different accounts**, and **over a VPN** (entirely different network path)
- Windows 11

## Reproduction

Click "Create Game" with any map/settings. The game launches, reaches `GameState Lobby`, and the lobby never opens.

## Captured protocol trace

Third of three consecutive attempts (client `logLevel: TRACE`). Tokens are masked by the client itself.

```
00:47:02.314 Outbound: {"command":"game_host","mapname":"dualgap_adaptive.v0014","title":"Chill Game",
"mod":"faf","options":[],"access":"public","version":0,"password":null,
"visibility":"public","rating_min":null,"rating_max":null,
"enforce_rating_range":false}

00:47:02.437 Inbound: {"command":"game_launch","args":["/numgames",814],"uid":27459407,"mod":"faf",
"name":"Chill Game","init_mode":0,"game_type":"custom","rating_type":"global"}

00:47:03.147 Inbound: {"command":"game_info","uid":27459407,"title":"Chill Game","state":"closed",
"mapname":"dualgap_adaptive.v0014","host":"RaidenBoson","num_players":0,
"max_players":12,"hosted_at":null,"launched_at":null,"teams":{}}

00:47:35.902 Outbound: {"command":"GameState","args":["Idle"],"target":"game"}
00:47:36.116 Outbound: {"command":"GameState","args":["Lobby"],"target":"game"}

(no HostGame; no further game_info for uid 27459407, ever)
```

The client-side emit is complete — the message is serialized and written, not dropped internally:

```
00:47:36.116 TRACE c.f.commons.lobby.FafLobbyClient : Sending message of type class com.faforever.commons.lobby.GpgGameOutboundMessage
00:47:36.116 TRACE c.f.commons.lobby.FafLobbyClient : Outbound message: {"command":"GameState","args":["Lobby"],"target":"game"}
```

## The connection is healthy — this is not a dropped message

Counting inbound/outbound traffic **after** the `GameState Lobby` relay at 00:47:36, over the following ~6 minutes on the same websocket:

| Message | Count |
|---|---|
| `game_info` (other players' games) | 503 |
| `player_info` | 145 |
| `matchmaker_info` | 43 |
| `ping` (server → client) | 8 |
| `pong` (client → server) | 8 |
| **`game_info` for our own uid 27459407** | **0** |

The server keeps pinging and the client keeps ponging, and the session is never timed out — so client→server frames **are** reaching the server. The server simply never acts on the `GameState Lobby` message and never broadcasts another update for the game it just created.

## What has been ruled out

**Request contents.** Three consecutive attempts varying `game_host` fields, all failing identically:

1. `astro_crater_battles_4x4_rich_huge.v0004`, `rating_min: 900`, `rating_max: 3000`, `enforce_rating_range: true`
2. `astro_crater_battles_4x4_rich_huge_by_lisnesta.v0004`, same rating settings
3. `dualgap_adaptive.v0014`, `rating_min: null`, `rating_max: null`, `enforce_rating_range: false`

All three maps are installed locally, and `dualgap_adaptive.v0014` was being used by 69 other open games at the time.

**Client side.** The TRACE capture shows correct serialization and emission of `GpgGameOutboundMessage`.

**ICE adapter.** Connects, sends `CreateLobby`, receives `GameState Lobby` from the game, and relays it to the client correctly:

```
Sent GPGNet message: CreateLobby 0 42410 RaidenBoson 454005 1
Received GPGNet message: GameState Lobby
Sending Notification: {"method":"onGpgNetMessageReceived","params":["GameState",["Lobby"]],"jsonrpc":"2.0"}
```

**Network / local environment.** Matchmaker games work over the identical websocket, TLS session, ICE adapter and TURN relay. Also independently checked and excluded: DNS, MTU/PMTU, IPv6, packet loss, firewall, antivirus, Windows port reservations, ephemeral port exhaustion, and stale/zombie game processes. A clean client reinstall did not help.

**Account / machine.** Two accounts, two machines, and a VPN all reproduce it.

## Failure occurs in windows, not at random

Hourly attempt/success counts for one day, taken from `ice-adapter.log` by counting `Sent GPGNet message: CreateLobby` (attempt) against `Sent GPGNet message: HostGame` (server responded):

| Hour | Attempts | Successes |
|---|---|---|
| 00 | 11 | 6 |
| 01 | 10 | 0 |
| 02 | 1 | 0 |
| 03 | 9 | 0 |
| 04 | 1 | 0 |
| 11 | 6 | 0 |
| 12 | 10 | 0 |
| 13 | 34 | 8 |
| 14 | 12 | 0 |
| 18 | 2 | 0 |
| 19 | 13 | 0 |
| 20 | 10 | 1 |
| 21 | 14 | 0 |
| 22 | 7 | 0 |
| 23 | 5 | 1 |

Inside a working window, `CreateLobby` and `HostGame` land in the **same second**, repeatedly. Outside one, it is 100% failure for hours. Nothing changes client-side across those boundaries.

Lifetime totals across all available logs: **266 custom-game attempts → 41 `HostGame` + 9 `JoinGame` returned.**

## Speculation

The windowed pattern would be consistent with the lobby connection being balanced across multiple server instances, where some instances have stuck or broken game-service state — leaving a client bound to a bad instance for the life of the websocket connection. I have no visibility into the server side to confirm this.

## Happy to provide

Full TRACE `client.log`, `ice-adapter.log`, and game logs for any of the affected game UIDs (`27459347`, `27459382`, `27459407`) on request.

Beitragsleitfaden

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.