fix(vi): the time of day passes again above a 60 fps cap #2093
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!2093
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/time-of-day-clock"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Above a Frame rate cap of 60, the time of day runs slow and above 120 fps it stops: the sun swings back and forth over a frozen hour. This is another of the above-60 side effects tracked in #1742.
Builds on #2006 (merged): it adds a site to that PR's
hos_frame_wholetable, next to #2409's water ripples. Rebased onto main, so it is one commit.Cause
Since #1612, above a 60 cap the game's frame step is the frame's own time (0.42 at 144 fps instead of 1).
The time of day is kept by
f_803edf70:(int)(2 * step)game seconds (+60) to the seconds of the day (+40). At 86400 those wrap and carry into the day count (+44).Fix
f_803edf70joinsWHOLE_SITESinnx2/oot_patches.py. Its cut goes throughhos_frame_whole, keyed by the clock's+60. Above a 60 cap that carries the fraction between frames, so the clock gains its 120 game seconds per real second at any frame rate.x8a second time, in the branch that sets the time from another source. So the anchor is the cut plus the store to+60after it, and the other cut is left alone (a test covers this).How it was found
Tests
tests/test_frame_whole.py:2 × 60/144make 120 seconds, a real second's worth at 60.x8, in the branch that sets the time from another source, is left as the game's.python -I -B tests/run_all.pyafter the rebase onto8568959d: 404 passed, 13 failed. All 13 fail the same way on a clean checkout of that main on this PC (which fails two more besides), so none come from this PR.🤖 Generated with Claude Code
Read the new commit (7bc9019) against the patched function; looks good to me.
Relation to #2006: this is a clean stack, not a copy. The first three commits are #2006's approved head (
3bf6dcf) unchanged, and this PR adds only aWHOLE_SITESentry, the warning text and a test.host/frame_whole.handhos_frame_wholearen't duplicated anywhere. Merge #2006 first. The repo uses merge commits, so after that this PR shrinks to its one commit with no conflict. If #2006 gets more commits, rebase this on top.The fix: the anchored cut is the one that matters. It's
(int)(step + step)stored to+60, and the rest of the clock (the seconds of the day in+40, wrapping at 86400 into+44, and the values derived from them) is built from that integer. So carrying the fraction at that one cut keeps the whole clock consistent. The rates I checked:hos_frame_seconds_bitsis 0, soframe_wholetakes the plain cut. That's the game's own behaviour, bit for bit.realtime_stepfloors the step at 1/240 s, so the clock runs fast along with everything else the step drives. That's already the case on main and isn't caused by this PR.+60right after the store when the clock is stopped. The remainder still moves on those frames, but it stays under 1, so there's no catch-up jump when the clock starts again.!(amount > 0)returns 0 and leaves the remainder alone.+40directly, and the leftover remainder (under 1 game second) doesn't matter there.CI: still running. The only red check so far is actionlint, on
.github/workflows/linux-appimage.yml:163(SC2012). That comes from main's workflow and this PR doesn't touch it. #2006's run was green apart from the known Windows timing test.Nit on the wording only, see inline.
Nit: as far as I can tell the other
x8cut isn't the minutes. It sits in the branch that sets the time from another source. The minutes come from the integer in+60, so they're already covered by this cut. The anchor (cut + store to+60) is still the right one, so this is just the wording here, in the test and in the PR text.Heads-up: this conflicts with main now. Could you rebase onto main and resolve the conflicts? Thanks!
This isn't on main yet (
f_803edf70isn't inWHOLE_SITES), and it doesn't overlap #2470. That draft handles the sound job, the physics solver steps and the quick menu, and doesn't touch the clock orWHOLE_SITES, so the two only meet as nearby text innx2/oot_patches.pyandhost/nn_vi.c.With #2006 merged, the conflict is small but has to be resolved by hand. #2409 (water ripples) added
f_800672e0toWHOLE_SITESand its comment list, and raisedFRAME_WHOLE_SLOTSinhost/frame_whole.hfrom 16 to 64 (each water surface takes a slot). Keep both sites and main's 64 slots and slot comment: going back to 16 would bring the ripple freeze back in busy scenes.tests/test_frame_whole.pyis an add/add conflict, so merge your rate and minutes-cut checks into main's version rather than replacing it.apply()in oot_patches.py also picked upheap_sitesfrom #2451, so that hunk should keep main's line. After the rebase, hckrman101's approval should still hold, as long as the warning count innn_vi.cincludes both new sites.Rebased onto main (
8568959d): the PR is now its one commit (087ba5dd).f_800672e0site is kept next to the clock's inWHOLE_SITES, with both comment entries;FRAME_WHOLE_SLOTSstays at main's 64 (this PR doesn't touchhost/frame_whole.h);tests/test_frame_whole.pymerged with main's version, so the ripple checks and the clock's rate and other-cut checks are all there;apply()is main's;x8is in the block atL_803ee05c, taken on bit 25 of the flags, and the minutes are read later from+60. The patch's comment, the test and the PR text now say "in the branch that sets the time from another source".test_frame_whole.pypasses. In the full run, all 13 failures fail the same way on a clean checkout of main here, which fails two more besides.github-sync referenced this pull request2026-11-12 06:22:54 +00:00