de.eldoria.eldoutilities.builder.ItemStackBuilder Maven / Gradle / Ivy
/*
* SPDX-License-Identifier: LGPL-3.0-or-later
*
* Copyright (C) EldoriaRPG Team and Contributor
*/
package de.eldoria.eldoutilities.builder;
import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
/**
* A class which allows the creation of ItemStacks with a builder like pattern.
*
* @since 1.1.0
*/
@SuppressWarnings("unused")
public final class ItemStackBuilder {
private final ItemStack itemStack;
private ItemStackBuilder(Material material, int amount) {
itemStack = new ItemStack(material, amount);
}
public ItemStackBuilder(ItemStack itemStack) {
this.itemStack = itemStack;
}
/**
* Creates a new item stack builder
*
* @param material material of item stack
* @return builder instance
*/
public static ItemStackBuilder of(Material material) {
return new ItemStackBuilder(material, 1);
}
/**
* Creates a new item stack builder
*
* @param material material of item stack
* @param amount size of item stack.
* @return builder instance
*/
public static ItemStackBuilder of(Material material, int amount) {
return new ItemStackBuilder(material, amount);
}
/**
* Load a item stack into a item stack builder.
*
* The item stack will be cloned to provide immutability.
*
* @param stack item stack to load
* @return builder instance
*/
public static ItemStackBuilder of(ItemStack stack) {
return of(stack, true);
}
/**
* Load a item stack into a item stack builder.
*
* @param stack item stack to load
* @param clone true if the item should be cloned
* @return builder instance
*/
public static ItemStackBuilder of(ItemStack stack, boolean clone) {
return new ItemStackBuilder(clone ? stack.clone() : stack);
}
/**
* Applies an item meta consumer on the item meta, if a item meta is present.
*
* @param itemMetaConsumer consumer for non null item meta.
* @return builder instance
*/
public ItemStackBuilder withMetaValue(Consumer<@NotNull ItemMeta> itemMetaConsumer) {
var meta = itemStack.getItemMeta();
if (meta != null) itemMetaConsumer.accept(meta);
itemStack.setItemMeta(meta);
return this;
}
/**
* Clone the underlying itemstack and return a cloned instance.
*
* @return new item stack instance
*/
public ItemStack build() {
return itemStack.clone();
}
/**
* Adds the specified enchantments to this item stack.
*
* This method is the same as calling {@link
* #withEnchantment(Enchantment, int)} for each
* element of the map.
*
* @param enchantments Enchantments to add
* @return builder instance
* @throws IllegalArgumentException if the specified enchantments is null
* @throws IllegalArgumentException if any specific enchantment or level
* is null. Warning: Some enchantments may be added before this
* exception is thrown.
*/
public ItemStackBuilder withEnchantments(@NotNull Map enchantments) {
itemStack.addEnchantments(enchantments);
return this;
}
/**
* Adds the specified {@link Enchantment} to this item stack.
*
* If this item stack already contained the given enchantment (at any
* level), it will be replaced.
*
* @param ench Enchantment to add
* @param level Level of the enchantment
* @return builder instance
* @throws IllegalArgumentException if enchantment null, or enchantment is
* not applicable
*/
public ItemStackBuilder withEnchantment(@NotNull Enchantment ench, int level) {
itemStack.addEnchantment(ench, level);
return this;
}
/**
* Adds the specified enchantments to this item stack in an unsafe manner.
*
* This method is the same as calling {@link
* #withUnsafeEnchantment(Enchantment, int)} for
* each element of the map.
*
* @param enchantments Enchantments to add
* @return builder instance
*/
public ItemStackBuilder withUnsafeEnchantments(@NotNull Map enchantments) {
itemStack.addUnsafeEnchantments(enchantments);
return this;
}
/**
* Adds the specified {@link Enchantment} to this item stack.
*
* If this item stack already contained the given enchantment (at any
* level), it will be replaced.
*
* This method is unsafe and will ignore level restrictions or item type.
* Use at your own discretion.
*
* @param ench Enchantment to add
* @param level Level of the enchantment
* @return builder instance
*/
public ItemStackBuilder withUnsafeEnchantment(@NotNull Enchantment ench, int level) {
itemStack.addUnsafeEnchantment(ench, level);
return this;
}
/**
* Sets the amount of items in this stack
*
* @param amount New amount of items in this stack
* @return builder instance
*/
public ItemStackBuilder ofAmount(int amount) {
itemStack.setAmount(amount);
return this;
}
/**
* Sets the display name.
*
* @param name the name to set
* @return builder instance
*/
public ItemStackBuilder withDisplayName(@Nullable String name) {
withMetaValue(m -> m.setDisplayName(name));
return this;
}
/**
* Sets the localized name.
*
* @param name the name to set
* @return builder instance
*/
public ItemStackBuilder withLocalizedName(@Nullable String name) {
withMetaValue(m -> m.setLocalizedName(name));
return this;
}
/**
* Sets the lore for this item.
*
* @param lore the lore that will be set
* @return builder instance
*/
public ItemStackBuilder withLore(@Nullable List lore) {
withMetaValue(m -> m.setLore(lore));
return this;
}
/**
* Sets the lore for this item.
*
* @param lore the lore that will be set
* @return builder instance
*/
public ItemStackBuilder withLore(String... lore) {
return withLore(Arrays.asList(lore));
}
/**
* 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
* @return builder instance
*/
public ItemStackBuilder withCustomModelData(@Nullable Integer data) {
withMetaValue(m -> m.setCustomModelData(data));
return this;
}
/**
* 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 builder instance
*/
public ItemStackBuilder withEnchant(@NotNull Enchantment ench, int level, boolean ignoreLevelRestriction) {
withMetaValue(m -> m.addEnchant(ench, level, ignoreLevelRestriction));
return this;
}
/**
* Set itemflags which should be ignored when rendering a ItemStack in the Client. This Method does silently ignore double set itemFlags.
*
* @param itemFlags The hideflags which shouldn't be rendered
* @return builder instance
*/
public ItemStackBuilder withItemFlags(@NotNull ItemFlag... itemFlags) {
withMetaValue(m -> m.addItemFlags(itemFlags));
return this;
}
/**
* Sets the unbreakable tag. An unbreakable item will not lose durability.
*
* @return builder instance
*/
public ItemStackBuilder asUnbreakable() {
withMetaValue(m -> m.setUnbreakable(true));
return this;
}
/**
* Sets the breakable tag. An breakable item will lose durability.
* This is the default value.
*
* @return builder instance
*/
public ItemStackBuilder asBreakable() {
withMetaValue(m -> m.setUnbreakable(false));
return this;
}
/**
* 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 builder instance
* @throws NullPointerException if Attribute is null
* @throws NullPointerException if AttributeModifier is null
* @throws IllegalArgumentException if AttributeModifier already exists
*/
public ItemStackBuilder withAttributeModifier(@NotNull Attribute attribute, @NotNull AttributeModifier modifier) {
withMetaValue(m -> m.addAttributeModifier(attribute, modifier));
return this;
}
/**
* Sets the damage
*
* @param damage item damage
* @return builder instance
*/
public ItemStackBuilder withDurability(int damage) {
withMetaValue(m -> {
if (m instanceof Damageable) {
((Damageable) m).setDamage(damage);
}
});
return this;
}
/**
* Applies a consumer on the {@link ItemMeta#getPersistentDataContainer()}.
* The consumer will only be executed if a item meta is present
*
* @param dataConsumer consumer for data container
* @return builder instance
*/
public ItemStackBuilder withNBTData(Consumer<@NotNull PersistentDataContainer> dataConsumer) {
withMetaValue(m -> dataConsumer.accept(m.getPersistentDataContainer()));
return this;
}
/**
* Casts the item meta to the defined class if possible.
*
* Will apply the consumer on the meta if the cast was successful.
*
* @param clazz class of item meta
* @param consumer consumer for item meta
* @param type of meta
* @return builder instance
*/
@SuppressWarnings("unchecked")
public ItemStackBuilder withMetaValue(Class clazz, Consumer<@NotNull T> consumer) {
var itemMeta = itemStack.getItemMeta();
if (itemMeta != null) {
if (clazz.isAssignableFrom(itemMeta.getClass())) {
consumer.accept((T) itemMeta);
}
}
itemStack.setItemMeta(itemMeta);
return this;
}
}