The server owns time of day and weather; the clock stands still unless the server runs it
Status: Accepted (2026-06-24)
Context
A player should enter the world the server defines, not whatever default the client happens to start with. Time of day and weather are the two global parts of that presentation. "The server owns the time" can mean three things: the server sets the time once on join and lets each client's clock tick on its own; the server sets the time and the client holds it; or the server streams its clock to every client continuously. The first drifts: two players who joined at different moments see different times, so the time is not global. The third costs a continuous channel for a value the client can compute itself.
Interior and virtual world are not part of this presentation: they decide what a player sees, not how the world looks, and are covered by ADR 0035.
Decision
One global clock policy per server, held by the server. It has three modes:
- frozen (the default, at 12:00): the time stands still;
- running: the clock advances from an anchor time at a server rate of
minute_msreal milliseconds per game minute (10..=3 600 000; 1000 is the game's own pace); - realtime: the server's wall clock at a fixed UTC offset (UTC-12:00..UTC+14:00, no daylight saving), at one game minute per real minute.
The server computes the current time on demand from the anchor; nothing ticks on the server.
The client holds or runs the clock as told, never by itself. ServerHello carries the current time of the global clock. A frozen clock is held at that time; SetTime freezes it at another one. A running or realtime clock is sent as RunClock: on connect, on a change of mode or rate (critical), and as a periodic resync every 45 s (droppable, since the next one replaces a lost one). Between resyncs the client runs its own clock at the server rate and corrects drift on each resync. A frozen clock needs no resync, so freezing it sends
SetTimeto everyone as critical.Weather is forced and held. The world's initial weather (id 1, clear) travels in
ServerHello. The client has no weather cycle of its own: it switches to the weather it was given and keeps it.Per-player overrides are one-off packets the server does not store.
Player:set_timeandPlayer:set_weathersend SetTime and SetWeather to one player. A per-player time lasts while the global clock is frozen; a running global clock resets every client at its next resync, by design. The server validates hours0..=23, minutes0..=59and weather ids0..=22(the complete set the game has); the client decoder rejects anything else.The client hides the game's HUD clock. The time on screen is server policy, and a game clock that pretends to run on its own would mislead.
Consequences
- Every client shows the same time and weather without a continuous stream: the steady cost is one small packet per player every 45 s, and only while the clock runs.
- A rejoining or late player gets the exact current time in
ServerHello, and the running clock on connect. - Per-player time and weather survive no reconnect: the game mode sends them again after a join if it wants them.
- Per-player running clocks and persisting the clock across restarts are not provided.
- The global clock modes are server facade operations (
run_clock,freeze_clock,realtime_clockinsrc/sdk.rs); resources currently reach only the per-player setters.
Alternatives considered
- Set the time once on join and let the client clock tick. Clients drift apart; the time is not global.
- Stream the server clock continuously. A heavy per-frame channel for a value the client computes from an anchor and a rate; rare resyncs fix the drift instead.
- A separate world-defaults packet at join. The join already has a packet for server-wide configuration,
ServerHello; changes after the join have packets of their own.
