瀏覽代碼

Fixed a bug that could prevent a Tree from being removed by Tree Feller
if 2 or more players were using Tree Feller simultaneously

nossr50 6 年之前
父節點
當前提交
0af3c82612

+ 3 - 0
Changelog.txt

@@ -1,3 +1,6 @@
+Version 2.1.94
+    Fixed a bug where 2 people using Tree Feller could result in the tree being rejected for being too big
+
 Version 2.1.93
     Fixed a bug where players would be told they could not breed summoned animals when the animals weren't summoned (bug didn't actually do anything besides send you a message)
 

+ 1 - 1
pom.xml

@@ -2,7 +2,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>com.gmail.nossr50.mcMMO</groupId>
     <artifactId>mcMMO</artifactId>
-    <version>2.1.93</version>
+    <version>2.1.94-SNAPSHOT</version>
     <name>mcMMO</name>
     <url>https://github.com/mcMMO-Dev/mcMMO</url>
     <scm>

+ 27 - 220
src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java

@@ -1,220 +1,27 @@
-package com.gmail.nossr50.skills.woodcutting;
-
-import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.config.experience.ExperienceConfig;
-import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
-import com.gmail.nossr50.mcMMO;
-import com.gmail.nossr50.util.BlockUtils;
-import com.gmail.nossr50.util.Misc;
-import com.gmail.nossr50.util.skills.SkillUtils;
-import org.bukkit.Material;
-import org.bukkit.block.BlockFace;
-import org.bukkit.block.BlockState;
-import org.bukkit.inventory.ItemStack;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-
-public final class Woodcutting {
-    public static int treeFellerThreshold = Config.getInstance().getTreeFellerThreshold();
-    protected static boolean treeFellerReachedThreshold = false;
-
-    private Woodcutting() {}
-
-    /**
-     * Retrieves the experience reward from a log
-     *
-     * @param blockState Log being broken
-     * @return Amount of experience
-     */
-    protected static int getExperienceFromLog(BlockState blockState) {
-        if (mcMMO.getModManager().isCustomLog(blockState)) {
-            return mcMMO.getModManager().getBlock(blockState).getXpGain();
-        }
-
-        return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
-    }
-
-    /**
-     * Retrieves the experience reward from logging via Tree Feller
-     * Experience is reduced per log processed so far
-     * Experience is only reduced if the config option to reduce Tree Feller XP is set
-     * Experience per log will not fall below 1 unless the experience for that log is set to 0 in the config
-     *
-     * @param blockState Log being broken
-     * @param woodCount how many logs have given out XP for this tree feller so far
-     * @return Amount of experience
-     */
-    protected static int processTreeFellerXPGains(BlockState blockState, int woodCount) {
-        int rawXP = ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
-
-        if(rawXP <= 0)
-            return 0;
-
-        if(ExperienceConfig.getInstance().isTreeFellerXPReduced()) {
-            int reducedXP = 1 + (woodCount * 5);
-            rawXP = Math.max(1, rawXP - reducedXP);
-            return rawXP;
-        } else {
-            return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
-        }
-    }
-
-
-
-    /**
-     * Checks for double drops
-     *
-     * @param blockState Block being broken
-     */
-    protected static void checkForDoubleDrop(BlockState blockState) {
-        if (mcMMO.getModManager().isCustomLog(blockState) && mcMMO.getModManager().getBlock(blockState).isDoubleDropEnabled()) {
-            Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops());
-        }
-        else {
-            if (Config.getInstance().getWoodcuttingDoubleDropsEnabled(blockState.getBlockData())) {
-                Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops());
-            }
-        }
-    }
-
-    /**
-     * The x/y differences to the blocks in a flat cylinder around the center
-     * block, which is excluded.
-     */
-    private static final int[][] directions = {
-                            new int[] {-2, -1}, new int[] {-2, 0}, new int[] {-2, 1},
-        new int[] {-1, -2}, new int[] {-1, -1}, new int[] {-1, 0}, new int[] {-1, 1}, new int[] {-1, 2},
-        new int[] { 0, -2}, new int[] { 0, -1},                    new int[] { 0, 1}, new int[] { 0, 2},
-        new int[] { 1, -2}, new int[] { 1, -1}, new int[] { 1, 0}, new int[] { 1, 1}, new int[] { 1, 2},
-                            new int[] { 2, -1}, new int[] { 2, 0}, new int[] { 2, 1},
-    };
-
-    /**
-     * Processes Tree Feller in a recursive manner
-     *
-     * @param blockState Block being checked
-     * @param treeFellerBlocks List of blocks to be removed
-     */
-    /*
-     * Algorithm: An int[][] of X/Z directions is created on static class
-     * initialization, representing a cylinder with radius of about 2 - the
-     * (0,0) center and all (+-2, +-2) corners are omitted.
-     *
-     * handleBlock() returns a boolean, which is used for the sole purpose of
-     * switching between these two behaviors:
-     *
-     * (Call blockState "this log" for the below explanation.)
-     *
-     *  [A] There is another log above this log (TRUNK)
-     *    Only the flat cylinder in the directions array is searched.
-     *  [B] There is not another log above this log (BRANCH AND TOP)
-     *    The cylinder in the directions array is extended up and down by 1
-     *    block in the Y-axis, and the block below this log is checked as
-     *    well. Due to the fact that the directions array will catch all
-     *    blocks on a red mushroom, the special method for it is eliminated.
-     *
-     * This algorithm has been shown to achieve a performance of 2-5
-     * milliseconds on regular trees and 10-15 milliseconds on jungle trees
-     * once the JIT has optimized the function (use the ability about 4 times
-     * before taking measurements).
-     */
-    protected static void processTree(BlockState blockState, Set<BlockState> treeFellerBlocks) {
-        List<BlockState> futureCenterBlocks = new ArrayList<BlockState>();
-
-        // Check the block up and take different behavior (smaller search) if it's a log
-        if (handleBlock(blockState.getBlock().getRelative(BlockFace.UP).getState(), futureCenterBlocks, treeFellerBlocks)) {
-            for (int[] dir : directions) {
-                handleBlock(blockState.getBlock().getRelative(dir[0], 0, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks);
-
-                if (treeFellerReachedThreshold) {
-                    return;
-                }
-            }
-        }
-        else {
-            // Cover DOWN
-            handleBlock(blockState.getBlock().getRelative(BlockFace.DOWN).getState(), futureCenterBlocks, treeFellerBlocks);
-            // Search in a cube
-            for (int y = -1; y <= 1; y++) {
-                for (int[] dir : directions) {
-                    handleBlock(blockState.getBlock().getRelative(dir[0], y, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks);
-
-                    if (treeFellerReachedThreshold) {
-                        return;
-                    }
-                }
-            }
-        }
-
-        // Recursive call for each log found
-        for (BlockState futureCenterBlock : futureCenterBlocks) {
-            if (treeFellerReachedThreshold) {
-                return;
-            }
-
-            processTree(futureCenterBlock, treeFellerBlocks);
-        }
-    }
-
-    /**
-     * Handles the durability loss
-     *
-     * @param treeFellerBlocks List of blocks to be removed
-     * @param inHand tool being used
-     * @return True if the tool can sustain the durability loss
-     */
-    protected static boolean handleDurabilityLoss(Set<BlockState> treeFellerBlocks, ItemStack inHand) {
-        //Treat the NBT tag for unbreakable and the durability enchant differently
-        if(inHand.getItemMeta() != null && inHand.getItemMeta().isUnbreakable()) {
-            return true;
-        }
-
-        short durabilityLoss = 0;
-        Material type = inHand.getType();
-
-        for (BlockState blockState : treeFellerBlocks) {
-            if (BlockUtils.isLog(blockState)) {
-                durabilityLoss += Config.getInstance().getAbilityToolDamage();
-            }
-        }
-
-        SkillUtils.handleDurabilityChange(inHand, durabilityLoss);
-        return (inHand.getDurability() < (mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability()));
-    }
-
-    /**
-     * Handle a block addition to the list of blocks to be removed and to the
-     * list of blocks used for future recursive calls of
-     * 'processTree()'
-     *
-     * @param blockState Block to be added
-     * @param futureCenterBlocks List of blocks that will be used to call
-     *     'processTree()'
-     * @param treeFellerBlocks List of blocks to be removed
-     * @return true if and only if the given blockState was a Log not already
-     *     in treeFellerBlocks.
-     */
-    private static boolean handleBlock(BlockState blockState, List<BlockState> futureCenterBlocks, Set<BlockState> treeFellerBlocks) {
-        if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) {
-            return false;
-        }
-
-        // Without this check Tree Feller propagates through leaves until the threshold is hit
-        if (treeFellerBlocks.size() > treeFellerThreshold) {
-            treeFellerReachedThreshold = true;
-        }
-
-        if (BlockUtils.isLog(blockState)) {
-            treeFellerBlocks.add(blockState);
-            futureCenterBlocks.add(blockState);
-            return true;
-        }
-        else if (BlockUtils.isLeaves(blockState)) {
-            treeFellerBlocks.add(blockState);
-            return false;
-        }
-        return false;
-    }
-}
+//package com.gmail.nossr50.skills.woodcutting;
+//
+//import com.gmail.nossr50.config.Config;
+//import com.gmail.nossr50.config.experience.ExperienceConfig;
+//import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
+//import com.gmail.nossr50.mcMMO;
+//import com.gmail.nossr50.util.BlockUtils;
+//import com.gmail.nossr50.util.Misc;
+//import com.gmail.nossr50.util.skills.SkillUtils;
+//import org.bukkit.Material;
+//import org.bukkit.block.BlockFace;
+//import org.bukkit.block.BlockState;
+//import org.bukkit.inventory.ItemStack;
+//
+//import java.util.ArrayList;
+//import java.util.List;
+//import java.util.Set;
+//
+//public final class Woodcutting {
+//    public static int treeFellerThreshold = Config.getInstance().getTreeFellerThreshold();
+//
+//    private Woodcutting() {}
+//
+//
+//
+//
+//}

