Event-driven world time sync (timeSync flag)

Introduce an optional timeSync field and event-driven time pushes so host time is only re-applied on connect, resume-from-freeze, or large jumps while weather continues on ~1 Hz heartbeats. Added IsGameTimeFrozen detection and client buffering of latest host time; clients apply host time only when timeSync is true or when gameplay just resumed. Updated networking to read/write timeSync, adjusted F4TWorldStateSync logic (separate time vs weather send/apply paths, changed function signatures and behavior), and updated protocol/docs/changelog and fake_client logging to reflect the new field and behavior.
This commit is contained in:
2026-06-23 15:55:05 +12:00
parent 87a264da80
commit 70933db6e5
10 changed files with 185 additions and 41 deletions
+9 -4
View File
@@ -43,6 +43,7 @@ know the current host immediately.
"gameHour": 14.25,
"gameDaysPassed": 12.5,
"weatherFormId": "00123456",
"timeSync": true,
"clientTime": 1780212128.301,
"serverTime": 1780212128.301
}
@@ -57,18 +58,22 @@ know the current host immediately.
| `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 |
| `timeSync` | boolean | no | When `true`, non-host clients should apply `gameHour` and `gameDaysPassed`. Omitted or `false` on weather-only heartbeats. |
| `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)
- About 1 Hz heartbeat for **weather** while connected (`timeSync` omitted or `false`)
- Immediate send with `timeSync: true` when:
- First connected or promoted to host
- Game time resumes after a freeze (menus, pip-boy, dialogue, loading screens, save/load, wait/sleep)
- `gameHour` or `gameDaysPassed` jumps beyond a small threshold (wait, sleep, console time changes)
- Immediate send when `weatherFormId` changes (includes current time fields; sets `timeSync` only when time also changed or on resume)
## Client Apply Rules
- **Time:** non-host clients snap local calendar globals when host values differ beyond threshold.
- **Time:** non-host clients track the latest host time from every packet but only snap local calendar globals when `timeSync` is `true` and gameplay time is not frozen, or immediately when gameplay time resumes after a freeze (using the latest stored host values).
- **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.