Просмотр исходного кода

Optimized Tree Feller
And cleaned up WoodCutting a little

bm01 12 лет назад
Родитель
Сommit
f0f7dee3c2

+ 1 - 1
src/main/java/com/gmail/nossr50/listeners/BlockListener.java

@@ -186,7 +186,7 @@ public class BlockListener implements Listener {
                 WoodCutting.woodcuttingBlockCheck(player, block);
             }
 
-            if (profile.getAbilityMode(AbilityType.TREE_FELLER) && Permissions.treeFeller(player) && ItemChecks.isAxe(inHand)) {
+            if (!mcMMO.placeStore.isTrue(block) && profile.getAbilityMode(AbilityType.TREE_FELLER) && Permissions.treeFeller(player) && ItemChecks.isAxe(inHand)) {
                 WoodCutting.treeFeller(event);
             }
         }

+ 167 - 255
src/main/java/com/gmail/nossr50/skills/gathering/WoodCutting.java

@@ -1,12 +1,14 @@
 package com.gmail.nossr50.skills.gathering;
 
 import java.util.ArrayList;
+import java.util.List;
 
 import org.bukkit.Location;
 import org.bukkit.Material;
 import org.bukkit.TreeSpecies;
+import org.bukkit.World;
 import org.bukkit.block.Block;
-import org.bukkit.enchantments.Enchantment;
+import org.bukkit.block.BlockFace;
 import org.bukkit.entity.Player;
 import org.bukkit.event.block.BlockBreakEvent;
 import org.bukkit.inventory.ItemStack;
@@ -17,7 +19,6 @@ import org.getspout.spoutapi.sound.SoundEffect;
 import com.gmail.nossr50.mcMMO;
 import com.gmail.nossr50.config.AdvancedConfig;
 import com.gmail.nossr50.config.Config;
-import com.gmail.nossr50.datatypes.PlayerProfile;
 import com.gmail.nossr50.datatypes.SkillType;
 import com.gmail.nossr50.datatypes.mods.CustomBlock;
 import com.gmail.nossr50.events.fake.FakePlayerAnimationEvent;
