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

2.7 KiB
Raw Blame History

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:

{
  "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

{
  "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.024.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.