9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-30 04:19:27 +00:00

Add support for Happy Ghast and harness interactions

Introduces logic for handling Happy Ghast entity interactions and harness item tags, gated by Minecraft version 1.21.6. Refactors entity and block interaction checks to use new utility methods and dynamic entity sets, improving maintainability and future compatibility.
This commit is contained in:
halogly
2025-07-18 13:42:49 +08:00
parent 2d9370615e
commit 348f004500
4 changed files with 81 additions and 23 deletions

View File

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

View File

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

View File

@@ -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<Key, QuadFunction<Player, Item<ItemStack>, BlockData, BlockHitResult, Boolean>> INTERACTIONS = new HashMap<>();
private static final Map<Key, QuadFunction<Player, Item<ItemStack>, 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<EntityType> 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<EntityType> INTERACTABLE_ENTITIES = Set.of(
private static Set<EntityType> createInteractableEntities() {
Set<EntityType> 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<org.bukkit.entity.Player, Item<ItemStack>, 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<ItemStack> 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) {

View File

@@ -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<Material> ITEMS_HARNESSES = getHarnessTag();
private ItemTags() {}
@@ -23,4 +29,13 @@ public class ItemTags {
}
return value;
}
public static Tag<Material> getHarnessTag() {
if (!VersionHelper.isOrAbove1_21_6()) return null;
try {
return Bukkit.getTag("items", NamespacedKey.minecraft("harnesses"), Material.class);
} catch (Exception e) {
return null;
}
}
}