diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index 270ab1c08..fa1f05417 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -48,31 +48,22 @@ import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager; import org.geysermc.geyser.entity.type.living.MobEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.level.physics.BoundingBox; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; -import org.geysermc.geyser.util.ItemUtils; import org.geysermc.geyser.util.MathUtils; -import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; -import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; import java.util.Collections; import java.util.EnumSet; @@ -701,12 +692,10 @@ public class Entity implements GeyserEntity { return InteractionResult.SUCCESS; } - if (this instanceof MobEntity mob && mob.passengers.isEmpty() && !session.isSneaking() && canShearEquipment(mob)) { + if (this instanceof MobEntity mob && !session.isSneaking() && mob.canShearEquipment()) { return InteractionResult.SUCCESS; } - } - - if (isAlive() && this instanceof Leashable leashable) { + } else if (isAlive() && this instanceof Leashable leashable) { if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) { // Note this might also update client side (a theoretical Geyser/client desync and Java parity issue). // Has yet to be an issue though, as of Java 1.21. @@ -725,7 +714,7 @@ public class Entity implements GeyserEntity { public boolean hasLeashesToDrop() { BoundingBox searchBB = new BoundingBox(position.getX(), position.getY(), position.getZ(), 32, 32, 32); List leashedInRange = session.getEntityCache().getEntities().values().stream() - .filter(entity -> entity instanceof Leashable leashablex && leashablex.leashHolderBedrockId() == this.getEntityId()) + .filter(entity -> entity instanceof Leashable leashablex && leashablex.leashHolderBedrockId() == this.getGeyserId()) .filter(entity -> { BoundingBox leashedBB = new BoundingBox(entity.position.toDouble(), entity.boundingBoxWidth, entity.boundingBoxHeight, entity.boundingBoxWidth); return searchBB.checkIntersection(leashedBB); @@ -739,26 +728,6 @@ public class Entity implements GeyserEntity { return found; } - public boolean canShearEquipment(MobEntity mob) { - for (EquipmentSlot equipmentSlot : EquipmentSlot.values()) { - ItemStack equipment = mob.equipment.get(equipmentSlot); - if (equipment == null) continue; - - Item item = Registries.JAVA_ITEMS.get(equipment.getId()); - if (item == null) continue; - - DataComponents components = item.gatherComponents(equipment.getDataComponentsPatch()); - Equippable equippable = components.get(DataComponentTypes.EQUIPPABLE); - if (equippable != null && equippable.canBeSheared()) { - if (!ItemUtils.hasEffect(session, equipment, EnchantmentComponent.PREVENT_ARMOR_CHANGE) || session.getGameMode() == GameMode.CREATIVE) { - return true; - } - } - } - - return false; - } - /** * Simulates interacting with this entity at a specific click point. As of Java Edition 1.18.1, this is only used for armor stands. */ diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java index c5c610b82..363ce6008 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java @@ -44,8 +44,6 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.vehicle.ClientVehicle; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; -import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; @@ -63,9 +61,7 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatE import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; -import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ColorParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; @@ -81,7 +77,7 @@ import java.util.UUID; @Getter @Setter public class LivingEntity extends Entity { - protected EnumMap equipment = new EnumMap<>(EquipmentSlot.class); + protected EnumMap equipment = new EnumMap<>(EquipmentSlot.class); protected ItemData helmet = ItemData.AIR; protected ItemData chestplate = ItemData.AIR; @@ -119,54 +115,52 @@ public class LivingEntity extends Entity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - public void setHelmet(ItemStack stack) { + public void setHelmet(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.HELMET, stack); this.helmet = ItemTranslator.translateToBedrock(session, stack); } - public void setChestplate(ItemStack stack) { + public void setChestplate(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.CHESTPLATE, stack); this.chestplate = ItemTranslator.translateToBedrock(session, stack); } - public void setLeggings(ItemStack stack) { + public void setLeggings(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.LEGGINGS, stack); this.leggings = ItemTranslator.translateToBedrock(session, stack); } - public void setBoots(ItemStack stack) { + public void setBoots(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.BOOTS, stack); this.boots = ItemTranslator.translateToBedrock(session, stack); } - public void setBody(ItemStack stack) { + public void setBody(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.BODY, stack); this.body = ItemTranslator.translateToBedrock(session, stack); } - public void setSaddle(@Nullable ItemStack stack) { + public void setSaddle(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.SADDLE, stack); this.saddle = ItemTranslator.translateToBedrock(session, stack); boolean saddled = false; - if (stack != null) { - Item item = Registries.JAVA_ITEMS.get(stack.getId()); - if (item != null) { - DataComponents components = item.gatherComponents(stack.getDataComponentsPatch()); - Equippable equippable = components.get(DataComponentTypes.EQUIPPABLE); - saddled = equippable != null && equippable.slot() == EquipmentSlot.SADDLE; - } + if (!stack.isEmpty()) { + Equippable equippable = stack.getComponent(DataComponentTypes.EQUIPPABLE); + saddled = equippable != null && equippable.slot() == EquipmentSlot.SADDLE; } updateSaddled(saddled); } - public void setHand(ItemStack stack) { + public void setHand(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.MAIN_HAND, stack); + this.hand = ItemTranslator.translateToBedrock(session, stack); } - public void setOffhand(ItemStack stack) { + public void setOffhand(GeyserItemStack stack) { this.equipment.put(EquipmentSlot.OFF_HAND, stack); + this.offhand = ItemTranslator.translateToBedrock(session, stack); } protected void updateSaddled(boolean saddled) { @@ -181,7 +175,7 @@ public class LivingEntity extends Entity { } public void switchHands() { - ItemStack javaOffhand = this.equipment.get(EquipmentSlot.OFF_HAND); + GeyserItemStack javaOffhand = this.equipment.get(EquipmentSlot.OFF_HAND); this.equipment.put(EquipmentSlot.OFF_HAND, this.equipment.get(EquipmentSlot.MAIN_HAND)); this.equipment.put(EquipmentSlot.MAIN_HAND, javaOffhand); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index e1c82345f..afbdcca31 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -36,6 +36,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.LivingEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; @@ -45,7 +46,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetad import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.Optional; import java.util.UUID; @@ -266,37 +266,37 @@ public class ArmorStandEntity extends LivingEntity { } @Override - public void setHelmet(ItemStack helmet) { + public void setHelmet(GeyserItemStack helmet) { super.setHelmet(helmet); updateSecondEntityStatus(true); } @Override - public void setChestplate(ItemStack chestplate) { + public void setChestplate(GeyserItemStack chestplate) { super.setChestplate(chestplate); updateSecondEntityStatus(true); } @Override - public void setLeggings(ItemStack leggings) { + public void setLeggings(GeyserItemStack leggings) { super.setLeggings(leggings); updateSecondEntityStatus(true); } @Override - public void setBoots(ItemStack boots) { + public void setBoots(GeyserItemStack boots) { super.setBoots(boots); updateSecondEntityStatus(true); } @Override - public void setHand(ItemStack hand) { + public void setHand(GeyserItemStack hand) { super.setHand(hand); updateSecondEntityStatus(true); } @Override - public void setOffhand(ItemStack offHand) { + public void setOffhand(GeyserItemStack offHand) { super.setOffhand(offHand); updateSecondEntityStatus(true); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java index ca5fe3f6d..558bffd99 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java @@ -34,12 +34,18 @@ import org.geysermc.geyser.entity.type.Leashable; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.item.enchantment.EnchantmentComponent; import org.geysermc.geyser.item.type.SpawnEggItem; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.geyser.util.ItemUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; +import org.geysermc.mcprotocollib.protocol.data.game.item.component.Equippable; import java.util.UUID; @@ -108,6 +114,26 @@ public class MobEntity extends LivingEntity implements Leashable { } } + public boolean canShearEquipment() { + if (!passengers.isEmpty()) { + return false; + } + + for (EquipmentSlot slot : EquipmentSlot.values()) { + GeyserItemStack equipped = equipment.get(slot); + if (equipped == null || equipped.isEmpty()) continue; + + Equippable equippable = equipped.getComponent(DataComponentTypes.EQUIPPABLE); + if (equippable != null && equippable.canBeSheared()) { + if (!ItemUtils.hasEffect(session, equipped, EnchantmentComponent.PREVENT_ARMOR_CHANGE) || session.getGameMode() == GameMode.CREATIVE) { + return true; + } + } + } + + return false; + } + private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) { if (itemInHand.asItem() == Items.NAME_TAG) { InteractionResult result = checkInteractWithNameTag(itemInHand); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java index 0b00f6ea1..46911480e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java @@ -51,7 +51,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEn import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; @@ -130,11 +129,10 @@ public class WolfEntity extends TameableEntity implements VariantIntHolder { } @Override - public void setBody(ItemStack stack) { + public void setBody(GeyserItemStack stack) { super.setBody(stack); isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); - // Not using ItemStack#getDataComponents as that wouldn't include default item components - repairableItems = GeyserItemStack.from(stack).getComponent(DataComponentTypes.REPAIRABLE); + repairableItems = stack.getComponent(DataComponentTypes.REPAIRABLE); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index 19b6d8e69..36c412ba7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -42,7 +42,6 @@ import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; @@ -71,9 +70,9 @@ public class PiglinEntity extends BasePiglinEntity { } @Override - public void setHand(ItemStack stack) { + public void setHand(GeyserItemStack stack) { ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); - boolean toCrossbow = stack != null && stack.getId() == crossbow.getJavaItem().javaId(); + boolean toCrossbow = stack != null && stack.asItem() == crossbow.getJavaItem(); if (toCrossbow ^ this.hand.getDefinition() == crossbow.getBedrockDefinition()) { // If switching to/from crossbow dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(toCrossbow ? 0 : 1)); diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java index d7532333a..a38bbb272 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java @@ -169,6 +169,22 @@ public final class ItemTranslator { .build(); } + @NonNull + public static ItemData translateToBedrock(GeyserSession session, @NonNull GeyserItemStack stack) { + if (stack.isEmpty()) { + return ItemData.AIR; + } + + ItemMapping bedrockItem = session.getItemMappings().getMapping(stack.getJavaId()); + if (bedrockItem == ItemMapping.AIR) { + session.getGeyser().getLogger().debug("ItemMapping returned air: " + stack); + return ItemData.AIR; + } + + return translateToBedrock(session, stack.asItem(), bedrockItem, stack.getAmount(), stack.getComponents()) + .build(); + } + public static ItemData.@NonNull Builder translateToBedrock(GeyserSession session, Item javaItem, ItemMapping bedrockItem, int count, @Nullable DataComponents customComponents) { BedrockItemBuilder nbtBuilder = new BedrockItemBuilder(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java index b9d65200e..d2f1ce153 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSetEquipmentTranslator.java @@ -34,8 +34,8 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.FakeHeadProvider; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Equipment; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket; @@ -58,15 +58,12 @@ public class JavaSetEquipmentTranslator extends PacketTranslator { - ItemStack javaItem = equipment.getItem(); - if (livingEntity instanceof PlayerEntity - && javaItem != null - && javaItem.getId() == Items.PLAYER_HEAD.javaId() - && javaItem.getDataComponentsPatch() != null) { - FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, GeyserItemStack.from(javaItem).getComponent(DataComponentTypes.PROFILE)); + GameProfile profile = stack.getComponent(DataComponentTypes.PROFILE); + if (livingEntity instanceof PlayerEntity && stack.asItem() == Items.PLAYER_HEAD && profile != null) { + FakeHeadProvider.setHead(session, (PlayerEntity) livingEntity, profile); } else { FakeHeadProvider.restoreOriginalSkin(session, livingEntity); } diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index 6de64b40c..0ada5eeb3 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.util; import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.item.BedrockEnchantment; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.enchantment.Enchantment; @@ -34,7 +35,6 @@ import org.geysermc.geyser.item.type.FishingRodItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.registry.JavaRegistries; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments; @@ -66,16 +66,12 @@ public final class ItemUtils { return 0; } - public static boolean hasEffect(GeyserSession session, @Nullable ItemStack itemStack, EnchantmentComponent component) { - if (itemStack == null) { - return false; - } - DataComponents components = itemStack.getDataComponentsPatch(); - if (components == null) { + public static boolean hasEffect(GeyserSession session, @Nullable GeyserItemStack itemStack, EnchantmentComponent component) { + if (itemStack == null || itemStack.isEmpty()) { return false; } - ItemEnchantments enchantmentData = components.get(DataComponentTypes.ENCHANTMENTS); + ItemEnchantments enchantmentData = itemStack.getComponent(DataComponentTypes.ENCHANTMENTS); if (enchantmentData == null) { return false; }