From 3b1dda55d73b9547af982c4fd1fac3c76246ed1e Mon Sep 17 00:00:00 2001 From: Pim van der Loos Date: Mon, 1 Nov 2021 18:08:01 +0100 Subject: [PATCH] Use custom durability - The durability of armored elytras is now stored in their NBT. This allows us to use custom max durability values for different armor tiers. Currently, only the anvil code uses the new durability system. The rest of the plugin will follow in a future commit, as all parts that interact with durability in any way will need to be updated. The durability returned by the regular methods now only show the display durability. --- .../armoredElytra/DurabilityManager.java | 229 ++++++++++++++++++ .../armoredElytra/handlers/AnvilHandler.java | 45 ++-- .../armoredElytra/nbtEditor/INBTEditor.java | 34 ++- .../armoredElytra/nbtEditor/NBTEditor.java | 98 ++++++-- .../pim16aap2/armoredElytra/util/Action.java | 30 ++- .../armoredElytra/util/ArmorTier.java | 4 +- .../armoredElytra/util/ConfigLoader.java | 5 +- .../nl/pim16aap2/armoredElytra/util/Util.java | 13 + 8 files changed, 399 insertions(+), 59 deletions(-) create mode 100644 src/main/java/nl/pim16aap2/armoredElytra/DurabilityManager.java diff --git a/src/main/java/nl/pim16aap2/armoredElytra/DurabilityManager.java b/src/main/java/nl/pim16aap2/armoredElytra/DurabilityManager.java new file mode 100644 index 0000000..604cc1c --- /dev/null +++ b/src/main/java/nl/pim16aap2/armoredElytra/DurabilityManager.java @@ -0,0 +1,229 @@ +package nl.pim16aap2.armoredElytra; + +import nl.pim16aap2.armoredElytra.nbtEditor.INBTEditor; +import nl.pim16aap2.armoredElytra.util.ArmorTier; +import nl.pim16aap2.armoredElytra.util.ConfigLoader; +import nl.pim16aap2.armoredElytra.util.Util; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import javax.annotation.Nullable; + +public class DurabilityManager +{ + private static final int ELYTRA_MAX_DURABILITY = Material.ELYTRA.getMaxDurability(); + + private final int[] repairSteps = new int[ArmorTier.values().length]; + private final int[] maxDurabilities = new int[ArmorTier.values().length]; + + private final INBTEditor nbtEditor; + private final ConfigLoader config; + + public DurabilityManager(INBTEditor nbtEditor, ConfigLoader config) + { + this.nbtEditor = nbtEditor; + this.config = config; + init(); + } + + /** + * Gets durability value resulting from combining an armored elytra with some other item with durability. + * + * @param armoredElytra The armored elytra item. + * @param other The other item that will be combined with the armored elytra. This can be another armored + * elytra, a chestplate, or any other item. + * @param currentTier The current armor tier of the armored elytra. + * @param targetTier The target tier of the armored elytra. + * @return The new real durability value of the armored elytra if it were to be combined with the other item. + */ + public int getCombinedDurability(ItemStack armoredElytra, ItemStack other, + ArmorTier currentTier, ArmorTier targetTier) + { + final ArmorTier otherTier = nbtEditor.getArmorTier(other); + + final int currentMaxDurability = getMaxDurability(currentTier); + final int targetMaxDurability = getMaxDurability(targetTier); + final int otherMaxDurability = otherTier == ArmorTier.NONE ? + other.getType().getMaxDurability() : getMaxDurability(otherTier); + + final int otherDurability = other.getType().equals(Material.ELYTRA) ? + getRealDurability(other, null) : other.getType().getMaxDurability(); + + final int currentDurability = getRealDurability(armoredElytra, currentTier); + + return targetMaxDurability - + (otherMaxDurability - otherDurability) - + (currentMaxDurability - currentDurability); + } + + /** + * Gets the required number of repair items required to fully repair an armored elytra. + *

+ * For example, for an ArmoredElytra that is damaged for 50 durability and its repair item restores 40 durability, + * this method would return 2. + * + * @param armoredElytra The armored elytra item for which to check how many items are needed to fully repair it. + * @param providedTier The tier of the armored elytra (if this is available). If this is null, it will be retrieved + * from the item itself. + * @return The required number of repair items required to fully repair the armored elytra. + */ + public int getFullRepairItemCount(ItemStack armoredElytra, @Nullable ArmorTier providedTier) + { + final ArmorTier currentTier = providedTier == null ? nbtEditor.getArmorTier(armoredElytra) : providedTier; + final int repairableDurability = getMaxDurability(currentTier) - getRealDurability(armoredElytra, currentTier); + return (int) Math.ceil((float) repairableDurability / getRepairSteps(currentTier)); + } + + /** + * Gets the new durability of an armored elytra if it were to be repaired right now. + * + * @param armoredElytra The armored elytra item for which to check what the new durability would be after repairing + * it. + * @param repairCount The number of repair items. + * @param providedTier The tier of the armored elytra (if this is available). If this is null, it will be retrieved + * from the item itself. + * @return The real durability value of the armored elytra if it were to be repaired. + */ + public int getRepairedDurability(ItemStack armoredElytra, int repairCount, @Nullable ArmorTier providedTier) + { + final ArmorTier currentTier = providedTier == null ? nbtEditor.getArmorTier(armoredElytra) : providedTier; + final int restoredDurability = repairCount * getRepairSteps(currentTier); + final int currentDurability = getRealDurability(armoredElytra, currentTier); + return Math.max(0, currentDurability - restoredDurability); + } + + /** + * Gets the real durability of an item. + *

+ * If the item is an armored elytra, and it does not have a real durability yet, it will be upgraded. + * + * @param item The item for which to figure out the real durability. + * @param providedTier The tier of the armored elytra (if this is available). If this is null, it will be retrieved + * from the item itself. + * @return The real durability of the item. + */ + public int getRealDurability(ItemStack item, @Nullable ArmorTier providedTier) + { + final ArmorTier currentTier = providedTier == null ? nbtEditor.getArmorTier(item) : providedTier; + + if (currentTier == ArmorTier.NONE) + //noinspection deprecation + return item.getDurability(); + + final int realDurability = nbtEditor.getRealDurability(item, currentTier); + return realDurability == -1 ? upgradeArmoredElytraToDurability(item, currentTier) : realDurability; + } + + /** + * Sets the durability values (real + shown) of an armored elytra. + * + * @param item The armored elytra item for which to set the durability values. + * @param durability The real durability value. + * @param providedTier The tier of the armored elytra (if this is available). If this is null, it will be retrieved + * from the item itself. + */ + public void setDurability(ItemStack item, int durability, @Nullable ArmorTier providedTier) + { + final ArmorTier currentTier = providedTier == null ? nbtEditor.getArmorTier(item) : providedTier; + final int rawDurability = getRemappedDurability(durability, getMaxDurability(currentTier), + ELYTRA_MAX_DURABILITY); + nbtEditor.updateDurability(item, durability, rawDurability); + } + + /** + * Sets the real durability NBT data for armored elytras that do not have it. + *

+ * The real durability is calculated from the current 'raw' durability. The real durability will be the same + * percentage of the max durability for the type as the raw durability is of an elytra's maximum durability. + * + * @param armoredElytra The armored elytra to upgrade to an armored elytra with durability. + * @param currentTier The current tier of the armored elytra. + * @return The real durability of the armored elytra. + */ + private int upgradeArmoredElytraToDurability(ItemStack armoredElytra, ArmorTier currentTier) + { + final int maxDurability = getMaxDurability(currentTier); + //noinspection deprecation + final int rawDurability = armoredElytra.getDurability(); + + final int realDurability = maxDurability == ELYTRA_MAX_DURABILITY ? + rawDurability : + getRemappedDurability(rawDurability, ELYTRA_MAX_DURABILITY, maxDurability); + + nbtEditor.updateDurability(armoredElytra, realDurability, rawDurability); + return realDurability; + } + + /** + * Gets the maximum durability for an armor tier. This may or may not be {@link + * ArmorTier#getMaxDurability(ArmorTier)} depending on {@link ConfigLoader#useTierDurability()}. + * + * @param armorTier The armor tier for which to figure out the maximum durability. + * @return The maximum durability of the armor tier. + */ + private int calculateMaxDurability(ArmorTier armorTier) + { + if (armorTier == ArmorTier.NONE || !config.useTierDurability()) + return ELYTRA_MAX_DURABILITY; + return ArmorTier.getMaxDurability(armorTier); + } + + /** + * Gets the maximum durability for a given armor tier. + * + * @param armorTier The armor tier for which to get the maximum durability. + * @return The maximum durability of the given armor tier. + */ + private int getMaxDurability(ArmorTier armorTier) + { + return maxDurabilities[armorTier.ordinal()]; + } + + /** + * Gets the amount of durability restored per repair step for a given armor tier. + * + * @param armorTier The armor tier. + * @return The amount of durability restored per repair step for the given armor tier. + */ + private int getRepairSteps(ArmorTier armorTier) + { + return repairSteps[armorTier.ordinal()]; + } + + /** + * Remaps a durability value from an old maximum value to a new maximum while maintaining the same durability + * percentage. + * + * @param durability The current durability value. + * @param oldMax The old maximum durability. + * @param newMax The new maximum durability. + * @return The new durability value after remapping it to the new maximum. The value cannot be less than 0 or more + * than newMax. + */ + private int getRemappedDurability(int durability, int oldMax, int newMax) + { + final float relativeDurability = (float) durability / oldMax; + return Util.between((int) Math.ceil(relativeDurability * newMax), 0, newMax); + } + + /** + * Initializes the {@link #maxDurabilities} and {@link #repairSteps} arrays. + */ + private void init() + { + repairSteps[0] = 0; + maxDurabilities[0] = ELYTRA_MAX_DURABILITY; + + final ArmorTier[] armorTiers = ArmorTier.values(); + for (int idx = 1; idx < armorTiers.length; ++idx) + { + final ArmorTier armorTier = armorTiers[idx]; + + final int maxDurability = calculateMaxDurability(armorTier); + maxDurabilities[idx] = maxDurability; + + final int steps = Math.max(1, config.getFullRepairItemCount(armorTier)); + repairSteps[idx] = (int) Math.ceil((float) maxDurability / steps); + } + } +} diff --git a/src/main/java/nl/pim16aap2/armoredElytra/handlers/AnvilHandler.java b/src/main/java/nl/pim16aap2/armoredElytra/handlers/AnvilHandler.java index 41f8351..2312632 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/handlers/AnvilHandler.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/handlers/AnvilHandler.java @@ -1,6 +1,7 @@ package nl.pim16aap2.armoredElytra.handlers; import nl.pim16aap2.armoredElytra.ArmoredElytra; +import nl.pim16aap2.armoredElytra.DurabilityManager; import nl.pim16aap2.armoredElytra.nbtEditor.INBTEditor; import nl.pim16aap2.armoredElytra.util.Action; import nl.pim16aap2.armoredElytra.util.ArmorTier; @@ -28,12 +29,14 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener { private final ConfigLoader configLoader; private final INBTEditor nbtEditor; + private final DurabilityManager durabilityManager; public AnvilHandler(final ArmoredElytra plugin, final boolean creationEnabled) { super(plugin, creationEnabled); configLoader = plugin.getConfigLoader(); nbtEditor = plugin.getNbtEditor(); + durabilityManager = new DurabilityManager(nbtEditor, configLoader); } public AnvilHandler(final ArmoredElytra plugin) @@ -46,7 +49,7 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener // - Elytra (armored) + enchanted book -> Enchant // - Elytra (armored) + its repair item -> Repair // - Elytra (armored) + other elytra (armored) -> Combine (Enchant + Repair) - // ! Elytra (armored, !leather) + leather/membrane -> Block + // - Elytra (armored, !leather) + leather/membrane -> Block // // Ignoring: // - Elytra (not armored) + !chestplate -> None @@ -56,14 +59,6 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener if (itemOne == null || itemTwo == null) return Action.NONE; - // If itemTwo is the elytra, while itemOne isn't, switch itemOne and itemTwo. - if (itemTwo.getType() == Material.ELYTRA && itemOne.getType() != Material.ELYTRA) - { - ItemStack tmp = itemOne; - itemOne = itemTwo; - itemTwo = tmp; - } - if (itemOne.getType() != Material.ELYTRA) return Action.NONE; @@ -83,10 +78,9 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener // If the armored elytra is to be repaired using its repair item... if (ArmorTier.getRepairItem(tier) == matTwo) - return itemOne.getDurability() == 0 ? Action.NONE : Action.REPAIR; + return itemOne.getDurability() == 0 ? Action.BLOCK : Action.REPAIR; - // If the armored elytra is to be combined with another armored elytra of the - // same tier... + // If the armored elytra is to be combined with another armored elytra of the same tier... if (nbtEditor.getArmorTier(itemTwo) == tier) return creationEnabled ? Action.COMBINE : Action.NONE; @@ -101,13 +95,13 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener } // Handle all anvil related stuff for this plugin. - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOWEST) private void onAnvilInventoryOpen(PrepareAnvilEvent event) { Player player = (Player) event.getView().getPlayer(); ItemStack itemA = event.getInventory().getItem(0); ItemStack itemB = event.getInventory().getItem(1); - ItemStack result = null; + ItemStack result; if (itemA != null && itemB != null) // If itemB is the (armored) elytra, while itemA isn't, switch itemA and itemB. @@ -121,37 +115,36 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener // Check if there are items in both input slots. if (itemA != null && itemB != null) { - Action action = isValidInput(itemA, itemB); + final Action action = isValidInput(itemA, itemB); ArmorTier newTier = ArmorTier.NONE; - ArmorTier curTier = nbtEditor.getArmorTier(itemA); - short durability = 0; + final ArmorTier curTier = nbtEditor.getArmorTier(itemA); + + int newDurability = 0; EnchantmentContainer enchantments = EnchantmentContainer.getEnchantments(itemA, plugin); switch (action) { case REPAIR: newTier = curTier; - durability = repairItem(itemA.getDurability(), itemB); + newDurability = durabilityManager.getRepairedDurability(itemA, itemB.getAmount(), curTier); break; case COMBINE: newTier = curTier; - durability = (short) (-itemA.getType().getMaxDurability() - itemA.getDurability() - - itemB.getDurability()); - durability = durability < 0 ? 0 : durability; + newDurability = durabilityManager.getCombinedDurability(itemA, itemB, curTier, newTier); enchantments.merge(EnchantmentContainer.getEnchantments(itemB, plugin)); break; case CREATE: newTier = Util.armorToTier(itemB.getType()); - durability = 0; + newDurability = durabilityManager.getCombinedDurability(itemA, itemB, curTier, newTier); enchantments.merge(EnchantmentContainer.getEnchantments(itemB, plugin)); break; case ENCHANT: newTier = curTier; - durability = itemA.getDurability(); + newDurability = durabilityManager.getRealDurability(itemA, newTier); // If there aren't any illegal enchantments on the book, continue as normal. // Otherwise... Block. - EnchantmentContainer enchantmentsB = EnchantmentContainer.getEnchantments(itemB, plugin); + final EnchantmentContainer enchantmentsB = EnchantmentContainer.getEnchantments(itemB, plugin); if (enchantmentsB.getEnchantmentCount() > 0) { enchantments.merge(enchantmentsB); @@ -170,7 +163,7 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener { result = new ItemStack(Material.ELYTRA, 1); enchantments.applyEnchantments(result); - result.setDurability(durability); + durabilityManager.setDurability(result, newDurability, newTier); final String name = getElytraResultName(itemA, action, newTier, event.getInventory().getRenameText()); final Color color = getItemColor(itemA, itemB); @@ -183,7 +176,7 @@ public class AnvilHandler extends ArmoredElytraHandler implements Listener } // If one of the input items is null and the other an armored elytra, remove the result. - // This prevent some naming issues. + // This prevents some naming issues. if ((itemA == null ^ itemB == null) && nbtEditor.getArmorTier(itemA == null ? itemB : itemA) != ArmorTier.NONE) event.setResult(null); diff --git a/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/INBTEditor.java b/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/INBTEditor.java index 2731678..6c1449b 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/INBTEditor.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/INBTEditor.java @@ -4,6 +4,7 @@ import nl.pim16aap2.armoredElytra.ArmoredElytra; import nl.pim16aap2.armoredElytra.util.ArmorTier; import org.bukkit.Color; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import javax.annotation.Nullable; import java.util.List; @@ -99,7 +100,7 @@ public interface INBTEditor * @param item The item to check. * @return The {@link ArmorTier} that is on the item. If none is found, {@link ArmorTier#NONE} is returned. */ - ArmorTier getArmorTier(ItemStack item); + ArmorTier getArmorTier(@Nullable ItemStack item); /** * Gets the Color of an armored elytra. @@ -107,7 +108,34 @@ public interface INBTEditor * If the provided {@link ItemStack} is not an AE, null is returned. * * @param item The armored elytra to check. - * @return The color of the armored elytra, if the input is a color armored elytra, otherwise null. + * @return The color of the armored elytra, if the input is a colored armored elytra, otherwise null. */ - Color getColorOfArmoredElytra(ItemStack item); + Color getColorOfArmoredElytra(@Nullable ItemStack item); + + /** + * Updates the durability values of an item. + * + * @param itemStack The itemstack to which the durability values will be applied. + * @param realDurability The real durability to store in NBT. + * @param displayDurability The durability value to display on the item. This is the durability value the client can + * actually see.This only works if the item's meta is an instance of {@link Damageable}. + */ + void updateDurability(ItemStack itemStack, int realDurability, int displayDurability); + + /** + * Gets the real durability value as stored in the NBT of an armored elytra. + * + * @param itemStack The item for which to retrieve the real durability. + * @param armorTier The armor tier of the armored elytra. If this is null, it will be retrieved from NBT. + * @return The real durability of the itemstack if the itemstack has the AE durability attribute, or -1 otherwise. + */ + int getRealDurability(ItemStack itemStack, @Nullable ArmorTier armorTier); + + /** + * See {@link #getRealDurability(ItemStack, ArmorTier)}. + */ + default int getRealDurability(ItemStack itemStack) + { + return getRealDurability(itemStack, null); + } } diff --git a/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java b/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java index 8368a76..27eec03 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/nbtEditor/NBTEditor.java @@ -10,6 +10,7 @@ import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataContainer; import org.bukkit.persistence.PersistentDataType; @@ -17,14 +18,48 @@ import org.bukkit.persistence.PersistentDataType; import javax.annotation.Nullable; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.UUID; public class NBTEditor implements INBTEditor { - private static final NamespacedKey armorTierKey = new NamespacedKey(ArmoredElytra.getInstance(), - "ARMOR_TIER_LEVEL"); - private static final NamespacedKey armorColorKey = new NamespacedKey(ArmoredElytra.getInstance(), - "ARMORED_ELYTRA_COLOR"); + private static final NamespacedKey ARMOR_TIER_KEY = new NamespacedKey(ArmoredElytra.getInstance(), + "ARMOR_TIER_LEVEL"); + private static final NamespacedKey ARMOR_COLOR_KEY = new NamespacedKey(ArmoredElytra.getInstance(), + "ARMORED_ELYTRA_COLOR"); + private static final NamespacedKey DURABILITY_KEY = new NamespacedKey(ArmoredElytra.getInstance(), + "ARMORED_ELYTRA_DURABILITY"); + + @Override + public int getRealDurability(ItemStack itemStack, @Nullable ArmorTier providedTier) + { + final @Nullable ItemMeta meta = itemStack.getItemMeta(); + final ArmorTier armorTier = providedTier == null ? getArmorTier(meta) : providedTier; + + if (armorTier == ArmorTier.NONE) + return -1; + + if (!(meta instanceof Damageable)) + throw new IllegalStateException("Item \"" + itemStack + "\" with meta \"" + meta + "\" is not Damageable!"); + + final @Nullable Integer realDurability = + Objects.requireNonNull(meta, "Meta cannot be null for armored elytras!") + .getPersistentDataContainer().get(DURABILITY_KEY, PersistentDataType.INTEGER); + + return realDurability == null ? -1 : realDurability; + } + + @Override + public void updateDurability(ItemStack itemStack, int realDurability, int displayDurability) + { + final ItemMeta meta = getOrCreateItemMeta(itemStack); + meta.getPersistentDataContainer().set(DURABILITY_KEY, PersistentDataType.INTEGER, realDurability); + + if (meta instanceof Damageable) + ((Damageable) meta).setDamage(displayDurability); + + itemStack.setItemMeta(meta); + } @Override public ItemStack addArmorNBTTags(ItemStack item, ArmorTier armorTier, boolean unbreakable, String name, @@ -33,14 +68,13 @@ public class NBTEditor implements INBTEditor if (armorTier == null || armorTier == ArmorTier.NONE) return new ItemStack(item); - ItemStack ret = new ItemStack(item); - ItemMeta meta = ret.hasItemMeta() ? ret.getItemMeta() : Bukkit.getItemFactory().getItemMeta(ret.getType()); - if (meta == null) - throw new IllegalArgumentException("Tried to add armor to invalid item: " + item); - meta.getPersistentDataContainer().set(armorTierKey, PersistentDataType.INTEGER, ArmorTier.getTierID(armorTier)); + final ItemStack ret = new ItemStack(item); + final ItemMeta meta = getOrCreateItemMeta(ret); + meta.getPersistentDataContainer().set(ARMOR_TIER_KEY, PersistentDataType.INTEGER, + ArmorTier.getTierID(armorTier)); if (color != null && armorTier == ArmorTier.LEATHER) - meta.getPersistentDataContainer().set(armorColorKey, PersistentDataType.INTEGER, color.asRGB()); + meta.getPersistentDataContainer().set(ARMOR_COLOR_KEY, PersistentDataType.INTEGER, color.asRGB()); overwriteNBTValue(meta, Attribute.GENERIC_ARMOR, ArmorTier.getArmor(armorTier), "generic.armor"); if (ArmorTier.getToughness(armorTier) > 0) @@ -65,33 +99,29 @@ public class NBTEditor implements INBTEditor if (meta.hasAttributeModifiers()) meta.removeAttributeModifier(attribute); - AttributeModifier attributeModifier = new AttributeModifier(UUID.randomUUID(), modifierName, value, - AttributeModifier.Operation.ADD_NUMBER, - EquipmentSlot.CHEST); + final AttributeModifier attributeModifier = new AttributeModifier(UUID.randomUUID(), modifierName, value, + AttributeModifier.Operation.ADD_NUMBER, + EquipmentSlot.CHEST); meta.addAttributeModifier(attribute, attributeModifier); } - @Override - public ArmorTier getArmorTier(ItemStack item) + private ArmorTier getArmorTier(@Nullable ItemMeta meta) { - if (item == null) - return ArmorTier.NONE; - - ItemMeta meta = item.getItemMeta(); if (meta == null || !meta.hasAttributeModifiers()) return ArmorTier.NONE; - Integer tierID = meta.getPersistentDataContainer().get(armorTierKey, PersistentDataType.INTEGER); + final @Nullable Integer tierID = meta.getPersistentDataContainer() + .get(ARMOR_TIER_KEY, PersistentDataType.INTEGER); if (tierID != null) return ArmorTier.getArmorTierFromID(tierID); - Collection attributeModifiers = meta.getAttributeModifiers(Attribute.GENERIC_ARMOR); + final Collection attributeModifiers = meta.getAttributeModifiers(Attribute.GENERIC_ARMOR); if (attributeModifiers == null) return ArmorTier.NONE; for (final AttributeModifier attributeModifier : attributeModifiers) { - ArmorTier armorTier = ArmorTier.getArmorTierFromArmor((int) attributeModifier.getAmount()); + final ArmorTier armorTier = ArmorTier.getArmorTierFromArmor((int) attributeModifier.getAmount()); if (armorTier != ArmorTier.NONE) return armorTier; } @@ -100,7 +130,15 @@ public class NBTEditor implements INBTEditor } @Override - public Color getColorOfArmoredElytra(final ItemStack item) + public ArmorTier getArmorTier(@Nullable ItemStack item) + { + if (item == null) + return ArmorTier.NONE; + return getArmorTier(item.getItemMeta()); + } + + @Override + public Color getColorOfArmoredElytra(@Nullable ItemStack item) { if (item == null || item.getType() != Material.ELYTRA || !item.hasItemMeta()) return null; @@ -110,10 +148,20 @@ public class NBTEditor implements INBTEditor return null; final PersistentDataContainer container = meta.getPersistentDataContainer(); - if (!container.has(armorColorKey, PersistentDataType.INTEGER)) + if (!container.has(ARMOR_COLOR_KEY, PersistentDataType.INTEGER)) return null; - final Integer rgb = container.get(armorColorKey, PersistentDataType.INTEGER); + final Integer rgb = container.get(ARMOR_COLOR_KEY, PersistentDataType.INTEGER); return rgb == null ? null : Color.fromRGB(rgb); } + + private static ItemMeta getOrCreateItemMeta(ItemStack item) + { + final ItemMeta meta = item.hasItemMeta() ? + item.getItemMeta() : + Bukkit.getItemFactory().getItemMeta(item.getType()); + if (meta == null) + throw new IllegalArgumentException("Tried to add armor to invalid item: " + item); + return meta; + } } diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/Action.java b/src/main/java/nl/pim16aap2/armoredElytra/util/Action.java index a9bd2a4..e3bb55c 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/Action.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/Action.java @@ -2,5 +2,33 @@ package nl.pim16aap2.armoredElytra.util; public enum Action { - NONE, REPAIR, ENCHANT, COMBINE, CREATE, BLOCK + /** + * Take no action at all and let vanilla (or some other plugin) handle the process. + */ + NONE, + + /** + * Repair an armored elytra. + */ + REPAIR, + + /** + * Enchant an armored elytra. + */ + ENCHANT, + + /** + * Combines one armored elytra with another one of the same tier. + */ + COMBINE, + + /** + * Creates a new armored elytra. + */ + CREATE, + + /** + * Blocks an otherwise valid input. + */ + BLOCK } diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTier.java b/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTier.java index e20ac62..d3e6d62 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTier.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/ArmorTier.java @@ -29,8 +29,8 @@ public enum ArmorTier private static final Map armorValueMap = new HashMap<>(); private static final Map armorIDMap = new HashMap<>(); - ArmorTier(int tierID, int armor, int toughness, double knockbackResistance, Material repair, int defaultRepairCount, - String name, int durability) + ArmorTier(int tierID, int armor, int toughness, double knockbackResistance, Material repair, + int defaultRepairCount, String name, int durability) { this.tierID = tierID; this.armor = armor; diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java b/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java index 6bbb353..6c0ab2e 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java @@ -73,7 +73,8 @@ public class ConfigLoader String[] repairComment = { "Amount of items it takes to fully repair an armored elytra", - "Repair cost for every tier of armored elytra in number of items to repair 100%." + "Repair cost for every tier of armored elytra in number of items to repair 100%.", + "Note that this value cannot be less than 1." }; String[] enchantmentsComment = { @@ -328,7 +329,7 @@ public class ConfigLoader public int getFullRepairItemCount(ArmorTier armorTier) { - return repairCounts[ArmorTier.getArmor(armorTier)]; + return repairCounts[armorTier.ordinal()]; } public boolean allowMultipleProtectionEnchantments() diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/Util.java b/src/main/java/nl/pim16aap2/armoredElytra/util/Util.java index 7acaa57..8e15057 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/Util.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/Util.java @@ -137,4 +137,17 @@ public class Util ret += 16; return ret; } + + /** + * Ensures that a given value does not exceed the provided upper and lower bounds. + * + * @param val The value to check. + * @param min The lower bound limit. + * @param max The upper bound limit. + * @return The value if it is bigger than min and larger than max, otherwise either min or max. + */ + public static int between(int val, int min, int max) + { + return Math.max(min, Math.min(max, val)); + } }