From fb168424520dbd77c3e78a2d2a5b1c369864a356 Mon Sep 17 00:00:00 2001
From: Mark Vainomaa <mikroskeem@mikroskeem.eu>
Date: Wed, 12 Sep 2018 18:53:55 +0300
Subject: [PATCH] Implement an API for CanPlaceOn and CanDestroy NBT values


diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index b90a02ef6f..c9d4d45564 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -252,6 +252,12 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
     static final ItemMetaKey UNBREAKABLE = new ItemMetaKey("Unbreakable");
     @Specific(Specific.To.NBT)
     static final ItemMetaKey DAMAGE = new ItemMetaKey("Damage");
+    // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+    @Specific(Specific.To.NBT)
+    static final ItemMetaKey CAN_DESTROY = new ItemMetaKey("CanDestroy");
+    @Specific(Specific.To.NBT)
+    static final ItemMetaKey CAN_PLACE_ON = new ItemMetaKey("CanPlaceOn");
+    // Paper end
 
     private IChatBaseComponent displayName;
     private IChatBaseComponent locName;
@@ -262,6 +268,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
     private int hideFlag;
     private boolean unbreakable;
     private int damage;
+    // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+    private Set<Material> canPlaceOn = Sets.newHashSet();
+    private Set<Material> canDestroy = Sets.newHashSet();
+    // Paper end
 
     private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
 
@@ -292,6 +302,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
         this.hideFlag = meta.hideFlag;
         this.unbreakable = meta.unbreakable;
         this.damage = meta.damage;
+        // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+        this.canDestroy = new java.util.HashSet<>(meta.canDestroy);
+        this.canPlaceOn = new java.util.HashSet<>(meta.canPlaceOn);
+        // Paper end
         this.unhandledTags.putAll(meta.unhandledTags);
 
         this.internalTag = meta.internalTag;
@@ -347,6 +361,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
         if (tag.hasKey(DAMAGE.NBT)) {
             damage = tag.getInt(DAMAGE.NBT);
         }
+        // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+        if (tag.hasKey(CAN_DESTROY.NBT)) {
+            NBTTagList list = tag.getList(CAN_DESTROY.NBT, CraftMagicNumbers.NBT.TAG_STRING);
+            for (int i = 0; i < list.size(); i++) {
+                Material material = Material.matchMaterial(list.getString(i), false);
+                this.canDestroy.add(material);
+            }
+        }
+
+        if (tag.hasKey(CAN_PLACE_ON.NBT)) {
+            NBTTagList list = tag.getList(CAN_PLACE_ON.NBT, CraftMagicNumbers.NBT.TAG_STRING);
+            for (int i = 0; i < list.size(); i++) {
+                Material material = Material.matchMaterial(list.getString(i), false);
+                this.canPlaceOn.add(material);
+            }
+        }
+        // Paper end
 
         Set<String> keys = tag.getKeys();
         for (String key : keys) {
@@ -567,6 +598,25 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
         if (hasDamage()) {
             itemTag.setInt(DAMAGE.NBT, damage);
         }
+        // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+        if (!this.canPlaceOn.isEmpty()) {
+            List<String> items = this.canPlaceOn.stream()
+                .map(Material::getKey)
+                .map(org.bukkit.NamespacedKey::toString)
+                .collect(java.util.stream.Collectors.toList());
+
+            itemTag.set(CAN_PLACE_ON.NBT, createStringList(items));
+        }
+
+        if (!this.canDestroy.isEmpty()) {
+            List<String> items = this.canDestroy.stream()
+                .map(Material::getKey)
+                .map(org.bukkit.NamespacedKey::toString)
+                .collect(java.util.stream.Collectors.toList());
+
+            itemTag.set(CAN_DESTROY.NBT, createStringList(items));
+        }
+        // Paper end
 
         for (Map.Entry<String, NBTBase> e : unhandledTags.entrySet()) {
             itemTag.set(e.getKey(), e.getValue());
@@ -1231,7 +1281,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
                         CraftMetaArmorStand.NO_BASE_PLATE.NBT,
                         CraftMetaArmorStand.SHOW_ARMS.NBT,
                         CraftMetaArmorStand.SMALL.NBT,
-                        CraftMetaArmorStand.MARKER.NBT
+                        CraftMetaArmorStand.MARKER.NBT,
+                        CAN_DESTROY.NBT,
+                        CAN_PLACE_ON.NBT
                         // Paper end
                 ));
             }
@@ -1278,4 +1330,35 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable {
         return spigot;
     }
     // Spigot end
+    // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
+    @Override
+    public Set<Material> getCanDestroy() {
+        return new java.util.HashSet<>(canDestroy);
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void setCanDestroy(Set<Material> canDestroy) {
+        if (canDestroy.stream().anyMatch(Material::isLegacy)) {
+            throw new IllegalArgumentException("canDestroy set must not contain any legacy materials!");
+        }
+        this.canDestroy.clear();
+        this.canDestroy.addAll(canDestroy);
+    }
+
+    @Override
+    public Set<Material> getCanPlaceOn() {
+        return new java.util.HashSet<>(canPlaceOn);
+    }
+
+    @Override
+    @SuppressWarnings("deprecation")
+    public void setCanPlaceOn(Set<Material> canPlaceOn) {
+        if (canPlaceOn.stream().anyMatch(Material::isLegacy)) {
+            throw new IllegalArgumentException("canPlaceOn set must not contain any legacy materials!");
+        }
+        this.canPlaceOn.clear();
+        this.canPlaceOn.addAll(canPlaceOn);
+    }
+    // Paper end
 }
-- 
2.19.0