From 2d9370615e7c6b1b782b341d75110cc8ae61ae86 Mon Sep 17 00:00:00 2001 From: halogly Date: Wed, 16 Jul 2025 18:22:07 +0800 Subject: [PATCH] Improve entity and block interaction handling Added checks for interactable entities and blocks, including chiseled bookshelf, redstone ore, and deepslate redstone ore. Updated ItemEventListener to use new InteractUtils methods for entity and block interactions, preventing custom item execution on interactable entities and blocks. --- .../item/listener/ItemEventListener.java | 33 ++++++++------ .../bukkit/util/InteractUtils.java | 44 ++++++++++++++++++- .../craftengine/core/block/BlockKeys.java | 3 ++ 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java index b10dd7ad7..b507b3b6f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/listener/ItemEventListener.java @@ -36,6 +36,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -66,6 +67,8 @@ public class ItemEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onInteractEntity(PlayerInteractEntityEvent event) { + Player player = event.getPlayer(); + Entity entity = event.getRightClicked(); BukkitServerPlayer serverPlayer = this.plugin.adapt(event.getPlayer()); if (serverPlayer == null) return; InteractionHand hand = event.getHand() == EquipmentSlot.HAND ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; @@ -75,15 +78,17 @@ public class ItemEventListener implements Listener { Optional> optionalCustomItem = itemInHand.getCustomItem(); if (optionalCustomItem.isEmpty()) return; - Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) - .withParameter(DirectContextParameters.HAND, hand) - ); - CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.RIGHT_CLICK); + if (!InteractUtils.isEntityInteractable(player, entity, itemInHand)) { + Cancellable cancellable = Cancellable.of(event::isCancelled, event::setCancelled); + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withOptionalParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.POSITION, LocationUtils.toWorldPosition(event.getRightClicked().getLocation())) + .withParameter(DirectContextParameters.HAND, hand) + ); + CustomItem customItem = optionalCustomItem.get(); + customItem.execute(context, EventTrigger.RIGHT_CLICK); + } } @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) @@ -275,10 +280,12 @@ public class ItemEventListener implements Listener { .withParameter(DirectContextParameters.EVENT, dummy) ); CustomItem customItem = optionalCustomItem.get(); - customItem.execute(context, EventTrigger.RIGHT_CLICK); - if (dummy.isCancelled()) { - event.setCancelled(true); - return; + if (!InteractUtils.isInteractable(player, blockData, hitResult, null)) { + customItem.execute(context, EventTrigger.RIGHT_CLICK); + if (dummy.isCancelled()) { + event.setCancelled(true); + return; + } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java index 11f5213b8..281b1ed0f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/InteractUtils.java @@ -16,12 +16,14 @@ import net.momirealms.craftengine.core.world.BlockHitResult; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.Bell; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; +import org.bukkit.entity.minecart.RideableMinecart; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.Set; public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); @@ -88,6 +90,7 @@ public class InteractUtils { item.recipeIngredientId(), item ))) != null; }); + registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DECORATED_POT, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.HOPPER, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.DISPENSER, (player, item, blockState, result) -> true); @@ -267,6 +270,8 @@ public class InteractUtils { registerInteraction(BlockKeys.REPEATING_COMMAND_BLOCK, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.CHAIN_COMMAND_BLOCK, (player, item, blockState, result) -> true); registerInteraction(BlockKeys.COMMAND_BLOCK, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.REDSTONE_ORE, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.DEEPSLATE_REDSTONE_ORE, (player, item, blockState, result) -> true); } static { @@ -274,6 +279,27 @@ public class InteractUtils { result.getDirection() == Direction.UP && item.id().equals(ItemKeys.CACTUS)); } + private static final Set INTERACTABLE_ENTITIES = Set.of( + EntityType.ALLAY, + EntityType.HORSE, + EntityType.ZOMBIE_HORSE, + EntityType.SKELETON_HORSE, + EntityType.DONKEY, + EntityType.MULE, + EntityType.VILLAGER, + EntityType.WANDERING_TRADER, + EntityType.LLAMA, + EntityType.TRADER_LLAMA, + EntityType.CAMEL, + EntityType.CHEST_MINECART, + EntityType.FURNACE_MINECART, + EntityType.HOPPER_MINECART, + EntityType.COMMAND_BLOCK_MINECART, + EntityType.ITEM_FRAME, + EntityType.GLOW_ITEM_FRAME, + EntityType.HAPPY_GHAST + ); + private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { var previous = INTERACTIONS.put(key, function); if (previous != null) { @@ -297,6 +323,22 @@ public class InteractUtils { } } + public static boolean isEntityInteractable(Player player, Entity entity, Item item) { + boolean isSneaking = player.isSneaking(); + if (entity.getType() == EntityType.PIGLIN && + item != null && + item.vanillaId().equals(Key.of("minecraft:gold_ingot"))) { + return true; + } + return switch (entity) { + case ChestBoat ignored -> true; + case Boat ignored -> !isSneaking; + case RideableMinecart ignored -> !isSneaking; + case Steerable steerable -> !isSneaking && steerable.hasSaddle(); + default -> INTERACTABLE_ENTITIES.contains(entity.getType()); + }; + } + public static boolean willConsume(Player player, BlockData state, BlockHitResult hit, @Nullable Item item) { if (item == null) return false; Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java index fba210d01..4e377f7d2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockKeys.java @@ -42,6 +42,9 @@ public final class BlockKeys { public static final Key CHAIN_COMMAND_BLOCK = Key.of("minecraft:chain_command_block"); public static final Key REPEATING_COMMAND_BLOCK = Key.of("minecraft:repeating_command_block"); public static final Key DECORATED_POT = Key.of("minecraft:decorated_pot"); + public static final Key CHISELED_BOOKSHELF = Key.of("minecraft:chiseled_bookshelf"); + public static final Key REDSTONE_ORE = Key.of("minecraft:redstone_ore"); + public static final Key DEEPSLATE_REDSTONE_ORE = Key.of("minecraft:deepslate_redstone_ore"); public static final Key CAKE = Key.of("minecraft:cake"); public static final Key CANDLE_CAKE = Key.of("minecraft:candle_cake");