Festival Handling
How the always-on server gets the host into and out of in-game festivals without a human present. The logic lives in AlwaysOnServerFestivals and deliberately mirrors the game's own DedicatedServer: monitor ready-checks, warp/answer via public entry points, no reflection-driven reinvention. The manual reproduction steps are in the festival testing runbook.
Lifecycle
A festival day runs through four phases, each driven from a per-tick or per-second handler in AlwaysOn:
Enter —
HandleFestivalStart(per tick). WhenGame1.whereIsTodaysFestis set and thefestivalStartready-check shows every player except the host is ready, the host marks itself ready (so clients' "Waiting for players…" dialog clears) and warps to the festival. Once warped,BeginActiveFestivalrecords which festival is active.Main event —
HandleFestivalEvents(per second), for festivals that have one. It announces a countdown in chat, and when the countdown elapses the host answers the festival host's "start the event?" dialogue. The!eventchat command short-circuits the countdown and starts immediately.Leave —
HandleFestivalLeave(per tick). The host ends the festival for everyone in two cases, both matching the game's dedicated host: when thefestivalEndready-check shows every remaining player is ready to leave (viaTryStartEndFestivalDialogue, the ReadyCheckDialog flow players expect when they vote to leave), or immediately once the last player has left so the host isn't stranded (viaforceEndFestival, which ends without a dialog). Either way the game's own exit path warps every player home.Reset —
UpdateFestivalStatus(on time change). In-game time is frozen while a festival event is active, so this runs only after the festival has ended and time resumes: once it passes the festival's window, active-festival state is cleared. It is deliberately not gated on connected players, so a festival that ended with nobody present still clears its state instead of poisoning the next festival.
Ready-check formula
"Everyone except the host is ready" is numberReady >= GetNumberRequired(check) - 1 && !IsReady(check) && numberReady > 0, matching DedicatedServer.CheckOthersReady. The same formula gates both festivalStart (warp in) and festivalEnd (leave). See .claude/rules/host-automation.md item 2 for why variants break specific transports.
Timeout backstop
Players drive entry and exit, but an AFK festival where no one votes to leave would otherwise stay open until its time window closes. RunFestivalTimeout is the wall-clock backstop: after *TimeOut elapses it warns players (FestivalExitWarningSeconds before the deadline) and then ends the festival directly via forceEndFestival, which warps every player home (and the host) with their connections intact — the same exit the game uses for a player-voted end. It does not disconnect anyone or take the server offline; a new client can still join afterward. There is no fixed "dwell then auto-leave" timer for leave-only festivals; they end on the festivalEnd ready-check, the no-players path, or this backstop — nothing in between.
Per-festival reference
Two shapes:
- Main event — the host warps in, runs a countdown, and starts a host-triggered event (egg hunt, grange judging, soup tasting, etc.).
- Leave-only — no host-triggered event; the host just waits for the
festivalEndready-check (or the timeout). Spirit's Eve and the Feast of Winter Star are the only two.
No festival auto-ends on its own. Every festival, main-event or leave-only — the Stardew Valley Fair included — ends on the festivalEnd ready-check (a player votes to leave, or the last player leaves) or on the timeout backstop. This mirrors the game's own DedicatedServer, which ends festivals only via CheckOthersReady("festivalEnd") or the no-players path and never auto-ends the Fair.
| Festival | Date | Shape | Countdown (default) | Timeout (default) |
|---|---|---|---|---|
| Egg Festival | Spring 13 | Main event | 5 min | ~33 min |
| Flower Dance | Spring 24 | Main event | 5 min | ~33 min |
| Luau | Summer 11 | Main event (adds iridium starfruit to the soup) | 5 min | ~33 min |
| Dance of the Moonlight Jellies | Summer 28 | Main event | 5 min | ~33 min |
| Stardew Valley Fair | Fall 16 | Main event | 5 min | ~33 min |
| Spirit's Eve | Fall 27 | Leave-only | — | ~33 min |
| Festival of Ice | Winter 8 | Main event | 5 min | ~33 min |
| Feast of the Winter Star | Winter 25 | Leave-only | — | ~33 min |
All durations are operator-tunable via AlwaysOnConfig: the *CountdownSeconds knobs (seconds) and the *TimeOut knobs (ticks at 60 TPS, so 120000 ≈ 2000 s ≈ 33 min). Most main-event timeouts start counting once the event begins; leave-only festivals and the Fair start theirs on entry.
Why no fixed auto-end for leave-only festivals
The game's dedicated host never auto-leaves a festival on a fixed dwell timer — it leaves on the festivalEnd ready-check, or immediately once no players remain. The server matches that exactly. A short fixed "dwell then leave" timer would be a second wall-clock timeout layered on top of the existing AFK backstop, so it is deliberately absent.