9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-25 09:59:20 +00:00

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.
This commit is contained in:
halogly
2025-07-16 18:22:07 +08:00
parent 10bb3d2e5e
commit 2d9370615e
3 changed files with 66 additions and 14 deletions

View File

@@ -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<CustomItem<ItemStack>> 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<ItemStack> 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<ItemStack> 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<ItemStack> 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;
}
}
}

View File

@@ -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<Key, QuadFunction<Player, Item<ItemStack>, 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<EntityType> 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<org.bukkit.entity.Player, Item<ItemStack>, 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<ItemStack> 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<ItemStack> item) {
if (item == null) return false;
Key blockType = BlockStateUtils.getBlockOwnerIdFromData(state);

View File

@@ -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");