The calendar pitch for this slot said “what a 30-day season does to player behavior — 3 seasons of data.” Honest correction up front: the game has been live for weeks, not months, and there are no three seasons of player data to analyze yet. What exists is the season system itself — and the design is interesting enough to stand on its own. This is that post.
The clock that needs no state
SeasonService.luau defines a season as exactly 30 days of wall-clock time, anchored to the unix epoch. Season index = floor(now / 30 days) + 1. That is the whole trick: because the boundary is derived from time itself, two servers always agree on which season it is without syncing anything, and the current season needs zero stored state. A fresh server and a six-month-old server compute the same answer from the same timestamp.
Each season gets a flavor name from a deterministic rotation — Season of the Convergence, Season of Eternal Champions, Season of the Shattered Crown, Season of the Ashen Dawn. The names cycle; the math does not care.
What happens when a season ends
The end-of-season pipeline runs once per season, in order:
- Snapshot the winners — top 3 per category (the champion cut)
- Grant badges — each winner gets the season_N_champion badge
- Archive — the season index, name, and winners get handed to the archive hook
- Reset — all five leaderboards wipe to zero
- Broadcast — SeasonEnded fires on the event bus so clients can show the rollover
The five boards are the game’s canon progression categories: combat rating, siege wins, gold earned, essences collected, and max companion trust. All five reset together — a season is a full standings wipe, not a per-mode rotation.
The detail that took the most thought
Restart safety. A naive season service replays endings on every boot — restart the server and suddenly last season’s badges re-grant, boards re-reset, broadcasts re-fire. SeasonService only fires the pipeline for seasons that end *while it is alive*. A season that ended during downtime is already history at boot — no replay, no double badges.
The server owns the clock entirely. Clients receive snapshots and the ended broadcast; they never report time. That is the server-authoritative rule from the project guide applied to a timer — the client cannot talk its way into a badge.
Why 30 days, honestly
Short enough that a bad month is recoverable. Long enough that the top of a leaderboard means sustained play, not one good weekend. And a clean boundary gives the reset a reason to exist: the standings answer a question (“who owned September?”) instead of accumulating forever.
When real seasons have actually run and there is data worth sharing, that post will have the numbers in it. This one has the design.
Keep reading
- Play EFER on Roblox
- Devlog: the Convergence hub at 60% fidelity
- The Convergence — neutral ground between all factions
- Join the Discord
Agree, disagree, or caught something off? The comment form is below — I read all of them.