Astral Realms Documentation Help

Quests & Goals

A quest blueprint is one YAML file under blueprints/: a display item, a goal describing the gameplay trigger that advances it, and a goal-value range the concrete target is rolled in. Generation turns blueprints into QuestInstances for the current month; as players play, EventService routes events into QuestService.progress, which advances every matching active quest and credits points on completion.

See Developer API for adding a goal type.

Blueprint format

One file, one blueprint — sub-folders are walked, so blueprints/daily/wheat.yml and blueprints/weekly/warden.yml are just organisation.

id: "wheat" type: "DAILY" display: material: "wheat" name: "<primary_color><bold>Quête journalière : Blé" lore: - "<secondary_color>%required%/%total%<text_color> blés" goal: type: "block-break" materials: - "wheat" goal-value: minimum: 346 maximum: 422

Field

Type

Required

Description

id

String

Yes

Unique, stable identifier. It feeds the seed that rolls the quest's target, so renaming it re-rolls that quest. Duplicates are skipped with a warning.

type

QuestType

Yes

DAILY or WEEKLY — must match a categories key in config.yml, otherwise the blueprint is never generated and a warning is logged at startup.

display

ItemStackWrapper

Yes

The menu item. Standard AstralCore item shape (material, copy-from, name, lore, …); its lore can use the quest placeholders.

goal

Goal object

Yes

type names an entry of the goal catalogue; the remaining keys are that goal's own fields.

goal-value

{minimum, maximum}

No

Inclusive range the target is rolled in. Omitted (or absent) means a target of 1. See target rolling.

completion-requirements

PaperRequirementList

No

Requirements that must pass for an event to count — see below.

available-from

Season or date

No

First season this quest may be dealt in. null = always.

available-until

Season or date

No

Last season this quest may be dealt in. null = never retired.

type

QuestType has two values, DAILY and WEEKLY. The type decides which categories entry the quest follows — how many are dealt per batch, how often, how long they live, and how many points completing one awards. It is not a difficulty label: a DAILY blueprint is simply drawn from the daily pool.

goal-value

goal-value: minimum: 346 maximum: 422

An inclusive range, not a value: every month each dealt quest rolls its own target inside it, from the generation seed, so every server rolls the same number. maximum <= minimum pins the target to minimum. See Seasons & Generation § Targets for the rounding rule value-step applies.

completion-requirements

An optional PaperRequirementList — the same grammar as anywhere else in AstralCore.

completion-requirements: - "[compare] %server_group% == resource"

It is evaluated per event, not once at completion: an event whose goal matched is dropped when the list fails, so the quest simply does not advance there. Progress already earned is never rolled back, and the player can advance the same quest later somewhere the requirements pass. The list runs last — after the goal has recognised the event — because running configured requirements is far more expensive than letting the goal reject the event. A failing requirement list logs an error and counts as not satisfied.

available-from/available-until

available-from: "2026-09" available-until: "2026-11"

The window that decides whether a blueprint enters a season's draw at all. Both bounds are inclusive and both are optional (available-until alone retires a quest after that season; available-from alone introduces one).

The window is read a season at a time, against the month being generated — not against today's date. A season deals its quests once, from a pool that has to be identical on every server for the whole month, so a quest cannot join or leave a season halfway through. Accepted forms are a season (2026-09) or a full date (2026-09-01), a date being folded onto the season that contains it. A malformed value throws at load time, naming the blueprint. Both bounds also feed the blueprint fingerprint.

Display placeholders

When a quest's display item is rendered for a viewer, the QuestInstance registers itself in the container, so the blueprint's name/lore can describe that player's copy of the quest:

Placeholder

Resolves to

%required%

The viewer's current progress on this quest.

%total%

The quest's rolled target.

%quest_…%

Any quest sub-key — %quest_progress%, %quest_expiresAt_remaining-format%, %quest_values%, …

lore: - "<secondary_color>%required%/%total%<text_color> blés"

%required%/%total% are the short names the blueprint files have always used; they are the same two numbers as %quest_progress% and %quest_requiredAmount%.

Progress

EventService registers one listener per entry of EventAdapterRegistry at MONITOR priority. An event that is Cancellable and cancelled is dropped. The matching adapter pulls the acting player — and, when the event carries them, the block, item stack or entity — into a QuestGoalContext; an adapter returning null (no player behind the event) drops it too.

QuestService.progress then walks every quest of the month and, for each one that is active and not already completed, hands the context to its goal. A goal returns a QuestGoalResult in one of four shapes:

