Skip to content

[GroundhogDay] Fix for Stardew Valley 1.6 - #244

Open
Setrilo wants to merge 5 commits into
aedenthorn:masterfrom
Setrilo:pr/groundhogday-1.6-fix
Open

[GroundhogDay] Fix for Stardew Valley 1.6#244
Setrilo wants to merge 5 commits into
aedenthorn:masterfrom
Setrilo:pr/groundhogday-1.6-fix

Conversation

@Setrilo

@Setrilo Setrilo commented Jul 13, 2026

Copy link
Copy Markdown

Summary

Groundhog Day stopped working on 1.6 - the calendar date advanced on sleep even with the mod enabled. Fixes, in order of how they were found:

  • The actual bug: the mod patched the private Game1._newDayAfterFade() iterator method with a Harmony prefix. That method is now just a 1-2 instruction stub (it constructs the compiler-generated state machine), small enough that the .NET 6 JIT inlines it at both call sites - which silently bypasses a Harmony patch on it (the patch "applies" with no error, but the prefix never runs). Patches the public Game1.newDayAfterFade(Action) wrapper instead, which has enough real logic that it can't be inlined, and always runs synchronously before the state machine's day-rollover logic does.
  • Updated the season check from the removed Game1.currentSeason string comparison to the Season enum (Game1.season).
  • Also freezes Game1.stats.DaysPlayed, not just the calendar - some scripted content (e.g. the vanilla earthquake event) is gated on total days played rather than the visible date, so it could still fire early after a couple of repeated sleeps with only the calendar frozen.
  • Also holds back Farmer.mailForTomorrow while the mod is enabled. Mail queued via any "AddMail ... tomorrow" trigger action (vanilla or a pack like Stardew Valley Extended) isn't keyed to a calendar date at all, so it was still arriving on every repeated day. It now queues up and delivers in full once the mod is toggled off.
  • Restricted the date rewind to the host (Context.IsMainPlayer) so a farmhand doesn't independently decrement its own copy of the date with nothing to cancel it back out.
  • Retargeted the project to net6.0 and bumped MinimumApiVersion to 4.0.0 for SMAPI/SDV 1.6.

All of the above was verified against a live 1.6.15 install (decompiled
the relevant Game1/Farmer/TriggerActionManager code to confirm each mechanism rather than guessing, and iterated based on in-game testing - including a Harmony patch that turned out not to actually fire at runtime despite applying without error).

Test plan

  • Builds against SDV 1.6.15 / SMAPI 4.5.2
  • Sleeping with the mod enabled no longer advances the date
  • Game1.stats.DaysPlayed-gated content no longer fires early
  • Mail queued via "tomorrow" trigger actions no longer arrives on repeated days
  • Confirmed in actual gameplay across multiple sleep cycles

Setrilo added 3 commits July 13, 2026 07:05
_newDayAfterFade still exists in 1.6.15 but the season is now the
Season enum, not a string, and the day-transition path is now a
multiplayer-synced coroutine. Update the patch to:

- Compare Game1.season against Season.Spring instead of the removed
  string comparison against Game1.currentSeason.
- Only rewind the calendar on the host (Context.IsMainPlayer); a
  farmhand decrementing its own dayOfMonth had nothing to cancel it
  back out and would just desync from the host's date.
- Log a clear error instead of letting Harmony throw if the private
  method target is ever missing in a future game update.
- Target net6.0 and bump MinimumApiVersion to 4.0.0 for SMAPI/SDV 1.6.

