From 900d3bb7fd6c347d6ddc5d2ecf235c947e6a2a73 Mon Sep 17 00:00:00 2001 From: nossr50 Date: Wed, 3 Jul 2019 03:16:22 -0700 Subject: [PATCH] Wire up woodcutting behaviour, adding missing dependency injection in a few places --- .../nossr50/datatypes/player/McMMOPlayer.java | 6 +- .../behaviours/WoodcuttingBehaviour.java | 72 ++++++ src/main/java/com/gmail/nossr50/mcMMO.java | 6 +- .../skills/smelting/SmeltingManager.java | 1 - .../skills/woodcutting/Woodcutting.java | 213 ------------------ .../woodcutting/WoodcuttingManager.java | 164 +++++++++++++- 6 files changed, 230 insertions(+), 232 deletions(-) delete mode 100644 src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java index fa5aae660..91cc318f7 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java @@ -271,7 +271,7 @@ public class McMMOPlayer { public void resetAbilityMode() { for (SuperAbilityType ability : SuperAbilityType.values()) { // Correctly disable and handle any special deactivate code - new AbilityDisableTask(this, ability).run(); + new AbilityDisableTask(pluginRef,this, ability).run(); } } @@ -889,7 +889,7 @@ public class McMMOPlayer { } setToolPreparationMode(tool, false); - new AbilityDisableTask(this, ability).runTaskLater(pluginRef, abilityLength * Misc.TICK_CONVERSION_FACTOR); + new AbilityDisableTask(pluginRef, this, ability).runTaskLater(pluginRef, abilityLength * Misc.TICK_CONVERSION_FACTOR); } public void processAbilityActivation(PrimarySkillType skill) { @@ -936,7 +936,7 @@ public class McMMOPlayer { } setToolPreparationMode(tool, true); - new ToolLowerTask(this, tool).runTaskLater(pluginRef, 4 * Misc.TICK_CONVERSION_FACTOR); + new ToolLowerTask(pluginRef,this, tool).runTaskLater(pluginRef, 4 * Misc.TICK_CONVERSION_FACTOR); } } diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/WoodcuttingBehaviour.java b/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/WoodcuttingBehaviour.java index 74f4dc3f6..54e823488 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/WoodcuttingBehaviour.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/behaviours/WoodcuttingBehaviour.java @@ -1,6 +1,8 @@ package com.gmail.nossr50.datatypes.skills.behaviours; import com.gmail.nossr50.mcMMO; +import com.gmail.nossr50.util.Misc; +import org.bukkit.block.BlockState; /** * These behaviour classes are a band-aid fix for a larger problem @@ -13,8 +15,78 @@ public class WoodcuttingBehaviour { private final mcMMO pluginRef; + /** + * The x/y differences to the blocks in a flat cylinder around the center + * block, which is excluded. + */ + private 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 WoodcuttingBehaviour(mcMMO pluginRef) { this.pluginRef = pluginRef; + } + public int[][] getDirections() { + return directions; + } + + /** + * Retrieves the experience reward from a log + * + * @param blockState Log being broken + * @return Amount of experience + */ + public int getExperienceFromLog(BlockState blockState) { + return pluginRef.getDynamicSettingsManager().getExperienceManager().getWoodcuttingXp(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 + */ + public int processTreeFellerXPGains(BlockState blockState, int woodCount) { + int rawXP = pluginRef.getDynamicSettingsManager().getExperienceManager().getWoodcuttingXp(blockState.getType()); + + if(rawXP <= 0) + return 0; + + if(pluginRef.getConfigManager().getConfigExperience().getExperienceWoodcutting().isReduceTreeFellerXP()) { + int reducedXP = 1 + (woodCount * 5); + rawXP = Math.max(1, rawXP - reducedXP); + return rawXP; + } else { + return pluginRef.getDynamicSettingsManager().getExperienceManager().getWoodcuttingXp(blockState.getType()); + } + } + + /** + * Checks for double drops + * + * @param blockState Block being broken + */ + public void checkForDoubleDrop(BlockState blockState) { + /*if (mcMMO.getModManager().isCustomLog(blockState) && mcMMO.getModManager().getBlock(blockState).isDoubleDropEnabled()) { + Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); + } + else {*/ + if (pluginRef.getDynamicSettingsManager().getBonusDropManager().isBonusDropWhitelisted(blockState.getType())) { + Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); + } + //} + } + + + } diff --git a/src/main/java/com/gmail/nossr50/mcMMO.java b/src/main/java/com/gmail/nossr50/mcMMO.java index b8cc64735..8e4e8498e 100644 --- a/src/main/java/com/gmail/nossr50/mcMMO.java +++ b/src/main/java/com/gmail/nossr50/mcMMO.java @@ -575,7 +575,7 @@ public class mcMMO extends JavaPlugin { //TODO: Should do this differently if (configManager.getConfigCoreSkills().isRollEnabled()) { - InteractionManager.registerSubSkill(new Roll()); + InteractionManager.registerSubSkill(new Roll(this)); } } } @@ -594,14 +594,14 @@ public class mcMMO extends JavaPlugin { private void scheduleTasks() { // Periodic save timer (Saves every 10 minutes by default) long saveIntervalTicks = Math.max(1200, (getConfigManager().getConfigDatabase().getConfigSectionDatabaseGeneral().getSaveIntervalMinutes() * (20 * 60))); - new SaveTimerTask().runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); + new SaveTimerTask(this).runTaskTimer(this, saveIntervalTicks, saveIntervalTicks); // Cleanup the backups folder new CleanBackupFilesTask(this).runTaskAsynchronously(this); // Bleed timer (Runs every 0.5 seconds) bleedTimerTask = new BleedTimerTask(this); - pluginRef.getBleedTimerTask().runTaskTimer(this, Misc.TICK_CONVERSION_FACTOR, (Misc.TICK_CONVERSION_FACTOR / 2)); + bleedTimerTask.runTaskTimer(this, Misc.TICK_CONVERSION_FACTOR, (Misc.TICK_CONVERSION_FACTOR / 2)); // Old & Powerless User remover long purgeIntervalTicks = getConfigManager().getConfigDatabase().getConfigSectionCleaning().getPurgeInterval() * 60L * 60L * Misc.TICK_CONVERSION_FACTOR; diff --git a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java index 39450ba7e..8d5c488d2 100644 --- a/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/smelting/SmeltingManager.java @@ -11,7 +11,6 @@ import com.gmail.nossr50.util.Permissions; import com.gmail.nossr50.util.random.RandomChanceUtil; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillActivationType; -import org.bukkit.block.BlockState; import org.bukkit.event.inventory.FurnaceBurnEvent; import org.bukkit.inventory.ItemStack; diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java deleted file mode 100644 index 653e47464..000000000 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/Woodcutting.java +++ /dev/null @@ -1,213 +0,0 @@ -package com.gmail.nossr50.skills.woodcutting; - -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 { - /** - * 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}, - }; - 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) { - return pluginRef.getDynamicSettingsManager().getExperienceManager().getWoodcuttingXp(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 = pluginRef.getDynamicSettingsManager().getExperienceManager().getWoodcuttingXp(blockState.getType()); - - if(rawXP <= 0) - return 0; - - if(pluginRef.getConfigManager().getConfigExperience().getExperienceWoodcutting().isReduceTreeFellerXP()) { - int reducedXP = 1 + (woodCount * 5); - rawXP = Math.max(1, rawXP - reducedXP); - return rawXP; - } else { - return pluginRef.getDynamicSettingsManager().getExperienceManager().getWoodcuttingXp(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 (pluginRef.getDynamicSettingsManager().getBonusDropManager().isBonusDropWhitelisted(blockState.getType())) { - Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops()); - } - //} - } - - /** - * 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 treeFellerBlocks) { - List futureCenterBlocks = new ArrayList<>(); - - // 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 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 += pluginRef.getConfigManager().getConfigSuperAbilities().getSuperAbilityLimits().getToolDurabilityDamage(); - } - } - - SkillUtils.handleDurabilityChange(inHand, durabilityLoss); - return (inHand.getDurability() < (pluginRef.getRepairableManager().isRepairable(type) ? pluginRef.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 futureCenterBlocks, Set treeFellerBlocks) { - if (treeFellerBlocks.contains(blockState) || pluginRef.getPlaceStore().isTrue(blockState)) { - return false; - } - - // Without this check Tree Feller propagates through leaves until the threshold is hit - if (treeFellerBlocks.size() > pluginRef.getConfigManager().getConfigSuperAbilities().getSuperAbilityLimits().getTreeFeller().getTreeFellerLimit()) { - 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; - } - - protected enum ExperienceGainMethod { - DEFAULT, - TREE_FELLER, - } -} diff --git a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java index 56e215c12..bb6539f3d 100644 --- a/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java +++ b/src/main/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManager.java @@ -6,6 +6,7 @@ import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; import com.gmail.nossr50.datatypes.skills.SuperAbilityType; +import com.gmail.nossr50.datatypes.skills.behaviours.WoodcuttingBehaviour; import com.gmail.nossr50.mcMMO; import com.gmail.nossr50.skills.SkillManager; import com.gmail.nossr50.util.BlockUtils; @@ -16,19 +17,28 @@ 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 final WoodcuttingBehaviour woodcuttingBehaviour; + private boolean treeFellerReachedThreshold; + public WoodcuttingManager(mcMMO pluginRef, McMMOPlayer mcMMOPlayer) { super(pluginRef, mcMMOPlayer, PrimarySkillType.WOODCUTTING); + this.treeFellerReachedThreshold = false; + this.woodcuttingBehaviour = pluginRef.getDynamicSettingsManager().getSkillBehaviourManager().getWoodcuttingBehaviour(); } public boolean canUseLeafBlower(ItemStack heldItem) { @@ -42,7 +52,7 @@ public class WoodcuttingManager extends SkillManager { && ItemUtils.isAxe(heldItem); } - protected boolean canGetDoubleDrops() { + public boolean canGetDoubleDrops() { return Permissions.isSubSkillEnabled(getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RankUtils.hasReachedRank(1, getPlayer(), SubSkillType.WOODCUTTING_HARVEST_LUMBER) && RandomChanceUtil.isActivationSuccessful(SkillActivationType.RANDOM_LINEAR_100_SCALE_WITH_CAP, SubSkillType.WOODCUTTING_HARVEST_LUMBER, getPlayer()); @@ -54,7 +64,7 @@ public class WoodcuttingManager extends SkillManager { * @param blockState Block being broken */ public void woodcuttingBlockCheck(BlockState blockState) { - int xp = Woodcutting.getExperienceFromLog(blockState); + int xp = woodcuttingBehaviour.getExperienceFromLog(blockState); switch (blockState.getType()) { case BROWN_MUSHROOM_BLOCK: @@ -63,7 +73,7 @@ public class WoodcuttingManager extends SkillManager { default: if (canGetDoubleDrops()) { - Woodcutting.checkForDoubleDrop(blockState); + woodcuttingBehaviour.checkForDoubleDrop(blockState); } } @@ -79,20 +89,20 @@ public class WoodcuttingManager extends SkillManager { Player player = getPlayer(); Set treeFellerBlocks = new HashSet<>(); - 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; pluginRef.getNotificationManager().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())) { pluginRef.getNotificationManager().sendPlayerInformation(player, NotificationType.SUBSKILL_MESSAGE_FAILED, "Woodcutting.Skills.TreeFeller.Splinter"); double health = player.getHealth(); @@ -105,7 +115,137 @@ public class WoodcuttingManager extends SkillManager { } dropBlocks(treeFellerBlocks); - Woodcutting.treeFellerReachedThreshold = false; // Reset the value after we're done with Tree Feller each time. + 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 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). + */ + public void processTree(BlockState blockState, Set treeFellerBlocks) { + List futureCenterBlocks = new ArrayList<>(); + + // 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 : woodcuttingBehaviour.getDirections()) { + 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 : woodcuttingBehaviour.getDirections()) { + 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 + */ + public boolean handleDurabilityLoss(Set 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 += pluginRef.getConfigManager().getConfigSuperAbilities().getSuperAbilityLimits().getToolDurabilityDamage(); + } + } + + SkillUtils.handleDurabilityChange(inHand, durabilityLoss); + return (inHand.getDurability() < (pluginRef.getRepairableManager().isRepairable(type) ? pluginRef.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 handleBlock(BlockState blockState, List futureCenterBlocks, Set treeFellerBlocks) { + if (treeFellerBlocks.contains(blockState) || pluginRef.getPlaceStore().isTrue(blockState)) { + return false; + } + + // Without this check Tree Feller propagates through leaves until the threshold is hit + if (treeFellerBlocks.size() > pluginRef.getConfigManager().getConfigSuperAbilities().getSuperAbilityLimits().getTreeFeller().getTreeFellerLimit()) { + 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; + } + + public enum ExperienceGainMethod { + DEFAULT, + TREE_FELLER, } /** @@ -129,14 +269,14 @@ 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 += woodcuttingBehaviour.processTreeFellerXPGains(blockState, processedLogCount); Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops()); } else { if (BlockUtils.isLog(blockState)) { if (canGetDoubleDrops()) { - Woodcutting.checkForDoubleDrop(blockState); + woodcuttingBehaviour.checkForDoubleDrop(blockState); } - xp += Woodcutting.processTreeFellerXPGains(blockState, processedLogCount); + xp += woodcuttingBehaviour.processTreeFellerXPGains(blockState, processedLogCount); Misc.dropItems(Misc.getBlockCenter(blockState), block.getDrops()); } if (BlockUtils.isLeaves(blockState)) {