Result

Meaning

notHandled()

The goal does not recognise this event. Nothing happens.

handled(delta)

Adds delta to the player's progress, capped at the target.

distinct(key)

Adds 1, but only the first time key is seen for that quest — what "do N different things" quests are built on. The keys already counted are stored per quest in the player's data.

best(value)

Raises progress to value if that beats the current one, instead of accumulating — what "in a single go" quests are built on.

When progress reaches the target, the quest type's reward points are credited and quest-completed is sent. Completion is derived from progress, so there is no separate "claimed quest" state: a completed quest just sits at its target.

Goal catalogue

Twenty-four goal types, registered in QuestGoalRegistry. A type that is not in this list fails the blueprint file with Unknown QuestGoal type.

In every goal below, an empty or omitted filter list accepts everything.

Block goals

block-break

Breaking blocks. Counts blocks, not swings.

goal: type: "block-break" materials: - "wheat"

Field

Type

Description

materials

Set<Material>

The blocks that count; empty for any.

Two checks keep it from being farmed: a block AstralCore's BlockService reports as wasPlacedByPlayer never counts, and an Ageable block only counts at maximum age — so replanted or unripe crops are ignored. The exception is the column crops (CACTUS, SUGAR_CANE, BAMBOO, SWEET_BERRY_BUSH), which are broken mid-growth by design: for those the whole column counts, walking upward from the broken block and adding every consecutive block of the same material in one go.

block-break-distinct

Breaking a number of different kinds of blocks. A thousand stone blocks only ever count once.

goal: type: "block-break-distinct" materials: [ ]

Field

Type

Description

materials

Set<Material>

The blocks that count; empty for any.

Same player-placed and maturity checks as block-break. The distinct key is the block's material.

block-place

Placing blocks.

goal: type: "block-place" materials: - "torch"

Field

Type

Description

materials

Set<Material>

The blocks that count; empty for any.

The held item and the block it becomes often differ (seeds become wheat, a water bucket becomes water), so the filter matches if either side matches.

block-harvest

Harvesting a block without breaking it — right-clicking a grown sweet berry bush, a cave vine, …

goal: type: "block-harvest" materials: - "sweet_berry_bush"

Field

Type

Description

materials

Set<Material>

The harvested block that counts; empty for any.

The filter is matched on the block, not on what dropped out of it: a quest names the plant to look for, and the same item can come from more than one. Progress counts the items the block gave, not the number of harvests — picking six berries at once is worth six.

block-brush

Brushing suspicious sand or gravel.

goal: type: "block-brush" materials: [ ]

Field

Type

Description

materials

Set<Material>

The brushable blocks that count; empty for any.

Requires a main-hand right click with a BRUSH on a block whose block data is Brushable. Worth 1.

Entity goals

entity-kill

Killing mobs.

goal: type: "entity-kill" entities: - "zombie" with-fireball: false

Field

Type

Description

entities

Set<EntityType>

The mobs that count; empty for any.

with-fireball

boolean

true requires an indirect kill whose direct entity is a Fireball — a ghast fireball hit back at its sender. Default false.

The kill must be credited to the player: the damage source's causing entity, so a bow or a thrown potion counts as the shooter's kill.

entity-kill-distinct

Killing a number of different species. Farming zombies only ever counts once.

goal: type: "entity-kill-distinct" entities: [ ]

Field

Type

Description

entities

Set<EntityType>

The mobs that count; empty for any.

The distinct key is the entity type.

entity-multi-kill

Killing several mobs of the same kind in a single swing.

goal: type: "entity-multi-kill" entities: - "zombie" weapons: - "crossbow"

Field

Type

Description

entities

Set<EntityType>

The mobs that count; empty for any.

weapons

Set<Material>

What the player must be holding in their main hand; empty for anything.

Driven by PlayerMultiKillEvent, which MultiKillService raises when a player kills several mobs of one type within a single tick — a sweeping attack, an explosion, a piercing arrow. The target is how many mobs the swing has to take down, so progress keeps the best swing so far: three swings of four do not add up to a swing of twelve.

entity-breed

Breeding animals. Worth 1 per breeding.

goal: type: "entity-breed" entities: - "cow"

Field

Type

Description

entities

Set<EntityType>

The animals that count; empty for any.

Only breedings a player caused count — villagers and animals fed by a dispenser have no breeder.

entity-breed-distinct

Breeding a number of different species. A cow farm only ever counts once.

goal: type: "entity-breed-distinct" entities: [ ]

Field

Type

