From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: William Blake Galbreath Date: Sun, 15 Mar 2020 20:52:12 -0500 Subject: [PATCH] ItemStack convenience methods diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java index 54704da43cf9c429f3914f0580246dde99aa93c0..e1a677cfde05aba487a09e34e170fea61a125e7d 100644 --- a/src/main/java/org/bukkit/Material.java +++ b/src/main/java/org/bukkit/Material.java @@ -5622,4 +5622,40 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla } return Registry.BLOCK.get(material.key); } + + // Purpur start + public boolean isArmor() { + switch (this) { + // + case LEATHER_BOOTS: + case LEATHER_CHESTPLATE: + case LEATHER_HELMET: + case LEATHER_LEGGINGS: + case CHAINMAIL_BOOTS: + case CHAINMAIL_CHESTPLATE: + case CHAINMAIL_HELMET: + case CHAINMAIL_LEGGINGS: + case IRON_BOOTS: + case IRON_CHESTPLATE: + case IRON_HELMET: + case IRON_LEGGINGS: + case GOLDEN_BOOTS: + case GOLDEN_CHESTPLATE: + case GOLDEN_HELMET: + case GOLDEN_LEGGINGS: + case DIAMOND_BOOTS: + case DIAMOND_CHESTPLATE: + case DIAMOND_HELMET: + case DIAMOND_LEGGINGS: + case NETHERITE_BOOTS: + case NETHERITE_CHESTPLATE: + case NETHERITE_HELMET: + case NETHERITE_LEGGINGS: + case TURTLE_HELMET: + return true; + default: + return false; + } + } + // Purpur end } diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java index 8bbd98ea729755e7666403b96f277fd419560951..cb37a8af9e54349fc8a3eb70bbe2fddaaa3767d6 100644 --- a/src/main/java/org/bukkit/inventory/ItemStack.java +++ b/src/main/java/org/bukkit/inventory/ItemStack.java @@ -19,6 +19,17 @@ import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.material.MaterialData; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +// Purpur start +import com.google.common.collect.Multimap; +import java.util.Collection; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.meta.BlockDataMeta; +import org.bukkit.inventory.meta.Repairable; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataHolder; +// Purpur end /** * Represents a stack of items. @@ -1033,4 +1044,551 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat return Bukkit.getUnsafe().computeTooltipLines(this, tooltipContext, player); } // Paper end - expose itemstack tooltip lines + + // Purpur start + /** + * Gets the display name that is set. + *

