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; /** * Represents a shaped (ie normal) crafting recipe. */ public class ShapedRecipe implements Recipe { private ItemStack output; private String[] rows; private Map ingredients = new HashMap(); /** * Create a shaped recipe to craft the specified ItemStack. The constructor merely determines the * result and type; to set the actual recipe, you'll need to call the appropriate methods. * * @param result The item you want the recipe to create. * @see ShapedRecipe#shape(String...) * @see ShapedRecipe#setIngredient(char, Material) * @see ShapedRecipe#setIngredient(char, Material, int) * @see ShapedRecipe#setIngredient(char, MaterialData) */ public ShapedRecipe(ItemStack result) { this.output = new ItemStack(result); } /** * Set the shape of this recipe to the specified rows. Each character represents a different * ingredient; exactly what each character represents is set separately. The first row supplied * corresponds with the upper most part of the recipe on the workbench e.g. if all three * rows are supplies the first string represents the top row on the workbench. * * @param shape The rows of the recipe (up to 3 rows). * @return The changed recipe, so you can chain calls. */ 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) { 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]; } // Remove character mappings for characters that no longer exist in the shape HashMap newIngredients = new HashMap(); for (String row : shape) { for (Character c : row.toCharArray()) { newIngredients.put(c, ingredients.get(c)); } } this.ingredients = newIngredients; return this; } /** * Sets the material that a character in the recipe shape refers to. * * @param key The character that represents the ingredient in the shape. * @param ingredient The ingredient. * @return The changed recipe, so you can chain calls. */ public ShapedRecipe setIngredient(char key, MaterialData ingredient) { return setIngredient(key, ingredient.getItemType(), ingredient.getData()); } /** * Sets the material that a character in the recipe shape refers to. * * @param key The character that represents the ingredient in the shape. * @param ingredient The ingredient. * @return The changed recipe, so you can chain calls. */ public ShapedRecipe setIngredient(char key, Material ingredient) { return setIngredient(key, ingredient, 0); } /** * Sets the material that a character in the recipe shape refers to. * * @param key The character that represents the ingredient in the shape. * @param ingredient The ingredient. * @param raw The raw material data as an integer. * @return The changed recipe, so you can chain calls. * @deprecated Magic value */ @Deprecated public ShapedRecipe setIngredient(char key, Material ingredient, int raw) { Validate.isTrue(ingredients.containsKey(key), "Symbol does not appear in the shape:", key); // -1 is the old wildcard, map to Short.MAX_VALUE as the new one if (raw == -1) { raw = Short.MAX_VALUE; } ingredients.put(key, new ItemStack(ingredient, 1, (short) raw)); return this; } /** * Get a copy of the ingredients map. * * @return The mapping of character to 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; } /** * Get the shape. * * @return The recipe's shape. */ public String[] getShape() { return rows.clone(); } /** * Get the result. * * @return The result stack. */ public ItemStack getResult() { return output.clone(); } }