Description

entities

Set<EntityType>

The animals that count; empty for any.

entity-leash

Putting a lead on an entity. Worth 1.

goal: type: "entity-leash" entities: - "cow"

Field

Type

Description

entities

Set<EntityType>

The entities that count; empty for any.

entity-fertilize-egg

Breeding egg-laying animals — turtles, sniffers. They lay an egg instead of spawning a baby and therefore never fire the ordinary breed event, which is why they need their own goal.

goal: type: "entity-fertilize-egg" entities: - "turtle"

Field

Type

Description

entities

Set<EntityType>

Matched against the mother; empty for any.

Item goals

item-craft

Crafting items.

goal: type: "item-craft" materials: - "bread"

Field

Type

Description

materials

Set<Material>

The crafting results that count; empty for any.

Counts items, not clicks: shift-clicking crafts the recipe as many times as the smallest ingredient stack allows, and all of it counts.

item-enchant

Enchanting an item at an enchantment table.

goal: type: "item-enchant" materials: [ ] enchantments: - "sharpness" minimum-level: 3

Field

Type

Description

materials

Set<Material>

The items that count; empty for any.

enchantments

Set<Enchantment>

The enchantments that count; empty for any.

minimum-level

int

The level a matching enchantment must reach. 0 for any.

Worth 1 when at least one enchantment being applied matches the filter and reaches minimum-level. The values shown on the tooltip are the enchantments when the list is set, otherwise the materials — the enchantment is what the quest is about, the item only narrows it down.

item-fish

Fishing something up.

goal: type: "item-fish" materials: - "cod"

Field

Type

Description

materials

Set<Material>

The catches that count; empty for any.

Only a CAUGHT_FISH catch counts, and progress is the caught stack's amount.

Player goals

player-travel

Travelling a distance in blocks, on foot.

goal: type: "player-travel" flying: false

Field

Type

Description

flying

boolean

Whether flying and gliding count. Default false.

Only actual position changes count, and a change of world (a teleport) never does. Fractions of a block are carried over per player, so a hundred tiny steps still credit their blocks; that remainder is runtime state, held per goal instance and expiring ten minutes after it was last touched.

player-biome

Exploring a number of different biomes.

goal: type: "player-biome" biomes: [ ]

Field

Type

Description

biomes

Set<Biome>

The biomes that count; empty for any.

Only checked when the player crosses a block boundary. The distinct key is the biome's namespaced key, so walking back and forth across the same one counts once.

player-potion

Holding a set of potion effects at the same time, each at least at the given level.

goal: type: "player-potion" potions: speed: 2 strength: 1

Field

Type

Description

potions

Map<PotionEffectType, Integer>

Effect → the level it must reach, 1 being the first level as it reads in game. Required: an empty map never progresses.

Checked whenever an effect is added to the player. The effect being added is read off the event — it is not applied to the player yet at that point — and every other required effect off the player. Worth 1 each time the whole set is satisfied.

player-vote

Voting for the server. Worth 1 per vote; no fields.

goal: type: "player-vote"

player-loot

Opening a generated loot container — a dungeon chest, a shipwreck, …

goal: type: "player-loot" loot-tables: - "minecraft:chests/shipwreck_treasure"

Field

Type

Description

loot-tables

Set<String>

Namespaced loot-table keys that count; empty for any.

Loot generated by a plugin never counts. Worth 1.

player-vault

Unlocking a trial chamber vault.

goal: type: "player-vault" ominous: false

Field

Type

Description

ominous

boolean

Which kind of vault counts. Matched exactly — false counts ordinary vaults only, true ominous ones only.

Counted the moment the vault enters its UNLOCKING state. Worth 1.

player-scroll

Completing an AstralScrolls scroll.

goal: type: "player-scroll" rarities: - "common"

Field

Type

Description

rarities

Set<String>

Scroll rarity ids that count; empty for any.

Worth 1.

player-tower

Getting through the AstralTower tower.

goal: type: "player-tower" room: 10

Field

Type

Description

room

int

The room the run has to reach for it to count. A finished run below it is ignored.

Worth 1 per qualifying run.

Shop goals

shop-sell

Selling items to the AstralShop server shop.

goal: type: "shop-sell" shops: [ ] items: [ ]

Field

Type

Description

shops

Set<String>

Shop ids that count; empty for any.

items

Set<String>

Shop item ids that count; empty for any.

Progress counts items, not sales: selling a stack of sixty-four is worth sixty-four.

Further reading

Last modified: 25 September 2026