From 308443b15b6798d282ff37bc6848fefa5b2e9029 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sat, 23 Jul 2011 23:18:58 -0400 Subject: [Bleeding] Add ways to retrieve and delete crafting recipes and fixed some issues with the existing recipe API. - New recipe iterator which enables deleting specific recipes - Functions to delete all recipes or revert to vanilla recipe set - Fixed the recipes API; you should now be able to define recipes that take brewed potions! - Fetch all recipes that result in a specific item --- src/main/java/org/bukkit/Bukkit.java | 18 ++++ src/main/java/org/bukkit/Server.java | 30 +++++- .../java/org/bukkit/inventory/FurnaceRecipe.java | 47 +++++--- src/main/java/org/bukkit/inventory/ItemStack.java | 10 ++ .../java/org/bukkit/inventory/ShapedRecipe.java | 83 +++++++------- .../java/org/bukkit/inventory/ShapelessRecipe.java | 119 +++++++++++++++++---- 6 files changed, 226 insertions(+), 81 deletions(-) (limited to 'src') diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java index 2497a31a..893172c5 100644 --- a/src/main/java/org/bukkit/Bukkit.java +++ b/src/main/java/org/bukkit/Bukkit.java @@ -1,6 +1,7 @@ package org.bukkit; import java.io.File; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -11,6 +12,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.map.MapView; import org.bukkit.plugin.PluginManager; @@ -192,6 +194,22 @@ public final class Bukkit { return server.addRecipe(recipe); } + public List getRecipesFor(ItemStack result) { + return server.getRecipesFor(result); + } + + public Iterator recipeIterator() { + return server.recipeIterator(); + } + + public void clearRecipes() { + server.clearRecipes(); + } + + public void resetRecipes() { + server.resetRecipes(); + } + public static Map getCommandAliases() { return server.getCommandAliases(); } diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java index df83db74..958c41e5 100644 --- a/src/main/java/org/bukkit/Server.java +++ b/src/main/java/org/bukkit/Server.java @@ -1,6 +1,7 @@ package org.bukkit; import java.io.File; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -12,6 +13,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.map.MapView; import org.bukkit.plugin.PluginManager; @@ -382,10 +384,36 @@ public interface Server extends PluginMessageRecipient { * Adds a recipe to the crafting manager. * * @param recipe The recipe to add. - * @return True to indicate that the recipe was added. + * @return True if the recipe was added, false if it wasn't for some reason. */ public boolean addRecipe(Recipe recipe); + /** + * Get a list of all recipes for a given item. The stack size is ignored in comparisons. + * If the durability is -1, it will match any data value. + * + * @param result The item whose recipes you want + * @return The list of recipes + */ + public List getRecipesFor(ItemStack result); + + /** + * Get an iterator through the list of crafting recipes. + * + * @return The iterator. + */ + public Iterator recipeIterator(); + + /** + * Clears the list of crafting recipes. + */ + public void clearRecipes(); + + /** + * Resets the list of crafting recipes to the default. + */ + public void resetRecipes(); + /** * Gets a list of command aliases defined in the server properties. * diff --git a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java index fe45e705..12842c94 100644 --- a/src/main/java/org/bukkit/inventory/FurnaceRecipe.java +++ b/src/main/java/org/bukkit/inventory/FurnaceRecipe.java @@ -8,7 +8,7 @@ import org.bukkit.material.MaterialData; */ public class FurnaceRecipe implements Recipe { private ItemStack output; - private MaterialData ingredient; + private ItemStack ingredient; /** * Create a furnace recipe to craft the specified ItemStack. @@ -17,10 +17,7 @@ public class FurnaceRecipe implements Recipe { * @param source The input material. */ public FurnaceRecipe(ItemStack result, Material source) { - this(result, source.getNewData((byte) 0)); - if (this.ingredient == null) { - setInput(new MaterialData(source)); - } + this(result, source, 0); } /** @@ -30,8 +27,19 @@ public class FurnaceRecipe implements Recipe { * @param source The input material. */ public FurnaceRecipe(ItemStack result, MaterialData source) { - this.output = result; - this.ingredient = source; + this(result, source.getItemType(), source.getData()); + } + + /** + * Create a furnace recipe to craft the specified ItemStack. + * + * @param result The item you want the recipe to create. + * @param source The input material. + * @param data The data value. (Note: This is currently ignored by the CraftBukkit server.) + */ + public FurnaceRecipe(ItemStack result, Material source, int data) { + this.output = new ItemStack(result); + this.ingredient = new ItemStack(source, 1, (short) data); } /** @@ -41,8 +49,7 @@ public class FurnaceRecipe implements Recipe { * @return The changed recipe, so you can chain calls. */ public FurnaceRecipe setInput(MaterialData input) { - this.ingredient = input; - return this; + return setInput(input.getItemType(), input.getData()); } /** @@ -52,10 +59,18 @@ public class FurnaceRecipe implements Recipe { * @return The changed recipe, so you can chain calls. */ public FurnaceRecipe setInput(Material input) { - setInput(input.getNewData((byte) 0)); - if (this.ingredient == null) { - setInput(new MaterialData(input)); - } + return setInput(input, 0); + } + + /** + * Sets the input of this furnace recipe. + * + * @param input The input material. + * @param data The data value. (Note: This is currently ignored by the CraftBukkit server.) + * @return The changed recipe, so you can chain calls. + */ + public FurnaceRecipe setInput(Material input, int data) { + this.ingredient = new ItemStack(input, 1, (short) data); return this; } @@ -64,8 +79,8 @@ public class FurnaceRecipe implements Recipe { * * @return The input material. */ - public MaterialData getInput() { - return ingredient; + public ItemStack getInput() { + return this.ingredient.clone(); } /** @@ -74,6 +89,6 @@ public class FurnaceRecipe implements Recipe { * @return The resulting stack. */ public ItemStack getResult() { - return output; + return output.clone(); } } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java index 7dd59d83..36cb83db 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -57,6 +57,16 @@ public class ItemStack implements Cloneable, ConfigurationSerializable { this(type.getId(), amount, damage, data); } + public ItemStack(final ItemStack stack) { + this.type = stack.type; + this.amount = stack.amount; + this.durability = stack.durability; + if (stack.data != null) { + this.data = stack.data.clone(); + } + enchantments.putAll(stack.enchantments); + } + /** * Gets the type of this item * diff --git a/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/src/main/java/org/bukkit/inventory/ShapedRecipe.java index d099ca5b..577597ce 100644 --- a/src/main/java/org/bukkit/inventory/ShapedRecipe.java +++ b/src/main/java/org/bukkit/inventory/ShapedRecipe.java @@ -1,6 +1,9 @@ package org.bukkit.inventory; import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang.Validate; import org.bukkit.Material; import org.bukkit.material.MaterialData; @@ -11,7 +14,7 @@ import org.bukkit.material.MaterialData; public class ShapedRecipe implements Recipe { private ItemStack output; private String[] rows; - private HashMap ingredients = new HashMap(); + private Map ingredients = new HashMap(); /** * Create a shaped recipe to craft the specified ItemStack. The constructor merely determines the @@ -24,7 +27,7 @@ public class ShapedRecipe implements Recipe { * @see ShapedRecipe#setIngredient(char, MaterialData) */ public ShapedRecipe(ItemStack result) { - this.output = result; + this.output = new ItemStack(result); } /** @@ -34,26 +37,28 @@ public class ShapedRecipe implements Recipe { * @param shape The rows of the recipe (up to 3 rows). * @return The changed recipe, so you can chain calls. */ - public ShapedRecipe shape(String... shape) { - if (shape == null || shape.length > 3 || shape.length < 1) { - throw new IllegalArgumentException("Crafting recipes should be 1, 2, or 3 rows."); - } + public ShapedRecipe shape(final String... shape) { + Validate.notNull(shape, "Must provide a shape"); + Validate.isTrue(shape.length > 0 && shape.length < 4, "Crafting recipes should be 1, 2, 3 rows, not ", shape.length); + for (String row : shape) { - if (row == null || row.length() > 3 || row.length() < 1) { - throw new IllegalArgumentException("Crafting rows should be 1, 2, or 3 characters."); - } + Validate.notNull(row, "Shape cannot have null rows"); + Validate.isTrue(row.length() > 0 && row.length() < 4, "Crafting rows should be 1, 2, or 3 characters, not ", row.length()); + } + this.rows = new String[shape.length]; + for (int i = 0; i < shape.length; i++) { + this.rows[i] = shape[i]; } - this.rows = shape; // Remove character mappings for characters that no longer exist in the shape - HashMap ingredientsTemp = this.ingredients; - - this.ingredients = new HashMap(); - for (char key : ingredientsTemp.keySet()) { - try { - setIngredient(key, ingredientsTemp.get(key)); - } catch (IllegalArgumentException e) {} + HashMap newIngredients = new HashMap(); + for (String row : shape) { + for (Character c : row.toCharArray()) { + newIngredients.put(c, ingredients.get(c)); + } } + this.ingredients = newIngredients; + return this; } @@ -65,11 +70,7 @@ public class ShapedRecipe implements Recipe { * @return The changed recipe, so you can chain calls. */ public ShapedRecipe setIngredient(char key, MaterialData ingredient) { - if (!hasKey(key)) { - throw new IllegalArgumentException("Symbol " + key + " does not appear in the shape."); - } - ingredients.put(key, ingredient); - return this; + return setIngredient(key, ingredient.getItemType(), ingredient.getData()); } /** @@ -92,32 +93,26 @@ public class ShapedRecipe implements Recipe { * @return The changed recipe, so you can chain calls. */ public ShapedRecipe setIngredient(char key, Material ingredient, int raw) { - MaterialData data = ingredient.getNewData((byte) raw); - - if (data == null) { - data = new MaterialData(ingredient, (byte) raw); - } - return setIngredient(key, data); - } - - private boolean hasKey(char c) { - String key = Character.toString(c); - - for (String row : rows) { - if (row.contains(key)) { - return true; - } - } - return false; + Validate.isTrue(ingredients.containsKey(key), "Symbol does not appear in the shape:", key); + ingredients.put(key, new ItemStack(ingredient, 1, (short) raw)); + return this; } /** - * Get the ingredients map. + * Get a copy of the ingredients map. * * @return The mapping of character to ingredients. */ - public HashMap getIngredientMap() { - return ingredients; + public Map getIngredientMap() { + HashMap result = new HashMap(); + for (Map.Entry ingredient : ingredients.entrySet()) { + if (ingredient.getValue() == null) { + result.put(ingredient.getKey(), null); + } else { + result.put(ingredient.getKey(), ingredient.getValue().clone()); + } + } + return result; } /** @@ -126,7 +121,7 @@ public class ShapedRecipe implements Recipe { * @return The recipe's shape. */ public String[] getShape() { - return rows; + return rows.clone(); } /** @@ -135,6 +130,6 @@ public class ShapedRecipe implements Recipe { * @return The result stack. */ public ItemStack getResult() { - return output; + return output.clone(); } } diff --git a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java index 1ed559e8..2263043f 100644 --- a/src/main/java/org/bukkit/inventory/ShapelessRecipe.java +++ b/src/main/java/org/bukkit/inventory/ShapelessRecipe.java @@ -1,6 +1,10 @@ package org.bukkit.inventory; import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.lang.Validate; import org.bukkit.Material; import org.bukkit.material.MaterialData; @@ -11,7 +15,7 @@ import org.bukkit.material.MaterialData; */ public class ShapelessRecipe implements Recipe { private ItemStack output; - private ArrayList ingredients = new ArrayList(); + private List ingredients = new ArrayList(); /** * Create a shapeless recipe to craft the specified ItemStack. The constructor merely determines the @@ -20,9 +24,13 @@ public class ShapelessRecipe implements Recipe { * @param result The item you want the recipe to create. * @see ShapelessRecipe#addIngredient(Material) * @see ShapelessRecipe#addIngredient(MaterialData) + * @see ShapelessRecipe#addIngredient(Material,int) + * @see ShapelessRecipe#addIngredient(int,Material) + * @see ShapelessRecipe#addIngredient(int,MaterialData) + * @see ShapelessRecipe#addIngredient(int,Material,int) */ public ShapelessRecipe(ItemStack result) { - this.output = result; + this.output = new ItemStack(result); } /** @@ -49,7 +57,7 @@ public class ShapelessRecipe implements Recipe { * Adds the specified ingredient. * * @param ingredient The ingredient to add. - * @param rawdata The data value. + * @param rawdata The data value, or -1 to allow any data value. * @return The changed recipe, so you can chain calls. */ public ShapelessRecipe addIngredient(Material ingredient, int rawdata) { @@ -64,13 +72,7 @@ public class ShapelessRecipe implements Recipe { * @return The changed recipe, so you can chain calls. */ public ShapelessRecipe addIngredient(int count, MaterialData ingredient) { - if (ingredients.size() + count > 9) { - throw new IllegalArgumentException("Shapeless recipes cannot have more than 9 ingredients"); - } - while (count-- > 0) { - ingredients.add(ingredient); - } - return this; + return addIngredient(count, ingredient.getItemType(), ingredient.getData()); } /** @@ -89,27 +91,100 @@ public class ShapelessRecipe implements Recipe { * * @param count How many to add (can't be more than 9!) * @param ingredient The ingredient to add. - * @param rawdata The data value. + * @param rawdata The data value, or -1 to allow any data value. * @return The changed recipe, so you can chain calls. */ public ShapelessRecipe addIngredient(int count, Material ingredient, int rawdata) { - MaterialData data = ingredient.getNewData((byte) rawdata); + Validate.isTrue(ingredients.size() + count <= 9, "Shapeless recipes cannot have more than 9 ingredients"); - if (data == null) { - data = new MaterialData(ingredient, (byte) rawdata); + while (count-- > 0) { + ingredients.add(new ItemStack(ingredient, 1, (short) rawdata)); } - return addIngredient(count, data); + 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, with a data value + * of 0. + * + * @param ingredient The ingredient to remove + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(Material ingredient) { + return removeIngredient(ingredient, 0); } /** * Removes an ingredient from the list. If the ingredient occurs multiple times, - * only one instance of it is removed. + * only one instance of it is removed. If the data value is -1, only ingredients + * with a -1 data value will be removed. * * @param ingredient The ingredient to remove * @return The changed recipe. */ public ShapelessRecipe removeIngredient(MaterialData ingredient) { - this.ingredients.remove(ingredient); + return removeIngredient(ingredient.getItemType(), ingredient.getData()); + } + + /** + * Removes multiple instances of an ingredient from the list. If there are less instances + * then specified, all will be removed. Only removes exact matches, with a data value + * of 0. + * + * @param count The number of copies to remove. + * @param ingredient The ingredient to remove + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(int count, Material ingredient) { + return removeIngredient(count, ingredient, 0); + } + + /** + * Removes multiple instances of an ingredient from the list. If there are less instances + * then specified, all will be removed. If the data value is -1, only ingredients + * with a -1 data value will be removed. + * + * @param count The number of copies to remove. + * @param ingredient The ingredient to remove. + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(int count, MaterialData ingredient) { + return removeIngredient(count, ingredient.getItemType(), ingredient.getData()); + } + + /** + * Removes an ingredient from the list. If the ingredient occurs multiple times, + * only one instance of it is removed. If the data value is -1, only ingredients + * with a -1 data value will be removed. + * + * @param ingredient The ingredient to remove + * @param rawdata The data value; + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(Material ingredient, int rawdata) { + return removeIngredient(1, ingredient, rawdata); + } + + /** + * Removes multiple instances of an ingredient from the list. If there are less instances + * then specified, all will be removed. If the data value is -1, only ingredients + * with a -1 data value will be removed. + * + * @param count The number of copies to remove. + * @param ingredient The ingredient to remove. + * @param rawdata The data value. + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(int count, Material ingredient, int rawdata) { + Iterator iterator = ingredients.iterator(); + while (count > 0 && iterator.hasNext()) { + ItemStack stack = iterator.next(); + if (stack.getType() == ingredient && stack.getDurability() == rawdata) { + iterator.remove(); + count--; + } + } return this; } @@ -119,7 +194,7 @@ public class ShapelessRecipe implements Recipe { * @return The result stack. */ public ItemStack getResult() { - return output; + return output.clone(); } /** @@ -127,7 +202,11 @@ public class ShapelessRecipe implements Recipe { * * @return The input list */ - public ArrayList getIngredientList() { - return ingredients; + public List getIngredientList() { + ArrayList result = new ArrayList(ingredients.size()); + for (ItemStack ingredient : ingredients) { + result.add(ingredient.clone()); + } + return result; } } -- cgit v1.2.3