Files
Purpur/patches/api/0018-ItemStack-convenience-methods.patch
BillyGalbreath d93887a156 Updated Upstream (Paper)
Upstream has released updates that appear to apply and compile correctly

Paper Changes:
5b20df6bf added PlayerNameEntityEvent
ff9c82444 Add worldborder events
616b1f3cd consider enchants for destroy speed
aaef1d5cc fix file conversion
674d8f7f7 Make discovered maps config work in treasure maps from loot tables too
be1687914 stop firing pressure plate EntityInteractEvent for ignored entities (fixes #4962)
7d56f38ed Do not use the bukkit singleton for the GUI (Fixes #5301)
4c9bdf53a Updated Upstream (Bukkit/CraftBukkit/Spigot) (#5299)
8647bd130 Improve ServerGUI
fcc6d3359 Throw proper exception on empty JsonList file
17d2e1291 Fix interact event in adventure mode
964e0bf42 MC-29274: Fix Wither hostility towards players
9e24a5213 Fixed furnace cook-speed multiplier losing precision when calculating cook time
c7e42faa3 Do not create unnecessary copies of the passenger list
40881ad67 added tnt minecarts to the tnt height nerf
26be708f4 Remove streams from SensorNearest
5b5989b21 fix nullability of playerlist header/footer, closes #5290
45bc531dd Fix Material#getTranslationKey for Block Materials (#5294)
2021-03-04 21:45:44 -06:00

699 lines
23 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: William Blake Galbreath <Blake.Galbreath@GMail.com>
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 7b77c7132723a01e8c38ddaa616b363be300b653..c6b1131b1700797e0515045f4e5c81f85aa3449f 100644
--- a/src/main/java/org/bukkit/Material.java
+++ b/src/main/java/org/bukkit/Material.java
@@ -8649,4 +8649,36 @@ public enum Material implements Keyed {
// </editor-fold>
}
}
+
+ // Purpur start
+ public boolean isArmor() {
+ switch (this) {
+ // <editor-fold defaultstate="collapsed" desc="isarmor">
+ 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 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 7531fc910ed65dc12e242cf5042ce4cef9fe661d..890a37ebd79e770114ea188a0a5d9d2e27542911 100644
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
@@ -17,6 +17,18 @@ 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;
+import com.destroystokyo.paper.Namespaced;
+// Purpur end
/**
* Represents a stack of items.
@@ -798,4 +810,627 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, net.kyor
return itemMeta.hasItemFlag(flag);
}
// Paper end
+
+ // Purpur start
+ /**
+ * Gets the display name that is set.
+ * <p>
+ * Plugins should check that hasDisplayName() returns <code>true</code>
+ * 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 getItemMeta().hasDisplayName();
+ }
+
+ /**
+ * Gets the localized display name that is set.
+ * <p>
+ * Plugins should check that hasLocalizedName() returns <code>true</code>
+ * 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 getItemMeta().hasLocalizedName();
+ }
+
+ /**
+ * Checks for existence of lore.
+ *
+ * @return true if this has lore
+ */
+ public boolean hasLore() {
+ return 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 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. <br>
+ * Returns an empty map if none.
+ *
+ * @return An immutable copy of the enchantments
+ */
+ @NotNull
+ public Map<Enchantment, Integer> 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 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 getItemMeta().hasConflictingEnchant(ench);
+ }
+
+ /**
+ * Sets the custom model data.
+ * <p>
+ * 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.
+ * <p>
+ * CustomModelData is an integer that may be associated client side with a
+ * custom item model.
+ * <p>
+ * Plugins should check that hasCustomModelData() returns <code>true</code>
+ * before calling this method.
+ *
+ * @return the localized name that is set
+ */
+ public int getCustomModelData() {
+ return getItemMeta().getCustomModelData();
+ }
+
+ /**
+ * Checks for existence of custom model data.
+ * <p>
+ * 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 getItemMeta().hasCustomModelData();
+ }
+
+ /**
+ * Returns whether the item has block data currently attached to it.
+ *
+ * @return whether block data is already attached
+ */
+ public boolean hasBlockData() {
+ return ((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 ((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 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 getItemMeta().hasAttributeModifiers();
+ }
+
+ /**
+ * Return an immutable copy of all Attributes and
+ * their modifiers in this ItemMeta.<br>
+ * Returns null if none exist.
+ *
+ * @return an immutable {@link Multimap} of Attributes
+ * and their AttributeModifiers, or null if none exist
+ */
+ @Nullable
+ public Multimap<Attribute, AttributeModifier> getAttributeModifiers() {
+ return getItemMeta().getAttributeModifiers();
+ }
+
+ /**
+ * Return an immutable copy of all {@link Attribute}s and their
+ * {@link AttributeModifier}s for a given {@link EquipmentSlot}.<br>
+ * 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.<br>
+ * 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<Attribute, AttributeModifier> 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<AttributeModifier> 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.
+ * <br>
+ * 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<Attribute, AttributeModifier> 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}.<br>
+ * 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;
+ }
+
+ /**
+ * Returns a custom tag container capable of storing tags on the object.
+ *
+ * Note that the tags stored on this container are all stored under their
+ * own custom namespace therefore modifying default tags using this
+ * {@link PersistentDataHolder} is impossible.
+ *
+ * @return the persistent metadata container
+ */
+ @NotNull
+ public PersistentDataContainer getPersistentDataContainer() {
+ return getItemMeta().getPersistentDataContainer();
+ }
+
+ /**
+ * Checks to see if this item has damage
+ *
+ * @return true if this has damage
+ */
+ public boolean hasDamage() {
+ return ((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);
+ }
+
+ /**
+ * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE}
+ *
+ * @return Set of {@link com.destroystokyo.paper.Namespaced}
+ */
+ @NotNull
+ public Set<Namespaced> getDestroyableKeys() {
+ return getItemMeta().getDestroyableKeys();
+ }
+
+ /**
+ * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE}
+ *
+ * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced}
+ */
+ public void setDestroyableKeys(@NotNull Collection<Namespaced> canDestroy) {
+ ItemMeta itemMeta = getItemMeta();
+ itemMeta.setDestroyableKeys(canDestroy);
+ setItemMeta(itemMeta);
+ }
+
+ /**
+ * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE}
+ *
+ * @return Set of {@link com.destroystokyo.paper.Namespaced}
+ */
+ @NotNull
+ public Set<Namespaced> getPlaceableKeys() {
+ return getItemMeta().getPlaceableKeys();
+ }
+
+ /**
+ * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE}
+ *
+ * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced}
+ */
+ @NotNull
+ public void setPlaceableKeys(@NotNull Collection<Namespaced> canPlaceOn) {
+ ItemMeta itemMeta = getItemMeta();
+ itemMeta.setPlaceableKeys(canPlaceOn);
+ setItemMeta(itemMeta);
+ }
+
+ /**
+ * Checks for the existence of any keys that the item can be placed on
+ *
+ * @return true if this item has placeable keys
+ */
+ public boolean hasPlaceableKeys() {
+ return getItemMeta().hasPlaceableKeys();
+ }
+
+ /**
+ * Checks for the existence of any keys that the item can destroy
+ *
+ * @return true if this item has destroyable keys
+ */
+ public boolean hasDestroyableKeys() {
+ return getItemMeta().hasDestroyableKeys();
+ }
+
+ /**
+ * 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.DURABILITY);
+ 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
}