Files
shadow-over-bishkek001/WEBSOCKET_NETWORKING.md
T

158 lines
5.5 KiB
Markdown

# WebSocket Networking: First Iteration
## Scope
The first networking iteration adds a Windows-only WebSocket transport using
Boost.Asio and Boost.Beast.
The goal of this iteration is connection and replication stability. It does not
yet implement multiplayer commands, authentication, per-connection players,
state deltas, or presentation-event replication.
## Runtime Architecture
### Server
`WebsocketGameServer` wraps the headless `InternalGameServer`.
- It accepts any WebSocket connection.
- It sends the current complete game state immediately after connection.
- It broadcasts the current complete state every five seconds.
- Incoming WebSocket messages are read and discarded.
- The authoritative simulation remains on the main server thread.
- Network sessions only receive serialized state and never access
`InternalGameServer` directly.
The standalone server creates the existing fixed player ID `"player"` and does
not enable the battle-zone test bot.
### Client
`WebsocketGameClient` implements `IGameServer`.
- It connects asynchronously to `ws://127.0.0.1:8080/`.
- Received messages are queued by the network thread and applied on the game
thread from `update()`.
- It maintains an internal `InternalGameServer` replica so existing snapshot
consumers and transitional runtime-state bindings continue to work.
- Camera orientation lives in host-owned `LocationLocalState`, so incoming
authoritative snapshots cannot overwrite camera movement.
- `submit()` intentionally discards all commands.
- `drainEvents()` returns no events.
- Client-side save and load calls are ignored because persistence remains
server-side.
`RemoteGameServerHost` prepares local presentation resources and runtime
locations against the replicated state. It does not advance authoritative
simulation or write Lua/dialogue auxiliary state back to the server.
## Campaign Routing
The graphical game uses stable router objects for `IGameServer` and
`IGameServerHost`, allowing existing UI and runtime references to remain valid.
When `NETWORK` is defined:
- `battle_zone_multiplayer` uses `WebsocketGameClient` and `RemoteGameServerHost`.
- `main`, `battle_zone`, and every other campaign use `InternalGameServer` and
`LocalGameServerHost`.
The WebSocket client is created only when `battle_zone_multiplayer` is selected
and is destroyed when that campaign is unloaded. The single-player and
multiplayer Battle Zone entries share location content and the start-state path,
so the state can be regenerated through the single-player entry. At startup, the
standalone server loads the authoritative half of that shared save and rewrites
its campaign ID to `battle_zone_multiplayer`; each remote client restores only
the local presentation half.
If DNS resolution, TCP connection, the WebSocket handshake, or the active socket
fails, the client unloads the remote campaign and returns to the campaign
selection screen.
## JSON Protocol
Messages use a versioned JSON envelope:
```json
{
"protocolVersion": 1,
"type": "state",
"payload": {
"schemaVersion": 2
}
}
```
The payload uses the authoritative `GameState::save()` representation and excludes
the client-local location map, including camera orientation.
The client applies it through `InternalGameServer::load()`.
Malformed JSON, unsupported protocol versions, unsupported message types, and
invalid state payloads are logged and ignored.
Single-player persistence uses a separate envelope that combines this authoritative
document with client-local location state. The temporary full-state network format
is still expected to be replaced by a dedicated replication schema or deltas as
command handling and production replication are implemented.
## Build Configuration
Networking is enabled only for Windows:
- `proj-windows/CMakeLists.txt` defines `NETWORK`, compiles the WebSocket client
and remote host, and links `ws2_32` and `mswsock`.
- `server/CMakeLists.txt` defines `NETWORK` for the Windows `GameServer`, compiles
the WebSocket server, and links the Windows socket libraries.
- Linux, Android, and Web builds do not define `NETWORK` and do not compile the
network transport.
The previous Web-build `NETWORK` definition was removed.
## Running
Build the server:
```powershell
cmake -S server -B server/build
cmake --build server/build --config Debug --target GameServer
```
Run it from the repository root:
```powershell
.\server\build\Debug\GameServer.exe --campaign battle_zone_multiplayer --location uni_exterior
```
The listener defaults to `0.0.0.0:8080`. It can be changed with:
```text
--address IP
--port N
```
Launch the Windows game and select `battle_zone_multiplayer`. The client connects to
`127.0.0.1:8080`. Selecting another campaign continues to use the local server.
## Verification
The implementation was verified with:
- A successful Windows graphical-game build.
- A successful Windows headless-server build.
- Server state and protocol tests.
- A WebSocket smoke test receiving the initial state and the next five-second
broadcast.
- A check that the shared `"player"` exists and the battle-zone test bot is not
created for the network server.
## Current Limitations
- All clients share the fixed player ID `"player"`.
- Client commands are not sent to the server.
- The server does not process commands.
- State is sent as a complete snapshot rather than a delta.
- There is no authentication, authorization, reconnect loop, or session identity.
- Presentation events are not replicated.
- The endpoint is hardcoded in the graphical client.
- Multiplayer Lua and dialogue behavior remains unsupported.