From 7a7cf18e997b10dd48a5fa887498ad7b9ef30570 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 8 Apr 2021 19:52:54 -0400 Subject: [PATCH] Fix banners on entity heads (#2110) On Bedrock, a banner must be placed in the chestplate slot in order to be visible. On Java Edition, banners are placed in the helmet slot. This commit fixes the issue by migrating banners to the chestplate spot if the chestplate spot is empty. This commit also fixes pillager poses if they're not holding a crossbow, along with a couple other optimizations. --- .../connector/entity/LivingEntity.java | 39 ++++++++++++++++--- .../entity/living/monster/PiglinEntity.java | 12 +++--- .../living/monster/raid/PillagerEntity.java | 32 +++++++++++---- .../connector/entity/player/PlayerEntity.java | 2 +- .../entity/player/SkullPlayerEntity.java | 2 +- .../translators/item/ItemRegistry.java | 22 +++++++++-- .../entity/JavaEntityEquipmentTranslator.java | 24 +++++++++++- 7 files changed, 108 insertions(+), 25 deletions(-) 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 4dc0998aaae..025cf085b72 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 void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s 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 void updateEquipment(GeyserSession session) { 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 void updateEquipment(GeyserSession session) { 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 void updateEquipment(GeyserSession session) { 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 79402391968..e6e509b11c4 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 void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession s } @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 09d28fbfd20..73794586f45 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 PillagerEntity(long entityId, long geyserId, EntityType entityType, Vecto } @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 5cef3252ad0..b8be69ab3ad 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 void spawnEntity(GeyserSession session) { 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 3f8d9ea9339..d12a6c528a4 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 void spawnEntity(GeyserSession session) { 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 195ee1d2cef..baf83c357ec 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.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 static void init() { case "minecraft:bamboo": BAMBOO = itemEntry; break; + case "minecraft:crossbow": + CROSSBOW = itemEntry; + break; case "minecraft:egg": EGG = itemEntry; break; @@ -320,6 +331,9 @@ public static void init() { 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 d2d63cd9f4c..d3a1c52bcfa 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