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
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);
}
}
}
}