package com.earth2me.essentials.items; import com.earth2me.essentials.ManagedFile; import com.earth2me.essentials.utils.EnumUtil; import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.StringUtil; import com.earth2me.essentials.utils.VersionUtil; import net.ess3.api.IEssentials; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.earth2me.essentials.I18n.tl; public class LegacyItemDb extends AbstractItemDb { private final transient Map items = new HashMap<>(); private final transient Map> names = new HashMap<>(); private final transient Map primaryName = new HashMap<>(); private final transient Map legacyIds = new HashMap<>(); private final transient Map durabilities = new HashMap<>(); private final transient Map nbtData = new HashMap<>(); private final transient ManagedFile file; private final transient Pattern splitPattern = Pattern.compile("((.*)[:+',;.](\\d+))"); private final transient Pattern csvSplitPattern = Pattern.compile("(\"([^\"]*)\"|[^,]*)(,|$)"); public LegacyItemDb(final IEssentials ess) { super(ess); file = new ManagedFile("items.csv", ess); } @Override public void reloadConfig() { final List lines = file.getLines(); if (lines.isEmpty()) { return; } ready = false; durabilities.clear(); items.clear(); names.clear(); primaryName.clear(); for (final String line : lines) { if (line.length() > 0 && line.charAt(0) == '#') { continue; } String itemName = null; int numeric = -1; short data = 0; String nbt = null; int col = 0; final Matcher matcher = csvSplitPattern.matcher(line); while (matcher.find()) { String match = matcher.group(1); if (StringUtil.stripToNull(match) == null) { continue; } match = StringUtil.strip(match.trim(), "\""); switch (col) { case 0: itemName = match.toLowerCase(Locale.ENGLISH); break; case 1: numeric = Integer.parseInt(match); break; case 2: data = Short.parseShort(match); break; case 3: nbt = StringUtil.stripToNull(match); break; default: continue; } col++; } // Invalid row if (itemName == null || numeric < 0) { continue; } durabilities.put(itemName, data); items.put(itemName, numeric); if (nbt != null) { nbtData.put(itemName, nbt); } final ItemData itemData = new ItemData(numeric, data); if (names.containsKey(itemData)) { final List nameList = names.get(itemData); nameList.add(itemName); } else { final List nameList = new ArrayList<>(); nameList.add(itemName); names.put(itemData, nameList); primaryName.put(itemData, itemName); } legacyIds.put(numeric, itemData); } for (final List nameList : names.values()) { nameList.sort(LengthCompare.INSTANCE); } ess.getLogger().info(String.format("Loaded %s items from items.csv.", listNames().size())); ready = true; } @Override public ItemStack get(final String id, final boolean useResolvers) throws Exception { if (useResolvers) { final ItemStack resolved = tryResolverDeserialize(id); if (resolved != null) { return resolved; } } int itemid = 0; String itemname; short metaData = 0; final Matcher parts = splitPattern.matcher(id); if (parts.matches()) { itemname = parts.group(2); metaData = Short.parseShort(parts.group(3)); } else { itemname = id; } if (NumberUtil.isInt(itemname)) { itemid = Integer.parseInt(itemname); } else if (NumberUtil.isInt(id)) { itemid = Integer.parseInt(id); } else { itemname = itemname.toLowerCase(Locale.ENGLISH); } if (itemid < 1) { if (items.containsKey(itemname)) { itemid = items.get(itemname); if (durabilities.containsKey(itemname) && metaData == 0) { metaData = durabilities.get(itemname); } } } if (itemid < 1) { final Material matFromName = EnumUtil.getMaterial(itemname.toUpperCase()); if (matFromName != null) { itemid = matFromName.getId(); } } if (itemid < 1) { throw new Exception(tl("unknownItemName", itemname)); } final ItemData data = legacyIds.get(itemid); if (data == null) { throw new Exception(tl("unknownItemId", itemid)); } final Material mat = getFromLegacy(itemid, (byte) metaData); ItemStack retval = new ItemStack(mat); if (nbtData.containsKey(itemname)) { String nbt = nbtData.get(itemname); if (nbt.startsWith("*")) { nbt = nbtData.get(nbt.substring(1)); } retval = ess.getServer().getUnsafe().modifyItemStack(retval, nbt); } final Material MOB_SPAWNER = EnumUtil.getMaterial("SPAWNER", "MOB_SPAWNER"); if (mat == MOB_SPAWNER) { if (metaData == 0) metaData = EntityType.PIG.getTypeId(); try { retval = ess.getSpawnerItemProvider().setEntityType(retval, EntityType.fromId(metaData)); ess.getPersistentDataProvider().set(retval, "convert", "true"); } catch (final IllegalArgumentException e) { throw new Exception("Can't spawn entity ID " + metaData + " from mob spawners."); } } else if (mat.name().contains("MONSTER_EGG")) { final EntityType type; try { type = EntityType.fromId(metaData); } catch (final IllegalArgumentException e) { throw new Exception("Can't spawn entity ID " + metaData + " from spawn eggs."); } retval = ess.getSpawnEggProvider().createEggItem(type); } else if (mat.name().endsWith("POTION") && VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_11_R01)) { // Only apply this to pre-1.11 as items.csv might only work in 1.11 retval = ess.getPotionMetaProvider().createPotionItem(mat, metaData); } else { retval.setDurability(metaData); } retval.setAmount(mat.getMaxStackSize()); return retval; } @Override public List nameList(final ItemStack item) { ItemData itemData = new ItemData(item.getType().getId(), item.getDurability()); List nameList = names.get(itemData); if (nameList == null) { itemData = new ItemData(item.getType().getId(), (short) 0); nameList = names.get(itemData); if (nameList == null) { return null; } } return Collections.unmodifiableList(nameList); } @Override public String name(final ItemStack item) { ItemData itemData = new ItemData(item.getType().getId(), item.getDurability()); String name = primaryName.get(itemData); if (name == null) { itemData = new ItemData(item.getType().getId(), (short) 0); name = primaryName.get(itemData); } return name; } @Override public int getLegacyId(final Material material) throws Exception { for (final Map.Entry entry : items.entrySet()) { if (material.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(entry.getKey())) { return entry.getValue(); } } throw new Exception("Itemid not found for material: " + material.name()); } @Override public Collection listNames() { final Collection values = new ArrayList<>(primaryName.values()); values.addAll(getResolverNames()); return values; } static class ItemData { private final int itemNo; final private short itemData; ItemData(final int itemNo, final short itemData) { this.itemNo = itemNo; this.itemData = itemData; } public int getItemNo() { return itemNo; } public short getItemData() { return itemData; } @Override public int hashCode() { return (31 * itemNo) ^ itemData; } @Override public boolean equals(final Object o) { if (o == null) { return false; } if (!(o instanceof ItemData)) { return false; } final ItemData pairo = (ItemData) o; return this.itemNo == pairo.getItemNo() && this.itemData == pairo.getItemData(); } } static class LengthCompare implements java.util.Comparator { private static final LengthCompare INSTANCE = new LengthCompare(); LengthCompare() { super(); } @Override public int compare(final String s1, final String s2) { return s1.length() - s2.length(); } } }