diff --git a/src/main/java/fr/openmc/core/ListenersManager.java b/src/main/java/fr/openmc/core/ListenersManager.java index e5977fe91..dbed68ddb 100644 --- a/src/main/java/fr/openmc/core/ListenersManager.java +++ b/src/main/java/fr/openmc/core/ListenersManager.java @@ -40,7 +40,8 @@ public static void init() { new AywenCapListener(), new NoMoreRabbit(), new ArmorListener(), - new SpawnerExtractorListener() + new SpawnerExtractorListener(), + new BlockBreakListener() ); if (!OMCPlugin.isUnitTestVersion()) { diff --git a/src/main/java/fr/openmc/core/items/CustomItem.java b/src/main/java/fr/openmc/core/items/CustomItem.java index 49309a6b6..95fe16897 100644 --- a/src/main/java/fr/openmc/core/items/CustomItem.java +++ b/src/main/java/fr/openmc/core/items/CustomItem.java @@ -6,13 +6,15 @@ import org.bukkit.inventory.ItemStack; public abstract class CustomItem { - public abstract ItemStack getVanilla(); - @Getter private final String name; + @Getter + private final String name; public CustomItem(String name) { this.name = name; } + public abstract ItemStack getVanilla(); + public ItemStack getItemsAdder() { CustomStack stack = CustomStack.getInstance(getName()); return stack != null ? stack.getItemStack() : null; @@ -42,6 +44,7 @@ public boolean equals(Object object) { * Order: * 1. ItemsAdder * 2. Vanilla + * * @return Best ItemStack to use for the server */ public ItemStack getBest() { diff --git a/src/main/java/fr/openmc/core/items/usable/CustomUsableItem.java b/src/main/java/fr/openmc/core/items/usable/CustomUsableItem.java index 518f367de..cf19430b7 100644 --- a/src/main/java/fr/openmc/core/items/usable/CustomUsableItem.java +++ b/src/main/java/fr/openmc/core/items/usable/CustomUsableItem.java @@ -3,6 +3,7 @@ import fr.openmc.core.items.CustomItem; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.player.PlayerInteractEvent; public abstract class CustomUsableItem extends CustomItem { @@ -20,25 +21,31 @@ protected CustomUsableItem(String name) { * Event called when the player right-clicks with this item. * * @param player The player who performed the right-click. - * @param event The {@link PlayerInteractEvent} representing the click. + * @param event The {@link PlayerInteractEvent} representing the click. */ - public void onRightClick(Player player, PlayerInteractEvent event) {} + public void onRightClick(Player player, PlayerInteractEvent event) { + } /** * Event called when the player left-clicks with this item. * * @param player The player who performed the left-click. - * @param event The {@link PlayerInteractEvent} representing the click. + * @param event The {@link PlayerInteractEvent} representing the click. */ - public void onLeftClick(Player player, PlayerInteractEvent event) {} + public void onLeftClick(Player player, PlayerInteractEvent event) { + } /** * Event called when the player sneaks and clicks with this item. * * @param player The player who is sneaking and performed the click. - * @param event The {@link PlayerInteractEvent} representing the click. + * @param event The {@link PlayerInteractEvent} representing the click. */ - public void onSneakClick(Player player, PlayerInteractEvent event) {} + public void onSneakClick(Player player, PlayerInteractEvent event) { + } + + public void onBlockBreak(Player player, BlockBreakEvent event) { + } /** * Handles the interaction with the item. @@ -49,13 +56,13 @@ public void onSneakClick(Player player, PlayerInteractEvent event) {} public final void handleInteraction(Player player, PlayerInteractEvent event) { Action action = event.getAction(); - if (player.isSneaking()) { - onSneakClick(player, event); - } else if (action.isLeftClick()) { - onLeftClick(player, event); - } else if (action.isRightClick()) { - onRightClick(player, event); - } + if (player.isSneaking()) onSneakClick(player, event); + else if (action.isLeftClick()) onLeftClick(player, event); + else if (action.isRightClick()) onRightClick(player, event); + } + + public final void handleBlockBreak(Player player, BlockBreakEvent event) { + onBlockBreak(player, event); } } diff --git a/src/main/java/fr/openmc/core/items/usable/CustomUsableItemRegistry.java b/src/main/java/fr/openmc/core/items/usable/CustomUsableItemRegistry.java index 5475197b1..6531d189a 100644 --- a/src/main/java/fr/openmc/core/items/usable/CustomUsableItemRegistry.java +++ b/src/main/java/fr/openmc/core/items/usable/CustomUsableItemRegistry.java @@ -1,6 +1,8 @@ package fr.openmc.core.items.usable; import dev.lone.itemsadder.api.CustomStack; +import fr.openmc.core.items.usable.tools.Hammer; +import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import java.util.HashMap; @@ -15,7 +17,9 @@ public class CustomUsableItemRegistry { * This constructor should be called once during server startup. */ public static void init() { - // register here + register(new Hammer("omc_items:iron_hammer", Material.IRON_PICKAXE, 1, 0)); + register(new Hammer("omc_items:diamond_hammer", Material.DIAMOND_PICKAXE, 1, 1)); + register(new Hammer("omc_items:netherite_hammer", Material.NETHERITE_PICKAXE, 1, 2)); } /** diff --git a/src/main/java/fr/openmc/core/items/usable/tools/Hammer.java b/src/main/java/fr/openmc/core/items/usable/tools/Hammer.java new file mode 100644 index 000000000..62eecbf08 --- /dev/null +++ b/src/main/java/fr/openmc/core/items/usable/tools/Hammer.java @@ -0,0 +1,98 @@ +package fr.openmc.core.items.usable.tools; + +import fr.openmc.core.features.city.ProtectionsManager; +import fr.openmc.core.items.usable.CustomUsableItem; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; + +public class Hammer extends CustomUsableItem { + + private static final float MAX_HARDNESS = 41.0f; + + private final Material vanillaMaterial; + private final int radius; + private final int depth; + + public Hammer(String namespacedId, Material vanillaMaterial, int radius, int depth) { + super(namespacedId); + this.vanillaMaterial = vanillaMaterial; + this.radius = radius; + this.depth = depth; + } + + private static BlockFace getTargetFace(Player player) { + Location eye = player.getEyeLocation(); + RayTraceResult result = eye.getWorld().rayTraceBlocks(eye, eye.getDirection(), 10, FluidCollisionMode.NEVER); + + return result != null && result.getHitBlockFace() != null ? result.getHitBlockFace() : BlockFace.SELF; + } + + private static Vector rotateOffset(int x, int y, int z, BlockFace face) { + return switch (face) { + case NORTH, SOUTH -> new Vector(x, y, z); + case EAST, WEST -> new Vector(z, y, x); + case UP, DOWN -> new Vector(x, z, y); + default -> new Vector(0, 0, 0); + }; + } + + private void breakArea(Player player, Block origin, BlockFace face, ItemStack tool, Material targetType) { + World world = origin.getWorld(); + int ox = origin.getX(); + int oy = origin.getY(); + int oz = origin.getZ(); + + for (int dx = -radius; dx <= radius; dx++) { + for (int dy = -radius; dy <= radius; dy++) { + for (int dz = -depth; dz <= depth; dz++) { + + if (dx == 0 && dy == 0 && dz == 0) continue; + + Vector offset = rotateOffset(dx, dy, dz, face); + breakBlock(world, player, tool, ox + offset.getBlockX(), oy + offset.getBlockY(), oz + offset.getBlockZ(), targetType); + } + } + } + } + + private void breakBlock(World world, Player player, ItemStack tool, int x, int y, int z, Material targetType) { + Block block = world.getBlockAt(x, y, z); + + if (block.getType() != targetType) return; + if (!isBreakable(block.getType())) return; + if (!ProtectionsManager.canInteract(player, block.getLocation())) return; + + block.breakNaturally(tool); + } + + private boolean isBreakable(Material material) { + return !material.isAir() && material.getHardness() <= MAX_HARDNESS; + } + + @Override + public ItemStack getVanilla() { + return ItemStack.of(vanillaMaterial); + } + + @Override + public void onBlockBreak(Player player, BlockBreakEvent event) { + if (player.getGameMode() != GameMode.SURVIVAL) return; + + ItemStack tool = player.getInventory().getItemInMainHand(); + if (tool.getType().isAir()) return; + + Block origin = event.getBlock(); + Material targetType = origin.getType(); + + if (!isBreakable(targetType)) return; + + BlockFace face = getTargetFace(player).getOppositeFace(); + breakArea(player, origin, face, tool, targetType); + } +} diff --git a/src/main/java/fr/openmc/core/listeners/BlockBreakListener.java b/src/main/java/fr/openmc/core/listeners/BlockBreakListener.java new file mode 100644 index 000000000..780768216 --- /dev/null +++ b/src/main/java/fr/openmc/core/listeners/BlockBreakListener.java @@ -0,0 +1,27 @@ +package fr.openmc.core.listeners; + +import fr.openmc.core.features.city.ProtectionsManager; +import fr.openmc.core.items.usable.CustomUsableItem; +import fr.openmc.core.items.usable.CustomUsableItemRegistry; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.inventory.ItemStack; + +public class BlockBreakListener implements Listener { + + @EventHandler + public void onBlockBreak(BlockBreakEvent event) { + Player player = event.getPlayer(); + if (event.isCancelled()) return; + if (event.getBlock() == null) return; + ProtectionsManager.verify(player, event, event.getBlock().getLocation()); + + ItemStack itemInHand = player.getInventory().getItemInMainHand(); + CustomUsableItem usableItem = CustomUsableItemRegistry.getByItemStack(itemInHand); + + if (usableItem != null) usableItem.handleBlockBreak(player, event); + } + +} diff --git a/src/main/java/fr/openmc/core/listeners/InteractListener.java b/src/main/java/fr/openmc/core/listeners/InteractListener.java index fd99571d7..31df2d139 100644 --- a/src/main/java/fr/openmc/core/listeners/InteractListener.java +++ b/src/main/java/fr/openmc/core/listeners/InteractListener.java @@ -21,8 +21,7 @@ void onInteract(PlayerInteractEvent event) { ItemStack itemInHand = player.getInventory().getItemInMainHand(); CustomUsableItem usableItem = CustomUsableItemRegistry.getByItemStack(itemInHand); - if (usableItem != null) - usableItem.handleInteraction(player, event); + if (usableItem != null) usableItem.handleInteraction(player, event); } }