Files
Commonwealth-Online-Public/protocol/world-state.md
T
andrew 99595ef87c Add host-authoritative world-state sync
Implement host-authoritative time/weather sync across server and clients. Adds a new worldState packet (and worldStateHost for host assignment) and server-side host tracking/reassignment to the lowest remaining playerId when the host disconnects. Plugin-side changes introduce F4T::WorldStateSync (new header + implementation), polling/apply hooks in the game-thread main loop, and Networking support to send/receive/parse worldState/worldStateHost packets. The server validates host-only sends, relays worldState to peers, broadcasts worldStateHost on host handoff, and augments logging/stats. Protocol and documentation files updated (protocol/world-state.md, docs/*) and server/fake_client.py extended to track/print host world-state snapshots.
2026-06-22 21:50:59 +12:00

78 lines
2.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# World State Packet
Host-authoritative time and weather sync for the Commonwealth Online prototype.
## Authority
- The server tracks a `worldStateHostPlayerId` for the session.
- The first connected client becomes host. When the host disconnects, the server
reassigns host to the lowest remaining `playerId` and broadcasts `worldStateHost`.
- Only the current host sends `worldState` packets.
- The Python relay validates the sender and broadcasts to all other clients.
Promoted hosts keep their already-synced local time and weather; reassignment should
not change world state for remaining clients.
## worldStateHost Packet
Sent in `welcome` (initial host) and broadcast when the host disconnects:
```json
{
"type": "worldStateHost",
"worldStateHostPlayerId": 2,
"serverTime": 1780212128.301
}
```
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | yes | Must be `"worldStateHost"` |
| `worldStateHostPlayerId` | integer | yes | Connected player ID that is now world-state host |
| `serverTime` | number (double) | no | Relay timestamp |
The `welcome` packet also includes optional `worldStateHostPlayerId` so new joiners
know the current host immediately.
## Packet Format
```json
{
"type": "worldState",
"playerId": 1,
"gameHour": 14.25,
"gameDaysPassed": 12.5,
"weatherFormId": "00123456",
"clientTime": 1780212128.301,
"serverTime": 1780212128.301
}
```
## Field Definitions
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `type` | string | yes | Must be `"worldState"` |
| `playerId` | integer | yes (server) | Injected by server; identifies the sending host |
| `gameHour` | number (float) | yes | In-game hour of day, `0.0``24.0` |
| `gameDaysPassed` | number (float) | yes | In-game days passed global |
| `weatherFormId` | string | no | 8-character hex `TESWeather` form ID; omitted or `""` when host is indoors |
| `clientTime` | number (double) | no | Sender Unix epoch seconds |
| `serverTime` | number (double) | no | Relay timestamp added by server |
## Send Cadence (Host)
- About 1 Hz heartbeat while connected
- Immediate send when `weatherFormId` changes
- Immediate send when `gameHour` or `gameDaysPassed` jumps beyond a small threshold (wait, sleep, console time changes)
## Client Apply Rules
- **Time:** non-host clients snap local calendar globals when host values differ beyond threshold.
- **Weather:** non-host clients apply forced weather only when the local player is in an exterior cell.
- Missing optional fields use safe defaults on receive.
## Backward Compatibility
Older clients that do not send or parse `worldState` continue to work. Transform sync is unchanged.