From 756c38d1e41620427696b20415b27174d392910d Mon Sep 17 00:00:00 2001
From: md_5 <git@md-5.net>
Date: Wed, 2 Jan 2019 15:56:21 +1100
Subject: [PATCH] Add RecipeChoice.ExactChoice API for NBT matches on
 ingredients

---
 nms-patches/FurnaceRecipe.patch               | 13 ++------
 nms-patches/RecipeItemStack.patch             | 26 ++++++++++++++++
 nms-patches/ShapedRecipes.patch               | 18 +++++------
 nms-patches/ShapelessRecipes.patch            | 16 +++-------
 .../craftbukkit/inventory/CraftRecipe.java    | 30 +++++++++++++++++++
 5 files changed, 71 insertions(+), 32 deletions(-)
 create mode 100644 nms-patches/RecipeItemStack.patch

diff --git a/nms-patches/FurnaceRecipe.patch b/nms-patches/FurnaceRecipe.patch
index ef5091f17e..e9b367f873 100644
--- a/nms-patches/FurnaceRecipe.patch
+++ b/nms-patches/FurnaceRecipe.patch
@@ -9,30 +9,23 @@
 +import java.util.List;
 +import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
 +import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
 +import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 +import org.bukkit.craftbukkit.util.CraftNamespacedKey;
 +import org.bukkit.inventory.Recipe;
