--- a/net/minecraft/world/item/crafting/RecipeItemStack.java
+++ b/net/minecraft/world/item/crafting/RecipeItemStack.java
@@ -21,6 +21,11 @@
 import net.minecraft.world.item.crafting.display.SlotDisplay;
 import net.minecraft.world.level.IMaterial;
 
+// CraftBukkit start
+import java.util.List;
+import javax.annotation.Nullable;
+// CraftBukkit end
+
 public final class RecipeItemStack implements AutoRecipeStackManager.a<Holder<Item>>, Predicate<ItemStack> {
 
     public static final StreamCodec<RegistryFriendlyByteBuf, RecipeItemStack> CONTENTS_STREAM_CODEC = ByteBufCodecs.holderSet(Registries.ITEM).map(RecipeItemStack::new, (recipeitemstack) -> {
@@ -38,6 +43,24 @@
         return recipeitemstack.values;
     });
     private final HolderSet<Item> values;
+    // CraftBukkit start
+    @Nullable
+    private List<ItemStack> itemStacks;
+
+    public boolean isExact() {
+        return this.itemStacks != null;
+    }
+
+    public List<ItemStack> itemStacks() {
+        return this.itemStacks;
+    }
+
+    public static RecipeItemStack ofStacks(List<ItemStack> stacks) {
+        RecipeItemStack recipe = RecipeItemStack.of(stacks.stream().map(ItemStack::getItem));
+        recipe.itemStacks = stacks;
+        return recipe;
+    }
+    // CraftBukkit end
 
     private RecipeItemStack(HolderSet<Item> holderset) {
         holderset.unwrap().ifRight((list) -> {
@@ -70,6 +93,17 @@
     }
 
     public boolean test(ItemStack itemstack) {
+        // CraftBukkit start
+        if (this.isExact()) {
+            for (ItemStack itemstack1 : this.itemStacks()) {
+                if (itemstack1.getItem() == itemstack.getItem() && ItemStack.isSameItemSameComponents(itemstack, itemstack1)) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+        // CraftBukkit end
         return itemstack.is(this.values);
     }
 
@@ -79,7 +113,7 @@
 
     public boolean equals(Object object) {
         if (object instanceof RecipeItemStack recipeitemstack) {
-            return Objects.equals(this.values, recipeitemstack.values);
+            return Objects.equals(this.values, recipeitemstack.values) && Objects.equals(this.itemStacks, recipeitemstack.itemStacks); // CraftBukkit
         } else {
             return false;
         }
