diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 4bfc36de02..8e4a9224db 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -71,6 +71,7 @@ mappingCompression { compress("item/item_potion_mappings.json") compress("item/item_trim_material_mappings.json") compress("item/item_trim_pattern_mappings.json") + compress("item/recipe_serializer_mappings.json") compress("particle/particle_type_mappings.json") diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/CookingCategory.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/CookingCategory.java new file mode 100644 index 0000000000..c0e874521e --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/CookingCategory.java @@ -0,0 +1,26 @@ +/* + * This file is part of packetevents - https://github.com/retrooper/packetevents + * Copyright (C) 2024 retrooper and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.github.retrooper.packetevents.protocol.recipe; + +public enum CookingCategory { + + FOOD, + BLOCKS, + MISC, +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/CraftingCategory.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/CraftingCategory.java new file mode 100644 index 0000000000..7ae8bfbb50 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/CraftingCategory.java @@ -0,0 +1,27 @@ +/* + * This file is part of packetevents - https://github.com/retrooper/packetevents + * Copyright (C) 2024 retrooper and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.github.retrooper.packetevents.protocol.recipe; + +public enum CraftingCategory { + + BUILDING, + REDSTONE, + EQUIPMENT, + MISC, +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Ingredient.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Ingredient.java index 59838c2772..8c758312c6 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Ingredient.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Ingredient.java @@ -19,17 +19,26 @@ package com.github.retrooper.packetevents.protocol.recipe; import com.github.retrooper.packetevents.protocol.item.ItemStack; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; -// From MCProtocolLib public class Ingredient { - private final @NotNull ItemStack[] options; - public Ingredient(@NotNull ItemStack... options) { + private final ItemStack[] options; + + public Ingredient(ItemStack... options) { this.options = options; } - public @NotNull ItemStack[] getOptions() { - return options; + public static Ingredient read(PacketWrapper wrapper) { + ItemStack[] options = wrapper.readArray(PacketWrapper::readItemStack, ItemStack.class); + return new Ingredient(options); + } + + public static void write(PacketWrapper wrapper, Ingredient ingredient) { + wrapper.writeArray(ingredient.options, PacketWrapper::writeItemStack); + } + + public ItemStack[] getOptions() { + return this.options; } -} \ No newline at end of file +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Recipe.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Recipe.java index 2e61c121d5..b171c33926 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Recipe.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/Recipe.java @@ -18,39 +18,89 @@ package com.github.retrooper.packetevents.protocol.recipe; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.recipe.data.RecipeData; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.resources.ResourceLocation; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; -// From MCProtocolLib -public class Recipe { - private final @NotNull RecipeType type; - private final @NotNull String identifier; - private final RecipeData data; +public class Recipe { - public Recipe(@NotNull RecipeType type, @NotNull String identifier, RecipeData data) { - this.type = type; - this.identifier = identifier; + private final ResourceLocation key; + private final RecipeSerializer serializer; + private final T data; + + @SuppressWarnings("unchecked") // backwards compat + @Deprecated + public Recipe(RecipeType serializer, String key, RecipeData data) { + this( + new ResourceLocation(key), + (RecipeSerializer) serializer.getSerializer(), + (T) data + ); + } + + public Recipe(ResourceLocation key, RecipeSerializer serializer, T data) { + this.key = key; + this.serializer = serializer; this.data = data; } - public @NotNull RecipeType getType() { - return type; + public static Recipe read(PacketWrapper wrapper) { + ResourceLocation key; + RecipeSerializer serializer; + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) { + key = wrapper.readIdentifier(); + serializer = wrapper.readMappedEntity(RecipeSerializers::getById); + } else { + serializer = RecipeSerializers.getByName(wrapper.readIdentifier().toString()); + key = wrapper.readIdentifier(); + } + return read(wrapper, key, serializer); + } + + private static Recipe read( + PacketWrapper wrapper, + ResourceLocation key, + RecipeSerializer serializer + ) { + T data = serializer.read(wrapper); + return new Recipe<>(key, serializer, data); + } + + public static void write(PacketWrapper wrapper, Recipe recipe) { + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) { + wrapper.writeIdentifier(recipe.key); + wrapper.writeMappedEntity(recipe.serializer); + } else { + wrapper.writeIdentifier(recipe.serializer.getName()); + wrapper.writeIdentifier(recipe.key); + } + recipe.serializer.write(wrapper, recipe.data); + } + + @Deprecated + public RecipeType getType() { + return this.serializer.getLegacyType(); + } + + public String getIdentifier() { + return this.key.toString(); + } + + public ResourceLocation getKey() { + return this.key; } - public @NotNull String getIdentifier() { - return identifier; + public RecipeSerializer getSerializer() { + return this.serializer; } - public @NotNull RecipeData getData() { - return data; + public T getData() { + return this.data; } @Override public String toString() { - return "Recipe{" + - "type=" + type + - ", identifier='" + identifier + '\'' + - ", data=" + data + - '}'; + return "Recipe{key=" + this.key + ", serializer=" + this.serializer + ", data=" + this.data + '}'; } -} \ No newline at end of file +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeSerializer.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeSerializer.java new file mode 100644 index 0000000000..bfde499413 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeSerializer.java @@ -0,0 +1,33 @@ +/* + * This file is part of packetevents - https://github.com/retrooper/packetevents + * Copyright (C) 2024 retrooper and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.github.retrooper.packetevents.protocol.recipe; + +import com.github.retrooper.packetevents.protocol.mapper.MappedEntity; +import com.github.retrooper.packetevents.protocol.recipe.data.RecipeData; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; + +public interface RecipeSerializer extends MappedEntity { + + @Deprecated + RecipeType getLegacyType(); + + T read(PacketWrapper wrapper); + + void write(PacketWrapper wrapper, T data); +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeSerializers.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeSerializers.java new file mode 100644 index 0000000000..bfd8724186 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeSerializers.java @@ -0,0 +1,179 @@ +/* + * This file is part of packetevents - https://github.com/retrooper/packetevents + * Copyright (C) 2024 retrooper and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.github.retrooper.packetevents.protocol.recipe; + +import com.github.retrooper.packetevents.protocol.player.ClientVersion; +import com.github.retrooper.packetevents.protocol.recipe.data.CookedRecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.RecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.ShapedRecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.ShapelessRecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.SimpleRecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.SmithingRecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.SmithingTrimRecipeData; +import com.github.retrooper.packetevents.protocol.recipe.data.StoneCuttingRecipeData; +import com.github.retrooper.packetevents.resources.ResourceLocation; +import com.github.retrooper.packetevents.util.mappings.MappingHelper; +import com.github.retrooper.packetevents.util.mappings.TypesBuilder; +import com.github.retrooper.packetevents.util.mappings.TypesBuilderData; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class RecipeSerializers { + + private static final Map> PATTERN_TYPE_MAP = new HashMap<>(); + private static final Map>> PATTERN_TYPE_ID_MAP = new HashMap<>(); + private static final TypesBuilder TYPES_BUILDER = new TypesBuilder("item/recipe_serializer_mappings"); + + public static RecipeSerializer define( + String key, + PacketWrapper.Reader reader, + PacketWrapper.Writer writer + ) { + return define(key, reader, writer, null); + } + + public static RecipeSerializer define( + String key, + PacketWrapper.Reader reader, + PacketWrapper.Writer writer, + @Nullable RecipeType recipeType + ) { + TypesBuilderData data = TYPES_BUILDER.define(key); + RecipeSerializer pattern = new RecipeSerializer() { + @Override + public ResourceLocation getName() { + return data.getName(); + } + + @Override + public int getId(ClientVersion version) { + return MappingHelper.getId(version, TYPES_BUILDER, data); + } + + @Override + public RecipeType getLegacyType() { + if (recipeType == null) { + throw new UnsupportedOperationException("No legacy type found for " + this.getName()); + } + return recipeType; + } + + @Override + public T read(PacketWrapper wrapper) { + return reader.apply(wrapper); + } + + @Override + public void write(PacketWrapper wrapper, T data) { + writer.accept(wrapper, data); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof RecipeSerializer) { + return this.getName().equals(((RecipeSerializer) obj).getName()); + } + return false; + } + }; + MappingHelper.registerMapping(TYPES_BUILDER, PATTERN_TYPE_MAP, PATTERN_TYPE_ID_MAP, pattern); + return pattern; + } + + // with key + public static RecipeSerializer getByName(String name) { + return PATTERN_TYPE_MAP.get(name); + } + + public static RecipeSerializer getById(ClientVersion version, int id) { + int index = TYPES_BUILDER.getDataIndex(version); + Map> idMap = PATTERN_TYPE_ID_MAP.get((byte) index); + return idMap.get(id); + } + + public static final RecipeSerializer CRAFTING_SHAPED = define("crafting_shaped", + ShapedRecipeData::read, ShapedRecipeData::write, RecipeType.CRAFTING_SHAPED); + public static final RecipeSerializer CRAFTING_SHAPELESS = define("crafting_shapeless", + ShapelessRecipeData::read, ShapelessRecipeData::write, RecipeType.CRAFTING_SHAPELESS); + public static final RecipeSerializer CRAFTING_SPECIAL_ARMORDYE = define("crafting_special_armordye", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_ARMORDYE); + public static final RecipeSerializer CRAFTING_SPECIAL_BOOKCLONING = define("crafting_special_bookcloning", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_BOOKCLONING); + public static final RecipeSerializer CRAFTING_SPECIAL_MAPCLONING = define("crafting_special_mapcloning", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_MAPCLONING); + public static final RecipeSerializer CRAFTING_SPECIAL_MAPEXTENDING = define("crafting_special_mapextending", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_MAPEXTENDING); + public static final RecipeSerializer CRAFTING_SPECIAL_FIREWORK_ROCKET = define("crafting_special_firework_rocket", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_FIREWORK_ROCKET); + public static final RecipeSerializer CRAFTING_SPECIAL_FIREWORK_STAR = define("crafting_special_firework_star", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR); + public static final RecipeSerializer CRAFTING_SPECIAL_FIREWORK_STAR_FADE = define("crafting_special_firework_star_fade", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_FIREWORK_STAR_FADE); + public static final RecipeSerializer CRAFTING_SPECIAL_TIPPEDARROW = define("crafting_special_tippedarrow", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_TIPPEDARROW); + public static final RecipeSerializer CRAFTING_SPECIAL_BANNERDUPLICATE = define("crafting_special_bannerduplicate", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_BANNERDUPLICATE); + public static final RecipeSerializer CRAFTING_SPECIAL_SHIELDDECORATION = define("crafting_special_shielddecoration", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_SHIELDDECORATION); + public static final RecipeSerializer CRAFTING_SPECIAL_SHULKERBOXCOLORING = define("crafting_special_shulkerboxcoloring", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_SHULKERBOXCOLORING); + public static final RecipeSerializer CRAFTING_SPECIAL_SUSPICIOUSSTEW = define("crafting_special_suspiciousstew", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_SUSPICIOUSSTEW); + public static final RecipeSerializer CRAFTING_SPECIAL_REPAIRITEM = define("crafting_special_repairitem", + SimpleRecipeData::read, SimpleRecipeData::write, RecipeType.CRAFTING_SPECIAL_REPAIRITEM); + public static final RecipeSerializer SMELTING = define("smelting", + CookedRecipeData::read, CookedRecipeData::write, RecipeType.SMELTING); + public static final RecipeSerializer BLASTING = define("blasting", + CookedRecipeData::read, CookedRecipeData::write, RecipeType.BLASTING); + public static final RecipeSerializer SMOKING = define("smoking", + CookedRecipeData::read, CookedRecipeData::write, RecipeType.SMOKING); + public static final RecipeSerializer CAMPFIRE_COOKING = define("campfire_cooking", + CookedRecipeData::read, CookedRecipeData::write, RecipeType.CAMPFIRE_COOKING); + public static final RecipeSerializer STONECUTTING = define("stonecutting", + StoneCuttingRecipeData::read, StoneCuttingRecipeData::write, RecipeType.STONECUTTING); + @Deprecated + public static final RecipeSerializer SMITHING = define("smithing_transform", + ew -> SmithingRecipeData.read(ew, true), + (ew, data) -> SmithingRecipeData.write(ew, data, true), + RecipeType.SMITHING); + public static final RecipeSerializer SMITHING_TRANSFORM = define("smithing_transform", + SmithingRecipeData::read, SmithingRecipeData::write, RecipeType.SMITHING); + public static final RecipeSerializer SMITHING_TRIM = define("smithing_trim", + SmithingTrimRecipeData::read, SmithingTrimRecipeData::write); + public static final RecipeSerializer CRAFTING_DECORATED_POT = define("crafting_decorated_pot", + SimpleRecipeData::read, SimpleRecipeData::write); + + /** + * Returns an immutable view of the banner patterns. + * + * @return Banner Patterns + */ + public static Collection> values() { + return Collections.unmodifiableCollection(PATTERN_TYPE_MAP.values()); + } + + static { + TYPES_BUILDER.unloadFileMappings(); + } +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeType.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeType.java index 5995efaffb..d58a751e51 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeType.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/RecipeType.java @@ -18,28 +18,45 @@ package com.github.retrooper.packetevents.protocol.recipe; +import org.jetbrains.annotations.Nullable; + // From MCProtocolLib +@Deprecated public enum RecipeType { - CRAFTING_SHAPELESS, - CRAFTING_SHAPED, - CRAFTING_SPECIAL_ARMORDYE, - CRAFTING_SPECIAL_BOOKCLONING, - CRAFTING_SPECIAL_MAPCLONING, - CRAFTING_SPECIAL_MAPEXTENDING, - CRAFTING_SPECIAL_FIREWORK_ROCKET, - CRAFTING_SPECIAL_FIREWORK_STAR, - CRAFTING_SPECIAL_FIREWORK_STAR_FADE, - CRAFTING_SPECIAL_REPAIRITEM, - CRAFTING_SPECIAL_TIPPEDARROW, - CRAFTING_SPECIAL_BANNERDUPLICATE, - CRAFTING_SPECIAL_BANNERADDPATTERN, - CRAFTING_SPECIAL_SHIELDDECORATION, - CRAFTING_SPECIAL_SHULKERBOXCOLORING, - CRAFTING_SPECIAL_SUSPICIOUSSTEW, - SMELTING, - BLASTING, - SMOKING, - CAMPFIRE_COOKING, - STONECUTTING, - SMITHING + + CRAFTING_SHAPELESS(RecipeSerializers.CRAFTING_SHAPELESS), + CRAFTING_SHAPED(RecipeSerializers.CRAFTING_SHAPED), + CRAFTING_SPECIAL_ARMORDYE(RecipeSerializers.CRAFTING_SPECIAL_ARMORDYE), + CRAFTING_SPECIAL_BOOKCLONING(RecipeSerializers.CRAFTING_SPECIAL_BOOKCLONING), + CRAFTING_SPECIAL_MAPCLONING(RecipeSerializers.CRAFTING_SPECIAL_MAPCLONING), + CRAFTING_SPECIAL_MAPEXTENDING(RecipeSerializers.CRAFTING_SPECIAL_MAPEXTENDING), + CRAFTING_SPECIAL_FIREWORK_ROCKET(RecipeSerializers.CRAFTING_SPECIAL_FIREWORK_ROCKET), + CRAFTING_SPECIAL_FIREWORK_STAR(RecipeSerializers.CRAFTING_SPECIAL_FIREWORK_STAR), + CRAFTING_SPECIAL_FIREWORK_STAR_FADE(RecipeSerializers.CRAFTING_SPECIAL_FIREWORK_STAR_FADE), + CRAFTING_SPECIAL_REPAIRITEM(RecipeSerializers.CRAFTING_SPECIAL_REPAIRITEM), + CRAFTING_SPECIAL_TIPPEDARROW(RecipeSerializers.CRAFTING_SPECIAL_TIPPEDARROW), + CRAFTING_SPECIAL_BANNERDUPLICATE(RecipeSerializers.CRAFTING_SPECIAL_BANNERDUPLICATE), + CRAFTING_SPECIAL_BANNERADDPATTERN(null), // I didn't find this anywhere + CRAFTING_SPECIAL_SHIELDDECORATION(RecipeSerializers.CRAFTING_SPECIAL_SHIELDDECORATION), + CRAFTING_SPECIAL_SHULKERBOXCOLORING(RecipeSerializers.CRAFTING_SPECIAL_SHULKERBOXCOLORING), + CRAFTING_SPECIAL_SUSPICIOUSSTEW(RecipeSerializers.CRAFTING_SPECIAL_SUSPICIOUSSTEW), + SMELTING(RecipeSerializers.SMELTING), + BLASTING(RecipeSerializers.BLASTING), + SMOKING(RecipeSerializers.SMOKING), + CAMPFIRE_COOKING(RecipeSerializers.CAMPFIRE_COOKING), + STONECUTTING(RecipeSerializers.STONECUTTING), + SMITHING(RecipeSerializers.SMITHING_TRANSFORM); + + private final @Nullable RecipeSerializer serializer; + + RecipeType(@Nullable RecipeSerializer serializer) { + this.serializer = serializer; + } + + public RecipeSerializer getSerializer() { + if (this.serializer == null) { + throw new UnsupportedOperationException("No serializer found for legacy recipe type " + this); + } + return this.serializer; + } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/CookedRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/CookedRecipeData.java index 76b557dd51..aa97f2aa9e 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/CookedRecipeData.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/CookedRecipeData.java @@ -18,45 +18,81 @@ package com.github.retrooper.packetevents.protocol.recipe.data; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.item.ItemStack; +import com.github.retrooper.packetevents.protocol.recipe.CookingCategory; import com.github.retrooper.packetevents.protocol.recipe.Ingredient; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; public class CookedRecipeData implements RecipeData { - private final @NotNull String group; - private final @NotNull Ingredient ingredient; + + private final String group; + private final CookingCategory category; + private final Ingredient ingredient; private final ItemStack result; private final float experience; private final int cookingTime; - public CookedRecipeData(@NotNull String group, @NotNull Ingredient ingredient, @NotNull ItemStack result, float experience, int cookingTime) { + @Deprecated + public CookedRecipeData(String group, Ingredient ingredient, ItemStack result, float experience, int cookingTime) { + this(group, CookingCategory.MISC, ingredient, result, experience, cookingTime); + } + + public CookedRecipeData( + String group, CookingCategory category, Ingredient ingredient, + ItemStack result, float experience, int cookingTime + ) { this.group = group; + this.category = category; this.ingredient = ingredient; this.result = result; this.experience = experience; this.cookingTime = cookingTime; } - @NotNull + public static CookedRecipeData read(PacketWrapper wrapper) { + String group = wrapper.readString(); + CookingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3) ? + wrapper.readEnum(CookingCategory.values()) : CookingCategory.MISC; + Ingredient ingredient = Ingredient.read(wrapper); + ItemStack result = wrapper.readItemStack(); + float experience = wrapper.readFloat(); + int cookingTime = wrapper.readVarInt(); + return new CookedRecipeData(group, category, ingredient, result, experience, cookingTime); + } + + public static void write(PacketWrapper wrapper, CookedRecipeData data) { + wrapper.writeString(data.group); + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) { + wrapper.writeEnum(data.category); + } + Ingredient.write(wrapper, data.ingredient); + wrapper.writeItemStack(data.result); + wrapper.writeFloat(data.experience); + wrapper.writeVarInt(data.cookingTime); + } + public String getGroup() { - return group; + return this.group; + } + + public CookingCategory getCategory() { + return this.category; } - @NotNull public Ingredient getIngredient() { - return ingredient; + return this.ingredient; } - @NotNull public ItemStack getResult() { - return result; + return this.result; } public float getExperience() { - return experience; + return this.experience; } public int getCookingTime() { - return cookingTime; + return this.cookingTime; } -} \ No newline at end of file +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapedRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapedRecipeData.java index ce27d32e2d..6dae3b14c9 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapedRecipeData.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapedRecipeData.java @@ -18,42 +18,119 @@ package com.github.retrooper.packetevents.protocol.recipe.data; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.item.ItemStack; +import com.github.retrooper.packetevents.protocol.recipe.CraftingCategory; import com.github.retrooper.packetevents.protocol.recipe.Ingredient; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; public class ShapedRecipeData implements RecipeData { + + private final String group; + private final CraftingCategory category; + private final ItemStack result; + private final boolean showNotification; + + // pattern private final int width; private final int height; - private final @NotNull String group; - private final @NotNull Ingredient[] ingredients; - private final ItemStack result; + private final Ingredient[] ingredients; - public ShapedRecipeData(final int width, final int height, final @NotNull String group, final @NotNull Ingredient[] ingredients, final ItemStack result) { + @Deprecated + public ShapedRecipeData(int width, int height, String group, Ingredient[] ingredients, ItemStack result) { + this(group, CraftingCategory.MISC, result, true, width, height, ingredients); + } + + public ShapedRecipeData( + String group, CraftingCategory category, ItemStack result, boolean showNotification, + int width, int height, Ingredient[] ingredients + ) { + if (width * height != ingredients.length) { + throw new IllegalArgumentException("Illegal ingredients length, found " + ingredients.length + + " but expected " + width + " * " + height); + } + + this.group = group; + this.category = category; + this.result = result; + this.showNotification = showNotification; this.width = width; this.height = height; - this.group = group; this.ingredients = ingredients; - this.result = result; } - public int getWidth() { - return this.width; + public static ShapedRecipeData read(PacketWrapper wrapper) { + int width = 0, height = 0; + if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_20_3)) { + width = wrapper.readVarInt(); + height = wrapper.readVarInt(); + } + String group = wrapper.readString(); + CraftingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3) + ? wrapper.readEnum(CraftingCategory.values()) : CraftingCategory.MISC; + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_3)) { + width = wrapper.readVarInt(); + height = wrapper.readVarInt(); + } + Ingredient[] ingredients = new Ingredient[width * height]; + for (int i = 0; i < ingredients.length; i++) { + ingredients[i] = Ingredient.read(wrapper); + } + ItemStack result = wrapper.readItemStack(); + boolean showNotification = true; + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4)) { + showNotification = wrapper.readBoolean(); + } + return new ShapedRecipeData(group, category, result, showNotification, width, height, ingredients); } - public int getHeight() { - return this.height; + public static void write(PacketWrapper wrapper, ShapedRecipeData data) { + if (wrapper.getServerVersion().isOlderThan(ServerVersion.V_1_20_3)) { + wrapper.writeVarInt(data.width); + wrapper.writeVarInt(data.height); + } + wrapper.writeString(data.group); + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) { + wrapper.writeEnum(data.category); + } + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20_3)) { + wrapper.writeVarInt(data.width); + wrapper.writeVarInt(data.height); + } + for (Ingredient ingredient : data.ingredients) { + Ingredient.write(wrapper, ingredient); + } + wrapper.writeItemStack(data.result); + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4)) { + wrapper.writeBoolean(data.showNotification); + } } - public @NotNull String getGroup() { + public String getGroup() { return this.group; } - public @NotNull Ingredient[] getIngredients() { - return this.ingredients; + public CraftingCategory getCategory() { + return this.category; } public ItemStack getResult() { return this.result; } -} \ No newline at end of file + + public boolean isShowNotification() { + return this.showNotification; + } + + public int getWidth() { + return this.width; + } + + public int getHeight() { + return this.height; + } + + public Ingredient[] getIngredients() { + return this.ingredients; + } +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapelessRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapelessRecipeData.java index a37a7a3270..aafbd37f09 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapelessRecipeData.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/ShapelessRecipeData.java @@ -18,30 +18,62 @@ package com.github.retrooper.packetevents.protocol.recipe.data; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.item.ItemStack; +import com.github.retrooper.packetevents.protocol.recipe.CraftingCategory; import com.github.retrooper.packetevents.protocol.recipe.Ingredient; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; public class ShapelessRecipeData implements RecipeData { - private final @NotNull String group; - private final @NotNull Ingredient[] ingredients; + + private final String group; + private final CraftingCategory category; + private final Ingredient[] ingredients; private final ItemStack result; - public ShapelessRecipeData(@NotNull String group, @NotNull Ingredient[] ingredients, @NotNull ItemStack result) { + @Deprecated + public ShapelessRecipeData(String group, Ingredient[] ingredients, ItemStack result) { + this(group, CraftingCategory.MISC, ingredients, result); + } + + public ShapelessRecipeData(String group, CraftingCategory category, Ingredient[] ingredients, ItemStack result) { this.group = group; + this.category = category; this.ingredients = ingredients; this.result = result; } - public @NotNull String getGroup() { - return group; + public static ShapelessRecipeData read(PacketWrapper wrapper) { + String group = wrapper.readString(); + CraftingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3) + ? wrapper.readEnum(CraftingCategory.values()) : CraftingCategory.MISC; + Ingredient[] ingredients = wrapper.readArray(Ingredient::read, Ingredient.class); + ItemStack result = wrapper.readItemStack(); + return new ShapelessRecipeData(group, category, ingredients, result); + } + + public static void write(PacketWrapper wrapper, ShapelessRecipeData data) { + wrapper.writeString(data.group); + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) { + wrapper.writeEnum(data.category); + } + wrapper.writeArray(data.ingredients, Ingredient::write); + wrapper.writeItemStack(data.result); + } + + public String getGroup() { + return this.group; + } + + public CraftingCategory getCategory() { + return this.category; } - public @NotNull Ingredient[] getIngredients() { - return ingredients; + public Ingredient[] getIngredients() { + return this.ingredients; } - public @NotNull ItemStack getResult() { - return result; + public ItemStack getResult() { + return this.result; } -} \ No newline at end of file +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SimpleRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SimpleRecipeData.java new file mode 100644 index 0000000000..37c9a30b27 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SimpleRecipeData.java @@ -0,0 +1,48 @@ +/* + * This file is part of packetevents - https://github.com/retrooper/packetevents + * Copyright (C) 2024 retrooper and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.github.retrooper.packetevents.protocol.recipe.data; + +import com.github.retrooper.packetevents.manager.server.ServerVersion; +import com.github.retrooper.packetevents.protocol.recipe.CraftingCategory; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; + +public class SimpleRecipeData implements RecipeData { + + private final CraftingCategory category; + + public SimpleRecipeData(CraftingCategory category) { + this.category = category; + } + + public static SimpleRecipeData read(PacketWrapper wrapper) { + CraftingCategory category = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3) + ? wrapper.readEnum(CraftingCategory.values()) : CraftingCategory.MISC; + return new SimpleRecipeData(category); + } + + public static void write(PacketWrapper wrapper, SimpleRecipeData data) { + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_3)) { + wrapper.writeEnum(data.getCategory()); + } + } + + public CraftingCategory getCategory() { + return this.category; + } +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingRecipeData.java index c32f216f54..be14a5f97d 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingRecipeData.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingRecipeData.java @@ -18,32 +18,75 @@ package com.github.retrooper.packetevents.protocol.recipe.data; +import com.github.retrooper.packetevents.manager.server.ServerVersion; import com.github.retrooper.packetevents.protocol.item.ItemStack; import com.github.retrooper.packetevents.protocol.recipe.Ingredient; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; +import org.jetbrains.annotations.UnknownNullability; public class SmithingRecipeData implements RecipeData { - private final @NotNull Ingredient base; - private final @NotNull Ingredient addition; + + private final @UnknownNullability Ingredient template; + private final Ingredient base; + private final Ingredient addition; private final ItemStack result; - public SmithingRecipeData(@NotNull Ingredient base, @NotNull Ingredient addition, ItemStack result) { + @Deprecated + public SmithingRecipeData(Ingredient base, Ingredient addition, ItemStack result) { + this(null, base, addition, result); + } + + public SmithingRecipeData( + @UnknownNullability Ingredient template, + Ingredient base, Ingredient addition, ItemStack result + ) { + this.template = template; this.base = base; this.addition = addition; this.result = result; } - @NotNull + public static SmithingRecipeData read(PacketWrapper wrapper) { + return read(wrapper, false); + } + + public static SmithingRecipeData read(PacketWrapper wrapper, boolean legacy) { + Ingredient template = wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20) + || (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4) && !legacy) + ? Ingredient.read(wrapper) : null; + Ingredient base = Ingredient.read(wrapper); + Ingredient addition = Ingredient.read(wrapper); + ItemStack result = wrapper.readItemStack(); + return new SmithingRecipeData(template, base, addition, result); + } + + public static void write(PacketWrapper wrapper, SmithingRecipeData data) { + write(wrapper, data, false); + } + + public static void write(PacketWrapper wrapper, SmithingRecipeData data, boolean legacy) { + if (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_20) + || (wrapper.getServerVersion().isNewerThanOrEquals(ServerVersion.V_1_19_4) && !legacy)) { + Ingredient.write(wrapper, data.template); + } + Ingredient.write(wrapper, data.base); + Ingredient.write(wrapper, data.addition); + wrapper.writeItemStack(data.result); + } + + public @UnknownNullability Ingredient getTemplate() { + return this.template; + } + public Ingredient getBase() { - return base; + return this.base; } - @NotNull public Ingredient getAddition() { - return addition; + return this.addition; } public ItemStack getResult() { - return result; + return this.result; } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingTrimRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingTrimRecipeData.java new file mode 100644 index 0000000000..4b484096c1 --- /dev/null +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/SmithingTrimRecipeData.java @@ -0,0 +1,60 @@ +/* + * This file is part of packetevents - https://github.com/retrooper/packetevents + * Copyright (C) 2024 retrooper and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.github.retrooper.packetevents.protocol.recipe.data; + +import com.github.retrooper.packetevents.protocol.recipe.Ingredient; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; + +public class SmithingTrimRecipeData implements RecipeData { + + private final Ingredient template; + private final Ingredient base; + private final Ingredient addition; + + public SmithingTrimRecipeData(Ingredient template, Ingredient base, Ingredient addition) { + this.template = template; + this.base = base; + this.addition = addition; + } + + public static SmithingTrimRecipeData read(PacketWrapper wrapper) { + Ingredient template = Ingredient.read(wrapper); + Ingredient base = Ingredient.read(wrapper); + Ingredient addition = Ingredient.read(wrapper); + return new SmithingTrimRecipeData(template, base, addition); + } + + public static void write(PacketWrapper wrapper, SmithingTrimRecipeData data) { + Ingredient.write(wrapper, data.template); + Ingredient.write(wrapper, data.base); + Ingredient.write(wrapper, data.addition); + } + + public Ingredient getTemplate() { + return this.template; + } + + public Ingredient getBase() { + return this.base; + } + + public Ingredient getAddition() { + return this.addition; + } +} diff --git a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/StoneCuttingRecipeData.java b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/StoneCuttingRecipeData.java index 14354340db..94471a9289 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/StoneCuttingRecipeData.java +++ b/api/src/main/java/com/github/retrooper/packetevents/protocol/recipe/data/StoneCuttingRecipeData.java @@ -20,31 +20,42 @@ import com.github.retrooper.packetevents.protocol.item.ItemStack; import com.github.retrooper.packetevents.protocol.recipe.Ingredient; -import org.jetbrains.annotations.NotNull; +import com.github.retrooper.packetevents.wrapper.PacketWrapper; public class StoneCuttingRecipeData implements RecipeData { - private final @NotNull String group; - private final @NotNull Ingredient ingredient; + + private final String group; + private final Ingredient ingredient; private final ItemStack result; - public StoneCuttingRecipeData(@NotNull String group, @NotNull Ingredient ingredient, ItemStack result) { + public StoneCuttingRecipeData(String group, Ingredient ingredient, ItemStack result) { this.group = group; this.ingredient = ingredient; this.result = result; } - @NotNull + public static StoneCuttingRecipeData read(PacketWrapper wrapper) { + String group = wrapper.readString(); + Ingredient ingredient = Ingredient.read(wrapper); + ItemStack result = wrapper.readItemStack(); + return new StoneCuttingRecipeData(group, ingredient, result); + } + + public static void write(PacketWrapper wrapper, StoneCuttingRecipeData data) { + wrapper.writeString(data.group); + Ingredient.write(wrapper, data.ingredient); + wrapper.writeItemStack(data.result); + } + public String getGroup() { - return group; + return this.group; } - @NotNull public Ingredient getIngredient() { - return ingredient; + return this.ingredient; } - @NotNull public ItemStack getResult() { - return result; + return this.result; } } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java index 39b27d6c8b..ddf6d1257f 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/PacketWrapper.java @@ -79,6 +79,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Array; import java.nio.charset.StandardCharsets; import java.security.PublicKey; import java.time.Instant; @@ -1399,6 +1400,23 @@ public void writeList(List list, Writer writer) { } } + @SuppressWarnings("unchecked") // not unchecked + public K[] readArray(Reader reader, Class clazz) { + int length = this.readVarInt(); + K[] array = (K[]) Array.newInstance(clazz, length); + for (int i = 0; i < length; i++) { + array[i] = reader.apply(this); + } + return array; + } + + public void writeArray(K[] array, Writer writer) { + this.writeVarInt(array.length); + for (K element : array) { + writer.accept(this, element); + } + } + public > Z readEnum(Class clazz) { return this.readEnum(clazz.getEnumConstants()); } diff --git a/api/src/main/java/com/github/retrooper/packetevents/wrapper/play/server/WrapperPlayServerDeclareRecipes.java b/api/src/main/java/com/github/retrooper/packetevents/wrapper/play/server/WrapperPlayServerDeclareRecipes.java index 67bd3ce327..31ad0ca068 100644 --- a/api/src/main/java/com/github/retrooper/packetevents/wrapper/play/server/WrapperPlayServerDeclareRecipes.java +++ b/api/src/main/java/com/github/retrooper/packetevents/wrapper/play/server/WrapperPlayServerDeclareRecipes.java @@ -19,189 +19,37 @@ package com.github.retrooper.packetevents.wrapper.play.server; import com.github.retrooper.packetevents.event.PacketSendEvent; -import com.github.retrooper.packetevents.protocol.item.ItemStack; -import com.github.retrooper.packetevents.protocol.recipe.Ingredient; import com.github.retrooper.packetevents.protocol.recipe.Recipe; -import com.github.retrooper.packetevents.protocol.recipe.RecipeType; -import com.github.retrooper.packetevents.protocol.recipe.data.*; import com.github.retrooper.packetevents.wrapper.PacketWrapper; -import java.util.Locale; - -// Copy and pasted from MCProtocolLib public class WrapperPlayServerDeclareRecipes extends PacketWrapper { - private Recipe[] recipes; + + private Recipe[] recipes; public WrapperPlayServerDeclareRecipes(PacketSendEvent event) { super(event); } - public Recipe[] getRecipes() { - return this.recipes; - } - - public void setRecipes(Recipe[] recipes) { - this.recipes = recipes; - } - @Override public void read() { - this.recipes = new Recipe[readVarInt()]; - for (int i = 0; i < this.recipes.length; i++) { - RecipeType type = RecipeType.valueOf(readString().replace("minecraft:", "").toUpperCase(Locale.ROOT)); - String identifier = readString(); - RecipeData data = null; - switch (type) { - case CRAFTING_SHAPELESS: { - String group = readString(); - Ingredient[] ingredients = new Ingredient[readVarInt()]; - for (int j = 0; j < ingredients.length; j++) { - ingredients[j] = this.readIngredient(); - } - - ItemStack result = readItemStack(); - - data = new ShapelessRecipeData(group, ingredients, result); - break; - } - case CRAFTING_SHAPED: { - int width = readVarInt(); - int height = readVarInt(); - String group = readString(); - Ingredient[] ingredients = new Ingredient[width * height]; - for (int j = 0; j < ingredients.length; j++) { - ingredients[j] = this.readIngredient(); - } - - ItemStack result = readItemStack(); - - data = new ShapedRecipeData(width, height, group, ingredients, result); - break; - } - case SMELTING: - case BLASTING: - case SMOKING: - case CAMPFIRE_COOKING: { - String group = readString(); - Ingredient ingredient = this.readIngredient(); - ItemStack result = readItemStack(); - float experience = readFloat(); - int cookingTime = readVarInt(); - - data = new CookedRecipeData(group, ingredient, result, experience, cookingTime); - break; - } - case STONECUTTING: { - String group = readString(); - Ingredient ingredient = this.readIngredient(); - ItemStack result = readItemStack(); - - data = new StoneCuttingRecipeData(group, ingredient, result); - break; - } - case SMITHING: { - Ingredient base = this.readIngredient(); - Ingredient addition = this.readIngredient(); - ItemStack result = readItemStack(); - - data = new SmithingRecipeData(base, addition, result); - break; - } - default: - break; - } - - this.recipes[i] = new Recipe(type, identifier, data); - } + this.recipes = this.readArray(Recipe::read, Recipe.class); } - private Ingredient readIngredient() { - ItemStack[] options = new ItemStack[readVarInt()]; - for (int i = 0; i < options.length; i++) { - options[i] = readItemStack(); - } - - return new Ingredient(options); - } - - private void writeIngredient(Ingredient ingredient) { - writeVarInt(ingredient.getOptions().length); - for (ItemStack option : ingredient.getOptions()) { - writeItemStack(option); - } + @Override + public void write() { + this.writeArray(this.recipes, Recipe::write); } + @Override public void copy(WrapperPlayServerDeclareRecipes wrapper) { this.recipes = wrapper.recipes; } - @Override - public void write() { - writeVarInt(this.recipes.length); - for (Recipe recipe : this.recipes) { - writeString("minecraft:" + recipe.getType().toString().toLowerCase(Locale.ROOT)); - writeString(recipe.getIdentifier()); - switch (recipe.getType()) { - case CRAFTING_SHAPELESS: { - ShapelessRecipeData data = (ShapelessRecipeData) recipe.getData(); - - writeString(data.getGroup()); - writeVarInt(data.getIngredients().length); - for (Ingredient ingredient : data.getIngredients()) { - this.writeIngredient(ingredient); - } - - writeItemStack(data.getResult()); - break; - } - case CRAFTING_SHAPED: { - ShapedRecipeData data = (ShapedRecipeData) recipe.getData(); - if (data.getIngredients().length != data.getWidth() * data.getHeight()) { - throw new IllegalStateException("Shaped recipe must have ingredient count equal to width * height."); - } - - writeVarInt(data.getWidth()); - writeVarInt(data.getHeight()); - writeString(data.getGroup()); - for (Ingredient ingredient : data.getIngredients()) { - this.writeIngredient(ingredient); - } - - writeItemStack(data.getResult()); - break; - } - case SMELTING: - case BLASTING: - case SMOKING: - case CAMPFIRE_COOKING: { - CookedRecipeData data = (CookedRecipeData) recipe.getData(); - - writeString(data.getGroup()); - this.writeIngredient(data.getIngredient()); - writeItemStack(data.getResult()); - writeFloat(data.getExperience()); - writeVarInt(data.getCookingTime()); - break; - } - case STONECUTTING: { - StoneCuttingRecipeData data = (StoneCuttingRecipeData) recipe.getData(); - - writeString(data.getGroup()); - this.writeIngredient(data.getIngredient()); - writeItemStack(data.getResult()); - break; - } - case SMITHING: { - SmithingRecipeData data = (SmithingRecipeData) recipe.getData(); + public Recipe[] getRecipes() { + return this.recipes; + } - this.writeIngredient(data.getBase()); - this.writeIngredient(data.getAddition()); - writeItemStack(data.getResult()); - break; - } - default: - break; - } - } + public void setRecipes(Recipe[] recipes) { + this.recipes = recipes; } } diff --git a/mappings/item/recipe_serializer_mappings.json b/mappings/item/recipe_serializer_mappings.json new file mode 100644 index 0000000000..94e3481824 --- /dev/null +++ b/mappings/item/recipe_serializer_mappings.json @@ -0,0 +1,27 @@ +{ + "V_1_20_5": [ + "crafting_shaped", + "crafting_shapeless", + "crafting_special_armordye", + "crafting_special_bookcloning", + "crafting_special_mapcloning", + "crafting_special_mapextending", + "crafting_special_firework_rocket", + "crafting_special_firework_star", + "crafting_special_firework_star_fade", + "crafting_special_tippedarrow", + "crafting_special_bannerduplicate", + "crafting_special_shielddecoration", + "crafting_special_shulkerboxcoloring", + "crafting_special_suspiciousstew", + "crafting_special_repairitem", + "smelting", + "blasting", + "smoking", + "campfire_cooking", + "stonecutting", + "smithing_transform", + "smithing_trim", + "crafting_decorated_pot" + ] +}