+ * Plugins should check that hasDisplayName() returns true + * before calling this method. + * + * @return the display name that is set + */ + @NotNull + public String getDisplayName() { + return getItemMeta().getDisplayName(); + } + + /** + * Sets the display name. + * + * @param name the name to set + */ + public void setDisplayName(@Nullable String name) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setDisplayName(name); + setItemMeta(itemMeta); + } + + /** + * Checks for existence of a display name. + * + * @return true if this has a display name + */ + public boolean hasDisplayName() { + return hasItemMeta() && getItemMeta().hasDisplayName(); + } + + /** + * Gets the localized display name that is set. + *

+ * Plugins should check that hasLocalizedName() returns true + * before calling this method. + * + * @return the localized name that is set + */ + @NotNull + public String getLocalizedName() { + return getItemMeta().getLocalizedName(); + } + + /** + * Sets the localized name. + * + * @param name the name to set + */ + public void setLocalizedName(@Nullable String name) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setLocalizedName(name); + setItemMeta(itemMeta); + } + + /** + * Checks for existence of a localized name. + * + * @return true if this has a localized name + */ + public boolean hasLocalizedName() { + return hasItemMeta() && getItemMeta().hasLocalizedName(); + } + + /** + * Checks for existence of lore. + * + * @return true if this has lore + */ + public boolean hasLore() { + return hasItemMeta() && getItemMeta().hasLore(); + } + + /** + * Checks for existence of the specified enchantment. + * + * @param ench enchantment to check + * @return true if this enchantment exists for this meta + */ + public boolean hasEnchant(@NotNull Enchantment ench) { + return hasItemMeta() && getItemMeta().hasEnchant(ench); + } + + /** + * Checks for the level of the specified enchantment. + * + * @param ench enchantment to check + * @return The level that the specified enchantment has, or 0 if none + */ + public int getEnchantLevel(@NotNull Enchantment ench) { + return getItemMeta().getEnchantLevel(ench); + } + + /** + * Returns a copy the enchantments in this ItemMeta.
+ * Returns an empty map if none. + * + * @return An immutable copy of the enchantments + */ + @NotNull + public Map getEnchants() { + return getItemMeta().getEnchants(); + } + + /** + * Adds the specified enchantment to this item meta. + * + * @param ench Enchantment to add + * @param level Level for the enchantment + * @param ignoreLevelRestriction this indicates the enchantment should be + * applied, ignoring the level limit + * @return true if the item meta changed as a result of this call, false + * otherwise + */ + public boolean addEnchant(@NotNull Enchantment ench, int level, boolean ignoreLevelRestriction) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.addEnchant(ench, level, ignoreLevelRestriction); + setItemMeta(itemMeta); + return result; + } + + /** + * Removes the specified enchantment from this item meta. + * + * @param ench Enchantment to remove + * @return true if the item meta changed as a result of this call, false + * otherwise + */ + public boolean removeEnchant(@NotNull Enchantment ench) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeEnchant(ench); + setItemMeta(itemMeta); + return result; + } + + /** + * Checks for the existence of any enchantments. + * + * @return true if an enchantment exists on this meta + */ + public boolean hasEnchants() { + return hasItemMeta() && getItemMeta().hasEnchants(); + } + + /** + * Checks if the specified enchantment conflicts with any enchantments in + * this ItemMeta. + * + * @param ench enchantment to test + * @return true if the enchantment conflicts, false otherwise + */ + public boolean hasConflictingEnchant(@NotNull Enchantment ench) { + return hasItemMeta() && getItemMeta().hasConflictingEnchant(ench); + } + + /** + * Sets the custom model data. + *

+ * CustomModelData is an integer that may be associated client side with a + * custom item model. + * + * @param data the data to set, or null to clear + */ + public void setCustomModelData(@Nullable Integer data) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setCustomModelData(data); + setItemMeta(itemMeta); + } + + /** + * Gets the custom model data that is set. + *

+ * CustomModelData is an integer that may be associated client side with a + * custom item model. + *

+ * Plugins should check that hasCustomModelData() returns true + * before calling this method. + * + * @return the localized name that is set + */ + public int getCustomModelData() { + return getItemMeta().getCustomModelData(); + } + + /** + * Checks for existence of custom model data. + *

+ * CustomModelData is an integer that may be associated client side with a + * custom item model. + * + * @return true if this has custom model data + */ + public boolean hasCustomModelData() { + return hasItemMeta() && getItemMeta().hasCustomModelData(); + } + + /** + * Returns whether the item has block data currently attached to it. + * + * @return whether block data is already attached + */ + public boolean hasBlockData() { + return hasItemMeta() && ((BlockDataMeta) getItemMeta()).hasBlockData(); + } + + /** + * Returns the currently attached block data for this item or creates a new + * one if one doesn't exist. + * + * The state is a copy, it must be set back (or to another item) with + * {@link #setBlockData(BlockData)} + * + * @param material the material we wish to get this data in the context of + * @return the attached data or new data + */ + @NotNull + public BlockData getBlockData(@NotNull Material material) { + return ((BlockDataMeta) getItemMeta()).getBlockData(material); + } + + /** + * Attaches a copy of the passed block data to the item. + * + * @param blockData the block data to attach to the block. + * @throws IllegalArgumentException if the blockData is null or invalid for + * this item. + */ + public void setBlockData(@NotNull BlockData blockData) { + ItemMeta itemMeta = getItemMeta(); + ((BlockDataMeta) itemMeta).setBlockData(blockData); + setItemMeta(itemMeta); + } + + /** + * Gets the repair penalty + * + * @return the repair penalty + */ + public int getRepairCost() { + return ((Repairable) getItemMeta()).getRepairCost(); + } + + /** + * Sets the repair penalty + * + * @param cost repair penalty + */ + public void setRepairCost(int cost) { + ItemMeta itemMeta = getItemMeta(); + ((Repairable) itemMeta).setRepairCost(cost); + setItemMeta(itemMeta); + } + + /** + * Checks to see if this has a repair penalty + * + * @return true if this has a repair penalty + */ + public boolean hasRepairCost() { + return hasItemMeta() && ((Repairable) getItemMeta()).hasRepairCost(); + } + + /** + * Return if the unbreakable tag is true. An unbreakable item will not lose + * durability. + * + * @return true if the unbreakable tag is true + */ + public boolean isUnbreakable() { + return hasItemMeta() && getItemMeta().isUnbreakable(); + } + + /** + * Sets the unbreakable tag. An unbreakable item will not lose durability. + * + * @param unbreakable true if set unbreakable + */ + public void setUnbreakable(boolean unbreakable) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setUnbreakable(unbreakable); + setItemMeta(itemMeta); + } + + /** + * Checks for the existence of any AttributeModifiers. + * + * @return true if any AttributeModifiers exist + */ + public boolean hasAttributeModifiers() { + return hasItemMeta() && getItemMeta().hasAttributeModifiers(); + } + + /** + * Return an immutable copy of all Attributes and + * their modifiers in this ItemMeta.
+ * Returns null if none exist. + * + * @return an immutable {@link Multimap} of Attributes + * and their AttributeModifiers, or null if none exist + */ + @Nullable + public Multimap getAttributeModifiers() { + return getItemMeta().getAttributeModifiers(); + } + + /** + * Return an immutable copy of all {@link Attribute}s and their + * {@link AttributeModifier}s for a given {@link EquipmentSlot}.
+ * Any {@link AttributeModifier} that does have have a given + * {@link EquipmentSlot} will be returned. This is because + * AttributeModifiers without a slot are active in any slot.
+ * If there are no attributes set for the given slot, an empty map + * will be returned. + * + * @param slot the {@link EquipmentSlot} to check + * @return the immutable {@link Multimap} with the + * respective Attributes and modifiers, or an empty map + * if no attributes are set. + */ + @NotNull + public Multimap getAttributeModifiers(@Nullable EquipmentSlot slot) { + return getItemMeta().getAttributeModifiers(slot); + } + + /** + * Return an immutable copy of all {@link AttributeModifier}s + * for a given {@link Attribute} + * + * @param attribute the {@link Attribute} + * @return an immutable collection of {@link AttributeModifier}s + * or null if no AttributeModifiers exist for the Attribute. + * @throws NullPointerException if Attribute is null + */ + @Nullable + public Collection getAttributeModifiers(@NotNull Attribute attribute) { + return getItemMeta().getAttributeModifiers(attribute); + } + + /** + * Add an Attribute and it's Modifier. + * AttributeModifiers can now support {@link EquipmentSlot}s. + * If not set, the {@link AttributeModifier} will be active in ALL slots. + *
+ * Two {@link AttributeModifier}s that have the same {@link java.util.UUID} + * cannot exist on the same Attribute. + * + * @param attribute the {@link Attribute} to modify + * @param modifier the {@link AttributeModifier} specifying the modification + * @return true if the Attribute and AttributeModifier were + * successfully added + * @throws NullPointerException if Attribute is null + * @throws NullPointerException if AttributeModifier is null + * @throws IllegalArgumentException if AttributeModifier already exists + */ + public boolean addAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.addAttributeModifier(attribute, modifier); + setItemMeta(itemMeta); + return result; + } + + /** + * Set all {@link Attribute}s and their {@link AttributeModifier}s. + * To clear all currently set Attributes and AttributeModifiers use + * null or an empty Multimap. + * If not null nor empty, this will filter all entries that are not-null + * and add them to the ItemStack. + * + * @param attributeModifiers the new Multimap containing the Attributes + * and their AttributeModifiers + */ + public void setAttributeModifiers(@Nullable Multimap attributeModifiers) { + ItemMeta itemMeta = getItemMeta(); + itemMeta.setAttributeModifiers(attributeModifiers); + setItemMeta(itemMeta); + } + + /** + * Remove all {@link AttributeModifier}s associated with the given + * {@link Attribute}. + * This will return false if nothing was removed. + * + * @param attribute attribute to remove + * @return true if all modifiers were removed from a given + * Attribute. Returns false if no attributes were + * removed. + * @throws NullPointerException if Attribute is null + */ + public boolean removeAttributeModifier(@NotNull Attribute attribute) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeAttributeModifier(attribute); + setItemMeta(itemMeta); + return result; + } + + /** + * Remove all {@link Attribute}s and {@link AttributeModifier}s for a + * given {@link EquipmentSlot}.
+ * If the given {@link EquipmentSlot} is null, this will remove all + * {@link AttributeModifier}s that do not have an EquipmentSlot set. + * + * @param slot the {@link EquipmentSlot} to clear all Attributes and + * their modifiers for + * @return true if all modifiers were removed that match the given + * EquipmentSlot. + */ + public boolean removeAttributeModifier(@Nullable EquipmentSlot slot) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeAttributeModifier(slot); + setItemMeta(itemMeta); + return result; + } + + /** + * Remove a specific {@link Attribute} and {@link AttributeModifier}. + * AttributeModifiers are matched according to their {@link java.util.UUID}. + * + * @param attribute the {@link Attribute} to remove + * @param modifier the {@link AttributeModifier} to remove + * @return if any attribute modifiers were remove + * + * @throws NullPointerException if the Attribute is null + * @throws NullPointerException if the AttributeModifier is null + * + * @see AttributeModifier#getUniqueId() + */ + public boolean removeAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) { + ItemMeta itemMeta = getItemMeta(); + boolean result = itemMeta.removeAttributeModifier(attribute, modifier); + setItemMeta(itemMeta); + return result; + } + + /** + * Checks to see if this item has damage + * + * @return true if this has damage + */ + public boolean hasDamage() { + return hasItemMeta() && ((Damageable) getItemMeta()).hasDamage(); + } + + /** + * Gets the damage + * + * @return the damage + */ + public int getDamage() { + return ((Damageable) getItemMeta()).getDamage(); + } + + /** + * Sets the damage + * + * @param damage item damage + */ + public void setDamage(int damage) { + ItemMeta itemMeta = getItemMeta(); + ((Damageable) itemMeta).setDamage(damage); + setItemMeta(itemMeta); + } + + /** + * Repairs this item by 1 durability + */ + public void repair() { + repair(1); + } + + /** + * Damages this item by 1 durability + * + * @return True if damage broke the item + */ + public boolean damage() { + return damage(1); + } + + /** + * Repairs this item's durability by amount + * + * @param amount Amount of durability to repair + */ + public void repair(int amount) { + damage(-amount); + } + + /** + * Damages this item's durability by amount + * + * @param amount Amount of durability to damage + * @return True if damage broke the item + */ + public boolean damage(int amount) { + return damage(amount, false); + } + + /** + * Damages this item's durability by amount + * + * @param amount Amount of durability to damage + * @param ignoreUnbreaking Ignores unbreaking enchantment + * @return True if damage broke the item + */ + public boolean damage(int amount, boolean ignoreUnbreaking) { + Damageable damageable = (Damageable) getItemMeta(); + if (amount > 0) { + int unbreaking = getEnchantLevel(Enchantment.UNBREAKING); + int reduce = 0; + for (int i = 0; unbreaking > 0 && i < amount; ++i) { + if (reduceDamage(java.util.concurrent.ThreadLocalRandom.current(), unbreaking)) { + ++reduce; + } + } + amount -= reduce; + if (amount <= 0) { + return isBroke(damageable.getDamage()); + } + } + int damage = damageable.getDamage() + amount; + damageable.setDamage(damage); + setItemMeta((ItemMeta) damageable); + return isBroke(damage); + } + + public boolean isBroke(int damage) { + if (damage > getType().getMaxDurability()) { + if (getAmount() > 0) { + // ensure it "breaks" + setAmount(0); + } + return true; + } + return false; + } + + private boolean reduceDamage(java.util.Random random, int unbreaking) { + if (getType().isArmor()) { + return random.nextFloat() < 0.6F; + } + return random.nextInt(unbreaking + 1) > 0; + } + // Purpur end }