Advancements

Challenge and achievement system with 9 tabbed categories, 36 trigger types, tree-positioned GUIs, toasts, sounds, points, console rewards, and per-player progress stored in the database. Everything is defined in advancement.yml.

How Players Use It

  1. Open the GUI: /advancements (aliases: /adv, /achievements, /sdadv). Permission: shyamduels.advancements.use.
  2. Pick a category tab (Duels, Ranked, Bed Fight, Bridge, FFA, Kits, Party, Challenges, Secrets) and click through the tree.
  3. Play normally. Progress counters fill automatically (for example Win 10 duels shows 4/10).
  4. On completion the player gets a toast popup, a chat message, and a sound. Big milestones also broadcast server-wide.

How To Make An Advancement

Work in plugins/ShyamDuels/advancement.yml. The file is versioned (config-version: 2) and missing keys are merged from the built-in defaults on load, so editing never wipes your entries.

  1. Decide the category. Use one of the 9 shipped categories or add your own block under categories: (see the category table below). Note its key, for example DUELS.
  2. Add an entry under advancements: with a unique id, for example my_first_win:.
  3. Wire it into the tree with category: and parent:. Use parent: null for a root node, or the id of the previous advancement to chain it. The GUI position is computed automatically unless you set coords.x / coords.y.
  4. Describe it under display: (title, description lines, icon material, frame). See the display table below.
  5. Pick a difficulty (EASY to SECRET). It sets the label color and the default point value when rewards.points is omitted.
  6. Pick a trigger under trigger: with type: and amount: (how many times the event must fire). Full trigger list is in the trigger table below.
  7. Narrow it with conditions (optional) under trigger.conditions:, for example ranked: true or kit: "nethpot". Full condition list is in the condition table below.
  8. Set rewards under rewards: (points, console commands, extra message lines). Override announcements per advancement under announcements: if needed.
  9. Reload and test: run /advancements reload (or /shyamduels reload-advancements), then /advancements list to confirm your id appears. Grant it to yourself with /advancements grant <player> <id> to preview the toast and rewards. Turn on settings.debug: true and reload if an entry does not show up; unknown trigger types log a warning and never complete.

Minimal Example (Copy And Edit)

yamladvancements:
  my_bridge_debut:
    category: BRIDGE
    parent: "bridge_root"
    display:
      title: "<green>My Bridge Debut"
      description:
        - "<gray>Score your first Bridge goal."
      icon:
        material: "END_PORTAL_FRAME"
      frame: TASK
    difficulty: EASY
    trigger:
      type: BRIDGE_GOAL
      amount: 1
    rewards:
      points: 25
      commands:
        - "give %player% diamond 3"

Placeholders usable in messages, commands, and lore: %player%, %uuid%, %advancement%, %advancement_id%, %category%, %difficulty%, %progress%, %required%, %percentage%, %rewards%.

settings: (7 Keys)

KeyDefaultWhat It Does
settings.enabledtrueMaster switch. When false the whole subsystem stays off.
settings.debugfalseLogs load counts and warnings (for example unknown trigger types) to console. Turn on while building advancements.
settings.disable-vanilla-advancementsfalseDisables vanilla Minecraft advancements through the embedded advancement library.
settings.suppress-vanilla-in-arenatrueCancels vanilla advancement toast packets while a player is inside an arena world.
settings.sound-volume1.0Fallback volume for completion sounds when an entry does not set its own.
settings.sound-pitch1.0Fallback pitch for completion sounds when an entry does not set its own.
settings.broadcast-prefix[ACHIEVEMENT] gradientPrefix prepended to server-wide broadcast lines.

defaults: (Global Fallbacks)

KeyDefaultWhat It Does
defaults.frameTASKFrame used when an advancement omits display.frame.
defaults.show_toasttrueToast popup used when an entry omits announcements.toast.enabled.
defaults.progress.enabledtrueShows current/required counters. Disable per entry with progress.enabled: false.
defaults.announcements.chat.enabledtrueSends the private completion message to the earning player.
defaults.announcements.chat.messagecheckmark line with [%advancement%]Default private message lines. Supports all placeholders above.
defaults.announcements.toast.enabledtrueShows the vanilla-style toast popup.
defaults.announcements.sound.enabled / .type / .volume / .pitchtrue / UI_TOAST_CHALLENGE_COMPLETE / 1.0 / 1.0Completion sound. Volume and pitch fall back to settings.sound-volume / sound-pitch when omitted here.
defaults.announcements.broadcast.enabled / .messagefalse / %player% unlocked [%advancement%]Server-wide broadcast. Off by default; big milestones enable it per entry.
defaults.how_to_get.enabled / .headertrue / How to unlock:Shows the hint section in the GUI.

