⚠️ The latest release is unstable. Use preview builds instead
Skip to content

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:

  1. EnterHandleFestivalStart (per tick). When Game1.whereIsTodaysFest is set and the festivalStart ready-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, BeginActiveFestival records which festival is active.

  2. Main eventHandleFestivalEvents (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 !event chat command short-circuits the countdown and starts immediately.

  3. LeaveHandleFestivalLeave (per tick). The host ends the festival for everyone in two cases, both matching the game's dedicated host: when the festivalEnd ready-check shows every remaining player is ready to leave (via TryStartEndFestivalDialogue, the ReadyCheckDialog flow players expect when they vote to leave), or immediately once the last player has left so the host isn't stranded (via forceEndFestival, which ends without a dialog). Either way the game's own exit path warps every player home.

  4. ResetUpdateFestivalStatus (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 festivalEnd ready-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.

FestivalDateShapeCountdown (default)Timeout (default)
Egg FestivalSpring 13Main event5 min~33 min
Flower DanceSpring 24Main event5 min~33 min
LuauSummer 11Main event (adds iridium starfruit to the soup)5 min~33 min
Dance of the Moonlight JelliesSummer 28Main event5 min~33 min
Stardew Valley FairFall 16Main event5 min~33 min
Spirit's EveFall 27Leave-only~33 min
Festival of IceWinter 8Main event5 min~33 min
Feast of the Winter StarWinter 25Leave-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.

Released under the MIT License.