Search code examples
javaminecraftbukkit

Minecraft Java Bukkit


I want to make it so that my bukkit-paper plugin for 1.20.1 works, where you can mine an end portal frame with silk-touch and it mines, and you get the item:

package me.grubbauer.endcrafter;

import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.plugin.java.JavaPlugin;

public final class EndCrafter extends JavaPlugin implements Listener {

    @Override
    public void onEnable() {
        getServer().getPluginManager().registerEvents(this, this);
    }

    @EventHandler
    public void onBlockBreak(BlockBreakEvent event) {
        Block block = event.getBlock();
        if (block.getType() == Material.END_PORTAL) {
            // Check if the player has silk touch
            if (event.getPlayer().getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH)) {
                // Drop end portal blocks
                dropEndPortalBlocks(block);
                // Cancel the event so the original block doesn't drop anything
                event.setCancelled(true);
            }
        }
    }

    private void dropEndPortalBlocks(Block block) {
        // Drop end portal blocks
        for (BlockFace face : BlockFace.values()) {
            Block adjacentBlock = block.getRelative(face);
            if (adjacentBlock.getType() == Material.END_PORTAL_FRAME) {
                adjacentBlock.breakNaturally();
            }
        }
    }
}

Expected: Block destroys and block gets dropped when mined with silk touch

Result: Doesn't mine


Solution

  • In the event, you are checking for the block END_PORTAL, then on dropEndPortalBlocks() method you are looking for END_PORTAL_FRAME block. It cannot be the same.

    The END_PORTAL_FRAME is the world block, while END_PORTAL is the in-hand item. You should put END_PORTAL_FRAME both time. If you don't know, you can put both in the if like this: if (block.getType() == Material.END_PORTAL || block.getType() == Material.END_PORTAL_FRAME)

    Then, for the logic problem reported by Rogue, it's solved y the BlockFace.SELF. So it should not be a problem, but you can do better: let the event manage the drop of the main block and ignore BlockFace.SELF in the loop.

    Also, if you want to clear drop, just do event.setDropItems(false).

    Finally, the breakNaturally() will simply drop the block as normal. But, you can add the item of the player in hand to make it break exactly as it were the player that broke it. Example: breakNaturally(player.getInventory().getItemInMainHand()).

    Full code:

    package me.grubbauer.endcrafter;
    
    import org.bukkit.Material;
    import org.bukkit.block.Block;
    import org.bukkit.block.BlockFace;
    import org.bukkit.enchantments.Enchantment;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.BlockBreakEvent;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public final class EndCrafter extends JavaPlugin implements Listener {
    
        @Override
        public void onEnable() {
            getServer().getPluginManager().registerEvents(this, this);
        }
    
        @EventHandler
        public void onBlockBreak(BlockBreakEvent event) {
            Block block = event.getBlock();
            if (block.getType() == Material.END_PORTAL_FRAME) {
                // Check if the player has silk touch
                if (event.getPlayer().getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH)) {
                    // Drop end portal blocks
                    dropEndPortalBlocks(block, event.getPlayer().getInventory().getItemInMainHand());
                }
            }
        }
    
        private void dropEndPortalBlocks(Block block, ItemStack inHand) {
            // Drop end portal blocks
            for (BlockFace face : BlockFace.values()) {
                if(face == BlockFace.SELF) // ignore this one
                    continue;
                Block adjacentBlock = block.getRelative(face);
                if (adjacentBlock.getType() == Material.END_PORTAL_FRAME) {
                    adjacentBlock.breakNaturally(inHand);
                }
            }
        }
    }