Tags
Creators
Details
1.3.0
Compatibility
Changes
BattlePass 1.3.0
A fix release. One reward duplication path is closed, two quest-farming exploits are closed, and the data layer has been rewritten so progress survives a busy server.
Heads up: this release changes behaviour. The anti-farm work and the craft counting fix both change how fast players progress. Read "Behaviour changes" below before updating.
1. Reward duplication (critical)
Rewards could be claimed twice across a server restart. The chain: while one async save was in flight, the next save request was silently dropped; the claim path never marked the player dirty either, and shutdown only wrote players that were marked dirty. A reward claimed inside that window never reached disk, so the player could claim it again after a restart.
Players are now marked dirty before a snapshot is taken and only cleared once the write has actually landed, a save requested while another is running is queued instead of discarded, and shutdown writes every cached player.
2. Quest progress exploits
-
Unlimited block farming. Breaking a block you had just placed still counted toward BREAK_BLOCKS, so a single stack of stone was enough to climb tiers forever. Player-placed blocks no longer pay out when broken, and PLACE_BLOCKS only pays once per location, so both halves of the loop are closed. Mining natural blocks is unaffected.
-
PvP alt farming. Kills from the same connection no longer count, and repeat kills of the same victim only count once every 5 minutes.
-
Progress from cancelled events. Every quest handler now respects ignoreCancelled. Previously, breaking blocks inside a WorldGuard or GriefPrevention claim still added progress even though the block was never destroyed.
3. Craft counting
Shift-click crafting always counted as one batch no matter how much was actually made, so CRAFT_ITEMS quests barely moved for anyone crafting normally. The number credited is now what the player genuinely received, measured from the change in their inventory. If the inventory fills up partway through and vanilla stops crafting early, the count stops with it. No more, no less.
4. Stability and data integrity
-
The player data cache was read from the save threads with no synchronisation at all, even though it is access-ordered, which means a read mutates it. Every access now goes through a single lock, and the collections inside PlayerData were swapped for concurrent ones.
-
A full cache could evict a player who was still online, rolling their progress back to whatever was on disk, including their list of claimed rewards. Online players are no longer evicted.
-
Player data files were read on the main thread from inside a click handler. Data is now loaded asynchronously when the player joins.
-
An editor session abandoned by disconnecting left the player flagged as awaiting chat input, so their first message after reconnecting was swallowed by the editor. That state is cleared on quit.
5. GUI
-
Clicking your own inventory in slots 19 to 34 triggered a reward claim, because the slot index was read in a numbering that does not distinguish the top inventory from the bottom one. Only clicks inside the GUI are handled now.
-
A renamed item in a player's inventory could drive GUI navigation. A stone block named "Next Tier" would change tiers when clicked. Closed by the same fix.
-
Colour codes in reward and quest names, descriptions and lore were never translated, so the GUI showed raw text such as "&aWarrior Kit". They render correctly now.
Compatibility
- Minecraft 1.21 to 26.2, one jar for all of them.
- Paper, Purpur, Spigot, Bukkit. Folia is not supported yet.
- Java 21.
- The player data format is unchanged. No migration, just swap the jar and restart.
Projects on Modrinth are automatically available through a Maven repository for use with JVM build tools such as Gradle. To learn more about the Modrinth Maven API, click here.
Note: When available, you should use the creator's maven repo instead as it will have transitive dependency information that the Modrinth Maven API does not. You may also end up with duplicate dependencies if you use a mix of Modrinth and non-Modrinth Maven repositories for your dependencies, because the group identifier will be different when served through the Modrinth Maven API.
Maven coordinates:
Version ID:
build.gradle:
repositories {
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
// forRepositories(fg.repository) // Uncomment when using ForgeGradle
filter {
includeGroup "maven.modrinth"
}
}
}
// Standard Gradle dependency
dependencies {
implementation "maven.modrinth:5i4QwtMC:9z7G6H0u"
}
// Legacy Loom dependency
dependencies {
modImplementation "maven.modrinth:5i4QwtMC:9z7G6H0u"
}

