sky(phase-3d): fix time drift — WorldTime.TickSize is always 1.0

User reported the in-game sky time in acdream consistently trails
retail's, even after Phases 3a-3c.1 aligned the DayGroup selection.
Diagnosed it as a rate mismatch between our client-side extrapolation
and the ACE server's tick advancement.

ACE advances PortalYearTicks at 1.0 ticks per real-second:
  Timers.cs:  PortalYearTicks += worldTickTimer.Elapsed.TotalSeconds

Our WorldTime was using SkyDesc.TickSize (0.8 in the live Dereth dat)
as the extrapolation rate:
  NowTicks = lastSync + elapsed * TickSize   // with TickSize=0.8

Between the server's ~20s TimeSync gap, we fell 4 ticks behind. Every
sync yanked us back, but in the window between syncs the sky interp
was rendering at a stale (earlier) dayFraction — visible as "acdream
is behind retail" when the user had retail running alongside.

Root cause: we misread r12 §1.2's definition of SkyDesc.TickSize.
Agent C's decompile (`docs/research/2026-04-23-sky-decompile-hunt-C.md`
§5 and the 2026-04-23 sky-retail-verbatim synthesis §5) showed
SkyDesc.TickSize is consulted at `FUN_005062e0:6241` as:

  _DAT_00842798 = SkyDesc.TickSize + _DAT_008379a8   // next deadline

i.e. the per-frame sky-subsystem update PERIOD. It's a throttle, not a
clock-rate multiplier. SkyDesc.LightTickSize=15 plays the same role for
lighting interpolation (re-run every 15 real-seconds).

Fix: remove the SkyDesc.TickSize → WorldTime.TickSize assignment. Keep
WorldTime.TickSize at its default 1.0, matching the server's rate.
SkyDesc.TickSize stays on the LoadedSkyDesc for a future Phase 4 port
of the actual retail throttle logic.

Build + 717 tests green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-04-24 09:25:03 +02:00
parent f466c337ce
commit 75ad74e0b3

View file

@ -877,10 +877,26 @@ public sealed class GameWindow : IDisposable
_loadedSkyDesc = AcDream.Core.World.SkyDescLoader.LoadFromRegion(region);
if (_loadedSkyDesc is not null)
{
WorldTime.TickSize = _loadedSkyDesc.TickSize > 0 ? _loadedSkyDesc.TickSize : 1.0;
// Phase 3d: do NOT assign WorldTime.TickSize from
// SkyDesc.TickSize. Agent C's decompile (chunk_00500000.c:6241
// FUN_005062e0) shows SkyDesc.TickSize is the "next sky-tick
// deadline" period — a throttle — NOT a game-time
// advancement rate. ACE's server advances PortalYearTicks at
// 1.0 ticks per real-second (Timers.cs: `PortalYearTicks +=
// worldTickTimer.Elapsed.TotalSeconds`). Our client
// extrapolation between TimeSyncs must match: 1.0.
//
// Previous behavior: WorldTime.TickSize = 0.8 (from the live
// SkyDesc.TickSize). Between ~20s TimeSync gaps we fell 4
// ticks behind the server, producing a visible "acdream sky
// is behind retail" time-of-day mismatch (user-verified
// 2026-04-23).
WorldTime.TickSize = 1.0;
Console.WriteLine(
$"sky: loaded Region 0x13000000 — {_loadedSkyDesc.DayGroups.Count} day groups, " +
$"TickSize={_loadedSkyDesc.TickSize}, LightTickSize={_loadedSkyDesc.LightTickSize}");
$"SkyDesc.TickSize={_loadedSkyDesc.TickSize} (throttle, not rate), " +
$"LightTickSize={_loadedSkyDesc.LightTickSize}");
// Initial DayGroup roll using whatever WorldTime currently
// has (either the hardcoded boot seed or a pre-arrived