From 3dfc1b71af0ae513ad07d713fd7a82e79e334829 Mon Sep 17 00:00:00 2001 From: Dylan Garvis Date: Tue, 11 Aug 2026 19:54:07 -0400 Subject: [PATCH] fix(felling): support copper axes --- README.md | 2 +- design/log.md | 6 ++++++ design/user-stories/us-003-fell-unlocked-trees.md | 2 +- src/main/java/games/dmg/treefeller/TreeTools.java | 1 + .../java/games/dmg/treefeller/TreeFellingListenerTest.java | 2 +- src/test/java/games/dmg/treefeller/TreeToolsTest.java | 1 + 6 files changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c4074c0..5078a1f 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Player preferences, administrative locks, progress, unlocks, and known names are Tree detection searches matching natural trunk blocks laterally and upward, never below the initiating chop, and requires corresponding foliage or caps. Search bounds prevent unbounded traversal. Leaves, caps, roots, vines, and decorations are not automatically broken. -Additional trunk blocks use Spigot's `Player.breakBlock` path so block-break cancellation, drops, experience, enchantments, and axe durability remain authoritative. Protection plugins should cancel `BlockBreakEvent` normally. A cancelled additional break stops the remaining felling. +Automatic felling supports Spigot 26.2 wooden, stone, copper, iron, golden, diamond, and netherite axes. Additional trunk blocks use Spigot's `Player.breakBlock` path so block-break cancellation, drops, experience, enchantments, and axe durability remain authoritative. Protection plugins should cancel `BlockBreakEvent` normally. A cancelled additional break stops the remaining felling. ## Releases diff --git a/design/log.md b/design/log.md index c8e8dfc..56b3422 100644 --- a/design/log.md +++ b/design/log.md @@ -2,6 +2,12 @@ ## 2026-08-11 +### US-003 copper axe support corrected + +- Reproduced copper axes failing automatic-felling eligibility because the explicit Spigot 26.2 axe-material set omitted `COPPER_AXE`. +- Added copper axes alongside wooden, stone, iron, golden, diamond, and netherite axes without broadening eligibility to pickaxes or other tools. +- Verified copper-axe classification, end-to-end felling activation, non-axe rejection, and the complete build with `./gradlew clean check jar`. + ### US-001 disrupted-tree progress corrected - Reproduced remaining lower logs failing to count after an upper trunk block was removed because progression unnecessarily re-ran full intact-tree validation. diff --git a/design/user-stories/us-003-fell-unlocked-trees.md b/design/user-stories/us-003-fell-unlocked-trees.md index 634d6dd..9e7520f 100644 --- a/design/user-stories/us-003-fell-unlocked-trees.md +++ b/design/user-stories/us-003-fell-unlocked-trees.md @@ -11,7 +11,7 @@ As a **player with an unlocked species**, I want its trees to break progressivel ## Acceptance criteria -- [x] Automatic felling is considered only for a non-cancelled Survival-mode block break made with an axe against a species the player has unlocked. +- [x] Automatic felling is considered only for a non-cancelled Survival-mode block break made with a supported wooden, stone, copper, iron, golden, diamond, or netherite axe against a species the player has unlocked. - [x] Sneaking when the initiating block is broken always bypasses automatic felling and leaves the ordinary single-block break intact. - [x] A disabled or administratively locked player receives the ordinary single-block break without automatic felling. - [x] Tree detection follows connected blocks of the initiating trunk family laterally and upward, including diagonal branches, but never follows trunk blocks below the initiating block. diff --git a/src/main/java/games/dmg/treefeller/TreeTools.java b/src/main/java/games/dmg/treefeller/TreeTools.java index 4fc3ec2..bcfa3c5 100644 --- a/src/main/java/games/dmg/treefeller/TreeTools.java +++ b/src/main/java/games/dmg/treefeller/TreeTools.java @@ -9,6 +9,7 @@ public final class TreeTools { private static final Set AXES = EnumSet.of( Material.WOODEN_AXE, Material.STONE_AXE, + Material.COPPER_AXE, Material.IRON_AXE, Material.GOLDEN_AXE, Material.DIAMOND_AXE, diff --git a/src/test/java/games/dmg/treefeller/TreeFellingListenerTest.java b/src/test/java/games/dmg/treefeller/TreeFellingListenerTest.java index 29cbfa9..5703c5d 100644 --- a/src/test/java/games/dmg/treefeller/TreeFellingListenerTest.java +++ b/src/test/java/games/dmg/treefeller/TreeFellingListenerTest.java @@ -35,7 +35,7 @@ class TreeFellingListenerTest { when(player.getName()).thenReturn("Player"); when(player.getGameMode()).thenReturn(GameMode.SURVIVAL); when(player.getInventory()).thenReturn(inventory); - when(inventory.getItemInMainHand()).thenReturn(new ItemStack(Material.IRON_AXE)); + when(inventory.getItemInMainHand()).thenReturn(new ItemStack(Material.COPPER_AXE)); TreeStructure tree = new TreeStructure( TreeSpecies.OAK, List.of(new BlockPoint(0, 0, 0), new BlockPoint(0, 1, 0))); PlayerTreeFellerState eligible = PlayerTreeFellerState.initial(playerId, "Player") diff --git a/src/test/java/games/dmg/treefeller/TreeToolsTest.java b/src/test/java/games/dmg/treefeller/TreeToolsTest.java index fe87800..b17a1f1 100644 --- a/src/test/java/games/dmg/treefeller/TreeToolsTest.java +++ b/src/test/java/games/dmg/treefeller/TreeToolsTest.java @@ -11,6 +11,7 @@ class TreeToolsTest { void acceptsAxesButNotPickaxesOrOtherItems() { assertTrue(TreeTools.isAxe(Material.WOODEN_AXE)); assertTrue(TreeTools.isAxe(Material.GOLDEN_AXE)); + assertTrue(TreeTools.isAxe(Material.COPPER_AXE)); assertTrue(TreeTools.isAxe(Material.NETHERITE_AXE)); assertFalse(TreeTools.isAxe(Material.DIAMOND_PICKAXE)); assertFalse(TreeTools.isAxe(Material.AIR));