Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding CustomModelChoice to bukkit recipe system #9991

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions patches/api/0449-Adding-CustomModelChoice.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: derverdox <[email protected]>
Date: Thu, 30 Nov 2023 13:20:23 +0100
Subject: [PATCH] Adding CustomModelChoice

CustomModelChoice is used to create recipes that not only compare for materials but also CustomModelData.
Using the ExactChoice alternative is not a good idea since items can have different lores or attributes.
This is a great way to implement recipes with the new possibilities of Minecraft custom items.


diff --git a/src/main/java/org/bukkit/inventory/CustomItemData.java b/src/main/java/org/bukkit/inventory/CustomItemData.java
new file mode 100644
index 0000000000000000000000000000000000000000..3adbb5dbe9d53522b1ef528ba4c86d43f1dcef16
--- /dev/null
+++ b/src/main/java/org/bukkit/inventory/CustomItemData.java
@@ -0,0 +1,52 @@
+package org.bukkit.inventory;
+
+import org.bukkit.Material;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * CustomItemData representing a vanilla material and a customModelData value.
+ * Is used in {@link RecipeChoice.CustomModelChoice}
+ * @param material The vanilla material
+ * @param customModelData the customModelData value of the item.
+ */
+public record CustomItemData(@NotNull Material material, int customModelData) {
+ /**
+ * Creates an item stack with the material and the customModelData of the CustomItemDataObject
+ * @return the new item stack
+ */
+ public @NotNull ItemStack createStack() {
+ var stack = new ItemStack(material);
derverdox marked this conversation as resolved.
Show resolved Hide resolved
+ stack.editMeta(meta -> meta.setCustomModelData(customModelData));
+ return stack;
+ }
+
+ /**
+ * Checks if the provided item stack is equal based on its material and customModelData
+ * @param stackToCheck The item stack to check
+ * @return true if they are equal
+ */
+ public boolean isSame(@Nullable ItemStack stackToCheck) {
+ if(stackToCheck == null)
+ return false;
+ if (!stackToCheck.getType().equals(material))
+ return false;
derverdox marked this conversation as resolved.
Show resolved Hide resolved
+ return customModelData == ItemStack.getCustomModelData(stackToCheck);
+ }
+
+ /**
+ * Reads the CustomItemData from an item stack
+ * @param stack The item stack
+ * @return a new CustomItemData object
+ */
+ public static CustomItemData fromItemStack(@NotNull ItemStack stack){
+ return new CustomItemData(stack.getType(), ItemStack.getCustomModelData(stack));
+ }
+ @Override
+ public String toString() {
+ return "CustomItemData{" +
+ "material=" + material +
+ ", customModelData=" + customModelData +
+ '}';
+ }
+}
diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java
index 0af73cc04edb93b9772136d4d808f657ea40e733..184cd662885f3ec96308315532631b9740f0a7f7 100644
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
@@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap;
import java.util.LinkedHashMap;
import java.util.List; // Paper
import java.util.Map;
+import java.util.Objects;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Translatable;
@@ -1005,4 +1006,32 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
return type.isAir() || amount <= 0;
}
// Paper end
+
+ // Paper start - Adding CustomModelChoice to bukkit recipes
+ /**
+ * Helper method to set customModelData of an ItemStack
+ * @param stack the ItemStack
+ * @param customModelData the new customModelData
+ */
+ public static void setCustomModelData(@NotNull ItemStack stack, int customModelData){
+ Objects.requireNonNull(stack);
+ stack.editMeta(meta -> meta.setCustomModelData(customModelData));
+ }
+
+ /**
+ * Helper method to get the customModelData of an ItemStack
+ * @param stack the ItemStack
+ * @return the customModelData
+ */
+
derverdox marked this conversation as resolved.
Show resolved Hide resolved
+ public static int getCustomModelData(ItemStack stack){
+ if(stack == null || stack.getType().isAir())
+ return 0;
+ if(!stack.hasItemMeta())
+ return 0;
+ if(!stack.getItemMeta().hasCustomModelData())
+ return 0;
+ return stack.getItemMeta().getCustomModelData();
+ }
+ // Paper end - Adding CustomModelChoice to bukkit recipes
}
diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java
index 523818cbb0d6c90481ec97123e7fe0e2ff4eea14..f4cd027cb9adb23ae31dacba7d5205e431f2289e 100644
--- a/src/main/java/org/bukkit/inventory/RecipeChoice.java
+++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java
@@ -233,4 +233,67 @@ public interface RecipeChoice extends Predicate<ItemStack>, Cloneable {
return "ExactChoice{" + "choices=" + choices + '}';
}
}
+ // Paper start - Adding CustomModelChoice to bukkit recipes
+ /**
+ * Represents a choice of multiple matching materials and customModelData values.
+ */
+ public static class CustomModelChoice implements RecipeChoice {
+ private final List<CustomItemData> choices;
+
+ public CustomModelChoice(List<CustomItemData> customItemDataList) {
+ this.choices = Collections.unmodifiableList(customItemDataList);
+ }
+
+ public CustomModelChoice(CustomItemData customItemData) {
+ this.choices = Collections.unmodifiableList(List.of(customItemData));
+ }
+
+ public CustomModelChoice(Material material, int customModelData) {
+ this.choices = Collections.unmodifiableList(List.of(new CustomItemData(material, customModelData)));
+ }
+
+ @Override
+ public @NotNull ItemStack getItemStack() {
+ var choice = choices.get(0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use var

+ return choice.createStack();
+ }
+
+ @Override
+ public @NotNull RecipeChoice clone() {
+ return new CustomModelChoice(this.choices);
+ }
+
+ @Override
+ public boolean test(@NotNull ItemStack stackToCheck) {
+ for (CustomItemData choice : choices) {
+ if(choice.isSame(stackToCheck))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CustomModelChoice that = (CustomModelChoice) o;
+ return Objects.equals(choices, that.choices);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(choices);
+ }
+
+ @Override
+ public String toString() {
+ return "CustomModelChoice{" +
+ "choices=" + choices +
+ '}';
+ }
+
+ public List<CustomItemData> getChoices() {
+ return this.choices;
+ }
+ } // Paper end - Adding CustomModelChoice to bukkit recipes
}
110 changes: 110 additions & 0 deletions patches/server/1055-Adding-CustomModelChoice.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: derverdox <[email protected]>
Date: Thu, 30 Nov 2023 13:20:22 +0100
Subject: [PATCH] Adding CustomModelChoice


diff --git a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
index 06fe5b056d78d42cdf78437eeabe1786d596b7f8..4ffc47b8788176eb60412235e021e39a5f0afd2a 100644
--- a/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
+++ b/src/main/java/net/minecraft/world/item/crafting/Ingredient.java
@@ -29,6 +29,7 @@ import net.minecraft.world.entity.player.StackedContents;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;

public final class Ingredient implements Predicate<ItemStack> {

@@ -39,6 +40,7 @@ public final class Ingredient implements Predicate<ItemStack> {
@Nullable
private IntList stackingIds;
public boolean exact; // CraftBukkit
+ public boolean isCustomModelChoice = true; // Paper
public static final Codec<Ingredient> CODEC = Ingredient.codec(true);
public static final Codec<Ingredient> CODEC_NONEMPTY = Ingredient.codec(false);

@@ -84,6 +86,13 @@ public final class Ingredient implements Predicate<ItemStack> {

continue;
}
+ else if(this.isCustomModelChoice){ // Paper start - Adding CustomModelChoice to bukkit recipes
+ var material = itemstack.getBukkitStack().getType();
+ var customModelData = CraftItemStack.getCustomModelData(itemstack);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use var

+ if(itemstack1.getBukkitStack().getType().equals(material) && CraftItemStack.getCustomModelData(itemstack1) == customModelData)
+ return true;
+ continue;
+ } // Paper end - Adding CustomModelChoice to bukkit recipes
// CraftBukkit end
if (itemstack1.is(itemstack.getItem())) {
return true;
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index 654694515b4b9257a41c8623675fa3abc51a1cb7..938371a98e128dfd8e4fb4fa9fa1e6e623bba75d 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -23,6 +23,19 @@ import org.bukkit.material.MaterialData;
@DelegateDeserialization(ItemStack.class)
public final class CraftItemStack extends ItemStack {

+ // Paper start - Adding CustomModelChoice to bukkit recipes
+ public static void setCustomModelData(net.minecraft.world.item.ItemStack stack, int customModelData){
+ stack.getOrCreateTag().putInt("CustomModelData", customModelData);
+ }
+ public static int getCustomModelData(net.minecraft.world.item.ItemStack stack){
derverdox marked this conversation as resolved.
Show resolved Hide resolved
+ if(!stack.hasTag())
+ return 0;
+ if(!stack.getTag().contains("CustomModelData"))
+ return 0;
+ return stack.getTag().getInt("CustomModelData");
+ }
+ // Paper end - Adding CustomModelChoice to bukkit recipes
+
// Paper start - MC Utils
public static net.minecraft.world.item.ItemStack unwrap(ItemStack bukkit) {
if (bukkit instanceof CraftItemStack craftItemStack) {
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
index 13d25d118eb4d3ef35a4cdfb9bbde9ed83f6c04b..dd639231955150736bd9776032374d682617c39b 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftRecipe.java
@@ -3,6 +3,7 @@ package org.bukkit.craftbukkit.inventory;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.List;
+import org.bukkit.inventory.CustomItemData;
import net.minecraft.world.item.crafting.Ingredient;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.inventory.ItemStack;
@@ -30,7 +31,15 @@ public interface CraftRecipe extends Recipe {
} else if (bukkit instanceof RecipeChoice.ExactChoice) {
stack = new Ingredient(((RecipeChoice.ExactChoice) bukkit).getChoices().stream().map((mat) -> new net.minecraft.world.item.crafting.Ingredient.ItemValue(CraftItemStack.asNMSCopy(mat))));
stack.exact = true;
- } else {
+ } // Paper start - Adding CustomModelChoice to bukkit recipes
+ else if (bukkit instanceof RecipeChoice.CustomModelChoice choice) {
+ stack = new Ingredient(choice.getChoices().stream()
+ .map(customItemData -> CraftItemStack.asNMSCopy(customItemData.createStack()))
+ .map(Ingredient.ItemValue::new)
+ );
+ stack.isCustomModelChoice = true;
+ }
+ else { // Paper end - Adding CustomModelChoice to bukkit recipes
derverdox marked this conversation as resolved.
Show resolved Hide resolved
throw new IllegalArgumentException("Unknown recipe stack instance " + bukkit);
}

@@ -56,7 +65,15 @@ public interface CraftRecipe extends Recipe {
}

return new RecipeChoice.ExactChoice(choices);
- } else {
+ } // Paper start - Adding CustomModelChoice to bukkit recipes
+ else if(list.isCustomModelChoice){
+ List<CustomItemData> choices = new ArrayList<>(list.itemStacks.length);
+ for (net.minecraft.world.item.ItemStack i : list.itemStacks) {
+ choices.add(CustomItemData.fromItemStack(CraftItemStack.asBukkitCopy(i)));
+ }
+ return new RecipeChoice.CustomModelChoice(choices);
+ }
+ else { // Paper end - Adding CustomModelChoice to bukkit recipes
derverdox marked this conversation as resolved.
Show resolved Hide resolved

List<org.bukkit.Material> choices = new ArrayList<>(list.itemStacks.length);
for (net.minecraft.world.item.ItemStack i : list.itemStacks) {
Loading