From 62ba4fbc95fb2dd6f8c33a704a179ada422085f7 Mon Sep 17 00:00:00 2001 From: Aikar Date: Thu, 28 Feb 2019 00:02:20 -0500 Subject: [PATCH] Improve reliability of Shapeless Recipe logic per feedback from @liach about a bug with vanillas previous logic that we essentially just reverted to. complex recipes could run into cases where a recipe that does have enough items can be unsatisfied if the items are in certain orders, making them not truely shapeless. this scenario doesn't occur in vanilla, but users can load custom recipes. this improves the logic to do some sorting on the lists to improve chances of matching the recipes harder ingredients before the easier to satisfy ingredients. the likelyhood of someone adding a recipe that still fails this is too extreme to care about. i doubt mojangs implementation is perfect either. we can improve this logic more later if we actually get bug reports on it. --- ...om-Shapeless-Custom-Crafting-Recipes.patch | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/Spigot-Server-Patches/Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch b/Spigot-Server-Patches/Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch index 1e64b64fab..645c8c4b31 100644 --- a/Spigot-Server-Patches/Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch +++ b/Spigot-Server-Patches/Fix-Custom-Shapeless-Custom-Crafting-Recipes.patch @@ -10,18 +10,18 @@ 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 819b4ac2da..1dc9a1c93c 100644 +index 819b4ac2da..ea4083a45a 100644 --- a/src/main/java/net/minecraft/server/ShapelessRecipes.java +++ b/src/main/java/net/minecraft/server/ShapelessRecipes.java @@ -0,0 +0,0 @@ public class ShapelessRecipes implements IRecipe { - if (!(iinventory instanceof InventoryCrafting)) { - return false; - } else { -- AutoRecipeStackManager autorecipestackmanager = new AutoRecipeStackManager(); -- int i = 0; -- -+ // Paper start - use RecipeItemStack.test + AutoRecipeStackManager autorecipestackmanager = new AutoRecipeStackManager(); + int i = 0; + ++ // Paper start + java.util.List providedItems = new java.util.ArrayList<>(); ++ co.aikar.util.Counter matchedProvided = new co.aikar.util.Counter<>(); ++ co.aikar.util.Counter matchedIngredients = new co.aikar.util.Counter<>(); ++ // Paper end for (int j = 0; j < iinventory.n(); ++j) { for (int k = 0; k < iinventory.U_(); ++k) { ItemStack itemstack = iinventory.getItem(k + j * iinventory.U_()); @@ -29,13 +29,25 @@ index 819b4ac2da..1dc9a1c93c 100644 if (!itemstack.isEmpty()) { - ++i; - autorecipestackmanager.b(new ItemStack(itemstack.getItem())); -+ providedItems.add(itemstack.cloneItemStack()); ++ // 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 + java.util.List 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) {