package net.glowstone.inventory; import com.google.common.base.Strings; import net.glowstone.util.nbt.CompoundTag; import net.glowstone.util.nbt.TagType; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.meta.ItemMeta; import java.util.*; /** * An implementation of {@link ItemMeta}, created through {@link GlowItemFactory}. */ class GlowMetaItem implements ItemMeta { private String displayName; private List<String> lore; private Map<Enchantment, Integer> enchants; /** * Create a GlowMetaItem, copying from another if possible. * @param meta The meta to copy from, or null. */ public GlowMetaItem(GlowMetaItem meta) { if (meta == null) { return; } displayName = meta.displayName; if (meta.hasLore()) { this.lore = new ArrayList<>(meta.lore); } if (meta.hasEnchants()) { this.enchants = new HashMap<>(meta.enchants); } } /** * Check whether this ItemMeta can be applied to the given material. * @param material The Material. * @return True if this ItemMeta is applicable. */ public boolean isApplicable(Material material) { return material != Material.AIR; } @Override public ItemMeta clone() { return new GlowMetaItem(this); } @Override public Spigot spigot() { return null; } protected static void serializeEnchants(String name, Map<String, Object> map, Map<Enchantment, Integer> enchants) { Map<String, Object> enchantList = new HashMap<>(); for (Map.Entry<Enchantment, Integer> enchantment : enchants.entrySet()) { enchantList.put(enchantment.getKey().getName(), enchantment.getValue()); } map.put(name, enchantList); } @Override public Map<String, Object> serialize() { Map<String, Object> result = new HashMap<>(); result.put("meta-type", "UNSPECIFIC"); if (hasDisplayName()) { result.put("display-name", getDisplayName()); } if (hasLore()) { result.put("lore", getLore()); } if (hasEnchants()) { serializeEnchants("enchants", result, getEnchants()); } return result; } protected static void writeNbtEnchants(String name, CompoundTag to, Map<Enchantment, Integer> enchants) { List<CompoundTag> ench = new ArrayList<>(); for (Map.Entry<Enchantment, Integer> enchantment : enchants.entrySet()) { CompoundTag enchantmentTag = new CompoundTag(); enchantmentTag.putShort("id", enchantment.getKey().getId()); enchantmentTag.putShort("lvl", enchantment.getValue()); ench.add(enchantmentTag); } to.putCompoundList(name, ench); } void writeNbt(CompoundTag tag) { CompoundTag displayTags = new CompoundTag(); if (hasDisplayName()) { displayTags.putString("Name", getDisplayName()); } if (hasLore()) { displayTags.putList("Lore", TagType.STRING, getLore()); } if (!displayTags.isEmpty()) { tag.putCompound("display", displayTags); } if (hasEnchants()) { writeNbtEnchants("ench", tag, enchants); } } protected static Map<Enchantment, Integer> readNbtEnchants(String name, CompoundTag tag) { Map<Enchantment, Integer> result = null; if (tag.isList(name, TagType.COMPOUND)) { Iterable<CompoundTag> enchs = tag.getCompoundList(name); for (CompoundTag enchantmentTag : enchs) { if (enchantmentTag.isShort("id") && enchantmentTag.isShort("lvl")) { Enchantment enchantment = Enchantment.getById(enchantmentTag.getShort("id")); if (result == null) result = new HashMap<>(4); result.put(enchantment, (int) enchantmentTag.getShort("lvl")); } } } return result; } void readNbt(CompoundTag tag) { if (tag.isCompound("display")) { CompoundTag display = tag.getCompound("display"); if (display.isString("Name")) { setDisplayName(display.getString("Name")); } if (display.isList("Lore", TagType.STRING)) { setLore(display.<String>getList("Lore", TagType.STRING)); } } //TODO currently ignoring level restriction, is that right? Map<Enchantment, Integer> tagEnchants = readNbtEnchants("ench", tag); if (tagEnchants != null) { if (enchants == null) enchants = tagEnchants; else enchants.putAll(tagEnchants); } } @Override public String toString() { Map<String, Object> map = serialize(); return map.get("meta-type") + "_META:" + map; } //////////////////////////////////////////////////////////////////////////// // Basic properties @Override public boolean hasDisplayName() { return !Strings.isNullOrEmpty(displayName); } @Override public String getDisplayName() { return displayName; } @Override public void setDisplayName(String name) { displayName = name; } @Override public boolean hasLore() { return lore != null && !lore.isEmpty(); } @Override public List<String> getLore() { return lore; } @Override public void setLore(List<String> lore) { // todo: fancy validation things this.lore = lore; } //////////////////////////////////////////////////////////////////////////// // Enchants @Override public boolean hasEnchants() { return enchants != null && !enchants.isEmpty(); } @Override public boolean hasEnchant(Enchantment ench) { return hasEnchants() && enchants.containsKey(ench); } @Override public int getEnchantLevel(Enchantment ench) { return hasEnchant(ench) ? enchants.get(ench) : 0; } @Override public Map<Enchantment, Integer> getEnchants() { return hasEnchants() ? Collections.unmodifiableMap(enchants) : Collections.<Enchantment, Integer>emptyMap(); } @Override public boolean addEnchant(Enchantment ench, int level, boolean ignoreLevelRestriction) { if (enchants == null) { enchants = new HashMap<>(4); } if (ignoreLevelRestriction || level >= ench.getStartLevel() && level <= ench.getMaxLevel()) { Integer old = enchants.put(ench, level); return old == null || old != level; } return false; } @Override public boolean removeEnchant(Enchantment ench) { return hasEnchants() && enchants.remove(ench) != null; } @Override public boolean hasConflictingEnchant(Enchantment ench) { if (!hasEnchants()) return false; for (Enchantment e : enchants.keySet()) { if (e.conflictsWith(ench)) return true; } return false; } @Override public void addItemFlags(ItemFlag... itemFlags) { //To change body of implemented methods use File | Settings | File Templates. } @Override public void removeItemFlags(ItemFlag... itemFlags) { //To change body of implemented methods use File | Settings | File Templates. } @Override public Set<ItemFlag> getItemFlags() { return null; //To change body of implemented methods use File | Settings | File Templates. } @Override public boolean hasItemFlag(ItemFlag itemFlag) { return false; //To change body of implemented methods use File | Settings | File Templates. } }