package net.knarcraft.blacksmith.util; import net.knarcraft.blacksmith.BlacksmithPlugin; import net.knarcraft.blacksmith.config.SmithPreset; import org.bukkit.Material; import org.bukkit.Server; import org.bukkit.inventory.CraftingRecipe; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.Recipe; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; /** * A helper class for getting information about items */ public final class ItemHelper { private ItemHelper() { } /** * Gets whether the given item is repairable * * @param item

The item to check

* @return

True if the item is repairable

*/ public static boolean isRepairable(@NotNull ItemStack item) { return item.getItemMeta() instanceof Damageable && getMaxDurability(item) > 0; } /** * Gets the max durability of an item * * @param itemStack

The item to get the durability of

* @return

The max durability of the item

*/ public static short getMaxDurability(@NotNull ItemStack itemStack) { if (itemStack.getItemMeta() instanceof Damageable) { return itemStack.getType().getMaxDurability(); } else { return 0; } } /** * Gets the current durability of the given item * * @param itemStack

The item to get the durability of

* @return

The durability of the item

*/ public static short getDurability(@NotNull ItemStack itemStack) { if (itemStack.getItemMeta() instanceof Damageable damageable) { int maxDurability = getMaxDurability(itemStack); return (short) (maxDurability - damageable.getDamage()); } else { return 0; } } /** * Gets the damage done to the given item * * @param itemStack

The damage done to the item

* @return

The damage done to the item

*/ public static short getDamage(@NotNull ItemStack itemStack) { if (itemStack.getItemMeta() instanceof Damageable damageable) { return (short) damageable.getDamage(); } else { return 0; } } /** * Updates the damage done to an item * * @param item

The item to update damage for

* @param newDamage

The new damage done

* @return

True if the damage was updated. False if not damageable.

*/ public static boolean updateDamage(@NotNull ItemStack item, int newDamage) { ItemMeta meta = item.getItemMeta(); if (!(meta instanceof Damageable damageable)) { return false; } damageable.setDamage(newDamage); item.setItemMeta(meta); return true; } /** * Gets a complete list of all reforge-able materials * *

Note: As this loops through all materials, the result should be cached

* * @return

A complete list of reforge-able materials

*/ public static @NotNull Set getAllReforgeAbleMaterials() { Set reforgeAbleMaterials = new HashSet<>(); for (Material material : Material.values()) { ItemStack item = new ItemStack(material); if (isRepairable(item)) { reforgeAbleMaterials.add(material); } } return reforgeAbleMaterials; } /** * Checks whether the given material is an anvil * * @param material

The material to check

* @param requireDamaged

Whether only a damaged anvil should count

* @return

True if the given material is an anvil

*/ public static boolean isAnvil(@NotNull Material material, boolean requireDamaged) { boolean isDamagedAnvil = material == Material.CHIPPED_ANVIL || material == Material.DAMAGED_ANVIL; boolean isAnvil = isDamagedAnvil || material == Material.ANVIL; return (requireDamaged && isDamagedAnvil) || (!requireDamaged && isAnvil); } /** * Checks whether the given inventory is able to fit the given item * * @param inventory

The inventory to check

* @param item

The item to check

* @return

True if the inventory can fit the item

*/ public static boolean canFitItem(@NotNull Inventory inventory, @NotNull ItemStack item) { // If a slot is available, there is no problem if (inventory.firstEmpty() != -1) { return true; } // If the inventory doesn't contain the correct type of item, stacking is impossible if (!inventory.contains(item.getType())) { return false; } // Check if the item stack can fit in the inventory if stacked with existing items int availableSlots = 0; for (ItemStack itemStack : inventory.getStorageContents()) { ItemMeta itemMeta = itemStack.getItemMeta(); ItemMeta targetMeta = item.getItemMeta(); // Skip items of a different type, or with metadata that would prevent stacking if (itemStack.getType() != item.getType() || (itemMeta != null && targetMeta != null && !itemMeta.equals(targetMeta))) { continue; } availableSlots += itemStack.getMaxStackSize() - itemStack.getAmount(); if (availableSlots < item.getAmount()) { return true; } } return false; } /** * Checks whether the given item can be salvaged, assuming no restrictions apply * * @param server

The server to get recipes from

* @param item

The item to check

* @return

True if the item can be salvaged

*/ public static boolean isSalvageable(@NotNull Server server, @NotNull ItemStack item) { for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) { // Only crafting recipes are allowed. if ((recipe instanceof CraftingRecipe) && item.getAmount() >= recipe.getResult().getAmount()) { return true; } } return false; } /** * Gets the amount of an item that's required to salvage that item * * @param server

The server to get recipes from

* @param item

The item to check

* @return

The number of items required for salvage, or -1 if the recipe was not found

*/ public static int getRequiredAmountForSalvage(@NotNull Server server, @NotNull ItemStack item) { for (Recipe recipe : server.getRecipesFor(new ItemStack(item.getType(), item.getAmount()))) { // Only crafting recipes are allowed. if (recipe instanceof CraftingRecipe) { return recipe.getResult().getAmount(); } } return -1; } /** * Gets all materials matching the given material wildcard * * @param materialName

The material name or material wildcard to match

* @param extended

Whether to use an extended match, allowing any material

* @return

The matched material(s)

*/ public static @NotNull Set getWildcardMatch(@NotNull String materialName, boolean extended) { String search = InputParsingHelper.regExIfy(materialName); Set materials = new HashSet<>(); Set all; if (extended) { all = Set.of(Material.values()); } else { all = ItemHelper.getAllReforgeAbleMaterials(); } for (Material material : all) { if (material.name().matches(search)) { materials.add(material); } } return materials; } /** * Gets a list of the items described in the given item list * * @param itemList

The list of items defined by the user

* @param requireRepairable

Whether a material must be repairable to be valid.

* @return

The materials contained in the item list

*/ public static List getItems(@Nullable List itemList, boolean requireRepairable) { List items = new ArrayList<>(); if (itemList == null) { return null; } //Convert any presets with a list of materials itemList = replacePresets(itemList); Set blacklisted = new HashSet<>(); //Parse every material, and add to reforgeAble items for (String item : itemList) { //Ignore ",," if (InputParsingHelper.isEmpty(item) || item.matches("\\[]")) { continue; } boolean blacklist = false; if (item.startsWith("-")) { blacklist = true; item = item.substring(1); } Material material = InputParsingHelper.matchMaterial(item); if (material != null && (!requireRepairable || ItemHelper.isRepairable(new ItemStack(material, 1)))) { if (!blacklist) { items.add(material); } else { blacklisted.add(material); } } else { BlacksmithPlugin.getInstance().getLogger().log(Level.WARNING, "Unable to verify " + item + " as a valid repairable item"); } } //Remove any blacklisted materials at the end to make sure order of arguments won't matter items.removeAll(blacklisted); return items; } /** * Replaces smith presets in the given list of strings * * @param stringList

The value specified by a user

* @return

The value with smith presets replaced

*/ private static @NotNull List replacePresets(@NotNull List stringList) { List newStrings = new ArrayList<>(); for (String item : stringList) { if (item == null) { continue; } String replaced = SmithPreset.replacePreset(item); if (!replaced.equals(item)) { newStrings.addAll(List.of(replaced.split(","))); } else { newStrings.add(item); } } return newStrings; } }