categories: (9 Shipped Tabs)

KeyWhat It Does
categories.<ID>.enabledShows or hides the whole tab.
categories.<ID>.titleTab title (MiniMessage, gradients allowed).
categories.<ID>.descriptionString or list of lines shown on the tab icon.
categories.<ID>.icon.material / .amountTab icon item (any Bukkit material name, MINECRAFT: prefix optional; EYE_OF_ENDER is accepted as ENDER_EYE).
categories.<ID>.backgroundVanilla texture path drawn behind the tree.
categories.<ID>.rootAdvancement id used as the tree root. If missing, the first entry with parent: null is used.

Shipped tabs and roots: DUELS (duels_root), RANKED (ranked_root), BEDFIGHT (bedfight_root), BRIDGE (bridge_root), FFA (ffa_root), KITS (kits_root), PARTY (party_root), CHALLENGES (challenges_root), SECRETS (secrets_root). Category keys are uppercased on load. An advancement whose category does not exist falls back to the first loaded category.

advancements: (Per-Entry Keys)

KeyWhat It Does
enabledDefault true. Disabled entries are skipped entirely at load.
categoryCategory key (default DUELS). Case insensitive.
parentParent advancement id, or null for a root. Use quotes around ids. A missing parent still loads (positioned by the tree generator).
display.titleName shown in the GUI (MiniMessage). Falls back to the entry id.
display.descriptionString or list of lore lines under the title.
display.loreExtra lore lines appended after the description.
display.icon.materialItem material (default DIAMOND_SWORD). Also accepts legacy icon.material / icon paths.
display.icon.amountStack size 1-64 (default 1).
display.icon.skull.ownerPlayer name, %player%, or {player} for player-head icons.
display.icon.custom_model_dataCustomModelData int for resource-pack icons (optional).
display.frameTASK, GOAL, or CHALLENGE (default from defaults.frame).
display.backgroundOptional per-advancement background texture override.
display.hidden (alias hidden)Secret entry. Hidden nodes stay invisible until the player has progress on them, then appear. Used by the whole SECRETS tab.
difficultyEASY, NORMAL, HARD, VERY_HARD, EXTREME, LEGENDARY, SECRET (default NORMAL). Unknown values fall back to NORMAL.
trigger.typeOne of the 36 trigger types below (default DUEL_WIN). Unknown values become CUSTOM, log a warning, and never complete, so check spelling.
trigger.amount (aliases required_amount, amount)How many matching events are needed (minimum 1). Progress accumulates across matches.
trigger.conditions (alias conditions)Map of extra requirements. See the condition table below. Supports all: / any: / not: groups and typed type: / field: / value: rules.
progress.enabledDefault from defaults.progress.enabled. Shows the counter on multi-step advancements.
coords.x / coords.y (aliases x, y)Optional fixed tree position. When omitted, the layout generator places the node (leaf-span with parent centering, normalized at zero or above).
display.how_to_get / how_to_get.lines / how_to_getHint lines. how_to_get.enabled: false hides them for that entry.
rewards.* / announcements.*See the rewards table below. Per-entry announcements.chat/toast/sound/broadcast blocks override the global defaults.

Difficulty Tiers And Default Points

When rewards.points is omitted, the tier value is used.

DifficultyDefault PointsUsed For
EASY10First steps (first duel, first kill, first goal).
NORMAL25Regular milestones (10 wins, first bed break).
HARD50Demanding goals (50 wins, 100 FFA kills).
VERY_HARD100Long grinds (100 wins, 500 FFA kills).
EXTREME250Elite feats (500 wins, flawless duels).
LEGENDARY500Legendary grinds (1,000 wins, 100 winstreak).
SECRET1000Hidden easter eggs (whole SECRETS tab).

Trigger Types (All 36)

amount counts matching events. Pair a counter trigger with a condition to scope it (for example DUEL_WIN plus ranked: true).