Credit to aedenthorn for the original mod (on hiatus; fixed per the
Nexus page's modification permissions).
…ze DaysPlayed too

The previous commit patched Game1._newDayAfterFade() directly. That
compiled fine and Harmony reported the patch as applied, but it never
actually ran in-game (confirmed with diagnostic logging): the method
is a 1-2 instruction iterator stub that just constructs the compiler-
generated state machine, and .NET 6's JIT inlines it at both of its
call sites, which bypasses a Harmony patch on it entirely.

Patch Game1.newDayAfterFade(Action) instead — the public method that
calls _newDayAfterFade(). It has enough real logic that it won't get
inlined, and it always runs synchronously before the day-rollover
logic does, so the same "decrement now, let the game's own increment
cancel it out" trick still applies at the right point in the sequence.

Also decrement Game1.stats.DaysPlayed alongside dayOfMonth. Some
scripted content (e.g. the vanilla earthquake event) is gated on total
days played rather than the calendar date, so with only dayOfMonth
frozen it could still fire early after a couple of repeated sleeps.

Confirmed in-game: the calendar date now stays put across multiple
sleeps with the mod enabled.
Mail queued via any "AddMail ... tomorrow" trigger action - a vanilla
mechanism also used by content mods like Stardew Valley Expanded -
isn't keyed to a calendar date at all. It's just a plain queue
(Farmer.mailForTomorrow) that Game1.ReceiveMailForTomorrow() drains
into the mailbox unconditionally on every sleep. Since our date freeze
only touches dayOfMonth/season/year/DaysPlayed, this queue was still
flushing in full on every repeated day, so "tomorrow"-scheduled mail
(vanilla or modded) would arrive on the very first loop instead of
waiting for the date to actually advance.

Prefix Game1.ReceiveMailForTomorrow(string) and skip the general
queue-flush call (the one with no argument) while the mod is enabled.
The game's own internal one-off calls with a specific mail key still
go through untouched. Queued mail keeps accumulating and gets
delivered once the mod is toggled off and a real day passes.

Not yet confirmed in-game - pending live test.
@Setrilo
Setrilo force-pushed the pr/groundhogday-1.6-fix branch from 7ff742b to 3e13f8c Compare July 13, 2026 14:06
Setrilo added a commit to Setrilo/aedenthorn that referenced this pull request Jul 13, 2026
Ports the fix from aedenthorn/StardewValleyMods#244:

- Patches Game1.newDayAfterFade(Action) instead of the private
  Game1._newDayAfterFade() iterator, which the .NET 6 JIT inlines at
  its call sites - silently bypassing a Harmony patch placed directly
  on it (confirmed via diagnostic logging that the original patch
  target never actually ran, despite Harmony reporting no error).
- Updated the season check from the removed Game1.currentSeason string
  to the Season enum.
- Also freezes Game1.stats.DaysPlayed, since some scripted content
  (e.g. the vanilla earthquake event) is gated on total days played
  rather than the visible calendar date.
- Also holds back Farmer.mailForTomorrow while the mod is enabled -
  mail queued via any "AddMail ... tomorrow" trigger action (vanilla
  or a content pack) isn't keyed to a calendar date at all, so it was
  arriving on every repeated day instead of waiting for the date to
  actually advance.
- Restricted the date rewind to the host (Context.IsMainPlayer) so a
  farmhand doesn't independently desync its own copy of the date.
- Retargeted to net6.0, bumped MinimumApiVersion to 4.0.0.

Verified against a live SDV 1.6.15 / SMAPI 4.5.2 install across
multiple sleep cycles, including the DaysPlayed and mailForTomorrow
edge cases.
Farmer.mailForTomorrow holds two different kinds of entries: plain
keys are visible letters, but keys suffixed with "%&NL&%" are silent,
permanent progress flags (e.g. "ccBoilerRoom" for a completed
Community Center room, "leoMoved" for Leo relocating from Ginger
Island) - not letters at all. The previous fix held back the entire
queue while the mod was enabled, which also blocked these flags from
ever landing in mailReceived.

That broke real progression: completing the Boiler Room bundles still
shows the overnight Junimo cutscene (that's decided by checking
mailForTomorrow directly, unaffected by this patch), but the minecarts
stayed "out of order" forever afterward, because the follow-up
permanent flag never actually got recorded while the mod was on.

Manually replicate the flag half of Game1.ReceiveMailForTomorrow's
loop before skipping the original: %&NL&%-suffixed entries always go
through immediately, and only plain (visible letter) entries continue
to be held back.
@Setrilo
Setrilo force-pushed the pr/groundhogday-1.6-fix branch from 3e13f8c to dfe897f Compare July 14, 2026 07:45
Some "arrives tomorrow" mail is a reward for something the player did
(e.g. "CarolineTea", the Tea Sapling recipe from Caroline's 2-heart
event) rather than being tied to a calendar-locked world event (like
the earlier Stardew Valley Expanded railroad letter, whose payoff
literally can't happen while the date is frozen). There's no general
way to tell these two cases apart in code - both use the exact same
"AddMail ... tomorrow" mechanism - so this is a small, manually
curated allowlist of mail keys that should always be delivered
immediately as normal visible letters, on top of the existing
%&NL&%-suffixed flag handling.
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.

1 participant