diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java index 7e3199567..4f5568707 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemMetas.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.inventory; +import com.destroystokyo.paper.inventory.meta.ArmorStandMeta; import java.util.function.BiFunction; import java.util.function.Function; import net.minecraft.world.item.BannerItem; @@ -103,7 +104,7 @@ public final class CraftItemMetas { item -> new CraftMetaSpawnEgg(item.getComponentsPatch()), (type, meta) -> meta instanceof CraftMetaSpawnEgg spawnEgg ? spawnEgg : new CraftMetaSpawnEgg(meta)); - private static final ItemMetaData ARMOR_STAND_META_DATA = new ItemMetaData<>(ItemMeta.class, + private static final ItemMetaData ARMOR_STAND_META_DATA = new ItemMetaData<>(ArmorStandMeta.class, // paper item -> new CraftMetaArmorStand(item.getComponentsPatch()), (type, meta) -> meta instanceof CraftMetaArmorStand armorStand ? armorStand : new CraftMetaArmorStand(meta)); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java index c4f12f96e..ecce5d0da 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java @@ -11,9 +11,17 @@ import org.bukkit.Material; import org.bukkit.configuration.serialization.DelegateDeserialization; @DelegateDeserialization(SerializableMeta.class) -public class CraftMetaArmorStand extends CraftMetaItem { +public class CraftMetaArmorStand extends CraftMetaItem implements com.destroystokyo.paper.inventory.meta.ArmorStandMeta { // Paper static final ItemMetaKeyType ENTITY_TAG = new ItemMetaKeyType<>(DataComponents.ENTITY_DATA, "entity-tag"); + // Paper start + static final ItemMetaKey ENTITY_ID = new ItemMetaKey("id", "entity-id"); + static final ItemMetaKey INVISIBLE = new ItemMetaKey("Invisible", "invisible"); + static final ItemMetaKey NO_BASE_PLATE = new ItemMetaKey("NoBasePlate", "no-base-plate"); + static final ItemMetaKey SHOW_ARMS = new ItemMetaKey("ShowArms", "show-arms"); + static final ItemMetaKey SMALL = new ItemMetaKey("Small", "small"); + static final ItemMetaKey MARKER = new ItemMetaKey("Marker", "marker"); + // Paper end CompoundTag entityTag; CraftMetaArmorStand(CraftMetaItem meta) { @@ -37,6 +45,42 @@ public class CraftMetaArmorStand extends CraftMetaItem { CraftMetaArmorStand(Map map) { super(map); + // Paper start + String entityTag = SerializableMeta.getString(map, ENTITY_TAG.BUKKIT, true); + if (entityTag != null) { + java.io.ByteArrayInputStream buf = new java.io.ByteArrayInputStream(java.util.Base64.getDecoder().decode(entityTag)); + try { + this.entityTag = net.minecraft.nbt.NbtIo.readCompressed(buf, net.minecraft.nbt.NbtAccounter.unlimitedHeap()); + } catch (java.io.IOException ex) { + java.util.logging.Logger.getLogger(CraftMetaItem.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } + return; + } + SerializableMeta.getObjectOptionally(Boolean.class, map, INVISIBLE.BUKKIT, true).ifPresent((value) -> { + populateTagIfNull(); + this.entityTag.putBoolean(INVISIBLE.NBT, value); + }); + SerializableMeta.getObjectOptionally(Boolean.class, map, NO_BASE_PLATE.BUKKIT, true).ifPresent((value) -> { + populateTagIfNull(); + this.entityTag.putBoolean(NO_BASE_PLATE.NBT, value); + }); + SerializableMeta.getObjectOptionally(Boolean.class, map, SHOW_ARMS.BUKKIT, true).ifPresent((value) -> { + populateTagIfNull(); + this.entityTag.putBoolean(SHOW_ARMS.NBT, value); + }); + SerializableMeta.getObjectOptionally(Boolean.class, map, SMALL.BUKKIT, true).ifPresent((value) -> { + populateTagIfNull(); + this.entityTag.putBoolean(SMALL.NBT, value); + }); + SerializableMeta.getObjectOptionally(Boolean.class, map, MARKER.BUKKIT, true).ifPresent((value) -> { + populateTagIfNull(); + this.entityTag.putBoolean(MARKER.NBT, value); + }); + SerializableMeta.getObjectOptionally(String.class, map, ENTITY_ID, true).ifPresent((value) -> { + populateTagIfNull(); + this.entityTag.putString(ENTITY_ID.NBT, value); + }); + // Paper end } @Override @@ -45,12 +89,13 @@ public class CraftMetaArmorStand extends CraftMetaItem { if (tag.contains(CraftMetaArmorStand.ENTITY_TAG.NBT)) { this.entityTag = tag.getCompound(CraftMetaArmorStand.ENTITY_TAG.NBT); + if (!this.entityTag.contains(ENTITY_ID.NBT)) entityTag.putString(ENTITY_ID.NBT, "minecraft:armor_stand"); // Paper - fixup legacy armorstand metas that did not include this. } } @Override void serializeInternal(Map internalTags) { - if (this.entityTag != null && !this.entityTag.isEmpty()) { + if (false && this.entityTag != null && !this.entityTag.isEmpty()) { // Paper - now correctly serialised as entity tag internalTags.put(CraftMetaArmorStand.ENTITY_TAG.NBT, this.entityTag); } } @@ -75,7 +120,7 @@ public class CraftMetaArmorStand extends CraftMetaItem { } boolean isArmorStandEmpty() { - return !(this.entityTag != null); + return entityTag == null || entityTag.isEmpty(); // Paper - consider armor stand empty if tag is empty. } @Override @@ -86,7 +131,9 @@ public class CraftMetaArmorStand extends CraftMetaItem { if (meta instanceof CraftMetaArmorStand) { CraftMetaArmorStand that = (CraftMetaArmorStand) meta; - return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null; + // Paper start + return java.util.Objects.equals(this.entityTag, that.entityTag); + // Paper end } return true; } @@ -112,6 +159,21 @@ public class CraftMetaArmorStand extends CraftMetaItem { Builder serialize(Builder builder) { super.serialize(builder); + // Paper start + if (entityTag == null) { + return builder; + } else if (true) { + java.io.ByteArrayOutputStream buf = new java.io.ByteArrayOutputStream(); + try { + net.minecraft.nbt.NbtIo.writeCompressed(entityTag, buf); + } catch (java.io.IOException ex) { + java.util.logging.Logger.getLogger(CraftMetaItem.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); + } + builder.put(ENTITY_TAG.BUKKIT, java.util.Base64.getEncoder().encodeToString(buf.toByteArray())); + return builder; + } + // Paper end + return builder; } @@ -125,4 +187,68 @@ public class CraftMetaArmorStand extends CraftMetaItem { return clone; } + + // Paper start + private void populateTagIfNull() { + if (this.entityTag == null) { + this.entityTag = new CompoundTag(); + this.entityTag.putString(ENTITY_ID.NBT, "minecraft:armor_stand"); + } + } + + @Override + public boolean isInvisible() { + return entityTag != null && entityTag.contains(INVISIBLE.NBT) && entityTag.getBoolean(INVISIBLE.NBT); + } + + @Override + public boolean hasNoBasePlate() { + return entityTag != null && entityTag.contains(NO_BASE_PLATE.NBT) && entityTag.getBoolean(NO_BASE_PLATE.NBT); + } + + @Override + public boolean shouldShowArms() { + return entityTag != null && entityTag.contains(SHOW_ARMS.NBT) && entityTag.getBoolean(SHOW_ARMS.NBT); + } + + @Override + public boolean isSmall() { + return entityTag != null && entityTag.contains(SMALL.NBT) && entityTag.getBoolean(SMALL.NBT); + } + + @Override + public boolean isMarker() { + return entityTag != null && entityTag.contains(MARKER.NBT) && entityTag.getBoolean(MARKER.NBT); + } + + @Override + public void setInvisible(boolean invisible) { + populateTagIfNull(); + entityTag.putBoolean(INVISIBLE.NBT, invisible); + } + + @Override + public void setNoBasePlate(boolean noBasePlate) { + populateTagIfNull(); + entityTag.putBoolean(NO_BASE_PLATE.NBT, noBasePlate); + } + + @Override + public void setShowArms(boolean showArms) { + populateTagIfNull(); + entityTag.putBoolean(SHOW_ARMS.NBT, showArms); + } + + @Override + public void setSmall(boolean small) { + populateTagIfNull(); + entityTag.putBoolean(SMALL.NBT, small); + } + + @Override + public void setMarker(boolean marker) { + populateTagIfNull(); + entityTag.putBoolean(MARKER.NBT, marker); + } + // Paper end } diff --git a/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java index debab9859..6cc54035a 100644 --- a/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +++ b/paper-server/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java @@ -365,6 +365,7 @@ public class ItemMetaTest { final CraftMetaArmorStand meta = (CraftMetaArmorStand) cleanStack.getItemMeta(); meta.entityTag = new CompoundTag(); meta.entityTag.putBoolean("Small", true); + meta.setInvisible(true); // Paper cleanStack.setItemMeta(meta); return cleanStack; }