diff --git a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java index 4dc0998aa..025cf085b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java @@ -113,9 +113,28 @@ public class LivingEntity extends Entity { super.updateBedrockMetadata(entityMetadata, session); } - public void updateEquipment(GeyserSession session) { - if (!valid) - return; + public void updateAllEquipment(GeyserSession session) { + if (!valid) return; + + updateArmor(session); + updateMainHand(session); + updateOffHand(session); + } + + public void updateArmor(GeyserSession session) { + if (!valid) return; + + ItemData helmet = this.helmet; + ItemData chestplate = this.chestplate; + // If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock + // But don't overwrite the chestplate if it isn't empty + if (chestplate.getId() == ItemData.AIR.getId() && helmet.getId() == ItemRegistry.BANNER.getBedrockId()) { + chestplate = this.helmet; + helmet = ItemData.AIR; + } else if (chestplate.getId() == ItemRegistry.BANNER.getBedrockId()) { + // Prevent chestplate banners from showing erroneously + chestplate = ItemData.AIR; + } MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket(); armorEquipmentPacket.setRuntimeEntityId(geyserId); @@ -124,6 +143,12 @@ public class LivingEntity extends Entity { armorEquipmentPacket.setLeggings(leggings); armorEquipmentPacket.setBoots(boots); + session.sendUpstreamPacket(armorEquipmentPacket); + } + + public void updateMainHand(GeyserSession session) { + if (!valid) return; + MobEquipmentPacket handPacket = new MobEquipmentPacket(); handPacket.setRuntimeEntityId(geyserId); handPacket.setItem(hand); @@ -131,6 +156,12 @@ public class LivingEntity extends Entity { handPacket.setInventorySlot(0); handPacket.setContainerId(ContainerId.INVENTORY); + session.sendUpstreamPacket(handPacket); + } + + public void updateOffHand(GeyserSession session) { + if (!valid) return; + MobEquipmentPacket offHandPacket = new MobEquipmentPacket(); offHandPacket.setRuntimeEntityId(geyserId); offHandPacket.setItem(offHand); @@ -138,8 +169,6 @@ public class LivingEntity extends Entity { offHandPacket.setInventorySlot(0); offHandPacket.setContainerId(ContainerId.OFFHAND); - session.sendUpstreamPacket(armorEquipmentPacket); - session.sendUpstreamPacket(handPacket); session.sendUpstreamPacket(offHandPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java index 794023919..e6e509b11 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java @@ -59,11 +59,13 @@ public class PiglinEntity extends BasePiglinEntity { } @Override - public void updateEquipment(GeyserSession session) { - // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly - metadata.getFlags().setFlag(EntityFlag.ADMIRING, offHand.getId() == ItemRegistry.GOLD.getBedrockId()); - super.updateBedrockMetadata(session); + public void updateOffHand(GeyserSession session) { + // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates + boolean changed = metadata.getFlags().setFlag(EntityFlag.ADMIRING, offHand.getId() == ItemRegistry.GOLD.getBedrockId()); + if (changed) { + super.updateBedrockMetadata(session); + } - super.updateEquipment(session); + super.updateOffHand(session); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java index 09d28fbfd..73794586f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java @@ -25,11 +25,11 @@ package org.geysermc.connector.entity.living.monster.raid; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.item.ItemRegistry; public class PillagerEntity extends AbstractIllagerEntity { @@ -38,12 +38,30 @@ public class PillagerEntity extends AbstractIllagerEntity { } @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { - // Java Edition always has the Pillager entity as positioning the crossbow - metadata.getFlags().setFlag(EntityFlag.USING_ITEM, true); - metadata.getFlags().setFlag(EntityFlag.CHARGED, true); + public void updateMainHand(GeyserSession session) { + checkForCrossbow(session); + + super.updateMainHand(session); + } + + @Override + public void updateOffHand(GeyserSession session) { + checkForCrossbow(session); + + super.updateOffHand(session); + } + + /** + * Check for a crossbow in either the mainhand or offhand. If one exists, indicate that the pillager should be posing + */ + protected void checkForCrossbow(GeyserSession session) { + boolean hasCrossbow = this.hand.getId() == ItemRegistry.CROSSBOW.getBedrockId() + || this.offHand.getId() == ItemRegistry.CROSSBOW.getBedrockId(); + boolean usingItemChanged = metadata.getFlags().setFlag(EntityFlag.USING_ITEM, hasCrossbow); + boolean chargedChanged = metadata.getFlags().setFlag(EntityFlag.CHARGED, hasCrossbow); + + if (usingItemChanged || chargedChanged) { + updateBedrockMetadata(session); } - super.updateBedrockMetadata(entityMetadata, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java index 5cef3252a..b8be69ab3 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java @@ -112,7 +112,7 @@ public class PlayerEntity extends LivingEntity { valid = true; session.sendUpstreamPacket(addPlayerPacket); - updateEquipment(session); + updateAllEquipment(session); updateBedrockAttributes(session); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java index 3f8d9ea93..d12a6c528 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java @@ -88,7 +88,7 @@ public class SkullPlayerEntity extends PlayerEntity { valid = true; session.sendUpstreamPacket(addPlayerPacket); - updateEquipment(session); + updateAllEquipment(session); updateBedrockAttributes(session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index 195ee1d2c..baf83c357 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -38,8 +38,8 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntArraySet; +import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; @@ -79,14 +79,22 @@ public class ItemRegistry { * Bamboo item entry, used in PandaEntity.java */ public static ItemEntry BAMBOO; + /** + * Banner item entry, used in LivingEntity.java + */ + public static ItemEntry BANNER; /** * Boat item entries, used in BedrockInventoryTransactionTranslator.java */ - public static IntList BOATS = new IntArrayList(); + public static final IntSet BOATS = new IntArraySet(); /** * Bucket item entries (excluding the milk bucket), used in BedrockInventoryTransactionTranslator.java */ - public static IntList BUCKETS = new IntArrayList(); + public static final IntSet BUCKETS = new IntArraySet(); + /** + * Crossbow item entry, used in PillagerEntity.java + */ + public static ItemEntry CROSSBOW; /** * Empty item bucket, used in BedrockInventoryTransactionTranslator.java */ @@ -305,6 +313,9 @@ public class ItemRegistry { case "minecraft:bamboo": BAMBOO = itemEntry; break; + case "minecraft:crossbow": + CROSSBOW = itemEntry; + break; case "minecraft:egg": EGG = itemEntry; break; @@ -320,6 +331,9 @@ public class ItemRegistry { case "minecraft:wheat": WHEAT = itemEntry; break; + case "minecraft:white_banner": // As of 1.16.220, all banners share the same Bedrock ID and differ their colors through their damage value + BANNER = itemEntry; + break; case "minecraft:writable_book": WRITABLE_BOOK = itemEntry; break; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java index d2d63cd9f..d3a1c52bc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityEquipmentTranslator.java @@ -40,9 +40,11 @@ public class JavaEntityEquipmentTranslator extends PacketTranslator