mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-01 18:22:01 +00:00
Reduce lobby broadcast bandwidth via counts-only deltas (#4116)
## Description:
- The lobby WebSocket broadcast (`/lobbies`) was re-sending the full
`PublicGames` snapshot — including each lobby's `gameConfig` — to every
connected client every 500ms. Almost nothing in that payload changes
tick-to-tick; only `numClients` moves.
- `WorkerLobbyService` now tracks the sorted set of `gameID`s it last
sent as a full snapshot. On each incoming broadcast it sends a `full`
only when that set changes; otherwise it sends a `counts` delta carrying
just `{gameID → numClients}`.
- This relies on the master-side coupling at
[MasterLobbyService.ts:140-159](src/server/MasterLobbyService.ts#L140-L159):
when master finds a lobby without `startsAt`, it both sets `startsAt`
AND schedules a fresh lobby on the same tick, so the gameID change
brings the `startsAt` (and `gameConfig`) along with it.
- New WS connections are primed with the worker's cached last `full` so
late joiners don't have to wait for the next structural change.
- `LobbySocket` parses the new discriminated union (`PublicLobbyMessage
= full | counts`), keeps the last full snapshot in memory, and merges
counts into it before invoking the existing callback. `GameModeSelector`
is unchanged.
- Master → worker IPC is unchanged — still sends the full snapshot every
500ms. The optimization only applies to the worker → WS-client boundary,
which is the fan-out point.
## Please complete the following:
- [x] I have added screenshots for all UI updates
- [x] I process any text displayed to the user through translateText()
and I've added it to the en.json file
- [x] I have added relevant tests to the test directory
## Please put your Discord username so you can be contacted if a bug or
regression is found:
evan
This commit is contained in:
@@ -183,6 +183,28 @@ export const PublicGamesSchema = z.object({
|
||||
games: z.record(PublicGameTypeSchema, z.array(PublicGameInfoSchema)),
|
||||
});
|
||||
|
||||
// Wire message sent from server to lobby WebSocket clients.
|
||||
// "full" carries the complete snapshot; "counts" carries only the
|
||||
// per-lobby player counts, which change far more often than the rest.
|
||||
export const PublicLobbyFullSchema = z.object({
|
||||
type: z.literal("full"),
|
||||
serverTime: z.number(),
|
||||
games: z.record(PublicGameTypeSchema, z.array(PublicGameInfoSchema)),
|
||||
});
|
||||
|
||||
export const PublicLobbyCountsSchema = z.object({
|
||||
type: z.literal("counts"),
|
||||
serverTime: z.number(),
|
||||
counts: z.record(z.string(), z.number()),
|
||||
});
|
||||
|
||||
export const PublicLobbyMessageSchema = z.discriminatedUnion("type", [
|
||||
PublicLobbyFullSchema,
|
||||
PublicLobbyCountsSchema,
|
||||
]);
|
||||
|
||||
export type PublicLobbyMessage = z.infer<typeof PublicLobbyMessageSchema>;
|
||||
|
||||
export class LobbyInfoEvent implements GameEvent {
|
||||
constructor(
|
||||
public lobby: GameInfo,
|
||||
|
||||
Reference in New Issue
Block a user