From eaf05a2ab257f19498826db6964039d9b1246afd Mon Sep 17 00:00:00 2001 From: md_5 Date: Sat, 1 Sep 2018 11:04:43 +1000 Subject: Expand Recipe API to allow multiple Materials per slot --- .../java/org/bukkit/inventory/RecipeChoice.java | 114 +++++++++++++++++++++ .../java/org/bukkit/inventory/ShapedRecipe.java | 28 ++++- .../java/org/bukkit/inventory/ShapelessRecipe.java | 38 ++++++- 3 files changed, 171 insertions(+), 9 deletions(-) create mode 100644 src/main/java/org/bukkit/inventory/RecipeChoice.java (limited to 'src') diff --git a/src/main/java/org/bukkit/inventory/RecipeChoice.java b/src/main/java/org/bukkit/inventory/RecipeChoice.java new file mode 100644 index 00000000..2dd72242 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/RecipeChoice.java @@ -0,0 +1,114 @@ +package org.bukkit.inventory; + +import com.google.common.base.Preconditions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Predicate; +import org.bukkit.Material; + +/** + * Represents a potential item match within a recipe. All choices within a + * recipe must be satisfied for it to be craftable. + * + * This class is not legal for implementation by plugins! + * + * @deprecated draft API + */ +@Deprecated +public interface RecipeChoice extends Predicate, Cloneable { + + /** + * Gets a single item stack representative of this stack choice. + * + * @return a single representative item + * @deprecated for compatability only + */ + @Deprecated + ItemStack getItemStack(); + + RecipeChoice clone(); + + /** + * Represents a choice of multiple matching Materials. + */ + public static class MaterialChoice implements RecipeChoice { + + private List choices; + + public MaterialChoice(List choices) { + Preconditions.checkArgument(choices != null, "choices"); + Preconditions.checkArgument(!choices.isEmpty(), "Must have at least one choice"); + this.choices = choices; + } + + @Override + public boolean test(ItemStack t) { + for (Material match : choices) { + if (t.getType() == match) { + return true; + } + } + + return false; + } + + @Override + public ItemStack getItemStack() { + ItemStack stack = new ItemStack(choices.get(0)); + + // For compat + if (choices.size() > 1) { + stack.setDurability(Short.MAX_VALUE); + } + + return stack; + } + + public List getChoices() { + return Collections.unmodifiableList(choices); + } + + @Override + public MaterialChoice clone() { + try { + MaterialChoice clone = (MaterialChoice) super.clone(); + clone.choices = new ArrayList<>(choices); + return clone; + } catch (CloneNotSupportedException ex) { + throw new AssertionError(ex); + } + } + + @Override + public int hashCode() { + int hash = 3; + hash = 37 * hash + Objects.hashCode(this.choices); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final MaterialChoice other = (MaterialChoice) obj; + if (!Objects.equals(this.choices, other.choices)) { + return false; + } + return true; + } + + @Override + public String toString() { + return "MaterialChoice{" + "choices=" + choices + '}'; + } + } +} diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java index 398ac245..90d6d50c 100644 --- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java +++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java @@ -1,6 +1,7 @@ package org.bukkit.inventory; import com.google.common.base.Preconditions; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -18,7 +19,7 @@ public class ShapedRecipe implements Recipe, Keyed { private final NamespacedKey key; private final ItemStack output; private String[] rows; - private Map ingredients = new HashMap(); + private Map ingredients = new HashMap<>(); private String group = ""; @Deprecated @@ -75,7 +76,7 @@ public class ShapedRecipe implements Recipe, Keyed { } // Remove character mappings for characters that no longer exist in the shape - HashMap newIngredients = new HashMap(); + HashMap newIngredients = new HashMap<>(); for (String row : shape) { for (Character c : row.toCharArray()) { newIngredients.put(c, ingredients.get(c)); @@ -126,7 +127,14 @@ public class ShapedRecipe implements Recipe, Keyed { raw = Short.MAX_VALUE; } - ingredients.put(key, new ItemStack(ingredient, 1, (short) raw)); + ingredients.put(key, new RecipeChoice.MaterialChoice(Collections.singletonList(ingredient))); + return this; + } + + public ShapedRecipe setIngredient(char key, RecipeChoice ingredient) { + Validate.isTrue(ingredients.containsKey(key), "Symbol does not appear in the shape:", key); + + ingredients.put(key, ingredient); return this; } @@ -137,7 +145,19 @@ public class ShapedRecipe implements Recipe, Keyed { */ public Map getIngredientMap() { HashMap result = new HashMap(); - for (Map.Entry ingredient : ingredients.entrySet()) { + for (Map.Entry ingredient : ingredients.entrySet()) { + if (ingredient.getValue() == null) { + result.put(ingredient.getKey(), null); + } else { + result.put(ingredient.getKey(), ingredient.getValue().getItemStack().clone()); + } + } + return result; + } + + public Map getChoiceMap() { + Map result = new HashMap<>(); + for (Map.Entry ingredient : ingredients.entrySet()) { if (ingredient.getValue() == null) { result.put(ingredient.getKey(), null); } else { diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java index 0c340c84..ea359c54 100644 --- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java @@ -2,6 +2,7 @@ package org.bukkit.inventory; import com.google.common.base.Preconditions; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -19,7 +20,7 @@ import org.bukkit.material.MaterialData; public class ShapelessRecipe implements Recipe, Keyed { private final NamespacedKey key; private final ItemStack output; - private final List ingredients = new ArrayList(); + private final List ingredients = new ArrayList<>(); private String group = ""; @Deprecated @@ -121,11 +122,30 @@ public class ShapelessRecipe implements Recipe, Keyed { } while (count-- > 0) { - ingredients.add(new ItemStack(ingredient, 1, (short) rawdata)); + ingredients.add(new RecipeChoice.MaterialChoice(Collections.singletonList(ingredient))); } return this; } + public ShapelessRecipe addIngredient(RecipeChoice ingredient) { + Validate.isTrue(ingredients.size() + 1 <= 9, "Shapeless recipes cannot have more than 9 ingredients"); + + ingredients.add(ingredient); + return this; + } + + /** + * Removes an ingredient from the list. + * + * @param ingredient The ingredient to remove + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(RecipeChoice ingredient) { + ingredients.remove(ingredient); + + return this; + } + /** * Removes an ingredient from the list. If the ingredient occurs multiple * times, only one instance of it is removed. Only removes exact matches, @@ -204,9 +224,9 @@ public class ShapelessRecipe implements Recipe, Keyed { */ @Deprecated public ShapelessRecipe removeIngredient(int count, Material ingredient, int rawdata) { - Iterator iterator = ingredients.iterator(); + Iterator iterator = ingredients.iterator(); while (count > 0 && iterator.hasNext()) { - ItemStack stack = iterator.next(); + ItemStack stack = iterator.next().getItemStack(); if (stack.getType() == ingredient && stack.getDurability() == rawdata) { iterator.remove(); count--; @@ -231,7 +251,15 @@ public class ShapelessRecipe implements Recipe, Keyed { */ public List getIngredientList() { ArrayList result = new ArrayList(ingredients.size()); - for (ItemStack ingredient : ingredients) { + for (RecipeChoice ingredient : ingredients) { + result.add(ingredient.getItemStack().clone()); + } + return result; + } + + public List getChoiceList() { + List result = new ArrayList<>(ingredients.size()); + for (RecipeChoice ingredient : ingredients) { result.add(ingredient.clone()); } return result; -- cgit v1.2.3