diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java index 7bd704a509..b1d3c82b93 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/core/handlers/BlockBreakHandler.java @@ -65,6 +65,16 @@ public void onAndroidBreak(AndroidMineEvent e) { // This can be overridden, if necessary } + /** + * Called when sensitive block was collapsed by breaking the supporting block + * + * @param block Collapsed {@link Block} + */ + @ParametersAreNonnullByDefault + public void onCollapse(Block block) { + // This can be overridden, if necessary + } + /** * This returns whether an explosion is able to break the given {@link Block}. * diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java index 0122d13390..ccd73cb238 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/handlers/SimpleBlockBreakHandler.java @@ -33,8 +33,7 @@ protected SimpleBlockBreakHandler() { } /** - * This method is called when a {@link Block} of this type is broken by a {@link Player}, - * by a {@link MinerAndroid} or through an explosion. + * This method is called when a {@link Block} is broken * * @param b * The broken {@link Block} @@ -56,4 +55,8 @@ public void onExplode(Block b, List drops) { onBlockBreak(b); } + @Override + public void onCollapse(Block block) { + onBlockBreak(block); + } } diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java index 6fe1174e4f..6d9dcaa14b 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/items/tools/ExplosiveTool.java @@ -160,6 +160,11 @@ private void breakBlock(BlockBreakEvent e, Player p, ItemStack item, Block b, Li SlimefunItem sfItem = BlockStorage.check(b); if (sfItem != null && !sfItem.useVanillaBlockBreaking()) { + // Fixes #4037 + if (Slimefun.getTickerTask().isDeletedSoon(b.getLocation())) { + return; + } + /* * Fixes #2989 * We create a dummy here to pass onto the BlockBreakHandler. diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java index 12937e45a4..4fcc9c070e 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockListener.java @@ -15,8 +15,6 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockState; -import org.bukkit.block.data.BlockData; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; @@ -29,17 +27,14 @@ import org.bukkit.inventory.meta.ItemMeta; import io.github.bakedlibs.dough.protection.Interaction; -import io.github.thebusybiscuit.slimefun4.api.events.ExplosiveToolBreakBlocksEvent; import io.github.thebusybiscuit.slimefun4.api.events.SlimefunBlockBreakEvent; import io.github.thebusybiscuit.slimefun4.api.events.SlimefunBlockPlaceEvent; import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; -import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; import io.github.thebusybiscuit.slimefun4.core.attributes.NotPlaceable; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.BlockPlaceHandler; import io.github.thebusybiscuit.slimefun4.core.handlers.ToolUseHandler; import io.github.thebusybiscuit.slimefun4.implementation.Slimefun; -import io.github.thebusybiscuit.slimefun4.utils.tags.SlimefunTag; import me.mrCookieSlime.Slimefun.api.BlockStorage; import me.mrCookieSlime.Slimefun.api.inventory.BlockMenu; @@ -171,23 +166,9 @@ public void onBlockBreak(BlockBreakEvent e) { } if (!e.isCancelled()) { - // Checks for Slimefun sensitive blocks above, using Slimefun Tags - // TODO: merge this with the vanilla sensitive block check (when 1.18- is dropped) - checkForSensitiveBlockAbove(e.getPlayer(), e.getBlock(), item); - callBlockHandler(e, item, drops, sfItem); dropItems(e, drops); - - // Checks for vanilla sensitive blocks everywhere - // checkForSensitiveBlocks(e.getBlock(), 0, e.isDropItems()); - } - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onExplosiveToolBlockBreak(ExplosiveToolBreakBlocksEvent e) { - for (Block block : e.getAdditionalBlocks()) { - checkForSensitiveBlockAbove(e.getPlayer(), block, e.getItemInHand()); } } @@ -215,6 +196,11 @@ private void callBlockHandler(BlockBreakEvent e, ItemStack item, List } if (sfItem != null && !sfItem.useVanillaBlockBreaking()) { + // Fixes #4037 + if (Slimefun.getTickerTask().isDeletedSoon(e.getBlock().getLocation()) || !BlockStorage.hasBlockInfo(e.getBlock())) { + return; + } + sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(e, item, drops)); if (e.isCancelled()) { @@ -250,6 +236,9 @@ private void dropItems(BlockBreakEvent e, List drops) { // Disable normal block drops e.setDropItems(false); + // Fixes #3182 - Drop the sensitive blocks that require supporting block but don't drop the supporting block + e.getBlock().setType(Material.AIR, true); + for (ItemStack drop : drops) { // Prevent null or air from being dropped if (drop != null && drop.getType() != Material.AIR) { @@ -262,107 +251,6 @@ private void dropItems(BlockBreakEvent e, List drops) { } } - /** - * This method checks for a sensitive {@link Block}. - * Sensitive {@link Block Blocks} are pressure plates or saplings, which should be broken - * when the block beneath is broken as well. - * - * @param player - * The {@link Player} who broke this {@link Block} - * @param block - * The {@link Block} that was broken - * @param item - * The {@link ItemStack} that was used to break the {@link Block} - */ - @ParametersAreNonnullByDefault - private void checkForSensitiveBlockAbove(Player player, Block block, ItemStack item) { - Block blockAbove = block.getRelative(BlockFace.UP); - - if (SlimefunTag.SENSITIVE_MATERIALS.isTagged(blockAbove.getType())) { - SlimefunItem sfItem = BlockStorage.check(blockAbove); - - if (sfItem != null && !sfItem.useVanillaBlockBreaking()) { - /* - * We create a dummy here to pass onto the BlockBreakHandler. - * This will set the correct block context. - */ - BlockBreakEvent dummyEvent = new BlockBreakEvent(blockAbove, player); - List drops = new ArrayList<>(sfItem.getDrops(player)); - - sfItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onPlayerBreak(dummyEvent, item, drops)); - blockAbove.setType(Material.AIR); - - if (!dummyEvent.isCancelled() && dummyEvent.isDropItems()) { - for (ItemStack drop : drops) { - if (drop != null && !drop.getType().isAir()) { - blockAbove.getWorld().dropItemNaturally(blockAbove.getLocation(), drop); - } - } - } - - // Fixes #2944 - Don't forget to clear the Block Data - BlockStorage.clearBlockInfo(blockAbove); - } - } - } - - /** - * This method checks recursively for any sensitive blocks - * that are no longer supported due to this block breaking - * - * @param block - * The {@link Block} in question - * @param count - * The amount of times this has been recursively called - */ - // Disabled for now due to #4069 - Servers crashing due to this check - // There is additionally a second bug with `getMaxChainedNeighborUpdates` not existing in 1.17 - @ParametersAreNonnullByDefault - private void checkForSensitiveBlocks(Block block, int count, boolean isDropItems) { - if (count >= Bukkit.getServer().getMaxChainedNeighborUpdates()) { - return; - } - - BlockState state = block.getState(); - // We set the block to air to make use of BlockData#isSupported. - block.setType(Material.AIR, false); - for (BlockFace face : CARDINAL_BLOCKFACES) { - if (!isSupported(block.getRelative(face).getBlockData(), block.getRelative(face))) { - Block relative = block.getRelative(face); - if (!isDropItems) { - for (ItemStack drop : relative.getDrops()) { - block.getWorld().dropItemNaturally(relative.getLocation(), drop); - } - } - checkForSensitiveBlocks(relative, ++count, isDropItems); - } - } - // Set the BlockData back: this makes it so containers and spawners drop correctly. This is a hacky fix. - block.setBlockData(state.getBlockData(), false); - state.update(true, false); - } - - /** - * This method checks if the {@link BlockData} would be - * supported at the given {@link Block}. - * - * @param blockData - * The {@link BlockData} to check - * @param block - * The {@link Block} the {@link BlockData} would be at - * @return - * Whether the {@link BlockData} would be supported at the given {@link Block} - */ - @ParametersAreNonnullByDefault - private boolean isSupported(BlockData blockData, Block block) { - if (Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_19)) { - return blockData.isSupported(block); - } else { - // TODO: Make 1.16-1.18 version. BlockData::isSupported is 1.19+. - return true; - } - } - private int getBonusDropsWithFortune(@Nullable ItemStack item, @Nonnull Block b) { int amount = 1; diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java index d63289aa46..774cd704d5 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/listeners/BlockPhysicsListener.java @@ -2,6 +2,9 @@ import javax.annotation.Nonnull; +import io.github.thebusybiscuit.slimefun4.api.MinecraftVersion; +import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem; +import io.github.thebusybiscuit.slimefun4.core.handlers.BlockBreakHandler; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -12,6 +15,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPistonEvent; import org.bukkit.event.block.BlockPistonExtendEvent; import org.bukkit.event.block.BlockPistonRetractEvent; @@ -112,4 +116,36 @@ public void onBucketUse(PlayerBucketEmptyEvent e) { e.setCancelled(true); } } + + @EventHandler + public void onBlockUpdate(BlockPhysicsEvent event) { + if (!Slimefun.getMinecraftVersion().isAtLeast(MinecraftVersion.MINECRAFT_1_18)) { + // Method BlockData#isSupported is 1.18+ + return; + } + + Block block = event.getBlock(); + + // Listen for collapsing sensitive slimefun blocks + if (BlockStorage.hasBlockInfo(block) && !Slimefun.getTickerTask().isDeletedSoon(block.getLocation()) && !block.getBlockData().isSupported(block)) { + SlimefunItem sfBlockItem = BlockStorage.check(block); + + if (sfBlockItem != null && !sfBlockItem.useVanillaBlockBreaking()) { + sfBlockItem.callItemHandler(BlockBreakHandler.class, handler -> handler.onCollapse(block)); + + // Drop items from surrounding sensitive blocks but don't drop from supporting block + event.setCancelled(true); + block.setType(Material.AIR, true); + + for (ItemStack drop : sfBlockItem.getDrops()) { + if (drop != null && !drop.getType().isAir()) { + block.getWorld().dropItemNaturally(block.getLocation(), drop); + } + } + + // Fixes #2944 - Don't forget to clear the Block Data + BlockStorage.clearBlockInfo(block); + } + } + } }