TriggerFires WhenTypical Amount
DUEL_PLAYA duel starts (any mode, add ranked: true or kit: to scope).1+
DUEL_WINThe player wins a duel.1, 10, 50, 100, 500, 1000, 2000
DUEL_KILLThe player gets a duel kill (add weapon conditions below to scope).1+
DUEL_DEATHThe player dies in a duel.1+
WIN_STREAKWinstreak reaches the amount (any mode unless ranked: true).5, 10, 15, 25, 30, 50, 100
KILL_STREAKKillstreak reaches the amount.1+
RANK_TIERPost-win Elo check passes elo_min (always amount: 1).1
ELO_GAINPost-win Elo gain event (ranked wins only).1+
BED_BREAKAn enemy bed is destroyed.1, 10, 25, 50, 100
BEDFIGHT_VOID_SURVIVEA Bed Fight void fall is survived.1
BEDFIGHT_FIREBALL_LAUNCHA Bed Fight fireball is launched.1
BEDFIGHT_FIREBALL_KILLA Bed Fight kill comes from fireball impact or knockback.1
BEDFIGHT_TNT_JUMPA Bed Fight TNT jump succeeds.1
BEDFIGHT_FINAL_KILLAn opponent with no bed left is eliminated.1
BRIDGE_GOALA Bridge goal is scored.1, 10, 25, 50, 100
BRIDGE_SHUTOUTA Bridge shutout or clean match completes.1, 5
BRIDGE_PORTAL_JUMPA Bridge portal jump or fast goal happens.1
BRIDGE_BLOCK_CLUTCHA Bridge block clutch is executed.1
FFA_KILLAn FFA kill happens (add bounty, multikill, or iron_man to scope).1, 25, 100, 250, 500, 1000
FFA_KILLSTREAKFFA killstreak reaches the amount.5, 10, 25, 50
FFA_SURVIVEAn FFA survival tick completes.1+
BOXING_COMBOHit combo reaches the amount without taking a hit back (mace kits).20, 50
SUMO_RINGOUTA sumo-style ringout happens.1
FLAWLESS_WINA duel is won with zero damage taken (pair with flawless: true).1, 5
LOW_HEALTH_WINA duel is won at low health (pair with health_max: 2.0 or 1.0).1
COMEBACK_WINA match is won after losing early rounds (pair with comeback: true or clutch_win: true).1, 5
KIT_CUSTOMIZEA kit layout is customized and saved in the Kit Editor.1
KIT_SHAREA customized kit layout is shared with another player.1
PARTY_PLAYA party match is played (add fight_type, split_win, ffa_win, or pvp_win to scope).1, 10, 25, 50
PARTY_SIZEA party session starts (pair with party_size_min: 8 or 16).1
PLAYTIMEFighting-time check passes playtime_hours (always amount: 1).1
STAT_TOTAL_KILLSLifetime kills reach the amount.1000
STAT_TOTAL_WINSLifetime wins reach the amount.500, 1000
SECRET_TRIGGERA secret interaction happens (pair with secret_id).1, 25
CUSTOMNever fired by gameplay. If you see this, the trigger name is misspelled. Fix the spelling.-

Conditions (Every Key)

Conditions live under trigger.conditions: (or conditions:). Flat keys combine with AND. Use all:, any:, and not: lists for logic, and typed rules (type: plus field: plus value:) for full control. Any other key falls back to generic payload matching: booleans must equal, numbers must be greater than or equal, text must equal ignoring case.

Condition KeyValueWhat It Checks
kit (alias kit_name)kit nameOnly this kit, for example kit: "nethpot", kit: "bedwars", kit: "bridge", kit: "Stickfight", kit: "macepvp".
rankedtrue / falseRanked-only or unranked-only matches.
modemode nameQueue mode string from the match payload.
arena (alias arena_name)arena nameOnly this arena.
flawless (alias no_damage_taken)trueNo damage taken in the match.
combo (alias combo_hits_min)numberMinimum combo hits.
health_max (alias health_lte)health numberHealth at or below the value (20.0 is full). Example: health_max: 2.0 is 1 heart, 1.0 is half a heart.
health_min (alias health_gte)health numberHealth at or above the value.
distance_min (alias distance_gte)blocks numberKill distance at or above the value, for example distance_min: 30.0 for longbow kills.
winstreak_min (alias min_winstreak)numberMinimum winstreak.
killstreak_min (alias min_killstreak)numberMinimum killstreak.
elo_min (alias min_elo)elo numberElo at or above the value, for example elo_min: 1050 up to 2200.
duration_max_seconds (alias time_max_seconds)secondsMatch at or under this length, for example 10 for blitz wins or 60 for fast shutouts.
duration_min_seconds (alias time_min_seconds)secondsMatch at or over this length, for example 300 for 5-minute marathons.
macetrueMace-based combat payload.
shutouttrueShutout payload (Bridge defense).
void_clutchtrueVoid-clutch payload.
fireball_killtrueFireball-kill payload.
tnt_jumptrueTNT-jump payload.
comeback (alias reverse_sweep)trueComeback-win payload.
party_size_minnumberParty at or above this size (8, 16).
friends_minnumberMinimum friends count in the payload.
bow_killtrueLethal hit was a bow shot (generic match).
crossbow_killtrueLethal hit was a crossbow shot (generic match).
sword_kill / axe_killtrueLethal hit used a sword or an axe (generic match).
shield_brokentrueEnemy shield was disabled with an axe (generic match).
fist_onlytrueWon with bare hands only (generic match).
wood_swordtrueWooden-sword kill (generic match).
final_roundtrueKill happened in the final round (generic match).
rounds_wonnumberRounds won in the series, for example 2 for Best-of-3 or 3 for Best-of-5.
fight_typePARTY_SPLIT etc.Party fight type, for example fight_type: "PARTY_SPLIT".
split_win / ffa_win / pvp_wintrueParty split win, party FFA win, or party-vs-party win.
speed_demontrueFast bed break (within 15 seconds of match start).
clutch_wintrueBed Fight win after your own bed was destroyed.
fast_goaltrueBridge goal within 8 seconds of round start.
hat_tricktrue3 consecutive Bridge goals in one match.
bountytrueVictim had a killstreak of 10 or higher (FFA).
multikilltrue2 kills within 4 seconds (FFA).
iron_mantrueKill while below 2 hearts (FFA).
secret_idid stringSecret interaction id, for example secret_good_game or secret_about_command.
playtime_hourshoursMinimum fighting hours (10, 50, 100).

Logic Groups And Typed Rules

yamltrigger:
  type: BOXING_COMBO
  amount: 20
  conditions:
    any:                 # OR: macepvp kit OR mace kit OR mace payload
      - kit: "macepvp"
      - kit: "mace"
      - mace: true
yamltrigger:
  type: DUEL_KILL
  amount: 1
  conditions:
    all:                 # AND group
      - bow_kill: true
      - ranked: true
    not:                 # NOT group
      - kit: "bridge"

Typed rules use type: plus field: plus value:: KIT_EQUALS (kit name equals), NUMERIC_GTE (payload number greater than or equal), NUMERIC_LTE (payload number less than or equal), BOOLEAN_IS (payload flag equals), STRING_EQUALS (payload text equals ignoring case). Example: {type: NUMERIC_GTE, field: elo, value: 2000}.

rewards: (Every Key)

KeyDefaultWhat It Does
rewards.pointsdifficulty default (10 to 1000)Point score for leaderboards and progress totals.
rewards.currency0.0Economy amount granted on completion.
rewards.commandsempty listConsole commands run on completion. Supports all placeholders above.
rewards.message.enabledtrueSends the extra reward lines below.
rewards.message.lines (aliases rewards.message)emptyExtra private message lines about the reward.
announcements.sound.enabled / .type / .volume / .pitch (aliases sound.*)global defaultsPer-entry sound override.
announcements.toast.enabled (alias display.show_toast)global defaultPer-entry toast override.
announcements.chat.enabled / .messageglobal defaultsPer-entry private message override.
announcements.broadcast.enabled / .messageglobal defaults (off)Per-entry server broadcast override. Enable for legendary milestones.

Admin Commands And Permissions

CommandPermissionWhat It Does
/advancements (/adv, /achievements, /sdadv)shyamduels.advancements.useOpens the advancement GUI.
/advancements listshyamduels.advancements.adminLists loaded advancement ids.
/advancements grant <player> <id>shyamduels.advancements.adminGrants an advancement (fires AdvancementGrantEvent, runs rewards).
/advancements revoke <player> <id>shyamduels.advancements.adminRevokes an advancement and its progress.
/advancements reset <player>shyamduels.advancements.adminResets one player's progress.
/advancements resetallshyamduels.advancements.adminResets progress for all players.
/advancements reload (also /shyamduels reload-advancements)shyamduels.adminReloads advancement.yml and rebuilds the registry and tree layout.

Behind The Scenes

Troubleshooting new advancements

Entry missing from the GUI: check enabled: true, a valid category, and run /advancements reload with settings.debug: true. Advancement never completes: the trigger name is probably misspelled (it becomes CUSTOM and logs a warning). Progress not counting: the condition is too strict (for example a wrong kit name). Tree looks wrong: set explicit coords.x / coords.y or fix the parent chain and the category root.