fix: respect Unbreaking (Прочность) when consuming shears/axe durability - #13
Merged
Conversation
Durability was decremented unconditionally, bypassing vanilla Unbreaking. Unify damageShears/damageAxe into damageTool, resolve the Unbreaking level via the registry key, and apply a point only with probability 1/(level+1) (level 0 keeps the old always-consume behaviour). RNG is an injectable ctor param and the decision is extracted to consumesDurability for deterministic unit tests.
The mixin decremented tool durability unconditionally, ignoring vanilla Unbreaking. Gate both durability sites (shears in injectDamage, axe in injectWax) on a 1/(level+1) roll using the world RNG, in both the yarn and mojmap branches. Add a cross-version unbreakingLevel helper (Stonecutter-branched: plain Enchantment <1.21, RegistryEntry via getOptionalWrapper 1.21-1.21.1, via getOrThrow 1.21.2+, Holder on mojmap 1.22+) wrapped in the existing try/catch (level 0 fallback). The gametest now asserts an Unbreaking-3 stack reads back level 3.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The Прочность enchantment (vanilla Unbreaking) had no effect when the mod/plugin
consumes tool durability: the shears (invisibility toggle) and the axe (wax removal) lost a
durability point on every use. Root cause: durability was decremented unconditionally,
bypassing vanilla Unbreaking.
Vanilla mechanic for a non-armor tool: a durability point is applied only with probability
1/(level+1)— i.e. skipped whenrandom.nextInt(level+1) != 0. Level 0 → always applied,so existing behaviour is preserved for un-enchanted tools.
This fix covers both platforms in the repo.
Plugin (Bukkit/Paper —
plugin/)damageShears/damageAxeinto onedamageTool.Enchantment.getByKey(minecraft("unbreaking"))getEnchantmentLevel(0 if absent).(
random: java.util.Random = java.util.Random()) so existingFrameListener(plugin)callsites still compile.
internal fun consumesDurability(level, random)for unit tests.Unbreaking III consumes ~1/4 of the time (tolerance band, seeded RNG).
Fabric mod (
src/— Stonecutter multi-version)injectDamage, axe ininjectWax) on the1/(level+1)roll using the world RNG — in both the yarn and mojmap (>=1.22) branches.unbreakingLevelhelper, Stonecutter-branched because the enchantmentAPI churns per version:
<1.21(yarn): plainEnchantmentobject →EnchantmentHelper.getLevel(Enchantment, stack).1.21–1.21.1(yarn): registry entry viamanager.getOptionalWrapper(...).getOrThrow(...).1.21.2+(yarn): registry entry viamanager.getOrThrow(...).getOrThrow(...).1.22+(mojmap):HolderviaregistryAccess().lookupOrThrow(...).getOrThrow(...)+getItemEnchantmentLevel.returns level 0 (safe fallback = previous always-consume behaviour), so a bad lookup can
never crash the interaction.
cross-version lookup (deterministic) — this catches a silent registry-resolution failure
that compilation alone cannot.
Test evidence (run locally, offline)
./gradlew -p plugin test→ green, 27 tests (incl. the 3 new probability/level tests)../gradlew build→ BUILD SUCCESSFUL, all 9 anchors':buildtasks ran(yarn 1.18.2/1.19.4/1.20.4/1.20.6/1.21.1/1.21.8/1.21.10 and mojmap 26.1.2/26.2 on JDK 25).
runGameTeston all 4 gametest-enabled nodes (1.20.6, 1.21.1, 1.21.8, 1.21.10) →"All required tests passed" on each, exercising the
<1.21,1.21–1.21.1, and1.21.2+enchantment-lookup branches at runtime.
The mojmap
>=1.22branch was compiled locally (JDK 25 toolchain available in the sandbox);its gametest is not enabled for 26.x (mod matrix), matching CI.