From 4b35f0ee4e67493296b462eca04150f3eec27248 Mon Sep 17 00:00:00 2001 From: Esophose Date: Sun, 28 Apr 2019 18:58:38 -0600 Subject: [PATCH] Hook tree loot double drops fix, placed block detection --- .../ultimatetimber/UltimateTimber.java | 12 ++ .../animation/TreeAnimationDisintegrate.java | 7 + .../manager/ConfigurationManager.java | 5 +- .../manager/PlacedBlockManager.java | 124 ++++++++++++++++++ .../manager/TreeDefinitionManager.java | 20 ++- .../manager/TreeDetectionManager.java | 8 ++ .../manager/TreeFallManager.java | 4 +- .../src/main/resources/config-current.yml | 17 ++- .../src/main/resources/config-legacy.yml | 17 ++- 9 files changed, 193 insertions(+), 21 deletions(-) create mode 100644 UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/PlacedBlockManager.java diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java index 0d17c92..2358f64 100644 --- a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/UltimateTimber.java @@ -8,6 +8,7 @@ import com.songoda.ultimatetimber.manager.CommandManager; import com.songoda.ultimatetimber.manager.ConfigurationManager; import com.songoda.ultimatetimber.manager.HookManager; import com.songoda.ultimatetimber.manager.Manager; +import com.songoda.ultimatetimber.manager.PlacedBlockManager; import com.songoda.ultimatetimber.manager.SaplingManager; import com.songoda.ultimatetimber.manager.TreeAnimationManager; import com.songoda.ultimatetimber.manager.TreeDefinitionManager; @@ -40,6 +41,7 @@ public class UltimateTimber extends JavaPlugin { private CommandManager commandManager; private ConfigurationManager configurationManager; private HookManager hookManager; + private PlacedBlockManager placedBlockManager; private SaplingManager saplingManager; private TreeAnimationManager treeAnimationManager; private TreeDefinitionManager treeDefinitionManager; @@ -63,6 +65,7 @@ public class UltimateTimber extends JavaPlugin { this.commandManager = this.registerManager(CommandManager.class); this.configurationManager = new ConfigurationManager(this); this.hookManager = this.registerManager(HookManager.class); + this.placedBlockManager = this.registerManager(PlacedBlockManager.class); this.saplingManager = this.registerManager(SaplingManager.class); this.treeAnimationManager = this.registerManager(TreeAnimationManager.class); this.treeDefinitionManager = this.registerManager(TreeDefinitionManager.class); @@ -187,6 +190,15 @@ public class UltimateTimber extends JavaPlugin { return this.hookManager; } + /** + * Gets the placed block manager + * + * @return The PlacedBlockManager instance + */ + public PlacedBlockManager getPlacedBlockManager() { + return this.placedBlockManager; + } + /** * Gets the sapling manager * diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/animation/TreeAnimationDisintegrate.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/animation/TreeAnimationDisintegrate.java index 4ee84f8..b0cd870 100644 --- a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/animation/TreeAnimationDisintegrate.java +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/animation/TreeAnimationDisintegrate.java @@ -9,8 +9,10 @@ import com.songoda.ultimatetimber.tree.ITreeBlock; import com.songoda.ultimatetimber.tree.TreeBlock; import com.songoda.ultimatetimber.tree.TreeDefinition; import org.bukkit.block.Block; +import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; import java.util.ArrayList; import java.util.Collections; @@ -60,6 +62,11 @@ public class TreeAnimationDisintegrate extends TreeAnimation { } } + for (ITreeBlock fallingTreeBlock : TreeAnimationDisintegrate.this.fallingTreeBlocks.getAllTreeBlocks()) { + FallingBlock fallingBlock = fallingTreeBlock.getBlock(); + fallingBlock.setVelocity(fallingBlock.getVelocity().clone().subtract(new Vector(0, 0.05, 0))); + } + if (!toDestroy.isEmpty()) { ITreeBlock first = toDestroy.get(0); if (useCustomSound) diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/ConfigurationManager.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/ConfigurationManager.java index 6654623..1678b6a 100644 --- a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/ConfigurationManager.java +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/ConfigurationManager.java @@ -36,12 +36,13 @@ public class ConfigurationManager extends Manager { USE_CUSTOM_SOUNDS(SettingType.BOOLEAN), USE_CUSTOM_PARTICLES(SettingType.BOOLEAN), BONUS_LOOT_MULTIPLIER(SettingType.DOUBLE), + IGNORE_PLACED_BLOCKS(SettingType.BOOLEAN), + IGNORE_PLACED_BLOCKS_MEMORY_SIZE(SettingType.INT), HOOKS_APPLY_EXPERIENCE(SettingType.BOOLEAN), HOOKS_APPLY_EXTRA_DROPS(SettingType.BOOLEAN), HOOKS_REQUIRE_ABILITY_ACTIVE(SettingType.BOOLEAN), TREE_ANIMATION_TYPE(SettingType.STRING), - SCATTER_TREE_BLOCKS_ON_GROUND(SettingType.BOOLEAN), - MIX_ALL_TREE_TYPES(SettingType.BOOLEAN); + SCATTER_TREE_BLOCKS_ON_GROUND(SettingType.BOOLEAN); private SettingType settingType; private Object value = null; diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/PlacedBlockManager.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/PlacedBlockManager.java new file mode 100644 index 0000000..f105781 --- /dev/null +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/PlacedBlockManager.java @@ -0,0 +1,124 @@ +package com.songoda.ultimatetimber.manager; + +import com.songoda.ultimatetimber.UltimateTimber; +import com.songoda.ultimatetimber.adapter.IBlockData; +import com.songoda.ultimatetimber.events.TreeFellEvent; +import com.songoda.ultimatetimber.tree.ITreeBlock; +import com.songoda.ultimatetimber.tree.TreeBlockType; +import com.songoda.ultimatetimber.tree.TreeDefinition; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.LeavesDecayEvent; +import org.bukkit.event.world.StructureGrowEvent; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class PlacedBlockManager extends Manager implements Listener { + + private List placedBlocks; + private boolean ignorePlacedBlocks; + private int maxPlacedBlockMemorySize; + + public PlacedBlockManager(UltimateTimber ultimateTimber) { + super(ultimateTimber); + this.placedBlocks = new ArrayList<>(); + this.ignorePlacedBlocks = true; + this.maxPlacedBlockMemorySize = 10000; + Bukkit.getPluginManager().registerEvents(this, ultimateTimber); + } + + @Override + public void reload() { + this.placedBlocks.clear(); + this.ignorePlacedBlocks = ConfigurationManager.Setting.IGNORE_PLACED_BLOCKS.getBoolean(); + this.maxPlacedBlockMemorySize = ConfigurationManager.Setting.IGNORE_PLACED_BLOCKS_MEMORY_SIZE.getInt(); + } + + @Override + public void disable() { + this.placedBlocks.clear(); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlaced(BlockPlaceEvent event) { + if (!this.ignorePlacedBlocks) + return; + + this.internalProtect(event.getBlock(), true); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent event) { + if (!this.ignorePlacedBlocks) + return; + + this.internalProtect(event.getBlock(), false); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onLeafDecay(LeavesDecayEvent event) { + if (!this.ignorePlacedBlocks) + return; + + this.internalProtect(event.getBlock(), false); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onStructureGrow(StructureGrowEvent event) { + if (!this.ignorePlacedBlocks) + return; + + for (BlockState blockState : event.getBlocks()) + this.internalProtect(blockState.getBlock(), false); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onTreeFell(TreeFellEvent event) { + if (!this.ignorePlacedBlocks) + return; + + for (ITreeBlock treeBlock : event.getDetectedTree().getDetectedTreeBlocks().getAllTreeBlocks()) + this.internalProtect(treeBlock.getBlock(), false); + } + + /** + * Handles when a block is placed/broken + */ + private void internalProtect(Block block, boolean isPlaced) { + if (isPlaced) { + if (this.isBlockPlaced(block)) + return; + + this.placedBlocks.add(block.getLocation()); + if (this.placedBlocks.size() > this.maxPlacedBlockMemorySize) + this.placedBlocks.remove(0); + } else { + this.placedBlocks.remove(block.getLocation()); + } + } + + /** + * Gets if a block is placed + * + * @param block The Block to check + * @return True if the block is placed, otherwise false + */ + public boolean isBlockPlaced(Block block) { + return this.placedBlocks.contains(block.getLocation()); + } + +} diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java index 736230b..b7f5f6a 100644 --- a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDefinitionManager.java @@ -15,7 +15,9 @@ import org.bukkit.configuration.file.YamlConfiguration; 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.Random; import java.util.Set; @@ -221,11 +223,11 @@ public class TreeDefinitionManager extends Manager { boolean addToInventory = ConfigurationManager.Setting.ADD_ITEMS_TO_INVENTORY.getBoolean(); boolean hasBonusChance = player.hasPermission("ultimatetimber.bonusloot"); - Set lootedItems = new HashSet<>(); - Set lootedCommands = new HashSet<>(); + List lootedItems = new ArrayList<>(); + List lootedCommands = new ArrayList<>(); // Get the loot that we should try to drop - Set toTry = new HashSet<>(); + List toTry = new ArrayList<>(); if (hasSilkTouch) { lootedItems.addAll(versionAdapter.getBlockDrops(treeDefinition, treeBlock)); } else { @@ -233,14 +235,20 @@ public class TreeDefinitionManager extends Manager { case LOG: toTry.addAll(treeDefinition.getLogLoot()); toTry.addAll(this.globalLogLoot); - if (treeDefinition.shouldDropOriginalLog()) + if (treeDefinition.shouldDropOriginalLog()) { + if (hookManager.shouldApplyDoubleDropsHooks(player)) + lootedItems.addAll(versionAdapter.getBlockDrops(treeDefinition, treeBlock)); lootedItems.addAll(versionAdapter.getBlockDrops(treeDefinition, treeBlock)); + } break; case LEAF: toTry.addAll(treeDefinition.getLeafLoot()); toTry.addAll(this.globalLeafLoot); - if (treeDefinition.shouldDropOriginalLeaf()) + if (treeDefinition.shouldDropOriginalLeaf()) { + if (hookManager.shouldApplyDoubleDropsHooks(player)) + lootedItems.addAll(versionAdapter.getBlockDrops(treeDefinition, treeBlock)); lootedItems.addAll(versionAdapter.getBlockDrops(treeDefinition, treeBlock)); + } break; } } @@ -267,7 +275,7 @@ public class TreeDefinitionManager extends Manager { // Add to inventory or drop on ground if (addToInventory && player.getWorld().equals(treeBlock.getLocation().getWorld())) { - Set extraItems = new HashSet<>(); + List extraItems = new ArrayList<>(); for (ItemStack lootedItem : lootedItems) extraItems.addAll(player.getInventory().addItem(lootedItem).values()); Location location = player.getLocation().clone().subtract(0.5, 0, 0.5); diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java index a143627..1a2b24f 100644 --- a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeDetectionManager.java @@ -24,6 +24,7 @@ public class TreeDetectionManager extends Manager { private final Set VALID_TRUNK_OFFSETS, VALID_BRANCH_OFFSETS, VALID_LEAF_OFFSETS; private TreeDefinitionManager treeDefinitionManager; + private PlacedBlockManager placedBlockManager; private int maxLogBlocksAllowed, numLeavesRequiredForTree; private boolean onlyBreakLogsUpwards, entireTreeBase, destroyLeaves; @@ -57,6 +58,7 @@ public class TreeDetectionManager extends Manager { @Override public void reload() { this.treeDefinitionManager = this.ultimateTimber.getTreeDefinitionManager(); + this.placedBlockManager = this.ultimateTimber.getPlacedBlockManager(); this.maxLogBlocksAllowed = ConfigurationManager.Setting.MAX_LOGS_PER_CHOP.getInt(); this.numLeavesRequiredForTree = ConfigurationManager.Setting.LEAVES_REQUIRED_FOR_TREE.getInt(); this.onlyBreakLogsUpwards = ConfigurationManager.Setting.ONLY_DETECT_LOGS_UPWARDS.getBoolean(); @@ -224,6 +226,9 @@ public class TreeDetectionManager extends Manager { * @return True if the block is a valid log type, otherwise false */ private boolean isValidLogType(Set treeDefinitions, Block block) { + if (this.placedBlockManager.isBlockPlaced(block)) + return false; + for (TreeDefinition treeDefinition : treeDefinitions) for (IBlockData logBlockData : treeDefinition.getLogBlockData()) if (logBlockData.isSimilar(block)) @@ -239,6 +244,9 @@ public class TreeDetectionManager extends Manager { * @return True if the block is a valid log type, otherwise false */ private boolean isValidLeafType(Set treeDefinitions, Block block) { + if (this.placedBlockManager.isBlockPlaced(block)) + return false; + for (TreeDefinition treeDefinition : treeDefinitions) for (IBlockData leafBlockData : treeDefinition.getLeafBlockData()) if (leafBlockData.isSimilar(block)) diff --git a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeFallManager.java b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeFallManager.java index 14b80ef..d13714f 100644 --- a/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeFallManager.java +++ b/UltimateTimber/Plugin/src/main/java/com/songoda/ultimatetimber/manager/TreeFallManager.java @@ -71,8 +71,10 @@ public class TreeFallManager extends Manager implements Listener { if (!choppingManager.isChopping(player)) isValid = false; - if (treeAnimationManager.isBlockInAnimation(block)) + if (treeAnimationManager.isBlockInAnimation(block)) { isValid = false; + event.setCancelled(true); + } if (!treeDefinitionManager.isToolValidForAnyTreeDefinition(tool)) isValid = false; diff --git a/UltimateTimber/Plugin/src/main/resources/config-current.yml b/UltimateTimber/Plugin/src/main/resources/config-current.yml index a2d95a0..f3ad2fd 100644 --- a/UltimateTimber/Plugin/src/main/resources/config-current.yml +++ b/UltimateTimber/Plugin/src/main/resources/config-current.yml @@ -116,6 +116,17 @@ use-custom-particles: true # Default: 2 bonus-loot-multiplier: 2 +# If placed blocks should be ignored for toppling trees +# Note: This only keeps track of blocks placed during the current server load +# If your server restarts, the placed tree blocks could be toppled again +# Default: true +ignore-placed-blocks: true + +# The maximum number of blocks to keep track of in memory at once +# Use a lower number if this starts to take up too much memory +# Default: 10000 +ignore-placed-blocks-memory-size: 10000 + # Applies experience when using Jobs/mcMMO # Only does something if Jobs or mcMMO is installed # Default: true @@ -140,12 +151,6 @@ tree-animation-type: FANCY # Default: false scatter-tree-blocks-on-ground: false -# Mix all the tree types below and consider all of them as a single tree type -# Useful for EpicWorldGenerator and similar plugins that make custom trees -# Warning: Custom loot can get messy with this enabled -# Default: false -mix-all-tree-types: false - # Tree configuration # Allows for extreme fine-tuning of tree detection and what are considered trees # Multiple log and leaf types are allowed, only one sapling type is allowed diff --git a/UltimateTimber/Plugin/src/main/resources/config-legacy.yml b/UltimateTimber/Plugin/src/main/resources/config-legacy.yml index 4da52cf..023aa2d 100644 --- a/UltimateTimber/Plugin/src/main/resources/config-legacy.yml +++ b/UltimateTimber/Plugin/src/main/resources/config-legacy.yml @@ -117,6 +117,17 @@ use-custom-particles: true # Default: 2 bonus-loot-multiplier: 2 +# If placed blocks should be ignored for toppling trees +# Note: This only keeps track of blocks placed during the current server load +# If your server restarts, the placed tree blocks could be toppled again +# Default: true +ignore-placed-blocks: true + +# The maximum number of blocks to keep track of in memory at once +# Use a lower number if this starts to take up too much memory +# Default: 10000 +ignore-placed-blocks-memory-size: 10000 + # Applies experience when using Jobs/mcMMO # Only does something if Jobs or mcMMO is installed # Default: true @@ -141,12 +152,6 @@ tree-animation-type: FANCY # Default: false scatter-tree-blocks-on-ground: false -# Mix all the tree types below and consider all of them as a single tree type -# Useful for EpicWorldGenerator and similar plugins that make custom trees -# Warning: Custom loot can get messy with this enabled -# Default: false -mix-all-tree-types: false - # Tree configuration # Allows for extreme fine-tuning of tree detection and what are considered trees # Multiple log and leaf types are allowed, only one sapling type is allowed