diff --git a/paper-api/src/main/java/org/bukkit/Server.java b/paper-api/src/main/java/org/bukkit/Server.java index be0bd52193..01c5726c6f 100644 --- a/paper-api/src/main/java/org/bukkit/Server.java +++ b/paper-api/src/main/java/org/bukkit/Server.java @@ -3,6 +3,8 @@ package org.bukkit; import com.avaje.ebean.config.ServerConfig; import org.bukkit.entity.Player; +import org.bukkit.inventory.Recipe; + import java.util.List; import java.util.logging.Logger; import org.bukkit.command.PluginCommand; @@ -194,4 +196,11 @@ public interface Server { * @param config ServerConfig to populate */ public void configureDbConfig(ServerConfig config); + + /** + * Adds a recipe to the crafting manager. + * @param recipe The recipe to add. + * @return True to indicate that the recipe was added. + */ + public boolean addRecipe(Recipe recipe); } diff --git a/paper-api/src/main/java/org/bukkit/inventory/FurnaceRecipe.java b/paper-api/src/main/java/org/bukkit/inventory/FurnaceRecipe.java new file mode 100644 index 0000000000..50c4cc71ee --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/inventory/FurnaceRecipe.java @@ -0,0 +1,73 @@ +package org.bukkit.inventory; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +/** + * Represents a smelting recipe. + */ +public class FurnaceRecipe implements Recipe { + private ItemStack output; + private MaterialData ingredient; + + /** + * Create a furnace recipe to craft the specified ItemStack. + * @param result The item you want the recipe to create. + * @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)); + } + } + + /** + * Create a furnace recipe to craft the specified ItemStack. + * @param result The item you want the recipe to create. + * @param source The input material. + */ + public FurnaceRecipe(ItemStack result, MaterialData source) { + this.output = result; + this.ingredient = source; + } + + /** + * Sets the input of this furnace recipe. + * @param input The input material. + * @return The changed recipe, so you can chain calls. + */ + public FurnaceRecipe setInput(MaterialData input) { + this.ingredient = input; + return this; + } + + /** + * Sets the input of this furnace recipe. + * @param input The input material. + * @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 this; + } + + /** + * Get the input material. + * @return The input material. + */ + public MaterialData getInput() { + return (MaterialData) ingredient; + } + + /** + * Get the result of this recipe. + * @return The resulting stack. + */ + public ItemStack getResult() { + return output; + } +} diff --git a/paper-api/src/main/java/org/bukkit/inventory/Recipe.java b/paper-api/src/main/java/org/bukkit/inventory/Recipe.java new file mode 100644 index 0000000000..7d1466855d --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/inventory/Recipe.java @@ -0,0 +1,12 @@ +package org.bukkit.inventory; + +/** + * Represents some type of crafting recipe. + */ +public interface Recipe { + /** + * Get the result of this recipe. + * @return The result stack + */ + ItemStack getResult(); +} diff --git a/paper-api/src/main/java/org/bukkit/inventory/ShapedRecipe.java b/paper-api/src/main/java/org/bukkit/inventory/ShapedRecipe.java new file mode 100644 index 0000000000..1693db8a66 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/inventory/ShapedRecipe.java @@ -0,0 +1,129 @@ +package org.bukkit.inventory; + +import java.util.HashMap; + +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 HashMap 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 = 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. + * @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."); + } + 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."); + } + } + 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) { + } + } + 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) { + if (!hasKey(key)) { + throw new IllegalArgumentException("Symbol " + key + " does not appear in the shape."); + } + ingredients.put(key, ingredient); + 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, 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. + */ + 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; + } + + /** + * Get the ingredients map. + * @return The mapping of character to ingredients. + */ + public HashMap getIngredientMap() { + return ingredients; + } + + /** + * Get the shape. + * @return The recipe's shape. + */ + public String[] getShape() { + return rows; + } + + /** + * Get the result. + * @return The result stack. + */ + public ItemStack getResult() { + return output; + } +} diff --git a/paper-api/src/main/java/org/bukkit/inventory/ShapelessRecipe.java b/paper-api/src/main/java/org/bukkit/inventory/ShapelessRecipe.java new file mode 100644 index 0000000000..c8f9a2b56b --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/inventory/ShapelessRecipe.java @@ -0,0 +1,122 @@ +package org.bukkit.inventory; + +import java.util.ArrayList; + +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +/** + * Represents a shapeless recipe, where the arrangement of the ingredients on the crafting grid + * does not matter. + */ +public class ShapelessRecipe implements Recipe { + private ItemStack output; + private ArrayList ingredients = new ArrayList(); + + /** + * Create a shapeless 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 ShapelessRecipe#addIngredient(Material) + * @see ShapelessRecipe#addIngredient(MaterialData) + */ + public ShapelessRecipe(ItemStack result) { + this.output = result; + } + + /** + * Adds the specified ingredient. + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(MaterialData ingredient) { + return addIngredient(1, ingredient); + } + + /** + * Adds the specified ingredient. + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(Material ingredient) { + return addIngredient(1, ingredient, 0); + } + + /** + * Adds the specified ingredient. + * @param ingredient The ingredient to add. + * @param rawdata The data value. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(Material ingredient, int rawdata) { + return addIngredient(1, ingredient, rawdata); + } + + /** + * Adds multiples of the specified ingredient. + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @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; + } + + /** + * Adds multiples of the specified ingredient. + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @return The changed recipe, so you can chain calls. + */ + public ShapelessRecipe addIngredient(int count, Material ingredient) { + return addIngredient(count, ingredient, 0); + } + + /** + * Adds multiples of the specified ingredient. + * @param count How many to add (can't be more than 9!) + * @param ingredient The ingredient to add. + * @param rawdata The 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); + if (data == null) { + data = new MaterialData(ingredient, (byte) rawdata); + } + return addIngredient(count, data); + } + + /** + * Removes an ingredient from the list. If the ingredient occurs multiple times, + * only one instance of it is removed. + * @param ingredient The ingredient to remove + * @return The changed recipe. + */ + public ShapelessRecipe removeIngredient(MaterialData ingredient) { + this.ingredients.remove(ingredient); + return this; + } + + /** + * Get the result of this recipe. + * @return The result stack. + */ + public ItemStack getResult() { + return output; + } + + /** + * Get the list of ingredients used for this recipe. + * @return The input list + */ + public ArrayList getIngredientList() { + return ingredients; + } +}