geforkt von Mirrors/Paper
Improve Recipe validation (#10707)
Dieser Commit ist enthalten in:
Ursprung
def79f079d
Commit
eba7123352
252
patches/api/Improve-Recipe-validation.patch
Normale Datei
252
patches/api/Improve-Recipe-validation.patch
Normale Datei
@ -0,0 +1,252 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Sun, 12 May 2024 10:42:42 -0700
|
||||
Subject: [PATCH] Improve Recipe validation
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/inventory/CookingRecipe.java b/src/main/java/org/bukkit/inventory/CookingRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/CookingRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/CookingRecipe.java
|
||||
@@ -0,0 +0,0 @@ public abstract class CookingRecipe<T extends CookingRecipe> implements Recipe,
|
||||
* @param cookingTime The cooking time (in ticks)
|
||||
*/
|
||||
public CookingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice input, float experience, int cookingTime) {
|
||||
- Preconditions.checkArgument(result.getType() != Material.AIR, "Recipe must have non-AIR result.");
|
||||
+ Preconditions.checkArgument(!result.isEmpty(), "Recipe cannot have an empty result."); // Paper
|
||||
this.key = key;
|
||||
this.output = new ItemStack(result);
|
||||
- this.ingredient = input;
|
||||
+ this.ingredient = input.validate().clone(); // Paper
|
||||
this.experience = experience;
|
||||
this.cookingTime = cookingTime;
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public abstract class CookingRecipe<T extends CookingRecipe> implements Recipe,
|
||||
*/
|
||||
@NotNull
|
||||
public T setInputChoice(@NotNull RecipeChoice input) {
|
||||
- this.ingredient = input;
|
||||
+ this.ingredient = input.validate().clone(); // Paper
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/inventory/CraftingRecipe.java b/src/main/java/org/bukkit/inventory/CraftingRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/CraftingRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/CraftingRecipe.java
|
||||
@@ -0,0 +0,0 @@ public abstract class CraftingRecipe implements Recipe, Keyed {
|
||||
|
||||
protected CraftingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result) {
|
||||
Preconditions.checkArgument(key != null, "key cannot be null");
|
||||
- Preconditions.checkArgument(result.getType() != Material.AIR, "Recipe must have non-AIR result.");
|
||||
+ Preconditions.checkArgument(!result.isEmpty(), "Recipe cannot have an empty result."); // Paper
|
||||
this.key = key;
|
||||
this.output = new ItemStack(result);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/inventory/MerchantRecipe.java b/src/main/java/org/bukkit/inventory/MerchantRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/MerchantRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/MerchantRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class MerchantRecipe implements Recipe {
|
||||
this(result, uses, maxUses, experienceReward, villagerExperience, priceMultiplier, 0, 0, ignoreDiscounts);
|
||||
}
|
||||
public MerchantRecipe(@NotNull ItemStack result, int uses, int maxUses, boolean experienceReward, int villagerExperience, float priceMultiplier, int demand, int specialPrice, boolean ignoreDiscounts) {
|
||||
+ Preconditions.checkArgument(!result.isEmpty(), "Recipe cannot have an empty result."); // Paper
|
||||
this.ignoreDiscounts = ignoreDiscounts;
|
||||
// Paper end
|
||||
this.result = result;
|
||||
@@ -0,0 +0,0 @@ public class MerchantRecipe implements Recipe {
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack getResult() {
|
||||
- return result;
|
||||
+ return result.clone(); // Paper
|
||||
}
|
||||
|
||||
public void addIngredient(@NotNull ItemStack item) {
|
||||
Preconditions.checkState(ingredients.size() < 2, "MerchantRecipe can only have maximum 2 ingredients");
|
||||
+ Preconditions.checkArgument(!item.isEmpty(), "Recipe cannot have an empty itemstack ingredient."); // Paper
|
||||
ingredients.add(item.clone());
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class MerchantRecipe implements Recipe {
|
||||
Preconditions.checkState(ingredients.size() <= 2, "MerchantRecipe can only have maximum 2 ingredients");
|
||||
this.ingredients = new ArrayList<ItemStack>();
|
||||
for (ItemStack item : ingredients) {
|
||||
+ Preconditions.checkArgument(!item.isEmpty(), "Recipe cannot have an empty itemstack ingredient."); // Paper
|
||||
this.ingredients.add(item.clone());
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/RecipeChoice.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java
|
||||
@@ -0,0 +0,0 @@ public interface RecipeChoice extends Predicate<ItemStack>, Cloneable {
|
||||
@Override
|
||||
boolean test(@NotNull ItemStack itemStack);
|
||||
|
||||
+ // Paper start - check valid ingredients
|
||||
+ @org.jetbrains.annotations.ApiStatus.Internal
|
||||
+ default @NotNull RecipeChoice validate() {
|
||||
+ return this;
|
||||
+ }
|
||||
+ // Paper end - check valid ingredients
|
||||
+
|
||||
/**
|
||||
* Represents a choice of multiple matching Materials.
|
||||
*/
|
||||
@@ -0,0 +0,0 @@ public interface RecipeChoice extends Predicate<ItemStack>, Cloneable {
|
||||
public ExactChoice clone() {
|
||||
try {
|
||||
ExactChoice clone = (ExactChoice) super.clone();
|
||||
- clone.choices = new ArrayList<>(choices);
|
||||
+ // Paper start - properly clone
|
||||
+ clone.choices = new ArrayList<>(this.choices.size());
|
||||
+ for (ItemStack choice : this.choices) {
|
||||
+ clone.choices.add(choice.clone());
|
||||
+ }
|
||||
+ // Paper end - properly clone
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new AssertionError(ex);
|
||||
@@ -0,0 +0,0 @@ public interface RecipeChoice extends Predicate<ItemStack>, Cloneable {
|
||||
public String toString() {
|
||||
return "ExactChoice{" + "choices=" + choices + '}';
|
||||
}
|
||||
+
|
||||
+ // Paper start - check valid ingredients
|
||||
+ @Override
|
||||
+ public @NotNull RecipeChoice validate() {
|
||||
+ if (this.choices.stream().anyMatch(s -> s.getType().isAir())) {
|
||||
+ throw new IllegalArgumentException("RecipeChoice.ExactChoice cannot contain air");
|
||||
+ }
|
||||
+ return this;
|
||||
+ }
|
||||
+ // Paper end - check valid ingredients
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class ShapedRecipe extends CraftingRecipe {
|
||||
public ShapedRecipe setIngredient(char key, @NotNull RecipeChoice ingredient) {
|
||||
Preconditions.checkArgument(ingredients.containsKey(key), "Symbol does not appear in the shape:", key);
|
||||
|
||||
- ingredients.put(key, ingredient);
|
||||
+ ingredients.put(key, ingredient.validate().clone()); // Paper
|
||||
return this;
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@NotNull
|
||||
public ShapedRecipe setIngredient(char key, @NotNull ItemStack item) {
|
||||
- return setIngredient(key, new RecipeChoice.ExactChoice(item));
|
||||
+ Preconditions.checkArgument(!item.getType().isAir(), "Item cannot be air"); // Paper
|
||||
+ return setIngredient(key, new RecipeChoice.ExactChoice(item.clone())); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class ShapelessRecipe extends CraftingRecipe {
|
||||
public ShapelessRecipe addIngredient(@NotNull RecipeChoice ingredient) {
|
||||
Preconditions.checkArgument(ingredients.size() + 1 <= 9, "Shapeless recipes cannot have more than 9 ingredients");
|
||||
|
||||
- ingredients.add(ingredient);
|
||||
+ ingredients.add(ingredient.validate().clone()); // Paper
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ShapelessRecipe extends CraftingRecipe {
|
||||
@NotNull
|
||||
public ShapelessRecipe addIngredient(int count, @NotNull ItemStack item) {
|
||||
Preconditions.checkArgument(ingredients.size() + count <= 9, "Shapeless recipes cannot have more than 9 ingredients");
|
||||
+ Preconditions.checkArgument(!item.getType().isAir(), "Item cannot be air"); // Paper
|
||||
+ item = item.clone(); // Paper
|
||||
while (count-- > 0) {
|
||||
ingredients.add(new RecipeChoice.ExactChoice(item));
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/inventory/SmithingRecipe.java b/src/main/java/org/bukkit/inventory/SmithingRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/SmithingRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/SmithingRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class SmithingRecipe implements Recipe, Keyed {
|
||||
*/
|
||||
@Deprecated
|
||||
public SmithingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice base, @NotNull RecipeChoice addition, boolean copyDataComponents) {
|
||||
+ com.google.common.base.Preconditions.checkArgument(!result.isEmpty(), "Recipe cannot have an empty result."); // Paper
|
||||
this.copyDataComponents = copyDataComponents;
|
||||
// Paper end
|
||||
this.key = key;
|
||||
this.result = result;
|
||||
- this.base = base;
|
||||
- this.addition = addition;
|
||||
+ this.base = base.validate().clone(); // Paper
|
||||
+ this.addition = addition.validate().clone(); // Paper
|
||||
}
|
||||
|
||||
/**
|
||||
diff --git a/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java b/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/SmithingTransformRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class SmithingTransformRecipe extends SmithingRecipe {
|
||||
*/
|
||||
public SmithingTransformRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice template, @NotNull RecipeChoice base, @NotNull RecipeChoice addition) {
|
||||
super(key, result, base, addition);
|
||||
- this.template = template;
|
||||
+ this.template = template.validate().clone(); // Paper
|
||||
}
|
||||
// Paper start
|
||||
/**
|
||||
diff --git a/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java b/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/SmithingTrimRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class SmithingTrimRecipe extends SmithingRecipe implements ComplexRecipe
|
||||
*/
|
||||
public SmithingTrimRecipe(@NotNull NamespacedKey key, @NotNull RecipeChoice template, @NotNull RecipeChoice base, @NotNull RecipeChoice addition) {
|
||||
super(key, new ItemStack(Material.AIR), base, addition);
|
||||
- this.template = template;
|
||||
+ this.template = template.validate().clone(); // Paper
|
||||
}
|
||||
// Paper start
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class SmithingTrimRecipe extends SmithingRecipe implements ComplexRecipe
|
||||
*/
|
||||
public SmithingTrimRecipe(@NotNull NamespacedKey key, @NotNull RecipeChoice template, @NotNull RecipeChoice base, @NotNull RecipeChoice addition, boolean copyDataComponents) {
|
||||
super(key, new ItemStack(Material.AIR), base, addition, copyDataComponents);
|
||||
- this.template = template;
|
||||
+ this.template = template.validate().clone(); // Paper
|
||||
}
|
||||
// Paper end
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java b/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/StonecuttingRecipe.java
|
||||
@@ -0,0 +0,0 @@ public class StonecuttingRecipe implements Recipe, Keyed {
|
||||
* @param input The input choices.
|
||||
*/
|
||||
public StonecuttingRecipe(@NotNull NamespacedKey key, @NotNull ItemStack result, @NotNull RecipeChoice input) {
|
||||
- Preconditions.checkArgument(result.getType() != Material.AIR, "Recipe must have non-AIR result.");
|
||||
+ Preconditions.checkArgument(!result.isEmpty(), "Recipe cannot have an empty result."); // Paper
|
||||
this.key = key;
|
||||
this.output = new ItemStack(result);
|
||||
- this.ingredient = input;
|
||||
+ this.ingredient = input.validate().clone(); // Paper
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class StonecuttingRecipe implements Recipe, Keyed {
|
||||
*/
|
||||
@NotNull
|
||||
public StonecuttingRecipe setInputChoice(@NotNull RecipeChoice input) {
|
||||
- this.ingredient = input;
|
||||
+ this.ingredient = input.validate().clone(); // Paper
|
||||
return (StonecuttingRecipe) this;
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren