diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java index bec9ecbb..c8985a13 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java @@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.api.crafting; import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.util.PostLoadObject; import net.Indyuce.mmoitems.MMOItems; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.CraftingRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.Recipe; diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStatus.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStatus.java index 85888d42..cd1b5735 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStatus.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStatus.java @@ -1,19 +1,14 @@ package net.Indyuce.mmoitems.api.crafting; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Level; - -import org.bukkit.configuration.ConfigurationSection; - import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.crafting.CraftingStatus.CraftingQueue.CraftingInfo; import net.Indyuce.mmoitems.api.crafting.recipe.CraftingRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.Recipe; import net.Indyuce.mmoitems.api.player.PlayerData; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.*; +import java.util.logging.Level; public class CraftingStatus { @@ -170,103 +165,4 @@ public class CraftingStatus { } } } - - /* - * instant craft: the progress bar is displayed on the subtitle and players - * must stay around their initial position or the craft will be cancelled - */ - // private InstantCraftingInfo instant; - // - // public InstantCraftingInfo getInstant() { - // return instant; - // } - // - // public - // public class InstantCraftingInfo extends CraftingInfo { - // private final PlayerDataManager data; - // private boolean timedOut; - // - // public InstantCraftingInfo(PlayerDataManager data, Recipe recipe) { - // super(recipe); - // this.data = data; - // } - // - // public void start() { - // data.getPlayer().closeInventory(); - // - // new BukkitRunnable() { - // int t = 0; - // final String format = - // Message.CRAFTING_SUBTITLE.formatRaw(ChatColor.GREEN); - // final Location loc = data.getPlayer().getLocation().clone(); - // - // public void run() { - // t++; - // - // if (data.getPlayer() == null || !data.getPlayer().isOnline() || - // data.getPlayer().isDead() || - // !data.getPlayer().getWorld().equals(loc.getWorld()) || - // loc.distanceSquared(data.getPlayer().getLocation()) > 15) { - // timedOut = true; - // cancel(); - // return; - // } - // - // if ((double) t / 10 > recipe.getRecipe().getCraftingTime()) { - // timedOut = true; - // - // recipe = recipe.getRecipe().getRecipeInfo(data, new - // IngredientInventory(data.getPlayer())); - // if (!recipe.areConditionsMet()) { - // Message.CONDITIONS_NOT_MET.format(ChatColor.RED).send(data.getPlayer()); - // data.getPlayer().playSound(data.getPlayer().getLocation(), - // Sound.ENTITY_VILLAGER_NO, 1, 1); - // return; - // } - // - // if (!recipe.allIngredientsHad()) { - // Message.NOT_ENOUGH_MATERIALS.format(ChatColor.RED).send(data.getPlayer()); - // data.getPlayer().playSound(data.getPlayer().getLocation(), - // Sound.ENTITY_VILLAGER_NO, 1, 1); - // return; - // } - // - // craft(); - // - // cancel(); - // return; - // } - // - // double left = recipe.getRecipe().getCraftingTime() - (double) t / 10; - // double r = (double) t / 10 / recipe.getRecipe().getCraftingTime(); - // data.getPlayer().sendTitle("", format.replace("#left#", - // formatDelay(left)).replace("#bar#", MMOUtils.getProgressBar(r, 10, - // AltChar.square)), 0, 20, 10); - // } - // }.runTaskTimer(MMOItems.plugin, 0, 2); - // } - // - // public void craft() { - // timedOut = true; - // - // for (CheckedIngredient ingredient : recipe.getIngredients()) - // ingredient.getPlayerIngredient().reduceItem(ingredient.getIngredient().getAmount(), - // ingredient.getIngredient()); - // - // data.getPlayer().playSound(data.getPlayer().getLocation(), - // Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1); - // for (ItemStack drop : - // data.getPlayer().getInventory().addItem(recipe.getRecipe().getOutput().generate()).values()) - // data.getPlayer().getWorld().dropItem(data.getPlayer().getLocation(), - // drop); - // - // updateData(); - // open(); - // } - // - // public boolean isTimedOut() { - // return timedOut || (System.currentTimeMillis() - started > - // recipe.getRecipe().getCraftingTime()); - // } - // } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/IngredientInventory.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/IngredientInventory.java deleted file mode 100644 index b5138ff6..00000000 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/IngredientInventory.java +++ /dev/null @@ -1,193 +0,0 @@ -package net.Indyuce.mmoitems.api.crafting; - -import io.lumine.mythic.lib.MythicLib; -import io.lumine.mythic.lib.api.item.NBTItem; -import io.lumine.mythic.lib.api.util.ui.QuickNumberRange; -import io.lumine.mythic.lib.api.util.ui.SilentNumbers; -import net.Indyuce.mmoitems.MMOItems; -import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; -import net.Indyuce.mmoitems.manager.CraftingManager.IngredientType; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; - -public class IngredientInventory { - - /* - * ingredients in the map are not stored using class instances as keys but - * using a unique string which is an unique ingredient identifier. allows - * for faster map check ups and fixes the >64 amount and ingredient - * splitting glitches - */ - private final Map ingredients = new HashMap<>(); - - public IngredientInventory(Player player) { this(player.getInventory()); } - - public IngredientInventory(Inventory inv) { - loop: for (ItemStack item : inv.getContents()) - if (item != null && item.getType() != Material.AIR) { - NBTItem nbt = MythicLib.plugin.getVersion().getWrapper().getNBTItem(item); - for (IngredientType ingredient : MMOItems.plugin.getCrafting().getIngredients()) { - if (ingredient.check(nbt)) { - addIngredient(nbt, ingredient); - continue loop; - } - } - } - } - - public void addIngredient(NBTItem item, IngredientType ingredient) { - String key = ingredient.getId() + ":" + ingredient.readKey(item); - - if (ingredients.containsKey(key)) - - /* - * add to current ingredient a specific amount. - */ - ingredients.get(key).add(item.getItem()); - else - - /* - * load an item stack and turn it into an ingredient which makes - * checking ingredients later much faster. - */ - ingredients.put(key, new PlayerIngredient(item.getItem())); - } - - @Nullable - public PlayerIngredient getIngredient(@NotNull Ingredient ingredient, @NotNull IngredientLookupMode lookupMode) { - String key = ingredient.getKey(); - - // Find level - QuickNumberRange lvl = null; - int dsh = key.indexOf('-'); - if (dsh > 0) { - - // Get lvl - String itemCrop = key.substring(dsh + 1); - String itemLevel = itemCrop.substring(0, itemCrop.indexOf('_')); - lvl = QuickNumberRange.getFromString(itemLevel); - key = key.substring(0, dsh) + key.substring(dsh + 1 + itemLevel.length()); } - - // Remove lvl - //ING//MMOItems.log("\u00a7a>\u00a78>\u00a77 Reading ingredient\u00a7a " + key + "\u00a77 (of level \u00a7a" + lvl + "\u00a77)"); - - for (String invKey : ingredients.keySet()) { - - int dash = invKey.indexOf('-'); - Integer itemLvl = null; - String ingredientKey = invKey; - if (dash > 0) { - - // Get lvl - String itemCrop = invKey.substring(dash + 1); - String itemLevel = itemCrop.substring(0, itemCrop.indexOf('_')); - itemLvl = SilentNumbers.IntegerParse(itemLevel); - ingredientKey = invKey.substring(0, dash) + invKey.substring(dash + 1 + itemLevel.length()); } - - - // Compare removing level - //ING//MMOItems.log(" \u00a7a>\u00a77 Comparing to \u00a7b" + invKey + "\u00a77 (\u00a73" + ingredientKey + "\u00a77)"); - - if (ingredientKey.equals(key)) { - - // Get level - boolean levelMet = true; - if (lookupMode != IngredientLookupMode.IGNORE_ITEM_LEVEL && lvl != null) { - - // Parse - if (itemLvl == null) { itemLvl = 0; } - levelMet = lvl.inRange(itemLvl); - //ING//MMOItems.log(" \u00a7a>\u00a77 Was level \u00a7e" + invKey + "\u00a77 (\u00a76" + levelMet + "\u00a77)"); - } - - if (levelMet) { return ingredients.get(invKey); } - } - } - - return null; - } - - @Deprecated - public boolean hasIngredient(Ingredient ingredient) { - PlayerIngredient found = getIngredient(ingredient, IngredientLookupMode.IGNORE_ITEM_LEVEL); - return found != null && found.getAmount() >= ingredient.getAmount(); - } - - public static class PlayerIngredient { - - /* - * stores items which correspond to a specific ingredient. when the - * ingredient is taken off the player inventory, the itemstack amounts - * get lowered. these POINT towards the player inventory itemStacks. - */ - private final List items = new ArrayList<>(); - - public PlayerIngredient(ItemStack item) { - items.add(item); - } - - public int getAmount() { - int t = 0; - for (ItemStack item : items) - t += item.getAmount(); - return t; - } - - public void add(ItemStack item) { - items.add(item); - } - - // used for upgrading recipes - public ItemStack getFirstItem() { - return items.get(0); - } - - /* - * algorythm which takes away a certain amount of items. used to consume - * ingredients when using recipes - */ - public void reduceItem(int amount) { - - Iterator iterator = items.iterator(); - while (iterator.hasNext() && amount > 0) { - ItemStack item = iterator.next(); - - // remove itemStack from list if amount <= 0 - if (item.getAmount() < 1) { - iterator.remove(); - continue; - } - - // amount of items it can take from this particular ItemStack - int take = Math.min(item.getAmount(), amount); - - amount -= take; - item.setAmount(item.getAmount() - take); - } - } - } - - /* - * could use a boolean because there are only two states possible, but makes - * things clearer. - */ - public enum IngredientLookupMode { - - /* - * item level must be ignored when the player is using an upgrading - * recipe, otherwise recipe cannot identify right item - */ - IGNORE_ITEM_LEVEL, - - /* - * scans ingredient inventory considering item levels - */ - BASIC - } -} diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/LoadedCraftingObject.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/LoadedCraftingObject.java new file mode 100644 index 00000000..34cf08ba --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/LoadedCraftingObject.java @@ -0,0 +1,47 @@ +package net.Indyuce.mmoitems.api.crafting; + +import io.lumine.mythic.lib.api.MMOLineConfig; + +import java.util.function.Function; + +/** + * Used to handle both ingredients and conditions because they share the same + * properties: + * - a way to display them in the recipe item lore. + * - some string identifier + * - a function which takes as input a line config and returns a loaded ingredient/condition + * + * @param Either Condition or Ingredient + */ +public class LoadedCraftingObject { + private final String id; + private final Function function; + + private ConditionalDisplay display; + + public LoadedCraftingObject(String id, Function function, ConditionalDisplay display) { + this.id = id; + this.function = function; + this.display = display; + } + + public String getId() { + return id; + } + + public void setDisplay(ConditionalDisplay display) { + this.display = display; + } + + public boolean hasDisplay() { + return display != null; + } + + public ConditionalDisplay getDisplay() { + return display; + } + + public C load(MMOLineConfig config) { + return function.apply(config); + } +} \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/CheckedCondition.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/CheckedCondition.java new file mode 100644 index 00000000..1ecf409a --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/CheckedCondition.java @@ -0,0 +1,31 @@ +package net.Indyuce.mmoitems.api.crafting.condition; + +public class CheckedCondition { + private final Condition condition; + private final boolean met; + + /** + * Instanciated everytime a condition needs to be evaluated for a player + * when evaluating a CheckedRecipe (when a player is opening a crafting + * station) + * + * @param condition Condition being evaluated + * @param met If the condition is met or not + */ + public CheckedCondition(Condition condition, boolean met) { + this.condition = condition; + this.met = met; + } + + public boolean isMet() { + return met; + } + + public Condition getCondition() { + return condition; + } + + public String format() { + return condition.formatDisplay(isMet() ? condition.getDisplay().getPositive() : condition.getDisplay().getNegative()); + } +} \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/Condition.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/Condition.java index 80046f13..201b2c17 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/Condition.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/condition/Condition.java @@ -56,34 +56,4 @@ public abstract class Condition { public CheckedCondition evaluateCondition(PlayerData data) { return new CheckedCondition(this, isMet(data)); } - - public static class CheckedCondition { - private final Condition condition; - private final boolean met; - - /** - * Instanciated everytime a condition needs to be evaluated for a player - * when evaluating a CheckedRecipe (when a player is opening a crafting - * station) - * - * @param condition Condition being evaluated - * @param met If the condition is met or not - */ - public CheckedCondition(Condition condition, boolean met) { - this.condition = condition; - this.met = met; - } - - public boolean isMet() { - return met; - } - - public Condition getCondition() { - return condition; - } - - public String format() { - return condition.formatDisplay(isMet() ? condition.getDisplay().getPositive() : condition.getDisplay().getNegative()); - } - } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/CheckedIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/CheckedIngredient.java new file mode 100644 index 00000000..ce8e189a --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/CheckedIngredient.java @@ -0,0 +1,95 @@ +package net.Indyuce.mmoitems.api.crafting.ingredient; + +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.PlayerIngredient; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Iterator; +import java.util.Set; + +public class CheckedIngredient { + @NotNull + private final Ingredient ingredient; + @Nullable + private final Set found; + private final boolean isHad; + + /** + * Instantiated everytime an ingredient is evaluated for a player when a + * CheckedRecipe is being created (when a player is opening a crafting + * station). This helps greatly reducing ingredient checkups by caching + * the items the plugin will need to take off the player's ingredient + * + * @param ingredient The ingredient being evaluated + * @param found The corresponding ingredient found in the player's + * ingredient + */ + public CheckedIngredient(@NotNull Ingredient ingredient, @Nullable Set found) { + this.ingredient = ingredient; + this.found = found; + this.isHad = getTotalAmount() >= ingredient.getAmount(); + } + + /** + * @return If the player has enough of the specific item or not + */ + public boolean isHad() { + return isHad; + } + + public int getTotalAmount() { + int total = 0; + for (PlayerIngredient ing : this.found) + total += ing.getAmount(); + return total; + } + + /** + * Takes off the required amount of ingredients from a player's inventory. + */ + public void takeAway() { + reduceItem(ingredient.getAmount()); + } + + /** + * Takes off a specific amount of ingredients from a player's inventory. + * + * @param amount Amount to take off the player's inventory. + * It most likely matches ingredient.getAmount() + */ + public void reduceItem(int amount) { + + Iterator iterator = found.iterator(); + while (iterator.hasNext() && amount > 0) { + ItemStack item = iterator.next().getItem(); + + // Remove itemStack from list if amount <= 0 + if (item.getAmount() <= 0) { + iterator.remove(); + continue; + } + + // Amount of items it can take from this particular ItemStack + int take = Math.min(item.getAmount(), amount); + + amount -= take; + item.setAmount(item.getAmount() - take); + } + } + + @NotNull + public Ingredient getIngredient() { + return ingredient; + } + + @Nullable + public Set getFound() { + return found; + } + + @NotNull + public String format() { + return ingredient.formatDisplay(isHad() ? ingredient.getDisplay().getPositive() : ingredient.getDisplay().getNegative()); + } +} \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java index 586d22a2..2ad1be01 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/Ingredient.java @@ -3,15 +3,18 @@ package net.Indyuce.mmoitems.api.crafting.ingredient; import io.lumine.mythic.lib.api.MMOLineConfig; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.crafting.ConditionalDisplay; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory.IngredientLookupMode; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory.PlayerIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.PlayerIngredient; import net.Indyuce.mmoitems.api.player.RPGPlayer; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -public abstract class Ingredient { +/** + * An ingredient from a crafting station recipe. + *

