Configuration
ShadowBattlePass
A season, a hundred and forty missions, and a reason to come back tomorrow.
Where the files are
plugins/ShadowBattlePass/ The plugin creates them on first start and updates them by itself on new versions, keeping your changes.
Applying changes
/bpa reload Reloads the files without restarting the server.
No setting found
Try another word, or search every plugin.
Settings
The files that decide how the plugin behaves. Start here.
config.yml
General settings 103 settings
config.ymlplugins/ShadowBattlePass/config.yml File notes
On update your files (this one, seasons/, quests/, lang/, menus/ and the others below) are moved to the new version automatically: every value you changed or added stays, new options arrive with their comments, and what you deleted stays deleted. The old copies are in backup/<date>/; if something needs your attention you will find PORTING-<version>.txt in the plugin folder.
A wrong value blocks nothing: it is replaced with the factory one and reported in console at start-up, with the path and expected value.
Where things live:
config.yml this file: storage, rules, notifications, hooks seasons/*.yml the seasons: tiers, tracks, rewards quests/*.yml the quests, one file per pool (daily, weekly, ...) rewards.yml reusable reward bundles boosters.yml scheduled multipliers (weekend, happy hour) shop.yml the shop you pay with pass coins challenges.yml the server-wide challenges lang/*.yml the messages menus/*.yml the layout of every screen
config-version4storage7 keysstorage.mysql7 keysenabledfalsefalse = local H2 database inside plugins/ShadowBattlePass/data/. Nothing to install: the plugin works the moment it is copied in. Put your credentials here and restart: the plugin creates every table on its own, and nothing in the local file is touched.
host127.0.0.1port3306databaseshadowbattlepassusernamerootpassword""parameters"useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&characterEncoding=utf8"storagetable-prefix"bp_"Table prefix. Change it and the plugin creates new tables and starts from scratch: useful for two servers sharing one database.
fallback-to-localtrueMySQL configured but unreachable: with true the plugin says so in console and falls back to the local file, so the server still starts.
flush-interval"30s"How often changed progress reaches the database. On shutdown a blocking save always happens, whatever this value says.
storage.pool5 keysmaximum-pool-size10minimum-idle2connection-timeout-ms10000idle-timeout-ms600000max-lifetime-ms1800000storage.h21 keyauto-serverfalseLets another process - a web panel, say - open the same H2 file while the server is running. Rarely needed.
Several servers on one database
Only needed if you run a network (lobby + survival + ...) sharing one MySQL. The servers pass news to each other through the database: no ports to open, nothing to install on the proxy.
Keep reading
What travels is a NOTICE, never a value: a message says "the season changed", not "the season is now season-2". Whoever gets it goes and re-reads the truth from the database, so two servers that change something in the same second converge instead of overwriting.
A player's pass does not need to travel: you are on one server at a time, the pass loads on join and is written on quit, and two servers never hold the same player.
storage.sync5 keysmodeAUTOAUTO = on when you use MySQL, off on the local database. ON | OFF to decide it yourself.
primarytrueIMPORTANT: across a network, EXACTLY ONE server may have primary: true. That is the one that starts and ends seasons and fires the scheduled challenges. The others read and display.
server-idautoA name for this server. "auto" uses hostname + port. Two servers must never share one.
poll-interval"3s"How often to read what the others have done.
keep-messages"1h"How long to keep messages already read before deleting them.
Messages and languages
messages2 keysdefault-locale"en_US"The language used when the player's own is not in lang/, and by the console. Ships with en_US and it_IT: set "it_IT" for an Italian server.
follow-client-localetruetrue = every player sees messages in their client's language. They can still pick one with /bp lang.
Time
This decides when quests rotate. It applies to everyone at the same instant: two players online on the same day get the same daily quests, and the reset is not "24 hours after your first login".
time3 keyszone"system""system" uses the server's zone. Or name one, e.g. "Europe/Rome".
daily-reset"00:00"What time the daily quests change. Before this hour the day has not turned yet, so somebody playing at 3 in the morning does not lose a whole cycle.
week-startsMONDAYWhich day the week starts on, for the weekly quests.
Where and how experience is earned
worlds2 keysonly-in[ ]If this list is NOT empty, the pass works ONLY in these worlds.
never-in[lobby]Otherwise it works everywhere except here.
earning3 keysconditions[ ]Requirements that must hold for experience to be counted. Same syntax as the quest conditions (see docs/07).
- "gamemode: survival, adventure" - "not-world: creative"
daily-xp-cap0Daily experience ceiling per player. 0 = no ceiling. Not a punishment: it is what stops an afk farm from closing a ninety day season in one afternoon.
earning.xp-sources7 keysPassive experience: how much every single action gives, even with no quest active. Leave empty for a pass that advances ONLY through quests, which is the commonest and the best balanced choice.
For amount-based actions (damage, money, distance) the number is per unit, with an internal cap so one hit cannot produce absurd numbers.
Full list of types: docs/05-OBIETTIVI.md
ORE_MINE1MOB_KILL1ITEM_FISH2CROP_HARVEST1ADVANCEMENT25RAID_WIN100BOSS_KILL250Anti abuse
This is what keeps a "break 500 ores" quest about mining instead of becoming "place and break the same block 500 times".
anti-abuse6 keysignore-placed-blockstrueA block placed by a player does not count when it is broken. The memory lives in the chunk itself, so it survives a restart.
placed-blocks-per-chunk4096How many placed blocks to remember per chunk. Past this number the oldest ones are forgotten.
ignore-spawner-mobstrueMobs out of a spawner or an egg do not count for quests that ask you to kill. Individual quests may override this.
ignore-afktrueSomebody who has not moved the mouse for a while is not playing: their actions do not count until they come back.
afk-after"5m"max-events-per-second64Ceiling of events per second per player. Not an anticheat: a safety net against machines that break thousands of blocks a second. 0 = no limit.
Claiming rewards
claiming5 keysauto-claim-tiersfalsetrue = rewards arrive on their own as soon as you gain a tier. false = the player clicks, which feels better and is far commoner.
auto-claim-questsfalseSame for finished quests.
auto-claim-on-season-endtrueAt the end of a season everything left unclaimed is handed over anyway. Leave this on: nobody should lose a reward they had earned just because they were offline.
allow-tier-dropfalseIf you lower the curve mid-season, true recalculates downwards for anyone already past it. Normally you do not want that.
mailboxtrueMailbox: an item that does not fit the inventory is not dropped and does not vanish, it waits there until there is room. Switch it off and a reward that does not fit is refused.
Notifications
The delicate part of a battle pass. Too little and progress is invisible; too much and the chat is unreadable after a minute.
notifications8 keysjoin-summarytrueA summary in chat when a player joins.
notifications.xp2 keysenabledtrueExperience gained shows in the action bar, never in chat.
every"1s"Gains are added up and shown at most once every:
notifications.boss-bar2 keysenabledtrueA bar under the crosshair while experience moves.
ticks60How many ticks it stays visible after the last gain.
notifications.bar3 keyslength20The characters of the progress bar, used everywhere.
full"█"empty"░"notifications.tier3 keystitletrueA title on screen when a tier is gained.
broadcast-every10Announce to everyone in chat every N tiers. 0 = never.
sound"entity.player.levelup 0.7 1.2"notifications.quest4 keystitletruesound"entity.experience_orb.pickup 0.8 1.4"progresstrueProgress notices during a long quest.
progress-steps4In how many steps: 4 means at 25%, 50%, 75%. 0 = never.
notifications.challenge-bar2 keysenabledtrueformat"<gradient:#B388FF:#7C4DFF><challenge></gradient> <white><progress>/<goal> <gray>(<time>)"notifications.announce3 keysseason-starttruetrack-unlocktruequest-resettrueLogin streaks
The cheapest and most honest way to bring somebody back tomorrow.
streaks3 keysenabledtruegrace-days1How many days you may miss without losing the streak. Losing thirty days in a row to one disconnection makes people stop playing, not play more.
streaks.rewards5 keysThe table may have gaps: whoever reaches day 12 gets the day 7 prize, not nothing.
1["coins: 10"]3["coins: 25", "xp: 100"]7["coins: 75", "xp: 500", "message: <gradient:#FFD54F:#FF8F00>A whole week in a row!</gradient>"]+1
14["coins: 150", "xp: 1000"]30["coins: 500", "xp: 3000", "tier: 1", "broadcast: &6<player> has played 30 days in a row!"]+1
Catch-up for whoever falls behind
A season is fun for as long as catching up looks possible. Whoever joins late, or comes back after two weeks, earns faster - up to a ceiling, and only until they have caught the others.
catch-up3 keysenabledtruebehind-tiers10How many tiers below average you must be for it to kick in.
max-multiplier2.0The most it can ever multiply by.
Gifting the pass
Buying a track for a friend. It is the most requested feature of any battle pass and the one nobody implements: it costs the server nothing - the money leaves the economy either way - and it turns the premium track into something you can give for a birthday, which sells far more copies than any discount.
gifting3 keysenabledtruemarkup0.0Surcharge, as a fraction. 0 = none, 0.1 = ten per cent more. Zero by default: gifting should be encouraged, not taxed.
announcetrueAnnounce the gift to the other players.
Leaderboard
leaderboard3 keyssize100How many places to keep in memory.
refresh"2m"How often it is recalculated.
hologram-size10How many places the floating leaderboard shows. Place it with /bpa hologram place <board>, standing where you want it. Needs ShadowEssentials for the holograms.
Screens
gui2 keysinput-timeout"60s"How long an administrator has to answer a question the editor asks in chat before it is cancelled.
refresh-ticks20Housekeeping
housekeeping3 keyshistory-days60How many days to keep the history of rewards given. 0 = forever.
mailbox-days30How many days to keep parcels already delivered.
quest-days30How many days to keep progress of cycles closed and claimed.
Integrations
All optional. A missing plugin degrades one feature and never stops a start-up.
integrations3 keyssuitetrueAnnounce ourselves to ShadowEssentials, so /se suite lists us.
integrations.permissions3 keysgrant-command""The command used to grant a permission as a reward. Leave empty to let the plugin choose: it recognises ShadowPermissions, LuckPerms, PermissionsEx and GroupManager. Placeholders: <player> <node> <duration>
grant-timed-command""revoke-command""integrations.crates1 keygive-command""The command used to give crate keys as a reward. Empty = recognises ShadowCrazyChest, CrazyCrates, ExcellentCrates. Placeholders: <player> <crate> <amount>
Diagnostics
debug1 keylog-sqlfalseWrites every query to console. Only to chase a problem down: on a real server it fills the log in minutes.
bStats (anonymous usage statistics, https://bStats.org)
What is sent, every 30 minutes: a random server id (serverUuid, not derived from anything), the plugin version, the Minecraft/Paper and Java versions, the operating system and core count, the online mode, how many players are online (a number only) and the licence tier (free/premium/creator). NO player data: no names, no UUIDs, no addresses, no progress. Nothing is sent while the plugin waits for a licence.
Keep reading
false switches off this plugin only. enabled: false in plugins/bStats/config.yml switches off every bStats plugin on the server at once.
metrics1 keyenabledtrueThe licence
Without a key the plugin runs the free edition. It never switches itself off and never deletes anything: what exceeds the limits is not loaded but stays on disk, intact, and comes back when a key arrives.
Keep reading
The key does NOT go here. It lives in license.yml, a separate file on purpose: a support request saying "send me your config" must not arrive with somebody's licence inside it. The field below exists only for people who generate the config from a deploy system.
license3 keysTHE KEY LIVES IN license.yml (same folder as this file), or in the central plugins/ShadowControl/licenses.yml for the whole suite. The 'key' below is only a fallback for deploy systems that generate config.yml: leave it empty.
The key does NOT live here: it lives in license.yml, in this folder, written at first start (or in plugins/ShadowControl/licenses.yml for the whole suite). Left empty: use /bpa license activate <key>, or license.yml.
activation-url'https://shadow-licences.riccardobotins.workers.dev'The BASE address of the activation service. The plugin appends /claim and /check itself. Empty means no automatic activation: keys are pasted by hand and everything else keeps working.
grace-days7How many days of grace when a licence expires or the addresses do not match. Seven, because a renewal that arrives on Monday morning must not cost anybody a weekend, and because an address that does not match is far more often a NAT than a thief.
resolve-public-iptrueAsk the licence service (activation-url + /ip) what this server's public address is: it answers with the address it sees, and nothing about the server is sent. Only needed to match a licence binding behind NAT. Switch it off if you prefer the plugin to talk to nobody. Only when a licence is installed: a server without a key asks nobody. false = never ask.
boosters.yml
Boosters 21 settings
boosters.ymlplugins/ShadowBattlePass/boosters.yml File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/boosters.yml
Copy it over this file to use it (copiala al posto di questo file).
The experience multipliers.
They come from four different places and all end up as one number:
1. PERMISSION shadowbattlepass.booster.150 -> x1.5 The number is a percentage: 200 doubles it. 2. SCHEDULE the windows defined below (weekend, happy hour) 3. PERSONAL bought in the shop or handed out as a reward 4. GLOBAL started by an administrator for the whole server
How they combine is a decision, not an accident: see "stacking".
config-version2stackingfalsefalse = the best one wins. true = they multiply together.
Leave this on false unless you know exactly what you are doing: two boosters that stack are the quickest way to have a season finished over a single weekend.
max-multiplier5.0The hard ceiling, whatever the rules above end up saying.
Scheduled windows
Each one switches itself on during the days and hours named here. Drop "days" to make it apply every day. Drop "from" and "to" to make it apply all day. Add "permission" to limit it to one group.
schedules4 keysschedules.weekend4 keysenabledtruedisplay"&6Weekend x1.5"multiplier1.5days[SATURDAY, SUNDAY]schedules.happy-hour5 keysenabledtruedisplay"&bHappy hour x2"multiplier2.0from"20:00"to"22:00"schedules.night-shift5 keysA window that crosses midnight works fine: 22:00 -> 02:00.
enabledfalsedisplay"&9Night shift x1.25"multiplier1.25from"22:00"to"02:00"schedules.vip4 keysOnly for whoever holds a permission: the first days of a rank, say.
enabledfalsedisplay"&dVIP bonus"multiplier1.25permission"shadowbattlepass.booster.vip" challenges.yml
Challenges 52 settings
challenges.ymlplugins/ShadowBattlePass/challenges.yml File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/challenges.yml
Copy it over this file to use it (copiala al posto di questo file).
Something the whole server does together.
"Kill fifty thousand zombies by Sunday night." One bar, everybody pushing it, a prize when it fills. This is what turns a battle pass from a personal to-do list into something people talk about in chat - and no other plugin of this kind has it.
Everyone's contribution is recorded, so the prize can be fair: whoever helped gets something, whoever helped most gets more, and whoever turned up in the last minute does not take home the same prize as the person who carried it.
Objectives use the same types as quests: docs/05-OBIETTIVI.md
config-version2enabledtruechallenges3 keysSaturday night, two hours, everybody killing undead
challenges.purge13 keysenabledtruedisplay"<gradient:#EF5350:#B71C1C><bold>The Purge</bold></gradient>"description["&7The whole server against the undead.", "&7Two hours to take out ten thousand."]+1
iconZOMBIE_HEADchallenges.purge.objective3 keystypeMOB_KILLtarget[ZOMBIE, SKELETON, HUSK, DROWNED, STRAY, ZOMBIE_VILLAGER]+3
no-spawner-mobstrueSpawner mobs do not count: that would be a lever, not a battle.
challenges.purgegoal10000duration2hauto-starttrueWhen it starts by itself. Drop "auto-start" to run it by hand only, with /bpa challenge start purge.
periodWEEKLYdays[SATURDAY]at"21:00"xp-per-contribution2Experience given on every contribution, while the challenge runs.
challenges.purge.rewards4 keysmin-contribution25How much you must have done to count as a participant.
participant["coins: 100", "money: 10000"]challenges.purge.rewards.top3 keysFirst place takes the "1" prize, second and third take the "3" one, fourth to tenth take the "10" one.
1["bundle: epic-crate", "broadcast: &6<player> led the Purge!"]+1
3["bundle: rare-crate"]10["bundle: common-crate"]challenges.purge.rewardseveryone["booster: 1.5 1h"]Given to everybody online when the challenge is won, even to those who never lifted a finger. It makes the event land for everyone.
Sunday afternoon, everybody digging
challenges.big-dig13 keysenabledtruedisplay"<gradient:#4FC3F7:#0288D1><bold>The Great Dig</bold></gradient>"description["&7A hundred thousand blocks of stone.", "&7Sounds like a lot. It is not, if everybody pitches in."]+1
iconDIAMOND_PICKAXEchallenges.big-dig.objective3 keystypeBLOCK_BREAKtarget[STONE, DEEPSLATE, ANDESITE, DIORITE, GRANITE, TUFF]+3
no-placed-blockstruechallenges.big-diggoal100000duration3hauto-starttrueperiodWEEKLYdays[SUNDAY]at"16:00"xp-per-contribution1challenges.big-dig.rewards3 keysmin-contribution200participant["coins: 75"]challenges.big-dig.rewards.top2 keys1["bundle: epic-crate"]5["bundle: rare-crate"]By hand only: the one to bring out for an event
challenges.big-catch10 keysenabledtruedisplay"<gradient:#80DEEA:#00838F><bold>The Big Catch</bold></gradient>"description["&7A thousand fish. Bring patience."]iconFISHING_RODchallenges.big-catch.objective1 keytypeITEM_FISHchallenges.big-catchgoal1000duration1hauto-startfalsexp-per-contribution5challenges.big-catch.rewards3 keysmin-contribution5participant["coins: 150"]challenges.big-catch.rewards.top1 key1["item: TRIDENT 1", "coins: 500"] rewards.yml
Rewards 15 settings
rewards.ymlplugins/ShadowBattlePass/rewards.yml File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/rewards.yml
Copy it over this file to use it (copiala al posto di questo file).
Named reward bundles.
Write a bundle here once, then call it from wherever you like - a season tier, a quest, a shop entry, a challenge - with one line:
- "bundle: epic-crate"
That is the whole point: if you decide the epic crate should give twice the money, you change it in one place and it changes in all twenty tiers that use it, without opening a single season file.
A bundle can contain anything, bundles included.
The full reward syntax is in docs/06-RICOMPENSE.md.
config-version2bundles14 keysCrates
bundlescommon-crate["coins: 25", "item: EXPERIENCE_BOTTLE 8", "money: 2500"]+1
rare-crate["coins: 75", "item: DIAMOND 3", "money: 10000", "sound: entity.player.levelup 0.8 1.4"]+1
epic-crate["coins: 200", "money: 50000", { type: RANDOM, display: "&dEpic item", picks: 1, options: […] }, "firework: B388FF"]+2
Milestone moments
bundleswelcome["coins: 25", "item: BREAD 16", "message: &7A little help to get you started."]+1
season-end["coins: 1000", "money: 100000", "booster: 2.0 24h", "item: TOTEM_OF_UNDYING 3", "firework: FFD54F"]+3
Reusable building blocks
bundlessnack["item: COOKED_BEEF 16", "item: GOLDEN_CARROT 8"]+1
starter-gear[{ type: ITEM, item: {…} }, "item: TORCH 64"]Example with an item from another plugin. The line works only if that plugin is present; if it is missing, the bundle says so in console and carries on with the rest instead of breaking.
item-custom: - "item: oraxen:mythril_sword" - "item: mmoitems:SWORD:EXCALIBUR"
Kits handed out along the season
Vanilla items only: they work on a freshly installed server. Enchanted, named, and unbreakable where it matters, so a level 15 reward is not an iron pickaxe anyone can craft.
bundlesiron-kit[{ type: ITEM, item: {…} }, { type: ITEM, item: {…} }, "item: IRON_CHESTPLATE 1", "item: COOKED_BEEF 16"]+3
diamond-kit[{ type: ITEM, item: {…} }, { type: ITEM, item: {…} }, { type: ITEM, item: {…} }, "item: GOLDEN_APPLE 4"]+3
netherite-kit[{ type: ITEM, item: {…} }, { type: ITEM, item: {…} }, "item: NETHERITE_INGOT 2", "item: ENCHANTED_GOLDEN_APPLE 1"]+3
builder-kit["item: STONE_BRICKS 128", "item: OAK_PLANKS 128", "item: GLASS 64", "item: LANTERN 16", "item: SCAFFOLDING 64"]+4
farmer-kit["item: BONE_MEAL 64", "item: WHEAT_SEEDS 32", "item: CARROT 16", "item: POTATO 16", { type: ITEM, item: {…} }, "item: WATER_BUCKET 2"]+4
mob-kit[{ type: ITEM, item: {…} }, "item: ARROW 1", "item: SHIELD 1", "item: COOKED_PORKCHOP 16"]+2
potion-kit["effect: speed 1200 2", "item: GOLDEN_CARROT 16", "item: TOTEM_OF_UNDYING 1", "item: ENDER_PEARL 8", "item: EXPERIENCE_BOTTLE 16"]+4
shop.yml
The shop 24 settings
shop.ymlplugins/ShadowBattlePass/shop.yml File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/shop.yml
Copy it over this file to use it (copiala al posto di questo file).
What pass coins buy. Coins come from the tiers and the quests; here they go. Three shelves, and every shelf full from day one: a shop with one thing in it teaches players that coins are worthless, and after that no quest is worth doing.
Every entry:
category: one of the ids under "categories" below
display / description / icon
price: coins, money (needs an economy plugin), or tiers
limit-per-cycle + cycle (DAILY, WEEKLY, MONTHLY, SEASON): how many
times per player per cycle; left out = no limit
limit-per-player: how many times ever
conditions: same syntax as the quests ("tier: >= 30")
rewards: same short form as the seasons and the quests
featured: true puts a glow on itconfig-version3enabledtruecurrency-name"Pass Coins"categories3 keyscategories.utili4 keysdisplay"<green><bold>Useful</bold>"description["&7Things you actually need."]iconCHESTorder0categories.progressi4 keysdisplay"<gold><bold>Progress</bold>"description["&7To move up faster."]iconLADDERorder1categories.cosmetici4 keysdisplay"<light_purple><bold>Cosmetics</bold>"description["&7Just for showing off."]iconFIREWORK_ROCKETorder2entries22 keysUseful
entries.reroll9 keysenabledtruecategoryutilidisplay"&eSwap a quest"description["&7A daily quest you do not fancy", "&7is replaced with another one."]+1
iconCLOCKentries.reroll.price1 keycoins50entries.rerolllimit-per-cycle2cycleDAILYrewards["reroll: 1"]reroll:
snack, golden-apples, ender-pearls, common-crate, rare-crate, epic-crate, gear, farmer-kit, totem, shulker, booster-2h, booster-6h, xp-pack, tier-skip, vanilla-xp, fireworks, fireworks-show, aura, veteran-title, champion-title, player-head vouchers.yml
Vouchers 12 settings
vouchers.ymlplugins/ShadowBattlePass/vouchers.yml File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/vouchers.yml
Copy it over this file to use it (copiala al posto di questo file).
Vouchers: rewards with a body.
A voucher is an item that, right-clicked, does something to the pass: unlocks a track, adds experience, hands over a bundle.
It is what a store actually needs: a product that can be given, kept, traded and used whenever the buyer feels like it, instead of a command that fires at the moment of payment even if the player is not online right then.
The item carries ONLY the voucher id, never its contents. That is the choice that makes it safe: tampering with the item cannot turn a coal voucher into a diamond one, and changing your mind means changing one file instead of chasing every copy already in circulation.
To hand one out:
/bpa voucher give <player> <id> [amount]
config-version2vouchers6 keys seasons/season-1.yml
Season: season-1 87 settings
seasons/season-1.ymlplugins/ShadowBattlePass/seasons/season-1.yml File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/seasons/season-1.yml
Copy it over this file to use it (copiala al posto di questo file).
ONE SEASON = ONE FILE. Copy this file, change its name and id, and you have season 2. The plugin finds them on its own: there is nothing to register anywhere.
Three ideas keep this file short even with a hundred tiers:
1. A CURVE, NOT A TABLE The cost of every tier comes from a formula. Only the tiers that break the pattern are written by hand, under "overrides".
2. PATTERNS, NOT REPETITION A reward can be attached to tier 7, to the range 1-10, to "*5" (every fifth tier) or to "default" (every tier nobody else took). The exact number always beats the pattern, so you can write the rule first and the exception after it.
3. AS MANY TRACKS AS YOU LIKE Free and premium are just the two you find here. You can add more: each one has its own permission, its own price and its own rewards at every tier.
config-version2season15 keysidseason-1display"<gradient:#FFD54F:#FF8F00><bold>Season 1 - The Lost Lands</bold></gradient>"description["&7Ninety days of exploring, digging and fighting.", "&7A hundred tiers, three tracks, rewards that last.", "&7A hundred and twenty-nine quests in rotation, and two stories."]+2
season.icon2 keysmaterialNETHER_STARglowtrueseasonenabledtrueWhen it runs
You can give a start date and an end date, or just a duration. With neither, the season stays active until you start another one by hand with /bpa season start.
seasonduration90dstart: "2026-09-01 00:00" end: "2026-11-30 23:59"
auto-start-nextfalseWhen it ends it moves to the next season file on its own.
Keep reading
SEASON TWO, when you want one: copy this file to seasons/season-2.yml, change "id" to season-2 and the display to match, and set the two lines below to true / season-2. Nothing else has to be registered anywhere, and nothing in the database has to be cleared: progress rows keep the id they were written with, so season 1 stays readable for ever.
Until that file exists, leave these as they are. A season that points at a file that is not there just carries on, but the console says so every time it checks, and that noise hides real warnings.
next: season-2
The tracks
season.tracks3 keysseason.tracks.free5 keysdisplay"<green><bold>Free</bold>"description["&7For everyone, always."]iconLIME_DYEdefaulttrueorder0season.tracks.deluxe6 keysdisplay"<light_purple><bold>Deluxe</bold>"description["&7A third row, for those who want it all."]iconAMETHYST_SHARDorder2permission"shadowbattlepass.deluxe"unlock-retroactivetrueThe tiers
THE MATHS, so that if you change something you know what you changed. Every number below is the one the files in quests/ actually produce.
Keep reading
WHAT THE LADDER COSTS
tier 1 1,000 cumulative 1,000 tier 10 1,900 14,500 tier 25 3,400 55,000 tier 50 8,000 (override) 174,600 tier 75 8,400 354,600 tier 100 25,000 (override) 611,200
611,200 experience over ninety days is 6,791 a day.
WHAT THE QUESTS PAY IN, IF YOU CLEAR THEM
daily 237,449 2,638 a day three of thirty-nine, plus
the 800 for clearing all three
weekly 251,573 2,795 a day four of the nine of that week
monthly 127,149 1,413 a day two of fifteen
premium 98,190 1,091 a day two of twenty-four, reserved
seasonal 335,000 3,722 a day fifteen, no reset
chains 166,000 1,844 a day eleven chapters, one at a timeWHERE THAT LANDS A PLAYER
only the dailies tier 59 does not finish dailies + weeklies tier 89 does not finish dailies + weeklies + monthlies tier 100 on day 89 of 90 the same, with premium tier 100 on day 77 everything, free tier 100 on day 49 everything, premium tier 100 on day 45
THE LINE THAT MATTERS is the third one. A player who does their three dailies and their four weeklies and their two monthlies, and nothing else at all, reaches the hundredth tier on the second to last day of the season. That is the promise: turn up, do the list, finish. The season quests and the chains are not required - they are the room to miss a fortnight and still make it.
Anybody who does clear everything finishes around day fifty and spends the rest of the season in the endless tiers below, which is what they are for.
Neither figure counts the boosters in boosters.yml - weekend x1.5 and happy hour x2 are worth roughly a third again to somebody who plays evenings - nor the catch-up bonus, which only helps whoever is behind. Both of those are slack, on purpose: a season that needs its boosters to be finishable is a season nobody finishes.
Premium arriving sooner rather than earning more per tier is on purpose: whoever pays should finish with a couple of weeks to spare, not halfway through with forty-five days of nothing left to do.
Raising "increment" raises the finish line: every +10 is 49,500 more experience, about seven days of the ordinary rhythm.
season.tiers6 keyscount100season.tiers.curve5 keystypeLINEARLINEAR = base + increment * (tier - 1) EXPONENTIAL = base * multiplier ^ (tier - 1) FLAT = always base
base1000increment100multiplier1.05max15000Ceiling for the cost of a single tier. 0 = none.
season.tiers.overrides2 keysThe tiers that should cost something other than the formula.
50800010025000season.tiersmilestone-every10How many tiers between milestone marks in the GUI. 0 = never.
milestones[1, 25, 75]Extra milestones, on top of the automatic ones.
season.tiers.icons19 keysCustom icon for individual tiers. Takes the same full shape as the rewards: material, head texture, model.
Every tier written by hand below gets its own, so that scrolling the ladder shows where the next real prize is instead of a hundred identical panes.
season.tiers.icons.101 keymaterialIRON_PICKAXE10:
15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100Past the last tier
Whoever finishes the season keeps earning: every "xp" below is worth one prestige, with its own reward. That way the top of the board still has a reason to play in November.
season.infinite3 keysenabledtruexp20000rewards["coins: 250", "money: 10000", "broadcast: &d<player> went past the top tier again!"]+1
Which quest pools this season uses
Empty = every pool in quests/. By listing them, a themed season can use only its own.
seasonquest-pools[daily, weekly, monthly, seasonal, chains, premium]+3
Only players who unlocked premium see this pool: the condition lives inside quests/premium.yml, not here.
join-rewards["coins: 25", "message: <gradient:#FFD54F:#FF8F00>Welcome to Season 1!</gradient>"]+1
Welcome gift the first time the pass is opened.
completion-rewards["bundle: season-end", "broadcast: <gradient:#FFD54F:#FF8F00><player> completed Season 1!</gradient>"]+1
Reward for reaching the last tier.
season.catch-up2 keysBonus for players falling behind. The general values live in config.yml; here you can raise or lower the ceiling for this season only.
enabledtruemax-multiplier2.0The rewards
Key = tier, range, "*n" or "default". Inside, one list per track.
Keep reading
Short form, one line:
- "money: 5000" - "coins: 100" - "xp: 250" - "item: DIAMOND 3" - "tier: 1" - "reroll: 1" - "crate: vote 2" - "booster: 1.5 2h" - "permission: vip 30d" - "command: fly <player> 10m" - "bundle: bundle-name" (defined in rewards.yml) - "broadcast: &6..." - "firework: FFD54F"
Long form, for icons, conditions, randomness and choices: see tier 50 below and docs/06-RICOMPENSE.md.
This table is already complete: every tier gives something to every track, from the first to the hundredth. The "common-crate", "rare-crate" and "epic-crate" are bundles defined in rewards.yml with vanilla content, and so are the kits: they work on a freshly installed server. With a real crate plugin, "bundle: rare-crate" can become "crate: rare 1".
HOW IT IS BUILT
a floor "default", so no tier is ever an empty pane
five bands 1-10, 11-25, 26-50, 51-75, 76-99: the money grows with
the number, so the eightieth tier is worth reaching
two patterns "*5" a crate, "*10" something serious
nineteen tiers written out by hand, one every five from ten to a
hundred: those are the ones with a name, an icon of
their own and something a player remembers - the kits
at 10 and 15, the cosmetics at 20, 30, 55 and 80, the
choices at 50 and 85, the storage at 65, and the endWHAT THE PRICES MEAN
The money here is in the currency of ShadowEconomy, and it is priced against that shop, not invented. In shop.yml a diamond sells for 10 and costs 1,000 to buy back; a netherite ingot costs 12,140, a netherite block 109,260. So:
money: 2,500 two and a half diamonds off the shelf money: 25,000 two netherite ingots money: 400,000 three and a half netherite blocks
Over a hundred tiers, bundles counted, the ladder hands out:
free 554,600 and 6,957 pass coins premium 1,813,000 and 12,195 deluxe 2,795,000 and 17,325
The benchmark to read those against is in quests/weekly.yml: "earn a hundred thousand in a week" is rated HARD there, so honest play is worth roughly fourteen thousand a day. The free ladder adds about six thousand a day on top of that - a real bonus that does not replace playing. The paid ones are deliberately several times that, because that is the thing being sold.
IF YOU THINK THAT IS TOO MUCH for your economy, do not go through this table tier by tier. The premium quests are the bigger half of it: quests/premium.yml hands out two commissions a day at ten to eighteen thousand each, which is about two and a half million over a season. Halving the "money:" lines in that one file is the single change that moves the needle, and it leaves the ladder - the part players actually look at - exactly as it is.
The pass coins are a closed currency: they come from here and from the quests and they go nowhere but shop.yml, where a season's worth buys roughly what a season's worth should. Nothing on those shelves can be bought with a credit card, which is what makes the rest of this safe.
season.rewards27 keysseason.rewards.default3 keysEvery tier that does not appear further down gives at least this.
All three tracks are here, and this is the most important line in the file. A tier where the paid track gives nothing is a grey slot next to a full one: the player who paid reads it as "I have been had", and they are not far wrong. Here every tier gives something to everyone, and the bands and milestones below pile the rest on top.
free["coins: 5", "money: 250"]deluxe["coins: 20", "money: 2000", "item: EXPERIENCE_BOTTLE 8"]+1
season.rewards.1-103 keysThe first ten are generous on purpose: that is where it is decided whether somebody carries on or quits.
free["coins: 10", "money: 500", "item: BREAD 8"]deluxe["coins: 40", "money: 4000", "item: GOLDEN_APPLE 2", "item: EXPERIENCE_BOTTLE 8"]+2
season.rewards.11-253 keysBands: the money grows with the tier, so the eightieth tier is worth reaching and not just another five coins.
free["coins: 6", "money: 400"]deluxe["coins: 25", "money: 3000", "item: EXPERIENCE_BOTTLE 12"]+1
default:
26-50, 51-75, 76-99, 15, 25, 35, 40, 55, 60, 70, 75, 80, 90season.rewards.*53 keysEvery fifth tier, a crate. Careful, this is the easiest trap in the whole file: a key here REPLACES the default and the bands, it does not add to them. Every entry must therefore be written out in full, or tier 5 ends up worth less than tier 4 and the player notices at once.
free["coins: 10", "money: 600", "bundle: common-crate"]+1
deluxe["coins: 40", "money: 5000", "bundle: rare-crate", "bundle: snack", "booster: 1.25 30m"]+3
season.rewards.*103 keysEvery tenth, something serious.
free["coins: 50", "money: 1500", "item: DIAMOND 2", "bundle: common-crate"]+1
deluxe["coins: 200", "money: 20000", "bundle: rare-crate", "bundle: potion-kit", "booster: 1.5 2h"]+3
Exceptions: being exact numbers, they beat the patterns above. From here to the hundredth there is one every five.
season.rewards.103 keysThe first round number. Ten tiers in, a player decides whether this pass is worth the next ninety: this is the answer. A tool, a crate and a line across the screen.
free["coins: 60", "money: 2500", "bundle: common-crate", "bundle: starter-gear", "title: <gradient:#FFD54F:#FF8F00>TIER 10|<gray>and we are only getting started"]+3
deluxe["coins: 220", "money: 22000", "bundle: rare-crate", "bundle: starter-gear", "bundle: potion-kit", "booster: 2.0 2h"]+4
season.rewards.203 keysThe first cosmetic. From here on the track alternates: money, then something to use, then something to be seen wearing.
free["coins: 60", "money: 2500", "item: DIAMOND 3", "bundle: common-crate", "firework: FFD54F"]+2
deluxe["coins: 230", "money: 24000", "bundle: rare-crate", "permission: shadowbattlepass.cosmetic.aura 14d", "item: SHULKER_BOX 1", "booster: 2.0 2h"]+4
season.rewards.303 keysA named thing, which is the point of a cosmetic: it is not stronger, it is only yours, and everybody can see where it came from.
free["coins: 110", "money: 4000", "item: DIAMOND 4", "bundle: common-crate"]+1
deluxe["coins: 260", "money: 28000", "bundle: rare-crate", "bundle: potion-kit", { type: ITEM, display: "&5Wanderer's Cloak", item: {…} }, "booster: 2.0 3h"]+4
season.rewards.453 keysThe last tier before the halfway crate: gear, so that whoever gets to fifty gets there wearing something.
free["coins: 140", "money: 9000", "item: DIAMOND_BLOCK 1", "bundle: common-crate"]+2
deluxe["coins: 430", "money: 60000", "bundle: rare-crate", "bundle: diamond-kit", "booster: 2.0 3h"]+3
season.rewards.503 keysfree["coins: 400", "money: 20000", "item: NETHERITE_SCRAP 2", "bundle: diamond-kit"]+2
deluxe["coins: 800", "money: 90000", "bundle: potion-kit", "bundle: epic-crate", "item: SHULKER_BOX 2", "permission: shadowbattlepass.cosmetic.aura 30d", "booster: 2.0 6h"]+5
season.rewards.653 keysStorage. Unglamorous, and the reward players actually talk about.
free["coins: 200", "money: 13000", "item: SHULKER_BOX 1"]+1
deluxe["coins: 420", "money: 50000", "bundle: epic-crate", "item: SHULKER_BOX 3", "item: NETHERITE_INGOT 1"]+3
season.rewards.853 keysThe second choice of the season. The one at fifty was about what you wear; this one is about how you spend the last fifteen tiers.
free["coins: 380", "money: 30000", "bundle: rare-crate"]+1
deluxe["coins: 780", "money: 90000", "bundle: epic-crate", "item: SHULKER_BOX 3", "booster: 2.0 8h"]+3
season.rewards.953 keysFive tiers from the end, and the end costs twenty-five thousand on its own. This is the tier that pays for that last climb.
free["coins: 500", "money: 40000", "bundle: rare-crate", "item: DIAMOND_BLOCK 3"]+2
deluxe["coins: 1000", "money: 130000", "bundle: epic-crate", "item: NETHERITE_INGOT 6", "permission: shadowbattlepass.cosmetic.aura 30d", "booster: 2.0 12h"]+4
season.rewards.1003 keysThe last tier. Worth making memorable: it is the one people talk about, and it is the advert for the next season.
free["coins: 500", "money: 50000", "item: DIAMOND_BLOCK 4", "bundle: season-end"]+2
deluxe["coins: 1500", "money: 400000", "bundle: epic-crate", "bundle: season-end", "item: NETHERITE_BLOCK 1", { type: ITEM, display: "<gradient:#B388FF:#4527A0>Shadow Crown</gradient>", item: {…} }, "permission: shadowbattlep …+7
Languages
The texts the plugin shows to players, one file per language.
lang/
Texts and messages 2 files
lang/plugins/ShadowBattlePass/lang/ File notes
MiniMessage format. Placeholders are written <like_this>. This is the final fallback: a key missing from every other language file is looked up here, one key at a time. A key missing from this file on disk is read from the copy inside the plugin jar.
Every message the plugin shows to players, one file per language. The keys are not listed one by one: here are the files, how many texts they hold and the placeholders they use.
| File | Language | Texts |
|---|---|---|
lang/en_US.yml reference | English | 727 |
lang/it_IT.yml | Italiano | 727 |
Most used placeholders
The plugin replaces them with the right value: leave them written as they are.
<prefix><player><id><tier><count><amount><track><value><season><target><xp><coins><quest><goal>
Message groups
prefix1common19command10input4condition26reward25mailbox3pass47quest51objective68track17shop28wallet1leaderboard23info18challenge17choice2notify24booster4season3streak4team1recap26stat12voucher12gift18hologram4admin216license38locked5
Other
Ready-made content, examples, imports: the files you copy and edit as a model.
quests/
Quests, one group per file 6 files
quests/plugins/ShadowBattlePass/quests/ 6 files with the same structure. Below, 4 of them in full, one for each different shape; the others are listed by name.
chains.ymldaily.ymlmonthly.ymlpremium.ymlseasonal.ymlweekly.yml
Example quests/daily.yml
File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/quests/daily.yml
Copy it over this file to use it (copiala al posto di questo file).
ONE FILE = ONE QUEST POOL. A new file in this folder is a new pool: there is nothing to register anywhere.
The pool decides the rhythm (daily, weekly, ...) and how many quests a player gets at a time. Writing thirty daily quests and handing out three a day at random is what keeps a pass alive for ninety days without writing ninety days of content.
The draw is stable: the same player, on the same day, always gets the same quests, even after twenty restarts.
Every objective type: docs/05-OBIETTIVI.md Every condition: docs/07-CONDIZIONI.md Every reward: docs/06-RICOMPENSE.md
config-version2pool12 keysiddailydisplay"<yellow><bold>Daily</bold>"description["&7Three new quests every day.", "&7The rotation is wide: in ninety days", "&7the same three hardly ever come back."]+2
periodDAILYiconCLOCKorder0size3How many a player gets per cycle. "all" hands out every one.
sequentialfalsefalse = the plugin picks the quests at random, by weight. true = they are handed out in file order, one after another (storyline).
auto-assigntruepool.rerolls3 keysamount1How many times a day a quest you dislike can be swapped.
cost-coins0Cost in pass coins, on top of the free one. 0 = free.
cost-money0poolcompletion-xp800Bonus for finishing all three in one day. It is deliberately large: three quests plus this bonus is the daily rhythm the tier curve in seasons/season-1.yml is tuned against.
completion-rewards["coins: 50", "message: <gradient:#FFD54F:#FF8F00>Day complete!</gradient>"]+1
The quests
The smallest form is six lines:
quest-id:
display: "&bTitle"
xp: 500
objectives:
- type: MOB_KILL
amount: 30Everything else has a sensible factory value.
weight: how likely it is to come up. 2 = twice as likely as a 1. mode: all (every objective) or any (one is enough).
quests39 keystrades
quests.miner8 keysdisplay"&bTireless miner"description["&7Go down to where the stone turns dark."]quests.miner.icon1 keymaterialDIAMOND_PICKAXEquests.minerdifficultyEASYweight2.0xp600objectives[{ type: BLOCK_BREAK, target: […], amount: 300…]no-placed-blocksA block you placed yourself does not count.
rewards["coins: 20"]miner:
prospector, lumberjack, farmer, fisher, nether, duelist, wanderer, sightseer, attendance, breeder, trader, enchanter, brewer, crafter, smelter, well-fed, sleeper, blacksmith, grinder, glassblower, bricklayer, coppersmith, spelunker, scavenger, sniper, arachnophobe, tank, sprinter, swimmer, boatman, horseman, jumper, shearer, achiever, pyrotechniccombat
quests.hunter8 keysdisplay"&cNight hunter"description["&7Monsters do not kill themselves."]quests.hunter.icon1 keymaterialIRON_SWORDquests.hunterdifficultyMEDIUMweight2.0xp800objectives[{ type: MOB_KILL, target: […], amount: 50, no…]no-spawner-mobsSpawner mobs do not count: that would be a lever, not a hunt.
rewards["coins: 30"]exploration
assorted
quests.full-day9 keysA quest with two objectives, both of which must be done.
display"&6A full day"description["&7A bit of everything."]quests.full-day.icon1 keymaterialBUNDLEquests.full-daydifficultyHARDweight0.6xp1500modeallobjectives[{ type: BLOCK_BREAK, amount: 200, no-placed-blocks: true }, { type: MOB_KILL, amount: 25, no-spawner-mobs: true }, { type: ITEM_CRAFT, amount: 32 }]+2
rewards["coins: 60", "bundle: snack"]quests.your-way9 keysA quest where any one of the objectives is enough.
display"&dYour way"description["&7Do any one of these things.", "&8Finishing one is enough."]+1
quests.your-way.icon1 keymaterialCOMPASSquests.your-waydifficultyMEDIUMweight0.8xp900modeanyobjectives[{ type: ORE_MINE, amount: 100 }, { type: MOB_KILL, amount: 60 }, { type: ITEM_FISH, amount: 30 }, { type: CROP_HARVEST, amount: 250 }]+3
rewards["coins: 35"]everyday jobs
the workshop
The anvil, the grindstone, the furnace: blocks most servers have in spawn and nobody ever has a reason to walk up to twice.
underground
combat, the other half
on the road
Example quests/chains.yml
File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/quests/chains.yml
Copy it over this file to use it (copiala al posto di questo file).
A STORY, NOT A LIST.
A pool with "sequential: true" draws nothing at random: it hands out the quests in file order, one after another, and the next one appears only once the previous one is finished.
Two keys are enough to build one:
requires: [ id ] this quest appears only after that one hidden: true until unlocked it is not even visible
Together they make a chapter that opens as you reach it, instead of a list of sixteen grey entries nobody reads.
"chain" and "step" only serve to group and order them in the GUI: two different chains in the same file live together happily - and this file holds two of them.
THE SEASON READS AS ONE BOOK
La Via del Cercatore six chapters, from a wooden pickaxe to the
thing at the bottom of the world.
Il Lascito five more, opened by the last chapter of the
first: what a seeker does once they have found
it. Building, trading, the End, and a name that
stays on the server after the season.Eleven chapters over ninety days, one held at a time. The second chain is hidden until the first is over, so a new player sees a beginning and not a wall of eleven grey entries.
config-version2pool12 keysidchainsdisplay"<gradient:#B388FF:#4527A0><bold>The Seeker's Path</bold></gradient>"description["&7Two stories, eleven chapters.", "&7The next one opens when you finish this one."]+1
periodSEASONiconWRITTEN_BOOKorder4size1How many a player holds at a time. With a chain, one.
sequentialtrueThis is the line that turns it into a story.
auto-assigntruepool.rerolls1 keyamount0poolcompletion-xp45000completion-rewards["coins: 1500", "money: 150000", "bundle: epic-crate", "permission: shadowbattlepass.title.cercatore", "broadcast: <gradient:#B388FF:#4527A0><player> read both stories to the very end.</gradient>"]+3
quests11 keyschapter 1
quests.path-110 keysdisplay"&fI. The first strike"description["&7Every seeker starts out with a pickaxe", "&7and no idea what they are looking for."]+1
quests.path-1.icon1 keymaterialWOODEN_PICKAXEquests.path-1chainvia-del-cercatorestep1difficultyEASYxp1000objectives[{ type: BLOCK_BREAK, target: […], amount: 100…]rewards["item: STONE_PICKAXE 1", "coins: 25"]unlocks[path-2]path-1:
path-2, path-4, path-5, path-6, legacy-1, legacy-2, legacy-3, legacy-5chapter 3
quests.path-313 keysdisplay"&bIII. The deep dark"description["&7Below Y zero there is no light left.", "&7Only black stone, and whatever lives in it."]+1
quests.path-3.icon1 keymaterialDEEPSLATEquests.path-3chainvia-del-cercatorestep3difficultyMEDIUMrequires[path-2]xp4000modeallobjectives[{ type: BLOCK_BREAK, target: […], amount: 500, max-y: 0, no-placed-blocks: true }, { type: MOB_KILL, amount: 50, max-y: 0, no-spawner-mobs: true }]+1
max-yOnly below level zero: that is where the real descent starts.
rewards["item: DIAMOND 4", "coins: 100"]unlocks[path-4]Il Lascito - five chapters
Opens when the Way of the Seeker is over. The first story is about going down; this one is about what gets built after coming back up. It is gated on the last chapter of the first, so the two never show at the same time.
chapter 4
quests.legacy-413 keysdisplay"&dIV. The sky at the end"description["&7The last door was always open.", "&7Nobody ever looked up, that is all."]+1
quests.legacy-4.icon1 keymaterialEND_CRYSTALquests.legacy-4chainil-lascitostep4difficultyEPICrequires[legacy-3]xp16000modeallobjectives[{ type: BOSS_KILL, target: […], amount: 1 }, { type: MOB_KILL, target: […], amount: 24, no-spawner-mobs: true }]+1
typeThe dragon and the shulkers say "you have been to the End" without naming a world: a server that renamed its worlds still works.
rewards["item: SHULKER_BOX 2", "item: DRAGON_BREATH 8", "coins: 450", "money: 60000"]+2
unlocks[legacy-5] Example quests/seasonal.yml
File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/quests/seasonal.yml
Copy it over this file to use it (copiala al posto di questo file).
Quests that last as long as the season and never reset. They are all handed out together ("size: all"), so from day one a player can see what the next three months hold.
THEY ARE THE SHAPE OF THE SEASON
Thirteen of them, and they are deliberately not thirteen versions of the same wall of numbers. Four are totals that only a player who logs in most days will reach, four reward going somewhere rather than repeating something, three are one-off feats that can be done in an afternoon by whoever knows how, and two are about the pass itself. Between them they say what this season is: exploration, digging, and coming back.
None of them can be finished on day one, and none of them needs the last week: the season has a shape rather than a deadline.
config-version2pool11 keysidseasonaldisplay"<gradient:#FFD54F:#FF8F00><bold>Seasonal</bold></gradient>"description["&7They last as long as the season.", "&7No reset, no hurry."]+1
periodSEASONiconNETHER_STARorder3sizeallauto-assigntruepool.rerolls1 keyamount0poolcompletion-xp50000completion-rewards["coins: 2000", "money: 250000", "bundle: season-end", "permission: shadowbattlepass.title.leggenda", "broadcast: <gradient:#FFD54F:#FF8F00><player> finished every seasonal quest!</gradient>"]+3
The same title the hundredth tier of the deluxe track gives. Two roads to one badge is deliberate: the player who cleared every season quest earned it as much as the one who climbed to the top.
quests15 keysquests.hundred-thousand7 keysdisplay"&bA hundred thousand"description["&7A hundred thousand blocks over the whole s…]quests.hundred-thousand.icon1 keymaterialNETHERITE_PICKAXEquests.hundred-thousanddifficultyEPICxp25000objectives[{ type: BLOCK_BREAK, amount: 100000, no-place…]rewards["coins: 1500", "bundle: epic-crate"]hundred-thousand:
legend, globetrotter, three-worlds, loyal, companion, deep-hundred, builder-of-things, harvest-season, long-road, dragonslayer, deep-dark, ancient-hoard, the-climb, hundred-queststhe totals
the road
the feats
templates/
Season templates 13 files
templates/plugins/ShadowBattlePass/templates/ 13 files with the same structure. Below, 4 of them in full, one for each different shape; the others are listed by name.
index.ymlpvp/daily.ymlpvp/premium.ymlpvp/season.ymlpvp/weekly.ymlskyblock/daily.ymlskyblock/premium.ymlskyblock/season.ymlskyblock/weekly.ymlsurvival/daily.ymlsurvival/premium.ymlsurvival/season.ymlsurvival/weekly.yml
Example templates/survival/season.yml
Template "survival" - the season
File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/templates/survival/season.yml
Once the template is applied, copy it over seasons/survival.yml (copiala al posto di quel file dopo /bpa template apply survival).
Fifty tiers in thirty days, two tracks: free and premium.
THE MATHS, so you know what you are installing and what to change:
The season is worth 99,000 experience in total (linear curve: 1,000 at the first tier, 2,960 at the fiftieth).
A FREE player doing their quests every day earns:
3 dailies x ~600 = 1,800 full-day bonus = 500 weeklies (2 x 4,000) = ~1,150 a day
about 3,450 a day -> finishes around day 28
A PREMIUM player also has two quests a day worth 400:
about 4,250 a day -> finishes around day 23, and from there on carries into the endless tiers.
If your server is more or less active than that, the right knob is "increment" below: raising it lengthens the season, lowering it shortens it. Do not touch "count" once a season has started.
config-version2season15 keysidsurvivaldisplay"<gradient:#66BB6A:#1B5E20><bold>Survival Season</bold></gradient>"description["&7Thirty days. Fifty tiers.", "&7Dig, build, survive."]+1
season.icon2 keysmaterialGRASS_BLOCKglowtrueseasonenabledtrueduration30dauto-start-nextfalseThe two tracks
season.tracks2 keysseason.tracks.free5 keysdisplay"<green><bold>Free</bold>"description["&7For everyone, always."]iconLIME_DYEdefaulttrueorder0The tiers
season.tiers5 keyscount50season.tiers.curve3 keystypeLINEARbase1000increment40season.tiers.overrides2 keysThe two tiers that should weigh more than the rest.
253000506000season.tiersmilestone-every10milestones[1, 25]season.infinite3 keysenabledtruexp5000rewards["coins: 100", "money: 5000"]seasonquest-pools[survival-daily, survival-weekly, survival-premium]+1
Only this template's quests: the plugin's sample dailies stay out, so that two different balancings do not get mixed.
join-rewards["coins: 25", "item: BREAD 16", "message: <gradient:#66BB6A:#1B5E20>Welcome to the season!</gradient> <gray>Open <white>/bp</white> to begin."]+1
completion-rewards["coins: 1000", "money: 100000", "booster: 2.0 24h", "broadcast: <gradient:#66BB6A:#1B5E20><player> completed the Survival Season!</gradient>"]+2
season.catch-up2 keysenabledtruemax-multiplier2.0The rewards
This is the rhythm, and it is worth understanding before changing it:
Keep reading
every tier free: coins premium: coins + money
every 5 tiers free: useful materials premium: a crate
every 10 tiers free: something good
premium: rare crate + booster
tier 25 the mid-season gift
tier 50 the one people talk aboutThe "bundle" entries are the packs in rewards.yml: change those and you change every tier that uses them in one go.
season.rewards8 keysseason.rewards.default2 keysfree["coins: 8"]season.rewards.1-52 keysThe first five tiers are generous on purpose: that is where a player decides whether this pass is for them or not.
free["coins: 20", "money: 1500"]default:
*5, *10, 10, 25, 40, 50 Example templates/skyblock/daily.yml
Template "skyblock" - the daily quests
File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/templates/skyblock/daily.yml
Once the template is applied, copy it over quests/skyblock-daily.yml (copiala al posto di quel file dopo /bpa template apply skyblock).
Twelve quests, three a day. None asks you to go anywhere: on an island you do not travel, you produce.
NOTE: the quests that depend on another plugin (earning money, raising the island level) are deliberately absent, so that this template works on a freshly installed server too. Adding them is easy, and the example is at the bottom of the file.
config-version2pool11 keysidskyblock-dailydisplay"<yellow><bold>Daily</bold>"description["&7Three new quests every day."]periodDAILYiconCLOCKorder0size3auto-assigntruepool.rerolls2 keysamount1cost-coins0poolcompletion-xp500completion-rewards["coins: 30", "message: <gradient:#FFD54F:#FF8F00>Day complete!</gradient>"]+1
quests12 keysthe generator
quests.skyblock-generator8 keysdisplay"&7The generator"description["&7Five hundred blocks from the cobblestone g…]quests.skyblock-generator.icon1 keymaterialCOBBLESTONEquests.skyblock-generatordifficultyEASYweight2.2xp500objectives[{ type: BLOCK_BREAK, target: […], amount: 500…]no-placed-blocksOn a generator blocks are not "placed by you": they are born. If your generator uses blocks the plugin sees as placed, remove this line.
rewards["coins: 15"]skyblock-generator:
skyblock-furnace, skyblock-harvest, skyblock-cane, skyblock-breeding, skyblock-trees, skyblock-crafter, skyblock-enchanter, skyblock-trader, skyblock-mobs, skyblock-fishing, skyblock-your-wayThe quests that depend on another plugin
Uncomment them once that plugin is present. Without it they would sit at zero and waste one of the day's three slots.
skyblock-earnings:
display: "&6Chi lavora guadagna"
icon:
material: GOLD_INGOT
difficulty: MEDIUM
weight: 1.2
xp: 650
objectives:
- type: MONEY_EARN # requires ShadowEconomy
amount: 50000
rewards:
- "coins: 20"skyblock-island:
display: "&bL'isola cresce"
icon:
material: BEACON
difficulty: HARD
weight: 0.8
xp: 900
objectives:
- type: ISLAND_LEVEL # requires ShadowSkyBlock
amount: 50
rewards:
- "coins: 40" Example templates/pvp/daily.yml
Template "pvp" - the daily quests
File notes
ITALIAN VERSION (versione italiana), in this plugin's folder:
esempi/it_IT/templates/pvp/daily.yml
Once the template is applied, copy it over quests/pvp-daily.yml (copiala al posto di quel file dopo /bpa template apply pvp).
Eleven quests, three a day, between 500 and 900 experience.
All of them can be done alone against mobs: nobody should depend on how many people are online to make progress. The quest that asks you to kill PLAYERS is the only exception, and it is commented out at the bottom with its reasons.
config-version2pool11 keysidpvp-dailydisplay"<yellow><bold>Daily</bold>"description["&7Three new quests every day."]periodDAILYiconCLOCKorder0size3auto-assigntruepool.rerolls2 keysamount1cost-coins0poolcompletion-xp400completion-rewards["coins: 30", "item: GOLDEN_APPLE 2"]quests11 keysfighting
quests.pvp-hunt8 keysdisplay"&cHunting party"description["&7Sixty monsters.", "&8Mobs from spawners do not count."]+1
quests.pvp-hunt.icon1 keymaterialIRON_SWORDquests.pvp-huntdifficultyEASYweight2.2xp550objectives[{ type: MOB_KILL, amount: 60, no-spawner-mobs…]rewards["coins: 18"]pvp-hunt:
pvp-damage, pvp-skeletons, pvp-hostiles, pvp-nether, pvp-endure, pvp-smith, pvp-anvil, pvp-supplies, pvp-ores, pvp-your-wayThe player-killing quest
Uncomment it only if you know what you are doing.
On a quiet server it is impossible and burns a slot for the whole day; on a busy one it becomes an incentive to camp the spawn exit. If you do switch it on, keep the number low (three is plenty) and the weight low, so it rarely comes up.
pvp-duel:
display: "&4Duellante"
description:
- "&7Tre giocatori."
icon:
material: PLAYER_HEAD
difficulty: HARD
weight: 0.5
xp: 900
objectives:
- type: PLAYER_KILL
amount: 3
rewards:
- "coins: 50" Example templates/index.yml
File notes
The catalogue of ready made battle passes.
This file lives INSIDE the jar and is never extracted: the templates you do not apply never clutter the plugin folder.
/bpa template list /bpa template info <id> /bpa template apply <id>
Applying copies the files into place and nothing more: it starts nothing and overwrites nothing. From then on they are ordinary YAML, editable by hand or with the in-game editor.
Under "files" the key is the file name inside the template folder WITHOUT .yml (a dot in a YAML key would be read as a nested path), and the value is where it lands in the plugin folder. So "season: seasons/survival.yml" means: take templates/survival/season.yml and write it to seasons/survival.yml.
config-version2templates3 keysClassic survival
templates.survival7 keysdisplay"<gradient:#66BB6A:#1B5E20><bold>Survival</bold></gradient>"flavour"Mine, build, survive"description["The pass for an ordinary survival server.", "Quests for digging, gathering, fighting and exploring,", "tuned for someone who plays an hour or two a day.", "", "Whoever plays every day reaches the end around day 28."]+4
tiers50days30quests28templates.survival.files4 keysseason"seasons/survival.yml"daily"quests/survival-daily.yml"weekly"quests/survival-weekly.yml"SkyBlock
templates.skyblock7 keysdisplay"<gradient:#4FC3F7:#0288D1><bold>SkyBlock</bold></gradient>"flavour"Island, farms, economy"description["The pass for a skyblock server.", "Quests about generators, farms, trading and money,", "with little that depends on exploring.", "", "It works well with the island team pass."]+4
tiers50days30quests25templates.skyblock.files4 keysseason"seasons/skyblock.yml"daily"quests/skyblock-daily.yml"weekly"quests/skyblock-weekly.yml"PvP and combat
templates.pvp7 keysdisplay"<gradient:#EF5350:#B71C1C><bold>PvP</bold></gradient>"flavour"Fight, hunt, outlive the others"description["The pass for a server where people fight.", "Quests about kills, damage, gear and bosses,", "with rewards meant for those who keep coming back to the arena.", "", "Shorter and steeper: 40 tiers in 30 days."]+4
tiers40days30quests23templates.pvp.files4 keysseason"seasons/pvp.yml"daily"quests/pvp-daily.yml"weekly"quests/pvp-weekly.yml"