-+import org.bukkit.inventory.RecipeChoice;
 +// CraftBukkit end
  
  public class FurnaceRecipe implements IRecipe {
  
-@@ -56,6 +66,23 @@
+@@ -56,6 +66,16 @@
          return this.key;
      }
  
 +    @Override
 +    public Recipe toBukkitRecipe() {
 +        CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
-+        RecipeItemStack list = this.ingredient;
-+        list.buildChoices();
 +
-+        List<org.bukkit.Material> choices = new ArrayList<>(list.choices.length);
-+        for (ItemStack i : list.choices) {
-+            choices.add(CraftMagicNumbers.getMaterial(i.getItem()));
-+        }
-+
-+        CraftFurnaceRecipe recipe = new CraftFurnaceRecipe(CraftNamespacedKey.fromMinecraft(this.key), result, new RecipeChoice.MaterialChoice(choices), this.experience, this.cookingTime);
++        CraftFurnaceRecipe recipe = new CraftFurnaceRecipe(CraftNamespacedKey.fromMinecraft(this.key), result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
 +        recipe.setGroup(this.group);
 +
 +        return recipe;
diff --git a/nms-patches/RecipeItemStack.patch b/nms-patches/RecipeItemStack.patch
new file mode 100644
index 0000000000..e70da7f459
--- /dev/null
+++ b/nms-patches/RecipeItemStack.patch
@@ -0,0 +1,26 @@
+--- a/net/minecraft/server/RecipeItemStack.java
++++ b/net/minecraft/server/RecipeItemStack.java
+@@ -28,6 +28,7 @@
+     private final RecipeItemStack.Provider[] c;
+     public ItemStack[] choices;
+     private IntList e;
++    public boolean exact; // CraftBukkit
+ 
+     public RecipeItemStack(Stream<? extends RecipeItemStack.Provider> stream) {
+         this.c = (RecipeItemStack.Provider[]) stream.filter(RecipeItemStack.b).toArray((i) -> {
+@@ -59,6 +60,15 @@
+             for (int j = 0; j < i; ++j) {
+                 ItemStack itemstack1 = aitemstack[j];
+ 
++                // CraftBukkit start
++                if (exact) {
++                    if (ItemStack.equals(itemstack, itemstack1)) {
++                        return true;
++                    }
++
++                    continue;
++                }
++                // CraftBukkit end
+                 if (itemstack1.getItem() == itemstack.getItem()) {
+                     return true;
+                 }
diff --git a/nms-patches/ShapedRecipes.patch b/nms-patches/ShapedRecipes.patch
index b2b1e08087..1ec2b7d366 100644
--- a/nms-patches/ShapedRecipes.patch
+++ b/nms-patches/ShapedRecipes.patch
@@ -1,6 +1,6 @@
 --- a/net/minecraft/server/ShapedRecipes.java
 +++ b/net/minecraft/server/ShapedRecipes.java
-@@ -12,6 +12,13 @@
+@@ -12,6 +12,15 @@
  import java.util.Map;
  import java.util.Set;
  import java.util.Map.Entry;
@@ -8,13 +8,15 @@
 +import java.util.ArrayList;
 +import java.util.List;
 +import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
 +import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
 +import org.bukkit.craftbukkit.util.CraftMagicNumbers;
++import org.bukkit.inventory.RecipeChoice;
 +// CraftBukkit end
  
  public class ShapedRecipes implements IRecipe {
  
-@@ -31,6 +38,70 @@
+@@ -31,6 +40,66 @@
          this.result = itemstack;
      }
  
@@ -67,15 +69,11 @@
 +        }
 +        char c = 'a';
 +        for (RecipeItemStack list : this.items) {
-+            list.buildChoices();
-+            if (list.choices.length > 0) {
-+                List<org.bukkit.Material> choices = new ArrayList<>(list.choices.length);
-+                for (ItemStack i : list.choices) {
-+                    choices.add(CraftMagicNumbers.getMaterial(i.getItem()));
-+                }
-+
-+                recipe.setIngredient(c, new org.bukkit.inventory.RecipeChoice.MaterialChoice(choices));
++            RecipeChoice choice = CraftRecipe.toBukkit(list);
++            if (choice != null) {
++                recipe.setIngredient(c, choice);
 +            }
++
 +            c++;
 +        }
 +        return recipe;
diff --git a/nms-patches/ShapelessRecipes.patch b/nms-patches/ShapelessRecipes.patch
index 9e7a932a40..dfc03324a7 100644
--- a/nms-patches/ShapelessRecipes.patch
+++ b/nms-patches/ShapelessRecipes.patch
@@ -1,20 +1,18 @@
 --- a/net/minecraft/server/ShapelessRecipes.java
 +++ b/net/minecraft/server/ShapelessRecipes.java
-@@ -5,6 +5,13 @@
+@@ -5,6 +5,11 @@
  import com.google.gson.JsonParseException;
  import it.unimi.dsi.fastutil.ints.IntList;
  import java.util.Iterator;
 +// CraftBukkit start
-+import java.util.ArrayList;
-+import java.util.List;
 +import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
 +import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
-+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 +// CraftBukkit end
  
  public class ShapelessRecipes implements IRecipe {
  
-@@ -20,6 +27,26 @@
+@@ -20,6 +25,20 @@
          this.ingredients = nonnulllist;
      }
  
@@ -26,13 +24,7 @@
 +        recipe.setGroup(this.group);
 +
 +        for (RecipeItemStack list : this.ingredients) {
-+            list.buildChoices();
-+
-+            List<org.bukkit.Material> choices = new ArrayList<>(list.choices.length);
-+            for (ItemStack i : list.choices) {
-+                choices.add(CraftMagicNumbers.getMaterial(i.getItem()));
-+            }
-+            recipe.addIngredient(new org.bukkit.inventory.RecipeChoice.MaterialChoice(choices));
++            recipe.addIngredient(CraftRecipe.toBukkit(list));
 +        }
 +        return recipe;
 +    }
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
index 3a704d1070..3309f32691 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
@@ -1,6 +1,11 @@
 package org.bukkit.craftbukkit.inventory;
 
+import com.google.common.base.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
 import net.minecraft.server.RecipeItemStack;
+import org.bukkit.craftbukkit.util.CraftMagicNumbers;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.Recipe;
 import org.bukkit.inventory.RecipeChoice;
@@ -14,8 +19,33 @@ public interface CraftRecipe extends Recipe {
             return RecipeItemStack.a;
         } else if (bukkit instanceof RecipeChoice.MaterialChoice) {
             return new RecipeItemStack(((RecipeChoice.MaterialChoice) bukkit).getChoices().stream().map((mat) -> new net.minecraft.server.RecipeItemStack.StackProvider(CraftItemStack.asNMSCopy(new ItemStack(mat)))));
+        } else if (bukkit instanceof RecipeChoice.ExactChoice) {
+            RecipeItemStack stack = new RecipeItemStack(Stream.of(new net.minecraft.server.RecipeItemStack.StackProvider(CraftItemStack.asNMSCopy(((RecipeChoice.ExactChoice) bukkit).getItemStack()))));
+            stack.exact = true;
+
+            return stack;
         } else {
             throw new IllegalArgumentException("Unknown recipe stack instance " + bukkit);
         }
     }
+
+    public static RecipeChoice toBukkit(RecipeItemStack list) {
+        list.buildChoices();
+
+        if (list.choices.length == 0) {
+            return null;
+        }
+
+        if (list.exact) {
+            Preconditions.checkState(list.choices.length == 1, "Exact recipe must have 1 choice");
+            return new RecipeChoice.ExactChoice(CraftItemStack.asBukkitCopy(list.choices[0]));
+        }
+
+        List<org.bukkit.Material> choices = new ArrayList<>(list.choices.length);
+        for (net.minecraft.server.ItemStack i : list.choices) {
+            choices.add(CraftMagicNumbers.getMaterial(i.getItem()));
+        }
+
+        return new RecipeChoice.MaterialChoice(choices);
+    }
 }