diff --git a/Spigot-API-Patches/0086-Add-ArmorStand-Item-Meta.patch b/Spigot-API-Patches/0086-Add-ArmorStand-Item-Meta.patch new file mode 100644 index 000000000..b828e84e7 --- /dev/null +++ b/Spigot-API-Patches/0086-Add-ArmorStand-Item-Meta.patch @@ -0,0 +1,99 @@ +From 5693424dde394e10b75b66196abb65c85c271dd2 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sat, 27 Jan 2018 17:06:24 -0500 +Subject: [PATCH] Add ArmorStand Item Meta + +This is adds basic item meta for armor stands. It does not add all +possible metadata however. + +There are armor, hand, and equipment types, as well as position data +that can also be added here. This initial addition should serve a +starting point for future additions in this area. + +diff --git a/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java +new file mode 100644 +index 00000000..7e4acfff +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/inventory/meta/ArmorStandMeta.java +@@ -0,0 +1,78 @@ ++package com.destroystokyo.paper.inventory.meta; ++ ++import org.bukkit.inventory.meta.ItemMeta; ++ ++public interface ArmorStandMeta extends ItemMeta { ++ ++ /** ++ * Gets whether the ArmorStand should be invisible when spawned ++ * ++ * @return true if this should be invisible ++ */ ++ boolean isInvisible(); ++ ++ /** ++ * Gets whether this ArmorStand should have no base plate when spawned ++ * ++ * @return true if it will not have a base plate ++ */ ++ boolean hasNoBasePlate(); ++ ++ /** ++ * Gets whether this ArmorStand should show arms when spawned ++ * ++ * @return true if it will show arms ++ */ ++ boolean shouldShowArms(); ++ ++ /** ++ * Gets whether this ArmorStand will be small when spawned ++ * ++ * @return true if it will be small ++ */ ++ boolean isSmall(); ++ ++ /** ++ * Gets whether this ArmorStand will be a marker when spawned ++ * The exact details of this flag are an implementation detail ++ * ++ * @return true if it will be a marker ++ */ ++ boolean isMarker(); ++ ++ /** ++ * Sets that this ArmorStand should be invisible when spawned ++ * ++ * @param invisible true if set invisible ++ */ ++ void setInvisible(boolean invisible); ++ ++ /** ++ * Sets that this ArmorStand should have no base plate when spawned ++ * ++ * @param noBasePlate true if no base plate ++ */ ++ void setNoBasePlate(boolean noBasePlate); ++ ++ /** ++ * Sets that this ArmorStand should show arms when spawned ++ * ++ * @param showArms true if show arms ++ */ ++ void setShowArms(boolean showArms); ++ ++ /** ++ * Sets that this ArmorStand should be small when spawned ++ * ++ * @param small true if small ++ */ ++ void setSmall(boolean small); ++ ++ /** ++ * Sets that this ArmorStand should be a marker when spawned ++ * The exact details of this flag are an implementation detail ++ * ++ * @param marker true if a marker ++ */ ++ void setMarker(boolean marker); ++} +-- +2.14.3 + diff --git a/Spigot-Server-Patches/0269-Add-ArmorStand-Item-Meta.patch b/Spigot-Server-Patches/0269-Add-ArmorStand-Item-Meta.patch new file mode 100644 index 000000000..03b6b7fe1 --- /dev/null +++ b/Spigot-Server-Patches/0269-Add-ArmorStand-Item-Meta.patch @@ -0,0 +1,403 @@ +From 67cd6fe88d1ff2f141e122db653a648877c14bbb Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Sat, 27 Jan 2018 17:04:14 -0500 +Subject: [PATCH] Add ArmorStand Item Meta + +This is adds basic item meta for armor stands. It does not add all +possible metadata however. + +There are armor, hand, and equipment types, as well as position data +that can also be added here. This initial addition should serve a +starting point for future additions in this area. + +Fixes GH-559 + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +index c2f26577c..851960afb 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +@@ -96,6 +96,8 @@ public final class CraftItemFactory implements ItemFactory { + return meta instanceof CraftMetaSpawnEgg ? meta : new CraftMetaSpawnEgg(meta); + case KNOWLEDGE_BOOK: + return meta instanceof CraftMetaKnowledgeBook ? meta : new CraftMetaKnowledgeBook(meta); ++ case ARMOR_STAND: ++ return meta instanceof CraftMetaArmorStand ? meta : new CraftMetaArmorStand(meta); // Paper + case FURNACE: + case CHEST: + case TRAPPED_CHEST: +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index cdf16e15a..aa99254ff 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -307,6 +307,8 @@ public final class CraftItemStack extends ItemStack { + return new CraftMetaSpawnEgg(item.getTag()); + case KNOWLEDGE_BOOK: + return new CraftMetaKnowledgeBook(item.getTag()); ++ case ARMOR_STAND: ++ return new CraftMetaArmorStand(item.getTag()); // Paper + case FURNACE: + case CHEST: + case TRAPPED_CHEST: +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +new file mode 100644 +index 000000000..dc372f6db +--- /dev/null ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java +@@ -0,0 +1,305 @@ ++package org.bukkit.craftbukkit.inventory; ++ ++import com.destroystokyo.paper.inventory.meta.ArmorStandMeta; ++import com.google.common.collect.ImmutableMap; ++import net.minecraft.server.DataConverterTypes; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.NBTBase; ++import net.minecraft.server.NBTTagCompound; ++import org.bukkit.Material; ++import org.bukkit.configuration.serialization.DelegateDeserialization; ++ ++import java.util.Map; ++ ++// Paper - Created entire class ++@DelegateDeserialization(CraftMetaItem.SerializableMeta.class) ++public class CraftMetaArmorStand extends CraftMetaItem implements ArmorStandMeta { ++ ++ static final ItemMetaKey ENTITY_TAG = new ItemMetaKey("EntityTag", "entity-tag"); ++ 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"); ++ ++ private NBTTagCompound entityTag; ++ ++ private boolean invisible; ++ private boolean noBasePlate; ++ private boolean showArms; ++ private boolean small; ++ private boolean marker; ++ ++ CraftMetaArmorStand(CraftMetaItem meta) { ++ super(meta); ++ ++ if (!(meta instanceof CraftMetaArmorStand)) { ++ return; ++ } ++ ++ CraftMetaArmorStand standMeta = (CraftMetaArmorStand) meta; ++ this.invisible = standMeta.invisible; ++ this.noBasePlate = standMeta.noBasePlate; ++ this.showArms = standMeta.showArms; ++ this.small = standMeta.small; ++ this.marker = standMeta.marker; ++ } ++ ++ CraftMetaArmorStand(NBTTagCompound tag) { ++ super(tag); ++ ++ if (tag.hasKey(ENTITY_TAG.NBT)) { ++ entityTag = tag.getCompound(ENTITY_TAG.NBT); ++ ++ if (entityTag.hasKey(INVISIBLE.NBT)) { ++ invisible = entityTag.getBoolean(INVISIBLE.NBT); ++ } ++ ++ if (entityTag.hasKey(NO_BASE_PLATE.NBT)) { ++ noBasePlate = entityTag.getBoolean(NO_BASE_PLATE.NBT); ++ } ++ ++ if (entityTag.hasKey(SHOW_ARMS.NBT)) { ++ showArms = entityTag.getBoolean(SHOW_ARMS.NBT); ++ } ++ ++ if (entityTag.hasKey(SMALL.NBT)) { ++ small = entityTag.getBoolean(SMALL.NBT); ++ } ++ ++ if (entityTag.hasKey(MARKER.NBT)) { ++ marker = entityTag.getBoolean(MARKER.NBT); ++ } ++ } ++ } ++ ++ CraftMetaArmorStand(Map map) { ++ super(map); ++ ++ boolean invis = SerializableMeta.getBoolean(map, INVISIBLE.BUKKIT); ++ boolean noBase = SerializableMeta.getBoolean(map, NO_BASE_PLATE.BUKKIT); ++ boolean showArms = SerializableMeta.getBoolean(map, SHOW_ARMS.BUKKIT); ++ boolean small = SerializableMeta.getBoolean(map, SMALL.BUKKIT); ++ boolean marker = SerializableMeta.getBoolean(map, MARKER.BUKKIT); ++ ++ this.invisible = invis; ++ this.noBasePlate = noBase; ++ this.showArms = showArms; ++ this.small = small; ++ this.marker = marker; ++ } ++ ++ @Override ++ void applyToItem(NBTTagCompound tag) { ++ super.applyToItem(tag); ++ ++ if (!isArmorStandEmpty() && entityTag == null) { ++ entityTag = new NBTTagCompound(); ++ } ++ ++ if (isInvisible()) { ++ entityTag.setBoolean(INVISIBLE.NBT, invisible); ++ } ++ ++ if (hasNoBasePlate()) { ++ entityTag.setBoolean(NO_BASE_PLATE.NBT, noBasePlate); ++ } ++ ++ if (shouldShowArms()) { ++ entityTag.setBoolean(SHOW_ARMS.NBT, showArms); ++ } ++ ++ if (isSmall()) { ++ entityTag.setBoolean(SMALL.NBT, small); ++ } ++ ++ if (isMarker()) { ++ entityTag.setBoolean(MARKER.NBT, marker); ++ } ++ ++ if (entityTag != null) { ++ tag.set(ENTITY_TAG.NBT, entityTag); ++ } ++ } ++ ++ @Override ++ boolean applicableTo(Material type) { ++ switch (type) { ++ case ARMOR_STAND: ++ return true; ++ default: ++ return false; ++ } ++ } ++ ++ @Override ++ boolean isEmpty() { ++ return super.isEmpty() && isArmorStandEmpty(); ++ } ++ ++ boolean isArmorStandEmpty() { ++ return !(isInvisible() || hasNoBasePlate() || shouldShowArms() || isSmall() || isMarker() || entityTag != null); ++ } ++ ++ @Override ++ ImmutableMap.Builder serialize(ImmutableMap.Builder builder) { ++ super.serialize(builder); ++ ++ if (isInvisible()) { ++ builder.put(INVISIBLE.BUKKIT, invisible); ++ } ++ ++ if (hasNoBasePlate()) { ++ builder.put(NO_BASE_PLATE.BUKKIT, noBasePlate); ++ } ++ ++ if (shouldShowArms()) { ++ builder.put(SHOW_ARMS.BUKKIT, showArms); ++ } ++ ++ if (isSmall()) { ++ builder.put(SMALL.BUKKIT, small); ++ } ++ ++ if (isMarker()) { ++ builder.put(MARKER.BUKKIT, marker); ++ } ++ ++ return builder; ++ } ++ ++ @Override ++ void deserializeInternal(NBTTagCompound tag) { ++ super.deserializeInternal(tag); ++ ++ if (tag.hasKey(ENTITY_TAG.NBT)) { ++ entityTag = tag.getCompound(ENTITY_TAG.NBT); ++ MinecraftServer.getServer().dataConverterManager.a(DataConverterTypes.ENTITY, entityTag); // PAIL: convert ++ ++ if (entityTag.hasKey(INVISIBLE.NBT)) { ++ invisible = entityTag.getBoolean(INVISIBLE.NBT); ++ } ++ ++ if (entityTag.hasKey(NO_BASE_PLATE.NBT)) { ++ noBasePlate = entityTag.getBoolean(NO_BASE_PLATE.NBT); ++ } ++ ++ if (entityTag.hasKey(SHOW_ARMS.NBT)) { ++ showArms = entityTag.getBoolean(SHOW_ARMS.NBT); ++ } ++ ++ if (entityTag.hasKey(SMALL.NBT)) { ++ small = entityTag.getBoolean(SMALL.NBT); ++ } ++ ++ if (entityTag.hasKey(MARKER.NBT)) { ++ marker = entityTag.getBoolean(MARKER.NBT); ++ } ++ } ++ } ++ ++ @Override ++ boolean equalsCommon(CraftMetaItem meta) { ++ if (!super.equalsCommon(meta)) { ++ return false; ++ } ++ if (meta instanceof CraftMetaArmorStand) { ++ CraftMetaArmorStand that = (CraftMetaArmorStand) meta; ++ ++ return invisible == that.invisible && ++ noBasePlate == that.noBasePlate && ++ showArms == that.showArms && ++ small == that.small && ++ marker == that.marker; ++ } ++ return true; ++ } ++ ++ @Override ++ boolean notUncommon(CraftMetaItem meta) { ++ return super.notUncommon(meta) && (meta instanceof CraftMetaArmorStand || isArmorStandEmpty()); ++ } ++ ++ @Override ++ void serializeInternal(Map internalTags) { ++ if (entityTag != null) { ++ internalTags.put(ENTITY_TAG.NBT, entityTag); ++ } ++ } ++ ++ @Override ++ public boolean isInvisible() { ++ return invisible; ++ } ++ ++ @Override ++ public boolean hasNoBasePlate() { ++ return noBasePlate; ++ } ++ ++ @Override ++ public boolean shouldShowArms() { ++ return showArms; ++ } ++ ++ @Override ++ public boolean isSmall() { ++ return small; ++ } ++ ++ @Override ++ public boolean isMarker() { ++ return marker; ++ } ++ ++ @Override ++ public void setInvisible(boolean invisible) { ++ this.invisible = invisible; ++ } ++ ++ @Override ++ public void setNoBasePlate(boolean noBasePlate) { ++ this.noBasePlate = noBasePlate; ++ } ++ ++ @Override ++ public void setShowArms(boolean showArms) { ++ this.showArms = showArms; ++ } ++ ++ @Override ++ public void setSmall(boolean small) { ++ this.small = small; ++ } ++ ++ @Override ++ public void setMarker(boolean marker) { ++ this.marker = marker; ++ } ++ ++ @Override ++ int applyHash() { ++ final int original; ++ int hash = original = super.applyHash(); ++ ++ hash += entityTag != null ? 73 * hash + entityTag.hashCode() : 0; ++ hash += isInvisible() ? 61 * hash + 1231 : 0; ++ hash += hasNoBasePlate() ? 61 * hash + 1231 : 0; ++ hash += shouldShowArms() ? 61 * hash + 1231 : 0; ++ hash += isSmall() ? 61 * hash + 1231 : 0; ++ hash += isMarker() ? 61 * hash + 1231 : 0; ++ ++ return original != hash ? CraftMetaArmorStand.class.hashCode() ^ hash : hash; ++ } ++ ++ @Override ++ public CraftMetaArmorStand clone() { ++ CraftMetaArmorStand clone = (CraftMetaArmorStand) super.clone(); ++ ++ if (entityTag != null) { ++ clone.entityTag = entityTag.g(); ++ } ++ ++ return clone; ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index 0cdc8007a..990d1e619 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -1034,7 +1034,15 @@ class CraftMetaItem implements ItemMeta, Repairable { + CraftMetaEnchantedBook.STORED_ENCHANTMENTS.NBT, + CraftMetaCharge.EXPLOSION.NBT, + CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, +- CraftMetaKnowledgeBook.BOOK_RECIPES.NBT ++ CraftMetaKnowledgeBook.BOOK_RECIPES.NBT, ++ // Paper start ++ CraftMetaArmorStand.ENTITY_TAG.NBT, ++ CraftMetaArmorStand.INVISIBLE.NBT, ++ CraftMetaArmorStand.NO_BASE_PLATE.NBT, ++ CraftMetaArmorStand.SHOW_ARMS.NBT, ++ CraftMetaArmorStand.SMALL.NBT, ++ CraftMetaArmorStand.MARKER.NBT ++ // Paper end + )); + } + return HANDLED_TAGS; +diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +index 1f537d584..a29731f1d 100644 +--- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java ++++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java +@@ -5,6 +5,8 @@ import static org.hamcrest.Matchers.*; + + import java.util.Arrays; + import java.util.List; ++ ++import com.destroystokyo.paper.inventory.meta.ArmorStandMeta; + import net.minecraft.server.Block; + import net.minecraft.server.ITileEntity; + import net.minecraft.server.Item; +@@ -275,6 +277,14 @@ public class ItemMetaTest extends AbstractTestingBase { + cleanStack.setItemMeta(meta); + return cleanStack; + } ++ }, ++ new StackProvider(Material.ARMOR_STAND) { ++ @Override ItemStack operate(ItemStack cleanStack) { ++ final ArmorStandMeta meta = (ArmorStandMeta) cleanStack.getItemMeta(); ++ meta.setInvisible(true); ++ cleanStack.setItemMeta(meta); ++ return cleanStack; ++ } + } + ); + +-- +2.14.3 +