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


diff --git a/src/main/java/com/destroystokyo/paper/Namespaced.java b/src/main/java/com/destroystokyo/paper/Namespaced.java
new file mode 100644
index 0000000000000000000000000000000000000000..e708cc48f480e91a60834897e447e4a2fc1244d4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/Namespaced.java
@@ -0,0 +1,41 @@
+package com.destroystokyo.paper;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Represents a namespaced resource, see {@link org.bukkit.NamespacedKey} for single elements
+ * or {@link com.destroystokyo.paper.NamespacedTag} for a collection of elements
+ *
+ * Namespaces may only contain lowercase alphanumeric characters, periods,
+ * underscores, and hyphens.
+ * <p>
+ * Keys may only contain lowercase alphanumeric characters, periods,
+ * underscores, hyphens, and forward slashes.
+ * <p>
+ * You should not be implementing this interface yourself, use {@link org.bukkit.NamespacedKey}
+ * or {@link com.destroystokyo.paper.NamespacedTag} as needed instead.
+ */
+@Deprecated(forRemoval = true, since = "1.20.6")
+public interface Namespaced {
+    /**
+     * Gets the namespace this resource is a part of
+     * <p>
+     * This is contractually obligated to only contain lowercase alphanumeric characters,
+     * periods, underscores, and hyphens.
+     *
+     * @return resource namespace
+     */
+    @NotNull
+    String getNamespace();
+
+    /**
+     * Gets the key corresponding to this resource
+     * <p>
+     * This is contractually obligated to only contain lowercase alphanumeric characters,
+     * periods, underscores, hyphens, and forward slashes.
+     *
+     * @return resource key
+     */
+    @NotNull
+    String getKey();
+}
diff --git a/src/main/java/com/destroystokyo/paper/NamespacedTag.java b/src/main/java/com/destroystokyo/paper/NamespacedTag.java
new file mode 100644
index 0000000000000000000000000000000000000000..c976995a0fceaf0cbddd399906a866747b12a202
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/NamespacedTag.java
@@ -0,0 +1,143 @@
+package com.destroystokyo.paper;
+
+import com.google.common.base.Preconditions;
+import java.util.Locale;
+import java.util.UUID;
+import java.util.regex.Pattern;
+import org.bukkit.plugin.Plugin;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Represents a String based key pertaining to a tagged entry. Consists of two components - a namespace
+ * and a key.
+ * <p>
+ * Namespaces may only contain lowercase alphanumeric characters, periods,
+ * underscores, and hyphens.
+ * <p>
+ * Keys may only contain lowercase alphanumeric characters, periods,
+ * underscores, hyphens, and forward slashes.
+ *
+ */
+// Paper - entire class, based on org.bukkit.NamespacedKey
+@Deprecated(forRemoval = true, since = "1.20.6")
+public final class NamespacedTag implements com.destroystokyo.paper.Namespaced {
+
+    /**
+     * The namespace representing all inbuilt keys.
+     */
+    public static final String MINECRAFT = "minecraft";
+    /**
+     * The namespace representing all keys generated by Bukkit for backwards
+     * compatibility measures.
+     */
+    public static final String BUKKIT = "bukkit";
+    //
+    private static final Pattern VALID_NAMESPACE = Pattern.compile("[a-z0-9._-]+");
+    private static final Pattern VALID_KEY = Pattern.compile("[a-z0-9/._-]+");
+    //
+    private final String namespace;
+    private final String key;
+
+    /**
+     * Create a key in a specific namespace.
+     *
+     * @param namespace String representing a grouping of keys
+     * @param key Name for this specific key
+     * @deprecated should never be used by plugins, for internal use only!!
+     */
+    @Deprecated
+    public NamespacedTag(@NotNull String namespace, @NotNull String key) {
+        Preconditions.checkArgument(namespace != null && VALID_NAMESPACE.matcher(namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace);
+        Preconditions.checkArgument(key != null && VALID_KEY.matcher(key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", key);
+
+        this.namespace = namespace;
+        this.key = key;
+
+        String string = toString();
+        Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters", string);
+    }
+
+    /**
+     * Create a key in the plugin's namespace.
+     * <p>
+     * Namespaces may only contain lowercase alphanumeric characters, periods,
+     * underscores, and hyphens.
+     * <p>
+     * Keys may only contain lowercase alphanumeric characters, periods,
+     * underscores, hyphens, and forward slashes.
+     *
+     * @param plugin the plugin to use for the namespace
+     * @param key the key to create
+     */
+    public NamespacedTag(@NotNull Plugin plugin, @NotNull String key) {
+        Preconditions.checkArgument(plugin != null, "Plugin cannot be null");
+        Preconditions.checkArgument(key != null, "Key cannot be null");
+
+        this.namespace = plugin.getName().toLowerCase(Locale.ROOT);
+        this.key = key.toLowerCase().toLowerCase(Locale.ROOT);
+
+        // Check validity after normalization
+        Preconditions.checkArgument(VALID_NAMESPACE.matcher(this.namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace);
+        Preconditions.checkArgument(VALID_KEY.matcher(this.key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", this.key);
+
+        String string = toString();
+        Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters (%s)", string);
+    }
+
+    @NotNull
+    public String getNamespace() {
+        return namespace;
+    }
+
+    @NotNull
+    public String getKey() {
+        return key;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 47 * hash + this.namespace.hashCode();
+        hash = 47 * hash + this.key.hashCode();
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final NamespacedTag other = (NamespacedTag) obj;
+        return this.namespace.equals(other.namespace) && this.key.equals(other.key);
+    }
+
+    @Override
+    public String toString() {
+        return "#" + this.namespace + ":" + this.key;
+    }
+
+    /**
+     * Return a new random key in the {@link #BUKKIT} namespace.
+     *
+     * @return new key
+     * @deprecated should never be used by plugins, for internal use only!!
+     */
+    @Deprecated
+    public static NamespacedTag randomKey() {
+        return new NamespacedTag(BUKKIT, UUID.randomUUID().toString());
+    }
+
+    /**
+     * Get a key in the Minecraft namespace.
+     *
+     * @param key the key to use
+     * @return new key in the Minecraft namespace
+     */
+    @NotNull
+    public static NamespacedTag minecraft(@NotNull String key) {
+        return new NamespacedTag(MINECRAFT, key);
+    }
+}
diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java
index 7ff6d60deb129e23b2a4d772aee123eb6c0b6433..52a2763773b234c581b2dcc6f0584f8d8b0fbc60 100644
--- a/src/main/java/org/bukkit/NamespacedKey.java
+++ b/src/main/java/org/bukkit/NamespacedKey.java
@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable;
  * underscores, hyphens, and forward slashes.
  *
  */
-public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key
+public final class NamespacedKey implements net.kyori.adventure.key.Key, com.destroystokyo.paper.Namespaced { // Paper - implement Key and Namespaced
 
     /**
      * The namespace representing all inbuilt keys.
@@ -121,11 +121,13 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap
     }
 
     @NotNull
+    @Override // Paper
     public String getNamespace() {
         return namespace;
     }
 
     @NotNull
+    @Override // Paper
     public String getKey() {
         return key;
     }
diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java
index 3fdba38fd5e75ddcbfca9cee70a606bfa4a539bf..66219e3855aef885341132a7456af54cf315475f 100644
--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java
+++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java
@@ -1010,4 +1010,98 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste
     @SuppressWarnings("javadoc")
     @NotNull
     ItemMeta clone();
+
+    // Paper start - Add an API for can-place-on/can-break adventure mode predicates
+    /**
+     * Gets set of materials what given item can destroy in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @return Set of materials
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.14")
+    Set<org.bukkit.Material> getCanDestroy();
+
+    /**
+     * Sets set of materials what given item can destroy in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @param canDestroy Set of materials
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.14")
+    void setCanDestroy(Set<org.bukkit.Material> canDestroy);
+
+    /**
+     * Gets set of materials where given item can be placed on in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @return Set of materials
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.14")
+    Set<org.bukkit.Material> getCanPlaceOn();
+
+    /**
+     * Sets set of materials where given item can be placed on in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @param canPlaceOn Set of materials
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.14")
+    void setCanPlaceOn(Set<org.bukkit.Material> canPlaceOn);
+
+    /**
+     * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @return Set of {@link com.destroystokyo.paper.Namespaced}
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.20.6")
+    @NotNull
+    Set<com.destroystokyo.paper.Namespaced> getDestroyableKeys();
+
+    /**
+     * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced}
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.20.6")
+    void setDestroyableKeys(@NotNull Collection<com.destroystokyo.paper.Namespaced> canDestroy);
+
+    /**
+     * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @return Set of {@link com.destroystokyo.paper.Namespaced}
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @NotNull
+    @Deprecated(forRemoval = true, since = "1.20.6")
+    Set<com.destroystokyo.paper.Namespaced> getPlaceableKeys();
+
+    /**
+     * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE}
+     *
+     * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced}
+     * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates.
+     */
+    @Deprecated(forRemoval = true, since = "1.20.6")
+    void setPlaceableKeys(@NotNull Collection<com.destroystokyo.paper.Namespaced> canPlaceOn);
+
+    /**
+     * Checks for the existence of any keys that the item can be placed on
+     *
+     * @return true if this item has placeable keys
+     * @deprecated this API is unsupported and will be replaced
+     */
+    @Deprecated(forRemoval = true, since = "1.20.6")
+    boolean hasPlaceableKeys();
+
+    /**
+     * Checks for the existence of any keys that the item can destroy
+     *
+     * @return true if this item has destroyable keys
+     * @deprecated this API is unsupported and will be replaced
+     */
+    @Deprecated(forRemoval = true, since = "1.20.6")
+    boolean hasDestroyableKeys();
+    // Paper end - Add an API for can-place-on/can-break adventure mode predicates
 }