From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 18 Jan 2019 00:08:15 -0500
Subject: [PATCH] Fix Custom Shapeless Custom Crafting Recipes

Mojang implemented Shapeless different than Shaped

This made the Bukkit RecipeChoice API not work for Shapeless.

This reimplements vanilla logic using the same test logic as Shaped

diff --git a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
index 4e1159b3188d39c998e6887c2846209c10b701f9..6b960f0a31175bcfd8d477ee5b3c4d783303cdd5 100644
--- a/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
+++ b/src/main/java/net/minecraft/world/item/crafting/ShapelessRecipe.java
@@ -76,16 +76,49 @@ public class ShapelessRecipe implements CraftingRecipe {
         StackedContents autorecipestackmanager = new StackedContents();
         int i = 0;
 
+        // Paper start
+        java.util.List<ItemStack> providedItems = new java.util.ArrayList<>();
+        co.aikar.util.Counter<ItemStack> matchedProvided = new co.aikar.util.Counter<>();
+        co.aikar.util.Counter<Ingredient> matchedIngredients = new co.aikar.util.Counter<>();
+        // Paper end
         for (int j = 0; j < inventory.getContainerSize(); ++j) {
             ItemStack itemstack = inventory.getItem(j);
 
             if (!itemstack.isEmpty()) {
-                ++i;
-                autorecipestackmanager.accountStack(itemstack, 1);
+                // Paper start
+                itemstack = itemstack.copy();
+                providedItems.add(itemstack);
+                for (Ingredient ingredient : ingredients) {
+                    if (ingredient.test(itemstack)) {
+                        matchedProvided.increment(itemstack);
+                        matchedIngredients.increment(ingredient);
+                    }
+                }
+                // Paper end
             }
         }
 
-        return i == this.ingredients.size() && autorecipestackmanager.canCraft(this, (IntList) null);
+        // Paper start
+        if (matchedProvided.isEmpty() || matchedIngredients.isEmpty()) {
+            return false;
+        }
+        java.util.List<Ingredient> ingredients = new java.util.ArrayList<>(this.ingredients);
+        providedItems.sort(java.util.Comparator.comparingInt((ItemStack c) -> (int) matchedProvided.getCount(c)).reversed());
+        ingredients.sort(java.util.Comparator.comparingInt((Ingredient c) -> (int) matchedIngredients.getCount(c)));
+
+        PROVIDED:
+        for (ItemStack provided : providedItems) {
+            for (Iterator<Ingredient> itIngredient = ingredients.iterator(); itIngredient.hasNext(); ) {
+                Ingredient ingredient = itIngredient.next();
+                if (ingredient.test(provided)) {
+                    itIngredient.remove();
+                    continue PROVIDED;
+                }
+            }
+            return false;
+        }
+        return ingredients.isEmpty();
+        // Paper end
     }
 
     public ItemStack assemble(CraftingContainer inventory) {