@@ -32,317 +33,217 @@ import com.gmail.nossr50.util.Skills;
 import com.gmail.nossr50.util.Users;
 
 public class WoodCutting {
-
-    static AdvancedConfig advancedConfig = AdvancedConfig.getInstance();
+    private static final AdvancedConfig ADVANCED_CONFIG = AdvancedConfig.getInstance();
+    private static boolean treeFellerReachedThreshold = false;
 
     /**
      * Handle the Tree Feller ability.
      *
-     * @param event Event to modify
+     * @param event Event to process
      */
     public static void treeFeller(BlockBreakEvent event) {
-        Player player = event.getPlayer();
-        Block firstBlock = event.getBlock();
-        PlayerProfile profile = Users.getProfile(player);
-        ArrayList<Block> toBeFelled = new ArrayList<Block>();
-
-        /* NOTE: Tree Feller will cut upwards like how you actually fell trees */
-        processTreeFelling(firstBlock, toBeFelled);
-        removeBlocks(toBeFelled, player, profile);
+        List<Block> toBeFelled = processTreeFeller(event);
+
+        if (toBeFelled != null && !toBeFelled.isEmpty()) {
+            removeBlocks(toBeFelled, event.getPlayer());
+        }
     }
 
     /**
      * Handles removing & dropping the blocks from Tree Feller.
      *
-     * @param toBeFelled List of Blocks to be removed from the tree
-     * @param player The player using the ability
-     * @param profile The PlayerProfile of the player
+     * @param toBeFelled List of blocks to be removed
+     * @param player Player using the ability
      */
-    private static void removeBlocks(ArrayList<Block> toBeFelled, Player player, PlayerProfile profile) {
-        if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) {
-            player.sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFellerThreshold"));
-            return;
-        }
-
-        int xp = 0;
+    private static void removeBlocks(List<Block> toBeFelled, Player player) {
         ItemStack inHand = player.getItemInHand();
-        int level = 0;
-        if (inHand.containsEnchantment(Enchantment.DURABILITY)) {
-            level = inHand.getEnchantmentLevel(Enchantment.DURABILITY);
-        }
-        int durabilityLoss = durabilityLossCalulate(toBeFelled, level);
+        Material inHandMaterial = inHand.getType();
+        short finalDurability = (short) (inHand.getDurability() + calulateDurabilityLossFromTreeFeller(toBeFelled));
 
-        /* This is to prevent using wood axes everytime you tree fell */
-        if (ModChecks.isCustomTool(inHand)) {
-            if (inHand.getDurability() + durabilityLoss >= ModChecks.getToolFromItemStack(inHand).getDurability()) {
+        // Prevent the tree to be cut down if the tool doesn't have enough durability
+        if (inHandMaterial != Material.AIR) {
+            short maxDurability = ModChecks.isCustomTool(inHand) ? ModChecks.getToolFromItemStack(inHand).getDurability() : inHandMaterial.getMaxDurability();
+
+            if (finalDurability >= maxDurability) {
                 player.sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFeller.Splinter"));
 
                 int health = player.getHealth();
 
                 if (health >= 2) {
-                    Combat.dealDamage(player, Misc.getRandom().nextInt(health - 1));
+                    Combat.dealDamage(player, Misc.getRandom().nextInt(health - 1)); // Why not base the damage on the number of elements in toBeFelled?
                 }
-                inHand.setDurability(inHand.getType().getMaxDurability());
-                return;
-            }
-        }
-        else if ((inHand.getDurability() + durabilityLoss >= inHand.getType().getMaxDurability()) || inHand.getType().equals(Material.AIR)) {
-            player.sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFeller.Splinter"));
-
-            int health = player.getHealth();
 
-            if (health >= 2) {
-                Combat.dealDamage(player, Misc.getRandom().nextInt(health - 1));
+                inHand.setDurability(maxDurability);
+                return;
             }
-            inHand.setDurability(inHand.getType().getMaxDurability());
-            return;
         }
 
-        /* Damage the tool */
-        inHand.setDurability((short) (inHand.getDurability() + durabilityLoss));
+        inHand.setDurability(finalDurability);
 
-        //Prepare ItemStacks
+        int xp = 0;
         ItemStack item = null;
-        ItemStack oak = (new MaterialData(Material.LOG, TreeSpecies.GENERIC.getData())).toItemStack(1);
-        ItemStack spruce = (new MaterialData(Material.LOG, TreeSpecies.REDWOOD.getData())).toItemStack(1);
-        ItemStack birch = (new MaterialData(Material.LOG, TreeSpecies.BIRCH.getData())).toItemStack(1);
-        ItemStack jungle = (new MaterialData(Material.LOG, TreeSpecies.JUNGLE.getData())).toItemStack(1);
-
-        for (Block x : toBeFelled) {
-            if (Misc.blockBreakSimulate(x, player, true)) {
-                if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(x)) {
-                    if (ModChecks.isCustomLogBlock(x)) {
-                        CustomBlock block = ModChecks.getCustomBlock(x);
-                        item = block.getItemDrop();
-
-                        if (!mcMMO.placeStore.isTrue(x)) {
-                            WoodCutting.woodCuttingProcCheck(player, x);
-                            xp = block.getXpGain();
-                        }
-
-                        /* Remove the block */
-                        x.setData((byte) 0x0);
-                        x.setType(Material.AIR);
-
-                        int minimumDropAmount = block.getMinimumDropAmount();
-                        int maximumDropAmount = block.getMaximumDropAmount();
-
-                        item = block.getItemDrop();
-
-                        if (minimumDropAmount != maximumDropAmount) {
-                            Misc.dropItems(x.getLocation(), item, minimumDropAmount);
-                            Misc.randomDropItems(x.getLocation(), item, 50, maximumDropAmount - minimumDropAmount);
-                        }
-                        else {
-                            Misc.dropItems(x.getLocation(), item, minimumDropAmount);
-                        }
-                    }
-                    else if (ModChecks.isCustomLeafBlock(x)) {
-                        CustomBlock block = ModChecks.getCustomBlock(x);
-                        item = block.getItemDrop();
-
-                        final int SAPLING_DROP_CHANCE = 10;
-
-                        /* Remove the block */
-                        x.setData((byte) 0x0);
-                        x.setType(Material.AIR);
-
-                        Misc.randomDropItem(x.getLocation(), item, SAPLING_DROP_CHANCE);
-                    }
-                }
-                else if (x.getType() == Material.LOG) {
-                    Tree tree = (Tree) x.getState().getData();
-                    TreeSpecies species = tree.getSpecies();
 
-                    switch (species) {
-                    case GENERIC:
-                        item = oak;
-                        break;
-
-                    case REDWOOD:
-                        item = spruce;
-                        break;
+        for (Block block : toBeFelled) {
+            if (!Misc.blockBreakSimulate(block, player, true)) {
+                break;
+            }
 
-                    case BIRCH:
-                        item = birch;
-                        break;
+            if (block.getType() == Material.LOG) {
+                WoodCutting.woodCuttingProcCheck(player, block);
 
-                    case JUNGLE:
-                        item = jungle;
-                        break;
+                TreeSpecies species = ((Tree) block.getState().getData()).getSpecies();
 
-                    default:
-                        break;
-                    }
+                switch (species) {
+                case GENERIC:
+                    item = new MaterialData(Material.LOG, TreeSpecies.GENERIC.getData()).toItemStack(1);
+                    xp += Config.getInstance().getWoodcuttingXPOak();
+                    break;
+                case REDWOOD:
+                    item = new MaterialData(Material.LOG, TreeSpecies.REDWOOD.getData()).toItemStack(1);
+                    xp += Config.getInstance().getWoodcuttingXPSpruce();
+                    break;
+                case BIRCH:
+                    item = new MaterialData(Material.LOG, TreeSpecies.BIRCH.getData()).toItemStack(1);
+                    xp += Config.getInstance().getWoodcuttingXPBirch();
+                    break;
+                case JUNGLE:
+                    item = new MaterialData(Material.LOG, TreeSpecies.JUNGLE.getData()).toItemStack(1);
+                    xp += Config.getInstance().getWoodcuttingXPJungle() / 2; // Nerf XP from Jungle Trees when using Tree Feller
+                    break;
+                default:
+                    break;
+                }
 
-                    if (!mcMMO.placeStore.isTrue(x)) {
-                        WoodCutting.woodCuttingProcCheck(player, x);
+                Misc.dropItem(block.getLocation(), item);
+            }
+            else if (block.getType() == Material.LEAVES) {
+                item = new MaterialData(Material.SAPLING, (byte) (block.getData() & 3)).toItemStack(1); 
 
-                        switch (species) {
-                        case GENERIC:
-                            xp += Config.getInstance().getWoodcuttingXPOak();
-                            break;
+                Misc.randomDropItem(block.getLocation(), item, 10);
+            }
+            else if (Config.getInstance().getBlockModsEnabled()) {
+                if (ModChecks.isCustomLogBlock(block)) {
+                    CustomBlock customBlock = ModChecks.getCustomBlock(block);
 
-                        case REDWOOD:
-                            xp += Config.getInstance().getWoodcuttingXPSpruce();
-                            break;
+                    WoodCutting.woodCuttingProcCheck(player, block);
 
-                        case BIRCH:
-                            xp += Config.getInstance().getWoodcuttingXPBirch();
-                            break;
+                    xp = customBlock.getXpGain();
+                    int minimumDropAmount = customBlock.getMinimumDropAmount();
+                    int maximumDropAmount = customBlock.getMaximumDropAmount();
+                    Location location = block.getLocation();
+                    item = customBlock.getItemDrop();
 
-                        case JUNGLE:
-                            xp += Config.getInstance().getWoodcuttingXPJungle() / 2; //Nerf XP from Jungle Trees when using Tree Feller
-                            break;
+                    Misc.dropItems(location, item, minimumDropAmount);
 
-                        default:
-                            break;
-                        }
+                    if (minimumDropAmount < maximumDropAmount) {
+                        Misc.randomDropItems(location, item, 50, maximumDropAmount - minimumDropAmount);
                     }
-
-                    /* Remove the block */
-                    x.setData((byte) 0x0);
-                    x.setType(Material.AIR);
-
-                    /* Drop the block */
-                    Misc.dropItem(x.getLocation(), item);
                 }
-                else if (x.getType() == Material.LEAVES) {
-                    final int SAPLING_DROP_CHANCE = 10;
-
-                    //Drop the right type of sapling
-                    item = (new MaterialData(Material.SAPLING, (byte) (x.getData() & 3))).toItemStack(1);
+                else if (ModChecks.isCustomLeafBlock(block)) {
+                    CustomBlock customBlock = ModChecks.getCustomBlock(block);
 
-                    Misc.randomDropItem(x.getLocation(), item, SAPLING_DROP_CHANCE);
-
-                    //Remove the block
-                    x.setData((byte) 0);
-                    x.setType(Material.AIR);
+                    Misc.randomDropItem(block.getLocation(), customBlock.getItemDrop(), 10);
                 }
             }
+
+            block.setData((byte) 0);
+            block.setType(Material.AIR);
         }
 
         if (Permissions.woodcutting(player)) {
-            Skills.xpProcessing(player, profile, SkillType.WOODCUTTING, xp);
+            Skills.xpProcessing(player, Users.getProfile(player), SkillType.WOODCUTTING, xp);
         }
     }
 
     /**
-     * Handle the calculations from Tree Feller.
+     * Process Tree Feller around a block.
      *
-     * @param currentBlock The current block to be removed
-     * @param toBeFelled The list of blocks left to be removed
+     * @param block Point of origin of the layer
+     * @param toBeFelled List of blocks to be removed
      */
-    private static void processTreeFelling(Block currentBlock, ArrayList<Block> toBeFelled) {
-        Material type = currentBlock.getType();
-
-        if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) {
-            return;
-        }
-
-        if (!mcMMO.placeStore.isTrue(currentBlock)) {
-            if ((type.equals(Material.LOG) || type.equals(Material.LEAVES))) {
-                toBeFelled.add(currentBlock);
+    private static void processTreeFellerAroundBlock(Block block, List<Block> toBeFelled) {
+        // TODO: too much duplicate code here
+        List<Block> futureCenterBlocks = new ArrayList<Block>();
+        boolean centerIsLog = (block.getType() == Material.LOG); //TODO: custom blocks?
+        
+        // Handle the block above 'block'
+        Block nextBlock = block.getRelative(BlockFace.UP);;
+
+        if (BlockChecks.treeFellerCompatible(nextBlock) && !toBeFelled.contains(nextBlock) && !mcMMO.placeStore.isTrue(nextBlock)) {
+            toBeFelled.add(nextBlock);
+
+            if (centerIsLog) {
+                futureCenterBlocks.add(nextBlock);
             }
-            else if (Config.getInstance().getBlockModsEnabled() && (ModChecks.isCustomLogBlock(currentBlock) || ModChecks.isCustomLeafBlock(currentBlock))) {
-                toBeFelled.add(currentBlock);
-            }
-        }
-
-        Block xPositive = currentBlock.getRelative(1, 0, 0);
-        Block xNegative = currentBlock.getRelative(-1, 0, 0);
-        Block zPositive = currentBlock.getRelative(0, 0, 1);
-        Block zNegative = currentBlock.getRelative(0, 0, -1);
-        Block yPositive = currentBlock.getRelative(0, 1, 0);
 
-        if (!mcMMO.placeStore.isTrue(currentBlock)) {
-            if (!isTooAggressive(currentBlock, xPositive) && BlockChecks.treeFellerCompatible(xPositive) && !toBeFelled.contains(xPositive)) {
-                processTreeFelling(xPositive, toBeFelled);
-            }
-
-            if (!isTooAggressive(currentBlock, xNegative) && BlockChecks.treeFellerCompatible(xNegative) && !toBeFelled.contains(xNegative)) {
-                processTreeFelling(xNegative, toBeFelled);
-            }
-
-            if (!isTooAggressive(currentBlock, zPositive) && BlockChecks.treeFellerCompatible(zPositive) && !toBeFelled.contains(zPositive)) {
-                processTreeFelling(zPositive, toBeFelled);
-            }
-
-            if (!isTooAggressive(currentBlock, zNegative) && BlockChecks.treeFellerCompatible(zNegative) && !toBeFelled.contains(zNegative)) {
-                processTreeFelling(zNegative, toBeFelled);
+            if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) {
+                treeFellerReachedThreshold = true;
+                return;
             }
         }
 
-        byte data = currentBlock.getData();
-
-        if ((data & 0x4) == 0x4)
-            data ^= 0x4;
+        World world = block.getWorld();
 
-        if ((data & 0x8) == 0x8)
-            data ^= 0x8;
+        // Handle the blocks around 'block'
+        for (int x = -1 ; x <= 1 ; x++) {
+            for (int z = -1 ; z <= 1 ; z++) {
+                nextBlock = world.getBlockAt(block.getLocation().add(x, 0, z));
 
-        if (TreeSpecies.getByData(data) == TreeSpecies.JUNGLE) {
-            Block corner1 = currentBlock.getRelative(1, 0, 1);
-            Block corner2 = currentBlock.getRelative(1, 0, -1);
-            Block corner3 = currentBlock.getRelative(-1, 0, 1);
-            Block corner4 = currentBlock.getRelative(-1, 0, -1);
+                if (BlockChecks.treeFellerCompatible(nextBlock) && !toBeFelled.contains(nextBlock) && !mcMMO.placeStore.isTrue(nextBlock)) {
+                    toBeFelled.add(nextBlock);
 
-            if (!mcMMO.placeStore.isTrue(currentBlock)) {
-                if (!isTooAggressive(currentBlock, corner1) && BlockChecks.treeFellerCompatible(corner1) && !toBeFelled.contains(corner1)) {
-                    processTreeFelling(corner1, toBeFelled);
-                }
-
-                if (!isTooAggressive(currentBlock, corner2) && BlockChecks.treeFellerCompatible(corner2) && !toBeFelled.contains(corner2)) {
-                    processTreeFelling(corner2, toBeFelled);
-                }
-
-                if (!isTooAggressive(currentBlock, corner3) && BlockChecks.treeFellerCompatible(corner3) && !toBeFelled.contains(corner3)) {
-                    processTreeFelling(corner3, toBeFelled);
-                }
+                    if (centerIsLog) {
+                        futureCenterBlocks.add(nextBlock);
+                    }
 
-                if (!isTooAggressive(currentBlock, corner4) && BlockChecks.treeFellerCompatible(corner4) && !toBeFelled.contains(corner4)) {
-                    processTreeFelling(corner4, toBeFelled);
+                    if (toBeFelled.size() >= Config.getInstance().getTreeFellerThreshold()) {
+                        treeFellerReachedThreshold = true;
+                        return;
+                    }
                 }
             }
         }
 
-        if (BlockChecks.treeFellerCompatible(yPositive)) {
-            if (!mcMMO.placeStore.isTrue(currentBlock) && !toBeFelled.contains(yPositive)) {
-                processTreeFelling(yPositive, toBeFelled);
+        // Recursive call for each log found
+        for (Block futurCenterBlock : futureCenterBlocks) {
+            if (treeFellerReachedThreshold) {
+                return;
             }
+
+            processTreeFellerAroundBlock(futurCenterBlock, toBeFelled);
         }
     }
 
     /**
-     * Check if Tree Feller is being too aggressive.
+     * Process Tree Feller.
      *
-     * @param currentBlock The current block being felled
-     * @param newBlock The next block to be felled
-     * @return true if Tree Feller is too aggressive, false otherwise
+     * @param event Event to process
+     * @return List of blocks to be removed
      */
-    private static boolean isTooAggressive(Block currentBlock, Block newBlock) {
-        Material currentType = currentBlock.getType();
-        Material newType = newBlock.getType();
+    private static List<Block> processTreeFeller(BlockBreakEvent event) {
+        List<Block> toBeFelled = new ArrayList<Block>();
 
-        if ((currentType.equals(Material.LEAVES) || currentType.equals(Material.AIR) || (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLeafBlock(currentBlock))) && (newType.equals(Material.LEAVES) || newType.equals(Material.AIR) || (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLeafBlock(currentBlock)))) {
-            return true;
+        processTreeFellerAroundBlock(event.getBlock(), toBeFelled);
+
+        if (treeFellerReachedThreshold) {
+            treeFellerReachedThreshold = false;
+
+            event.getPlayer().sendMessage(LocaleLoader.getString("Woodcutting.Skills.TreeFellerThreshold"));
+            return null;
         }
 
-        return false;
+        return toBeFelled;
     }
 
     /**
      * Check for double drops.
      *
      * @param player Player breaking the block
-     * @param block The block being broken
+     * @param block Block being broken
      */
     private static void woodCuttingProcCheck(Player player, Block block) {
-
-        final int MAX_CHANCE = advancedConfig.getMiningDoubleDropChance();
-        final int MAX_BONUS_LEVEL = advancedConfig.getMiningDoubleDropMaxLevel();
-
-        int skillLevel = Users.getProfile(player).getSkillLevel(SkillType.WOODCUTTING);
+        final int MAX_CHANCE = ADVANCED_CONFIG.getMiningDoubleDropChance();
+        final int MAX_BONUS_LEVEL = ADVANCED_CONFIG.getMiningDoubleDropMaxLevel();
         byte type = block.getData();
 
         if ((type & 0x4) == 0x4)
@@ -351,17 +252,27 @@ public class WoodCutting {
         if ((type & 0x8) == 0x8)
             type ^= 0x8;
 
+<<<<<<< Upstream, based on origin/master
         Material mat = Material.getMaterial(block.getTypeId());
 
         int chance = (int) (((double) MAX_CHANCE / (double) MAX_BONUS_LEVEL) * skillLevel);
         if (chance > MAX_CHANCE) chance = MAX_CHANCE;
+=======
+        Material blockMaterial = block.getType();
+        int randomChance = 100;
+        int chance = (int) (((double) MAX_CHANCE / (double) MAX_BONUS_LEVEL) * Users.getProfile(player).getSkillLevel(SkillType.WOODCUTTING));
+        
+        if (chance > MAX_CHANCE) {
+            chance = MAX_CHANCE;
+        }
+>>>>>>> f510cb2 Optimized Tree Feller And cleaned up WoodCutting a little
 
         int activationChance = Misc.calculateActivationChance(Permissions.luckyWoodcutting(player));
 
         if (chance > Misc.getRandom().nextInt(activationChance) && Permissions.woodcuttingDoubleDrops(player)) {
             Config configInstance = Config.getInstance();
-            ItemStack item;
-            Location location;
+            ItemStack item = null;
+            Location location = null;
 
             if (configInstance.getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) {
                 CustomBlock customBlock = ModChecks.getCustomBlock(block);
@@ -380,14 +291,10 @@ public class WoodCutting {
                 }
             }
             else {
-                item = (new MaterialData(mat, type)).toItemStack(1);
-
+                item = (new MaterialData(blockMaterial, type)).toItemStack(1);
                 location = block.getLocation();
 
-                TreeSpecies species = TreeSpecies.getByData(type);
-
-                /* Drop the block */
-                switch (species) {
+                switch (TreeSpecies.getByData(type)) {
                 case GENERIC:
                     if (configInstance.getOakDoubleDropsEnabled()) {
                         Misc.dropItem(location, item);
@@ -422,17 +329,16 @@ public class WoodCutting {
     /**
      * Check XP gain for woodcutting.
      *
-     * @param player The player breaking the block
-     * @param block The block being broken
+     * @param player Player breaking the block
+     * @param block Block being broken
      */
     public static void woodcuttingBlockCheck(Player player, Block block) {
-        PlayerProfile profile = Users.getProfile(player);
-        int xp = 0;
-
         if (mcMMO.placeStore.isTrue(block)) {
             return;
         }
 
+        int xp = 0;
+
         if (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(block)) {
             xp = ModChecks.getCustomBlock(block).getXpGain();
         }
@@ -447,8 +353,8 @@ public class WoodCutting {
 
             TreeSpecies species = TreeSpecies.getByData(type);
 
-            //Apparently species can be null in certain cases (custom server mods?)
-            //https://github.com/mcMMO-Dev/mcMMO/issues/229
+            // Apparently species can be null in certain cases (custom server mods?)
+            // https://github.com/mcMMO-Dev/mcMMO/issues/229
             if (species == null)
                 return;
 
@@ -475,7 +381,7 @@ public class WoodCutting {
         }
 
         WoodCutting.woodCuttingProcCheck(player, block);
-        Skills.xpProcessing(player, profile, SkillType.WOODCUTTING, xp);
+        Skills.xpProcessing(player,  Users.getProfile(player), SkillType.WOODCUTTING, xp);
     }
 
     /**
@@ -485,19 +391,25 @@ public class WoodCutting {
      * @param block Block being broken
      */
     public static void leafBlower(Player player, Block block) {
-        FakePlayerAnimationEvent armswing = new FakePlayerAnimationEvent(player);
-        mcMMO.p.getServer().getPluginManager().callEvent(armswing);
+        mcMMO.p.getServer().getPluginManager().callEvent(new FakePlayerAnimationEvent(player));
 
         if (mcMMO.spoutEnabled) {
             SpoutSounds.playSoundForPlayer(SoundEffect.POP, player, block.getLocation());
         }
     }
 
-    private static int durabilityLossCalulate(ArrayList<Block> toBeFelled, int level) {
-        int durabilityLoss = 0;
-        for (Block x : toBeFelled) {
-            if (Misc.getRandom().nextInt(level + 1) > 0) {}//Don't add durabilityLoss, because Unbreaking enchantment does it's work.
-            else if (x.getType().equals(Material.LOG) || (Config.getInstance().getBlockModsEnabled() && ModChecks.isCustomLogBlock(x))) {
+    /**
+     * Calculate the durability loss from Tree Feller
+     *
+     * @param List<Block> Blocks to be felled
+     * @return Durability loss
+     */
+    private static short calulateDurabilityLossFromTreeFeller(List<Block> toBeFelled) {
+        short durabilityLoss = 0;
+        boolean blockModsEnabled = Config.getInstance().getBlockModsEnabled();
+
+        for (Block block : toBeFelled) {
+            if (block.getType() == Material.LOG || (blockModsEnabled && ModChecks.isCustomLogBlock(block))) {
                 durabilityLoss += Misc.toolDurabilityLoss;
             }
         }

+ 0 - 1
src/main/java/com/gmail/nossr50/util/BlockChecks.java

@@ -283,7 +283,6 @@ public class BlockChecks {
         switch (block.getType()) {
         case LOG:
         case LEAVES:
-        case AIR:
             return true;
 
         default: