package com.Acrobot.Breeze.Utils; import com.google.common.base.Splitter; import com.google.common.collect.Iterables; import info.somethingodd.bukkit.OddItem.OddItem; import org.bukkit.CoalType; import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.TreeSpecies; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.material.*; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author Acrobot */ public class MaterialUtil { public static final Pattern DURABILITY = Pattern.compile(":(\\d)*"); public static final Pattern ENCHANTMENT = Pattern.compile("-([0-9a-zA-Z])*"); /** * Checks if the itemStack is empty or null * * @param item Item to check * @return Is the itemStack empty? */ public static boolean isEmpty(ItemStack item) { return item == null || item.getType() == Material.AIR; } /** * Checks if the itemStacks are equal, ignoring their amount * * @param one first itemStack * @param two second itemStack * @return Are they equal? */ public static boolean equals(ItemStack one, ItemStack two) { return one.isSimilar(two); } /** * Gives you a Material from a String (doesn't have to be fully typed in) * * @param name Name of the material * @return Material found */ public static Material getMaterial(String name) { Material material = Material.matchMaterial(name); if (material != null) { return material; } name = name.replaceAll(" |_", "").toUpperCase(); short length = Short.MAX_VALUE; for (Material currentMaterial : Material.values()) { String matName = currentMaterial.name(); if (matName.replace("_", "").startsWith(name) && matName.length() < length) { length = (short) matName.length(); material = currentMaterial; } } return material; } /** * Returns item's name * * @param itemStack ItemStack to name * @return ItemStack's name */ public static String getName(ItemStack itemStack) { return getName(itemStack, true); } /** * Returns item's name * * @param itemStack ItemStack to name * @param showDataValue Should we also show the data value? * @return ItemStack's name */ public static String getName(ItemStack itemStack, boolean showDataValue) { String dataName = DataValue.name(itemStack); if (dataName != null && showDataValue) { return StringUtil.capitalizeFirstLetter(dataName + '_' + itemStack.getType(), '_'); } else { return StringUtil.capitalizeFirstLetter(itemStack.getType().toString(), '_'); } } /** * Returns item's name, just like on the sign * * @param itemStack ItemStack to name * @return ItemStack's name */ public static String getSignName(ItemStack itemStack) { StringBuilder name = new StringBuilder(15); name.append(itemStack.getType().name()); if (itemStack.getDurability() != 0) { name.append(':').append(itemStack.getDurability()); } if (!itemStack.getEnchantments().isEmpty()) { name.append('-').append(MaterialUtil.Enchantment.encodeEnchantment(itemStack)); } return StringUtil.capitalizeFirstLetter(name.toString(), '_'); } /** * Gives you an ItemStack from a String * * @param itemName Item name * @return ItemStack */ public static ItemStack getItem(String itemName) { ItemStack itemStack = Odd.getFromString(itemName); if (itemStack != null) { return itemStack; } String[] split = Iterables.toArray(Splitter.onPattern(":|-").trimResults().split(itemName), String.class); Material material = getMaterial(split[0]); boolean onlyPartiallyChecked = false; if (material == null) { if (!split[0].contains(" ")) { return null; } int index = split[0].indexOf(' '); material = getMaterial(split[0].substring(index + 1)); if (material == null) { return null; } onlyPartiallyChecked = true; } itemStack = new ItemStack(material, 1); short durability = getDurability(itemName); if (durability == 0 && onlyPartiallyChecked) { String[] spaces = itemName.split(" "); if (spaces.length != 0) { durability = DataValue.get(spaces[0], material); } } itemStack.setDurability(durability); Map enchantments = getEnchantments(itemName); if (!enchantments.isEmpty()) { try { itemStack.addEnchantments(enchantments); } catch (IllegalArgumentException exception) { //Do nothing, because the enchantment can't be applied } } return itemStack; } /** * Returns the durability from a string * * @param itemName Item name * @return Durability found */ public static short getDurability(String itemName) { Matcher m = DURABILITY.matcher(itemName); if (!m.find()) { return 0; } String data = m.group(); if (data == null || data.isEmpty()) { return 0; } data = data.substring(1); return NumberUtil.isShort(data) ? Short.valueOf(data) : 0; } /** * Returns enchantments from a string * * @param itemName Item name * @return Enchantments found */ public static Map getEnchantments(String itemName) { Matcher m = ENCHANTMENT.matcher(itemName); if (!m.find()) { return new HashMap(); } String group = m.group().substring(1); return Enchantment.getEnchantments(group); } public static class Enchantment { /** * Returns enchantments this itemName contains * * @param base32 The encoded enchantment * @return Enchantments found */ public static Map getEnchantments(String base32) { if (base32 == null || base32.isEmpty() || !NumberUtil.isEnchantment(base32)) { return new HashMap(); } StringBuilder number = new StringBuilder(Long.toString(Long.parseLong(base32, 32))); Map map = new HashMap(); while (number.length() % 3 != 0) { number.insert(0, '0'); } for (int i = 0; i < number.length() / 3; i++) { String item = number.substring(i * 3, i * 3 + 3); org.bukkit.enchantments.Enchantment enchantment = org.bukkit.enchantments.Enchantment.getById(Integer.parseInt(item.substring(0, 2))); if (enchantment == null) { continue; } int level = Integer.parseInt(item.substring(2)); if (level > enchantment.getMaxLevel() || level < enchantment.getStartLevel()) { continue; } map.put(enchantment, level); } return map; } /** * Encodes enchantments * They are being encoded in a string like XXL (XXLXXL), where L is the enchantment level and XX is the ID * Then the string is being encoded in base-32 string * * @param enchantments Enchantments to encode * @return Encoded enchantments */ public static String encodeEnchantment(Map enchantments) { long number = 0; for (Map.Entry entry : enchantments.entrySet()) { number = number * 1000 + (entry.getKey().getId()) * 10 + entry.getValue(); } return number != 0 ? Long.toString(number, 32) : null; } /** * Encodes enchantments * They are being encoded in a string like XXL (XXLXXL), where L is the enchantment level and XX is the ID * Then the string is being encoded in base-32 string * * @param item Item to encode * @return Encoded enchantments */ public static String encodeEnchantment(ItemStack item) { return encodeEnchantment(item.getEnchantments()); } } public static class DataValue { /** * Gets the data value from a string * * @param type Data Value string * @param material Material * @return data value */ public static byte get(String type, Material material) { if (material == null || material.getData() == null) { return 0; } type = type.toUpperCase().replace(" ", "_"); MaterialData materialData = material.getNewData((byte) 0); if (materialData instanceof TexturedMaterial) { TexturedMaterial texturedMaterial = (TexturedMaterial) materialData; for (Material mat : texturedMaterial.getTextures()) { if (mat.name().startsWith(type) && !mat.equals(material)) { return (byte) texturedMaterial.getTextures().indexOf(mat); } } } else if (materialData instanceof Colorable) { DyeColor color; try { color = DyeColor.valueOf(type); } catch (IllegalArgumentException exception) { return 0; } if (material == Material.INK_SACK) { color = DyeColor.getByData((byte) (15 - color.getData())); } return color.getData(); } else if (materialData instanceof Tree) { try { return TreeSpecies.valueOf(type).getData(); } catch (IllegalArgumentException ex) { return 0; } } else if (materialData instanceof SpawnEgg) { try { EntityType entityType = EntityType.valueOf(type); return (byte) entityType.getTypeId(); } catch (IllegalArgumentException ex) { return 0; } } else if (materialData instanceof Coal) { try { return CoalType.valueOf(type).getData(); } catch (IllegalArgumentException ex) { return 0; } } return 0; } /** * Returns a string with the DataValue * * @param itemStack ItemStack to describe * @return Data value string */ public static String name(ItemStack itemStack) { MaterialData data = itemStack.getData(); if (data == null) { return null; } if (data instanceof TexturedMaterial) { return ((TexturedMaterial) data).getMaterial().name(); } else if (data instanceof Colorable) { DyeColor color = ((Colorable) data).getColor(); return (color != null ? color.name() : null); } else if (data instanceof Tree) { //TreeSpecies specie = TreeSpecies.getByData((byte) (data.getData() & 3)); //This works, but not as intended TreeSpecies specie = ((Tree) data).getSpecies(); return (specie != null && specie != TreeSpecies.GENERIC ? specie.name() : null); } else if (data instanceof SpawnEgg) { EntityType type = ((SpawnEgg) data).getSpawnedType(); return (type != null ? type.name() : null); } else if (data instanceof Coal) { CoalType coal = ((Coal) data).getType(); return (coal != null && coal != CoalType.COAL ? coal.name() : null); } else { return null; } } } public static class Odd { private static boolean isInitialized = false; /** * Returns the item stack from OddItem plugin * * @param itemName Item name to parse * @return itemStack that was parsed */ public static ItemStack getFromString(String itemName) { if (!isInitialized) { return null; } String name = itemName.replace(':', ';'); try { return OddItem.getItemStack(name); } catch (Exception ex) { return null; } } /** * Lets the class know that it's safe to use the OddItem methods now */ public static void initialize() { isInitialized = true; } } }