aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-vineflower/net/minecraft/world/item/crafting
diff options
context:
space:
mode:
Diffstat (limited to 'patch-remap/mache-vineflower/net/minecraft/world/item/crafting')
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch41
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch41
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch35
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Ingredient.java.patch323
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Recipe.java.patch47
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch51
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeManager.java.patch322
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch205
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch204
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch41
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch139
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch170
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch41
-rw-r--r--patch-remap/mache-vineflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch40
14 files changed, 1700 insertions, 0 deletions
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch
new file mode 100644
index 0000000000..b1903d9db4
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch
@@ -0,0 +1,41 @@
+--- a/net/minecraft/world/item/crafting/BlastingRecipe.java
++++ b/net/minecraft/world/item/crafting/BlastingRecipe.java
+@@ -3,9 +3,18 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftBlastingRecipe;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class BlastingRecipe extends AbstractCookingRecipe {
+- public BlastingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+- super(RecipeType.BLASTING, string, cookingBookCategory, ingredient, itemStack, f, i);
++
++ public BlastingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.BLASTING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.BLASTING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftBlastingRecipe recipe = new CraftBlastingRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch
new file mode 100644
index 0000000000..c92ff1542f
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch
@@ -0,0 +1,41 @@
+--- a/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
++++ b/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
+@@ -3,9 +3,18 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftCampfireRecipe;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class CampfireCookingRecipe extends AbstractCookingRecipe {
+- public CampfireCookingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+- super(RecipeType.CAMPFIRE_COOKING, string, cookingBookCategory, ingredient, itemStack, f, i);
++
++ public CampfireCookingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.CAMPFIRE_COOKING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.CAMPFIRE_COOKING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftCampfireRecipe recipe = new CraftCampfireRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch
new file mode 100644
index 0000000000..16057f8555
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/CustomRecipe.java
++++ b/net/minecraft/world/item/crafting/CustomRecipe.java
+@@ -3,11 +3,17 @@
+ import net.minecraft.core.RegistryAccess;
+ import net.minecraft.world.item.ItemStack;
+
+-public abstract class CustomRecipe implements CraftingRecipe {
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
++public abstract class CustomRecipe implements RecipeCrafting {
++
+ private final CraftingBookCategory category;
+
+- public CustomRecipe(CraftingBookCategory craftingBookCategory) {
+- this.category = craftingBookCategory;
++ public CustomRecipe(CraftingBookCategory craftingbookcategory) {
++ this.category = craftingbookcategory;
+ }
+
+ @Override
+@@ -24,4 +30,11 @@
+ public CraftingBookCategory category() {
+ return this.category;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ return new org.bukkit.craftbukkit.inventory.CraftComplexRecipe(id, this);
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Ingredient.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Ingredient.java.patch
new file mode 100644
index 0000000000..a4e23f27af
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Ingredient.java.patch
@@ -0,0 +1,323 @@
+--- a/net/minecraft/world/item/crafting/Ingredient.java
++++ b/net/minecraft/world/item/crafting/Ingredient.java
+@@ -5,13 +5,13 @@
+ import com.mojang.serialization.Codec;
+ import com.mojang.serialization.DataResult;
+ import com.mojang.serialization.codecs.RecordCodecBuilder;
+-import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
+ import it.unimi.dsi.fastutil.ints.IntArrayList;
+ import it.unimi.dsi.fastutil.ints.IntComparators;
+ import it.unimi.dsi.fastutil.ints.IntList;
+ import java.util.Arrays;
+ import java.util.Collection;
+ import java.util.Collections;
++import java.util.Iterator;
+ import java.util.List;
+ import java.util.function.Predicate;
+ import java.util.stream.Stream;
+@@ -25,43 +25,64 @@
+ import net.minecraft.world.entity.player.StackedContents;
+ import net.minecraft.world.item.Item;
+ import net.minecraft.world.item.ItemStack;
+-import net.minecraft.world.level.ItemLike;
++import net.minecraft.world.level.IMaterial;
+
+ public final class Ingredient implements Predicate<ItemStack> {
++
+ public static final Ingredient EMPTY = new Ingredient(Stream.empty());
+- private final Ingredient.Value[] values;
++ private final Ingredient.Provider[] values;
+ @Nullable
+- private ItemStack[] itemStacks;
++ public ItemStack[] itemStacks;
+ @Nullable
+ private IntList stackingIds;
++ public boolean exact; // CraftBukkit
+ public static final Codec<Ingredient> CODEC = codec(true);
+ public static final Codec<Ingredient> CODEC_NONEMPTY = codec(false);
+
+- private Ingredient(Stream<? extends Ingredient.Value> values) {
+- this.values = values.toArray(Ingredient.Value[]::new);
++ public Ingredient(Stream<? extends Ingredient.Provider> values) {
++ this.values = (Ingredient.Provider[]) values.toArray((i) -> {
++ return new Ingredient.Provider[i];
++ });
+ }
+
+- private Ingredient(Ingredient.Value[] values) {
+- this.values = values;
++ private Ingredient(Ingredient.Provider[] arecipeitemstack_provider) {
++ this.values = arecipeitemstack_provider;
+ }
+
+ public ItemStack[] getItems() {
+ if (this.itemStacks == null) {
+- this.itemStacks = Arrays.stream(this.values).flatMap(value -> value.getItems().stream()).distinct().toArray(ItemStack[]::new);
++ this.itemStacks = (ItemStack[]) Arrays.stream(this.values).flatMap((recipeitemstack_provider) -> {
++ return recipeitemstack_provider.getItems().stream();
++ }).distinct().toArray((i) -> {
++ return new ItemStack[i];
++ });
+ }
+
+ return this.itemStacks;
+ }
+
+- @Override
+ public boolean test(@Nullable ItemStack stack) {
+ if (stack == null) {
+ return false;
+ } else if (this.isEmpty()) {
+ return stack.isEmpty();
+ } else {
+- for (ItemStack itemStack : this.getItems()) {
+- if (itemStack.is(stack.getItem())) {
++ ItemStack[] aitemstack = this.getItems();
++ int i = aitemstack.length;
++
++ for (int j = 0; j < i; ++j) {
++ ItemStack itemstack1 = aitemstack[j];
++
++ // CraftBukkit start
++ if (exact) {
++ if (itemstack1.getItem() == stack.getItem() && ItemStack.isSameItemSameTags(stack, itemstack1)) {
++ return true;
++ }
++
++ continue;
++ }
++ // CraftBukkit end
++ if (itemstack1.is(stack.getItem())) {
+ return true;
+ }
+ }
+@@ -72,11 +93,16 @@
+
+ public IntList getStackingIds() {
+ if (this.stackingIds == null) {
+- ItemStack[] items = this.getItems();
+- this.stackingIds = new IntArrayList(items.length);
++ ItemStack[] aitemstack = this.getItems();
+
+- for (ItemStack itemStack : items) {
+- this.stackingIds.add(StackedContents.getStackingIndex(itemStack));
++ this.stackingIds = new IntArrayList(aitemstack.length);
++ ItemStack[] aitemstack1 = aitemstack;
++ int i = aitemstack.length;
++
++ for (int j = 0; j < i; ++j) {
++ ItemStack itemstack = aitemstack1[j];
++
++ this.stackingIds.add(StackedContents.getStackingIndex(itemstack));
+ }
+
+ this.stackingIds.sort(IntComparators.NATURAL_COMPARATOR);
+@@ -93,21 +119,27 @@
+ return this.values.length == 0;
+ }
+
+- @Override
+ public boolean equals(Object object) {
+- return object instanceof Ingredient ingredient && Arrays.equals((Object[])this.values, (Object[])ingredient.values);
++ if (object instanceof Ingredient) {
++ Ingredient recipeitemstack = (Ingredient) object;
++
++ return Arrays.equals(this.values, recipeitemstack.values);
++ } else {
++ return false;
++ }
+ }
+
+- private static Ingredient fromValues(Stream<? extends Ingredient.Value> stream) {
+- Ingredient ingredient = new Ingredient(stream);
+- return ingredient.isEmpty() ? EMPTY : ingredient;
++ private static Ingredient fromValues(Stream<? extends Ingredient.Provider> stream) {
++ Ingredient recipeitemstack = new Ingredient(stream);
++
++ return recipeitemstack.isEmpty() ? Ingredient.EMPTY : recipeitemstack;
+ }
+
+ public static Ingredient of() {
+- return EMPTY;
++ return Ingredient.EMPTY;
+ }
+
+- public static Ingredient of(ItemLike... items) {
++ public static Ingredient of(IMaterial... items) {
+ return of(Arrays.stream(items).map(ItemStack::new));
+ }
+
+@@ -116,7 +148,9 @@
+ }
+
+ public static Ingredient of(Stream<ItemStack> stacks) {
+- return fromValues(stacks.filter(stack -> !stack.isEmpty()).map(Ingredient.ItemValue::new));
++ return fromValues(stacks.filter((itemstack) -> {
++ return !itemstack.isEmpty();
++ }).map(Ingredient.ItemValue::new));
+ }
+
+ public static Ingredient of(TagKey<Item> tag) {
+@@ -124,67 +158,78 @@
+ }
+
+ public static Ingredient fromNetwork(FriendlyByteBuf buffer) {
+- return fromValues(buffer.<ItemStack>readList(FriendlyByteBuf::readItem).stream().map(Ingredient.ItemValue::new));
++ return fromValues(buffer.readList(FriendlyByteBuf::readItem).stream().map(Ingredient.ItemValue::new));
+ }
+
+ private static Codec<Ingredient> codec(boolean flag) {
+- Codec<Ingredient.Value[]> codec = Codec.list(Ingredient.Value.CODEC)
+- .comapFlatMap(
+- list -> !flag && list.size() < 1
+- ? DataResult.error(() -> "Item array cannot be empty, at least one item must be defined")
+- : DataResult.success(list.toArray(new Ingredient.Value[0])),
+- List::of
+- );
+- return ExtraCodecs.either(codec, Ingredient.Value.CODEC)
+- .flatComapMap(
+- either -> either.map(Ingredient::new, value -> new Ingredient(new Ingredient.Value[]{value})),
+- ingredient -> {
+- if (ingredient.values.length == 1) {
+- return DataResult.success(Either.right(ingredient.values[0]));
+- } else {
+- return ingredient.values.length == 0 && !flag
+- ? DataResult.error(() -> "Item array cannot be empty, at least one item must be defined")
+- : DataResult.success(Either.left(ingredient.values));
+- }
+- }
+- );
++ Codec<Ingredient.Provider[]> codec = Codec.list(Ingredient.Provider.CODEC).comapFlatMap((list) -> {
++ return !flag && list.size() < 1 ? DataResult.error(() -> {
++ return "Item array cannot be empty, at least one item must be defined";
++ }) : DataResult.success((Ingredient.Provider[]) list.toArray(new Ingredient.Provider[0]));
++ }, List::of);
++
++ return ExtraCodecs.either(codec, Ingredient.Provider.CODEC).flatComapMap((either) -> {
++ return (Ingredient) either.map(Ingredient::new, (recipeitemstack_provider) -> {
++ return new Ingredient(new Ingredient.Provider[]{recipeitemstack_provider});
++ });
++ }, (recipeitemstack) -> {
++ return recipeitemstack.values.length == 1 ? DataResult.success(Either.right(recipeitemstack.values[0])) : (recipeitemstack.values.length == 0 && !flag ? DataResult.error(() -> {
++ return "Item array cannot be empty, at least one item must be defined";
++ }) : DataResult.success(Either.left(recipeitemstack.values)));
++ });
+ }
+
+- static record ItemValue(ItemStack item) implements Ingredient.Value {
+- static final Codec<Ingredient.ItemValue> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(ItemStack.SINGLE_ITEM_CODEC.fieldOf("item").forGetter(itemValue -> itemValue.item))
+- .apply(instance, Ingredient.ItemValue::new)
+- );
++ public interface Provider {
+
+- @Override
+- public boolean equals(Object object) {
+- return object instanceof Ingredient.ItemValue itemValue
+- && itemValue.item.getItem().equals(this.item.getItem())
+- && itemValue.item.getCount() == this.item.getCount();
+- }
++ Codec<Ingredient.Provider> CODEC = ExtraCodecs.xor(Ingredient.ItemValue.CODEC, Ingredient.TagValue.CODEC).xmap((either) -> {
++ return (Ingredient.Provider) either.map((recipeitemstack_stackprovider) -> {
++ return recipeitemstack_stackprovider;
++ }, (recipeitemstack_b) -> {
++ return recipeitemstack_b;
++ });
++ }, (recipeitemstack_provider) -> {
++ if (recipeitemstack_provider instanceof Ingredient.TagValue) {
++ Ingredient.TagValue recipeitemstack_b = (Ingredient.TagValue) recipeitemstack_provider;
+
+- @Override
+- public Collection<ItemStack> getItems() {
+- return Collections.singleton(this.item);
+- }
++ return Either.right(recipeitemstack_b);
++ } else if (recipeitemstack_provider instanceof Ingredient.ItemValue) {
++ Ingredient.ItemValue recipeitemstack_stackprovider = (Ingredient.ItemValue) recipeitemstack_provider;
++
++ return Either.left(recipeitemstack_stackprovider);
++ } else {
++ throw new UnsupportedOperationException("This is neither an item value nor a tag value.");
++ }
++ });
++
++ Collection<ItemStack> getItems();
+ }
+
+- static record TagValue(TagKey<Item> tag) implements Ingredient.Value {
+- static final Codec<Ingredient.TagValue> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(TagKey.codec(Registries.ITEM).fieldOf("tag").forGetter(tagValue -> tagValue.tag))
+- .apply(instance, Ingredient.TagValue::new)
+- );
++ private static record TagValue(TagKey<Item> tag) implements Ingredient.Provider {
+
+- @Override
++ static final Codec<Ingredient.TagValue> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(TagKey.codec(Registries.ITEM).fieldOf("tag").forGetter((recipeitemstack_b) -> {
++ return recipeitemstack_b.tag;
++ })).apply(instance, Ingredient.TagValue::new);
++ });
++
+ public boolean equals(Object object) {
+- return object instanceof Ingredient.TagValue tagValue && tagValue.tag.location().equals(this.tag.location());
++ if (object instanceof Ingredient.TagValue) {
++ Ingredient.TagValue recipeitemstack_b = (Ingredient.TagValue) object;
++
++ return recipeitemstack_b.tag.location().equals(this.tag.location());
++ } else {
++ return false;
++ }
+ }
+
+ @Override
+ public Collection<ItemStack> getItems() {
+ List<ItemStack> list = Lists.newArrayList();
++ Iterator iterator = BuiltInRegistries.ITEM.getTagOrEmpty(this.tag).iterator();
+
+- for (Holder<Item> holder : BuiltInRegistries.ITEM.getTagOrEmpty(this.tag)) {
++ while (iterator.hasNext()) {
++ Holder<Item> holder = (Holder) iterator.next();
++
+ list.add(new ItemStack(holder));
+ }
+
+@@ -192,18 +237,27 @@
+ }
+ }
+
+- interface Value {
+- Codec<Ingredient.Value> CODEC = ExtraCodecs.xor(Ingredient.ItemValue.CODEC, Ingredient.TagValue.CODEC)
+- .xmap(either -> either.map(itemValue -> itemValue, tagValue -> tagValue), value -> {
+- if (value instanceof Ingredient.TagValue tagValue) {
+- return Either.right(tagValue);
+- } else if (value instanceof Ingredient.ItemValue itemValue) {
+- return Either.left(itemValue);
+- } else {
+- throw new UnsupportedOperationException("This is neither an item value nor a tag value.");
+- }
+- });
++ public static record ItemValue(ItemStack item) implements Ingredient.Provider {
+
+- Collection<ItemStack> getItems();
++ static final Codec<Ingredient.ItemValue> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(ItemStack.SINGLE_ITEM_CODEC.fieldOf("item").forGetter((recipeitemstack_stackprovider) -> {
++ return recipeitemstack_stackprovider.item;
++ })).apply(instance, Ingredient.ItemValue::new);
++ });
++
++ public boolean equals(Object object) {
++ if (!(object instanceof Ingredient.ItemValue)) {
++ return false;
++ } else {
++ Ingredient.ItemValue recipeitemstack_stackprovider = (Ingredient.ItemValue) object;
++
++ return recipeitemstack_stackprovider.item.getItem().equals(this.item.getItem()) && recipeitemstack_stackprovider.item.getCount() == this.item.getCount();
++ }
++ }
++
++ @Override
++ public Collection<ItemStack> getItems() {
++ return Collections.singleton(this.item);
++ }
+ }
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Recipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Recipe.java.patch
new file mode 100644
index 0000000000..0d6b152103
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/Recipe.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/crafting/Recipe.java
++++ b/net/minecraft/world/item/crafting/Recipe.java
+@@ -11,6 +11,7 @@
+ import net.minecraft.world.level.block.Blocks;
+
+ public interface Recipe<C extends Container> {
++
+ Codec<Recipe<?>> CODEC = BuiltInRegistries.RECIPE_SERIALIZER.byNameCodec().dispatch(Recipe::getSerializer, RecipeSerializer::codec);
+
+ boolean matches(C container, Level level);
+@@ -22,16 +23,17 @@
+ ItemStack getResultItem(RegistryAccess registryAccess);
+
+ default NonNullList<ItemStack> getRemainingItems(C container) {
+- NonNullList<ItemStack> list = NonNullList.withSize(container.getContainerSize(), ItemStack.EMPTY);
++ NonNullList<ItemStack> nonnulllist = NonNullList.withSize(container.getContainerSize(), ItemStack.EMPTY);
+
+- for (int i = 0; i < list.size(); i++) {
++ for (int i = 0; i < nonnulllist.size(); ++i) {
+ Item item = container.getItem(i).getItem();
++
+ if (item.hasCraftingRemainingItem()) {
+- list.set(i, new ItemStack(item.getCraftingRemainingItem()));
++ nonnulllist.set(i, new ItemStack(item.getCraftingRemainingItem()));
+ }
+ }
+
+- return list;
++ return nonnulllist;
+ }
+
+ default NonNullList<Ingredient> getIngredients() {
+@@ -59,7 +61,12 @@
+ RecipeType<?> getType();
+
+ default boolean isIncomplete() {
+- NonNullList<Ingredient> ingredients = this.getIngredients();
+- return ingredients.isEmpty() || ingredients.stream().anyMatch(ingredient -> ingredient.getItems().length == 0);
++ NonNullList<Ingredient> nonnulllist = this.getIngredients();
++
++ return nonnulllist.isEmpty() || nonnulllist.stream().anyMatch((recipeitemstack) -> {
++ return recipeitemstack.getItems().length == 0;
++ });
+ }
++
++ org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch
new file mode 100644
index 0000000000..b9dcb13846
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch
@@ -0,0 +1,51 @@
+--- a/net/minecraft/world/item/crafting/RecipeHolder.java
++++ b/net/minecraft/world/item/crafting/RecipeHolder.java
+@@ -1,27 +1,41 @@
+ package net.minecraft.world.item.crafting;
+
+ import net.minecraft.resources.ResourceLocation;
++// CraftBukkit start
++import org.bukkit.craftbukkit.util.CraftNamespacedKey;
++import org.bukkit.inventory.Recipe;
+
+-public record RecipeHolder<T extends Recipe<?>>(ResourceLocation id, T value) {
+- @Override
++public record RecipeHolder<T extends net.minecraft.world.item.crafting.Recipe<?>>(ResourceLocation id, T value) {
++
++ public final Recipe toBukkitRecipe() {
++ return this.value.toBukkitRecipe(CraftNamespacedKey.fromMinecraft(this.id));
++ }
++ // CraftBukkit end
++
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ } else {
+- if (object instanceof RecipeHolder<?> recipeHolder && this.id.equals(recipeHolder.id)) {
+- return true;
++ boolean flag;
++
++ if (object instanceof RecipeHolder) {
++ RecipeHolder<?> recipeholder = (RecipeHolder) object;
++
++ if (this.id.equals(recipeholder.id)) {
++ flag = true;
++ return flag;
++ }
+ }
+
+- return false;
++ flag = false;
++ return flag;
+ }
+ }
+
+- @Override
+ public int hashCode() {
+ return this.id.hashCode();
+ }
+
+- @Override
+ public String toString() {
+ return this.id.toString();
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeManager.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeManager.java.patch
new file mode 100644
index 0000000000..bef8eeac66
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/RecipeManager.java.patch
@@ -0,0 +1,322 @@
+--- a/net/minecraft/world/item/crafting/RecipeManager.java
++++ b/net/minecraft/world/item/crafting/RecipeManager.java
+@@ -1,8 +1,8 @@
+ package net.minecraft.world.item.crafting;
+
+ import com.google.common.collect.ImmutableMap;
+-import com.google.common.collect.Maps;
+ import com.google.common.collect.ImmutableMap.Builder;
++import com.google.common.collect.Maps;
+ import com.google.gson.Gson;
+ import com.google.gson.GsonBuilder;
+ import com.google.gson.JsonElement;
+@@ -14,83 +14,122 @@
+ import java.util.Collection;
+ import java.util.Collections;
+ import java.util.Comparator;
++import java.util.Iterator;
+ import java.util.List;
+ import java.util.Map;
+-import java.util.Optional;
+ import java.util.Map.Entry;
++import java.util.Optional;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;
+ import javax.annotation.Nullable;
+ import net.minecraft.Util;
+ import net.minecraft.core.NonNullList;
++import net.minecraft.world.Container;
++import net.minecraft.world.item.ItemStack;
++import net.minecraft.world.level.Level;
++import org.slf4j.Logger;
++
++// CraftBukkit start
++import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
++import net.minecraft.core.registries.BuiltInRegistries;
++// CraftBukkit end
+ import net.minecraft.resources.ResourceLocation;
+ import net.minecraft.server.packs.resources.ResourceManager;
+ import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
+ import net.minecraft.util.GsonHelper;
+ import net.minecraft.util.profiling.ProfilerFiller;
+-import net.minecraft.world.Container;
+-import net.minecraft.world.item.ItemStack;
+-import net.minecraft.world.level.Level;
+-import org.slf4j.Logger;
+
+ public class RecipeManager extends SimpleJsonResourceReloadListener {
+- private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
++
++ private static final Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create();
+ private static final Logger LOGGER = LogUtils.getLogger();
+- private Map<RecipeType<?>, Map<ResourceLocation, RecipeHolder<?>>> recipes = ImmutableMap.of();
++ public Map<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>>> recipes = ImmutableMap.of(); // CraftBukkit
+ private Map<ResourceLocation, RecipeHolder<?>> byName = ImmutableMap.of();
+ private boolean hasErrors;
+
+ public RecipeManager() {
+- super(GSON, "recipes");
++ super(RecipeManager.GSON, "recipes");
+ }
+
+- @Override
+ protected void apply(Map<ResourceLocation, JsonElement> object, ResourceManager resourceManager, ProfilerFiller profiler) {
+ this.hasErrors = false;
+- Map<RecipeType<?>, Builder<ResourceLocation, RecipeHolder<?>>> map = Maps.newHashMap();
++ // CraftBukkit start - SPIGOT-5667 make sure all types are populated and mutable
++ Map<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>>> map1 = Maps.newHashMap();
++ for (RecipeType<?> recipeType : BuiltInRegistries.RECIPE_TYPE) {
++ map1.put(recipeType, new Object2ObjectLinkedOpenHashMap<>());
++ }
++ // CraftBukkit end
+ Builder<ResourceLocation, RecipeHolder<?>> builder = ImmutableMap.builder();
++ Iterator iterator = object.entrySet().iterator();
+
+- for (Entry<ResourceLocation, JsonElement> entry : object.entrySet()) {
+- ResourceLocation resourceLocation = entry.getKey();
++ while (iterator.hasNext()) {
++ Entry<ResourceLocation, JsonElement> entry = (Entry) iterator.next();
++ ResourceLocation minecraftkey = (ResourceLocation) entry.getKey();
+
+ try {
+- RecipeHolder<?> recipeHolder = fromJson(resourceLocation, GsonHelper.convertToJsonObject(entry.getValue(), "top element"));
+- map.computeIfAbsent(recipeHolder.value().getType(), type -> ImmutableMap.builder()).put(resourceLocation, recipeHolder);
+- builder.put(resourceLocation, recipeHolder);
+- } catch (IllegalArgumentException | JsonParseException var10) {
+- LOGGER.error("Parsing error loading recipe {}", resourceLocation, var10);
++ RecipeHolder<?> recipeholder = fromJson(minecraftkey, GsonHelper.convertToJsonObject((JsonElement) entry.getValue(), "top element"));
++
++ // CraftBukkit start
++ (map1.computeIfAbsent(recipeholder.value().getType(), (recipes) -> {
++ return new Object2ObjectLinkedOpenHashMap<>();
++ // CraftBukkit end
++ })).put(minecraftkey, recipeholder);
++ builder.put(minecraftkey, recipeholder);
++ } catch (IllegalArgumentException | JsonParseException jsonparseexception) {
++ RecipeManager.LOGGER.error("Parsing error loading recipe {}", minecraftkey, jsonparseexception);
+ }
+ }
+
+- this.recipes = map.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, entry1 -> entry1.getValue().build()));
+- this.byName = builder.build();
+- LOGGER.info("Loaded {} recipes", map.size());
++ this.recipes = (Map) map1.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry1) -> {
++ return (entry1.getValue()); // CraftBukkit
++ }));
++ this.byName = Maps.newHashMap(builder.build()); // CraftBukkit
++ RecipeManager.LOGGER.info("Loaded {} recipes", map1.size());
+ }
+
++ // CraftBukkit start
++ public void addRecipe(RecipeHolder<?> irecipe) {
++ Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>> map = this.recipes.get(irecipe.value().getType()); // CraftBukkit
++
++ if (byName.containsKey(irecipe.id()) || map.containsKey(irecipe.id())) {
++ throw new IllegalStateException("Duplicate recipe ignored with ID " + irecipe.id());
++ } else {
++ map.putAndMoveToFirst(irecipe.id(), irecipe); // CraftBukkit - SPIGOT-4638: last recipe gets priority
++ byName.put(irecipe.id(), irecipe);
++ }
++ }
++ // CraftBukkit end
++
+ public boolean hadErrorsLoading() {
+ return this.hasErrors;
+ }
+
+ public <C extends Container, T extends Recipe<C>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> recipeType, C inventory, Level level) {
+- return this.byType(recipeType).values().stream().filter(recipeHolder -> recipeHolder.value().matches(inventory, level)).findFirst();
++ // CraftBukkit start
++ Optional<RecipeHolder<T>> recipe = this.byType(recipeType).values().stream().filter((recipeholder) -> {
++ return recipeholder.value().matches(inventory, level);
++ }).findFirst();
++ inventory.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found
++ return recipe;
++ // CraftBukkit end
+ }
+
+- public <C extends Container, T extends Recipe<C>> Optional<Pair<ResourceLocation, RecipeHolder<T>>> getRecipeFor(
+- RecipeType<T> recipeType, C inventory, Level level, @Nullable ResourceLocation lastRecipe
+- ) {
++ public <C extends Container, T extends Recipe<C>> Optional<Pair<ResourceLocation, RecipeHolder<T>>> getRecipeFor(RecipeType<T> recipeType, C inventory, Level level, @Nullable ResourceLocation lastRecipe) {
+ Map<ResourceLocation, RecipeHolder<T>> map = this.byType(recipeType);
++
+ if (lastRecipe != null) {
+- RecipeHolder<T> recipeHolder = map.get(lastRecipe);
+- if (recipeHolder != null && recipeHolder.value().matches(inventory, level)) {
+- return Optional.of(Pair.of(lastRecipe, recipeHolder));
++ RecipeHolder<T> recipeholder = (RecipeHolder) map.get(lastRecipe);
++
++ if (recipeholder != null && recipeholder.value().matches(inventory, level)) {
++ return Optional.of(Pair.of(lastRecipe, recipeholder));
+ }
+ }
+
+- return map.entrySet()
+- .stream()
+- .filter(entry -> entry.getValue().value().matches(inventory, level))
+- .findFirst()
+- .map(entry -> Pair.of(entry.getKey(), entry.getValue()));
++ return map.entrySet().stream().filter((entry) -> {
++ return ((RecipeHolder) entry.getValue()).value().matches(inventory, level);
++ }).findFirst().map((entry) -> {
++ return Pair.of((ResourceLocation) entry.getKey(), (RecipeHolder) entry.getValue());
++ });
+ }
+
+ public <C extends Container, T extends Recipe<C>> List<RecipeHolder<T>> getAllRecipesFor(RecipeType<T> recipeType) {
+@@ -98,67 +137,96 @@
+ }
+
+ public <C extends Container, T extends Recipe<C>> List<RecipeHolder<T>> getRecipesFor(RecipeType<T> recipeType, C inventory, Level level) {
+- return this.byType(recipeType)
+- .values()
+- .stream()
+- .filter(recipeHolder -> recipeHolder.value().matches(inventory, level))
+- .sorted(Comparator.comparing(recipeHolder -> recipeHolder.value().getResultItem(level.registryAccess()).getDescriptionId()))
+- .collect(Collectors.toList());
++ return (List) this.byType(recipeType).values().stream().filter((recipeholder) -> {
++ return recipeholder.value().matches(inventory, level);
++ }).sorted(Comparator.comparing((recipeholder) -> {
++ return recipeholder.value().getResultItem(level.registryAccess()).getDescriptionId();
++ })).collect(Collectors.toList());
+ }
+
+ private <C extends Container, T extends Recipe<C>> Map<ResourceLocation, RecipeHolder<T>> byType(RecipeType<T> recipeType) {
+- return (Map<ResourceLocation, RecipeHolder<T>>) ((Map<ResourceLocation, ?>) this.recipes.getOrDefault(recipeType, Collections.emptyMap()));
++ return (Map) this.recipes.getOrDefault(recipeType, new Object2ObjectLinkedOpenHashMap<>()); // CraftBukkit
+ }
+
+ public <C extends Container, T extends Recipe<C>> NonNullList<ItemStack> getRemainingItemsFor(RecipeType<T> recipeType, C inventory, Level level) {
+- Optional<RecipeHolder<T>> recipeFor = this.getRecipeFor(recipeType, inventory, level);
+- if (recipeFor.isPresent()) {
+- return recipeFor.get().value().getRemainingItems(inventory);
++ Optional<RecipeHolder<T>> optional = this.getRecipeFor(recipeType, inventory, level);
++
++ if (optional.isPresent()) {
++ return ((RecipeHolder) optional.get()).value().getRemainingItems(inventory);
+ } else {
+- NonNullList<ItemStack> list = NonNullList.withSize(inventory.getContainerSize(), ItemStack.EMPTY);
++ NonNullList<ItemStack> nonnulllist = NonNullList.withSize(inventory.getContainerSize(), ItemStack.EMPTY);
+
+- for (int i = 0; i < list.size(); i++) {
+- list.set(i, inventory.getItem(i));
++ for (int i = 0; i < nonnulllist.size(); ++i) {
++ nonnulllist.set(i, inventory.getItem(i));
+ }
+
+- return list;
++ return nonnulllist;
+ }
+ }
+
+ public Optional<RecipeHolder<?>> byKey(ResourceLocation recipeId) {
+- return Optional.ofNullable(this.byName.get(recipeId));
++ return Optional.ofNullable((RecipeHolder) this.byName.get(recipeId));
+ }
+
+ public Collection<RecipeHolder<?>> getRecipes() {
+- return this.recipes.values().stream().flatMap(map -> map.values().stream()).collect(Collectors.toSet());
++ return (Collection) this.recipes.values().stream().flatMap((map) -> {
++ return map.values().stream();
++ }).collect(Collectors.toSet());
+ }
+
+ public Stream<ResourceLocation> getRecipeIds() {
+- return this.recipes.values().stream().flatMap(map -> map.keySet().stream());
++ return this.recipes.values().stream().flatMap((map) -> {
++ return map.keySet().stream();
++ });
+ }
+
+- protected static RecipeHolder<?> fromJson(ResourceLocation resourceLocation, JsonObject jsonObject) {
+- Recipe<?> recipe = Util.getOrThrow(Recipe.CODEC.parse(JsonOps.INSTANCE, jsonObject), JsonParseException::new);
+- return new RecipeHolder<>(resourceLocation, recipe);
++ protected static RecipeHolder<?> fromJson(ResourceLocation minecraftkey, JsonObject jsonobject) {
++ Recipe<?> irecipe = (Recipe) Util.getOrThrow(Recipe.CODEC.parse(JsonOps.INSTANCE, jsonobject), JsonParseException::new);
++
++ return new RecipeHolder<>(minecraftkey, irecipe);
+ }
+
+ public void replaceRecipes(Iterable<RecipeHolder<?>> recipes) {
+ this.hasErrors = false;
+- Map<RecipeType<?>, Map<ResourceLocation, RecipeHolder<?>>> map = Maps.newHashMap();
++ Map<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>>> map = Maps.newHashMap(); // CraftBukkit
+ Builder<ResourceLocation, RecipeHolder<?>> builder = ImmutableMap.builder();
+- recipes.forEach(recipeHolder -> {
+- Map<ResourceLocation, RecipeHolder<?>> map1 = map.computeIfAbsent(recipeHolder.value().getType(), recipeType -> Maps.newHashMap());
+- ResourceLocation resourceLocation = recipeHolder.id();
+- RecipeHolder<?> recipeHolder1 = map1.put(resourceLocation, (RecipeHolder<?>)recipeHolder);
+- builder.put(resourceLocation, (RecipeHolder<?>)recipeHolder);
+- if (recipeHolder1 != null) {
+- throw new IllegalStateException("Duplicate recipe ignored with ID " + resourceLocation);
++
++ recipes.forEach((recipeholder) -> {
++ Map<ResourceLocation, RecipeHolder<?>> map1 = (Map) map.computeIfAbsent(recipeholder.value().getType(), (recipes) -> {
++ return new Object2ObjectLinkedOpenHashMap<>(); // CraftBukkit
++ });
++ ResourceLocation minecraftkey = recipeholder.id();
++ RecipeHolder<?> recipeholder1 = (RecipeHolder) map1.put(minecraftkey, recipeholder);
++
++ builder.put(minecraftkey, recipeholder);
++ if (recipeholder1 != null) {
++ throw new IllegalStateException("Duplicate recipe ignored with ID " + minecraftkey);
+ }
+ });
+ this.recipes = ImmutableMap.copyOf(map);
+- this.byName = builder.build();
++ this.byName = Maps.newHashMap(builder.build()); // CraftBukkit
+ }
+
++ // CraftBukkit start
++ public boolean removeRecipe(ResourceLocation mcKey) {
++ for (Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>> recipes : recipes.values()) {
++ recipes.remove(mcKey);
++ }
++
++ return byName.remove(mcKey) != null;
++ }
++
++ public void clearRecipes() {
++ this.recipes = Maps.newHashMap();
++
++ for (RecipeType<?> recipeType : BuiltInRegistries.RECIPE_TYPE) {
++ this.recipes.put(recipeType, new Object2ObjectLinkedOpenHashMap<>());
++ }
++
++ this.byName = Maps.newHashMap();
++ }
++ // CraftBukkit end
++
+ public static <C extends Container, T extends Recipe<C>> RecipeManager.CachedCheck<C, T> createCheck(final RecipeType<T> recipeType) {
+ return new RecipeManager.CachedCheck<C, T>() {
+ @Nullable
+@@ -166,12 +234,14 @@
+
+ @Override
+ public Optional<RecipeHolder<T>> getRecipeFor(C container, Level level) {
+- RecipeManager recipeManager = level.getRecipeManager();
+- Optional<Pair<ResourceLocation, RecipeHolder<T>>> recipeFor = recipeManager.getRecipeFor(recipeType, container, level, this.lastRecipe);
+- if (recipeFor.isPresent()) {
+- Pair<ResourceLocation, RecipeHolder<T>> pair = recipeFor.get();
+- this.lastRecipe = pair.getFirst();
+- return Optional.of(pair.getSecond());
++ RecipeManager craftingmanager = level.getRecipeManager();
++ Optional<Pair<ResourceLocation, RecipeHolder<T>>> optional = craftingmanager.getRecipeFor(recipeType, container, level, this.lastRecipe);
++
++ if (optional.isPresent()) {
++ Pair<ResourceLocation, RecipeHolder<T>> pair = (Pair) optional.get();
++
++ this.lastRecipe = (ResourceLocation) pair.getFirst();
++ return Optional.of((RecipeHolder) pair.getSecond());
+ } else {
+ return Optional.empty();
+ }
+@@ -180,6 +250,7 @@
+ }
+
+ public interface CachedCheck<C extends Container, T extends Recipe<C>> {
++
+ Optional<RecipeHolder<T>> getRecipeFor(C container, Level level);
+ }
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch
new file mode 100644
index 0000000000..bf7e64ba97
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch
@@ -0,0 +1,205 @@
+--- a/net/minecraft/world/item/crafting/ShapedRecipe.java
++++ b/net/minecraft/world/item/crafting/ShapedRecipe.java
+@@ -2,35 +2,104 @@
+
+ import com.mojang.serialization.Codec;
+ import com.mojang.serialization.codecs.RecordCodecBuilder;
+-import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
+ import net.minecraft.core.NonNullList;
+ import net.minecraft.core.RegistryAccess;
+ import net.minecraft.network.FriendlyByteBuf;
+ import net.minecraft.util.ExtraCodecs;
+-import net.minecraft.world.inventory.CraftingContainer;
++import net.minecraft.world.inventory.InventoryCrafting;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
++import org.bukkit.inventory.RecipeChoice;
++// CraftBukkit end
+
+-public class ShapedRecipe implements CraftingRecipe {
++public class ShapedRecipe implements RecipeCrafting {
++
+ final ShapedRecipePattern pattern;
+ final ItemStack result;
+ final String group;
+ final CraftingBookCategory category;
+ final boolean showNotification;
+
+- public ShapedRecipe(String string, CraftingBookCategory craftingBookCategory, ShapedRecipePattern shapedRecipePattern, ItemStack itemStack, boolean flag) {
+- this.group = string;
+- this.category = craftingBookCategory;
+- this.pattern = shapedRecipePattern;
+- this.result = itemStack;
++ public ShapedRecipe(String s, CraftingBookCategory craftingbookcategory, ShapedRecipePattern shapedrecipepattern, ItemStack itemstack, boolean flag) {
++ this.group = s;
++ this.category = craftingbookcategory;
++ this.pattern = shapedrecipepattern;
++ this.result = itemstack;
+ this.showNotification = flag;
+ }
+
+- public ShapedRecipe(String string, CraftingBookCategory craftingBookCategory, ShapedRecipePattern shapedRecipePattern, ItemStack itemStack) {
+- this(string, craftingBookCategory, shapedRecipePattern, itemStack, true);
++ public ShapedRecipe(String s, CraftingBookCategory craftingbookcategory, ShapedRecipePattern shapedrecipepattern, ItemStack itemstack) {
++ this(s, craftingbookcategory, shapedrecipepattern, itemstack, true);
+ }
+
++ // CraftBukkit start
+ @Override
++ public org.bukkit.inventory.ShapedRecipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++ CraftShapedRecipe recipe = new CraftShapedRecipe(id, result, this);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ switch (this.pattern.height()) {
++ case 1:
++ switch (this.pattern.width()) {
++ case 1:
++ recipe.shape("a");
++ break;
++ case 2:
++ recipe.shape("ab");
++ break;
++ case 3:
++ recipe.shape("abc");
++ break;
++ }
++ break;
++ case 2:
++ switch (this.pattern.width()) {
++ case 1:
++ recipe.shape("a","b");
++ break;
++ case 2:
++ recipe.shape("ab","cd");
++ break;
++ case 3:
++ recipe.shape("abc","def");
++ break;
++ }
++ break;
++ case 3:
++ switch (this.pattern.width()) {
++ case 1:
++ recipe.shape("a","b","c");
++ break;
++ case 2:
++ recipe.shape("ab","cd","ef");
++ break;
++ case 3:
++ recipe.shape("abc","def","ghi");
++ break;
++ }
++ break;
++ }
++ char c = 'a';
++ for (Ingredient list : this.pattern.ingredients()) {
++ RecipeChoice choice = CraftRecipe.toBukkit(list);
++ if (choice != null) {
++ recipe.setIngredient(c, choice);
++ }
++
++ c++;
++ }
++ return recipe;
++ }
++ // CraftBukkit end
++
++ @Override
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SHAPED_RECIPE;
+ }
+@@ -65,13 +134,11 @@
+ return width >= this.pattern.width() && height >= this.pattern.height();
+ }
+
+- @Override
+- public boolean matches(CraftingContainer inv, Level level) {
++ public boolean matches(InventoryCrafting inv, Level level) {
+ return this.pattern.matches(inv);
+ }
+
+- @Override
+- public ItemStack assemble(CraftingContainer container, RegistryAccess registryAccess) {
++ public ItemStack assemble(InventoryCrafting container, RegistryAccess registryAccess) {
+ return this.getResultItem(registryAccess).copy();
+ }
+
+@@ -85,39 +152,49 @@
+
+ @Override
+ public boolean isIncomplete() {
+- NonNullList<Ingredient> ingredients = this.getIngredients();
+- return ingredients.isEmpty()
+- || ingredients.stream().filter(ingredient -> !ingredient.isEmpty()).anyMatch(filteredIngredients -> filteredIngredients.getItems().length == 0);
++ NonNullList<Ingredient> nonnulllist = this.getIngredients();
++
++ return nonnulllist.isEmpty() || nonnulllist.stream().filter((recipeitemstack) -> {
++ return !recipeitemstack.isEmpty();
++ }).anyMatch((recipeitemstack) -> {
++ return recipeitemstack.getItems().length == 0;
++ });
+ }
+
+ public static class Serializer implements RecipeSerializer<ShapedRecipe> {
+- public static final Codec<ShapedRecipe> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(
+- ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter(shapedRecipe -> shapedRecipe.group),
+- CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter(shapedRecipe -> shapedRecipe.category),
+- ShapedRecipePattern.MAP_CODEC.forGetter(shapedRecipe -> shapedRecipe.pattern),
+- ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter(shapedRecipe -> shapedRecipe.result),
+- ExtraCodecs.strictOptionalField(Codec.BOOL, "show_notification", true).forGetter(shapedRecipe -> shapedRecipe.showNotification)
+- )
+- .apply(instance, ShapedRecipe::new)
+- );
+
++ public static final Codec<ShapedRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter((shapedrecipes) -> {
++ return shapedrecipes.group;
++ }), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter((shapedrecipes) -> {
++ return shapedrecipes.category;
++ }), ShapedRecipePattern.MAP_CODEC.forGetter((shapedrecipes) -> {
++ return shapedrecipes.pattern;
++ }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((shapedrecipes) -> {
++ return shapedrecipes.result;
++ }), ExtraCodecs.strictOptionalField(Codec.BOOL, "show_notification", true).forGetter((shapedrecipes) -> {
++ return shapedrecipes.showNotification;
++ })).apply(instance, ShapedRecipe::new);
++ });
++
++ public Serializer() {}
++
+ @Override
+ public Codec<ShapedRecipe> codec() {
+- return CODEC;
++ return ShapedRecipe.Serializer.CODEC;
+ }
+
+ @Override
+- public ShapedRecipe fromNetwork(FriendlyByteBuf friendlyByteBuf) {
+- String utf = friendlyByteBuf.readUtf();
+- CraftingBookCategory craftingBookCategory = friendlyByteBuf.readEnum(CraftingBookCategory.class);
+- ShapedRecipePattern shapedRecipePattern = ShapedRecipePattern.fromNetwork(friendlyByteBuf);
+- ItemStack item = friendlyByteBuf.readItem();
+- boolean _boolean = friendlyByteBuf.readBoolean();
+- return new ShapedRecipe(utf, craftingBookCategory, shapedRecipePattern, item, _boolean);
++ public ShapedRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ String s = packetdataserializer.readUtf();
++ CraftingBookCategory craftingbookcategory = (CraftingBookCategory) packetdataserializer.readEnum(CraftingBookCategory.class);
++ ShapedRecipePattern shapedrecipepattern = ShapedRecipePattern.fromNetwork(packetdataserializer);
++ ItemStack itemstack = packetdataserializer.readItem();
++ boolean flag = packetdataserializer.readBoolean();
++
++ return new ShapedRecipe(s, craftingbookcategory, shapedrecipepattern, itemstack, flag);
+ }
+
+- @Override
+ public void toNetwork(FriendlyByteBuf buffer, ShapedRecipe recipe) {
+ buffer.writeUtf(recipe.group);
+ buffer.writeEnum(recipe.category);
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch
new file mode 100644
index 0000000000..0434c3100b
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch
@@ -0,0 +1,204 @@
+--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
++++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
+@@ -3,31 +3,54 @@
+ import com.mojang.serialization.Codec;
+ import com.mojang.serialization.DataResult;
+ import com.mojang.serialization.codecs.RecordCodecBuilder;
+-import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
+-import java.util.List;
++import it.unimi.dsi.fastutil.ints.IntList;
++import java.util.Iterator;
+ import net.minecraft.core.NonNullList;
+ import net.minecraft.core.RegistryAccess;
+ import net.minecraft.network.FriendlyByteBuf;
+ import net.minecraft.util.ExtraCodecs;
+ import net.minecraft.world.entity.player.StackedContents;
+-import net.minecraft.world.inventory.CraftingContainer;
++import net.minecraft.world.inventory.InventoryCrafting;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
++// CraftBukkit end
+
+-public class ShapelessRecipe implements CraftingRecipe {
++public class ShapelessRecipe implements RecipeCrafting {
++
+ final String group;
+ final CraftingBookCategory category;
+ final ItemStack result;
+ final NonNullList<Ingredient> ingredients;
+
+- public ShapelessRecipe(String string, CraftingBookCategory craftingBookCategory, ItemStack itemStack, NonNullList<Ingredient> list) {
+- this.group = string;
+- this.category = craftingBookCategory;
+- this.result = itemStack;
+- this.ingredients = list;
++ public ShapelessRecipe(String s, CraftingBookCategory craftingbookcategory, ItemStack itemstack, NonNullList<Ingredient> nonnulllist) {
++ this.group = s;
++ this.category = craftingbookcategory;
++ this.result = itemstack;
++ this.ingredients = nonnulllist;
+ }
+
++ // CraftBukkit start
++ @SuppressWarnings("unchecked")
+ @Override
++ public org.bukkit.inventory.ShapelessRecipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++ CraftShapelessRecipe recipe = new CraftShapelessRecipe(id, result, this);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ for (Ingredient list : this.ingredients) {
++ recipe.addIngredient(CraftRecipe.toBukkit(list));
++ }
++ return recipe;
++ }
++ // CraftBukkit end
++
++ @Override
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SHAPELESS_RECIPE;
+ }
+@@ -52,24 +75,23 @@
+ return this.ingredients;
+ }
+
+- @Override
+- public boolean matches(CraftingContainer inv, Level level) {
+- StackedContents stackedContents = new StackedContents();
++ public boolean matches(InventoryCrafting inv, Level level) {
++ StackedContents autorecipestackmanager = new StackedContents();
+ int i = 0;
+
+- for (int i1 = 0; i1 < inv.getContainerSize(); i1++) {
+- ItemStack item = inv.getItem(i1);
+- if (!item.isEmpty()) {
+- i++;
+- stackedContents.accountStack(item, 1);
++ for (int j = 0; j < inv.getContainerSize(); ++j) {
++ ItemStack itemstack = inv.getItem(j);
++
++ if (!itemstack.isEmpty()) {
++ ++i;
++ autorecipestackmanager.accountStack(itemstack, 1);
+ }
+ }
+
+- return i == this.ingredients.size() && stackedContents.canCraft(this, null);
++ return i == this.ingredients.size() && autorecipestackmanager.canCraft(this, (IntList) null);
+ }
+
+- @Override
+- public ItemStack assemble(CraftingContainer container, RegistryAccess registryAccess) {
++ public ItemStack assemble(InventoryCrafting container, RegistryAccess registryAccess) {
+ return this.result.copy();
+ }
+
+@@ -79,60 +101,64 @@
+ }
+
+ public static class Serializer implements RecipeSerializer<ShapelessRecipe> {
+- private static final Codec<ShapelessRecipe> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(
+- ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter(shapelessRecipe -> shapelessRecipe.group),
+- CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter(shapelessRecipe -> shapelessRecipe.category),
+- ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter(shapelessRecipe -> shapelessRecipe.result),
+- Ingredient.CODEC_NONEMPTY
+- .listOf()
+- .fieldOf("ingredients")
+- .flatXmap(
+- list -> {
+- Ingredient[] ingredients = list.stream().filter(ingredient -> !ingredient.isEmpty()).toArray(Ingredient[]::new);
+- if (ingredients.length == 0) {
+- return DataResult.error(() -> "No ingredients for shapeless recipe");
+- } else {
+- return ingredients.length > 9
+- ? DataResult.error(() -> "Too many ingredients for shapeless recipe")
+- : DataResult.success(NonNullList.of(Ingredient.EMPTY, ingredients));
+- }
+- },
+- DataResult::success
+- )
+- .forGetter(shapelessRecipe -> shapelessRecipe.ingredients)
+- )
+- .apply(instance, ShapelessRecipe::new)
+- );
+
++ private static final Codec<ShapelessRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.group;
++ }), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.category;
++ }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.result;
++ }), Ingredient.CODEC_NONEMPTY.listOf().fieldOf("ingredients").flatXmap((list) -> {
++ Ingredient[] arecipeitemstack = (Ingredient[]) list.stream().filter((recipeitemstack) -> {
++ return !recipeitemstack.isEmpty();
++ }).toArray((i) -> {
++ return new Ingredient[i];
++ });
++
++ return arecipeitemstack.length == 0 ? DataResult.error(() -> {
++ return "No ingredients for shapeless recipe";
++ }) : (arecipeitemstack.length > 9 ? DataResult.error(() -> {
++ return "Too many ingredients for shapeless recipe";
++ }) : DataResult.success(NonNullList.of(Ingredient.EMPTY, arecipeitemstack)));
++ }, DataResult::success).forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.ingredients;
++ })).apply(instance, ShapelessRecipe::new);
++ });
++
++ public Serializer() {}
++
+ @Override
+ public Codec<ShapelessRecipe> codec() {
+- return CODEC;
++ return ShapelessRecipe.Serializer.CODEC;
+ }
+
+ @Override
+- public ShapelessRecipe fromNetwork(FriendlyByteBuf friendlyByteBuf) {
+- String utf = friendlyByteBuf.readUtf();
+- CraftingBookCategory craftingBookCategory = friendlyByteBuf.readEnum(CraftingBookCategory.class);
+- int varInt = friendlyByteBuf.readVarInt();
+- NonNullList<Ingredient> list = NonNullList.withSize(varInt, Ingredient.EMPTY);
++ public ShapelessRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ String s = packetdataserializer.readUtf();
++ CraftingBookCategory craftingbookcategory = (CraftingBookCategory) packetdataserializer.readEnum(CraftingBookCategory.class);
++ int i = packetdataserializer.readVarInt();
++ NonNullList<Ingredient> nonnulllist = NonNullList.withSize(i, Ingredient.EMPTY);
+
+- for (int i = 0; i < list.size(); i++) {
+- list.set(i, Ingredient.fromNetwork(friendlyByteBuf));
++ for (int j = 0; j < nonnulllist.size(); ++j) {
++ nonnulllist.set(j, Ingredient.fromNetwork(packetdataserializer));
+ }
+
+- ItemStack item = friendlyByteBuf.readItem();
+- return new ShapelessRecipe(utf, craftingBookCategory, item, list);
++ ItemStack itemstack = packetdataserializer.readItem();
++
++ return new ShapelessRecipe(s, craftingbookcategory, itemstack, nonnulllist);
+ }
+
+- @Override
+ public void toNetwork(FriendlyByteBuf buffer, ShapelessRecipe recipe) {
+ buffer.writeUtf(recipe.group);
+ buffer.writeEnum(recipe.category);
+ buffer.writeVarInt(recipe.ingredients.size());
++ Iterator iterator = recipe.ingredients.iterator();
+
+- for (Ingredient ingredient : recipe.ingredients) {
+- ingredient.toNetwork(buffer);
++ while (iterator.hasNext()) {
++ Ingredient recipeitemstack = (Ingredient) iterator.next();
++
++ recipeitemstack.toNetwork(buffer);
+ }
+
+ buffer.writeItem(recipe.result);
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch
new file mode 100644
index 0000000000..69d9e9092e
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch
@@ -0,0 +1,41 @@
+--- a/net/minecraft/world/item/crafting/SmeltingRecipe.java
++++ b/net/minecraft/world/item/crafting/SmeltingRecipe.java
+@@ -3,9 +3,18 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class SmeltingRecipe extends AbstractCookingRecipe {
+- public SmeltingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+- super(RecipeType.SMELTING, string, cookingBookCategory, ingredient, itemStack, f, i);
++
++ public SmeltingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.SMELTING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SMELTING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftFurnaceRecipe recipe = new CraftFurnaceRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch
new file mode 100644
index 0000000000..da1e2ac7d4
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch
@@ -0,0 +1,139 @@
+--- a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
++++ b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
+@@ -2,7 +2,6 @@
+
+ import com.mojang.serialization.Codec;
+ import com.mojang.serialization.codecs.RecordCodecBuilder;
+-import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
+ import java.util.stream.Stream;
+ import net.minecraft.core.RegistryAccess;
+ import net.minecraft.nbt.CompoundTag;
+@@ -10,18 +9,26 @@
+ import net.minecraft.world.Container;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftSmithingTransformRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
+
+ public class SmithingTransformRecipe implements SmithingRecipe {
++
+ final Ingredient template;
+ final Ingredient base;
+ final Ingredient addition;
+ final ItemStack result;
+
+- public SmithingTransformRecipe(Ingredient ingredient, Ingredient ingredient1, Ingredient ingredient2, ItemStack itemStack) {
+- this.template = ingredient;
+- this.base = ingredient1;
+- this.addition = ingredient2;
+- this.result = itemStack;
++ public SmithingTransformRecipe(Ingredient recipeitemstack, Ingredient recipeitemstack1, Ingredient recipeitemstack2, ItemStack itemstack) {
++ this.template = recipeitemstack;
++ this.base = recipeitemstack1;
++ this.addition = recipeitemstack2;
++ this.result = itemstack;
+ }
+
+ @Override
+@@ -31,13 +38,14 @@
+
+ @Override
+ public ItemStack assemble(Container container, RegistryAccess registryAccess) {
+- ItemStack itemStack = this.result.copy();
+- CompoundTag tag = container.getItem(1).getTag();
+- if (tag != null) {
+- itemStack.setTag(tag.copy());
++ ItemStack itemstack = this.result.copy();
++ CompoundTag nbttagcompound = container.getItem(1).getTag();
++
++ if (nbttagcompound != null) {
++ itemstack.setTag(nbttagcompound.copy());
+ }
+
+- return itemStack;
++ return itemstack;
+ }
+
+ @Override
+@@ -70,37 +78,53 @@
+ return Stream.of(this.template, this.base, this.addition).anyMatch(Ingredient::isEmpty);
+ }
+
+- public static class Serializer implements RecipeSerializer<SmithingTransformRecipe> {
+- private static final Codec<SmithingTransformRecipe> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(
+- Ingredient.CODEC.fieldOf("template").forGetter(smithingTransformRecipe -> smithingTransformRecipe.template),
+- Ingredient.CODEC.fieldOf("base").forGetter(smithingTransformRecipe -> smithingTransformRecipe.base),
+- Ingredient.CODEC.fieldOf("addition").forGetter(smithingTransformRecipe -> smithingTransformRecipe.addition),
+- ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter(smithingTransformRecipe -> smithingTransformRecipe.result)
+- )
+- .apply(instance, SmithingTransformRecipe::new)
+- );
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
+
++ CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition));
++
++ return recipe;
++ }
++ // CraftBukkit end
++
++ public static class a implements RecipeSerializer<SmithingTransformRecipe> {
++
++ private static final Codec<SmithingTransformRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(Ingredient.CODEC.fieldOf("template").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.template;
++ }), Ingredient.CODEC.fieldOf("base").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.base;
++ }), Ingredient.CODEC.fieldOf("addition").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.addition;
++ }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.result;
++ })).apply(instance, SmithingTransformRecipe::new);
++ });
++
++ public a() {}
++
+ @Override
+ public Codec<SmithingTransformRecipe> codec() {
+- return CODEC;
++ return SmithingTransformRecipe.a.CODEC;
+ }
+
+ @Override
+- public SmithingTransformRecipe fromNetwork(FriendlyByteBuf friendlyByteBuf) {
+- Ingredient ingredient = Ingredient.fromNetwork(friendlyByteBuf);
+- Ingredient ingredient1 = Ingredient.fromNetwork(friendlyByteBuf);
+- Ingredient ingredient2 = Ingredient.fromNetwork(friendlyByteBuf);
+- ItemStack item = friendlyByteBuf.readItem();
+- return new SmithingTransformRecipe(ingredient, ingredient1, ingredient2, item);
++ public SmithingTransformRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ Ingredient recipeitemstack = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack1 = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack2 = Ingredient.fromNetwork(packetdataserializer);
++ ItemStack itemstack = packetdataserializer.readItem();
++
++ return new SmithingTransformRecipe(recipeitemstack, recipeitemstack1, recipeitemstack2, itemstack);
+ }
+
+- @Override
+- public void toNetwork(FriendlyByteBuf buffer, SmithingTransformRecipe recipe) {
+- recipe.template.toNetwork(buffer);
+- recipe.base.toNetwork(buffer);
+- recipe.addition.toNetwork(buffer);
+- buffer.writeItem(recipe.result);
++ public void toNetwork(FriendlyByteBuf packetdataserializer, SmithingTransformRecipe smithingtransformrecipe) {
++ smithingtransformrecipe.template.toNetwork(packetdataserializer);
++ smithingtransformrecipe.base.toNetwork(packetdataserializer);
++ smithingtransformrecipe.addition.toNetwork(packetdataserializer);
++ packetdataserializer.writeItem(smithingtransformrecipe.result);
+ }
+ }
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch
new file mode 100644
index 0000000000..ef758f8657
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch
@@ -0,0 +1,170 @@
+--- a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
++++ b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
+@@ -2,7 +2,6 @@
+
+ import com.mojang.serialization.Codec;
+ import com.mojang.serialization.codecs.RecordCodecBuilder;
+-import com.mojang.serialization.codecs.RecordCodecBuilder.Instance;
+ import java.util.Optional;
+ import java.util.stream.Stream;
+ import net.minecraft.core.Holder;
+@@ -18,16 +17,23 @@
+ import net.minecraft.world.item.armortrim.TrimPattern;
+ import net.minecraft.world.item.armortrim.TrimPatterns;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftSmithingTrimRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
+
+ public class SmithingTrimRecipe implements SmithingRecipe {
++
+ final Ingredient template;
+ final Ingredient base;
+ final Ingredient addition;
+
+- public SmithingTrimRecipe(Ingredient ingredient, Ingredient ingredient1, Ingredient ingredient2) {
+- this.template = ingredient;
+- this.base = ingredient1;
+- this.addition = ingredient2;
++ public SmithingTrimRecipe(Ingredient recipeitemstack, Ingredient recipeitemstack1, Ingredient recipeitemstack2) {
++ this.template = recipeitemstack;
++ this.base = recipeitemstack1;
++ this.addition = recipeitemstack2;
+ }
+
+ @Override
+@@ -37,21 +43,26 @@
+
+ @Override
+ public ItemStack assemble(Container container, RegistryAccess registryAccess) {
+- ItemStack item = container.getItem(1);
+- if (this.base.test(item)) {
+- Optional<Holder.Reference<TrimMaterial>> fromIngredient = TrimMaterials.getFromIngredient(registryAccess, container.getItem(2));
+- Optional<Holder.Reference<TrimPattern>> fromTemplate = TrimPatterns.getFromTemplate(registryAccess, container.getItem(0));
+- if (fromIngredient.isPresent() && fromTemplate.isPresent()) {
+- Optional<ArmorTrim> trim = ArmorTrim.getTrim(registryAccess, item, false);
+- if (trim.isPresent() && trim.get().hasPatternAndMaterial(fromTemplate.get(), fromIngredient.get())) {
++ ItemStack itemstack = container.getItem(1);
++
++ if (this.base.test(itemstack)) {
++ Optional<Holder.Reference<TrimMaterial>> optional = TrimMaterials.getFromIngredient(registryAccess, container.getItem(2));
++ Optional<Holder.Reference<TrimPattern>> optional1 = TrimPatterns.getFromTemplate(registryAccess, container.getItem(0));
++
++ if (optional.isPresent() && optional1.isPresent()) {
++ Optional<ArmorTrim> optional2 = ArmorTrim.getTrim(registryAccess, itemstack, false);
++
++ if (optional2.isPresent() && ((ArmorTrim) optional2.get()).hasPatternAndMaterial((Holder) optional1.get(), (Holder) optional.get())) {
+ return ItemStack.EMPTY;
+ }
+
+- ItemStack itemStack = item.copy();
+- itemStack.setCount(1);
+- ArmorTrim armorTrim = new ArmorTrim(fromIngredient.get(), fromTemplate.get());
+- if (ArmorTrim.setTrim(registryAccess, itemStack, armorTrim)) {
+- return itemStack;
++ ItemStack itemstack1 = itemstack.copy();
++
++ itemstack1.setCount(1);
++ ArmorTrim armortrim = new ArmorTrim((Holder) optional.get(), (Holder) optional1.get());
++
++ if (ArmorTrim.setTrim(registryAccess, itemstack1, armortrim)) {
++ return itemstack1;
+ }
+ }
+ }
+@@ -61,17 +72,20 @@
+
+ @Override
+ public ItemStack getResultItem(RegistryAccess registryAccess) {
+- ItemStack itemStack = new ItemStack(Items.IRON_CHESTPLATE);
++ ItemStack itemstack = new ItemStack(Items.IRON_CHESTPLATE);
+ Optional<Holder.Reference<TrimPattern>> optional = registryAccess.registryOrThrow(Registries.TRIM_PATTERN).holders().findFirst();
++
+ if (optional.isPresent()) {
+- Optional<Holder.Reference<TrimMaterial>> holder = registryAccess.registryOrThrow(Registries.TRIM_MATERIAL).getHolder(TrimMaterials.REDSTONE);
+- if (holder.isPresent()) {
+- ArmorTrim armorTrim = new ArmorTrim(holder.get(), optional.get());
+- ArmorTrim.setTrim(registryAccess, itemStack, armorTrim);
++ Optional<Holder.Reference<TrimMaterial>> optional1 = registryAccess.registryOrThrow(Registries.TRIM_MATERIAL).getHolder(TrimMaterials.REDSTONE);
++
++ if (optional1.isPresent()) {
++ ArmorTrim armortrim = new ArmorTrim((Holder) optional1.get(), (Holder) optional.get());
++
++ ArmorTrim.setTrim(registryAccess, itemstack, armortrim);
+ }
+ }
+
+- return itemStack;
++ return itemstack;
+ }
+
+ @Override
+@@ -99,34 +113,45 @@
+ return Stream.of(this.template, this.base, this.addition).anyMatch(Ingredient::isEmpty);
+ }
+
+- public static class Serializer implements RecipeSerializer<SmithingTrimRecipe> {
+- private static final Codec<SmithingTrimRecipe> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(
+- Ingredient.CODEC.fieldOf("template").forGetter(smithingTrimRecipe -> smithingTrimRecipe.template),
+- Ingredient.CODEC.fieldOf("base").forGetter(smithingTrimRecipe -> smithingTrimRecipe.base),
+- Ingredient.CODEC.fieldOf("addition").forGetter(smithingTrimRecipe -> smithingTrimRecipe.addition)
+- )
+- .apply(instance, SmithingTrimRecipe::new)
+- );
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition));
++ }
++ // CraftBukkit end
+
++ public static class a implements RecipeSerializer<SmithingTrimRecipe> {
++
++ private static final Codec<SmithingTrimRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(Ingredient.CODEC.fieldOf("template").forGetter((smithingtrimrecipe) -> {
++ return smithingtrimrecipe.template;
++ }), Ingredient.CODEC.fieldOf("base").forGetter((smithingtrimrecipe) -> {
++ return smithingtrimrecipe.base;
++ }), Ingredient.CODEC.fieldOf("addition").forGetter((smithingtrimrecipe) -> {
++ return smithingtrimrecipe.addition;
++ })).apply(instance, SmithingTrimRecipe::new);
++ });
++
++ public a() {}
++
+ @Override
+ public Codec<SmithingTrimRecipe> codec() {
+- return CODEC;
++ return SmithingTrimRecipe.a.CODEC;
+ }
+
+ @Override
+- public SmithingTrimRecipe fromNetwork(FriendlyByteBuf friendlyByteBuf) {
+- Ingredient ingredient = Ingredient.fromNetwork(friendlyByteBuf);
+- Ingredient ingredient1 = Ingredient.fromNetwork(friendlyByteBuf);
+- Ingredient ingredient2 = Ingredient.fromNetwork(friendlyByteBuf);
+- return new SmithingTrimRecipe(ingredient, ingredient1, ingredient2);
++ public SmithingTrimRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ Ingredient recipeitemstack = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack1 = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack2 = Ingredient.fromNetwork(packetdataserializer);
++
++ return new SmithingTrimRecipe(recipeitemstack, recipeitemstack1, recipeitemstack2);
+ }
+
+- @Override
+- public void toNetwork(FriendlyByteBuf buffer, SmithingTrimRecipe recipe) {
+- recipe.template.toNetwork(buffer);
+- recipe.base.toNetwork(buffer);
+- recipe.addition.toNetwork(buffer);
++ public void toNetwork(FriendlyByteBuf packetdataserializer, SmithingTrimRecipe smithingtrimrecipe) {
++ smithingtrimrecipe.template.toNetwork(packetdataserializer);
++ smithingtrimrecipe.base.toNetwork(packetdataserializer);
++ smithingtrimrecipe.addition.toNetwork(packetdataserializer);
+ }
+ }
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch
new file mode 100644
index 0000000000..125f7896db
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch
@@ -0,0 +1,41 @@
+--- a/net/minecraft/world/item/crafting/SmokingRecipe.java
++++ b/net/minecraft/world/item/crafting/SmokingRecipe.java
+@@ -3,9 +3,18 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftSmokingRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class SmokingRecipe extends AbstractCookingRecipe {
+- public SmokingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+- super(RecipeType.SMOKING, string, cookingBookCategory, ingredient, itemStack, f, i);
++
++ public SmokingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.SMOKING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SMOKING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftSmokingRecipe recipe = new CraftSmokingRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch
new file mode 100644
index 0000000000..47fa959efd
--- /dev/null
+++ b/patch-remap/mache-vineflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch
@@ -0,0 +1,40 @@
+--- a/net/minecraft/world/item/crafting/StonecutterRecipe.java
++++ b/net/minecraft/world/item/crafting/StonecutterRecipe.java
+@@ -5,9 +5,18 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftStonecuttingRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class StonecutterRecipe extends SingleItemRecipe {
+- public StonecutterRecipe(String string, Ingredient ingredient, ItemStack itemStack) {
+- super(RecipeType.STONECUTTING, RecipeSerializer.STONECUTTER, string, ingredient, itemStack);
++
++ public StonecutterRecipe(String s, Ingredient recipeitemstack, ItemStack itemstack) {
++ super(RecipeType.STONECUTTING, RecipeSerializer.STONECUTTER, s, recipeitemstack, itemstack);
+ }
+
+ @Override
+@@ -19,4 +28,16 @@
+ public ItemStack getToastSymbol() {
+ return new ItemStack(Blocks.STONECUTTER);
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftStonecuttingRecipe recipe = new CraftStonecuttingRecipe(id, result, CraftRecipe.toBukkit(this.ingredient));
++ recipe.setGroup(this.group);
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }