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 b507b3b6f..8f2095acf 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 @@ -34,6 +34,8 @@ import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.ChiseledBookshelf; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; import org.bukkit.entity.Entity; @@ -53,10 +55,7 @@ import org.bukkit.inventory.EnchantingInventory; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; public class ItemEventListener implements Listener { private final BukkitCraftEngine plugin; @@ -280,12 +279,12 @@ public class ItemEventListener implements Listener { .withParameter(DirectContextParameters.EVENT, dummy) ); CustomItem customItem = optionalCustomItem.get(); - if (!InteractUtils.isInteractable(player, blockData, hitResult, null)) { + if (!InteractUtils.isInteractable(player, blockData, hitResult, itemInHand) && !player.isSneaking()) { customItem.execute(context, EventTrigger.RIGHT_CLICK); - if (dummy.isCancelled()) { - event.setCancelled(true); - return; - } + } + if (dummy.isCancelled()) { + event.setCancelled(true); + return; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java index 30fd6fa4b..0dfe4ec0d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/EntityUtils.java @@ -2,14 +2,17 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; +import org.bukkit.entity.*; import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; import java.util.function.Consumer; @@ -34,4 +37,24 @@ public class EntityUtils { return LegacyEntityUtils.spawnEntity(world, loc, type, function); } } + + public static boolean isPiglinWithGoldIngot(Entity entity, Item item) { + return entity.getType() == EntityType.PIGLIN && + item != null && + item.vanillaId().equals(Key.of("minecraft:gold_ingot")); + } + + public static boolean isHappyGhastRideable(Entity entity) { + if (!VersionHelper.isOrAbove1_21_6() && + !entity.getType().name().equals("HAPPY_GHAST")) return false; + return entity instanceof LivingEntity livingEntity + && livingEntity.getEquipment() != null + && hasHarness(livingEntity.getEquipment()); + } + + public static boolean hasHarness(EntityEquipment equipment) { + ItemStack bodyItem = equipment.getItem(EquipmentSlot.BODY); + return ItemTags.ITEMS_HARNESSES != null && + ItemTags.ITEMS_HARNESSES.isTagged(bodyItem.getType()); + } } 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 281b1ed0f..54e1aba40 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 @@ -12,23 +12,25 @@ import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.QuadFunction; +import net.momirealms.craftengine.core.util.VersionHelper; 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.block.data.type.ChiseledBookshelf; 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; +import java.lang.reflect.Field; +import java.util.*; public class InteractUtils { private static final Map, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>(); private static final Map, BlockData, BlockHitResult, Boolean>> WILL_CONSUME = new HashMap<>(); private static final Key NOTE_BLOCK_TOP_INSTRUMENTS = Key.of("minecraft:noteblock_top_instruments"); + private static final Set INTERACTABLE_ENTITIES = createInteractableEntities(); private InteractUtils() {} @@ -90,7 +92,15 @@ public class InteractUtils { item.recipeIngredientId(), item ))) != null; }); - registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> true); + registerInteraction(BlockKeys.CHISELED_BOOKSHELF, (player, item, blockState, result) -> { + Direction direction = result.getDirection(); + if (player.isSneaking()) return false; + if (blockState instanceof ChiseledBookshelf chiseledBookshelf) { + Direction facing = DirectionUtils.toDirection(chiseledBookshelf.getFacing()); + return facing == direction; + } + return false; + }); 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); @@ -279,7 +289,9 @@ public class InteractUtils { result.getDirection() == Direction.UP && item.id().equals(ItemKeys.CACTUS)); } - private static final Set INTERACTABLE_ENTITIES = Set.of( + private static Set createInteractableEntities() { + Set set = EnumSet.noneOf(EntityType.class); + set.addAll(Set.of( EntityType.ALLAY, EntityType.HORSE, EntityType.ZOMBIE_HORSE, @@ -296,9 +308,17 @@ public class InteractUtils { EntityType.HOPPER_MINECART, EntityType.COMMAND_BLOCK_MINECART, EntityType.ITEM_FRAME, - EntityType.GLOW_ITEM_FRAME, - EntityType.HAPPY_GHAST - ); + EntityType.GLOW_ITEM_FRAME + )); + if (VersionHelper.isOrAbove1_21_6()) { + try { + Field happyGhastField = EntityType.class.getField("HAPPY_GHAST"); + EntityType happyGhast = (EntityType) happyGhastField.get(null); + set.add(happyGhast); + } catch (NoSuchFieldException | IllegalAccessException ignored) {} + } + return Collections.unmodifiableSet(set); + } private static void registerInteraction(Key key, QuadFunction, BlockData, BlockHitResult, Boolean> function) { var previous = INTERACTIONS.put(key, function); @@ -325,9 +345,10 @@ 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"))) { + if (EntityUtils.isPiglinWithGoldIngot(entity, item)) { + return true; + } + if (EntityUtils.isHappyGhastRideable(entity) && !isSneaking) { return true; } return switch (entity) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java index 1f35e3e90..62ab60190 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/ItemTags.java @@ -3,6 +3,11 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Tag; import java.util.HashMap; import java.util.Map; @@ -12,6 +17,7 @@ public class ItemTags { public static final Key AXES = Key.of("minecraft:axes"); public static final Key SWORDS = Key.of("minecraft:swords"); + public static final Tag ITEMS_HARNESSES = getHarnessTag(); private ItemTags() {} @@ -23,4 +29,13 @@ public class ItemTags { } return value; } + + public static Tag getHarnessTag() { + if (!VersionHelper.isOrAbove1_21_6()) return null; + try { + return Bukkit.getTag("items", NamespacedKey.minecraft("harnesses"), Material.class); + } catch (Exception e) { + return null; + } + } }