diff --git a/pom.xml b/pom.xml index 21888c00..e745acf1 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 net.Indyuce MMOItems - 5.5.1 + 5.5.2 MMOItems A great item solution for your RPG server. diff --git a/src/main/java/net/Indyuce/mmoitems/MMOItems.java b/src/main/java/net/Indyuce/mmoitems/MMOItems.java index 7c3ab0dd..f8f24814 100644 --- a/src/main/java/net/Indyuce/mmoitems/MMOItems.java +++ b/src/main/java/net/Indyuce/mmoitems/MMOItems.java @@ -10,10 +10,12 @@ import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import net.Indyuce.mmoitems.api.ConfigFile; import net.Indyuce.mmoitems.api.SoulboundInfo; +import net.Indyuce.mmoitems.api.item.MMOItem; import net.Indyuce.mmoitems.api.player.PlayerData; import net.Indyuce.mmoitems.command.MMOItemsCommand; import net.Indyuce.mmoitems.command.UpdateItemCommand; @@ -45,6 +47,7 @@ import net.Indyuce.mmoitems.comp.rpg.DefaultHook; import net.Indyuce.mmoitems.comp.rpg.RPGHandler; import net.Indyuce.mmoitems.gui.PluginInventory; import net.Indyuce.mmoitems.gui.listener.GuiListener; +import net.Indyuce.mmoitems.listener.CraftingListener; import net.Indyuce.mmoitems.listener.CustomBlockListener; import net.Indyuce.mmoitems.listener.CustomSoundListener; import net.Indyuce.mmoitems.listener.DisableInteractions; @@ -155,6 +158,7 @@ public class MMOItems extends JavaPlugin { Bukkit.getPluginManager().registerEvents(new DisableInteractions(), this); Bukkit.getPluginManager().registerEvents(new GuiListener(), this); Bukkit.getPluginManager().registerEvents(new ElementListener(), this); + Bukkit.getPluginManager().registerEvents(new CraftingListener(), this); if (MMOLib.plugin.getVersion().isStrictlyHigher(1, 12)) { Bukkit.getPluginManager().registerEvents(new CustomBlockListener(), this); Bukkit.getPluginManager().registerEvents(new Listener_v1_13(), this); @@ -401,6 +405,45 @@ public class MMOItems extends JavaPlugin { return getConfig().getStringList("block-blacklist").contains(material.name()); } + /*** + * Parses an ItemStack from a string. + * Can be used to both get a vanilla material or + * an MMOItem. Used by the recipe manager. + */ + public ItemStack parseStack(String parse) { + ItemStack stack = null; + String[] split = parse.split("\\:"); + String input = split[0]; + + if (input.contains(".")) { + String[] typeId = input.split("\\."); + String typeFormat = typeId[0].toUpperCase().replace("-", "_").replace(" ", "_"); + Validate.isTrue(getTypes().has(typeFormat), "Could not find type " + typeFormat); + + MMOItem mmo = getItems().getMMOItem(MMOItems.plugin.getTypes().get(typeFormat), typeId[1]); + if(mmo != null) stack = mmo.newBuilder().build(); + } + else { + Material mat = Material.AIR; + try { + mat = Material.valueOf(input.toUpperCase().replace("-", "_").replace(" ", "_")); + } catch (IllegalArgumentException e) { + getLogger().warning("Couldn't parse material from '" + parse + "'!"); + } + + if(mat != Material.AIR) stack = new ItemStack(mat); + } + + try { + if(stack != null && split.length > 1) + stack.setAmount(Integer.parseInt(split[1])); + } catch (NumberFormatException e) { + getLogger().warning("Couldn't parse amount from '" + parse + "'!"); + } + + return stack; + } + public void debug(Object... message) { if (!getConfig().getBoolean("debug")) return; diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/MMORecipeChoice.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/MMORecipeChoice.java index 0a560c74..80fd033d 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/recipe/MMORecipeChoice.java +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/MMORecipeChoice.java @@ -1,93 +1,41 @@ package net.Indyuce.mmoitems.api.recipe; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.lang.Validate; -import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import net.Indyuce.mmoitems.MMOItems; -import net.Indyuce.mmoitems.api.Type; +import net.mmogroup.mmolib.api.item.NBTItem; public class MMORecipeChoice { - private final Material material; - private final int data; - - private final Type type; - private final String id; - - public MMORecipeChoice(Material material, int data) { - this(material, data, null, null); - } - - public MMORecipeChoice(Type type, String id) { - this(null, 0, type, id); - } + private final ItemStack item; + private final int amount; + private final boolean isVanilla; public MMORecipeChoice(String input) { - if (input.contains(".")) { - String[] typeId = input.split("\\."); - String typeFormat = typeId[0].toUpperCase().replace("-", "_").replace(" ", "_"); - Validate.isTrue(MMOItems.plugin.getTypes().has(typeFormat), "Could not find type " + typeFormat); - - type = MMOItems.plugin.getTypes().get(typeFormat); - id = typeId[1]; - - data = 0; - material = null; + item = MMOItems.plugin.parseStack(input); + + if(item != null) { + isVanilla = !NBTItem.get(item).hasType(); + amount = item.getAmount(); } - else { - String[] split = input.split("\\:"); - - material = Material.valueOf(split[0].toUpperCase().replace("-", "_").replace(" ", "_")); - data = split.length > 1 ? Integer.parseInt(split[1]) : 0; - - type = null; - id = null; + amount = 1; + isVanilla = true; } } - private MMORecipeChoice(Material material, int data, Type type, String id) { - this.type = type; - this.id = id; - this.material = material; - this.data = data; + public boolean isValid() { + return item != null; + } + + public boolean isVanilla() { + return isVanilla; } - @SuppressWarnings("deprecation") - public ItemStack generateStack() { - return material != null ? (data > 0 ? new ItemStack(material, 1, (short) data) : new ItemStack(material)) : MMOItems.plugin.getItems().getItem(type, id); + public int getAmount() { + return amount; } - public boolean isAir() { - return material == Material.AIR; - } - - public Material getMaterial() { - return material; - } - - public Type getType() { - return type; - } - - public String getId() { - return id; - } - - public int getMeta() { - return data; - } - - public static List getFromShapedConfig(List list) { - List choices = new ArrayList<>(); - - for (String key : list) - for (String subkey : key.split("\\ ")) - choices.add(new MMORecipeChoice(subkey)); - - return choices; + public ItemStack getItem() { + return item; } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/CachedRecipe.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/CachedRecipe.java new file mode 100644 index 00000000..089f715f --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/CachedRecipe.java @@ -0,0 +1,56 @@ +package net.Indyuce.mmoitems.api.recipe.workbench; + +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.inventory.ItemStack; + +public class CachedRecipe { + private Map amounts = new HashMap<>(); + private ItemStack stack; + + public boolean isValid(ItemStack[] matrix) { + boolean check = true; + for (int i = 0; i < matrix.length; i++) { + if (matrix[i] == null) + continue; + if (matrix[i].getAmount() < amounts.get(i)) + check = false; + if (!check) + break; + } + return check; + } + + public ItemStack[] generateMatrix(ItemStack[] matrix) { + ItemStack[] newMatrix = new ItemStack[9]; + for (int i = 0; i < matrix.length; i++) { + ItemStack stack = matrix[i]; + if (stack == null) { + newMatrix[i] = null; + continue; + } + int amountLeft = stack.getAmount() - amounts.get(i); + if (amountLeft < 1) { + newMatrix[i] = null; + continue; + } + stack.setAmount(amountLeft); + newMatrix[i] = stack; + } + + return newMatrix; + } + + public void add(int slot, int amount) { + amounts.put(slot, amount); + } + + public void setResult(ItemStack result) { + stack = result; + } + + public ItemStack getResult() { + return stack; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/CustomRecipe.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/CustomRecipe.java new file mode 100644 index 00000000..512005c9 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/CustomRecipe.java @@ -0,0 +1,81 @@ +package net.Indyuce.mmoitems.api.recipe.workbench; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import net.Indyuce.mmoitems.MMOItems; +import net.Indyuce.mmoitems.api.recipe.workbench.ingredients.AirIngredient; +import net.Indyuce.mmoitems.api.recipe.workbench.ingredients.WorkbenchIngredient; +import net.mmogroup.mmolib.api.item.NBTItem; + +public class CustomRecipe implements Comparable { + private final boolean shapeless; + private final ItemStack output; + private final Map ingredients = new HashMap<>(9); + + public CustomRecipe(NBTItem output, List recipe, boolean isShapeless) { + this.shapeless = isShapeless; + this.output = output.toItem(); + if (output.hasTag("MMOITEMS_CRAFTED_AMOUNT")) + this.output.setAmount(output.getInteger("MMOITEMS_CRAFTED_AMOUNT")); + + if (shapeless) { + for (int i = 0; i < 9; i++) { + ItemStack stack = MMOItems.plugin.parseStack(recipe.get(i)); + if (stack == null || stack.getType() == Material.AIR) + continue; + ingredients.put(i, WorkbenchIngredient.getAutomatically(stack)); + } + } + else { + for (int i = 0; i < 9; i++) { + List line = Arrays.asList(recipe.get(i / 3).split("\\ ")); + while (line.size() < 3) + line.add("AIR"); + + ItemStack stack = MMOItems.plugin.parseStack(line.get(i % 3)); + if (stack == null || stack.getType() == Material.AIR) + ingredients.put(i, new AirIngredient()); + else ingredients.put(i, WorkbenchIngredient.getAutomatically(stack)); + } + } + } + + public Set> getIngredients() { + return ingredients.entrySet(); + } + + public boolean fitsPlayerCrafting() { + boolean check = true; + for (int value : ingredients.keySet()) + if (value > 3) { + check = false; + break; + } + return check; + } + + public boolean isEmpty() { + return ingredients.isEmpty(); + } + + public boolean isShapeless() { + return shapeless; + } + + public ItemStack getResult() { + return output; + } + + @Override + public int compareTo(CustomRecipe o) { + return Boolean.compare(shapeless, o.shapeless); + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/AirIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/AirIngredient.java new file mode 100644 index 00000000..9ee9b1ea --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/AirIngredient.java @@ -0,0 +1,16 @@ +package net.Indyuce.mmoitems.api.recipe.workbench.ingredients; + +import org.bukkit.inventory.ItemStack; + +public class AirIngredient extends WorkbenchIngredient { + @Override + public boolean matches(ItemStack stack) { + if(stack == null) return true; + else return false; + } + + @Override + public boolean matchStack(ItemStack stack) { + return true; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/MMOIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/MMOIngredient.java new file mode 100644 index 00000000..0659d5b3 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/MMOIngredient.java @@ -0,0 +1,26 @@ +package net.Indyuce.mmoitems.api.recipe.workbench.ingredients; + +import org.bukkit.inventory.ItemStack; + +import net.Indyuce.mmoitems.api.Type; +import net.mmogroup.mmolib.api.item.NBTItem; + +public class MMOIngredient extends WorkbenchIngredient { + private final Type type; + private final String id; + + public MMOIngredient(Type type, String id) { + this.type = type; + this.id = id; + } + + @Override + public boolean matchStack(ItemStack stack) { + NBTItem nbt = NBTItem.get(stack); + if (!nbt.hasType()) + return false; + return nbt.getType().equals(type) && + nbt.getString("MMOITEMS_ITEM_ID").equalsIgnoreCase(id); + } + +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/VanillaIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/VanillaIngredient.java new file mode 100644 index 00000000..894d4951 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/VanillaIngredient.java @@ -0,0 +1,20 @@ +package net.Indyuce.mmoitems.api.recipe.workbench.ingredients; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import net.mmogroup.mmolib.api.item.NBTItem; + +public class VanillaIngredient extends WorkbenchIngredient { + private final Material mat; + + public VanillaIngredient(Material mat) { + this.mat = mat; + } + + @Override + public boolean matchStack(ItemStack stack) { + if(NBTItem.get(stack).hasType()) return false; + return stack.getType() == mat; + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/WorkbenchIngredient.java b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/WorkbenchIngredient.java new file mode 100644 index 00000000..1b39985a --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/recipe/workbench/ingredients/WorkbenchIngredient.java @@ -0,0 +1,34 @@ +package net.Indyuce.mmoitems.api.recipe.workbench.ingredients; + +import org.bukkit.inventory.ItemStack; + +import net.mmogroup.mmolib.api.item.NBTItem; + +public abstract class WorkbenchIngredient { + private int amount; + + public void setAmount(int value) { + amount = value; + } + + public int getAmount() { + return amount; + } + + public static WorkbenchIngredient getAutomatically(ItemStack stack) { + WorkbenchIngredient ingredient; + NBTItem nbt = NBTItem.get(stack); + if(nbt.hasType()) ingredient = new MMOIngredient(nbt.getType(), nbt.getString("MMOITEMS_ITEM_ID")); + else ingredient = new VanillaIngredient(stack.getType()); + ingredient.setAmount(stack.getAmount()); + return ingredient; + } + + public boolean matches(ItemStack stack) { + if(stack == null) return false; + if(stack.getAmount() < amount) return false; + else return matchStack(stack); + } + + public abstract boolean matchStack(ItemStack stack); +} diff --git a/src/main/java/net/Indyuce/mmoitems/command/MMOItemsCommand.java b/src/main/java/net/Indyuce/mmoitems/command/MMOItemsCommand.java index b9c0fb38..ce9ceb56 100644 --- a/src/main/java/net/Indyuce/mmoitems/command/MMOItemsCommand.java +++ b/src/main/java/net/Indyuce/mmoitems/command/MMOItemsCommand.java @@ -522,12 +522,10 @@ public class MMOItemsCommand implements CommandExecutor { * discoverRecipes must be called on the main thread. */ Bukkit.getScheduler().runTask(MMOItems.plugin, () -> { - if (MMOLib.plugin.getVersion().isStrictlyHigher(1, 12) && MMOItems.plugin.getConfig().getBoolean("auto-recipe-book")) - Bukkit.getOnlinePlayers().forEach(online -> online.discoverRecipes(MMOItems.plugin.getRecipes().getNamespacedKeys())); - sender.sendMessage(MMOItems.plugin.getPrefix() + "Successfully reloaded recipes."); sender.sendMessage(MMOItems.plugin.getPrefix() + "- " + ChatColor.RED - + MMOItems.plugin.getRecipes().getLoadedRecipes().size() + ChatColor.GRAY + " Recipes"); + + (MMOItems.plugin.getRecipes().getLoadedRecipes().size() + + MMOItems.plugin.getRecipes().getCustomRecipes().size()) + ChatColor.GRAY + " Recipes"); }); }); } diff --git a/src/main/java/net/Indyuce/mmoitems/gui/edition/RecipeEdition.java b/src/main/java/net/Indyuce/mmoitems/gui/edition/RecipeEdition.java index 30242c6c..f523767f 100644 --- a/src/main/java/net/Indyuce/mmoitems/gui/edition/RecipeEdition.java +++ b/src/main/java/net/Indyuce/mmoitems/gui/edition/RecipeEdition.java @@ -6,6 +6,7 @@ import java.util.List; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryClickEvent; @@ -13,10 +14,10 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.ConfigFile; import net.Indyuce.mmoitems.api.edition.StatEdition; import net.Indyuce.mmoitems.api.item.MMOItem; -import net.Indyuce.mmoitems.api.recipe.MMORecipeChoice; import net.Indyuce.mmoitems.stat.type.ItemStat; import net.mmogroup.mmolib.api.util.AltChar; @@ -56,8 +57,11 @@ public class RecipeEdition extends EditionInventory { while (line.size() < 3) line.add("AIR"); - ItemStack element = new MMORecipeChoice(fixAir(line.get(j % 3))).generateStack(); + ItemStack element = MMOItems.plugin.parseStack(line.get(j % 3)); + if(element == null) element = new ItemStack(Material.BARRIER); + if(element.getType() == Material.AIR) element.setType(Material.BARRIER); ItemMeta elementMeta = element.getItemMeta(); + if(element.getType() == Material.BARRIER) elementMeta.setDisplayName(ChatColor.RED + "Empty"); List elementLore = new ArrayList<>(); elementLore.add(""); elementLore.add(ChatColor.YELLOW + AltChar.listDash + " Click to change this ingredient."); @@ -76,34 +80,35 @@ public class RecipeEdition extends EditionInventory { Inventory inv = Bukkit.createInventory(this, 54, ChatColor.UNDERLINE + "Recipe Editor: " + mmoitem.getId()); ConfigFile config = mmoitem.getType().getConfigFile(); if (!config.getConfig().contains(mmoitem.getId() + ".crafting.shapeless.1")) { - for (int i = 1; i < 10; i++) - config.getConfig().set(mmoitem.getId() + ".crafting.shapeless.1.item" + i, "AIR"); + config.getConfig().set(mmoitem.getId() + ".crafting.shapeless.1", + Arrays.asList("AIR", "AIR", "AIR", "AIR", "AIR", "AIR", "AIR", "AIR", "AIR")); registerItemEdition(config); } - for (int j = 0; j < 9; j++) { - int slot = intToSlot(j); + List ingredients = config.getConfig().getStringList(mmoitem.getId() + ".crafting.shapeless.1"); + if(ingredients.size() == 9) + for (int j = 0; j < 9; j++) { + int slot = intToSlot(j); - ItemStack element = new MMORecipeChoice(fixAir(config.getConfig().getString(mmoitem.getId() + ".crafting.shapeless.1.item" + (j + 1)))) - .generateStack(); - ItemMeta elementMeta = element.getItemMeta(); - List elementLore = new ArrayList<>(); - elementLore.add(""); - elementLore.add(ChatColor.YELLOW + AltChar.listDash + " Click to change this ingredient."); - elementLore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to remove this ingredient."); - elementMeta.setLore(elementLore); - element.setItemMeta(elementMeta); + ItemStack element = MMOItems.plugin.parseStack(ingredients.get(j)); + if(element == null) element = new ItemStack(Material.BARRIER); + if(element.getType() == Material.AIR) element.setType(Material.BARRIER); + ItemMeta elementMeta = element.getItemMeta(); + if(element.getType() == Material.BARRIER) elementMeta.setDisplayName(ChatColor.RED + "Empty"); + List elementLore = new ArrayList<>(); + elementLore.add(""); + elementLore.add(ChatColor.YELLOW + AltChar.listDash + " Click to change this ingredient."); + elementLore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to remove this ingredient."); + elementMeta.setLore(elementLore); + element.setItemMeta(elementMeta); - inv.setItem(slot, element); - } + inv.setItem(slot, element); + } + else MMOItems.plugin.getLogger().warning("Couldn't load shapeless recipe for '" + mmoitem.getId() + "'!"); addEditionInventoryItems(inv, true); return inv; } - private String fixAir(String string) { - return string.equals("AIR") ? "BARRIER" : string; - } - private int intToSlot(int i) { return i >= 0 && i <= 2 ? 21 + i : (i >= 3 && i <= 5 ? 27 + i : (i >= 6 && i <= 8 ? 33 + i : 0)); } @@ -122,7 +127,7 @@ public class RecipeEdition extends EditionInventory { if (event.getAction() == InventoryAction.PICKUP_ALL) { if (slotToInt(event.getRawSlot()) >= 0) new StatEdition(this, ItemStat.CRAFTING, "recipe", (shapeless ? "shapeless" : "shaped"), slotToInt(event.getRawSlot())) - .enable("Write in the chat the item you want.", "Format: '[MATERIAL]' or '[MATERIAL]:[DURABILITY]' or '[TYPE].[ID]'"); + .enable("Write in the chat the item you want.", "Format: '[MATERIAL]' or '[TYPE].[ID]'"); } else if (event.getAction() == InventoryAction.PICKUP_HALF) { if (shapeless) @@ -146,8 +151,12 @@ public class RecipeEdition extends EditionInventory { private void deleteShapeless(int slot) { ConfigFile config = mmoitem.getType().getConfigFile(); - config.getConfig().set(mmoitem.getId() + ".crafting.shapeless.1.item" + (slot + 1), "AIR"); - registerItemEdition(config); - open(); + if(config.getConfig().contains(mmoitem.getId() + ".crafting.shapeless.1")) { + List newList = config.getConfig().getStringList(mmoitem.getId() + ".crafting.shapeless.1"); + newList.set(slot, "AIR"); + config.getConfig().set(mmoitem.getId() + ".crafting.shapeless.1", newList); + registerItemEdition(config); + open(); + } } } \ No newline at end of file diff --git a/src/main/java/net/Indyuce/mmoitems/listener/CraftingListener.java b/src/main/java/net/Indyuce/mmoitems/listener/CraftingListener.java new file mode 100644 index 00000000..9debae82 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/listener/CraftingListener.java @@ -0,0 +1,140 @@ +package net.Indyuce.mmoitems.listener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryAction; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType.SlotType; +import org.bukkit.event.inventory.PrepareItemCraftEvent; +import org.bukkit.inventory.CraftingInventory; +import org.bukkit.inventory.ItemStack; + +import net.Indyuce.mmoitems.MMOItems; +import net.Indyuce.mmoitems.api.recipe.workbench.CachedRecipe; +import net.Indyuce.mmoitems.api.recipe.workbench.CustomRecipe; +import net.Indyuce.mmoitems.api.recipe.workbench.ingredients.WorkbenchIngredient; + +public class CraftingListener implements Listener { + Map cachedRecipe = new HashMap<>(); + + @EventHandler + public void calculateCrafting(PrepareItemCraftEvent e) { + if (!(e.getView().getPlayer() instanceof Player)) + return; + handleCustomCrafting(e.getInventory(), (Player) e.getView().getPlayer()); + } + + @EventHandler + public void getResult(InventoryClickEvent e) { + if (!(e.getView().getPlayer() instanceof Player)) return; + if (!(e.getInventory() instanceof CraftingInventory)) return; + if (e.getSlotType() == SlotType.CRAFTING && e.getAction() == InventoryAction.PLACE_ONE) + Bukkit.getScheduler().runTaskLater(MMOItems.plugin, new Runnable() { + @Override + public void run() { + handleCustomCrafting((CraftingInventory) e.getInventory(), (Player) e.getView().getPlayer()); + } + }, 1); + else if (e.getSlotType() == SlotType.RESULT) { + CraftingInventory inv = (CraftingInventory) e.getInventory(); + if (e.getCurrentItem() == null || !cachedRecipe.containsKey(e.getWhoClicked().getUniqueId())) + return; + if (e.getClick() != ClickType.LEFT) { + e.setCancelled(true); + return; + } + CachedRecipe cached = cachedRecipe.get(e.getWhoClicked().getUniqueId()); + cachedRecipe.remove(e.getWhoClicked().getUniqueId()); + if (!cached.isValid(inv.getMatrix())) { + e.setCancelled(true); + return; + } + ItemStack[] newMatrix = cached.generateMatrix(inv.getMatrix()); + inv.setMatrix(new ItemStack[] { null, null, null, null, null, null, null, null, null }); + Bukkit.getScheduler().runTaskLater(MMOItems.plugin, new Runnable() { + @Override + public void run() { + boolean check = true; + for (ItemStack stack : newMatrix) + if (stack != null) + check = false; + if (check) { + inv.setMatrix(new ItemStack[] { null, null, null, null, null, null, null, null, null }); + ((Player) e.getView().getPlayer()).updateInventory(); + } else + inv.setMatrix(newMatrix); + } + }, 1); + e.setCurrentItem(cached.getResult()); + } + } + + public void handleCustomCrafting(CraftingInventory inv, Player player) { + player.updateInventory(); + cachedRecipe.remove(player.getUniqueId()); + for (CustomRecipe recipe : MMOItems.plugin.getRecipes().getCustomRecipes()) { + if (!recipe.fitsPlayerCrafting() && inv.getMatrix().length == 4) + continue; + + CachedRecipe cached = new CachedRecipe(); + boolean matches = true; + List slotsChecked = new ArrayList<>(); + for (Entry ingredients : recipe.getIngredients()) { + if (recipe.isShapeless()) { + boolean check = false; + int nonnullcount = 0; + for (int i = 0; i < inv.getMatrix().length; i++) { + if (slotsChecked.contains(i)) + continue; + ItemStack item = inv.getMatrix()[i]; + if (item == null) { + slotsChecked.add(i); + continue; + } + nonnullcount += 1; + if (ingredients.getValue().matches(item)) { + cached.add(i, ingredients.getValue().getAmount()); + slotsChecked.add(i); + check = true; + } + if (nonnullcount > recipe.getIngredients().size()) { + check = false; + break; + } + } + if (!check) + matches = false; + } else { + if (!ingredients.getValue().matches(inv.getMatrix()[ingredients.getKey()])) + matches = false; + else cached.add(ingredients.getKey(), ingredients.getValue().getAmount()); + } + + if (!matches) break; + } + + if (matches) { + cached.setResult(recipe.getResult()); + cachedRecipe.put(player.getUniqueId(), cached); + inv.setResult(recipe.getResult()); + Bukkit.getScheduler().runTaskLater(MMOItems.plugin, new Runnable() { + @Override + public void run() { + inv.setItem(0, recipe.getResult()); + } + }, 1); + break; + } + } + } +} diff --git a/src/main/java/net/Indyuce/mmoitems/listener/version/Listener_v1_13.java b/src/main/java/net/Indyuce/mmoitems/listener/version/Listener_v1_13.java index 237d310b..19a4eddb 100644 --- a/src/main/java/net/Indyuce/mmoitems/listener/version/Listener_v1_13.java +++ b/src/main/java/net/Indyuce/mmoitems/listener/version/Listener_v1_13.java @@ -4,10 +4,8 @@ import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.entity.Trident; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.ProjectileLaunchEvent; -import org.bukkit.event.player.PlayerJoinEvent; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.Type; @@ -18,8 +16,6 @@ import net.mmogroup.mmolib.MMOLib; import net.mmogroup.mmolib.api.item.NBTItem; public class Listener_v1_13 implements Listener { - private final boolean autoRecipeBook = MMOItems.plugin.getConfig().getBoolean("auto-recipe-book"); - @EventHandler public void a(ProjectileLaunchEvent event) { if (!(event.getEntity() instanceof Trident) || !(event.getEntity().getShooter() instanceof Player)) @@ -41,10 +37,4 @@ public class Listener_v1_13 implements Listener { MMOItems.plugin.getEntities().registerCustomProjectile(nbtItem, playerData.getStats().newTemporary(), (Trident) event.getEntity(), type != null); } - - @EventHandler(priority = EventPriority.LOW) - public void b(PlayerJoinEvent event) { - if (autoRecipeBook) - event.getPlayer().discoverRecipes(MMOItems.plugin.getRecipes().getNamespacedKeys()); - } } diff --git a/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManager.java b/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManager.java index 6c2d8c5f..e953aadf 100644 --- a/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManager.java +++ b/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManager.java @@ -1,5 +1,6 @@ package net.Indyuce.mmoitems.manager.recipe; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -10,58 +11,55 @@ import org.bukkit.Bukkit; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.recipe.MMORecipeChoice; +import net.Indyuce.mmoitems.api.recipe.workbench.CustomRecipe; public abstract class RecipeManager { - - /** - * TODO When Bukkit changes their 'RecipeChoice.ExactChoice' API we can - * remove the suppressed warnings, but right now it works despite being - * marked as deprecated. It is just a - */ + private final Set craftingRecipes = new HashSet<>(); private final Set loadedRecipes = new HashSet<>(); public abstract void reload(); public abstract void registerFurnaceRecipe(Type type, String id, BurningRecipeInformation info, String number); - - public abstract void registerShapelessRecipe(Type type, String id, ConfigurationSection config, String number); - - public abstract void shapedIngredient(ShapedRecipe recipe, char slot, MMORecipeChoice choice); - - public abstract void registerShapedRecipe(Type type, String id, List list, String number); - - public abstract void shapelessIngredient(ShapelessRecipe recipe, MMORecipeChoice choice); - - /** - * This method is purely for easily converting the AWB recipes. - * - * @deprecated Some day I want to get proper rid of the AWB but right now we - * don't want to force players to update their recipes right off - * the bat. - */ - @Deprecated - public abstract void setIngredientOrAir(ShapedRecipe recipe, char character, ConfigurationSection c); + public abstract void registerShapedRecipe(Type type, String id, List list); + public abstract void registerShapelessRecipe(Type type, String id, List ingredients); public void registerRecipe(NamespacedKey key, Recipe recipe) { loadedRecipes.add(new LoadedRecipe(key, recipe)); } + public void registerRecipe(CustomRecipe recipe) { + if(!recipe.isEmpty()) + craftingRecipes.add(recipe); + } + public Set getLoadedRecipes() { return loadedRecipes; } + + public Set getCustomRecipes() { + return craftingRecipes; + } public Set getNamespacedKeys() { return loadedRecipes.stream().map(recipe -> recipe.getKey()).collect(Collectors.toSet()); } + public void sortRecipes() { + List temporary = new ArrayList<>(); + temporary.addAll(craftingRecipes); + craftingRecipes.clear(); + craftingRecipes.addAll(temporary.stream().sorted().collect(Collectors.toList())); + } + + public void clearCustomRecipes() { + craftingRecipes.clear(); + } + public NamespacedKey getRecipeKey(Type type, String id, String recipeType, String number) { return new NamespacedKey(MMOItems.plugin, recipeType + "_" + type.getId() + "_" + id + "_" + number); } @@ -81,28 +79,6 @@ public abstract class RecipeManager { }); } - /** - * @deprecated Some day I want to get proper rid of the AWB but right now we - * don't want to force players to update their recipes right off - * the bat. - */ - public void registerAdvancedWorkbenchRecipe(Type type, String id, FileConfiguration config) { - MMOItems.plugin.getLogger().warning("Found deprecated adv. recipe for " + id + ". Converting it to the new system..."); - MMOItems.plugin.getLogger().warning("It is recommended to update your recipes!"); - - NamespacedKey key = getRecipeKey(type, id, "advanced", "deprecated"); - ShapedRecipe recipe = new ShapedRecipe(key, MMOItems.plugin.getItems().getItem(type, id)); - recipe.shape("012", "345", "678"); - - for (int j = 0; j < 9; j++) { - ConfigurationSection section = config.getConfigurationSection(id + ".advanced-craft." + j); - if (section != null) - setIngredientOrAir(recipe, ("" + j).charAt(0), section); - } - - registerRecipe(key, recipe); - } - /* * used because spigot API does not let us access namespaced key of a Recipe * instance. @@ -120,7 +96,7 @@ public abstract class RecipeManager { return key; } - public Recipe toBukkit() { + public Recipe getRecipe() { return recipe; } } diff --git a/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerDefault.java b/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerDefault.java index b6e834e5..23df1189 100644 --- a/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerDefault.java +++ b/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerDefault.java @@ -3,53 +3,44 @@ package net.Indyuce.mmoitems.manager.recipe; import java.util.List; import java.util.logging.Level; -import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.inventory.BlastingRecipe; import org.bukkit.inventory.CampfireRecipe; import org.bukkit.inventory.FurnaceRecipe; -import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.RecipeChoice; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.SmokingRecipe; -import org.bukkit.inventory.meta.ItemMeta; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.Type; import net.Indyuce.mmoitems.api.recipe.MMORecipeChoice; -import net.asangarin.hexcolors.ColorParse; +import net.Indyuce.mmoitems.api.recipe.workbench.CustomRecipe; public class RecipeManagerDefault extends RecipeManager { - public RecipeManagerDefault() { reload(); } @Override - @SuppressWarnings("deprecation") public void reload() { + clearCustomRecipes(); + for (Type type : MMOItems.plugin.getTypes().getAll()) { FileConfiguration config = type.getConfigFile().getConfig(); for (String id : config.getKeys(false)) try { - if (config.getConfigurationSection(id).contains("advanced-craft")) - registerAdvancedWorkbenchRecipe(type, id, config); - if (config.getConfigurationSection(id).contains("crafting")) { ConfigurationSection section = config.getConfigurationSection(id + ".crafting"); if (section.contains("shaped")) section.getConfigurationSection("shaped").getKeys(false) - .forEach(recipe -> registerShapedRecipe(type, id, section.getStringList("shaped." + recipe), recipe)); + .forEach(recipe -> registerShapedRecipe(type, id, section.getStringList("shaped." + recipe))); if (section.contains("shapeless")) section.getConfigurationSection("shapeless").getKeys(false).forEach( - recipe -> registerShapelessRecipe(type, id, section.getConfigurationSection("shapeless." + recipe), recipe)); + recipe -> registerShapelessRecipe(type, id, section.getStringList("shapeless." + recipe))); if (section.contains("furnace")) section.getConfigurationSection("furnace").getKeys(false).forEach(recipe -> registerFurnaceRecipe(type, id, new BurningRecipeInformation(section.getConfigurationSection("furnace." + recipe)), recipe)); @@ -68,16 +59,17 @@ public class RecipeManagerDefault extends RecipeManager { } } - // registerCampfireRecipe(MMOItems.plugin.getItems().getItem(Type.SWORD, - // "SILVER_SWORD"), new - // RecipeChoice.ExactChoice(MMOItems.plugin.getItems().getItem(Type.get("MATERIAL"), - // "SILVER_INGOT"))); - - Bukkit.getScheduler().runTask(MMOItems.plugin, () -> getLoadedRecipes().forEach(recipe -> Bukkit.addRecipe(recipe.toBukkit()))); + sortRecipes(); + Bukkit.getScheduler().runTask(MMOItems.plugin, + () -> getLoadedRecipes().forEach(recipe -> Bukkit.addRecipe(recipe.getRecipe()))); } @Override public void registerFurnaceRecipe(Type type, String id, BurningRecipeInformation info, String number) { + if(!info.getChoice().isValid()) { + MMOItems.plugin.getLogger().warning("Couldn't load furnace recipe for '" + type.getId() + "." + id + "'"); + return; + } NamespacedKey key = getRecipeKey(type, id, "furnace", number); FurnaceRecipe recipe = new FurnaceRecipe(key, MMOItems.plugin.getItems().getItem(type, id), toBukkit(info.getChoice()), info.getExp(), info.getBurnTime()); @@ -85,6 +77,10 @@ public class RecipeManagerDefault extends RecipeManager { } public void registerBlastRecipe(Type type, String id, BurningRecipeInformation info, String number) { + if(!info.getChoice().isValid()) { + MMOItems.plugin.getLogger().warning("Couldn't load blast furnace recipe for '" + type.getId() + "." + id + "'"); + return; + } NamespacedKey key = getRecipeKey(type, id, "blast", number); BlastingRecipe recipe = new BlastingRecipe(key, MMOItems.plugin.getItems().getItem(type, id), toBukkit(info.getChoice()), info.getExp(), info.getBurnTime()); @@ -92,6 +88,10 @@ public class RecipeManagerDefault extends RecipeManager { } public void registerSmokerRecipe(Type type, String id, BurningRecipeInformation info, String number) { + if(!info.getChoice().isValid()) { + MMOItems.plugin.getLogger().warning("Couldn't load smoker recipe for '" + type.getId() + "." + id + "'"); + return; + } NamespacedKey key = getRecipeKey(type, id, "smoker", number); SmokingRecipe recipe = new SmokingRecipe(key, MMOItems.plugin.getItems().getItem(type, id), toBukkit(info.getChoice()), info.getExp(), info.getBurnTime()); @@ -99,6 +99,10 @@ public class RecipeManagerDefault extends RecipeManager { } public void registerCampfireRecipe(Type type, String id, BurningRecipeInformation info, String number) { + if(!info.getChoice().isValid()) { + MMOItems.plugin.getLogger().warning("Couldn't load campfire recipe for '" + type.getId() + "." + id + "'"); + return; + } NamespacedKey key = getRecipeKey(type, id, "campfire", number); CampfireRecipe recipe = new CampfireRecipe(key, MMOItems.plugin.getItems().getItem(type, id), toBukkit(info.getChoice()), info.getExp(), info.getBurnTime()); @@ -106,94 +110,23 @@ public class RecipeManagerDefault extends RecipeManager { } @Override - public void registerShapedRecipe(Type type, String id, List list, String number) { - NamespacedKey key = getRecipeKey(type, id, "shaped", number); - ShapedRecipe recipe = new ShapedRecipe(key, MMOItems.plugin.getItems().getItem(type, id)); - - List choices = MMORecipeChoice.getFromShapedConfig(list); - if (choices.isEmpty()) - return; - - recipe.shape("ABC", "DEF", "GHI"); - - shapedIngredient(recipe, 'A', choices.get(0)); - shapedIngredient(recipe, 'B', choices.get(1)); - shapedIngredient(recipe, 'C', choices.get(2)); - shapedIngredient(recipe, 'D', choices.get(3)); - shapedIngredient(recipe, 'E', choices.get(4)); - shapedIngredient(recipe, 'F', choices.get(5)); - shapedIngredient(recipe, 'G', choices.get(6)); - shapedIngredient(recipe, 'H', choices.get(7)); - shapedIngredient(recipe, 'I', choices.get(8)); - - registerRecipe(key, recipe); + public void registerShapedRecipe(Type type, String id, List list) { + registerRecipe(new CustomRecipe(MMOItems.plugin.getItems().getMMOItem(type, id).newBuilder().buildNBT(), list, false)); } @Override - public void shapedIngredient(ShapedRecipe recipe, char slot, MMORecipeChoice choice) { - if (choice.isAir()) - recipe.setIngredient(slot, Material.AIR); - else - recipe.setIngredient(slot, toBukkit(choice)); - } - - @Override - public void registerShapelessRecipe(Type type, String id, ConfigurationSection config, String number) { - NamespacedKey key = getRecipeKey(type, id, "shapeless", number); - ShapelessRecipe recipe = new ShapelessRecipe(key, MMOItems.plugin.getItems().getItem(type, id)); - - for (int i = 1; i < 10; i++) - if (config.contains("item" + i)) - shapelessIngredient(recipe, new MMORecipeChoice(config.getString("item" + i))); - - if (!recipe.getIngredientList().isEmpty()) - registerRecipe(key, recipe); - } - - @Override - public void shapelessIngredient(ShapelessRecipe recipe, MMORecipeChoice choice) { - if (!choice.isAir()) - recipe.addIngredient(toBukkit(choice)); - } - - @Override - @SuppressWarnings("deprecation") - public void setIngredientOrAir(ShapedRecipe recipe, char character, ConfigurationSection config) { - if (config.contains("type")) { - String typeFormat = config.getString("type").toUpperCase().replace("-", "_").replace(" ", "_"); - Validate.notNull(MMOItems.plugin.getTypes().has(typeFormat), "Could not find item type"); - - String id = config.getString("id"); - Validate.notNull(id, "Could not find item ID"); - - ItemStack item = MMOItems.plugin.getItems().getItem(MMOItems.plugin.getTypes().get(typeFormat), id); - Validate.isTrue(item != null, "Could not load item with ID: " + id); - - item.setAmount(config.getInt("amount", 1)); - recipe.setIngredient(character, item.getType()); - - } else if (config.contains("material")) { - Material material = Material.valueOf(config.getString("material").toUpperCase().replace("-", "_").replace(" ", "_")); - int amount = config.getInt("amount", 1); - String name = config.getString("name", ""); - if (amount == 1) - recipe.setIngredient(character, material); - else { - ItemStack item = new ItemStack(material); - item.setAmount(amount); - if (!name.isEmpty()) { - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(new ColorParse('&', name).toChatColor()); - item.setItemMeta(meta); - } - recipe.setIngredient(character, new RecipeChoice.ExactChoice(item)); - } - } + public void registerShapelessRecipe(Type type, String id, List list) { + registerRecipe(new CustomRecipe(MMOItems.plugin.getItems().getMMOItem(type, id).newBuilder().buildNBT(), list, true)); } + /* + * TODO When Bukkit changes their 'RecipeChoice.ExactChoice' API we can + * remove the suppressed warnings, but right now it works despite being + * marked as deprecated. It is just draft API and probably subject to change. + */ @SuppressWarnings("deprecation") public RecipeChoice toBukkit(MMORecipeChoice choice) { - return choice.getMaterial() != null ? new RecipeChoice.MaterialChoice(choice.getMaterial()) - : new RecipeChoice.ExactChoice(MMOItems.plugin.getItems().getItem(choice.getType(), choice.getId())); + return choice.isVanilla() ? new RecipeChoice.MaterialChoice(choice.getItem().getType()) + : new RecipeChoice.ExactChoice(choice.getItem()); } } diff --git a/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerLegacy.java b/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerLegacy.java index 1b3b2dad..f053c2f6 100644 --- a/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerLegacy.java +++ b/src/main/java/net/Indyuce/mmoitems/manager/recipe/RecipeManagerLegacy.java @@ -3,144 +3,75 @@ package net.Indyuce.mmoitems.manager.recipe; import java.util.List; import java.util.logging.Level; -import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.inventory.FurnaceRecipe; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.Type; -import net.Indyuce.mmoitems.api.recipe.MMORecipeChoice; +import net.Indyuce.mmoitems.api.recipe.workbench.CustomRecipe; -/** One day I'll get rid of 1.12 for real >:) */ +/** One day we'll get rid of 1.12 for real >:) */ public class RecipeManagerLegacy extends RecipeManager { - public RecipeManagerLegacy() { reload(); } @Override - @SuppressWarnings("deprecation") public void reload() { + clearCustomRecipes(); + for (Type type : MMOItems.plugin.getTypes().getAll()) { FileConfiguration config = type.getConfigFile().getConfig(); for (String id : config.getKeys(false)) try { - if (config.getConfigurationSection(id).contains("advanced-craft")) - registerAdvancedWorkbenchRecipe(type, id, config); - if (config.getConfigurationSection(id).contains("crafting")) { ConfigurationSection section = config.getConfigurationSection(id + ".crafting"); if (section.contains("shaped")) section.getConfigurationSection("shaped").getKeys(false) - .forEach(recipe -> registerShapedRecipe(type, id, section.getStringList("shaped." + recipe), recipe)); + .forEach(recipe -> registerShapedRecipe(type, id, section.getStringList("shaped." + recipe))); if (section.contains("shapeless")) - section.getConfigurationSection("shapeless").getKeys(false).forEach( - recipe -> registerShapelessRecipe(type, id, section.getConfigurationSection("shapeless." + recipe), recipe)); + section.getConfigurationSection("shapeless").getKeys(false) + .forEach(recipe -> registerShapelessRecipe(type, id, section.getStringList("shapeless." + recipe))); if (section.contains("furnace")) - section.getConfigurationSection("furnace").getKeys(false).forEach(recipe -> registerFurnaceRecipe(type, id, - new BurningRecipeInformation(section.getConfigurationSection("furnace." + recipe)), recipe)); + section.getConfigurationSection("furnace").getKeys(false) + .forEach(recipe -> registerFurnaceRecipe(type, id, + new BurningRecipeInformation(section.getConfigurationSection("furnace." + recipe)), recipe)); } } catch (IllegalArgumentException exception) { - MMOItems.plugin.getLogger().log(Level.WARNING, "Could not load recipe of " + id + ": " + exception.getMessage()); + MMOItems.plugin.getLogger().log(Level.WARNING, + "Could not load recipe of " + id + ": " + exception.getMessage()); } } - // registerCampfireRecipe(MMOItems.plugin.getItems().getItem(Type.SWORD, - // "SILVER_SWORD"), new - // RecipeChoice.ExactChoice(MMOItems.plugin.getItems().getItem(Type.get("MATERIAL"), - // "SILVER_INGOT"))); - - Bukkit.getScheduler().runTask(MMOItems.plugin, () -> - - getLoadedRecipes().forEach(recipe -> Bukkit.addRecipe(recipe.toBukkit()))); + sortRecipes(); + Bukkit.getScheduler().runTask(MMOItems.plugin, + () -> getLoadedRecipes().forEach(recipe -> Bukkit.addRecipe(recipe.getRecipe()))); } @Override public void registerFurnaceRecipe(Type type, String id, BurningRecipeInformation info, String number) { - NamespacedKey key = getRecipeKey(type, id, "furnace", number); - FurnaceRecipe recipe = new FurnaceRecipe(key, MMOItems.plugin.getItems().getItem(type, id), info.getChoice().getMaterial(), info.getExp(), - info.getBurnTime()); - registerRecipe(key, recipe); - } - - @Override - public void registerShapedRecipe(Type type, String id, List list, String number) { - NamespacedKey key = getRecipeKey(type, id, "shaped", number); - ShapedRecipe recipe = new ShapedRecipe(key, MMOItems.plugin.getItems().getItem(type, id)); - - List rcList = MMORecipeChoice.getFromShapedConfig(list); - if (rcList == null) + if (!info.getChoice().isValid()) { + MMOItems.plugin.getLogger().warning("Couldn't load furnace recipe for '" + type.getId() + "." + id + "'"); return; - - recipe.shape("ABC", "DEF", "GHI"); - - shapedIngredient(recipe, 'A', rcList.get(0)); - shapedIngredient(recipe, 'B', rcList.get(1)); - shapedIngredient(recipe, 'C', rcList.get(2)); - shapedIngredient(recipe, 'D', rcList.get(3)); - shapedIngredient(recipe, 'E', rcList.get(4)); - shapedIngredient(recipe, 'F', rcList.get(5)); - shapedIngredient(recipe, 'G', rcList.get(6)); - shapedIngredient(recipe, 'H', rcList.get(7)); - shapedIngredient(recipe, 'I', rcList.get(8)); - + } + NamespacedKey key = getRecipeKey(type, id, "furnace", number); + FurnaceRecipe recipe = new FurnaceRecipe(key, MMOItems.plugin.getItems().getItem(type, id), + info.getChoice().getItem().getType(), info.getExp(), info.getBurnTime()); registerRecipe(key, recipe); } @Override - public void shapedIngredient(ShapedRecipe recipe, char c, MMORecipeChoice rc) { - if (rc.isAir()) - recipe.setIngredient(c, Material.AIR); - else - recipe.setIngredient(c, rc.generateStack().getType()); + public void registerShapedRecipe(Type type, String id, List list) { + registerRecipe(new CustomRecipe(MMOItems.plugin.getItems().getMMOItem(type, id).newBuilder().buildNBT(), list, false)); } @Override - public void registerShapelessRecipe(Type type, String id, ConfigurationSection config, String number) { - NamespacedKey key = getRecipeKey(type, id, "shapeless", number); - ShapelessRecipe recipe = new ShapelessRecipe(key, MMOItems.plugin.getItems().getItem(type, id)); - - for (int i = 1; i < 10; i++) - if (config.contains("item" + i)) - shapelessIngredient(recipe, new MMORecipeChoice(config.getString("item" + i))); - - if (!recipe.getIngredientList().isEmpty()) - registerRecipe(key, recipe); - } - - @Override - public void shapelessIngredient(ShapelessRecipe recipe, MMORecipeChoice rc) { - if (!rc.isAir()) - recipe.addIngredient(rc.getMaterial()); - } - - @Override - public void setIngredientOrAir(ShapedRecipe recipe, char character, ConfigurationSection config) { - if (config.contains("type")) { - String typeFormat = config.getString("type").toUpperCase().replace("-", "_").replace(" ", "_"); - Validate.notNull(MMOItems.plugin.getTypes().has(typeFormat), "Could not find item type"); - - String id = config.getString("id"); - Validate.notNull(id, "Could not find item ID"); - - ItemStack item = MMOItems.plugin.getItems().getItem(MMOItems.plugin.getTypes().get(typeFormat), id); - Validate.isTrue(item != null, "Could not load item with ID: " + id); - - item.setAmount(config.getInt("amount", 1)); - recipe.setIngredient(character, item.getType()); - - } else if (config.contains("material")) { - Material material = Material.valueOf(config.getString("material").toUpperCase().replace("-", "_").replace(" ", "_")); - recipe.setIngredient(character, material); - } + public void registerShapelessRecipe(Type type, String id, List list) { + registerRecipe(new CustomRecipe(MMOItems.plugin.getItems().getMMOItem(type, id).newBuilder().buildNBT(), list, true)); } } diff --git a/src/main/java/net/Indyuce/mmoitems/stat/Crafting.java b/src/main/java/net/Indyuce/mmoitems/stat/Crafting.java index 9aa164ae..139c26a6 100644 --- a/src/main/java/net/Indyuce/mmoitems/stat/Crafting.java +++ b/src/main/java/net/Indyuce/mmoitems/stat/Crafting.java @@ -71,7 +71,9 @@ public class Crafting extends ItemStat { config.getConfig().set(inv.getEdited().getId() + ".crafting.shaped.1", newList); inv.registerItemEdition(config); } else { - config.getConfig().set(inv.getEdited().getId() + ".crafting.shapeless.1.item" + (slot + 1), message); + List newList = config.getConfig().getStringList(inv.getEdited().getId() + ".crafting.shapeless.1"); + newList.set(slot, message); + config.getConfig().set(inv.getEdited().getId() + ".crafting.shapeless.1", newList); inv.registerItemEdition(config); } } @@ -128,6 +130,23 @@ public class Crafting extends ItemStat { } private boolean validate(Player player, String input) { + if (input.contains(":")) { + String[] count = input.split("\\:"); + + if (count.length != 2) { + player.sendMessage(MMOItems.plugin.getPrefix() + "Invalid format."); + return false; + } + + try { + Integer.parseInt(count[1]); + } catch (NumberFormatException exception) { + player.sendMessage(MMOItems.plugin.getPrefix() + "'" + count[1] + "' isn't a valid number."); + return false; + } + + input = count[0]; + } if (input.contains(".")) { String[] typeid = input.split("\\."); if (typeid.length != 2) { @@ -149,27 +168,6 @@ public class Crafting extends ItemStat { return true; } - if (input.contains(":")) { - String[] matmeta = input.split("\\:"); - if (matmeta.length != 2) { - player.sendMessage(MMOItems.plugin.getPrefix() + "Invalid format."); - return false; - } - try { - Material.valueOf(matmeta[0].toUpperCase().replace("-", "_")); - } catch (IllegalArgumentException exception) { - player.sendMessage(MMOItems.plugin.getPrefix() + "'" + matmeta[0].toUpperCase().replace("-", "_") + "' isn't a valid material."); - return false; - } - try { - Integer.parseInt(matmeta[1]); - } catch (NumberFormatException exception) { - player.sendMessage(MMOItems.plugin.getPrefix() + "'" + matmeta[1] + "' isn't a valid number."); - return false; - } - - return true; - } try { Material.valueOf(input.toUpperCase().replace("-", "_")); } catch (Exception e) { diff --git a/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java b/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java index c70236b0..a78866b6 100644 --- a/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java +++ b/src/main/java/net/Indyuce/mmoitems/stat/type/ItemStat.java @@ -77,177 +77,227 @@ import net.mmogroup.mmolib.version.VersionMaterial; public abstract class ItemStat { public static final ItemStat MATERIAL = new MaterialStat(), - DURABILITY = MMOLib.plugin.getVersion().isBelowOrEqual(1, 12) ? new LegacyDurability() : new DefaultDurability(), - CUSTOM_MODEL_DATA = new CustomModelData(), MAX_DURABILITY = new MaximumDurability(), WILL_BREAK = new LostWhenBroken(); + DURABILITY = MMOLib.plugin.getVersion().isBelowOrEqual(1, 12) ? new LegacyDurability() + : new DefaultDurability(), + CUSTOM_MODEL_DATA = new CustomModelData(), MAX_DURABILITY = new MaximumDurability(), + WILL_BREAK = new LostWhenBroken(); public static final ItemStat NAME = new DisplayName(), LORE = new Lore(), NBT_TAGS = new NBTTags(); - public static final ItemStat DISPLAYED_TYPE = new StringStat("DISPLAYED_TYPE", VersionMaterial.OAK_SIGN.toItem(), "Displayed Type", - new String[] { "This option will only affect the", "type displayed on the item lore." }, new String[] { "all" }); - public static final ItemStat ENCHANTS = new Enchants(), HIDE_ENCHANTS = new HideEnchants(), PERMISSION = new Permission(), - ITEM_PARTICLES = new ItemParticles(), ARROW_PARTICLES = new ArrowParticles(); - public static final ItemStat DISABLE_INTERACTION = new DisableStat("INTERACTION", VersionMaterial.GRASS_BLOCK.toMaterial(), "Disable Interaction", - "Disable any unwanted interaction:", "block placement, item use..."); - public static final ItemStat DISABLE_CRAFTING = new DisableStat("CRAFTING", VersionMaterial.CRAFTING_TABLE.toMaterial(), "Disable Crafting", + public static final ItemStat DISPLAYED_TYPE = new StringStat("DISPLAYED_TYPE", VersionMaterial.OAK_SIGN.toItem(), + "Displayed Type", new String[] { "This option will only affect the", "type displayed on the item lore." }, + new String[] { "all" }); + public static final ItemStat ENCHANTS = new Enchants(), HIDE_ENCHANTS = new HideEnchants(), + PERMISSION = new Permission(), ITEM_PARTICLES = new ItemParticles(), ARROW_PARTICLES = new ArrowParticles(); + public static final ItemStat DISABLE_INTERACTION = new DisableStat("INTERACTION", + VersionMaterial.GRASS_BLOCK.toMaterial(), "Disable Interaction", "Disable any unwanted interaction:", + "block placement, item use..."); + public static final ItemStat DISABLE_CRAFTING = new DisableStat("CRAFTING", + VersionMaterial.CRAFTING_TABLE.toMaterial(), "Disable Crafting", "Players can't use this item while crafting."); - public static final ItemStat DISABLE_SMELTING = new DisableStat("SMELTING", Material.FURNACE, "Disable Smelting", - "Players can't use this item in furnaces."); - public static final ItemStat DISABLE_SMITHING = new DisableStat("SMITHING", Material.DAMAGED_ANVIL, "Disable Smithing", - "Players can't smith this item in smithing tables."); - public static final ItemStat DISABLE_ENCHANTING = new DisableStat("ENCHANTING", VersionMaterial.ENCHANTING_TABLE.toMaterial(), - "Disable Enchanting", "Players can't enchant this item."), DISABLE_ADVANCED_ENCHANTS = new DisableAdvancedEnchantments(); + public static final ItemStat DISABLE_SMELTING = new DisableStat("SMELTING", Material.FURNACE, "Disable Smelting", + "Players can't use this item in furnaces."); + public static final ItemStat DISABLE_SMITHING = new DisableStat("SMITHING", Material.DAMAGED_ANVIL, + "Disable Smithing", "Players can't smith this item in smithing tables."); + public static final ItemStat DISABLE_ENCHANTING = new DisableStat("ENCHANTING", + VersionMaterial.ENCHANTING_TABLE.toMaterial(), "Disable Enchanting", "Players can't enchant this item."), + DISABLE_ADVANCED_ENCHANTS = new DisableAdvancedEnchantments(); public static final ItemStat DISABLE_REPAIRING = new DisableStat("REPAIRING", Material.ANVIL, "Disable Repairing", "Players can't use this item in anvils."); - public static final ItemStat DISABLE_ARROW_SHOOTING = new DisableStat("ARROW_SHOOTING", Material.ARROW, "Disable Arrow Shooting", - new Material[] { Material.ARROW }, "Players can't shoot this", "item using a bow."); - public static final ItemStat DISABLE_ATTACK_PASSIVE = new DisableStat("ATTACK_PASSIVE", Material.BARRIER, "Disable Attack Passive", - new String[] { "piercing", "slashing", "blunt" }, "Disables the blunt/slashing/piercing", "passive effects on attacks."); - public static final ItemStat DISABLE_RIGHT_CLICK_CONSUME = new DisableStat("RIGHT_CLICK_CONSUME", Material.BARRIER, "Disable Right Click Consume", - new String[] { "consumable" }, "This item will not be consumed", "when eaten by players."); + public static final ItemStat DISABLE_ARROW_SHOOTING = new DisableStat("ARROW_SHOOTING", Material.ARROW, + "Disable Arrow Shooting", new Material[] { Material.ARROW }, "Players can't shoot this", + "item using a bow."); + public static final ItemStat DISABLE_ATTACK_PASSIVE = new DisableStat("ATTACK_PASSIVE", Material.BARRIER, + "Disable Attack Passive", new String[] { "piercing", "slashing", "blunt" }, + "Disables the blunt/slashing/piercing", "passive effects on attacks."); + public static final ItemStat DISABLE_RIGHT_CLICK_CONSUME = new DisableStat("RIGHT_CLICK_CONSUME", Material.BARRIER, + "Disable Right Click Consume", new String[] { "consumable" }, "This item will not be consumed", + "when eaten by players."); - public static final ItemStat REQUIRED_LEVEL = new RequiredLevel(), REQUIRED_CLASS = new RequiredClass(), ATTACK_DAMAGE = new AttackDamage(), - ATTACK_SPEED = new AttackSpeed(); - public static final ItemStat CRITICAL_STRIKE_CHANCE = new DoubleStat("CRITICAL_STRIKE_CHANCE", new ItemStack(Material.NETHER_STAR), - "Critical Strike Chance", new String[] { "Critical Strikes deal more damage.", "In % chance." }, + public static final ItemStat REQUIRED_LEVEL = new RequiredLevel(), REQUIRED_CLASS = new RequiredClass(), + ATTACK_DAMAGE = new AttackDamage(), ATTACK_SPEED = new AttackSpeed(); + public static final ItemStat CRITICAL_STRIKE_CHANCE = new DoubleStat("CRITICAL_STRIKE_CHANCE", + new ItemStack(Material.NETHER_STAR), "Critical Strike Chance", + new String[] { "Critical Strikes deal more damage.", "In % chance." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat CRITICAL_STRIKE_POWER = new DoubleStat("CRITICAL_STRIKE_POWER", new ItemStack(Material.NETHER_STAR), - "Critical Strike Power", new String[] { "The extra damage weapon crits deals.", "(Stacks with default value)", "In %." }, + public static final ItemStat CRITICAL_STRIKE_POWER = new DoubleStat("CRITICAL_STRIKE_POWER", + new ItemStack(Material.NETHER_STAR), "Critical Strike Power", + new String[] { "The extra damage weapon crits deals.", "(Stacks with default value)", "In %." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat BLOCK_POWER = new DoubleStat("BLOCK_POWER", new ItemStack(Material.IRON_HELMET), "Block Power", - new String[] { "The % of the damage your", "armor/shield can block.", "Default: 25%" }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat BLOCK_RATING = new DoubleStat("BLOCK_RATING", new ItemStack(Material.IRON_HELMET), "Block Rating", - new String[] { "The chance your piece of armor", "has to block any entity attack." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat BLOCK_COOLDOWN_REDUCTION = new DoubleStat("BLOCK_COOLDOWN_REDUCTION", new ItemStack(Material.IRON_HELMET), - "Block Cooldown Reduction", new String[] { "Reduces the blocking cooldown (%)." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat DODGE_RATING = new DoubleStat("DODGE_RATING", new ItemStack(Material.FEATHER), "Dodge Rating", + public static final ItemStat BLOCK_POWER = new DoubleStat("BLOCK_POWER", new ItemStack(Material.IRON_HELMET), + "Block Power", new String[] { "The % of the damage your", "armor/shield can block.", "Default: 25%" }, + new String[] { "!miscellaneous", "all" }); + public static final ItemStat BLOCK_RATING = new DoubleStat("BLOCK_RATING", new ItemStack(Material.IRON_HELMET), + "Block Rating", new String[] { "The chance your piece of armor", "has to block any entity attack." }, + new String[] { "!miscellaneous", "all" }); + public static final ItemStat BLOCK_COOLDOWN_REDUCTION = new DoubleStat("BLOCK_COOLDOWN_REDUCTION", + new ItemStack(Material.IRON_HELMET), "Block Cooldown Reduction", + new String[] { "Reduces the blocking cooldown (%)." }, new String[] { "!miscellaneous", "all" }); + public static final ItemStat DODGE_RATING = new DoubleStat("DODGE_RATING", new ItemStack(Material.FEATHER), + "Dodge Rating", new String[] { "The chance to dodge an attack.", "Dodging completely negates", "the attack damage." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat DODGE_COOLDOWN_REDUCTION = new DoubleStat("DODGE_COOLDOWN_REDUCTION", new ItemStack(Material.FEATHER), - "Dodge Cooldown Reduction", new String[] { "Reduces the dodging cooldown (%)." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat PARRY_RATING = new DoubleStat("PARRY_RATING", new ItemStack(Material.BUCKET), "Parry Rating", - new String[] { "The chance to parry an attack.", "Parrying negates the damage", "and knocks the attacker back." }, + public static final ItemStat DODGE_COOLDOWN_REDUCTION = new DoubleStat("DODGE_COOLDOWN_REDUCTION", + new ItemStack(Material.FEATHER), "Dodge Cooldown Reduction", + new String[] { "Reduces the dodging cooldown (%)." }, new String[] { "!miscellaneous", "all" }); + public static final ItemStat PARRY_RATING = new DoubleStat( + "PARRY_RATING", new ItemStack(Material.BUCKET), "Parry Rating", new String[] { + "The chance to parry an attack.", "Parrying negates the damage", "and knocks the attacker back." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat PARRY_COOLDOWN_REDUCTION = new DoubleStat("PARRY_COOLDOWN_REDUCTION", new ItemStack(Material.BUCKET), - "Parry Cooldown Reduction", new String[] { "Reduces the parrying cooldown (%)." }, new String[] { "!miscellaneous", "all" }); - public static final ItemStat COOLDOWN_REDUCTION = new DoubleStat("COOLDOWN_REDUCTION", new ItemStack(Material.BOOK), "Cooldown Reduction", - new String[] { "Reduces cooldowns of item skills (%)." }); + public static final ItemStat PARRY_COOLDOWN_REDUCTION = new DoubleStat("PARRY_COOLDOWN_REDUCTION", + new ItemStack(Material.BUCKET), "Parry Cooldown Reduction", + new String[] { "Reduces the parrying cooldown (%)." }, new String[] { "!miscellaneous", "all" }); + public static final ItemStat COOLDOWN_REDUCTION = new DoubleStat("COOLDOWN_REDUCTION", new ItemStack(Material.BOOK), + "Cooldown Reduction", new String[] { "Reduces cooldowns of item skills (%)." }); public static final ItemStat RANGE = new DoubleStat("RANGE", new ItemStack(Material.STICK), "Range", new String[] { "The range of your item attacks." }, new String[] { "staff", "whip", "wand", "musket" }); - public static final ItemStat MANA_COST = new DoubleStat("MANA_COST", VersionMaterial.LAPIS_LAZULI.toItem(), "Mana Cost", - new String[] { "Mana spent by your weapon to be used." }, new String[] { "piercing", "slashing", "blunt", "range" }); - public static final ItemStat STAMINA_COST = new DoubleStat("STAMINA_COST", VersionMaterial.LIGHT_GRAY_DYE.toItem(), "Stamina Cost", - new String[] { "Stamina spent by your weapon to be used." }, new String[] { "piercing", "slashing", "blunt", "range" }); - public static final ItemStat ARROW_VELOCITY = new DoubleStat("ARROW_VELOCITY", new ItemStack(Material.ARROW), "Arrow Velocity", - new String[] { "Determins how far your", "crossbow can shoot.", "Default: 1.0" }, new String[] { "bow", "crossbow" }); - public static final ItemStat PVE_DAMAGE = new DoubleStat("PVE_DAMAGE", VersionMaterial.PORKCHOP.toItem(), "PvE Damage", - new String[] { "Additional damage against", "non human entities in %." }, - new String[] { "piercing", "slashing", "blunt", "offhand", "range", "tool", "armor", "gem_stone", "accessory" }); - public static final ItemStat PVP_DAMAGE = new DoubleStat("PVP_DAMAGE", VersionMaterial.SKELETON_SKULL.toItem(), "PvP Damage", - new String[] { "Additional damage", "against players in %." }, - new String[] { "piercing", "slashing", "blunt", "offhand", "range", "tool", "armor", "gem_stone", "accessory" }); - public static final ItemStat BLUNT_POWER = new DoubleStat("BLUNT_POWER", new ItemStack(Material.IRON_AXE), "Blunt Power", - new String[] { "The radius of the AoE attack.", "If set to 2.0, enemies within 2 blocks", "around your target will take damage." }, + public static final ItemStat MANA_COST = new DoubleStat("MANA_COST", VersionMaterial.LAPIS_LAZULI.toItem(), + "Mana Cost", new String[] { "Mana spent by your weapon to be used." }, + new String[] { "piercing", "slashing", "blunt", "range" }); + public static final ItemStat STAMINA_COST = new DoubleStat("STAMINA_COST", VersionMaterial.LIGHT_GRAY_DYE.toItem(), + "Stamina Cost", new String[] { "Stamina spent by your weapon to be used." }, + new String[] { "piercing", "slashing", "blunt", "range" }); + public static final ItemStat ARROW_VELOCITY = new DoubleStat("ARROW_VELOCITY", new ItemStack(Material.ARROW), + "Arrow Velocity", new String[] { "Determins how far your", "crossbow can shoot.", "Default: 1.0" }, + new String[] { "bow", "crossbow" }); + public static final ItemStat PVE_DAMAGE = new DoubleStat("PVE_DAMAGE", VersionMaterial.PORKCHOP.toItem(), + "PvE Damage", new String[] { "Additional damage against", "non human entities in %." }, new String[] { + "piercing", "slashing", "blunt", "offhand", "range", "tool", "armor", "gem_stone", "accessory" }); + public static final ItemStat PVP_DAMAGE = new DoubleStat("PVP_DAMAGE", VersionMaterial.SKELETON_SKULL.toItem(), + "PvP Damage", new String[] { "Additional damage", "against players in %." }, new String[] { "piercing", + "slashing", "blunt", "offhand", "range", "tool", "armor", "gem_stone", "accessory" }); + public static final ItemStat BLUNT_POWER = new DoubleStat("BLUNT_POWER", new ItemStack(Material.IRON_AXE), + "Blunt Power", new String[] { "The radius of the AoE attack.", "If set to 2.0, enemies within 2 blocks", + "around your target will take damage." }, new String[] { "blunt", "gem_stone" }); - public static final ItemStat BLUNT_RATING = new DoubleStat("BLUNT_RATING", new ItemStack(Material.BRICK), "Blunt Rating", - new String[] { "The force of the blunt attack.", "If set to 50%, enemies hit by the attack", "will take 50% of the initial damage." }, + public static final ItemStat BLUNT_RATING = new DoubleStat("BLUNT_RATING", new ItemStack(Material.BRICK), + "Blunt Rating", new String[] { "The force of the blunt attack.", "If set to 50%, enemies hit by the attack", + "will take 50% of the initial damage." }, new String[] { "blunt", "gem_stone" }); - public static final ItemStat WEAPON_DAMAGE = new DoubleStat("WEAPON_DAMAGE", new ItemStack(Material.IRON_SWORD), "Weapon Damage", - new String[] { "Additional on-hit weapon damage in %." }); - public static final ItemStat SKILL_DAMAGE = new DoubleStat("SKILL_DAMAGE", new ItemStack(Material.BOOK), "Skill Damage", - new String[] { "Additional ability damage in %." }); - public static final ItemStat PROJECTILE_DAMAGE = new DoubleStat("PROJECTILE_DAMAGE", new ItemStack(Material.ARROW), "Projectile Damage", - new String[] { "Additional skill/weapon projectile damage." }); - public static final ItemStat MAGIC_DAMAGE = new DoubleStat("MAGIC_DAMAGE", new ItemStack(Material.MAGMA_CREAM), "Magic Damage", - new String[] { "Additional magic skill damage in %." }); - public static final ItemStat PHYSICAL_DAMAGE = new DoubleStat("PHYSICAL_DAMAGE", new ItemStack(Material.IRON_AXE), "Physical Damage", - new String[] { "Additional skill/weapon physical damage." }); - public static final ItemStat DAMAGE_REDUCTION = new DoubleStat("DAMAGE_REDUCTION", new ItemStack(Material.IRON_CHESTPLATE), "Damage Reduction", + public static final ItemStat WEAPON_DAMAGE = new DoubleStat("WEAPON_DAMAGE", new ItemStack(Material.IRON_SWORD), + "Weapon Damage", new String[] { "Additional on-hit weapon damage in %." }); + public static final ItemStat SKILL_DAMAGE = new DoubleStat("SKILL_DAMAGE", new ItemStack(Material.BOOK), + "Skill Damage", new String[] { "Additional ability damage in %." }); + public static final ItemStat PROJECTILE_DAMAGE = new DoubleStat("PROJECTILE_DAMAGE", new ItemStack(Material.ARROW), + "Projectile Damage", new String[] { "Additional skill/weapon projectile damage." }); + public static final ItemStat MAGIC_DAMAGE = new DoubleStat("MAGIC_DAMAGE", new ItemStack(Material.MAGMA_CREAM), + "Magic Damage", new String[] { "Additional magic skill damage in %." }); + public static final ItemStat PHYSICAL_DAMAGE = new DoubleStat("PHYSICAL_DAMAGE", new ItemStack(Material.IRON_AXE), + "Physical Damage", new String[] { "Additional skill/weapon physical damage." }); + public static final ItemStat DAMAGE_REDUCTION = new DoubleStat("DAMAGE_REDUCTION", + new ItemStack(Material.IRON_CHESTPLATE), "Damage Reduction", new String[] { "Reduces damage from any source.", "In %." }); - public static final ItemStat FALL_DAMAGE_REDUCTION = new DoubleStat("FALL_DAMAGE_REDUCTION", new ItemStack(Material.FEATHER), - "Fall Damage Reduction", new String[] { "Reduces fall damage.", "In %." }); - public static final ItemStat PROJECTILE_DAMAGE_REDUCTION = new DoubleStat("PROJECTILE_DAMAGE_REDUCTION", VersionMaterial.SNOWBALL.toItem(), - "Projectile Damage Reduction", new String[] { "Reduces projectile damage.", "In %." }); - public static final ItemStat PHYSICAL_DAMAGE_REDUCTION = new DoubleStat("PHYSICAL_DAMAGE_REDUCTION", new ItemStack(Material.LEATHER_CHESTPLATE), - "Physical Damage Reduction", new String[] { "Reduces physical damage.", "In %." }); - public static final ItemStat FIRE_DAMAGE_REDUCTION = new DoubleStat("FIRE_DAMAGE_REDUCTION", new ItemStack(Material.BLAZE_POWDER), - "Fire Damage Reduction", new String[] { "Reduces fire damage.", "In %." }); - public static final ItemStat MAGIC_DAMAGE_REDUCTION = new DoubleStat("MAGIC_DAMAGE_REDUCTION", new ItemStack(Material.POTION), - "Magic Damage Reduction", new String[] { "Reduce magic damage dealt by potions.", "In %." }); - public static final ItemStat PVE_DAMAGE_REDUCTION = new DoubleStat("PVE_DAMAGE_REDUCTION", VersionMaterial.PORKCHOP.toItem(), - "PvE Damage Reduction", new String[] { "Reduces damage dealt by mobs.", "In %." }); - public static final ItemStat PVP_DAMAGE_REDUCTION = new DoubleStat("PVP_DAMAGE_REDUCTION", VersionMaterial.SKELETON_SKULL.toItem(), - "PvP Damage Reduction", new String[] { "Reduces damage dealt by players", "In %." }); - public static final ItemStat UNDEAD_DAMAGE = new DoubleStat("UNDEAD_DAMAGE", VersionMaterial.SKELETON_SKULL.toItem(), "Undead Damage", + public static final ItemStat FALL_DAMAGE_REDUCTION = new DoubleStat("FALL_DAMAGE_REDUCTION", + new ItemStack(Material.FEATHER), "Fall Damage Reduction", new String[] { "Reduces fall damage.", "In %." }); + public static final ItemStat PROJECTILE_DAMAGE_REDUCTION = new DoubleStat("PROJECTILE_DAMAGE_REDUCTION", + VersionMaterial.SNOWBALL.toItem(), "Projectile Damage Reduction", + new String[] { "Reduces projectile damage.", "In %." }); + public static final ItemStat PHYSICAL_DAMAGE_REDUCTION = new DoubleStat("PHYSICAL_DAMAGE_REDUCTION", + new ItemStack(Material.LEATHER_CHESTPLATE), "Physical Damage Reduction", + new String[] { "Reduces physical damage.", "In %." }); + public static final ItemStat FIRE_DAMAGE_REDUCTION = new DoubleStat("FIRE_DAMAGE_REDUCTION", + new ItemStack(Material.BLAZE_POWDER), "Fire Damage Reduction", + new String[] { "Reduces fire damage.", "In %." }); + public static final ItemStat MAGIC_DAMAGE_REDUCTION = new DoubleStat("MAGIC_DAMAGE_REDUCTION", + new ItemStack(Material.POTION), "Magic Damage Reduction", + new String[] { "Reduce magic damage dealt by potions.", "In %." }); + public static final ItemStat PVE_DAMAGE_REDUCTION = new DoubleStat("PVE_DAMAGE_REDUCTION", + VersionMaterial.PORKCHOP.toItem(), "PvE Damage Reduction", + new String[] { "Reduces damage dealt by mobs.", "In %." }); + public static final ItemStat PVP_DAMAGE_REDUCTION = new DoubleStat("PVP_DAMAGE_REDUCTION", + VersionMaterial.SKELETON_SKULL.toItem(), "PvP Damage Reduction", + new String[] { "Reduces damage dealt by players", "In %." }); + public static final ItemStat UNDEAD_DAMAGE = new DoubleStat("UNDEAD_DAMAGE", + VersionMaterial.SKELETON_SKULL.toItem(), "Undead Damage", new String[] { "Deals additional damage to undead.", "In %." }); - public static final ItemStat UNBREAKABLE = new Unbreakable(), TIER = new ItemTierStat(), SET = new ItemSetStat(), ARMOR = new Armor(), - ARMOR_TOUGHNESS = new ArmorToughness(), MAX_HEALTH = new MaxHealth(); - public static final ItemStat MAX_MANA = new DoubleStat("MAX_MANA", VersionMaterial.LAPIS_LAZULI.toItem(), "Max Mana", - new String[] { "Adds mana to your max mana bar." }); + public static final ItemStat UNBREAKABLE = new Unbreakable(), TIER = new ItemTierStat(), SET = new ItemSetStat(), + ARMOR = new Armor(), ARMOR_TOUGHNESS = new ArmorToughness(), MAX_HEALTH = new MaxHealth(); + public static final ItemStat MAX_MANA = new DoubleStat("MAX_MANA", VersionMaterial.LAPIS_LAZULI.toItem(), + "Max Mana", new String[] { "Adds mana to your max mana bar." }); public static final ItemStat KNOCKBACK_RESISTANCE = new KnockbackResistance(), MOVEMENT_SPEED = new MovementSpeed(); - public static final ItemStat TWO_HANDED = new BooleanStat("TWO_HANDED", new ItemStack(Material.IRON_INGOT), "Two Handed", - new String[] { "If set to true, a player will be", "significantly slower if holding two", "items, one being Two Handed." }, + public static final ItemStat TWO_HANDED = new BooleanStat("TWO_HANDED", new ItemStack(Material.IRON_INGOT), + "Two Handed", + new String[] { "If set to true, a player will be", "significantly slower if holding two", + "items, one being Two Handed." }, new String[] { "piercing", "slashing", "blunt", "offhand", "range", "tool" }); public static final ItemStat RESTORE = new Restore(); - public static final ItemStat RESTORE_MANA = new DoubleStat("RESTORE_MANA", VersionMaterial.LAPIS_LAZULI.toItem(), "Restore Mana", - new String[] { "The amount of mana", "your consumable restores." }, new String[] { "consumable" }); - public static final ItemStat RESTORE_STAMINA = new DoubleStat("RESTORE_STAMINA", VersionMaterial.LIGHT_GRAY_DYE.toItem(), "Restore Stamina", + public static final ItemStat RESTORE_MANA = new DoubleStat("RESTORE_MANA", VersionMaterial.LAPIS_LAZULI.toItem(), + "Restore Mana", new String[] { "The amount of mana", "your consumable restores." }, + new String[] { "consumable" }); + public static final ItemStat RESTORE_STAMINA = new DoubleStat("RESTORE_STAMINA", + VersionMaterial.LIGHT_GRAY_DYE.toItem(), "Restore Stamina", new String[] { "The amount of stamina/power", "your consumable restores." }, new String[] { "consumable" }); - public static final ItemStat CAN_IDENTIFY = new BooleanStat("CAN_IDENTIFY", new ItemStack(Material.PAPER), "Can Identify?", - new String[] { "Players can identify & make their", "item usable using this consumable." }, new String[] { "consumable" }); - public static final ItemStat CAN_DECONSTRUCT = new BooleanStat("CAN_DECONSTRUCT", new ItemStack(Material.PAPER), "Can Deconstruct?", - new String[] { "Players can deconstruct their item", "using this consumable, creating", "another random item." }, + public static final ItemStat CAN_IDENTIFY = new BooleanStat("CAN_IDENTIFY", new ItemStack(Material.PAPER), + "Can Identify?", new String[] { "Players can identify & make their", "item usable using this consumable." }, + new String[] { "consumable" }); + public static final ItemStat CAN_DECONSTRUCT = new BooleanStat( + "CAN_DECONSTRUCT", new ItemStack(Material.PAPER), "Can Deconstruct?", new String[] { + "Players can deconstruct their item", "using this consumable, creating", "another random item." }, new String[] { "consumable" }); public static final ItemStat EFFECTS = new Effects(), PERM_EFFECTS = new PermanentEffects(); - public static final ItemStat SOULBINDING_CHANCE = new DoubleStat("SOULBINDING_CHANCE", VersionMaterial.ENDER_EYE.toItem(), "Soulbinding Chance", - new String[] { "Defines the chance your item has to", "link another item to your soul,", "preventing other players from using it." }, + public static final ItemStat SOULBINDING_CHANCE = new DoubleStat("SOULBINDING_CHANCE", + VersionMaterial.ENDER_EYE.toItem(), "Soulbinding Chance", + new String[] { "Defines the chance your item has to", "link another item to your soul,", + "preventing other players from using it." }, new String[] { "consumable" }); - public static final ItemStat SOULBOUND_BREAK_CHANCE = new DoubleStat( - "SOULBOUND_BREAK_CHANCE", VersionMaterial.ENDER_EYE.toItem(), "Soulbound Break Chance", new String[] { "The chance of breaking an item's", - "soulbound when drag & drop'd on it.", "This chance is lowered depending", "on the soulbound's level." }, + public static final ItemStat SOULBOUND_BREAK_CHANCE = new DoubleStat("SOULBOUND_BREAK_CHANCE", + VersionMaterial.ENDER_EYE.toItem(), "Soulbound Break Chance", + new String[] { "The chance of breaking an item's", "soulbound when drag & drop'd on it.", + "This chance is lowered depending", "on the soulbound's level." }, new String[] { "consumable" }); public static final ItemStat SOULBOUND_LEVEL = new SoulboundLevel(); - public static final ItemStat ITEM_COOLDOWN = new DoubleStat("ITEM_COOLDOWN", new ItemStack(Material.COOKED_CHICKEN), "Item Cooldown", - new String[] { "This cooldown applies for consumables", "as well as for item commands." }, + public static final ItemStat ITEM_COOLDOWN = new DoubleStat("ITEM_COOLDOWN", new ItemStack(Material.COOKED_CHICKEN), + "Item Cooldown", new String[] { "This cooldown applies for consumables", "as well as for item commands." }, new String[] { "!armor", "!gem_stone", "all" }); - public static final ItemStat VANILLA_EATING_ANIMATION = new VanillaEatingAnimation(), INEDIBLE = new Inedible(), GEM_COLOR = new GemColor(), - ITEM_TYPE_RESTRICTION = new ItemTypeRestriction(); - public static final ItemStat MAX_CONSUME = new DoubleStat("MAX_CONSUME", new ItemStack(Material.BLAZE_POWDER), "Max Consume", - new String[] { "Max amount of usage before", "item disappears." }, new String[] { "consumable" }); + public static final ItemStat VANILLA_EATING_ANIMATION = new VanillaEatingAnimation(), INEDIBLE = new Inedible(), + GEM_COLOR = new GemColor(), ITEM_TYPE_RESTRICTION = new ItemTypeRestriction(); + public static final ItemStat MAX_CONSUME = new DoubleStat("MAX_CONSUME", new ItemStack(Material.BLAZE_POWDER), + "Max Consume", new String[] { "Max amount of usage before", "item disappears." }, + new String[] { "consumable" }); public static final ItemStat SUCCESS_RATE = new SuccessRate(); public static final ItemStat COMPATIBLE_TYPES = new CompatibleTypes(); - public static final ItemStat CRAFTING = new Crafting(), CRAFT_PERMISSION = new CraftingPermission(); + public static final ItemStat CRAFTING = new Crafting(), CRAFT_PERMISSION = new CraftingPermission(), + CRAFT_AMOUNT = new DoubleStat("CRAFTED_AMOUNT", new ItemStack(Material.WOODEN_AXE), "Crafted Amount", + new String[] { "The stack count for", "this item when crafted." }, new String[] { "all" }); public static final ItemStat AUTOSMELT = new BooleanStat("AUTOSMELT", new ItemStack(Material.COAL), "Autosmelt", - new String[] { "If set to true, your tool will", "automaticaly smelt mined ores." }, new String[] { "tool" }); - public static final ItemStat BOUNCING_CRACK = new BooleanStat("BOUNCING_CRACK", VersionMaterial.COBBLESTONE_WALL.toItem(), "Bouncing Crack", + new String[] { "If set to true, your tool will", "automaticaly smelt mined ores." }, + new String[] { "tool" }); + public static final ItemStat BOUNCING_CRACK = new BooleanStat("BOUNCING_CRACK", + VersionMaterial.COBBLESTONE_WALL.toItem(), "Bouncing Crack", new String[] { "If set to true, your tool will", "also break nearby blocks." }, new String[] { "tool" }); public static final ItemStat PICKAXE_POWER = new PickaxePower(); public static final ItemStat CUSTOM_SOUNDS = new CustomSounds(); public static final ItemStat ELEMENTS = new Elements(); - public static final ItemStat COMMANDS = new Commands(), STAFF_SPIRIT = new StaffSpiritStat(), LUTE_ATTACK_SOUND = new LuteAttackSoundStat(), - LUTE_ATTACK_EFFECT = new LuteAttackEffectStat(); - public static final ItemStat NOTE_WEIGHT = new DoubleStat("NOTE_WEIGHT", VersionMaterial.MUSIC_DISC_MALL.toItem(), "Note Weight", - new String[] { "Defines how the projectile cast", "by your lute tilts downwards." }, new String[] { "lute" }); - public static final ItemStat REMOVE_ON_CRAFT = new BooleanStat("REMOVE_ON_CRAFT", new ItemStack(Material.GLASS_BOTTLE), "Remove on Craft", - new String[] { "If the item should be completely", "removed when used in a recipe,", "or if it should become an", - "empty bottle or bucket." }, - new String[] { "all" }, Material.POTION, Material.SPLASH_POTION, Material.LINGERING_POTION, Material.MILK_BUCKET, Material.LAVA_BUCKET, - Material.WATER_BUCKET); + public static final ItemStat COMMANDS = new Commands(), STAFF_SPIRIT = new StaffSpiritStat(), + LUTE_ATTACK_SOUND = new LuteAttackSoundStat(), LUTE_ATTACK_EFFECT = new LuteAttackEffectStat(); + public static final ItemStat NOTE_WEIGHT = new DoubleStat("NOTE_WEIGHT", VersionMaterial.MUSIC_DISC_MALL.toItem(), + "Note Weight", new String[] { "Defines how the projectile cast", "by your lute tilts downwards." }, + new String[] { "lute" }); + public static final ItemStat REMOVE_ON_CRAFT = new BooleanStat("REMOVE_ON_CRAFT", + new ItemStack(Material.GLASS_BOTTLE), "Remove on Craft", + new String[] { "If the item should be completely", "removed when used in a recipe,", + "or if it should become an", "empty bottle or bucket." }, + new String[] { "all" }, Material.POTION, Material.SPLASH_POTION, Material.LINGERING_POTION, + Material.MILK_BUCKET, Material.LAVA_BUCKET, Material.WATER_BUCKET); public static final ItemStat GEM_SOCKETS = new GemSockets(); public static final ItemStat REPAIR = new DoubleStat("REPAIR", new ItemStack(Material.ANVIL), "Repair", - new String[] { "The amount of durability your item", "can repair when set an item." }, new String[] { "consumable" }); + new String[] { "The amount of durability your item", "can repair when set an item." }, + new String[] { "consumable" }); // public static final ItemStat REPAIR_MATERIAL = new RepairMaterial(); - public static final ItemStat KNOCKBACK = new DoubleStat("KNOCKBACK", VersionMaterial.IRON_HORSE_ARMOR.toItem(), "Knockback", - new String[] { "Using this musket will knock", "the user back if positive." }, new String[] { "musket" }); + public static final ItemStat KNOCKBACK = new DoubleStat("KNOCKBACK", VersionMaterial.IRON_HORSE_ARMOR.toItem(), + "Knockback", new String[] { "Using this musket will knock", "the user back if positive." }, + new String[] { "musket" }); public static final ItemStat RECOIL = new DoubleStat("RECOIL", VersionMaterial.IRON_HORSE_ARMOR.toItem(), "Recoil", new String[] { "Corresponds to the shooting innacuracy." }, new String[] { "musket" }); public static final ItemStat ABILITIES = new Abilities(), UPGRADE = new UpgradeStat(); - public static final ItemStat SKULL_TEXTURE = new SkullTextureStat(), DYE_COLOR = new DyeColor(), POTION_EFFECTS = new PotionEffects(), - POTION_COLOR = new PotionColor(), SHIELD_PATTERN = new ShieldPatternStat(), HIDE_POTION_EFFECTS = new HidePotionEffects(); + public static final ItemStat SKULL_TEXTURE = new SkullTextureStat(), DYE_COLOR = new DyeColor(), + POTION_EFFECTS = new PotionEffects(), POTION_COLOR = new PotionColor(), + SHIELD_PATTERN = new ShieldPatternStat(), HIDE_POTION_EFFECTS = new HidePotionEffects(); /* * internal stats @@ -262,8 +312,8 @@ public abstract class ItemStat { private final List compatibleMaterials; /* - * the stat can be enabled or not, depending on the server version to - * prevent from displaying useless editable stats in the edition menu. + * the stat can be enabled or not, depending on the server version to prevent + * from displaying useless editable stats in the edition menu. */ private boolean enabled = true; @@ -277,15 +327,14 @@ public abstract class ItemStat { } /* - * reads stat data from a configuration section and applies it to the item - * stack after having generated the corresponding stat data class instance + * reads stat data from a configuration section and applies it to the item stack + * after having generated the corresponding stat data class instance */ public abstract StatData whenInitialized(Object object); /* - * any item stat which can be used in the item generator. this method reads - * from a config file stat data which is cached to later generate a random - * item + * any item stat which can be used in the item generator. this method reads from + * a config file stat data which is cached to later generate a random item */ public abstract RandomStatData whenInitializedGeneration(Object object); @@ -300,8 +349,7 @@ public abstract class ItemStat { public abstract boolean whenClicked(EditionInventory inv, InventoryClickEvent event); /* - * when entering input using the chat edition feature from the item edition - * menu + * when entering input using the chat edition feature from the item edition menu */ public abstract boolean whenInput(EditionInventory inv, ConfigFile config, String message, Object... info); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 92d015b0..29462798 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -130,10 +130,6 @@ cooldown-progress-bar-char: █ # When toggled off, players can't damage each other using item abilities. ability-player-damage: true -# When enabled, all custom recipes will be in the recipe book on join. -# If toggled off they will have to use to recipe once to add it to their book. -auto-recipe-book: true - # Displays a message on the action bar instead of on the chat. # Can be used to reduce chat spam. # Might interfere with other action bar plugins. diff --git a/src/main/resources/default/item/consumable.yml b/src/main/resources/default/item/consumable.yml index 7f6fbb5e..46ae7a87 100644 --- a/src/main/resources/default/item/consumable.yml +++ b/src/main/resources/default/item/consumable.yml @@ -299,15 +299,15 @@ EGGNOG: crafting: shapeless: '1': - item1: EGG - item2: SUGAR - item3: AIR - item4: AIR - item5: AIR - item6: AIR - item7: AIR - item8: AIR - item9: AIR + - EGG + - SUGAR + - AIR + - AIR + - AIR + - AIR + - AIR + - AIR + - AIR MANGO: material: PLAYER_HEAD name: '&fMango' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d70eb149..b8e1fcfe 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -13,6 +13,8 @@ commands: updateitem: description: Update the item you are holding. aliases: [upitem,itemup] + recipes: + description: Opens the recipe book for viewing all custom recipes. permissions: mmoitems.admin: description: Access to admin commands. @@ -41,3 +43,6 @@ permissions: mmoitems.soulbound: description: Allows to use /soulbound. default: op + mmoitems.recipes: + description: Allows to use /recipes. + default: true \ No newline at end of file