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/server/ShapelessRecipes.java b/src/main/java/net/minecraft/server/ShapelessRecipes.java
index 7ba4196a9e71085c35e732b5440db3109121b195..61d88dbaa1f5c543be610ce0914b2c89d8ad40ee 100644
--- a/src/main/java/net/minecraft/server/ShapelessRecipes.java
+++ b/src/main/java/net/minecraft/server/ShapelessRecipes.java
@@ -63,16 +63,49 @@ public class ShapelessRecipes implements RecipeCrafting {
         AutoRecipeStackManager autorecipestackmanager = new AutoRecipeStackManager();
         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<RecipeItemStack> matchedIngredients = new co.aikar.util.Counter<>();
+        // Paper end
         for (int j = 0; j < inventorycrafting.getSize(); ++j) {
             ItemStack itemstack = inventorycrafting.getItem(j);
 
             if (!itemstack.isEmpty()) {
-                ++i;
-                autorecipestackmanager.a(itemstack, 1);
+                // Paper start
+                itemstack = itemstack.cloneItemStack();
+                providedItems.add(itemstack);
+                for (RecipeItemStack ingredient : ingredients) {
+                    if (ingredient.test(itemstack)) {
+                        matchedProvided.increment(itemstack);
+                        matchedIngredients.increment(ingredient);
+                    }
+                }
+                // Paper end
             }
         }
 
-        return i == this.ingredients.size() && autorecipestackmanager.a(this, (IntList) null);
+        // Paper start
+        if (matchedProvided.isEmpty() || matchedIngredients.isEmpty()) {
+            return false;
+        }
+        java.util.List<RecipeItemStack> 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((RecipeItemStack c) -> (int) matchedIngredients.getCount(c)));
+
+        PROVIDED:
+        for (ItemStack provided : providedItems) {
+            for (Iterator<RecipeItemStack> itIngredient = ingredients.iterator(); itIngredient.hasNext(); ) {
+                RecipeItemStack ingredient = itIngredient.next();
+                if (ingredient.test(provided)) {
+                    itIngredient.remove();
+                    continue PROVIDED;
+                }
+            }
+            return false;
+        }
+        return ingredients.isEmpty();
+        // Paper end
     }
 
     public ItemStack a(InventoryCrafting inventorycrafting) {
