Astral Realms Documentation Help

Seasons & Generation

A season is a calendar month in the configured time-zone, identified by its YearMonth (2026-08). Everything a season contains — which blueprints are dealt, into which slots, with which targets, unlocking and expiring when — is derived from the month, the seed-salt and the loaded blueprints. Nothing is stored, nothing is coordinated: every server derives the same season on its own, and re-derives it identically after a restart.

Why it is deterministic

Seeds hashes a canonical description of each decision — the salt, an algorithm version, then the parts identifying the decision — into either a 64-bit seed or a stable UUID:

sha256("<seed-salt>|1|<part>|<part>|…")

Because every decision is seeded independently, adding a quest slot never shifts the values of the existing ones. The 1 is the algorithm version, bumped in code when every generated quest should deliberately be re-rolled.

The consequence to keep in mind when operating a network: the inputs must match everywhere. time-zone, seed-salt, the categories block and the blueprint files are all part of the input.

Fingerprint

BlueprintService prints a fingerprint on every load — the first 12 hex characters of a SHA-256 over each blueprint's id, type, goal-value bounds and availability window, in sorted id order:

Loaded 78 quest blueprints (fingerprint: 3f9c1a72be04). Generated 108 quests for 2026-08 (fingerprint: 3f9c1a72be04).

Servers that do not print the same fingerprint will not generate the same quests, whatever the seed. Comparing that line across the network is the fastest way to catch a blueprint folder that drifted.

A month's schedule

Each category describes its own rhythm:

Key

Effect on the schedule

regeneration.interval

The length of a period, in days, counted from the 1st of the month.

regeneration.amount

How many quests are dealt per period.

regeneration.lifetime

How long a period's quests stay available.

The number of periods is the month's length divided by the interval, rounded up — so a 31-day month running interval: "7d" gets five weekly batches, the last one opening on the 29th and running until the month ends. The shipped configuration (DAILY 3/day, WEEKLY 3/week) therefore deals 93 daily and 15 weekly quests over a 31-day month.

For period p (0-based):

  • unlocks at the start of day 1 + p × interval, in the configured zone;

  • expires at the end of the month when lifetime: "season", otherwise lifetime days after it unlocked — clamped so that no quest ever outlives its month.

A quest is active between those two instants; before its unlock it is visible but locked, which is what %farmpass_all_WEEKLY% shows in the weekly menu with a countdown.

Dealing the blueprints

For each type, the pool is every blueprint of that type whose availability window contains the season being generated — not today's date, so a season keeps dealing from the same pool from its first to its last day. An empty pool logs a warning and produces no quests for that type.

The pool is then dealt like a deck of cards, not rolled per slot:

  1. Shuffle the whole pool with the month's deck seed ("deck" | type | month).

  2. Keep re-shuffling, with a derived seed per pass, until there are enough cards for every slot of the month plus one spare period.

  3. Walk the deck and push aside any card that would repeat inside its own period — a shuffle boundary can otherwise fall mid-period and deal the same quest twice on the same day.

The effect is that a blueprint is only reused once all the others have been used, and never twice in the same batch.

Each dealt quest gets a stable id, uuid("quest" | month | type | period | slot) — the same quest carries the same id on every server, which is what lets player progress be keyed by quest id and synced without reconciling anything.

Targets

A quest's target is rolled inside its blueprint's goal-value range from the seed "value" | blueprint id | month | type | period | slot. A blueprint with no goal-value, or whose maximum is not above its minimum, gets minimum (or 1 when the block is absent).

value-step then rounds the roll down to a multiple of itself, so big targets read as "break 240 blocks" rather than "break 237", never falling below minimum. A range narrower than the step has nothing to round to and would collapse onto its minimum, so it is left alone — quests asking for a handful of things keep their exact roll. value-step: 1 disables rounding entirely.

Rollover

The month is checked lazily on every read (listing quests, recording progress, resolving the current season) and, so that it also happens on an idle server, by a task running every 60 seconds. When the current time passes the end of the cached month, the whole month is re-generated.

On an actual month change:

  • every online player's FarmPassPlayerData is reset to the new season — progress, discoveries, claimed rewards and points all cleared — and they receive season-started;

  • offline players are dealt with when they next connect: FarmPassSnapshotAdapter.apply compares the season stamped on the loaded snapshot with the current one and resets it if it differs.

Re-generating the same month (a reload, a restart) is not a rollover and touches nobody's data.

The reset runs on the main thread; when a rollover is noticed from an async save it is scheduled back onto it rather than touching player data off-thread.

Changing the schedule mid-month

Anything that feeds generation is read on every re-generation, so editing it and reloading re-deals the running month:

Change

Effect

seed-salt

Every quest of every month is re-rolled.

categories (interval, amount, lifetime)

The month's whole schedule is re-computed.

A blueprint's id, type, goal-value or availability window

Fingerprint changes; the deal changes.

A blueprint's display, goal fields or completion-requirements

Not part of the fingerprint — the same quests are dealt, with a new description or a different trigger.

time-zone

Period boundaries move.

Because progress is keyed by quest id, a re-deal leaves players with progress recorded against ids that no longer exist — in practice, their pass looks reset for the quests that changed. Prefer using available-from/available-until to rotate the catalogue from one season to the next, which changes nothing for the running month.

Further reading

Last modified: 25 September 2026