From 318963b379448e3c7855690e88ad8c2d6be4d7c5 Mon Sep 17 00:00:00 2001 From: Sn0wStorm Date: Sat, 9 Nov 2019 17:02:48 +0100 Subject: [PATCH] Add/change recipes by plugin --- src/com/dre/brewery/BIngredients.java | 4 +- src/com/dre/brewery/Brew.java | 2 +- src/com/dre/brewery/P.java | 12 +- src/com/dre/brewery/api/BreweryApi.java | 165 +++++++++-- .../brewery/api/events/ConfigLoadEvent.java | 42 +++ src/com/dre/brewery/filedata/BConfig.java | 21 +- .../brewery/listeners/CommandListener.java | 2 +- .../dre/brewery/recipe/BCauldronRecipe.java | 173 ++++++++++- src/com/dre/brewery/recipe/BEffect.java | 9 + src/com/dre/brewery/recipe/BRecipe.java | 271 +++++++++++++++++- src/com/dre/brewery/recipe/PotionColor.java | 4 + test/com/dre/brewery/RecipeTests.java | 33 ++- 12 files changed, 697 insertions(+), 41 deletions(-) create mode 100644 src/com/dre/brewery/api/events/ConfigLoadEvent.java diff --git a/src/com/dre/brewery/BIngredients.java b/src/com/dre/brewery/BIngredients.java index 28d650e..660f4d4 100644 --- a/src/com/dre/brewery/BIngredients.java +++ b/src/com/dre/brewery/BIngredients.java @@ -203,7 +203,7 @@ public class BIngredients { int woodQuality; int ageQuality; BRecipe bestRecipe = null; - for (BRecipe recipe : BRecipe.recipes) { + for (BRecipe recipe : BRecipe.getAllRecipes()) { ingredientQuality = getIngredientQuality(recipe); cookingQuality = getCookingQuality(recipe, distilled); @@ -258,7 +258,7 @@ public class BIngredients { BCauldronRecipe best = null; float bestMatch = 0; float match; - for (BCauldronRecipe recipe : BCauldronRecipe.recipes) { + for (BCauldronRecipe recipe : BCauldronRecipe.getAllRecipes()) { match = recipe.getIngredientMatch(ingredients); if (match >= 10) { return recipe; diff --git a/src/com/dre/brewery/Brew.java b/src/com/dre/brewery/Brew.java index b9edf7d..78c6691 100644 --- a/src/com/dre/brewery/Brew.java +++ b/src/com/dre/brewery/Brew.java @@ -201,7 +201,7 @@ public class Brew { public boolean setRecipeFromString(String name) { currentRecipe = null; if (name != null && !name.equals("")) { - for (BRecipe recipe : BRecipe.recipes) { + for (BRecipe recipe : BRecipe.getAllRecipes()) { if (recipe.getRecipeName().equalsIgnoreCase(name)) { currentRecipe = recipe; return true; diff --git a/src/com/dre/brewery/P.java b/src/com/dre/brewery/P.java index f7715b8..bd7c860 100644 --- a/src/com/dre/brewery/P.java +++ b/src/com/dre/brewery/P.java @@ -439,11 +439,13 @@ public class P extends JavaPlugin { // delete Data from Ram Barrel.barrels.clear(); BCauldron.bcauldrons.clear(); - BRecipe.recipes.clear(); + BRecipe.getConfigRecipes().clear(); + BRecipe.numConfigRecipes = 0; BCauldronRecipe.acceptedMaterials.clear(); BCauldronRecipe.acceptedCustom.clear(); BCauldronRecipe.acceptedSimple.clear(); - BCauldronRecipe.recipes.clear(); + BCauldronRecipe.getConfigRecipes().clear(); + BCauldronRecipe.numConfigRecipes = 0; BConfig.customItems.clear(); BConfig.hasSlimefun = null; BConfig.hasMMOItems = null; @@ -462,11 +464,13 @@ public class P extends JavaPlugin { BConfig.reloader = sender; } // clear all existent config Data - BRecipe.recipes.clear(); + BRecipe.getConfigRecipes().clear(); + BRecipe.numConfigRecipes = 0; BCauldronRecipe.acceptedMaterials.clear(); BCauldronRecipe.acceptedCustom.clear(); BCauldronRecipe.acceptedSimple.clear(); - BCauldronRecipe.recipes.clear(); + BCauldronRecipe.getConfigRecipes().clear(); + BCauldronRecipe.numConfigRecipes = 0; BConfig.customItems.clear(); BConfig.hasSlimefun = null; BConfig.hasMMOItems = null; diff --git a/src/com/dre/brewery/api/BreweryApi.java b/src/com/dre/brewery/api/BreweryApi.java index 2f829ab..4f8d229 100644 --- a/src/com/dre/brewery/api/BreweryApi.java +++ b/src/com/dre/brewery/api/BreweryApi.java @@ -1,6 +1,7 @@ package com.dre.brewery.api; import com.dre.brewery.BCauldron; +import com.dre.brewery.recipe.BCauldronRecipe; import com.dre.brewery.recipe.BRecipe; import com.dre.brewery.Barrel; import com.dre.brewery.Brew; @@ -12,13 +13,14 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.Nullable; -public class BreweryApi { +import java.util.List; -/* +/** * Convenience methods to get common objects or do common things */ +public class BreweryApi { - /* + /** * Remove any data that this Plugin may associate with the given Block * Currently Cauldrons and Barrels (Cauldron, Wood, Woodstairs, Fence, Sign) * Does not remove any actual Blocks @@ -29,7 +31,7 @@ public class BreweryApi { return removeBarrel(block); } - /* + /** * Like removeAny() but removes data as if the given player broke the Block * Currently only makes a difference for Logging */ @@ -39,9 +41,11 @@ public class BreweryApi { } + // # # # # # # # # # # # # // # # # # # Brew # # # # # + // # # # # # # # # # # # # - /* + /** * Get a Brew from an ItemStack * Reads the Brew data from the saved data on the item * Checks if item is actually a Brew @@ -52,7 +56,7 @@ public class BreweryApi { return Brew.get(item); } - /* + /** * Get a Brew from an ItemMeta * Reads the Brew data from the saved data in the Meta * Checks if meta has a Brew saved @@ -64,9 +68,11 @@ public class BreweryApi { } + // # # # # # # # # # # # # // # # # # # Barrel # # # # # + // # # # # # # # # # # # # - /* + /** * Get a Barrel from a Block * May be any Wood, Fence, Sign that is part of a Barrel * Returns null if block is not part of a Barrel @@ -76,7 +82,7 @@ public class BreweryApi { return Barrel.get(block); } - /* + /** * Get the Inventory of a Block part of a Barrel * May be any Wood, Fence or Sign that is part of a Barrel * Returns null if block is not part of a Barrel @@ -90,7 +96,7 @@ public class BreweryApi { return null; } - /* + /** * Remove any Barrel that this Block may be Part of * Returns true if a Barrel was removed * Does not remove any actual Block @@ -99,10 +105,10 @@ public class BreweryApi { return removeBarrelByPlayer(block, null); } - /* + /** * Remove any Barrel that this Block may be Part of, as if broken by the Player * Returns true if a Barrel was removed - * Does not remove any actual Block + * Does not remove any actual Block from the World */ public static boolean removeBarrelByPlayer(Block block, Player player) { Barrel barrel = Barrel.get(block); @@ -113,10 +119,11 @@ public class BreweryApi { return false; } - + // # # # # # # # # # # # # // # # # # # Cauldron # # # # # + // # # # # # # # # # # # # - /* + /** * Get a BCauldron from a Block * Returns null if block is not a BCauldron */ @@ -125,19 +132,21 @@ public class BreweryApi { return BCauldron.get(block); } - /* + /** * Remove any data associated with a Cauldron at that given Block * Returns true if a Cauldron was removed - * Does not actually remove the Block + * Does not remove the Block from the World */ public static boolean removeCauldron(Block block) { return BCauldron.remove(block); } + // # # # # # # # # # # # # // # # # # # Recipe # # # # # + // # # # # # # # # # # # # - /* + /** * Get a BRecipe by its name * The name is the middle one of the three if three are set in the config * Returns null if recipe with that name does not exist @@ -147,11 +156,125 @@ public class BreweryApi { return BRecipe.get(name); } - /* - * Add a new recipe - * Not Implemented yet + /** + * Add a New Recipe. + * Brews can be made out of this Recipe. + * The recipe can be changed or removed later. + * + * @param recipe The Recipe to add + * @param saveForever If the recipe should be saved forever, even after the Server restarts + * If True: Recipe will be saved until removed manually + * If False: Recipe will be removed when the Server restarts, existing potions using + * this Recipe will become bad after continued aging, if the recipe is not added again. */ - public static boolean addRecipe(BRecipe recipe) { - throw new NotImplementedException(); // TODO implement + public static void addRecipe(BRecipe recipe, boolean saveForever) { + //recipe.setSaveInData(saveForever); + if (saveForever) { + throw new NotImplementedException(); + } + BRecipe.getAddedRecipes().add(recipe); + recipe.updateAcceptedLists(); } + + /** + * Removes a Recipe from the List of all Recipes. + * This can also remove Recipes that were loaded from config, though these will be readded when reloading the config + * + * @param name The name of the recipe to remove + * @return The Recipe that was removed, null if none was removed + */ + @Nullable + public static BRecipe removeRecipe(String name) { + List recipes = BRecipe.getAllRecipes(); + for (int i = 0; i < recipes.size(); i++) { + if (recipes.get(i).getRecipeName().equalsIgnoreCase(name)) { + BRecipe remove = recipes.remove(i); + if (i < BRecipe.numConfigRecipes) { + // We removed one of the Config Recipes + BRecipe.numConfigRecipes--; + } + return remove; + } + } + return null; + } + + /** + * Create a New Recipe with a Recipe Builder. + * + * @param recipeNames Either 1 or 3 names. Sets the Name for Quality (Bad, Normal, Good) + * @return A Recipe Builder + */ + public static BRecipe.Builder recipeBuilder(String... recipeNames) { + return new BRecipe.Builder(recipeNames); + } + + + + // # # # # # # # # # # # # + // # # # # # Cauldron Recipe # # # # # + // # # # # # # # # # # # # + + /** + * Get A BCauldronRecipe by its name + * Returns null if recipe with that name does not exist + */ + @Nullable + public static BCauldronRecipe getCauldronRecipe(String name) { + return BCauldronRecipe.get(name); + } + + /** + * Add a New Cauldron Recipe. + * Base Brews coming out of the Cauldron can be made from this recipe + * The recipe can be changed or removed later. + * + * @param recipe The Cauldron Recipe to add + * @param saveForever If the recipe should be saved forever, even after the Server restarts + * If True: Recipe will be saved until removed manually + * If False: Recipe will be removed when the Server restarts + */ + public static void addCauldronRecipe(BCauldronRecipe recipe, boolean saveForever) { + //recipe.setSaveInData(saveForever); + if (saveForever) { + throw new NotImplementedException(); + } + BCauldronRecipe.getAddedRecipes().add(recipe); + recipe.updateAcceptedLists(); + } + + /** + * Removes a Cauldron Recipe from the List of all Cauldron Recipes. + * This can also remove Cauldron Recipes that were loaded from config, though these will be readded when reloading the config + * + * @param name The name of the cauldron recipe to remove + * @return The Cauldron Recipe that was removed, null if none was removed + */ + @Nullable + public static BCauldronRecipe removeCauldronRecipe(String name) { + List recipes = BCauldronRecipe.getAllRecipes(); + for (int i = 0; i < recipes.size(); i++) { + if (recipes.get(i).getName().equalsIgnoreCase(name)) { + BCauldronRecipe remove = recipes.remove(i); + if (i < BCauldronRecipe.numConfigRecipes) { + // We removed one of the Config Recipes + BCauldronRecipe.numConfigRecipes--; + } + return remove; + } + } + return null; + } + + /** + * Create a New Cauldron Recipe with a Recipe Builder. + * + * @param name The name of the new Cauldron Recipe + * @return A Cauldron Recipe Builder + */ + public static BCauldronRecipe.Builder cauldronRecipeBuilder(String name) { + return new BCauldronRecipe.Builder(name); + } + + } diff --git a/src/com/dre/brewery/api/events/ConfigLoadEvent.java b/src/com/dre/brewery/api/events/ConfigLoadEvent.java new file mode 100644 index 0000000..c3fec33 --- /dev/null +++ b/src/com/dre/brewery/api/events/ConfigLoadEvent.java @@ -0,0 +1,42 @@ +package com.dre.brewery.api.events; + +import com.dre.brewery.api.BreweryApi; +import com.dre.brewery.recipe.BCauldronRecipe; +import com.dre.brewery.recipe.BRecipe; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ConfigLoadEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + + /** + * One of the things one might need to do after reloading + * Removes a Recipe, can also remove config recipes + * + * @param name Name of the Recipe to remove + * @return The Recipe that was removed, null if none was removed + */ + public BRecipe removeRecipe(String name) { + return BreweryApi.removeRecipe(name); + } + + /** + * One of the things one might need to do after reloading + * Removes a Cauldron Recipe, can also remove config recipes + * + * @param name Name of the Cauldron Recipe to remove + * @return The Cauldron Recipe that was removed, null if none was removed + */ + public BCauldronRecipe removeCauldronRecipe(String name) { + return BreweryApi.removeCauldronRecipe(name); + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } +} diff --git a/src/com/dre/brewery/filedata/BConfig.java b/src/com/dre/brewery/filedata/BConfig.java index c38349e..7ea44d9 100644 --- a/src/com/dre/brewery/filedata/BConfig.java +++ b/src/com/dre/brewery/filedata/BConfig.java @@ -4,6 +4,7 @@ import com.dre.brewery.Brew; import com.dre.brewery.DistortChat; import com.dre.brewery.MCBarrel; import com.dre.brewery.P; +import com.dre.brewery.api.events.ConfigLoadEvent; import com.dre.brewery.integration.barrel.WGBarrel; import com.dre.brewery.integration.barrel.WGBarrel5; import com.dre.brewery.integration.barrel.WGBarrel6; @@ -222,27 +223,39 @@ public class BConfig { // loading recipes configSection = config.getConfigurationSection("recipes"); if (configSection != null) { + List configRecipes = BRecipe.getConfigRecipes(); for (String recipeId : configSection.getKeys(false)) { BRecipe recipe = BRecipe.fromConfig(configSection, recipeId); if (recipe != null && recipe.isValid()) { - BRecipe.recipes.add(recipe); + configRecipes.add(recipe); } else { p.errorLog("Loading the Recipe with id: '" + recipeId + "' failed!"); } } + BRecipe.numConfigRecipes = configRecipes.size(); } // Loading Cauldron Recipes configSection = config.getConfigurationSection("cauldron"); if (configSection != null) { + List configRecipes = BCauldronRecipe.getConfigRecipes(); for (String id : configSection.getKeys(false)) { BCauldronRecipe recipe = BCauldronRecipe.fromConfig(configSection, id); if (recipe != null) { - BCauldronRecipe.recipes.add(recipe); + configRecipes.add(recipe); } else { p.errorLog("Loading the Cauldron-Recipe with id: '" + id + "' failed!"); } } + BCauldronRecipe.numConfigRecipes = configRecipes.size(); + } + + // Recalculating Cauldron-Accepted Items for non-config recipes + for (BRecipe recipe : BRecipe.getAddedRecipes()) { + recipe.updateAcceptedLists(); + } + for (BCauldronRecipe recipe : BCauldronRecipe.getAddedRecipes()) { + recipe.updateAcceptedLists(); } // loading drainItems @@ -286,6 +299,10 @@ public class BConfig { DistortChat.log = config.getBoolean("logRealChat", false); DistortChat.doSigns = config.getBoolean("distortSignText", false); + // The Config was reloaded, call Event + ConfigLoadEvent event = new ConfigLoadEvent(); + P.p.getServer().getPluginManager().callEvent(event); + return true; } } diff --git a/src/com/dre/brewery/listeners/CommandListener.java b/src/com/dre/brewery/listeners/CommandListener.java index 9ff7c1b..8ab4463 100644 --- a/src/com/dre/brewery/listeners/CommandListener.java +++ b/src/com/dre/brewery/listeners/CommandListener.java @@ -607,7 +607,7 @@ public class CommandListener implements CommandExecutor { } BRecipe recipe = null; - for (BRecipe r : BRecipe.recipes) { + for (BRecipe r : BRecipe.getAllRecipes()) { if (r.hasName(name)) { recipe = r; break; diff --git a/src/com/dre/brewery/recipe/BCauldronRecipe.java b/src/com/dre/brewery/recipe/BCauldronRecipe.java index 534b6e5..a724a30 100644 --- a/src/com/dre/brewery/recipe/BCauldronRecipe.java +++ b/src/com/dre/brewery/recipe/BCauldronRecipe.java @@ -2,12 +2,15 @@ package com.dre.brewery.recipe; import com.dre.brewery.P; import com.dre.brewery.utility.Tuple; +import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Set; @@ -15,6 +18,7 @@ import java.util.stream.Collectors; public class BCauldronRecipe { public static List recipes = new ArrayList<>(); + public static int numConfigRecipes; public static List acceptedCustom = new ArrayList<>(); // All accepted custom and other items public static Set acceptedSimple = EnumSet.noneOf(Material.class); // All accepted simple items public static Set acceptedMaterials = EnumSet.noneOf(Material.class); // Fast cache for all accepted Materials @@ -24,20 +28,33 @@ public class BCauldronRecipe { //private List particles private PotionColor color; private List lore; + private boolean saveInData; // If this recipe should be saved in data and loaded again when the server restarts. Applicable to non-config recipes + /** + * A New Cauldron Recipe with the given name + * Use new BCauldronRecipe.Builder() for easier Cauldron Recipe Creation + * + * @param name Name of the Cauldron Recipe + */ + public BCauldronRecipe(String name) { + this.name = name; + color = PotionColor.CYAN; + } + @Nullable public static BCauldronRecipe fromConfig(ConfigurationSection cfg, String id) { - BCauldronRecipe recipe = new BCauldronRecipe(); - recipe.name = cfg.getString(id + ".name"); - if (recipe.name != null) { - recipe.name = P.p.color(recipe.name); + String name = cfg.getString(id + ".name"); + if (name != null) { + name = P.p.color(name); } else { P.p.errorLog("Missing name for Cauldron-Recipe: " + id); return null; } + BCauldronRecipe recipe = new BCauldronRecipe(name); + recipe.ingredients = BRecipe.loadIngredients(cfg, id); if (recipe.ingredients == null || recipe.ingredients.isEmpty()) { P.p.errorLog("No ingredients for Cauldron-Recipe: " + recipe.name); @@ -66,6 +83,9 @@ public class BCauldronRecipe { return recipe; } + + // Getter + @NotNull public String getName() { return name; @@ -86,6 +106,32 @@ public class BCauldronRecipe { return lore; } + public boolean isSaveInData() { + return saveInData; + } + + + // Setter + + /** + * When Changing ingredients, Accepted Lists have to be updated in BCauldronRecipe + */ + public void setIngredients(@NotNull List ingredients) { + this.ingredients = ingredients; + } + + public void setColor(@NotNull PotionColor color) { + this.color = color; + } + + public void setLore(List lore) { + this.lore = lore; + } + + public void setSaveInData(boolean saveInData) { + this.saveInData = saveInData; + } + /** * Find how much these ingredients match the given ones from 0-10. * If any ingredient is missing, returns 0 @@ -132,11 +178,64 @@ public class BCauldronRecipe { return match; } + public void updateAcceptedLists() { + for (RecipeItem ingredient : getIngredients()) { + if (ingredient.hasMaterials()) { + BCauldronRecipe.acceptedMaterials.addAll(ingredient.getMaterials()); + } + if (ingredient instanceof SimpleItem) { + BCauldronRecipe.acceptedSimple.add(((SimpleItem) ingredient).getMaterial()); + } else { + // Add it as acceptedCustom + if (!BCauldronRecipe.acceptedCustom.contains(ingredient)) { + BCauldronRecipe.acceptedCustom.add(ingredient); + } + } + } + } + @Override public String toString() { return "BCauldronRecipe{" + name + '}'; } + @Nullable + public static BCauldronRecipe get(String name) { + for (BCauldronRecipe recipe : recipes) { + if (recipe.name.equalsIgnoreCase(name)) { + return recipe; + } + } + return null; + } + + /** + * Gets a Modifiable Sublist of the CauldronRecipes that are loaded by config + * Changes are directly reflected by the main list of all recipes + * Changes to the main List of all CauldronRecipes will make the reference to this sublist invalid + * + * After adding or removing elements, CauldronRecipes.numConfigRecipes MUST be updated! + */ + public static List getConfigRecipes() { + return recipes.subList(0, numConfigRecipes); + } + + /** + * Gets a Modifiable Sublist of the CauldronRecipes that are added by plugins + * Changes are directly reflected by the main list of all recipes + * Changes to the main List of all CauldronRecipes will make the reference to this sublist invalid + */ + public static List getAddedRecipes() { + return recipes.subList(numConfigRecipes, recipes.size()); + } + + /** + * Gets the main List of all CauldronRecipes + */ + public static List getAllRecipes() { + return recipes; + } + /*public static boolean acceptItem(ItemStack item) { if (acceptedMaterials.contains(item.getType())) { // Extremely fast way to check for most items @@ -172,4 +271,70 @@ public class BCauldronRecipe { } return null; }*/ + + public static class Builder { + private BCauldronRecipe recipe; + + public Builder(String name) { + recipe = new BCauldronRecipe(name); + } + + + public Builder addIngredient(RecipeItem... item) { + if (recipe.ingredients == null) { + recipe.ingredients = new ArrayList<>(); + } + Collections.addAll(recipe.ingredients, item); + return this; + } + + public Builder addIngredient(ItemStack... item) { + if (recipe.ingredients == null) { + recipe.ingredients = new ArrayList<>(); + } + for (ItemStack i : item) { + recipe.ingredients.add(new CustomItem(i)); + } + return this; + } + + public Builder color(String colorString) { + recipe.color = PotionColor.fromString(colorString); + return this; + } + + public Builder color(PotionColor color) { + recipe.color = color; + return this; + } + + public Builder color(Color color) { + recipe.color = PotionColor.fromColor(color); + return this; + } + + public Builder addLore(String line) { + if (recipe.lore == null) { + recipe.lore = new ArrayList<>(); + } + recipe.lore.add(line); + return this; + } + + public BCauldronRecipe get() { + if (recipe.name == null) { + throw new IllegalArgumentException("CauldronRecipe name is null"); + } + if (BCauldronRecipe.get(recipe.getName()) != null) { + throw new IllegalArgumentException("CauldronRecipe with name " + recipe.getName() + " already exists"); + } + if (recipe.color == null) { + throw new IllegalArgumentException("CauldronRecipe has no color"); + } + if (recipe.ingredients == null || recipe.ingredients.isEmpty()) { + throw new IllegalArgumentException("CauldronRecipe has no ingredients"); + } + return recipe; + } + } } diff --git a/src/com/dre/brewery/recipe/BEffect.java b/src/com/dre/brewery/recipe/BEffect.java index 0dc282e..edb99cc 100644 --- a/src/com/dre/brewery/recipe/BEffect.java +++ b/src/com/dre/brewery/recipe/BEffect.java @@ -17,6 +17,15 @@ public class BEffect { private boolean hidden = false; + public BEffect(PotionEffectType type, short minlvl, short maxlvl, short minduration, short maxduration, boolean hidden) { + this.type = type; + this.minlvl = minlvl; + this.maxlvl = maxlvl; + this.minduration = minduration; + this.maxduration = maxduration; + this.hidden = hidden; + } + public BEffect(String effectString) { String[] effectSplit = effectString.split("/"); String effect = effectSplit[0]; diff --git a/src/com/dre/brewery/recipe/BRecipe.java b/src/com/dre/brewery/recipe/BRecipe.java index dc59c5c..e3dab3f 100644 --- a/src/com/dre/brewery/recipe/BRecipe.java +++ b/src/com/dre/brewery/recipe/BRecipe.java @@ -5,6 +5,8 @@ import com.dre.brewery.Brew; import com.dre.brewery.P; import com.dre.brewery.filedata.BConfig; import com.dre.brewery.utility.Tuple; +import org.apache.commons.lang.NotImplementedException; +import org.bukkit.Color; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; @@ -12,11 +14,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class BRecipe { public static List recipes = new ArrayList<>(); + public static int numConfigRecipes; // The number of recipes in the list that are from config private String[] name; private List ingredients = new ArrayList<>(); // Items and amounts @@ -30,8 +34,33 @@ public class BRecipe { private int alcohol; // Alcohol in perfect potion private List> lore; // Custom Lore on the Potion. The int is for Quality Lore, 0 = any, 1,2,3 = Bad,Middle,Good private List effects = new ArrayList<>(); // Special Effects when drinking + private boolean saveInData; // If this recipe should be saved in data and loaded again when the server restarts. Applicable to non-config recipes - public BRecipe() { + private BRecipe() { + } + + /** + * New BRecipe with Name + * Use new BRecipe.Builder() for easier Recipe Creation + * + * @param name The name for all qualities + */ + public BRecipe(String name, @NotNull PotionColor color) { + this.name = new String[] {name}; + this.color = color; + difficulty = 5; + } + + /** + * New BRecipe with Names + * Use new BRecipe.Builder() for easier Recipe Creation + * + * @param names {name bad, name normal, name good} + */ + public BRecipe(String[] names, @NotNull PotionColor color) { + this.name = names; + this.color = color; + difficulty = 5; } @Nullable @@ -380,6 +409,22 @@ public class BRecipe { return new Brew(bIngredients, quality, 0, distillruns, getAge(), wood, getRecipeName(), false, true, 0); } + public void updateAcceptedLists() { + for (RecipeItem ingredient : getIngredients()) { + if (ingredient.hasMaterials()) { + BCauldronRecipe.acceptedMaterials.addAll(ingredient.getMaterials()); + } + if (ingredient instanceof SimpleItem) { + BCauldronRecipe.acceptedSimple.add(((SimpleItem) ingredient).getMaterial()); + } else { + // Add it as acceptedCustom + if (!BCauldronRecipe.acceptedCustom.contains(ingredient)) { + BCauldronRecipe.acceptedCustom.add(ingredient); + } + } + } + } + // Getter @@ -433,6 +478,13 @@ public class BRecipe { return false; } + + // Getters + + public List getIngredients() { + return ingredients; + } + public int getCookingTime() { return cookingTime; } @@ -500,11 +552,97 @@ public class BRecipe { return effects; } + public boolean isSaveInData() { + return saveInData; + } + + // Setters + + /** + * When Changing ingredients, Accepted Lists have to be updated in BCauldronRecipe + */ + public void setIngredients(List ingredients) { + this.ingredients = ingredients; + } + + public void setCookingTime(int cookingTime) { + this.cookingTime = cookingTime; + } + + public void setDistillruns(byte distillruns) { + this.distillruns = distillruns; + } + + public void setDistillTime(int distillTime) { + this.distillTime = distillTime; + } + + public void setWood(byte wood) { + this.wood = wood; + } + + public void setAge(int age) { + this.age = age; + } + + public void setColor(@NotNull PotionColor color) { + this.color = color; + } + + public void setDifficulty(int difficulty) { + this.difficulty = difficulty; + } + + public void setAlcohol(int alcohol) { + this.alcohol = alcohol; + } + + public void setLore(List> lore) { + this.lore = lore; + } + + public void setEffects(List effects) { + this.effects = effects; + } + + public void setSaveInData(boolean saveInData) { + throw new NotImplementedException(); + //this.saveInData = saveInData; + } + + @Override public String toString() { return "BRecipe{" + getRecipeName() + '}'; } + /** + * Gets a Modifiable Sublist of the Recipes that are loaded by config + * Changes are directly reflected by the main list of all recipes + * Changes to the main List of all recipes will make the reference to this sublist invalid + * + * After adding or removing elements, BRecipe.numConfigRecipes MUST be updated! + */ + public static List getConfigRecipes() { + return recipes.subList(0, numConfigRecipes); + } + + /** + * Gets a Modifiable Sublist of the Recipes that are added by plugins + * Changes are directly reflected by the main list of all recipes + * Changes to the main List of all recipes will make the reference to this sublist invalid + */ + public static List getAddedRecipes() { + return recipes.subList(numConfigRecipes, recipes.size()); + } + + /** + * Gets the main List of all recipes + */ + public static List getAllRecipes() { + return recipes; + } + public static BRecipe get(String name) { for (BRecipe recipe : recipes) { if (recipe.getRecipeName().equalsIgnoreCase(name)) { @@ -513,4 +651,135 @@ public class BRecipe { } return null; } + + /*public static void saveAddedRecipes(ConfigurationSection cfg) { + int i = 0; + for (BRecipe recipe : getAddedRecipes()) { + if (recipe.isSaveInData()) { + cfg.set(i + ".name", recipe.name); + } + } + }*/ + + + public static class Builder { + private BRecipe recipe; + + public Builder(String name) { + recipe = new BRecipe(name, PotionColor.WATER); + } + + public Builder(String... names) { + recipe = new BRecipe(names, PotionColor.WATER); + } + + + public Builder addIngredient(RecipeItem... item) { + Collections.addAll(recipe.ingredients, item); + return this; + } + + public Builder addIngredient(ItemStack... item) { + for (ItemStack i : item) { + CustomItem customItem = new CustomItem(i); + customItem.setAmount(i.getAmount()); + recipe.ingredients.add(customItem); + } + return this; + } + + public Builder difficulty(int difficulty) { + recipe.difficulty = difficulty; + return this; + } + + public Builder color(String colorString) { + recipe.color = PotionColor.fromString(colorString); + return this; + } + + public Builder color(PotionColor color) { + recipe.color = color; + return this; + } + + public Builder color(Color color) { + recipe.color = PotionColor.fromColor(color); + return this; + } + + public Builder cook(int cookTime) { + recipe.cookingTime = cookTime; + return this; + } + + public Builder distill(byte distillRuns, int distillTime) { + recipe.distillruns = distillRuns; + recipe.distillTime = distillTime; + return this; + } + + public Builder age(int age, byte wood) { + recipe.age = age; + recipe.wood = wood; + return this; + } + + public Builder alcohol(int alcohol) { + recipe.alcohol = alcohol; + return this; + } + + public Builder addLore(String line) { + return addLore(0, line); + } + + /** + * Add a Line of Lore + * + * @param quality 0 for any quality, 1: bad, 2: normal, 3: good + * @param line The Line for custom lore to add + * @return this + */ + public Builder addLore(int quality, String line) { + if (quality < 0 || quality > 3) { + throw new IllegalArgumentException("Lore Quality must be 0 - 3"); + } + if (recipe.lore == null) { + recipe.lore = new ArrayList<>(); + } + recipe.lore.add(new Tuple<>(quality, line)); + return this; + } + + public Builder addEffects(BEffect... effects) { + Collections.addAll(recipe.effects, effects); + return this; + } + + public BRecipe get() { + if (recipe.name == null) { + throw new IllegalArgumentException("Recipe name is null"); + } + if (recipe.name.length != 1 && recipe.name.length != 3) { + throw new IllegalArgumentException("Recipe name neither 1 nor 3"); + } + if (BRecipe.get(recipe.getRecipeName()) != null) { + throw new IllegalArgumentException("Recipe with name " + recipe.getRecipeName() + " already exists"); + } + if (recipe.color == null) { + throw new IllegalArgumentException("Recipe has no color"); + } + if (recipe.ingredients == null || recipe.ingredients.isEmpty()) { + throw new IllegalArgumentException("Recipe has no ingredients"); + } + if (!recipe.isValid()) { + throw new IllegalArgumentException("Recipe has not valid"); + } + for (RecipeItem ingredient : recipe.ingredients) { + ingredient.makeImmutable(); + } + return recipe; + } + } } diff --git a/src/com/dre/brewery/recipe/PotionColor.java b/src/com/dre/brewery/recipe/PotionColor.java index 8561ea4..bfeee7b 100644 --- a/src/com/dre/brewery/recipe/PotionColor.java +++ b/src/com/dre/brewery/recipe/PotionColor.java @@ -101,4 +101,8 @@ public class PotionColor { } } + public static PotionColor fromColor(Color color) { + return new PotionColor(color); + } + } diff --git a/test/com/dre/brewery/RecipeTests.java b/test/com/dre/brewery/RecipeTests.java index 6b9e63c..e7efb04 100644 --- a/test/com/dre/brewery/RecipeTests.java +++ b/test/com/dre/brewery/RecipeTests.java @@ -1,10 +1,7 @@ package com.dre.brewery; -import com.dre.brewery.recipe.BCauldronRecipe; -import com.dre.brewery.recipe.BRecipe; -import com.dre.brewery.recipe.Ingredient; -import com.dre.brewery.recipe.RecipeItem; -import com.dre.brewery.recipe.SimpleItem; +import com.dre.brewery.api.BreweryApi; +import com.dre.brewery.recipe.*; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; @@ -66,4 +63,30 @@ public class RecipeTests { RecipeItem.getMatchingRecipeItem(item, false); } + + public static void testCustomRecipe() { + BreweryApi.removeRecipe("Good Build"); + BRecipe recipe = BreweryApi.recipeBuilder("Bad Build", "Good Build", "Uber Build") + .color(PotionColor.PINK) + .addIngredient(new ItemStack(Material.FLOWER_POT)) + .alcohol(32) + .cook(3) + .difficulty(4) + .age(3, (byte) 0) + .get(); + BreweryApi.addRecipe(recipe, false); + + P.p.log(BRecipe.getConfigRecipes().size() + ""); + + BreweryApi.removeRecipe("Bier"); + + P.p.log(BRecipe.getConfigRecipes().size() + ""); + + BCauldronRecipe r = BreweryApi.cauldronRecipeBuilder("Cooler Trank") + .color(PotionColor.PINK) + .addIngredient(new SimpleItem(Material.FLOWER_POT)) + .addLore("Schmeckt nAcH TOn?!") + .get(); + BreweryApi.addCauldronRecipe(r, false); + } }