+ * See {@link PlayerIngredient} for more information. + */ +public abstract class Ingredient { private final String id; private final int amount; @@ -24,6 +27,10 @@ public abstract class Ingredient { this.amount = amount; } + /** + * @return The ingredient type id i.e the string placed + * at the beginning of the line config + */ public String getId() { return id; } @@ -42,61 +49,34 @@ public abstract class Ingredient { /** * @return The ingredient key which is used internally by MMOItems to check - * if two ingredients are of the same nature. + * if two ingredients are of the same nature. + * @deprecated Apart from ingredient type keys, keys are not used anymore. */ + @Deprecated public abstract String getKey(); /** * Apply specific placeholders to display the ingredient in the item lore. - * - * @param s String with unparsed placeholders - * @return String with parsed placeholders + * + * @param s String with unparsed placeholders + * @return String with parsed placeholders */ public abstract String formatDisplay(String s); + public abstract boolean matches(C playerIngredient); + /** * When the player right-clicks one of the items in a station, they can * preview the stats if itself and the components it is made of. This * is called to displace those preview elements. * * @param player Player looking at the recipe - * * @return The ItemStack to display to the player */ - @NotNull public abstract ItemStack generateItemStack(@NotNull RPGPlayer player); + @NotNull + public abstract ItemStack generateItemStack(@NotNull RPGPlayer player); public CheckedIngredient evaluateIngredient(@NotNull IngredientInventory inv) { - return new CheckedIngredient(this, inv.getIngredient(this, IngredientLookupMode.BASIC)); - } - - public static class CheckedIngredient { - @NotNull private final Ingredient ingredient; - @Nullable private final PlayerIngredient found; - - /** - * Instantiated everytime an ingredient is evaluated for a player when a - * CheckedRecipe is being created (when a player is opening a crafting - * station). This helps greatly reducing ingredient checkups by caching - * the items the plugin will need to take off the player's ingredient - * - * @param ingredient The ingredient being evaluated - * @param found The corresponding ingredient found in the player's - * ingredient - */ - private CheckedIngredient(@NotNull Ingredient ingredient, @Nullable PlayerIngredient found) { - this.ingredient = ingredient; - this.found = found; - } - - /** - * @return If the player has enough of the specific item or not - */ - public boolean isHad() { return found != null && found.getAmount() >= ingredient.getAmount(); } - - @NotNull public Ingredient getIngredient() { return ingredient; } - - @Nullable public PlayerIngredient getPlayerIngredient() { return found; } - - @NotNull public String format() { return ingredient.formatDisplay(isHad() ? ingredient.getDisplay().getPositive() : ingredient.getDisplay().getNegative()); } + return inv.findMatching(this); } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/IngredientType.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/IngredientType.java new file mode 100644 index 00000000..9d7ef7f5 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/IngredientType.java @@ -0,0 +1,44 @@ +package net.Indyuce.mmoitems.api.crafting.ingredient; + +import io.lumine.mythic.lib.api.MMOLineConfig; +import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmoitems.api.crafting.ConditionalDisplay; +import net.Indyuce.mmoitems.api.crafting.LoadedCraftingObject; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.PlayerIngredient; + +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * A type of ingredient, like a vanilla ingredient or a MMOItems ingredient. + *

+ * See {@link PlayerIngredient} for more information. + */ +public class IngredientType extends LoadedCraftingObject { + private final Predicate check; + private final Function readIngredient; + + public IngredientType(String id, Function function, ConditionalDisplay display, Predicate check, Function readIngredient) { + super(id, function, display); + + this.check = check; + this.readIngredient = readIngredient; + } + + /** + * @return If the checked item can be handled by this ingredient + */ + public boolean check(NBTItem item) { + return check.test(item); + } + + /** + * Reads the ingredient from an NBTItem, called after checking + * that this ingredient type can handle this NBTItem + * + * @return + */ + public PlayerIngredient readPlayerIngredient(NBTItem item) { + return readIngredient.apply(item); + } +} \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java index f9068ddd..46b4a35f 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/MMOItemIngredient.java @@ -1,28 +1,29 @@ package net.Indyuce.mmoitems.api.crafting.ingredient; import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.util.ui.QuickNumberRange; import io.lumine.mythic.lib.api.util.ui.SilentNumbers; import net.Indyuce.mmoitems.ItemStats; -import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem; -import net.Indyuce.mmoitems.stat.DisplayName; -import org.bukkit.inventory.ItemStack; - import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.crafting.ConfigMMOItem; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.MMOItemPlayerIngredient; +import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem; import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate; import net.Indyuce.mmoitems.api.player.RPGPlayer; +import net.Indyuce.mmoitems.stat.DisplayName; import net.Indyuce.mmoitems.stat.data.MaterialData; -import io.lumine.mythic.lib.api.MMOLineConfig; +import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; -public class MMOItemIngredient extends Ingredient { +public class MMOItemIngredient extends Ingredient { private final MMOItemTemplate template; - @NotNull private final QuickNumberRange level; + @NotNull + private final QuickNumberRange level; private final String display; public MMOItemIngredient(MMOLineConfig config) { @@ -64,7 +65,28 @@ public class MMOItemIngredient extends Ingredient { return s.replace("#item#", display).replace("#level#", (level.hasMax() || level.hasMax()) ? "lvl." + level.toString() + " " : "").replace("#amount#", String.valueOf(getAmount())); } - @NotNull @Override public ItemStack generateItemStack(@NotNull RPGPlayer player) { + @Override + public boolean matches(MMOItemPlayerIngredient playerIngredient) { + + // Check for item type + if (!playerIngredient.getType().equals(template.getType().getId())) + return false; + + // Check for item id + if (!playerIngredient.getId().equals(template.getId())) + return false; + + // Checks for level range + if (SilentNumbers.floor(level.getAsDouble(0)) != 0 && !level.inRange(playerIngredient.getUpgradeLevel())) + return false; + + // Yuss + return true; + } + + @NotNull + @Override + public ItemStack generateItemStack(@NotNull RPGPlayer player) { // Generate fresh from the template MMOItem mmo = template.newBuilder(player).build(); @@ -93,17 +115,22 @@ public class MMOItemIngredient extends Ingredient { } private String findName() { - String name = null; - if (template.getBaseItemData().containsKey(ItemStats.NAME)) - name = template.getBaseItemData().get(ItemStats.NAME).toString().replace("", "").replace("", "").replace("", ""); + String name; - if (template.getBaseItemData().containsKey(ItemStats.MATERIAL) && name == null) + // By default, take item display name + if (template.getBaseItemData().containsKey(ItemStats.NAME)) + name = template.getBaseItemData().get(ItemStats.NAME).toString().replace("", "").replace("", "").replace("", ""); + + // Try and take the material name + else if (template.getBaseItemData().containsKey(ItemStats.MATERIAL)) name = MMOUtils.caseOnWords(((MaterialData) template.getBaseItemData().get(ItemStats.MATERIAL)).getMaterial().name().toLowerCase().replace("_", " ")); - if (name == null) { name = "Unrecognized Item"; } + // Ultra rare case to avoid a NPE + else name = "Unrecognized Item"; // Append upgrade level - if (SilentNumbers.floor(level.getAsDouble(0)) != 0) { return DisplayName.appendUpgradeLevel(name, SilentNumbers.floor(level.getAsDouble(0))); } + if (SilentNumbers.floor(level.getAsDouble(0)) != 0) + return DisplayName.appendUpgradeLevel(name, SilentNumbers.floor(level.getAsDouble(0))); return name; } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java index cb086abf..a97fd12e 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/VanillaIngredient.java @@ -1,16 +1,16 @@ package net.Indyuce.mmoitems.api.crafting.ingredient; -import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.util.LegacyComponent; import net.Indyuce.mmoitems.MMOUtils; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.VanillaPlayerIngredient; import net.Indyuce.mmoitems.api.player.RPGPlayer; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -public class VanillaIngredient extends Ingredient { +public class VanillaIngredient extends Ingredient { private final Material material; /** @@ -40,8 +40,19 @@ public class VanillaIngredient extends Ingredient { return s.replace("#item#", display).replace("#amount#", "" + getAmount()); } + @Override + public boolean matches(VanillaPlayerIngredient ing) { + + // Check for material + if (ing.getType() != material) + return false; + + // Check for display name + return ing.getDisplayName() != null ? ing.getDisplayName().equals(displayName) : displayName == null; + } + @NotNull - @Override + @Override public ItemStack generateItemStack(@NotNull RPGPlayer player) { NBTItem item = NBTItem.get(new ItemStack(material, getAmount())); if (displayName != null) { diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/IngredientInventory.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/IngredientInventory.java new file mode 100644 index 00000000..653bfdea --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/IngredientInventory.java @@ -0,0 +1,111 @@ +package net.Indyuce.mmoitems.api.crafting.ingredient.inventory; + +import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmoitems.MMOItems; +import net.Indyuce.mmoitems.api.crafting.ingredient.CheckedIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.IngredientType; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class IngredientInventory { + private final Map> ingredients = new HashMap<>(); + + /** + * Loads all the possible crafting station ingredients from a player's inventory + */ + public IngredientInventory(Player player) { + this(player.getInventory()); + } + + /** + * Loads all the possible crafting station ingredients from an inventory + */ + public IngredientInventory(Inventory inv) { + loop: + for (ItemStack item : inv.getContents()) + if (item != null && item.getType() != Material.AIR && item.getAmount() > 0) { + NBTItem nbt = MythicLib.plugin.getVersion().getWrapper().getNBTItem(item); + for (IngredientType ingredient : MMOItems.plugin.getCrafting().getIngredients()) { + if (ingredient.check(nbt)) { + addIngredient(nbt, ingredient); + continue loop; + } + } + } + } + + /** + * Registers an ingredient. + * + * @param item The actual item in the inventory + * @param ingredient The type of the ingredient added + */ + public void addIngredient(NBTItem item, IngredientType ingredient) { + String key = ingredient.getId(); + + // Add to existing set + if (ingredients.containsKey(key)) + ingredients.get(key).add(ingredient.readPlayerIngredient(item)); + + // Initialize + else { + Set ingredients = new HashSet<>(); + ingredients.add(ingredient.readPlayerIngredient(item)); + this.ingredients.put(key, ingredients); + } + } + + @Nullable + public CheckedIngredient findMatching(@NotNull Ingredient ingredient) { + Set found = new HashSet<>(); + if (!ingredients.containsKey(ingredient.getId())) + return new CheckedIngredient(ingredient, found); + + for (PlayerIngredient checked : ingredients.get(ingredient.getId())) + if (ingredient.matches(checked)) + found.add(checked); + + return new CheckedIngredient(ingredient, found); + } + + /** + * @deprecated First use {@link #findMatching(Ingredient)} and cache its + * result to use the isHad() method of returned class instead. + */ + @Deprecated + public boolean hasIngredient(Ingredient ingredient) { + return findMatching(ingredient).isHad(); + } + + /** + * Could use a boolean because there are only two + * states possible, but makes things clearer. + * + * @deprecated Since 6.6 where ingredients were recoded. + */ + @Deprecated + public enum IngredientLookupMode { + + /** + * Item level must be ignored when the player is using an upgrading + * recipe, otherwise recipe cannot identify right item + */ + IGNORE_ITEM_LEVEL, + + /** + * Scans ingredient inventory considering item levels + */ + BASIC + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/MMOItemPlayerIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/MMOItemPlayerIngredient.java new file mode 100644 index 00000000..f858ca51 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/MMOItemPlayerIngredient.java @@ -0,0 +1,44 @@ +package net.Indyuce.mmoitems.api.crafting.ingredient.inventory; + +import com.google.gson.JsonParser; +import io.lumine.mythic.lib.api.item.NBTItem; + +public class MMOItemPlayerIngredient extends PlayerIngredient { + + /* + * No need to save as MMOItemTemplate or Type instances. Just need the string, + * because if they don't exist the recipe ingredients won't load anyways. + * And it's better for performance yes + */ + private final String type, id; + + /** + * Used to check if the level of the player's item matches + * the level range given by the recipe ingredient. + */ + private final int upgradeLevel; + + // TODO also add support for item level range? Quite easy to implement with the new PlayerIngredient interface. + + public MMOItemPlayerIngredient(NBTItem item) { + super(item); + + this.type = item.getString("MMOITEMS_ITEM_TYPE"); + this.id = item.getString("MMOITEMS_ITEM_ID"); + + String upgradeString = item.getString("MMOITEMS_UPGRADE"); + this.upgradeLevel = !upgradeString.isEmpty() ? new JsonParser().parse(upgradeString).getAsJsonObject().get("Level").getAsInt() : 0; + } + + public String getType() { + return type; + } + + public String getId() { + return id; + } + + public int getUpgradeLevel() { + return upgradeLevel; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/PlayerIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/PlayerIngredient.java new file mode 100644 index 00000000..9ca08e50 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/PlayerIngredient.java @@ -0,0 +1,59 @@ +package net.Indyuce.mmoitems.api.crafting.ingredient.inventory; + + +import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmoitems.api.crafting.ConditionalDisplay; +import net.Indyuce.mmoitems.api.crafting.ingredient.CheckedIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.IngredientType; +import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe; +import net.Indyuce.mmoitems.manager.CraftingManager; +import org.bukkit.inventory.ItemStack; + +import java.util.function.Function; +import java.util.function.Predicate; + +/** + * Code architecture for all the classes concerning Ingredients. + *

+ * MMOItems based ingredients / vanilla based ingredients are called IngredientTypes. + * One {@link IngredientType} is loaded for every type of ingredient there exists. + * External plugins can register other types of ingredients using + * {@link CraftingManager#registerIngredient(String, Function, ConditionalDisplay, Predicate, Function)}. + *

+ * Once all the ingredient types are loaded, stations are loaded from the config files. + * That means loading the ingredients from the recipes which is what {@link Ingredient} is used for. + *

+ * When a player opens a crafting station, MMOItems must first calculate all the ingredients + * they have in their inventory. A {@link IngredientInventory} is created, calculating all + * the ingredients the player has using the {@link PlayerIngredient} interface. + *

+ * The second step when opening a crafting station is comparing the ingredients required for one + * crafting recipe to the current player's ingredients, which is done using {@link CheckedIngredient} + * when creating {@link CheckedRecipe}. + * + * @author indyuce + */ +public abstract class PlayerIngredient { + + /** + * Redirects to the player's item in his inventory. This can be + * used later by MMOItems to reduce the amount of items in his inventory + * to take off ingredients from him. + */ + private final ItemStack item; + + public PlayerIngredient(NBTItem item) { + + // Throw NBTItem to garbage collector because no longer needed + this.item = item.getItem(); + } + + public ItemStack getItem() { + return item; + } + + public int getAmount() { + return item.getAmount(); + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/VanillaPlayerIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/VanillaPlayerIngredient.java new file mode 100644 index 00000000..eb19036f --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/ingredient/inventory/VanillaPlayerIngredient.java @@ -0,0 +1,31 @@ +package net.Indyuce.mmoitems.api.crafting.ingredient.inventory; + +import io.lumine.mythic.lib.api.item.NBTItem; +import org.bukkit.Material; +import org.bukkit.inventory.meta.ItemMeta; + +import javax.annotation.Nullable; + +public class VanillaPlayerIngredient extends PlayerIngredient { + private final Material material; + @Nullable + private final String displayName; + + public VanillaPlayerIngredient(NBTItem item) { + super(item); + + this.material = item.getItem().getType(); + + ItemMeta meta = item.getItem().getItemMeta(); + this.displayName = meta.hasDisplayName() ? meta.getDisplayName() : null; + } + + public Material getType() { + return material; + } + + @Nullable + public String getDisplayName() { + return displayName; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CheckedRecipe.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CheckedRecipe.java index 1d015d99..ae85ab39 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CheckedRecipe.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CheckedRecipe.java @@ -1,18 +1,17 @@ package net.Indyuce.mmoitems.api.crafting.recipe; +import net.Indyuce.mmoitems.api.crafting.condition.CheckedCondition; +import net.Indyuce.mmoitems.api.crafting.condition.Condition; +import net.Indyuce.mmoitems.api.crafting.ingredient.CheckedIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; +import net.Indyuce.mmoitems.api.player.PlayerData; +import org.bukkit.inventory.ItemStack; + import java.util.LinkedHashSet; import java.util.Set; import java.util.stream.Collectors; -import org.bukkit.inventory.ItemStack; - -import net.Indyuce.mmoitems.api.crafting.IngredientInventory; -import net.Indyuce.mmoitems.api.crafting.condition.Condition; -import net.Indyuce.mmoitems.api.crafting.condition.Condition.CheckedCondition; -import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; -import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient.CheckedIngredient; -import net.Indyuce.mmoitems.api.player.PlayerData; - public class CheckedRecipe { private final Recipe recipe; @@ -54,6 +53,10 @@ public class CheckedRecipe { return recipe; } + /** + * @return True if both conditions are met and ingredients are gathered + * @deprecated Not used internally anymore + */ @Deprecated public boolean isUnlocked() { return ingredientsHad && conditionsMet; diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CraftingRecipe.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CraftingRecipe.java index acf3f18c..b14a37ba 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CraftingRecipe.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/CraftingRecipe.java @@ -4,7 +4,7 @@ import io.lumine.mythic.lib.api.util.SmartGive; import net.Indyuce.mmoitems.api.crafting.ConfigMMOItem; import net.Indyuce.mmoitems.api.crafting.CraftingStation; import net.Indyuce.mmoitems.api.crafting.CraftingStatus.CraftingQueue; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; import net.Indyuce.mmoitems.api.event.PlayerUseCraftingStationEvent; import net.Indyuce.mmoitems.api.item.util.ConfigItems; import net.Indyuce.mmoitems.api.player.PlayerData; @@ -19,7 +19,7 @@ public class CraftingRecipe extends Recipe { private final ConfigMMOItem output; /* - * there can't be any crafting time for upgrading recipes since there is no + * There can't be any crafting time for upgrading recipes since there is no * way to save an MMOItem in the config file TODO save as ItemStack */ private final double craftingTime; @@ -96,4 +96,9 @@ public class CraftingRecipe extends Recipe { public ItemStack display(CheckedRecipe recipe) { return ConfigItems.CRAFTING_RECIPE_DISPLAY.newBuilder(recipe).build(); } + + @Override + public CheckedRecipe evaluateRecipe(PlayerData data, IngredientInventory inv) { + return new CheckedRecipe(this, data, inv); + } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/Recipe.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/Recipe.java index 0fd133ee..9977a48c 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/Recipe.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/Recipe.java @@ -3,9 +3,9 @@ package net.Indyuce.mmoitems.api.crafting.recipe; import io.lumine.mythic.lib.api.MMOLineConfig; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.crafting.CraftingStation; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory; import net.Indyuce.mmoitems.api.crafting.condition.Condition; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; import net.Indyuce.mmoitems.api.crafting.trigger.Trigger; import net.Indyuce.mmoitems.api.player.PlayerData; import org.apache.commons.lang.Validate; @@ -51,7 +51,6 @@ public abstract class Recipe { for (String format : config.getStringList("ingredients")) try { Ingredient ingredient = MMOItems.plugin.getCrafting().getIngredient(new MMOLineConfig(format)); - Validate.notNull(ingredient, "Could not match ingredient"); ingredients.add(ingredient); } catch (IllegalArgumentException exception) { throw new IllegalArgumentException("Could not load ingredient '" + format + "': " + exception.getMessage()); @@ -63,7 +62,6 @@ public abstract class Recipe { for (String format : config.getStringList("conditions")) try { Condition condition = MMOItems.plugin.getCrafting().getCondition(new MMOLineConfig(format)); - Validate.notNull(condition, "Could not match condition"); conditions.add(condition); } catch (IllegalArgumentException exception) { throw new IllegalArgumentException("Could not load condition '" + format + "': " + exception.getMessage()); @@ -131,20 +129,22 @@ public abstract class Recipe { options.put(option, value); } - public CheckedRecipe evaluateRecipe(PlayerData data, IngredientInventory inv) { - return new CheckedRecipe(this, data, inv); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof Recipe && ((Recipe) obj).id.equals(id); - } + /** + * THE method that checks if a player can use a recipe or not. This checks for + * conditions and ingredients and saves all the info needed to display everything + * in the item lore. + * + * @param data Player trying to use the recipe + * @param inv The ingredients of the player + * @return Class that knows if the player can use the recipe + */ + public abstract CheckedRecipe evaluateRecipe(PlayerData data, IngredientInventory inv); /** * Called when all the recipe conditions are to true and when the player * eventually starts crafting OR when the player claims the item in the * crafting queue once the delay is over. - * + * * @param data Player crafting the item * @param inv The player's ingredients * @param recipe The recipe used to craft the item @@ -156,18 +156,23 @@ public abstract class Recipe { * Applies extra conditions when a player has just clicked on a recipe item * in the GUI. This method is called after checking for the recipe * conditions and ingredients. - * - * @param data The player crafting the item - * @param inv The player's ingredients - * @param recipe The recipe used to craft the item - * @param station The station used to craft the item - * @return If the player can use the recipe + * + * @param data The player crafting the item + * @param inv The player's ingredients + * @param recipe The recipe used to craft the item + * @param station The station used to craft the item + * @return If the player can use the recipe */ public abstract boolean canUse(PlayerData data, IngredientInventory inv, CheckedRecipe recipe, CraftingStation station); public abstract ItemStack display(CheckedRecipe recipe); - public enum RecipeOption { + @Override + public boolean equals(Object obj) { + return obj instanceof Recipe && ((Recipe) obj).id.equals(id); + } + + public static enum RecipeOption { /** * Hide the crafting recipe when one of the condition is not met diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/UpgradingRecipe.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/UpgradingRecipe.java index 6db3de53..cb95fbdf 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/UpgradingRecipe.java +++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/recipe/UpgradingRecipe.java @@ -1,27 +1,25 @@ package net.Indyuce.mmoitems.api.crafting.recipe; -import java.util.Random; - -import org.bukkit.ChatColor; -import org.bukkit.Sound; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.inventory.ItemStack; - +import io.lumine.mythic.lib.api.item.NBTItem; import net.Indyuce.mmoitems.ItemStats; import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.crafting.ConfigMMOItem; import net.Indyuce.mmoitems.api.crafting.CraftingStation; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory.IngredientLookupMode; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory.PlayerIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.CheckedIngredient; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; import net.Indyuce.mmoitems.api.crafting.ingredient.MMOItemIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem; import net.Indyuce.mmoitems.api.item.util.ConfigItems; import net.Indyuce.mmoitems.api.player.PlayerData; import net.Indyuce.mmoitems.api.util.message.Message; import net.Indyuce.mmoitems.stat.data.UpgradeData; -import io.lumine.mythic.lib.MythicLib; +import org.bukkit.ChatColor; +import org.bukkit.Sound; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.inventory.ItemStack; + +import java.util.Random; public class UpgradingRecipe extends Recipe { private final ConfigMMOItem item; @@ -32,9 +30,7 @@ public class UpgradingRecipe extends Recipe { public UpgradingRecipe(ConfigurationSection config) { super(config); - /* - * load item being upgraded. - */ + // load item being upgraded. item = new ConfigMMOItem(config.getConfigurationSection("item")); ingredient = new MMOItemIngredient(item); } @@ -44,12 +40,12 @@ public class UpgradingRecipe extends Recipe { } @Override - public void whenUsed(PlayerData data, IngredientInventory inv, CheckedRecipe uncastRecipe, CraftingStation station) { - UpgradingRecipeInfo recipe = (UpgradingRecipeInfo) uncastRecipe; + public void whenUsed(PlayerData data, IngredientInventory inv, CheckedRecipe castRecipe, CraftingStation station) { + CheckedUpgradingRecipe recipe = (CheckedUpgradingRecipe) castRecipe; recipe.getUpgradeData().upgrade(recipe.getMMOItem()); recipe.getUpgraded().setItemMeta(recipe.getMMOItem().newBuilder().build().getItemMeta()); - uncastRecipe.getRecipe().getTriggers().forEach(trigger -> trigger.whenCrafting(data)); + castRecipe.getRecipe().getTriggers().forEach(trigger -> trigger.whenCrafting(data)); if (!data.isOnline()) return; @@ -60,14 +56,9 @@ public class UpgradingRecipe extends Recipe { @Override public boolean canUse(PlayerData data, IngredientInventory inv, CheckedRecipe uncastRecipe, CraftingStation station) { - /* - * try to find the item which is meant to be updated. null check is - * ugly, BUT it does halve calculations done because it does not calls - * two map lookups. it is not needed to check for the amount because - * only one item is upgraded. - */ - PlayerIngredient upgraded = inv.getIngredient(ingredient, IngredientLookupMode.IGNORE_ITEM_LEVEL); - if (upgraded == null) { + // Find the item which should be upgraded + CheckedIngredient upgraded = inv.findMatching(ingredient); + if (!upgraded.isHad()) { if (!data.isOnline()) return false; @@ -76,11 +67,15 @@ public class UpgradingRecipe extends Recipe { return false; } - UpgradingRecipeInfo recipe = (UpgradingRecipeInfo) uncastRecipe; - if (!(recipe.mmoitem = new LiveMMOItem(MythicLib.plugin.getVersion().getWrapper().getNBTItem(upgraded.getFirstItem()))) - .hasData(ItemStats.UPGRADE)) + // Finds the item that will be upgraded + NBTItem firstItem = NBTItem.get(upgraded.getFound().stream().findFirst().get().getItem()); + + // Checks if upgraded item DOES has an upgrade template + CheckedUpgradingRecipe recipe = (CheckedUpgradingRecipe) uncastRecipe; + if (!(recipe.mmoitem = new LiveMMOItem(firstItem)).hasData(ItemStats.UPGRADE)) return false; + // Checks for max upgrade level if (!(recipe.upgradeData = (UpgradeData) recipe.getMMOItem().getData(ItemStats.UPGRADE)).canLevelUp()) { if (!data.isOnline()) return false; @@ -90,11 +85,16 @@ public class UpgradingRecipe extends Recipe { return false; } + // Checks for failure if (random.nextDouble() > recipe.getUpgradeData().getSuccess()) { + + // Should the item be destroyed when failing to upgrade if (recipe.getUpgradeData().destroysOnFail()) recipe.getUpgraded().setAmount(recipe.getUpgraded().getAmount() - 1); - recipe.getIngredients().forEach(ingredient -> ingredient.getPlayerIngredient().reduceItem(ingredient.getIngredient().getAmount())); + // Take away ingredients + recipe.getIngredients().forEach(ingredient -> ingredient.takeAway()); + if (!data.isOnline()) return false; @@ -113,14 +113,18 @@ public class UpgradingRecipe extends Recipe { @Override public CheckedRecipe evaluateRecipe(PlayerData data, IngredientInventory inv) { - return new UpgradingRecipeInfo(this, data, inv); + return new CheckedUpgradingRecipe(this, data, inv); } - public static class UpgradingRecipeInfo extends CheckedRecipe { + /** + * Used to cache the LiveMMOItem instance and UpgradeData + * which take a little performance to calculate. + */ + public class CheckedUpgradingRecipe extends CheckedRecipe { private LiveMMOItem mmoitem; private UpgradeData upgradeData; - public UpgradingRecipeInfo(Recipe recipe, PlayerData data, IngredientInventory inv) { + public CheckedUpgradingRecipe(Recipe recipe, PlayerData data, IngredientInventory inv) { super(recipe, data, inv); } diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java b/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java index 08cd078c..b22f644b 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java +++ b/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java @@ -3,25 +3,19 @@ package net.Indyuce.mmoitems.api.item.template; import io.lumine.mythic.lib.api.util.PostLoadObject; import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory; import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider; -import io.lumine.mythic.lib.api.util.ui.SilentNumbers; -import net.Indyuce.mmoitems.ItemStats; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.ItemTier; import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.item.ItemReference; import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder; -import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem; import net.Indyuce.mmoitems.api.player.PlayerData; import net.Indyuce.mmoitems.api.player.RPGPlayer; -import net.Indyuce.mmoitems.api.util.NumericStatFormula; import net.Indyuce.mmoitems.api.util.message.FFPMMOItems; import net.Indyuce.mmoitems.stat.data.random.RandomStatData; import net.Indyuce.mmoitems.stat.type.ItemStat; import org.apache.commons.lang.Validate; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.util.*; @@ -149,7 +143,6 @@ public class MMOItemTemplate extends PostLoadObject implements ItemReference { return options.contains(option); } - public MMOItemBuilder newBuilder(@Nullable Player player) { if (player != null) { return newBuilder(PlayerData.get(player).getRPG()); } return newBuilder((RPGPlayer) null); diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/CraftingRecipeDisplay.java b/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/CraftingRecipeDisplay.java index 8ec5ba83..e1414649 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/CraftingRecipeDisplay.java +++ b/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/CraftingRecipeDisplay.java @@ -7,7 +7,7 @@ import io.lumine.mythic.lib.api.util.LegacyComponent; import io.lumine.mythic.utils.adventure.text.Component; import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.crafting.ConditionalDisplay; -import net.Indyuce.mmoitems.api.crafting.condition.Condition.CheckedCondition; +import net.Indyuce.mmoitems.api.crafting.condition.CheckedCondition; import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.CraftingRecipe; import net.Indyuce.mmoitems.api.item.util.ConfigItem; diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/UpgradingRecipeDisplay.java b/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/UpgradingRecipeDisplay.java index 6f62bb5a..31a98b32 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/UpgradingRecipeDisplay.java +++ b/src/main/java/net/Indyuce/mmoitems/api/item/util/crafting/UpgradingRecipeDisplay.java @@ -1,13 +1,12 @@ package net.Indyuce.mmoitems.api.item.util.crafting; -import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.api.item.ItemTag; import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.util.LegacyComponent; import io.lumine.mythic.utils.adventure.text.Component; import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.crafting.ConditionalDisplay; -import net.Indyuce.mmoitems.api.crafting.condition.Condition.CheckedCondition; +import net.Indyuce.mmoitems.api.crafting.condition.CheckedCondition; import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.UpgradingRecipe; import net.Indyuce.mmoitems.api.item.util.ConfigItem; @@ -16,11 +15,7 @@ import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; +import java.util.*; public class UpgradingRecipeDisplay extends ConfigItem { public UpgradingRecipeDisplay() { diff --git a/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java b/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java index 64d3640b..225293ea 100644 --- a/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java +++ b/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemIngredient.java @@ -1,19 +1,25 @@ package net.Indyuce.mmoitems.comp.mythicmobs.crafting; -import java.util.Optional; - -import org.apache.commons.lang.Validate; -import org.bukkit.inventory.ItemStack; - +import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.xikage.mythicmobs.MythicMobs; import io.lumine.xikage.mythicmobs.adapters.bukkit.BukkitAdapter; import io.lumine.xikage.mythicmobs.items.MythicItem; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; import net.Indyuce.mmoitems.api.player.RPGPlayer; -import io.lumine.mythic.lib.api.MMOLineConfig; +import org.apache.commons.lang.Validate; +import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -public class MythicItemIngredient extends Ingredient { +import java.util.Optional; + +/** + * No way of checking if an item was generated using MythicMobs? There does + * not seem to be any NBTTag for that using the latest dev build + * + * @deprecated Not implemented yet + */ +@Deprecated +public class MythicItemIngredient extends Ingredient { private final MythicItem mythicitem; private final String display; @@ -39,8 +45,13 @@ public class MythicItemIngredient extends Ingredient { return s.replace("#item#", display).replace("#amount#", "" + getAmount()); } + @Override + public boolean matches(MythicItemPlayerIngredient playerIngredient) { + return false; + } + @NotNull - @Override + @Override public ItemStack generateItemStack(@NotNull RPGPlayer player) { return BukkitAdapter.adapt(mythicitem.generateItemStack(getAmount())); } diff --git a/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemPlayerIngredient.java b/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemPlayerIngredient.java new file mode 100644 index 00000000..cc626ec2 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/comp/mythicmobs/crafting/MythicItemPlayerIngredient.java @@ -0,0 +1,29 @@ +package net.Indyuce.mmoitems.comp.mythicmobs.crafting; + +import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.PlayerIngredient; + +/** + * @deprecated Not implemented yet + */ +@Deprecated +public class MythicItemPlayerIngredient extends PlayerIngredient { + private final String type, id; + + public MythicItemPlayerIngredient(NBTItem item) { + super(item); + + type = item.getString("MYTHIC_TYPE").toLowerCase(); + + // No idea what to use here + id = null; + } + + public String getType() { + return type; + } + + public String getId() { + return id; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java b/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java index 01537d90..fe2c5105 100644 --- a/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java +++ b/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationPreview.java @@ -6,7 +6,7 @@ import io.lumine.mythic.lib.api.util.LegacyComponent; import io.lumine.mythic.lib.api.util.ui.SilentNumbers; import io.lumine.mythic.utils.adventure.text.Component; import net.Indyuce.mmoitems.MMOUtils; -import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient.CheckedIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.CheckedIngredient; import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.CraftingRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.UpgradingRecipe; diff --git a/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationView.java b/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationView.java index b6d48ec5..1fb5e914 100644 --- a/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationView.java +++ b/src/main/java/net/Indyuce/mmoitems/gui/CraftingStationView.java @@ -8,9 +8,9 @@ import net.Indyuce.mmoitems.MMOUtils; import net.Indyuce.mmoitems.api.crafting.CraftingStation; import net.Indyuce.mmoitems.api.crafting.CraftingStatus.CraftingQueue; import net.Indyuce.mmoitems.api.crafting.CraftingStatus.CraftingQueue.CraftingInfo; -import net.Indyuce.mmoitems.api.crafting.IngredientInventory; import net.Indyuce.mmoitems.api.crafting.Layout; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.IngredientInventory; import net.Indyuce.mmoitems.api.crafting.recipe.CheckedRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.CraftingRecipe; import net.Indyuce.mmoitems.api.crafting.recipe.Recipe; @@ -34,6 +34,7 @@ import java.util.UUID; public class CraftingStationView extends PluginInventory { private final CraftingStation station; private final Layout layout; + private List recipes; private IngredientInventory ingredients; @@ -128,6 +129,7 @@ public class CraftingStationView extends PluginInventory { public void whenClicked(InventoryClickEvent event) { if (!playerData.isOnline()) return; + event.setCancelled(true); if (!MMOUtils.isMetaItem(event.getCurrentItem(), false)) return; @@ -159,18 +161,17 @@ public class CraftingStationView extends PluginInventory { NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCurrentItem()); String tag = item.getString("recipeId"); - if (!tag.equals("")) { + if (!tag.isEmpty()) { CheckedRecipe recipe = getRecipe(tag); - if (event.isRightClick()) { + if (event.isRightClick()) new CraftingStationPreview(this, recipe).open(); - return; + else { + processRecipe(recipe); + open(); } - - processRecipe(recipe); - open(); } - if (!(tag = item.getString("queueId")).equals("")) { + if (!(tag = item.getString("queueId")).isEmpty()) { UUID uuid = UUID.fromString(tag); CraftingInfo recipeInfo = playerData.getCrafting().getQueue(station).getCraft(uuid); CraftingRecipe recipe = recipeInfo.getRecipe(); @@ -247,7 +248,7 @@ public class CraftingStationView extends PluginInventory { return; recipe.getRecipe().whenUsed(playerData, ingredients, recipe, station); - recipe.getIngredients().forEach(ingredient -> ingredient.getPlayerIngredient().reduceItem(ingredient.getIngredient().getAmount())); + recipe.getIngredients().forEach(ingredient -> ingredient.takeAway()); recipe.getConditions().forEach(condition -> condition.getCondition().whenCrafting(playerData)); updateData(); diff --git a/src/main/java/net/Indyuce/mmoitems/manager/CraftingManager.java b/src/main/java/net/Indyuce/mmoitems/manager/CraftingManager.java index dd0515e6..06fa0504 100644 --- a/src/main/java/net/Indyuce/mmoitems/manager/CraftingManager.java +++ b/src/main/java/net/Indyuce/mmoitems/manager/CraftingManager.java @@ -1,6 +1,5 @@ package net.Indyuce.mmoitems.manager; -import com.google.gson.JsonParser; import io.lumine.mythic.lib.api.MMOLineConfig; import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.util.AltChar; @@ -8,16 +7,22 @@ import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.ConfigFile; import net.Indyuce.mmoitems.api.crafting.ConditionalDisplay; import net.Indyuce.mmoitems.api.crafting.CraftingStation; +import net.Indyuce.mmoitems.api.crafting.LoadedCraftingObject; import net.Indyuce.mmoitems.api.crafting.condition.*; import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.IngredientType; import net.Indyuce.mmoitems.api.crafting.ingredient.MMOItemIngredient; import net.Indyuce.mmoitems.api.crafting.ingredient.VanillaIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.MMOItemPlayerIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.PlayerIngredient; +import net.Indyuce.mmoitems.api.crafting.ingredient.inventory.VanillaPlayerIngredient; import net.Indyuce.mmoitems.api.crafting.trigger.*; -import net.Indyuce.mmoitems.comp.mythicmobs.crafting.MythicItemIngredient; import net.Indyuce.mmoitems.comp.mythicmobs.crafting.MythicMobsSkillTrigger; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; +import org.jetbrains.annotations.NotNull; +import javax.annotation.Nullable; import java.io.File; import java.util.*; import java.util.function.Function; @@ -26,18 +31,19 @@ import java.util.logging.Level; public class CraftingManager implements Reloadable { - /* - * order matters when trying to recognize an ingredient type: if none + /** + * Order matters when trying to recognize an ingredient type: if none * ingredient matches, the item is considered as a vanilla item. */ private final List ingredients = new ArrayList<>(); - private final Set> conditions = new HashSet<>(); - private final Set> triggers = new HashSet<>(); + private final Set> conditions = new HashSet<>(); + private final Set> triggers = new HashSet<>(); private final Map stations = new HashMap<>(); public CraftingManager() { - // conditions + + // Conditions registerCondition("level", LevelCondition::new, new ConditionalDisplay("&a" + AltChar.check + " Requires Level #level#", "&c" + AltChar.cross + " Requires Level #level#")); registerCondition("permission", PermissionCondition::new, null); registerCondition("placeholder", PlaceholderCondition::new, null); @@ -46,26 +52,22 @@ public class CraftingManager implements Reloadable { registerCondition("food", FoodCondition::new, new ConditionalDisplay("&a" + AltChar.check + " Requires #food# Food", "&c" + AltChar.cross + " Requires #food# Food")); registerCondition("class", ClassCondition::new, new ConditionalDisplay("&a" + AltChar.check + " Required Class: #class#", "&c" + AltChar.cross + " Required Class: #class#")); - // triggers + // Triggers registerTrigger("command", CommandTrigger::new); registerTrigger("message", MessageTrigger::new); registerTrigger("sound", SoundTrigger::new); registerTrigger("vanilla", VanillaTrigger::new); registerTrigger("mmoitem", MMOItemTrigger::new); - // ingredients - registerIngredient("vanilla", VanillaIngredient::new, new ConditionalDisplay("&8" + AltChar.check + " &7#amount# #item#", "&c" + AltChar.cross + " &7#amount# #item#"), nbt -> true, item -> item.getItem().getType().name().toLowerCase() + "_" + (item.getItem().hasItemMeta() ? item.getItem().getItemMeta().getDisplayName() : null)); - registerIngredient("mmoitem", MMOItemIngredient::new, new ConditionalDisplay("&8" + AltChar.check + " &7#amount# #level##item#", "&c" + AltChar.cross + " &7#amount# #level##item#"), NBTItem::hasType, item -> { - String upgradeString = item.getString("MMOITEMS_UPGRADE"); - int level = !upgradeString.isEmpty() ? new JsonParser().parse(upgradeString).getAsJsonObject().get("Level").getAsInt() : 0; - return item.getString("MMOITEMS_ITEM_TYPE").toLowerCase() + (level != 0 ? "-" + level : "") + "_" + item.getString("MMOITEMS_ITEM_ID").toLowerCase(); - }); + // Ingredients + registerIngredient("vanilla", VanillaIngredient::new, new ConditionalDisplay("&8" + AltChar.check + " &7#amount# #item#", "&c" + AltChar.cross + " &7#amount# #item#"), nbt -> true, VanillaPlayerIngredient::new); + registerIngredient("mmoitem", MMOItemIngredient::new, new ConditionalDisplay("&8" + AltChar.check + " &7#amount# #level##item#", "&c" + AltChar.cross + " &7#amount# #level##item#"), NBTItem::hasType, MMOItemPlayerIngredient::new); - // mm comp + // MythicMobs native compatibility if (Bukkit.getPluginManager().getPlugin("MythicMobs") != null) { - registerIngredient("mythicitem", MythicItemIngredient::new, + /*registerIngredient("mythicitem", MythicItemIngredient::new, new ConditionalDisplay("&8" + AltChar.check + " &7#amount# #item#", "&c" + AltChar.cross + " &7#amount# #item#"), - nbt -> nbt.hasTag("MYTHIC_TYPE"), nbt -> nbt.getString("MYTHIC_TYPE").toLowerCase()); + nbt -> nbt.hasTag("MYTHIC_TYPE"), MythicItemPlayerIngredient::new);*/ registerTrigger("mmskill", MythicMobsSkillTrigger::new); } } @@ -75,7 +77,7 @@ public class CraftingManager implements Reloadable { ConfigFile language = new ConfigFile("/language", "crafting-stations"); - for (LoadedObject condition : getConditions()) + for (LoadedCraftingObject condition : getConditions()) if (condition.hasDisplay()) { String path = "condition." + condition.getId(); if (!language.getConfig().contains(path)) { @@ -134,6 +136,11 @@ public class CraftingManager implements Reloadable { return stations.get(id); } + /** + * Finds the corresponding ingredient type, and from there + * load the corresponding ingredient from the line config + */ + @NotNull public Ingredient getIngredient(MMOLineConfig config) { String key = config.getKey(); @@ -141,113 +148,91 @@ public class CraftingManager implements Reloadable { if (ingredient.getId().equals(key)) return ingredient.load(config); - return null; + throw new IllegalArgumentException("Could not match ingredient"); } + /** + * Finds the corresponding condition type, and from there + * load the corresponding condition from the line config + */ + @NotNull public Condition getCondition(MMOLineConfig config) { String key = config.getKey(); - for (LoadedObject condition : conditions) + for (LoadedCraftingObject condition : conditions) if (condition.getId().equalsIgnoreCase(key)) return condition.load(config); - return null; + throw new IllegalArgumentException("Could not match condition"); } + /** + * Finds the corresponding trigger type, and from there + * load the corresponding trigger from the line config + */ + @NotNull public Trigger getTrigger(MMOLineConfig config) { String key = config.getKey(); - for (LoadedObject trigger : triggers) + for (LoadedCraftingObject trigger : triggers) if (trigger.getId().equalsIgnoreCase(key)) return trigger.load(config); - return null; + throw new IllegalArgumentException("Could not match trigger"); } public List getIngredients() { return ingredients; } - public Set> getConditions() { + public Set> getConditions() { return conditions; } - public Set> getTriggers() { + public Set> getTriggers() { return triggers; } - public void registerIngredient(String id, Function function, ConditionalDisplay display, Predicate check, Function read) { - ingredients.add(0, new IngredientType(id, function, display, check, read)); + /** + * Registers a type of ingredient in MMOItems crafting stations + *

+ * See {@link IngredientType} for more information. + * + * @param id The ingredient id + * @param function Function that loads an ingredient from a line config + * @param display How it displays in the item lore + * @param check Should return true if an item can be handled by this ingredient type + * @param readIngredient After checking if this ingredient type can handle an item, + * method called to provide the corresponding PlayerIngredient + */ + public void registerIngredient(String id, Function function, ConditionalDisplay display, Predicate check, Function readIngredient) { + ingredients.add(0, new IngredientType(id, function, display, check, readIngredient)); } - public void registerCondition(String id, Function function, ConditionalDisplay display) { - conditions.add(new LoadedObject<>(id, function, display)); + /** + * Registers a type of condition in MMOItems crafting stations + * + * @param id Condition ID + * @param function Function that loads a condition from a line conf + * @param display How it displays in the item lore, null if it should not + */ + public void registerCondition(String id, Function function, @Nullable ConditionalDisplay display) { + conditions.add(new LoadedCraftingObject<>(id, function, display)); } + /** + * Registers a type of trigger in MMOItems crafting stations. Unlike + * conditions or ingredients, triggers don't need to be displayed + * in the item lore therefore no 'display' argument is required. + * + * @param id Trigger ID + * @param function Function that loads that type of trigger from a line configuration + */ public void registerTrigger(String id, Function function) { - triggers.add(new LoadedObject<>(id, function, null)); + triggers.add(new LoadedCraftingObject(id, function, null)); } public Collection getAll() { return stations.values(); } - - public static class LoadedObject { - private final String id; - private final Function function; - - private ConditionalDisplay display; - - public LoadedObject(String id, Function function, ConditionalDisplay display) { - this.id = id; - this.function = function; - this.display = display; - } - - public String getId() { - return id; - } - - public void setDisplay(ConditionalDisplay display) { - this.display = display; - } - - public boolean hasDisplay() { - return display != null; - } - - public ConditionalDisplay getDisplay() { - return display; - } - - public C load(MMOLineConfig config) { - return function.apply(config); - } - } - - public static class IngredientType extends LoadedObject { - private final Predicate check; - private final Function read; - - public IngredientType(String id, Function function, ConditionalDisplay display, Predicate check, Function read) { - super(id, function, display); - - this.check = check; - this.read = read; - } - - /* - * returns true if the checked item can be handled by this ingredient - */ - public boolean check(NBTItem item) { - return check.test(item); - } - - /* - * reads the ingredient read from an NBTItem - */ - public String readKey(NBTItem item) { - return read.apply(item); - } - } }