Rework TreasureConfig and FishingTreasureConfig so a single unrecognized or misconfigured entry can never fail server startup. Each entry is classified as loaded, incompatible (material absent in this Minecraft version), or invalid (misconfigured), skipped when unusable, and summarized per section. Unknown materials are skipped quietly; invalid entries are logged with their config key. Fishing drop-rate validation is now non-fatal. Add unit tests covering entry classification and drop-rate validation.
Add experience.yml XP for the new Chaos Cubed content: Mining XP for the Cinnabar and Sulfur block sets, Potent Sulfur, and Sulfur Spike; a Combat XP multiplier for the Sulfur Cube; and a Herbalism XP value for Golden Dandelion. Register the new pickaxe-mined blocks in MaterialMapStore, and add the 'Bounce' music disc as a very rare Excavation treasure in treasures.yml.
Mock ExperienceConfig.getInstance() in FlatFileDatabaseManagerTest and SQLDatabaseManagerTest with diminished returns disabled so test setup does not depend on global singleton state.
Close static mocks in tearDown to avoid leakage across test classes.
Initialize blacklist eagerly and guard isWorldBlacklisted for null world / null-or-empty blacklist so enable/disable world loops cannot throw during early plugin lifecycle.
Add WorldBlacklistTest coverage for null blacklist field, null world, case-insensitive match, and non-match behavior.
BukkitConfig calls mcMMO.p.getDataFolder() in its constructor to
determine where to write config files. When tests mock mcMMO.p but
don't stub getDataFolder(), it returns null, which Java resolves to
the current working directory (the project root), causing files like
experience.yml to be created there.
Fix by stubbing mcMMO.p.getDataFolder() with a fresh temporary
directory in every test setup that mocks mcMMO.p:
- MMOTestEnvironment.mockBaseEnvironment(): creates testDataFolder
in temp and deletes it in cleanUpStaticMocks()
- SQLDatabaseManagerTest.setUpAll(): same pattern, cleaned in tearDownAll()
- FlatFileDatabaseManagerTest.initBeforeAll(): same pattern, cleaned
in the new tearDownAll() method
Also remove the .gitignore band-aid entries that were added to paper
over the symptom.
- FishingTreasureConfig.fixMooshroomEntityId was a public static method that
called mcMMO.p.getLogger() directly, causing NPE when tests invoked it without
a live plugin instance. Add a private static Logger field and use it in the
static method instead.
- TridentsTest.impaleDamageBonusShouldMatchRankOneBaseDamage had a stale expected
value (1.0) left over from before commit 71868d9d fixed the Impale formula to
use rank * multiplier. The correct expectation for rank 1 is
base + 1 * multiplier = 1.5. Rename the test to match the new semantic.
- Add @Tag(docker) to FlatFileDatabaseManagerTest so the existing
skip-docker-tests Maven profile (-DskipDockerTests=true) excludes it alongside
SQLDatabaseManagerTest.
- Add generated config file names (experience.yml, config.yml, etc.) to
.gitignore to prevent accidental staging when tests run without a properly
mocked getDataFolder().
Extracts per-player DR data out of PlayerProfile into two new classes:
- DiminishedReturnsState: thread-safe XP gain queue and rolling totals
- DiminishedReturnsCache: UUID-keyed server-side cache that keeps DR
state alive across disconnect/reconnect to prevent window bypass
Fixes a bug where evictExpired() would remove fresh states that had
never registered any XP, orphaning the PlayerProfile reference and
allowing reconnects to bypass the DR window.
DR tracking is now skipped entirely (no state mutation) when the
diminished returns config option is disabled.
Fixes#3475. Fixes#3814.
Paper 26.1.2 fixed a bug where the player attack cooldown ticker was not
resetting at the correct point during melee hits. mcMMO relied on the old
(incorrect) order, reading the cooldown during the damage event, which
always returned near-zero after Paper's fix. Attack strength scale is
now back-derived from the raw event damage divided by the player's
GENERIC_ATTACK_DAMAGE attribute value and clamped to [0.0, 1.0].
AttributeMapper now survives test environments where Bukkit registries
are absent (catch Throwable in the registry reflection path).
Fixes#5287.
Nether_Wart_Block and Warped_Wart_Block both have woodcutting XP in
experience.yml AND are in the treeFellerDestructibleWhiteList. The
drop routing in dropTreeFellerLootFromBlocks used an if/else-if
structure, so blocks with woodcutting XP always took the first branch
and never reached the else-if where the KnockOnWood orb logic lived.
Fix: extract the orb spawning block into a standalone if-check that
runs after the drop routing, so it fires for any isNonWoodPartOfTree
block regardless of whether it also has woodcutting XP.
Fixes#5288
block.getType() returns AIR by the time BlockDropItemEvent fires because
the block is removed before the event is dispatched. Capture the pre-break
material from event.getBlockState().getType() and thread it through to
affectedByGigaDrillBreaker and rollAndCollectTreasureDrops so treasure
lookups use the correct material instead of AIR.
deepslate_bricks, deepslate_tiles, polished_blackstone_bricks, and
nether_bricks were handled in blockCrackerCheck() but were absent from
fillBlockCrackerWhiteList(). The listener gates on affectedByBlockCracker()
which reads the whitelist, so those blocks could never be cracked.
Warriorrrr's commit (fb6aebcaa) corrected the default potions.yml shipped
with the plugin (splash: 2500->3600, lingering: 3000->900), but existing
server installs still had the old incorrect values.
This adds a one-time UpgradeManager migration (FIX_TRICKY_TRIALS_SPLASH_POTION_DURATIONS)
that auto-patches existing potions.yml on first server startup after updating.
The migration only corrects exact-match bad values; user-customized durations
are intentionally left untouched. Absent potion keys are silently skipped.
- Add UpgradeType.FIX_TRICKY_TRIALS_SPLASH_POTION_DURATIONS
- Implement PotionConfig.fixTrickyTrialsPotionDurations() + patchTrickyTrialsDurations()
- Gate migration in PotionConfig.loadPotions() via shouldUpgrade()
- Add 13 unit tests covering all migration paths in PotionConfigTest
The old regex required a trailing [-_] after the version digits, which worked
for getBukkitVersion() strings (e.g. '1.21.4-R0.1-SNAPSHOT') but silently
failed on Spigot's Bukkit.getVersion() format ('git-Spigot-12345-abcdef
(MC: 1.21.4)') since '1.21.4)' has no trailing dash or underscore. Version
resolved to 0.0.0, causing Tricky Trials potions (isAtLeast 1.21.0 check)
to be incorrectly skipped on every Spigot server.
MinecraftGameVersionFactory now uses two patterns:
- Primary: extracts from the '(MC: X.Y.Z)' segment that CraftBukkit always
embeds in Bukkit.getVersion() — handles Spigot, old Paper, and Paper 26+
- Fallback: original regex for strings without '(MC: ...)' such as
getBukkitVersion()-style strings
Tests updated with @Nested classes covering both paths, including explicit
Spigot format cases and Paper 26+ versioning (26.1.2-60-b4682bf format).
Woodcutting (Harvest Lumber, Clean Cuts) and Excavation treasure drops
previously spawned items directly via world.dropItem(), bypassing
BlockDropItemEvent entirely. This made them invisible to Telekinesis-style
enchant plugins (ExcellentEnchants, EcoEnchants, etc.).
Woodcutting fix: processBonusDropCheck() now calls BlockUtils.markDropsAsBonus()
for normal breaks, routing bonus drops through the existing BlockDropItemEvent
metadata pipeline. Tree Feller retains the direct-spawn path since it sets
blocks to AIR without firing BlockDropItemEvent.
Excavation fix: treasure rolls are now performed inside onBlockDropItemEvent()
via ExcavationManager.rollAndCollectTreasureDrops(). The returned ItemStacks
are spawned and injected into event.getItems(), exposing them to the full
Bukkit event pipeline. GigaDrillBreaker's 3x roll count is preserved. The
old processExcavationBonusesOnBlock(treasure, location) path is kept as a
deprecated fallback for external API callers.