ProjectAres/Util/bukkit/src/main/java/tc/oc/commons/bukkit/item/ItemBuilder.java

186 lines
4.9 KiB
Java

package tc.oc.commons.bukkit.item;
import java.util.Collections;
import java.util.UUID;
import javax.annotation.Nullable;
import org.bukkit.Bukkit;
import org.bukkit.DyeColor;
import org.bukkit.Material;
import org.bukkit.Skin;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import org.bukkit.material.Dye;
import org.bukkit.material.MaterialData;
import org.bukkit.material.Wool;
import tc.oc.commons.core.ListUtils;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A nice way to build {@link ItemStack}s
*
* TODO: attributes, canPlaceOn, canDestroy, potion effects, etc.
*/
public class ItemBuilder<S extends ItemBuilder<?>> {
private final ItemStack stack;
private @Nullable ItemMeta meta;
public ItemBuilder() {
this(new ItemStack(Material.AIR));
}
public ItemBuilder(ItemStack stack) {
this.stack = stack;
}
// Convenient generic alias for this
@SuppressWarnings("unchecked")
protected S self() {
return (S) this;
}
public ItemStack get() {
if(meta != null) {
stack.setItemMeta(meta);
}
return stack;
}
public ItemStack copy() {
return get().clone();
}
protected void createMeta() {
// Bukkit refuses to create meta for air
final Material material = stack.getType() == Material.AIR ? Material.STONE
: stack.getType();
if(meta != null) {
// Ensure existing meta is the correct type
meta = Bukkit.getItemFactory().asMetaFor(meta, material);
} else {
meta = stack.getItemMeta();
if(meta == null) {
meta = Bukkit.getItemFactory().getItemMeta(material);
}
}
checkNotNull(meta);
}
protected ItemMeta meta() {
if(meta == null) {
createMeta();
}
return meta;
}
protected <T extends ItemMeta> T meta(Class<T> type) {
final ItemMeta meta = meta();
if(!type.isInstance(meta)) {
throw new IllegalArgumentException("Item of type " + stack.getType().name() + " cannot have metadata of type " + type.getName());
}
return type.cast(meta);
}
public S material(Material material) {
stack.setType(material);
if(meta != null) {
// Convert meta if needed
createMeta();
}
return self();
}
public S material(MaterialData material) {
material(material.getItemType());
stack.setData(material);
stack.setDurability(material.getData());
return self();
}
public S amount(int amount) {
stack.setAmount(amount);
return self();
}
public S durability(int durability) {
stack.setDurability((short) durability);
return self();
}
public S name(String name) {
meta().setDisplayName(name);
return self();
}
/**
* Append a line of lore
*/
public S lore(String lore) {
meta().setLore(meta().hasLore() ? ListUtils.append(meta().getLore(), lore)
: Collections.singletonList(lore));
return self();
}
public S flags(ItemFlag...flags) {
meta().addItemFlags(flags);
return self();
}
public S unbreakable(boolean unbreakable) {
meta().setUnbreakable(unbreakable);
return self();
}
public S enchant(Enchantment enchantment, int level) {
meta().addEnchant(enchantment, level, true);
return self();
}
public S color(DyeColor color) {
final Material type = stack.getType();
switch(type) {
case INK_SACK:
stack.setData(new Dye(color));
break;
case WOOL:
stack.setData(new Wool(color));
break;
default:
// Assume a colored block
// TODO verify this, support other things e.g. banners
stack.setData(new MaterialData(type, color.getWoolData()));
break;
}
// I'm not clear why Bukkit doesn't do this, but it needs to be done.
// Of course, if we ever support non-block items with this method,
// this gets a bit more complicated.
stack.setDurability(stack.getData().getData());
return self();
}
public S skin(String name, UUID uuid, Skin skin) {
meta(SkullMeta.class).setOwner(name, uuid, skin);
return self();
}
public S shareable(boolean yes) {
new BooleanItemTag("prevent-sharing", false).set(stack, !yes);
return self();
}
public S locked(boolean yes) {
new BooleanItemTag("locked", false).set(stack, !yes);
return self();
}
}