diff --git a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java index 21cee1d006..154150d979 100644 --- a/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java +++ b/src/main/java/io/github/thebusybiscuit/slimefun4/implementation/guide/SurvivalSlimefunGuide.java @@ -339,7 +339,7 @@ public void openSearch(PlayerProfile profile, String input, boolean addToHistory } ChestMenu menu = new ChestMenu(Slimefun.getLocalization().getMessage(p, "guide.search.inventory").replace("%item%", ChatUtils.crop(ChatColor.WHITE, input))); - String searchTerm = input.toLowerCase(Locale.ROOT); + String searchTerm = ChatColor.stripColor(input.toLowerCase(Locale.ROOT)); if (addToHistory) { profile.getGuideHistory().add(searchTerm); 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 58d066aae7..91fb9eb291 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 @@ -14,6 +14,8 @@ 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.Player; import org.bukkit.event.EventHandler; @@ -29,6 +31,7 @@ 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; @@ -53,6 +56,8 @@ */ public class BlockListener implements Listener { + private static final BlockFace[] CARDINAL_BLOCKFACES = new BlockFace[]{BlockFace.WEST, BlockFace.EAST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.DOWN, BlockFace.UP}; + public BlockListener(@Nonnull Slimefun plugin) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } @@ -163,10 +168,16 @@ 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()); } } @@ -280,6 +291,61 @@ private void checkForSensitiveBlockAbove(Player player, Block block, ItemStack i } } + /** + * 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 + */ + @ParametersAreNonnullByDefault + private void checkForSensitiveBlocks(Block block, Integer 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/resources/tags/block_placer_ignored_materials.json b/src/main/resources/tags/block_placer_ignored_materials.json index 3f9417b711..bc32030c7f 100644 --- a/src/main/resources/tags/block_placer_ignored_materials.json +++ b/src/main/resources/tags/block_placer_ignored_materials.json @@ -27,7 +27,6 @@ "minecraft:lily_pad", "minecraft:dead_bush", "minecraft:fern", - "minecraft:grass", "minecraft:sea_pickle", "minecraft:nether_wart", "minecraft:seagrass", @@ -35,6 +34,10 @@ "minecraft:kelp", "minecraft:bell", "minecraft:lantern", + { + "id" : "minecraft:grass", + "required" : false + }, { "id" : "minecraft:soul_lantern", "required" : false @@ -58,6 +61,10 @@ { "id" : "minecraft:weeping_vines", "required" : false + }, + { + "id" : "minecraft:short_grass", + "required" : false } ] } diff --git a/src/test/java/io/github/thebusybiscuit/slimefun4/core/guide/TestGuideOpening.java b/src/test/java/io/github/thebusybiscuit/slimefun4/core/guide/TestGuideOpening.java index 8ed5d838b9..a8685b9736 100644 --- a/src/test/java/io/github/thebusybiscuit/slimefun4/core/guide/TestGuideOpening.java +++ b/src/test/java/io/github/thebusybiscuit/slimefun4/core/guide/TestGuideOpening.java @@ -5,11 +5,14 @@ import javax.annotation.Nonnull; import javax.annotation.ParametersAreNonnullByDefault; +import io.github.thebusybiscuit.slimefun4.implementation.guide.SurvivalSlimefunGuide; +import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -89,14 +92,36 @@ void testOpenItemStack() throws InterruptedException { Mockito.verify(guide).displayItem(profile, item, 1, false); } + @Test + @DisplayName("Test if the Slimefun Search works with normal and colored terms") + void testOpenSearch_withColoredSearchTerm() throws InterruptedException { + String normalTerm = "iron"; + String coloredTerm = ChatColor.DARK_PURPLE + "iron"; + + SlimefunItem testItem = TestUtilities.mockSlimefunItem(plugin, "IRON_ITEM", new CustomItemStack(Material.IRON_INGOT, "iron item")); + testItem.register(plugin); + + Player player = server.addPlayer(); + PlayerProfile profile = TestUtilities.awaitProfile(player); + SlimefunGuideImplementation guide = new SurvivalSlimefunGuide(false, false); + + guide.openSearch(profile, normalTerm, false); + // Assert we can open with a non-coloured search term + Assertions.assertTrue(player.getOpenInventory().getTopInventory().contains(testItem.getItem()), "Failed on normal query"); + + guide.openSearch(profile, coloredTerm, false); + // Assert we can open with a coloured search term + Assertions.assertTrue(player.getOpenInventory().getTopInventory().contains(testItem.getItem()), "Failed on colored query"); + } + @Test @DisplayName("Test if the Slimefun Search can be opened from the History") - void testOpenSearch() throws InterruptedException { - String query = "electric"; + void testOpenSearchHistory() throws InterruptedException { + String term = "electric"; SlimefunGuideImplementation guide = Mockito.mock(SlimefunGuideImplementation.class); - PlayerProfile profile = prepare(guide, history -> history.add(query)); - Mockito.verify(guide).openSearch(profile, query, false); + PlayerProfile profile = prepare(guide, history -> history.add(term)); + Mockito.verify(guide).openSearch(profile, term, false); } @Test