Skip to content

[game] Keep world time in retail milliseconds - #324

Merged
Eldbury merged 1 commit into
modawan:masterfrom
Eldbury:fix/world-time-real-rate
Aug 25, 2026
Merged

[game] Keep world time in retail milliseconds#324
Eldbury merged 1 commit into
modawan:masterfrom
Eldbury:fix/world-time-real-rate

Conversation

@Eldbury

@Eldbury Eldbury commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fix world time issue resulting in NPC apparent flickering/warping.

  • Mod_MinPerHour now controls day length instead of clock speed
  • use absolute world milliseconds for runtime timing, forced-move deadlines, and restored events
  • preserve retail save fields and normalize legacy/unnormalized times on save

This fixes the 30x-fast clock on normal Mod_MinPerHour = 2 modules, including Dantooine ambient NPCs timing out and teleporting between waypoints.

Testing

  • Added world-time, save/load, forced-move, event-queue, and legacy-time regression coverage
  • Verified in K1: ambient NPCs walk normally between waypoints

@Eldbury
Eldbury force-pushed the fix/world-time-real-rate branch from 46e19df to ee42f3f Compare August 25, 2026 00:20
Comment thread doc/world-time-clock-rate.md Outdated
Comment thread src/libs/game/action/movetolocation.cpp Outdated
Mod_MinPerHour shortens the game day; it does not accelerate the clock.
CWorldTimer accumulates elapsed time and derives the day boundary from
m_nMillisecondsInDay = MinutesPerHour * 60 * 1000 * HOURS_IN_DAY, so one
world-time millisecond is one millisecond of simulation.

Reone instead kept a fixed 24-hour day and advanced the counter at
60 / Mod_MinPerHour times that rate. Durations measured against it were
short by that factor: exactly 30.00x on the 113 K1 and 82 K2 modules that
ship Mod_MinPerHour = 2, so a scripted 30 second ActionForceMoveToObject
timeout expired in one second and teleported ambient NPCs between
waypoints instead of letting them walk.

Make absolute world milliseconds the canonical runtime clock. Calendar
day and time of day remain first-class, but derived: they are composed
from the retail pair when loading and split back out when saving, and
nothing rebuilds a calendar per frame. Forced-move deadlines and restored
event-queue due times become absolute timestamps at those boundaries too;
the queue previously compared day and time of day lexicographically,
which fires an unnormalized record a whole day early.

Retail day lengths genuinely differ between modules - K1 ships danm14aa
at Mod_MinPerHour = 1 and danm14ab through danm14ad at 0 - so a stored
day/time pair is only meaningful alongside the day length that produced
it. An absolute clock cannot be displaced by rescaling the calendar.

Saved records stay in retail shape and no migration is needed. A time of
day larger than the current day length is unnormalized rather than
invalid: it carries into later days on load, as CWorldTimer::GetWorldTime
treats it, and is normalized again on the next save.
@Eldbury
Eldbury force-pushed the fix/world-time-real-rate branch from ee42f3f to c703d5b Compare August 25, 2026 10:15
@Eldbury
Eldbury merged commit 8a27b76 into modawan:master Aug 25, 2026
2 checks passed
@Eldbury
Eldbury deleted the fix/world-time-real-rate branch August 25, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants