Frostyh Plugins

Plugins / BattlePass

BattlePass Coming soon

Battle pass seasons: free and premium tracks, daily and weekly quests. Sell premium your way.

Get BattlePass

Coming soon Not on sale yet. This page gets a buy button the day it is.

Try it live

BattlePass runs on a public demo server, set up so you can use it yourself. Join, try it, then decide.

Address: try.zeropvp.xyz:25570 (Java Edition 1.21.11)

In Minecraft: Multiplayer, Add Server, paste the address, Join. Type /demo go battlepass to land at its booth, or right-click the compass and pick it. The world resets every night.

Overview

BattlePass

Give players a reason to log in every day, and sell the premium track through your own store

Players get daily, weekly and season quests. Finishing them pays season XP, XP unlocks tiers, and every tier holds a free reward and a premium reward. When the season ends, everybody starts again on a fresh pass.

Premium is a permission and nothing else. BattlePass never touches a payment: sell battlepass.premium through Tebex, CraftingStore or a LuckPerms rank, and the moment a player has it, every premium reward they already earned becomes claimable.

The season screen: tier, XP to the next tier, rewards waiting, quests.

Latest version
1.1.0
Server
Paper or Purpur, Java 21
BuiltByBit
coming soon
What changed in 1.1.0
  • New: server-wide XP boost events. /bpa boost <multiplier> <time> [reason] starts one for everyone, for example /bpa boost 2 2h Weekend event for double XP for two hours. Time takes 30m, 2h, 1d, 1w or a plain number of minutes, up to 30 days; the multiplier goes above 1 up to 10.
  • Running the same multiplier again adds the time on, so two store purchases of "x2 for 1 hour" give two hours. It works from the console, so Tebex or any store can sell it as a package.
  • /bpa boost info shows the running boost, /bpa boost stop ends it early. A boost survives a server restart and ends on its own, with a chat message when it starts, is extended and ends.
  • The event boost multiplies on top of each player's own boost (premium and the xp-boosts permissions). The /bp screen shows a line "XP event: x2 for everyone, 1h 20m left" while one runs.
  • New PlaceholderAPI placeholders: %battlepass_boost%, %battlepass_boost_active%, %battlepass_boost_time_left%.
  • New leaderboard placeholders for holograms and scoreboards: %battlepass_top_<1-10>_name%, %battlepass_top_<1-10>_level%, %battlepass_top_<1-10>_xp%. The ranking refreshes once a minute; a rank nobody holds yet shows "-" (messages.placeholder-top-empty).
  • XP boosts now read x1.1 instead of x1.10 on the /bp screen.
  • The /bpa boost commands use the existing battlepass.admin permission. Tab completion knows them.
  • Existing config.yml files keep working without changes. The new messages use their defaults until you add them. The /bpa help line only lists /bpa boost on a fresh config.yml (or copy admin-help from the new default config).

Features

Why server owners pick it

What makes it different

Works with

Highlights

The season's top players by tier and XP.

What you get

Quest progress on the action bar, completions in chat.

The pass screens

The free and premium track, tier by tier, with claim buttons.

Daily quests with progress bars and a swap.

For developers

Add softdepend: [BattlePass] and use dev.frostyh.battlepass.api.BattlePassAPI:

BattlePassAPI.registerQuestType(this, "votes", "Vote for the server");
BattlePassAPI.progress(player, "votes", "", 1);
BattlePassAPI.addXp(player, 250, "vote");
BattlePassAPI.getLevel(player);
BattlePassAPI.isPremium(player);

Or fire QuestProgressEvent yourself. Events to listen to: QuestProgressEvent (cancellable, also fired for every built-in action), BattlePassXpGainEvent (change or cancel XP), BattlePassLevelUpEvent, QuestCompleteEvent, RewardClaimEvent (cancellable).

FAQ

Which servers does it run on?

Paper or Purpur 1.21.11 or a newer 1.21.x, with Java 21.

Do I need other plugins?

No. PlaceholderAPI, Vault (for money rewards) and LuckPerms are optional.

Is there DRM or a licence key?

No. There is nothing to activate and no licence server to reach, and the code is not obfuscated.

How long does setup take?

Drop the jar into /plugins and restart. The setup guide above has 5 short steps.

Can I try it before I buy?

Yes. This page has a test server with the plugin installed.

Where do I get help?

In the active support Discord, in the discussion tab on this page, or in the documentation.

Can I sell double XP weekends?

Yes. /bpa boost runs from the console, so Tebex or any store can sell it as a package; buying twice adds the time on.

Updates

Released on October 14, 2026 and updated once since. The latest version is v1.1.0 (October 16, 2026). Every update is free, new Minecraft versions included.

Also by Frostyh

If this plugin helps your server, a short review on this page would mean a lot. Thank you!

Installation

Requirements

Server software
Paper, or a Paper fork such as Purpur. Spigot and CraftBukkit are not supported: the plugin uses Paper-only APIs.
Minecraft version
plugin.yml api-version 1.21; built against Paper API 1.21.11
Java
21 or newer
Required plugins
none
Optional plugins
PlaceholderAPI, Vault
Libraries
org.xerial:sqlite-jdbc:3.53.2.1, downloaded by the server at startup (plugin.yml libraries)

Steps

  1. Download BattlePass.jar from BuiltByBit. There is no licence key to enter.
  2. Stop the server and put the jar into the plugins folder.
  3. Start the server. The plugin creates plugins/BattlePass/config.yml with the defaults shown under Configuration.
  4. Edit config.yml to suit your server.
  5. Apply the changes with /bpa reload (Read config.yml, tiers.yml and quests.yml again), or restart the server.

Setup guide

  1. Drop BattlePass.jar into /plugins and restart. Season 1 starts by itself.
  2. Open tiers.yml and set your rewards, or hold an item in game and run /bpa setreward <tier> <free|premium>.
  3. Adjust quests.yml to your server: a skyblock pool, a factions pool, or the ready-made survival one.
  4. Sell battlepass.premium in your store as a permission package or a rank. Put your store link in premium.store-url for the in-game button.
  5. Run /bpa reload and open /bp.

Commands

From plugin.yml. "Not set" in the permission column means plugin.yml attaches no permission to the command itself; the nodes the plugin checks are listed under Permissions.

CommandAliasesUsageDescriptionPermission
/battlepass/bp, /pass/battlepass [quests|rewards|claim|help]Open the battle pass.not set
/battlepassadmin/bpadmin, /bpa/bpadmin helpBattle pass admin: XP, levels, seasons, rewards.not set

Subcommands in detail

/bp                                        Open the pass. Aliases: /battlepass, /pass
/bp rewards                                The reward track.
/bp quests [daily|weekly|season]           A quest list.
/bp claim [all|<tier> <free|premium>]      Claim from chat.
/bp top                                    The season ranking.

/bpa xp give|take|set <player> <amount>    (admin) Change season XP, online or offline.
/bpa level set <player> <level>            (admin) Put a player on a tier.
/bpa reset <player>                        (admin) Reset a player's pass for this season.
/bpa info <player>                         (admin) Tier, XP, claims and quest progress.
/bpa progress <player> <type> <n> [target] (admin) Report quest progress by hand or from scripts.
/bpa season info                           (admin) Season state and the reset timers.
/bpa season start [days] [name]            (admin) Start the next season now.
/bpa season end                            (admin) End the season now.
/bpa season extend <days>                  (admin) Move the end later.
/bpa season setend <days>                  (admin) End it this many days from now.
/bpa setreward <tier> <free|premium>       (admin) Add the item in your hand to a tier.
/bpa clearreward <tier> <free|premium>     (admin) Empty one track of a tier.
/bpa reload                                (admin) Read config.yml, tiers.yml and quests.yml again.
/bpa boost <multiplier> <time> [reason]   (admin) Server-wide XP event, for example /bpa boost 2 2h.
/bpa boost info · /bpa boost stop

Aliases for the admin command: /bpadmin, /bpa, /battlepassadmin

Permissions

From plugin.yml.

NodeDefaultDescriptionChildren
battlepass.useeveryoneOpen the battle pass, do quests and claim free rewards.none
battlepass.premiumnobody until grantedThe premium track. Give it through your store (Tebex and so on) or a rank.none
battlepass.adminoperatorsGive XP, set levels, reset players, start and end seasons, run server-wide XP boosts, reload.none

The premium permission can be renamed in config.yml. XP boosts are permissions you choose in the xp-boosts block.

Placeholders

Registered with PlaceholderAPI under the identifier battlepass (PassPlaceholders.java). PlaceholderAPI must be installed for these to work.

PlaceholderReturns
%battlepass_level%tier reached this season
%battlepass_max_level%number of tiers
%battlepass_xp%season XP
%battlepass_xp_next%XP still needed for the next tier
%battlepass_xp_into%XP earned inside the current tier
%battlepass_xp_step%XP the current tier step is wide
%battlepass_progress%percent of the way to the next tier
%battlepass_bar%a 10-cell progress bar (legacy colours)
%battlepass_premium%the configured yes/no text
%battlepass_premium_raw%true / false
%battlepass_claimable%rewards waiting to be claimed
%battlepass_season%season number
%battlepass_season_name%season name
%battlepass_days_left%whole days left, rounded up
%battlepass_time_left%"12d 4h"
%battlepass_daily_done%daily quests finished, "2/3"
%battlepass_weekly_done%weekly quests finished
%battlepass_season_done%season quests finished
%battlepass_boost%the server-wide XP boost, "2" (or "1" when none runs)
%battlepass_boost_active%true / false
%battlepass_boost_time_left%"1h 20m", empty when none runs
%battlepass_top_N_name%the player ranked N this season (1 to 10)
%battlepass_top_N_level%their tier
%battlepass_top_N_xp%their season XP
%battlepass_name%

Configuration reference

The default files as they ship in the jar, with their comments. The plugin writes them to plugins/BattlePass/ on first start.

config.yml

Top-level keys:

KeyDefaultComment above it
premiumsection, 3 keysPremium is a permission and nothing else. BattlePass never takes payments: sell the permission through the store you already use (Tebex, CraftingStore, a rank in LuckPerms) and the moment a player has it, every premium reward they have already earned...
xp-boostssection, 2 keysMore XP boosts by permission. The highest one a player has wins (premium's included). Section keys cannot contain dots, so write the permission with dashes: battlepass-boost-vip stands for battlepass.boost.vip (the dashed form works as a permission too).
seasonsection, 9 keysnone
resetssection, 3 keysWhen daily and weekly quests turn over. "server" uses the machine's own time zone, or name one such as "Europe/Berlin" or "America/New_York".
questssection, 9 keysnone
rewardssection, 5 keysnone
notifysection, 5 keysnone
menusection, 3 keysnone
storagesection, 1 keynone
themesection, 12 keysEvery message below is written against these names, not against hex codes: <accent>Open</accent> rather than <#ff4fd8>Open</#ff4fd8>. Change a colour here and it changes on every screen at once. Ordinary MiniMessage still works, so <gradient:#a:#b> and...
messagessection, 178 keysMiniMessage. An empty message ("") is not sent at all.
plugins/BattlePass/config.yml
# BattlePass - seasons, a free and a premium track, and quests that feed them.
#
# Players earn season XP by finishing daily, weekly and season quests. XP unlocks tiers, and every
# tier can hold a free reward and a premium reward. When the season ends, everybody starts again.
#
# The tiers and their rewards live in tiers.yml, the quests in quests.yml. Both are read again
# with /bpadmin reload, and player progress is never touched by a reload.

# ------------------------------------------------------------------------------------------------
# PREMIUM
# ------------------------------------------------------------------------------------------------
# Premium is a permission and nothing else. BattlePass never takes payments: sell the permission
# through the store you already use (Tebex, CraftingStore, a rank in LuckPerms) and the moment a
# player has it, every premium reward they have already earned becomes claimable.
premium:
  permission: "battlepass.premium"
  # A link the "Get premium" button opens. Leave empty to hide the button.
  store-url: ""
  # Premium players earn this much more XP from quests. 1.0 means no boost.
  xp-multiplier: 1.0

# More XP boosts by permission. The highest one a player has wins (premium's included).
# Section keys cannot contain dots, so write the permission with dashes: battlepass-boost-vip
# stands for battlepass.boost.vip (the dashed form works as a permission too).
xp-boosts:
  battlepass-boost-vip: 1.1
  battlepass-boost-mvp: 1.25

# A server-wide XP event on top of the boosts above: /bpa boost 2 1h starts double XP for an hour
# for everyone, and a second /bpa boost 2 1h adds another hour. It works from the console, so your
# store can sell it as a package. /bpa boost stop ends it early. It survives a restart.

# ------------------------------------------------------------------------------------------------
# SEASONS
# ------------------------------------------------------------------------------------------------
season:
  # {number} is the season number.
  name: "Season {number}"
  length-days: 30
  # Start season 1 by itself the first time the plugin runs.
  auto-start: true
  # Book season 1 for a date instead of starting it at once: "2026-11-01 18:00" (resets.timezone).
  first-start: ""
  # When a season ends, open the next one straight away. Off: it stays closed until
  # /bpadmin season start.
  auto-restart: true
  # Between seasons, players can still claim what they earned. The next season wipes it.
  claim-after-end: true
  # Announce the top players when a season ends. 0 turns it off.
  announce-top: 3
  # Console commands when a season starts and ends. {season} is the number.
  start-commands: []
  end-commands: []

# When daily and weekly quests turn over. "server" uses the machine's own time zone, or name one
# such as "Europe/Berlin" or "America/New_York".
resets:
  timezone: "server"
  daily-hour: 0
  weekly-day: MONDAY

# ------------------------------------------------------------------------------------------------
# QUESTS
# ------------------------------------------------------------------------------------------------
quests:
  daily:
    # How many daily quests each player gets, drawn at random from the daily pool in quests.yml.
    count: 3
    # Extra quests for premium players.
    premium-extra: 1
    # Swaps of an unfinished quest for another, per day.
    rerolls: 1
    rerolls-premium: 3
  weekly:
    count: 3
    premium-extra: 1
    rerolls: 1
    rerolls-premium: 2
  # Season quests are not drawn: every player gets the whole season pool from quests.yml.
  # Worlds where nothing counts (minigame lobbies, creative plots).
  disabled-worlds: []
  count-in-creative: false
  # A block a player placed does not count when broken again, so place-and-break farming pays nothing.
  ignore-placed-blocks: true
  # Mobs from spawners do not count for kill quests.
  ignore-spawner-mobs: false
  # The same victim only counts once in this many seconds for player-kill quests.
  same-victim-cooldown-seconds: 300
  # Play time stops counting after this many minutes without moving or looking around.
  afk-minutes: 5
  # Count the last few seconds of walking when a player logs out.
  walk-count-on-quit: true

# ------------------------------------------------------------------------------------------------
# REWARDS
# ------------------------------------------------------------------------------------------------
rewards:
  # How permission rewards are given:
  #   auto       LuckPerms installed: through its command. Otherwise kept by BattlePass.
  #   command    always run permission-command below.
  #   stored     BattlePass keeps them in its database and puts them back on every join.
  permission-mode: auto
  permission-command: "lp user {player} permission set {permission} true"
  # With stored permissions: keep them after the season they were earned in ends.
  permissions-keep-after-season: false
  # Hand out free rewards the moment a tier is reached, without a click.
  auto-claim-free: false
  auto-claim-message: true

# ------------------------------------------------------------------------------------------------
# NOTICES AND SCREENS
# ------------------------------------------------------------------------------------------------
notify:
  # Quest progress above the hotbar while it moves.
  actionbar: true
  # A chat line for every bit of XP. Off by default: the quest message already says it.
  xp-message: false
  level-up-title: true
  # Tell the whole server when somebody reaches a tier divisible by this (and the last tier).
  # 0 turns it off.
  broadcast-every: 10
  # Remind players on join when rewards are waiting.
  join-reminder: true

menu:
  tiers-per-page: 4
  show-top: true
  top-size: 10

storage:
  # Changed records are written to data.db this often, and always on quit, claim and shutdown.
  save-interval-seconds: 60

# ------------------------------------------------------------------------------------------------
# THEME
# ------------------------------------------------------------------------------------------------
# Every message below is written against these names, not against hex codes: <accent>Open</accent>
# rather than <#ff4fd8>Open</#ff4fd8>. Change a colour here and it changes on every screen at
# once. Ordinary MiniMessage still works, so <gradient:#a:#b> and <#ff0000> are fine anywhere.
theme:
  accent: "#ff4fd8"     # your colour: headings and anything the player is meant to click
  accent2: "#ffa8ec"    # a lighter accent, for a second level of emphasis
  title: "#f4f7ff"      # screen titles
  text: "#c2ccdd"       # ordinary prose
  muted: "#6b7a94"      # hints, separators, anything the eye should skip
  value: "#ffffff"      # the numbers and names the player opened the screen to read
  good: "#57e08a"
  warn: "#ffc857"
  bad: "#ff6b6b"
  small-caps: false     # a garnish; whole menus in it read badly
  # Real Minecraft item pictures beside the buttons. Drawn from the client's own textures, so
  # there is nothing to install and no resource pack: it needs a 1.21.9 or newer client.
  item-icons: true
  sounds: true

# ------------------------------------------------------------------------------------------------
# MESSAGES
# ------------------------------------------------------------------------------------------------
# MiniMessage. An empty message ("") is not sent at all.
messages:
  prefix: "<accent><bold>Pass</bold></accent> <muted>»</muted> "
  no-permission: "<bad>You cannot do that.</bad>"
  players-only: "<text>Players only.</text>"
  loading: "<text>Your pass is still loading, try again in a moment.</text>"
  unknown-player: "<bad>No player called </bad><value>{name}</value><bad> has played here.</bad>"
  hold-something: "<text>Hold the item first.</text>"
  save-failed: "<bad>tiers.yml could not be written. See the console.</bad>"
  help: "<text>/bp · /bp rewards · /bp quests [daily|weekly|season] · /bp claim [all|<tier> <free|premium>] · /bp top</text>"
  admin-help: "<text>/bpa xp give|take|set <player> <n> · /bpa level set <player> <n> · /bpa reset <player> · /bpa info <player> · /bpa progress <player> <type> <n> [target] · /bpa season info|start [days] [name]|end|extend <days>|setend <days> · /bpa boost <multiplier> <time> [reason]|stop|info · /bpa setreward <tier> <free|premium> · /bpa clearreward <tier> <free|premium> · /bpa reload</text>"
  reloaded: "<good>Reloaded:</good> <value>{tiers}</value><text> tiers, </text><value>{quests}</value><text> quests.</text>"

  # Names made up for rewards that have no name in tiers.yml.
  reward-money: "{amount} coins"
  reward-perks: "{count} perk(s)"
  reward-special: "a special reward"
  inventory-full: "<warn>Your inventory was full, so {amount} item(s) dropped at your feet.</warn>"

  # Quest names made up for quests that have no name in quests.yml.
  target-any: "anything"
  auto-break: "Break {amount} blocks ({target})"
  auto-place: "Place {amount} blocks ({target})"
  auto-kill_mob: "Kill {amount} mobs ({target})"
  auto-kill_player: "Kill {amount} players"
  auto-fish: "Catch {amount} fish ({target})"
  auto-craft: "Craft {amount} items ({target})"
  auto-smelt: "Smelt {amount} items ({target})"
  auto-walk: "Walk {amount} blocks"
  auto-playtime: "Play for {amount} minutes"
  auto-consume: "Eat or drink {amount} times ({target})"
  auto-enchant: "Enchant {amount} items ({target})"
  auto-trade: "Trade with villagers {amount} times"
  auto-custom: "{type}: {amount}"

  period-daily: "daily"
  period-weekly: "weekly"
  period-season: "season"
  actionbar-progress: "<accent>{quest}</accent> <muted>·</muted> {bar} <value>{progress}/{amount}</value>"
  quest-complete: "<good>Quest done:</good> <value>{quest}</value> <muted>({period})</muted> <accent>+{xp} XP</accent>"
  new-daily: "<text>New daily quests are in. </text><click:run_command:'/bp quests daily'><accent><u>Open them</u></accent></click>"
  new-weekly: "<text>New weekly quests are in. </text><click:run_command:'/bp quests weekly'><accent><u>Open them</u></accent></click>"

  rerolled: "<good>Swapped.</good><text> Here is a new quest.</text>"
  reroll-season: "<text>Season quests cannot be swapped.</text>"
  reroll-none-left: "<bad>No swaps left for this period.</bad>"
  reroll-unknown: "<bad>You do not have that quest.</bad>"
  reroll-done: "<text>That quest is already done.</text>"
  reroll-empty-pool: "<text>There is no other quest to swap it for.</text>"
  season-closed: "<text>No season is running right now.</text>"

  xp-gained: "<accent>+{xp} XP</accent>"
  levelup-title: "<accent><bold>Tier {level}</bold></accent>"
  levelup-subtitle: "<text>New rewards: </text><value>/bp</value>"
  levelup: "<good>Tier {level} reached</good><text> ({level}/{max}). </text><click:run_command:'/bp rewards'><accent><u>Claim your rewards</u></accent></click>"
  levelup-broadcast: "<value>{player}</value><text> reached </text><accent>tier {level}</accent><text> of the battle pass.</text>"

  claim-locked: "<text>You have not reached tier {tier} yet.</text>"
  no-tier: "<bad>There is no tier {tier}.</bad>"
  claim-already: "<text>You already claimed that.</text>"
  claim-need-premium: "<warn>That reward is on the premium track.</warn>"
  claim-empty: "<text>That tier has nothing on this track.</text>"
  claim-cancelled: "<text>That reward cannot be claimed right now.</text>"
  claimed: "<good>Claimed</good><text> tier {tier} ({track}): </text><value>{reward}</value>"
  claimed-all: "<good>Claimed {count} reward(s).</good>"
  claimed-none: "<text>Nothing to claim right now.</text>"
  join-claimable: "<text>You have </text><value>{count}</value><text> battle pass reward(s) waiting. </text><click:run_command:'/bp rewards'><accent><u>Claim them</u></accent></click>"
  usage-claim: "<text>/bp claim [all|<tier> <free|premium>]</text>"
  track-free: "free"
  track-premium: "premium"

  season-started: "<accent><bold>{season}</bold></accent><text> has started. It runs for {time}. </text><click:run_command:'/bp'><accent><u>Open the pass</u></accent></click>"
  season-ended: "<accent><bold>{season}</bold></accent><text> is over. Thank you for playing.</text>"
  season-top-line: "<accent>#{rank}</accent> <value>{player}</value> <muted>·</muted> <text>tier {level}, {xp} XP</text>"
  season-opens-in: "opens in {time}"
  season-none: "no season running"
  time-days: "{d}d {h}h"
  time-hours: "{h}h {m}m"
  time-minutes: "{m}m"
  time-now: "under a minute"

  # The screens. Every line here is a title, a body line, a button label or a tooltip.
  menu-title: "<value>{season}</value>"
  menu-close: "<white><icon:close></white><text>Close</text>"
  menu-back: "<white><icon:back></white><text>Back</text>"
  menu-back-tip: "<text>Back to the screen before.</text>"
  menu-prev: "<white><icon:prev></white><text>Previous</text>"
  menu-prev-tip: "<text>The tiers before these.</text>"
  menu-next: "<white><icon:next></white><text>Next</text>"
  menu-next-tip: "<text>The tiers after these.</text>"
  menu-season: "<accent><bold>{season}</bold></accent> <muted>·</muted> <text>ends in </text><value>{time}</value>"
  menu-season-upcoming: "<accent><bold>{season}</bold></accent> <muted>·</muted> <text>opens in </text><value>{time}</value>"
  menu-season-closed: "<warn>No season is running.</warn><text> What you earned can still be claimed.</text>"
  menu-level: "<text>Tier </text><value>{level}</value><muted>/{max}</muted> <muted>·</muted> <value>{xp}</value><text> XP</text>"
  menu-progress: "{bar} <value>{into}</value><muted>/{step} XP to tier {next}</muted>"
  menu-maxed: "<good>Every tier reached.</good>"
  menu-premium-yes: "<accent>Premium</accent><text> is active: both tracks are yours.</text>"
  menu-premium-no: "<text>Free track. </text><warn>{count} premium reward(s)</warn><text> are unlocked and waiting for premium.</text>"
  menu-premium-no-none: "<text>Free track. </text><accent>Premium</accent><text> adds a second reward to every tier.</text>"
  menu-boost: "<good>XP boost: x{boost}</good>"
  menu-event-boost: "<accent><bold>XP event:</bold></accent> <value>x{boost}</value><text> for everyone, </text><value>{time}</value><text> left</text>"
  menu-next-free: "<text>Next, tier {tier} </text><muted>free</muted><newline><value>{reward}</value>"
  menu-next-premium: "<text>Next, tier {tier} </text><accent>premium</accent><newline><value>{reward}</value>"
  menu-claim-all: "<white><icon:claim></white><good>Claim all ({count})</good>"
  menu-claim-all-tip: "<text>Every reward you can take right now.</text>"
  menu-rewards: "<white><icon:rewards></white><value>Rewards</value>"
  menu-rewards-tip: "<text>Every tier, free and premium, and what you can claim.</text>"
  menu-quests-daily: "<white><icon:daily></white><value>Daily quests</value> <muted>{done}/{total}</muted>"
  menu-quests-daily-tip: "<text>New ones every day.</text>"
  menu-quests-weekly: "<white><icon:weekly></white><value>Weekly quests</value> <muted>{done}/{total}</muted>"
  menu-quests-weekly-tip: "<text>Bigger quests, new ones every week.</text>"
  menu-quests-season: "<white><icon:season></white><value>Season quests</value> <muted>{done}/{total}</muted>"
  menu-quests-season-tip: "<text>Long goals for the whole season.</text>"
  menu-top: "<white><icon:top></white><value>Top players</value>"
  menu-top-tip: "<text>Who is furthest this season.</text>"
  menu-get-premium: "<white><icon:premium></white><accent>Get premium</accent>"
  menu-get-premium-tip: "<text>Opens the store: </text><value>{url}</value>"

  track-title: "<value>{season}</value><text> rewards</text>"
  track-head: "<text>Tier </text><value>{level}</value><muted>/{max}</muted> <muted>·</muted> <value>{xp}</value><text> XP</text> <muted>· page {page}/{pages}</muted>"
  track-premium-hint: "<muted>Premium rewards unlock with the premium pass, and stay claimable for every tier you already reached.</muted>"
  track-nothing: "<muted>nothing</muted>"
  track-row-free: "<value>Tier {tier}</value> <muted>free · {xp} XP</muted><newline>{reward} {state}"
  track-row-premium: "<accent>Tier {tier}</accent> <muted>premium</muted><newline>{reward} {state}"
  track-claim-free: "<white><icon:free></white><good>Claim tier {tier}</good>"
  track-claim-premium: "<white><icon:premium></white><accent>Claim tier {tier} premium</accent>"
  track-claim-tip: "<text>Take </text><value>{reward}</value>"
  state-claimed: "<good>claimed</good>"
  state-locked: "<muted>locked</muted>"
  state-premium-locked: "<warn>premium</warn>"
  state-claimable: "<good><bold>ready</bold></good>"
  state-closed: "<muted>season closed</muted>"

  quests-title-daily: "<value>Daily quests</value>"
  quests-title-weekly: "<value>Weekly quests</value>"
  quests-title-season: "<value>Season quests</value>"
  quests-head-daily: "<text>New daily quests in </text><value>{time}</value>"
  quests-head-weekly: "<text>New weekly quests in </text><value>{time}</value>"
  quests-head-season: "<text>These run until the season ends, in </text><value>{time}</value>"
  quests-rerolls: "<text>Swaps left: </text><value>{count}</value>"
  quests-closed: "<warn>No season is running, so quests are paused.</warn>"
  quests-empty: "<text>No quests here right now.</text>"
  quest-row: "<value>{quest}</value> <accent>+{xp} XP</accent><newline>{bar} <text>{progress}/{amount}</text>"
  quest-row-done: "<good>{quest}</good> <muted>+{xp} XP</muted><newline><good>Done</good>"
  quest-row-premium: "<value>{quest}</value> <accent>+{xp} XP</accent><newline><warn>Premium quest</warn>"
  quests-reroll: "<white><icon:reroll></white><text>Swap: {quest}</text>"
  quests-reroll-tip: "<text>Trades this quest for a random other one. Progress on it is lost.</text>"

  top-title: "<value>{season}</value><text> top players</text>"
  top-row: "<accent>#{rank}</accent> <value>{player}</value> <muted>·</muted> <text>tier {level}, {xp} XP</text>"
  top-row-you: "<accent>#{rank}</accent> <good>{player}</good> <muted>·</muted> <text>tier {level}, {xp} XP</text> <muted>(you)</muted>"
  top-empty: "<text>Nobody has earned XP yet this season.</text>"

  placeholder-yes: "Yes"
  placeholder-no: "No"
  # %battlepass_top_N_name% for a rank nobody holds yet.
  placeholder-top-empty: "-"

  # The server-wide XP boost (/bpa boost). {reason} is boost-reason, or nothing when none was given.
  boost-started: "<accent><bold>XP boost!</bold></accent><text> Everyone earns </text><value>x{boost}</value><text> battle pass XP for the next </text><value>{time}</value><text>.</text>{reason} <click:run_command:'/bp'><accent><u>Open the pass</u></accent></click>"
  boost-extended: "<accent><bold>XP boost extended!</bold></accent><text> </text><value>x{boost}</value><text> XP now runs for another </text><value>{time}</value><text>.</text>{reason}"
  boost-ended: "<text>The </text><accent>XP boost</accent><text> is over. Thanks for playing!</text>"
  boost-stopped: "<text>The </text><accent>XP boost</accent><text> was ended early.</text>"
  boost-reason: " <muted>({reason})</muted>"

  # Admin.
  usage-xp: "<text>/bpa xp give|take|set <player> <amount></text>"
  xp-done: "<value>{player}</value><text> now has </text><value>{xp}</value><text> XP (tier {level}).</text>"
  usage-level: "<text>/bpa level set <player> <level></text>"
  bad-level: "<bad>Levels go from 0 to {max}.</bad>"
  level-done: "<value>{player}</value><text> is now tier </text><value>{level}</value><text>.</text>"
  usage-reset: "<text>/bpa reset <player></text>"
  reset-done: "<value>{player}</value><text>'s pass for this season was reset.</text>"
  usage-info: "<text>/bpa info <player></text>"
  info: "<value>{player}</value><text>: season {season}, tier {level}/{max}, {xp} XP, claimed {free} free and {premium} premium, has premium: {haspremium}</text>"
  info-quest: "<muted>  {period}</muted> <text>{quest}: {progress}/{amount}</text> {done}"
  info-done: "<good>done</good>"
  usage-progress: "<text>/bpa progress <player> <type> <amount> [target]</text>"
  progress-done: "<text>Reported </text><value>{amount}</value><text> {type} for </text><value>{player}</value><text>.</text>"
  usage-season: "<text>/bpa season info · start [days] [name] · end · extend <days> · setend <days></text>"
  season-start-done: "<good>Started</good> <value>{season}</value><text>. It ends {end}.</text>"
  season-none-running: "<text>No season is running.</text>"
  season-end-done: "<value>{season}</value><text> was ended.</text>"
  season-moved: "<text>The season now ends </text><value>{end}</value><text>.</text>"
  season-info: "<value>{season}</value> <muted>(#{number})</muted><text>: {state}, {start} to {end}, {left}. Daily reset in {daily}, weekly in {weekly}.</text>"
  season-left: "{time} left"
  season-closed-short: "closed"
  state-running: "running"
  state-upcoming: "booked"
  state-ended: "ended"
  usage-setreward: "<text>/bpa setreward <tier> <free|premium>  (adds the item in your hand)</text>"
  reward-added: "<good>Added</good> <value>{item}</value><text> to tier {tier} ({track}).</text>"
  usage-clearreward: "<text>/bpa clearreward <tier> <free|premium></text>"
  reward-nothing: "<text>That tier has nothing on that track.</text>"
  reward-cleared: "<text>Emptied tier {tier} ({track}).</text>"
  usage-boost: "<text>/bpa boost <multiplier> <time> [reason] · /bpa boost stop · /bpa boost info. Multiplier above 1 up to 10, time like 30m, 2h, 1d (up to 30 days).</text>"
  boost-done: "<good>XP boost x{boost}</good><text> runs for </text><value>{time}</value><text>.</text>"
  boost-info: "<text>XP boost </text><value>x{boost}</value><text>, </text><value>{time}</value><text> left.</text>{reason}"
  boost-none: "<text>No XP boost is running.</text>"
  boost-stop-done: "<text>The XP boost was stopped.</text>"

quests.yml

Top-level keys:

KeyDefaultComment above it
dailysection, 17 keysnone
weeklysection, 10 keysnone
seasonsection, 5 keysnone
plugins/BattlePass/quests.yml
# BattlePass quests.
#
# Three pools. Each player draws quests.daily.count daily quests and quests.weekly.count weekly
# quests from these pools (see config.yml), new ones every day and every week. Season quests are
# given to everybody, all of them, for the whole season.
#
# A quest:
#   type:     break, place, kill_mob, kill_player, fish, craft, smelt, walk, playtime, consume,
#             enchant, trade, or a type another plugin registered through the API.
#   targets:  what counts. Materials or entity types ("STONE", "ZOMBIE"), or tags with a #
#             ("#logs", "#minecraft:diamond_ores"). Leave it out and anything counts.
#   amount:   how much. Blocks for walk, minutes for playtime, items for craft and smelt.
#   xp:       season XP it pays.
#   name:     what the screens call it (MiniMessage). Made up from type and amount when left out.
#   icon:     the item shown beside it. Defaults to the first target, else one per type.
#   weight:   how often it is drawn compared to the others in its pool (default 10).
#   premium:  true means only premium players are given it (and it only counts for them).
#
# Quest ids are what is stored for every player: renaming one hands everybody a fresh quest.

daily:
  mine-stone:
    name: "Mine 128 stone"
    type: break
    targets: [STONE, COBBLESTONE, DEEPSLATE, COBBLED_DEEPSLATE, ANDESITE, DIORITE, GRANITE, TUFF]
    amount: 128
    xp: 150
  chop-logs:
    name: "Chop 48 logs"
    type: break
    targets: ["#logs"]
    amount: 48
    xp: 150
  dig-ores:
    name: "Mine 12 ores"
    type: break
    targets: ["#coal_ores", "#iron_ores", "#copper_ores", "#gold_ores", "#redstone_ores", "#lapis_ores", "#diamond_ores", "#emerald_ores"]
    icon: IRON_ORE
    amount: 12
    xp: 175
  build:
    name: "Place 96 blocks"
    type: place
    amount: 96
    xp: 125
  zombies:
    name: "Kill 15 zombies"
    type: kill_mob
    targets: [ZOMBIE, HUSK, DROWNED, ZOMBIE_VILLAGER]
    amount: 15
    xp: 150
  skeletons:
    name: "Kill 12 skeletons"
    type: kill_mob
    targets: [SKELETON, STRAY, BOGGED]
    amount: 12
    xp: 150
  any-mobs:
    name: "Kill 25 mobs"
    type: kill_mob
    amount: 25
    xp: 150
  fishing:
    name: "Catch 8 fish"
    type: fish
    amount: 8
    xp: 150
  bake-bread:
    name: "Craft 16 bread"
    type: craft
    targets: [BREAD]
    amount: 16
    xp: 125
  smelt-iron:
    name: "Smelt 24 iron"
    type: smelt
    targets: [IRON_INGOT]
    amount: 24
    xp: 150
  walk:
    name: "Walk 1,500 blocks"
    type: walk
    amount: 1500
    xp: 125
  play:
    name: "Play for 45 minutes"
    type: playtime
    amount: 45
    xp: 125
  eat:
    name: "Eat 10 times"
    type: consume
    amount: 10
    xp: 100
  enchant:
    name: "Enchant 2 items"
    type: enchant
    amount: 2
    xp: 175
  trade:
    name: "Trade with villagers 5 times"
    type: trade
    amount: 5
    xp: 175
  pvp:
    name: "Win 3 fights against players"
    type: kill_player
    amount: 3
    xp: 200
    weight: 4
  premium-diamonds:
    name: "Mine 6 diamonds"
    type: break
    targets: ["#diamond_ores"]
    icon: DIAMOND
    amount: 6
    xp: 250
    premium: true

weekly:
  miner:
    name: "Mine 2,000 blocks"
    type: break
    amount: 2000
    xp: 600
  builder:
    name: "Place 1,500 blocks"
    type: place
    amount: 1500
    xp: 600
  hunter:
    name: "Kill 150 mobs"
    type: kill_mob
    amount: 150
    xp: 650
  creepers:
    name: "Kill 30 creepers"
    type: kill_mob
    targets: [CREEPER]
    amount: 30
    xp: 650
  angler:
    name: "Catch 60 fish"
    type: fish
    amount: 60
    xp: 600
  traveller:
    name: "Walk 15,000 blocks"
    type: walk
    amount: 15000
    xp: 600
  regular:
    name: "Play for 6 hours"
    type: playtime
    amount: 360
    xp: 650
  smith:
    name: "Smelt 200 items"
    type: smelt
    amount: 200
    xp: 600
  enchanter:
    name: "Enchant 12 items"
    type: enchant
    amount: 12
    xp: 700
  premium-ancient:
    name: "Mine 8 ancient debris"
    type: break
    targets: [ANCIENT_DEBRIS]
    amount: 8
    xp: 900
    premium: true

season:
  marathon:
    name: "Walk 100,000 blocks"
    type: walk
    amount: 100000
    xp: 2000
  veteran:
    name: "Play for 40 hours"
    type: playtime
    amount: 2400
    xp: 2500
  slayer:
    name: "Kill 1,500 mobs"
    type: kill_mob
    amount: 1500
    xp: 2500
  dragon:
    name: "Kill the Ender Dragon"
    type: kill_mob
    targets: [ENDER_DRAGON]
    icon: DRAGON_HEAD
    amount: 1
    xp: 3000
  diamonds:
    name: "Mine 100 diamonds"
    type: break
    targets: ["#diamond_ores"]
    icon: DIAMOND
    amount: 100
    xp: 2500

tiers.yml

Top-level keys:

KeyDefaultComment above it
default-step400none
tier-count30Use this to make the pass longer than the highest tier written below (the extra tiers are empty).
tierssection, 30 keysnone
plugins/BattlePass/tiers.yml
# BattlePass tiers and rewards.
#
# A tier's "xp" is the TOTAL season XP that reaches it. A tier without one sits default-step XP
# above the tier before it. Tier numbers run 1, 2, 3...; a missing number is an empty tier.
#
# Every tier can have a free reward and a premium reward. A reward can hold any mix of:
#   name:        what the screens call it (MiniMessage). Made up from the contents when left out.
#   icon:        the item the screens show, written like an item below. Defaults to the first item.
#   items:       written exactly as /give takes them, components included, with " xN" for a stack:
#                  - "diamond x3"
#                  - "diamond_sword[enchantments={sharpness:5,unbreaking:3}]"
#                  - "netherite_sword[custom_name={text:'Season Blade',color:'light_purple',italic:false}]"
#                An item added in game with /bpa setreward is stored as  - data: <bytes>  and keeps
#                every component it had.
#   commands:    run by the console. {player} {uuid} {tier} {track} {season}
#   money:       paid through Vault, when Vault and an economy plugin are installed.
#   permissions: given through LuckPerms or kept by BattlePass (see rewards.permission-mode).
#
# The fastest way to build a pass: hold the item and run /bpa setreward <tier> <free|premium>.

default-step: 400

# Use this to make the pass longer than the highest tier written below (the extra tiers are empty).
tier-count: 30

tiers:
  "1":
    xp: 200
    free: { items: ["bread x16"] }
    premium: { items: ["iron_ingot x16"] }
  "2":
    xp: 500
    free: { items: ["torch x32"] }
    premium: { items: ["golden_apple x2"], money: 250 }
  "3":
    free: { items: ["iron_ingot x8"] }
    premium: { items: ["experience_bottle x16"] }
  "4":
    free: { money: 150 }
    premium: { items: ["diamond x2"] }
  "5":
    free: { items: ["golden_apple x2"] }
    premium:
      name: "<accent>Pass Pickaxe</accent>"
      items: ["diamond_pickaxe[enchantments={efficiency:4,unbreaking:3}]"]
  "6":
    free: { items: ["cooked_beef x32"] }
    premium: { items: ["ender_pearl x8"] }
  "7":
    free: { items: ["experience_bottle x8"] }
    premium: { items: ["diamond x4"], money: 300 }
  "8":
    free: { items: ["arrow x64"] }
    premium: { items: ["enchanted_book[stored_enchantments={mending:1}]"] }
  "9":
    free: { items: ["lapis_lazuli x32"] }
    premium: { items: ["golden_carrot x32"] }
  "10":
    free: { items: ["diamond x3"] }
    premium:
      name: "<accent>Shulker box</accent> and 500 coins"
      items: ["shulker_box"]
      money: 500
  "11":
    free: { items: ["iron_block x2"] }
    premium: { items: ["firework_rocket[fireworks={flight_duration:2}] x32"] }
  "12":
    free: { money: 250 }
    premium: { items: ["diamond_block"] }
  "13":
    free: { items: ["golden_apple x3"] }
    premium: { items: ["experience_bottle x32"] }
  "14":
    free: { items: ["ender_pearl x4"] }
    premium: { items: ["enchanted_book[stored_enchantments={unbreaking:3}]"] }
  "15":
    free: { items: ["diamond x4"] }
    premium:
      name: "<accent>Totem of Undying</accent>"
      items: ["totem_of_undying"]
  "16":
    free: { items: ["gold_block x2"] }
    premium: { items: ["netherite_scrap x2"] }
  "17":
    free: { items: ["experience_bottle x16"] }
    premium: { money: 750 }
  "18":
    free: { items: ["obsidian x16"] }
    premium: { items: ["diamond x8"] }
  "19":
    free: { items: ["blaze_rod x8"] }
    premium: { items: ["enchanted_book[stored_enchantments={efficiency:5}]"] }
  "20":
    free: { items: ["diamond_block"] }
    premium:
      name: "<accent>Enchanted Golden Apple</accent>"
      items: ["enchanted_golden_apple"]
  "21":
    free: { money: 400 }
    premium: { items: ["netherite_scrap x2"] }
  "22":
    free: { items: ["golden_carrot x32"] }
    premium: { items: ["shulker_box"] }
  "23":
    free: { items: ["ender_pearl x8"] }
    premium: { items: ["experience_bottle x64"] }
  "24":
    free: { items: ["diamond x6"] }
    premium: { items: ["totem_of_undying"] }
  "25":
    free: { items: ["netherite_scrap"] }
    premium:
      name: "<accent>Season Boots</accent>"
      items: ["diamond_boots[enchantments={protection:4,feather_falling:4,unbreaking:3}]"]
  "26":
    free: { items: ["emerald_block x2"] }
    premium: { money: 1000 }
  "27":
    free: { items: ["golden_apple x4"] }
    premium: { items: ["netherite_ingot"] }
  "28":
    free: { items: ["experience_bottle x32"] }
    premium: { items: ["enchanted_golden_apple"] }
  "29":
    free: { items: ["diamond_block x2"] }
    premium: { items: ["netherite_ingot"] }
  "30":
    free:
      name: "<value>Netherite Ingot</value>"
      items: ["netherite_ingot"]
    premium:
      name: "<accent><bold>Season Blade</bold></accent>"
      items:
        - "netherite_sword[custom_name={text:'Season Blade',color:'light_purple',italic:false},enchantments={sharpness:5,unbreaking:3,looting:3}]"
      commands:
        - "say {player} finished the whole season {season} pass!"

Config guide

The annotated summary from the store page. Where it and the default file above differ, the file is what the plugin ships.

tiers.yml
  default-step: 400              XP between tiers that set none
  tiers:
    "5":
      xp: 1700                   total season XP that reaches tier 5
      free: { items: ["golden_apple x2"] }
      premium:
        name: "<accent>Pass Pickaxe</accent>"
        items: ["diamond_pickaxe[enchantments={efficiency:4,unbreaking:3}]"]
        commands: ["say {player} reached tier {tier}"]
        money: 250
        permissions: ["essentials.fly"]

quests.yml
  daily:
    chop-logs:
      name: "Chop 48 logs"
      type: break
      targets: ["#logs"]
      amount: 48
      xp: 150
      premium: false             true = only premium players get it

config.yml
  premium.permission, premium.store-url, premium.xp-multiplier
  season.length-days, season.auto-restart, season.first-start, season.end-commands
  resets.timezone, resets.daily-hour, resets.weekly-day
  quests.daily.count, premium-extra, rerolls, rerolls-premium (same for weekly)
  rewards.permission-mode, rewards.auto-claim-free
  theme: one block of colours for every screen

Differences between this summary and the shipped files (an example in the summary may use values of its own):

FAQ

Which servers and versions does it run on?

It needs Paper or a Paper fork such as Purpur, because it uses Paper-only APIs (the dialog API for its menus, Adventure text components). Spigot and CraftBukkit are not supported. plugin.yml declares api-version 1.21, the jar is built against Paper API 1.21.11, and it needs Java 21 or newer.

Does it need other plugins?

No other plugin is required (plugin.yml has no hard dependencies). Optional: PlaceholderAPI, Vault (plugin.yml softdepend), used when present. The server downloads org.xerial:sqlite-jdbc:3.53.2.1 at startup, so it needs internet access on first start.

How do I apply config changes?

Edit plugins/BattlePass/config.yml and run /bpa reload (read config.yml, tiers.yml and quests.yml again). A restart works too.

Does it run on Folia, or for Bedrock players?

Not tested on Folia, and plugin.yml does not declare folia-supported. Bedrock players (through Geyser) have not been tested either.

What licence do I get?

The licence terms are the BuiltByBit EULA shown on the listing. There is no licence key to enter, and the plugin never contacts a licence server.