+ 217 - 13
src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java

@@ -1,5 +1,7 @@
 package com.gmail.nossr50.skills.woodcutting;
 
+import com.gmail.nossr50.config.Config;
+import com.gmail.nossr50.config.experience.ExperienceConfig;
 import com.gmail.nossr50.datatypes.experience.XPGainReason;
 import com.gmail.nossr50.datatypes.interactions.NotificationType;
 import com.gmail.nossr50.datatypes.player.McMMOPlayer;
@@ -14,19 +16,39 @@ import com.gmail.nossr50.util.random.RandomChanceUtil;
 import com.gmail.nossr50.util.skills.CombatUtils;
 import com.gmail.nossr50.util.skills.RankUtils;
 import com.gmail.nossr50.util.skills.SkillActivationType;
+import com.gmail.nossr50.util.skills.SkillUtils;
 import org.bukkit.Material;
 import org.bukkit.block.Block;
+import org.bukkit.block.BlockFace;
 import org.bukkit.block.BlockState;
 import org.bukkit.entity.Player;
 import org.bukkit.inventory.ItemStack;
 
+import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 public class WoodcuttingManager extends SkillManager {
 
+    private boolean treeFellerReachedThreshold = false;
+    private static int treeFellerThreshold; //TODO: Shared setting, will be removed in 2.2
+
+    /**
+     * The x/y differences to the blocks in a flat cylinder around the center
+     * block, which is excluded.
+     */
+    private static final int[][] directions = {
+            new int[] {-2, -1}, new int[] {-2, 0}, new int[] {-2, 1},
+            new int[] {-1, -2}, new int[] {-1, -1}, new int[] {-1, 0}, new int[] {-1, 1}, new int[] {-1, 2},
+            new int[] { 0, -2}, new int[] { 0, -1},                    new int[] { 0, 1}, new int[] { 0, 2},
+            new int[] { 1, -2}, new int[] { 1, -1}, new int[] { 1, 0}, new int[] { 1, 1}, new int[] { 1, 2},
+            new int[] { 2, -1}, new int[] { 2, 0}, new int[] { 2, 1},
+    };
+
     public WoodcuttingManager(McMMOPlayer mcMMOPlayer) {
         super(mcMMOPlayer, PrimarySkillType.WOODCUTTING);
+        treeFellerThreshold = Config.getInstance().getTreeFellerThreshold();
     }
 
     public boolean canUseLeafBlower(ItemStack heldItem) {
@@ -52,7 +74,7 @@ public class WoodcuttingManager extends SkillManager {
      * @param blockState Block being broken
      */
     public void woodcuttingBlockCheck(BlockState blockState) {
-        int xp = Woodcutting.getExperienceFromLog(blockState);
+        int xp = getExperienceFromLog(blockState);
 
         switch (blockState.getType()) {
             case BROWN_MUSHROOM_BLOCK:
@@ -61,7 +83,7 @@ public class WoodcuttingManager extends SkillManager {
 
             default:
                 if (canGetDoubleDrops()) {
-                    Woodcutting.checkForDoubleDrop(blockState);
+                    checkForDoubleDrop(blockState);
                 }
         }
 
@@ -77,20 +99,20 @@ public class WoodcuttingManager extends SkillManager {
         Player player = getPlayer();
         Set<BlockState> treeFellerBlocks = new HashSet<BlockState>();
 
-        Woodcutting.treeFellerReachedThreshold = false;
+        treeFellerReachedThreshold = false;
 
-        Woodcutting.processTree(blockState, treeFellerBlocks);
+        processTree(blockState, treeFellerBlocks);
 
         // If the player is trying to break too many blocks
-        if (Woodcutting.treeFellerReachedThreshold) {
-            Woodcutting.treeFellerReachedThreshold = false;
+        if (treeFellerReachedThreshold) {
+            treeFellerReachedThreshold = false;
 
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Threshold");
             return;
         }
 
         // If the tool can't sustain the durability loss
-        if (!Woodcutting.handleDurabilityLoss(treeFellerBlocks, player.getInventory().getItemInMainHand())) {
+        if (!handleDurabilityLoss(treeFellerBlocks, player.getInventory().getItemInMainHand())) {
             NotificationManager.sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Splinter");
 
             double health = player.getHealth();
@@ -102,8 +124,135 @@ public class WoodcuttingManager extends SkillManager {
             return;
         }
 
-        dropBlocks(treeFellerBlocks);
-        Woodcutting.treeFellerReachedThreshold = false; // Reset the value after we're done with Tree Feller each time.
+        dropTreeFellerLootFromBlocks(treeFellerBlocks);
+        treeFellerReachedThreshold = false; // Reset the value after we're done with Tree Feller each time.
+    }
+
+    /**
+     * Processes Tree Feller in a recursive manner
+     *
+     * @param blockState Block being checked
+     * @param treeFellerBlocks List of blocks to be removed
+     */
+    /*
+     * Algorithm: An int[][] of X/Z directions is created on static class
+     * initialization, representing a cylinder with radius of about 2 - the
+     * (0,0) center and all (+-2, +-2) corners are omitted.
+     *
+     * processTreeFellerTargetBlock() returns a boolean, which is used for the sole purpose of
+     * switching between these two behaviors:
+     *
+     * (Call blockState "this log" for the below explanation.)
+     *
+     *  [A] There is another log above this log (TRUNK)
+     *    Only the flat cylinder in the directions array is searched.
+     *  [B] There is not another log above this log (BRANCH AND TOP)
+     *    The cylinder in the directions array is extended up and down by 1
+     *    block in the Y-axis, and the block below this log is checked as
+     *    well. Due to the fact that the directions array will catch all
+     *    blocks on a red mushroom, the special method for it is eliminated.
+     *
+     * This algorithm has been shown to achieve a performance of 2-5
+     * milliseconds on regular trees and 10-15 milliseconds on jungle trees
+     * once the JIT has optimized the function (use the ability about 4 times
+     * before taking measurements).
+     */
+    private void processTree(BlockState blockState, Set<BlockState> treeFellerBlocks) {
+        List<BlockState> futureCenterBlocks = new ArrayList<BlockState>();
+
+        // Check the block up and take different behavior (smaller search) if it's a log
+        if (processTreeFellerTargetBlock(blockState.getBlock().getRelative(BlockFace.UP).getState(), futureCenterBlocks, treeFellerBlocks)) {
+            for (int[] dir : directions) {
+                processTreeFellerTargetBlock(blockState.getBlock().getRelative(dir[0], 0, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks);
+
+                if (treeFellerReachedThreshold) {
+                    return;
+                }
+            }
+        }
+        else {
+            // Cover DOWN
+            processTreeFellerTargetBlock(blockState.getBlock().getRelative(BlockFace.DOWN).getState(), futureCenterBlocks, treeFellerBlocks);
+            // Search in a cube
+            for (int y = -1; y <= 1; y++) {
+                for (int[] dir : directions) {
+                    processTreeFellerTargetBlock(blockState.getBlock().getRelative(dir[0], y, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks);
+
+                    if (treeFellerReachedThreshold) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        // Recursive call for each log found
+        for (BlockState futureCenterBlock : futureCenterBlocks) {
+            if (treeFellerReachedThreshold) {
+                return;
+            }
+
+            processTree(futureCenterBlock, treeFellerBlocks);
+        }
+    }
+
+    /**
+     * Handles the durability loss
+     *
+     * @param treeFellerBlocks List of blocks to be removed
+     * @param inHand tool being used
+     * @return True if the tool can sustain the durability loss
+     */
+    private static boolean handleDurabilityLoss(Set<BlockState> treeFellerBlocks, ItemStack inHand) {
+        //Treat the NBT tag for unbreakable and the durability enchant differently
+        if(inHand.getItemMeta() != null && inHand.getItemMeta().isUnbreakable()) {
+            return true;
+        }
+
+        short durabilityLoss = 0;
+        Material type = inHand.getType();
+
+        for (BlockState blockState : treeFellerBlocks) {
+            if (BlockUtils.isLog(blockState)) {
+                durabilityLoss += Config.getInstance().getAbilityToolDamage();
+            }
+        }
+
+        SkillUtils.handleDurabilityChange(inHand, durabilityLoss);
+        return (inHand.getDurability() < (mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability()));
+    }
+
+    /**
+     * Handle a block addition to the list of blocks to be removed and to the
+     * list of blocks used for future recursive calls of
+     * 'processTree()'
+     *
+     * @param blockState Block to be added
+     * @param futureCenterBlocks List of blocks that will be used to call
+     *     'processTree()'
+     * @param treeFellerBlocks List of blocks to be removed
+     * @return true if and only if the given blockState was a Log not already
+     *     in treeFellerBlocks.
+     */
+    private boolean processTreeFellerTargetBlock(BlockState blockState, List<BlockState> futureCenterBlocks, Set<BlockState> treeFellerBlocks) {
+        if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) {
+            return false;
+        }
+
+        // Without this check Tree Feller propagates through leaves until the threshold is hit
+        if (treeFellerBlocks.size() > treeFellerThreshold) {
+            treeFellerReachedThreshold = true;
+        }
+
+        if (BlockUtils.isLog(blockState)) {
+            treeFellerBlocks.add(blockState);
+            futureCenterBlocks.add(blockState);
+            return true;
+        }
+        else if (BlockUtils.isLeaves(blockState)) {
+            treeFellerBlocks.add(blockState);
+            return false;
+        }
+        return false;
     }
 
     /**
@@ -111,7 +260,7 @@ public class WoodcuttingManager extends SkillManager {
      *
      * @param treeFellerBlocks List of blocks to be dropped
      */
-    private void dropBlocks(Set<BlockState> treeFellerBlocks) {
+    private void dropTreeFellerLootFromBlocks(Set<BlockState> treeFellerBlocks) {
         Player player = getPlayer();
         int xp = 0;
         int processedLogCount = 0;
@@ -127,16 +276,16 @@ public class WoodcuttingManager extends SkillManager {
 
             //TODO: Update this to drop the correct items/blocks via NMS
             if (material == Material.BROWN_MUSHROOM_BLOCK || material == Material.RED_MUSHROOM_BLOCK) {
-                xp += Woodcutting.processTreeFellerXPGains(blockState, processedLogCount);
+                xp += processTreeFellerXPGains(blockState, processedLogCount);
                 Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops());
             } else if (mcMMO.getModManager().isCustomLeaf(blockState)) {
                 Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops());
             } else {
                 if (BlockUtils.isLog(blockState)) {
                     if (canGetDoubleDrops()) {
-                        Woodcutting.checkForDoubleDrop(blockState);
+                        checkForDoubleDrop(blockState);
                     }
-                    xp += Woodcutting.processTreeFellerXPGains(blockState, processedLogCount);
+                    xp += processTreeFellerXPGains(blockState, processedLogCount);
                     Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops());
                 }
                 if (BlockUtils.isLeaves(blockState)) {
@@ -151,4 +300,59 @@ public class WoodcuttingManager extends SkillManager {
 
         applyXpGain(xp, XPGainReason.PVE);
     }
+
+    /**
+     * Retrieves the experience reward from logging via Tree Feller
+     * Experience is reduced per log processed so far
+     * Experience is only reduced if the config option to reduce Tree Feller XP is set
+     * Experience per log will not fall below 1 unless the experience for that log is set to 0 in the config
+     *
+     * @param blockState Log being broken
+     * @param woodCount how many logs have given out XP for this tree feller so far
+     * @return Amount of experience
+     */
+    private static int processTreeFellerXPGains(BlockState blockState, int woodCount) {
+        int rawXP = ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
+
+        if(rawXP <= 0)
+            return 0;
+
+        if(ExperienceConfig.getInstance().isTreeFellerXPReduced()) {
+            int reducedXP = 1 + (woodCount * 5);
+            rawXP = Math.max(1, rawXP - reducedXP);
+            return rawXP;
+        } else {
+            return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
+        }
+    }
+
+    /**
+     * Retrieves the experience reward from a log
+     *
+     * @param blockState Log being broken
+     * @return Amount of experience
+     */
+    protected static int getExperienceFromLog(BlockState blockState) {
+        if (mcMMO.getModManager().isCustomLog(blockState)) {
+            return mcMMO.getModManager().getBlock(blockState).getXpGain();
+        }
+
+        return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
+    }
+
+    /**
+     * Checks for double drops
+     *
+     * @param blockState Block being broken
+     */
+    protected static void checkForDoubleDrop(BlockState blockState) {
+        if (mcMMO.getModManager().isCustomLog(blockState) && mcMMO.getModManager().getBlock(blockState).isDoubleDropEnabled()) {
+            Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops());
+        }
+        else {
+            if (Config.getInstance().getWoodcuttingDoubleDropsEnabled(blockState.getBlockData())) {
+                Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops());
+            }
+        }
+    }
 }