From 9329cc1fb6815716d90f94aa6dd2b8b3c527bf6e Mon Sep 17 00:00:00 2001 From: Esophose Date: Thu, 28 Mar 2019 11:38:37 -0600 Subject: [PATCH] Tree detection --- .../ultimatetimber/UltimateTimber.java | 20 +- .../adapter/VersionAdapter.java | 20 +- .../adapter/current/CurrentAdapter.java | 10 +- .../adapter/legacy/LegacyAdapter.java | 10 +- .../ultimatetimber/events/TreeEvent.java | 2 +- .../ultimatetimber/manager/HookManager.java | 3 +- .../manager/MessageManager.java | 33 --- .../manager/TreeDefinitionManager.java | 53 ++++- .../manager/TreeDetectionManager.java | 201 +++++++++++++++++- .../ultimatetimber/tree/DetectedTree.java | 33 +++ .../ultimatetimber/tree/FallingTreeBlock.java | 3 +- .../ultimatetimber/tree/TreeBlock.java | 4 +- .../ultimatetimber/tree/TreeDefinition.java | 13 +- src/main/resources/config-current.yml | 8 + src/main/resources/config-legacy.yml | 8 + 15 files changed, 355 insertions(+), 66 deletions(-) delete mode 100644 src/main/java/com/songoda/ultimatetimber/manager/MessageManager.java create mode 100644 src/main/java/com/songoda/ultimatetimber/tree/DetectedTree.java diff --git a/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java b/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java index 15f00f7..1ca2696 100644 --- a/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java +++ b/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java @@ -29,7 +29,6 @@ public class UltimateTimber extends JavaPlugin { private CommandManager commandManager; private ConfigurationManager configurationManager; private HookManager hookManager; - private MessageManager messageManager; private TreeAnimationManager treeAnimationManager; private TreeDefinitionManager treeDefinitionManager; private TreeDetectionManager treeDetectionManager; @@ -50,15 +49,15 @@ public class UltimateTimber extends JavaPlugin { this.managers = new HashSet<>(); this.choppingManager = this.registerManager(ChoppingManager.class); this.commandManager = this.registerManager(CommandManager.class); - this.configurationManager = this.registerManager(ConfigurationManager.class); + this.configurationManager = new ConfigurationManager(this); this.hookManager = this.registerManager(HookManager.class); - this.messageManager = this.registerManager(MessageManager.class); this.treeAnimationManager = this.registerManager(TreeAnimationManager.class); this.treeDefinitionManager = this.registerManager(TreeDefinitionManager.class); this.treeDetectionManager = this.registerManager(TreeDetectionManager.class); this.treeFallManager = this.registerManager(TreeFallManager.class); this.setupVersionAdapter(); + this.reload(); new Metrics(this); @@ -80,6 +79,7 @@ public class UltimateTimber extends JavaPlugin { * Reloads the plugin's settings */ public void reload() { + this.configurationManager.reload(); this.managers.forEach(Manager::reload); } @@ -87,6 +87,7 @@ public class UltimateTimber extends JavaPlugin { * Disables most of the plugin */ public void disable() { + this.configurationManager.disable(); this.managers.forEach(Manager::disable); } @@ -112,9 +113,9 @@ public class UltimateTimber extends JavaPlugin { try { T newManager = managerClass.getConstructor(UltimateTimber.class).newInstance(this); this.managers.add(newManager); - newManager.reload(); return newManager; - } catch (Exception ignored) { + } catch (Exception ex) { + ex.printStackTrace(); return null; } } @@ -164,15 +165,6 @@ public class UltimateTimber extends JavaPlugin { return hookManager; } - /** - * Gets the configuration manager - * - * @return The ConfigurationManager instance - */ - public MessageManager getMessageManager() { - return messageManager; - } - /** * Gets the tree animation manager * diff --git a/src/main/java/com/songoda/ultimatetimber/adapter/VersionAdapter.java b/src/main/java/com/songoda/ultimatetimber/adapter/VersionAdapter.java index 4d20456..1bc63e4 100644 --- a/src/main/java/com/songoda/ultimatetimber/adapter/VersionAdapter.java +++ b/src/main/java/com/songoda/ultimatetimber/adapter/VersionAdapter.java @@ -9,10 +9,16 @@ import org.bukkit.block.BlockState; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import java.util.Collection; import java.util.Set; public interface VersionAdapter { + /** + * Gets the version adapter type + * + * @return The VersionAdapterType + */ VersionAdapterType getVersionAdapterType(); /** @@ -34,11 +40,19 @@ public interface VersionAdapter { /** * Get the items that a tree block should drop when it breaks * - * @param treeBlock The tree block broken - * @param treeDefinition The tree definition to get the drops for + * @param treeBlock The tree block * @return A Set of ItemStacks that should be dropped */ - Set getTreeBlockDrops(TreeBlock treeBlock, TreeDefinition treeDefinition); + Collection getBlockDrops(TreeBlock treeBlock); + + /** + * Checks if two block states are similar + * + * @param blockState1 The first BlockState + * @param blockState2 The second BlockState + * @return True if the BlockStates are similar, otherwise false + */ + boolean areBlockStatesSimilar(BlockState blockState1, BlockState blockState2); /** * Applies damage to a tool diff --git a/src/main/java/com/songoda/ultimatetimber/adapter/current/CurrentAdapter.java b/src/main/java/com/songoda/ultimatetimber/adapter/current/CurrentAdapter.java index bdda521..8407bc4 100644 --- a/src/main/java/com/songoda/ultimatetimber/adapter/current/CurrentAdapter.java +++ b/src/main/java/com/songoda/ultimatetimber/adapter/current/CurrentAdapter.java @@ -5,13 +5,12 @@ import com.songoda.ultimatetimber.adapter.VersionAdapterType; import com.songoda.ultimatetimber.tree.FallingTreeBlock; import com.songoda.ultimatetimber.tree.TreeBlock; import com.songoda.ultimatetimber.tree.TreeBlockSet; -import com.songoda.ultimatetimber.tree.TreeDefinition; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import java.util.Set; +import java.util.Collection; public class CurrentAdapter implements VersionAdapter { @@ -31,10 +30,15 @@ public class CurrentAdapter implements VersionAdapter { } @Override - public Set getTreeBlockDrops(TreeBlock treeBlock, TreeDefinition treeDefinition) { + public Collection getBlockDrops(TreeBlock treeBlock) { return null; } + @Override + public boolean areBlockStatesSimilar(BlockState blockState1, BlockState blockState2) { + return false; + } + @Override public void applyToolDurability(TreeBlockSet treeBlocks, ItemStack tool) { diff --git a/src/main/java/com/songoda/ultimatetimber/adapter/legacy/LegacyAdapter.java b/src/main/java/com/songoda/ultimatetimber/adapter/legacy/LegacyAdapter.java index ca24403..d438bd8 100644 --- a/src/main/java/com/songoda/ultimatetimber/adapter/legacy/LegacyAdapter.java +++ b/src/main/java/com/songoda/ultimatetimber/adapter/legacy/LegacyAdapter.java @@ -5,13 +5,12 @@ import com.songoda.ultimatetimber.adapter.VersionAdapterType; import com.songoda.ultimatetimber.tree.FallingTreeBlock; import com.songoda.ultimatetimber.tree.TreeBlock; import com.songoda.ultimatetimber.tree.TreeBlockSet; -import com.songoda.ultimatetimber.tree.TreeDefinition; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import java.util.Set; +import java.util.Collection; public class LegacyAdapter implements VersionAdapter { @@ -31,10 +30,15 @@ public class LegacyAdapter implements VersionAdapter { } @Override - public Set getTreeBlockDrops(TreeBlock treeBlock, TreeDefinition treeDefinition) { + public Collection getBlockDrops(TreeBlock treeBlock) { return null; } + @Override + public boolean areBlockStatesSimilar(BlockState blockState1, BlockState blockState2) { + return false; + } + @Override public void applyToolDurability(TreeBlockSet treeBlocks, ItemStack tool) { diff --git a/src/main/java/com/songoda/ultimatetimber/events/TreeEvent.java b/src/main/java/com/songoda/ultimatetimber/events/TreeEvent.java index 295ebfe..09a47e8 100644 --- a/src/main/java/com/songoda/ultimatetimber/events/TreeEvent.java +++ b/src/main/java/com/songoda/ultimatetimber/events/TreeEvent.java @@ -20,7 +20,7 @@ public abstract class TreeEvent extends PlayerEvent { /** * Get the tree blocks * - * @return tree checker for the tree + * @return The blocks that are part of the tree */ public TreeBlockSet getTreeBlocks() { return this.treeBlocks; diff --git a/src/main/java/com/songoda/ultimatetimber/manager/HookManager.java b/src/main/java/com/songoda/ultimatetimber/manager/HookManager.java index 9deac3f..f4617be 100644 --- a/src/main/java/com/songoda/ultimatetimber/manager/HookManager.java +++ b/src/main/java/com/songoda/ultimatetimber/manager/HookManager.java @@ -6,6 +6,7 @@ import com.songoda.ultimatetimber.hooks.McMMOHook; import com.songoda.ultimatetimber.hooks.TimberHook; import com.songoda.ultimatetimber.tree.TreeBlockSet; import org.bukkit.Bukkit; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import java.util.HashSet; @@ -56,7 +57,7 @@ public class HookManager extends Manager { * @param player The player to apply the hook for * @param treeBlocks The blocks of the tree that were broken */ - public void applyHooks(Player player, TreeBlockSet treeBlocks) { + public void applyHooks(Player player, TreeBlockSet treeBlocks) { Set invalidHooks = new HashSet<>(); for (TimberHook hook : this.hooks) { try { diff --git a/src/main/java/com/songoda/ultimatetimber/manager/MessageManager.java b/src/main/java/com/songoda/ultimatetimber/manager/MessageManager.java deleted file mode 100644 index 4518602..0000000 --- a/src/main/java/com/songoda/ultimatetimber/manager/MessageManager.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.songoda.ultimatetimber.manager; - -import com.songoda.ultimatetimber.UltimateTimber; - -public class MessageManager extends Manager { - - public enum MessageType { - TOGGLE_ON, - TOGGLE_OFF, - RELOAD - } - - private final String prefix = "&8[&6UltimateTimber&8]"; - - public MessageManager(UltimateTimber ultimateTimber) { - super(ultimateTimber); - } - - @Override - public void reload() { - - } - - @Override - public void disable() { - - } - - public String getPrefix() { - return this.prefix; - } - -} diff --git a/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java b/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java index 1a6a3a6..c0174b1 100644 --- a/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java +++ b/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java @@ -8,7 +8,6 @@ import com.songoda.ultimatetimber.tree.TreeDefinition; import com.songoda.ultimatetimber.tree.TreeLoot; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -56,6 +55,7 @@ public class TreeDefinitionManager extends Manager { Set leafBlockStates = new HashSet<>(); BlockState saplingBlockState; int maxLeafDistanceFromLog; + boolean detectLeavesDiagonally; boolean dropOriginalLog; boolean dropOriginalLeaf; Set logLoot = new HashSet<>(); @@ -70,6 +70,7 @@ public class TreeDefinitionManager extends Manager { saplingBlockState = versionAdapter.parseBlockStateFromString(tree.getString("sapling")); maxLeafDistanceFromLog = tree.getInt("max-leaf-distance-from-log"); + detectLeavesDiagonally = tree.getBoolean("search-for-leaves-diagonally"); dropOriginalLog = tree.getBoolean("drop-original-log"); dropOriginalLeaf = tree.getBoolean("drop-original-leaf"); @@ -84,7 +85,7 @@ public class TreeDefinitionManager extends Manager { for (String itemStackString : tree.getStringList("required-tools")) requiredTools.add(versionAdapter.parseItemStackFromString(itemStackString)); - this.treeDefinitions.add(new TreeDefinition(key, logBlockStates, leafBlockStates, saplingBlockState, maxLeafDistanceFromLog, dropOriginalLog, dropOriginalLeaf, logLoot, leafLoot, requiredTools)); + this.treeDefinitions.add(new TreeDefinition(key, logBlockStates, leafBlockStates, saplingBlockState, maxLeafDistanceFromLog, detectLeavesDiagonally, dropOriginalLog, dropOriginalLeaf, logLoot, leafLoot, requiredTools)); } // Load global log drops @@ -107,6 +108,54 @@ public class TreeDefinitionManager extends Manager { this.treeDefinitions.clear(); } + /** + * Gets a Set of possible TreeDefinitions that match the given BlockState + * + * @param blockState The BlockState to check + * @return A Set of TreeDefinitions for the given BlockState + */ + public Set getTreeDefinitionsForLog(BlockState blockState) { + return this.narrowTreeDefinition(this.treeDefinitions, blockState, TreeBlockType.LOG); + } + + /** + * Narrows a Set of TreeDefinitions down to ones matching the given BlockState and TreeBlockType + * + * @param possibleTreeDefinitions The possible TreeDefinitions + * @param blockState The BlockState to narrow to + * @param treeBlockType The TreeBlockType of the given BlockState + * @return A Set of TreeDefinitions narrowed down + */ + public Set narrowTreeDefinition(Set possibleTreeDefinitions, BlockState blockState, TreeBlockType treeBlockType) { + VersionAdapter versionAdapter = this.ultimateTimber.getVersionAdapter(); + + Set matchingTreeDefinitions = new HashSet<>(); + switch (treeBlockType) { + case LOG: + for (TreeDefinition treeDefinition : this.treeDefinitions) { + for (BlockState logBlockState : treeDefinition.getLogBlockStates()) { + if (versionAdapter.areBlockStatesSimilar(logBlockState, blockState)) { + matchingTreeDefinitions.add(treeDefinition); + break; + } + } + } + break; + case LEAF: + for (TreeDefinition treeDefinition : this.treeDefinitions) { + for (BlockState leafBlockState : treeDefinition.getLeafBlockStates()) { + if (versionAdapter.areBlockStatesSimilar(leafBlockState, blockState)) { + matchingTreeDefinitions.add(treeDefinition); + break; + } + } + } + break; + } + + return matchingTreeDefinitions; + } + /** * Checks if a given tool is valid for a given tree definition, also takes into account global tools * diff --git a/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java b/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java index 867f1d1..1aaed6a 100644 --- a/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java +++ b/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java @@ -1,18 +1,65 @@ package com.songoda.ultimatetimber.manager; import com.songoda.ultimatetimber.UltimateTimber; +import com.songoda.ultimatetimber.adapter.VersionAdapter; +import com.songoda.ultimatetimber.tree.*; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.util.Vector; + +import java.util.Comparator; +import java.util.HashSet; +import java.util.Set; public class TreeDetectionManager extends Manager { - private UltimateTimber ultimateTimber; + private final Set VALID_TRUNK_OFFSETS, VALID_BRANCH_OFFSETS, VALID_LEAF_OFFSETS; + + private TreeDefinitionManager treeDefinitionManager; + private int maxBranchBlocksAllowed; + private int numLeavesRequiredForTree; + private boolean allowMixedTreeTypes; + private boolean onlyBreakLogsUpwards; + private boolean destroyBaseLog; + private boolean entireTreeBase; public TreeDetectionManager(UltimateTimber ultimateTimber) { super(ultimateTimber); + + VALID_BRANCH_OFFSETS = new HashSet<>(); + VALID_TRUNK_OFFSETS = new HashSet<>(); + VALID_LEAF_OFFSETS = new HashSet<>(); + + // 3x2x3 centered around log, excluding -y axis + for (int x = -1; x <= 1; x++) + for (int y = 0; y <= 1; y++) + for (int z = -1; z <= 1; z++) + VALID_BRANCH_OFFSETS.add(new Vector(x, y, z)); + + // 3x3x3 centered around log + for (int x = -1; x <= 1; x++) + for (int y = -1; y <= 1; y++) + for (int z = -1; z <= 1; z++) + VALID_TRUNK_OFFSETS.add(new Vector(x, y, z)); + + // Adjacent blocks to log + for (int i = -1; i <= 1; i += 2) { + VALID_LEAF_OFFSETS.add(new Vector(i, 0, 0)); + VALID_LEAF_OFFSETS.add(new Vector(0, i, 0)); + VALID_LEAF_OFFSETS.add(new Vector(0, 0, i)); + } } @Override public void reload() { - + this.treeDefinitionManager = this.ultimateTimber.getTreeDefinitionManager(); + this.maxBranchBlocksAllowed = ConfigurationManager.Setting.MAX_LOGS_PER_CHOP.getInt(); + this.numLeavesRequiredForTree = ConfigurationManager.Setting.LEAVES_REQUIRED_FOR_TREE.getInt(); + this.allowMixedTreeTypes = ConfigurationManager.Setting.MIX_ALL_TREE_TYPES.getBoolean(); + this.onlyBreakLogsUpwards = ConfigurationManager.Setting.ONLY_DETECT_LOGS_UPWARDS.getBoolean(); + this.destroyBaseLog = ConfigurationManager.Setting.DESTROY_INITIATED_BLOCK.getBoolean(); + this.entireTreeBase = ConfigurationManager.Setting.BREAK_ENTIRE_TREE_BASE.getBoolean(); } @Override @@ -20,4 +67,154 @@ public class TreeDetectionManager extends Manager { } + /** + * Detects a tree given an initial starting block + * + * @param initialBlock The starting Block of the detection + * @return A DetectedTree if one was found, otherwise null + */ + public DetectedTree detectTree(Block initialBlock) { + TreeBlock initialTreeBlock = new TreeBlock(initialBlock, TreeBlockType.LOG); + TreeBlockSet detectedTreeBlocks = new TreeBlockSet<>(initialTreeBlock); + Set possibleTreeDefinitions = treeDefinitionManager.getTreeDefinitionsForLog(initialBlock.getState()); + + // Detect tree trunk + Set trunkBlocks = new HashSet<>(); + trunkBlocks.add(initialBlock); + Block targetBlock = initialBlock; + while (this.isValidLogType(possibleTreeDefinitions, (targetBlock = targetBlock.getRelative(BlockFace.UP)))) { + TreeBlock treeBlock = new TreeBlock(targetBlock, TreeBlockType.LOG); + detectedTreeBlocks.add(treeBlock); + trunkBlocks.add(initialBlock); + possibleTreeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(possibleTreeDefinitions, targetBlock.getState(), TreeBlockType.LOG)); + } + + // Tree must be at least 2 blocks tall + if (detectedTreeBlocks.size() < 2) + return null; + + // Detect branches off the main trunk + for (Block trunkBlock : trunkBlocks) + this.recursiveBranchSearch(possibleTreeDefinitions, detectedTreeBlocks, trunkBlock, initialBlock.getY()); + + // Detect leaves off the trunk/branches + Set> branchBlocks = new HashSet<>(detectedTreeBlocks.getLogBlocks()); + for (ITreeBlock branchBlock : branchBlocks) + this.recursiveLeafSearch(possibleTreeDefinitions, detectedTreeBlocks, branchBlock.getBlock(), 1); + + // Trees need at least a certain number of leaves + if (detectedTreeBlocks.getLeafBlocks().size() < this.numLeavesRequiredForTree) + return null; + + // TODO: Soil detection + + // Delete the starting block if applicable + if (this.destroyBaseLog) + detectedTreeBlocks.remove(initialTreeBlock); + + // Use the first tree definition in the set + return new DetectedTree(possibleTreeDefinitions.iterator().next(), detectedTreeBlocks); + } + + /** + * Recursively searches for branches off a given block + * + * @param treeDefinitions The possible tree definitions + * @param treeBlocks The detected tree blocks + * @param block The next block to check for a branch + * @param startingBlockY The Y coordinate of the initial block + */ + private void recursiveBranchSearch(Set treeDefinitions, TreeBlockSet treeBlocks, Block block, int startingBlockY) { + if (treeBlocks.size() > this.maxBranchBlocksAllowed) + return; + + for (Vector offset : this.onlyBreakLogsUpwards ? VALID_BRANCH_OFFSETS : VALID_TRUNK_OFFSETS) { + Block targetBlock = block.getRelative(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ()); + TreeBlock treeBlock = new TreeBlock(targetBlock, TreeBlockType.LOG); + if (this.isValidLogType(treeDefinitions, targetBlock) && !treeBlocks.contains(treeBlock)) { + treeBlocks.add(treeBlock); + treeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(treeDefinitions, block.getState(), TreeBlockType.LOG)); + if (!this.onlyBreakLogsUpwards || targetBlock.getLocation().getBlockY() > startingBlockY) + this.recursiveBranchSearch(treeDefinitions, treeBlocks, targetBlock, startingBlockY); + } + } + } + + /** + * Recursively searches for leaves that are next to this tree + * + * @param treeDefinitions The possible tree definitions + * @param treeBlocks The detected tree blocks + * @param block The next block to check for a leaf + * @param distanceFromLog The distance this leaf is from a log + */ + private void recursiveLeafSearch(Set treeDefinitions, TreeBlockSet treeBlocks, Block block, int distanceFromLog) { + int maxDistanceFromLog = treeDefinitions.stream().max(Comparator.comparingInt(TreeDefinition::getMaxLeafDistanceFromLog)).get().getMaxLeafDistanceFromLog(); + boolean detectLeavesDiagonally = treeDefinitions.stream().anyMatch(TreeDefinition::shouldDetectLeavesDiagonally); + + if (distanceFromLog > maxDistanceFromLog) + return; + + for (Vector offset : !detectLeavesDiagonally ? VALID_LEAF_OFFSETS : VALID_TRUNK_OFFSETS) { + Block targetBlock = block.getRelative(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ()); + TreeBlock treeBlock = new TreeBlock(targetBlock, TreeBlockType.LEAF); + if (this.isValidLeafType(treeDefinitions, targetBlock)) { + if (!treeBlocks.contains(treeBlock) && !this.doesLeafBorderInvalidLog(treeDefinitions, treeBlocks, targetBlock)) { + treeBlocks.add(treeBlock); + treeDefinitions.retainAll(this.treeDefinitionManager.narrowTreeDefinition(treeDefinitions, block.getState(), TreeBlockType.LEAF)); + } + this.recursiveLeafSearch(treeDefinitions, treeBlocks, targetBlock, distanceFromLog + 1); + } + } + } + + /** + * Checks if a leaf is bordering a log that isn't part of this tree + * + * @param treeDefinitions The possible tree definitions + * @param treeBlocks The detected tree blocks + * @param block The block to check + * @return True if the leaf borders an invalid log, otherwise false + */ + private boolean doesLeafBorderInvalidLog(Set treeDefinitions, TreeBlockSet treeBlocks, Block block) { + for (Vector offset : VALID_TRUNK_OFFSETS) { + Block targetBlock = block.getRelative(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ()); + if (this.isValidLogType(treeDefinitions, targetBlock) && !treeBlocks.contains(new TreeBlock(targetBlock, TreeBlockType.LOG))) + return true; + } + return false; + } + + /** + * Checks if a given block is valid for the given TreeDefinitions + * + * @param treeDefinitions The Set of TreeDefinitions to compare against + * @param block The Block to check + * @return True if the block is a valid log type, otherwise false + */ + private boolean isValidLogType(Set treeDefinitions, Block block) { + VersionAdapter versionAdapter = this.ultimateTimber.getVersionAdapter(); + for (TreeDefinition treeDefinition : treeDefinitions) + for (BlockState logBlockState : treeDefinition.getLogBlockStates()) + if (versionAdapter.areBlockStatesSimilar(logBlockState, block.getState())) + return true; + return false; + } + + /** + * Checks if a given block is valid for the given TreeDefinitions + * + * @param treeDefinitions The Set of TreeDefinitions to compare against + * @param block The Block to check + * @return True if the block is a valid log type, otherwise false + */ + private boolean isValidLeafType(Set treeDefinitions, Block block) { + VersionAdapter versionAdapter = this.ultimateTimber.getVersionAdapter(); + for (TreeDefinition treeDefinition : treeDefinitions) + for (BlockState leafBlockState : treeDefinition.getLeafBlockStates()) + if (versionAdapter.areBlockStatesSimilar(leafBlockState, block.getState())) + return true; + return false; + } + } diff --git a/src/main/java/com/songoda/ultimatetimber/tree/DetectedTree.java b/src/main/java/com/songoda/ultimatetimber/tree/DetectedTree.java new file mode 100644 index 0000000..fd7f6ce --- /dev/null +++ b/src/main/java/com/songoda/ultimatetimber/tree/DetectedTree.java @@ -0,0 +1,33 @@ +package com.songoda.ultimatetimber.tree; + +import org.bukkit.block.Block; + +public class DetectedTree { + + private TreeDefinition treeDefinition; + private TreeBlockSet detectedTreeBlocks; + + public DetectedTree(TreeDefinition treeDefinition, TreeBlockSet detectedTreeBlocks) { + this.treeDefinition = treeDefinition; + this.detectedTreeBlocks = detectedTreeBlocks; + } + + /** + * Gets the TreeDefinition of this detected tree + * + * @return The TreeDefinition of this detected tree + */ + public TreeDefinition getTreeDefinition() { + return this.treeDefinition; + } + + /** + * Gets the blocks that were detected as part of this tree + * + * @return A TreeBlockSet of detected Blocks + */ + public TreeBlockSet getDetectedTreeBlocks() { + return this.detectedTreeBlocks; + } + +} diff --git a/src/main/java/com/songoda/ultimatetimber/tree/FallingTreeBlock.java b/src/main/java/com/songoda/ultimatetimber/tree/FallingTreeBlock.java index 2d3d983..c8d9c58 100644 --- a/src/main/java/com/songoda/ultimatetimber/tree/FallingTreeBlock.java +++ b/src/main/java/com/songoda/ultimatetimber/tree/FallingTreeBlock.java @@ -1,5 +1,6 @@ package com.songoda.ultimatetimber.tree; +import com.songoda.ultimatetimber.UltimateTimber; import org.bukkit.Location; import org.bukkit.entity.FallingBlock; import org.bukkit.inventory.ItemStack; @@ -15,7 +16,7 @@ public class FallingTreeBlock implements ITreeBlock { public FallingTreeBlock(TreeBlock originalTreeBlock, FallingBlock fallingBlock, TreeBlockType treeBlockType) { this.fallingBlock = fallingBlock; this.treeBlockType = treeBlockType; - this.drops = originalTreeBlock.getDrops(); + this.drops = UltimateTimber.getInstance().getVersionAdapter().getBlockDrops(originalTreeBlock); } @Override diff --git a/src/main/java/com/songoda/ultimatetimber/tree/TreeBlock.java b/src/main/java/com/songoda/ultimatetimber/tree/TreeBlock.java index fc4be40..e7ff79e 100644 --- a/src/main/java/com/songoda/ultimatetimber/tree/TreeBlock.java +++ b/src/main/java/com/songoda/ultimatetimber/tree/TreeBlock.java @@ -1,11 +1,11 @@ package com.songoda.ultimatetimber.tree; +import com.songoda.ultimatetimber.UltimateTimber; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.inventory.ItemStack; import java.util.Collection; -import java.util.Set; public class TreeBlock implements ITreeBlock { @@ -29,7 +29,7 @@ public class TreeBlock implements ITreeBlock { @Override public Collection getDrops() { - return this.block.getDrops(); + return UltimateTimber.getInstance().getVersionAdapter().getBlockDrops(this); } @Override diff --git a/src/main/java/com/songoda/ultimatetimber/tree/TreeDefinition.java b/src/main/java/com/songoda/ultimatetimber/tree/TreeDefinition.java index 9b2c42d..5bb6358 100644 --- a/src/main/java/com/songoda/ultimatetimber/tree/TreeDefinition.java +++ b/src/main/java/com/songoda/ultimatetimber/tree/TreeDefinition.java @@ -12,18 +12,20 @@ public class TreeDefinition { private final Set logBlockStates, leafBlockStates; private final BlockState saplingBlockState; private final int maxLeafDistanceFromLog; + private final boolean detectLeavesDiagonally; private final boolean dropOriginalLog, dropOriginalLeaf; private final Set logLoot, leafLoot; private final Set requiredTools; public TreeDefinition(String key, Set logBlocks, Set leafBlocks, BlockState saplingBlockState, - int maxLeafDistanceFromLog, boolean dropOriginalLog, boolean dropOriginalLeaf, + int maxLeafDistanceFromLog, boolean detectLeavesDiagonally, boolean dropOriginalLog, boolean dropOriginalLeaf, Set logLoot, Set leafLoot, Set requiredTools) { this.key = key; this.logBlockStates = logBlocks; this.leafBlockStates = leafBlocks; this.saplingBlockState = saplingBlockState; this.maxLeafDistanceFromLog = maxLeafDistanceFromLog; + this.detectLeavesDiagonally = detectLeavesDiagonally; this.dropOriginalLog = dropOriginalLog; this.dropOriginalLeaf = dropOriginalLeaf; this.logLoot = logLoot; @@ -76,6 +78,15 @@ public class TreeDefinition { return this.maxLeafDistanceFromLog; } + /** + * Gets if tree detection should check for leaves diagonally + * + * @return True if leaves should be searched for diagonally, otherwise false + */ + public boolean shouldDetectLeavesDiagonally() { + return this.detectLeavesDiagonally; + } + /** * Gets if the logs of this tree should drop their original block * diff --git a/src/main/resources/config-current.yml b/src/main/resources/config-current.yml index 1e34551..1991595 100644 --- a/src/main/resources/config-current.yml +++ b/src/main/resources/config-current.yml @@ -125,6 +125,7 @@ trees: - OAK_LEAVES sapling: OAK_SAPLING max-leaf-distance-from-log: 6 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -146,6 +147,7 @@ trees: - SPRUCE_LEAVES sapling: SPRUCE_SAPLING max-leaf-distance-from-log: 6 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -164,6 +166,7 @@ trees: - SPRUCE_BIRCH sapling: BIRCH_SAPLING max-leaf-distance-from-log: 4 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -182,6 +185,7 @@ trees: - SPRUCE_LEAVES sapling: SPRUCE_SAPLING max-leaf-distance-from-log: 5 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -200,6 +204,7 @@ trees: - ACACIA_LEAVES sapling: ACACIA_SAPLING max-leaf-distance-from-log: 5 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -218,6 +223,7 @@ trees: - DARK_OAK_LEAVES sapling: DARK_OAK_SAPLING max-leaf-distance-from-log: 5 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -236,6 +242,7 @@ trees: - BROWN_MUSHROOM_BLOCK sapling: BROWN_MUSHROOM max-leaf-distance-from-log: 4 + search-for-leaves-diagonally: false drop-original-log: false drop-original-leaf: false log-loot: [] @@ -251,6 +258,7 @@ trees: - RED_MUSHROOM_BLOCK sapling: RED_MUSHROOM max-leaf-distance-from-log: 4 + search-for-leaves-diagonally: true drop-original-log: false drop-original-leaf: false log-loot: [] diff --git a/src/main/resources/config-legacy.yml b/src/main/resources/config-legacy.yml index 00e1fea..7d43b49 100644 --- a/src/main/resources/config-legacy.yml +++ b/src/main/resources/config-legacy.yml @@ -128,6 +128,7 @@ trees: - LEAVES:12 sapling: SAPLING:0 max-leaf-distance-from-log: 6 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -152,6 +153,7 @@ trees: - LEAVES:13 sapling: SAPLING:1 max-leaf-distance-from-log: 6 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -173,6 +175,7 @@ trees: - LEAVES:14 sapling: SAPLING:2 max-leaf-distance-from-log: 4 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -194,6 +197,7 @@ trees: - LEAVES:15 sapling: SAPLING:3 max-leaf-distance-from-log: 5 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -215,6 +219,7 @@ trees: - LEAVES_2:12 sapling: SAPLING:4 max-leaf-distance-from-log: 5 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -236,6 +241,7 @@ trees: - LEAVES:13 sapling: SAPLING:5 max-leaf-distance-from-log: 5 + search-for-leaves-diagonally: false drop-original-log: true drop-original-leaf: false log-loot: [] @@ -265,6 +271,7 @@ trees: - HUGE_MUSHROOM_1:14 sapling: BROWN_MUSHROOM max-leaf-distance-from-log: 4 + search-for-leaves-diagonally: false drop-original-log: false drop-original-leaf: false log-loot: [] @@ -291,6 +298,7 @@ trees: - HUGE_MUSHROOM_2:14 sapling: RED_MUSHROOM max-leaf-distance-from-log: 4 + search-for-leaves-diagonally: true drop-original-log: false drop-original-leaf: false log-loot: []