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"
+ ]
+}