package com.earth2me.essentials.items; import com.earth2me.essentials.ManagedFile; import com.earth2me.essentials.utils.EnumUtil; import com.earth2me.essentials.utils.MaterialUtil; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import net.ess3.api.IEssentials; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionData; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import static com.earth2me.essentials.I18n.tl; public class FlatItemDb extends AbstractItemDb { private static final Gson gson = new Gson(); // Maps primary name to ItemData private final transient Map items = new HashMap<>(); // Maps alias to primary name private final transient Map itemAliases = new HashMap<>(); // Every known alias private final transient Set allAliases = new HashSet<>(); private transient ManagedFile file = null; public FlatItemDb(final IEssentials ess) { super(ess); } @Override public void reloadConfig() { if (file == null) { file = new ManagedFile("items.json", ess); } this.rebuild(); ess.getLogger().info(String.format("Loaded %s items from items.json.", listNames().size())); } private void rebuild() { this.reset(); final String json = file.getLines().stream() .filter(line -> !line.startsWith("#")) .collect(Collectors.joining()); this.loadJSON(String.join("\n", json)); ready = true; } private void reset() { ready = false; items.clear(); itemAliases.clear(); allAliases.clear(); } private void loadJSON(final String source) { final JsonObject map = new JsonParser().parse(source).getAsJsonObject(); for (final Map.Entry entry : map.entrySet()) { final String key = entry.getKey(); final JsonElement element = entry.getValue(); boolean valid = false; if (element.isJsonObject()) { final ItemData data = gson.fromJson(element, ItemData.class); items.put(key, data); valid = true; } else { try { final String target = element.getAsString(); itemAliases.put(key, target); valid = true; } catch (final Exception ignored) { } } if (valid) { allAliases.add(key); } else { ess.getLogger().warning(String.format("Failed to add item: \"%s\": %s", key, element.toString())); } } } @Override public ItemStack get(String id, final boolean useResolvers) throws Exception { if (useResolvers) { final ItemStack resolved = tryResolverDeserialize(id); if (resolved != null) { return resolved; } } id = id.toLowerCase(); final String[] split = id.split("(? 1 && meta instanceof Damageable) { final Damageable damageMeta = (Damageable) meta; damageMeta.setDamage(Integer.parseInt(split[1])); } stack.setItemMeta(meta); // The spawner provider will update the meta again, so we need to call it after // setItemMeta to prevent a race condition final EntityType entity = data.getEntity(); if (entity != null && material.toString().contains("SPAWNER")) { ess.getSpawnerItemProvider().setEntityType(stack, entity); ess.getPersistentDataProvider().set(stack, "convert", "true"); } return stack; } private ItemData getByName(String name) { name = name.toLowerCase(); if (items.containsKey(name)) { return items.get(name); } else if (itemAliases.containsKey(name)) { return items.get(itemAliases.get(name)); } return null; } @Override public List nameList(final ItemStack item) { final List names = new ArrayList<>(); final String primaryName = name(item); names.add(primaryName); for (final Map.Entry entry : itemAliases.entrySet()) { if (entry.getValue().equalsIgnoreCase(primaryName)) { names.add(entry.getKey()); } } return names; } @Override public String name(final ItemStack item) { final ItemData data = lookup(item); for (final Map.Entry entry : items.entrySet()) { if (entry.getValue().equals(data)) { return entry.getKey(); } } return null; } @Override @Deprecated public int getLegacyId(final Material material) { throw new UnsupportedOperationException("Legacy IDs aren't supported on this version."); } private ItemData lookup(final ItemStack item) { final Material type = item.getType(); if (MaterialUtil.isPotion(type) && item.getItemMeta() instanceof PotionMeta) { final PotionData potion = ((PotionMeta) item.getItemMeta()).getBasePotionData(); return new ItemData(type, potion); } else if (type.toString().contains("SPAWNER")) { final EntityType entity = ess.getSpawnerItemProvider().getEntityType(item); return new ItemData(type, entity); } else { return new ItemData(type); } } @Override public Collection listNames() { final Set names = new HashSet<>(allAliases); names.addAll(getResolverNames()); return names; } public static class ItemData { private Material material; private String[] fallbacks = null; private PotionData potionData = null; private EntityType entity = null; ItemData(final Material material) { this.material = material; } ItemData(final Material material, final PotionData potionData) { this.material = material; this.potionData = potionData; } ItemData(final Material material, final EntityType entity) { this.material = material; this.entity = entity; } @Override public int hashCode() { return (31 * material.hashCode()) ^ potionData.hashCode(); } @Override public boolean equals(final Object o) { if (o == null) { return false; } if (!(o instanceof ItemData)) { return false; } final ItemData that = (ItemData) o; return this.getMaterial() == that.getMaterial() && potionDataEquals(that) && entityEquals(that); } public Material getMaterial() { if (material == null && fallbacks != null) { material = EnumUtil.getMaterial(fallbacks); fallbacks = null; // If fallback fails, don't keep trying to look up fallbacks } return material; } public PotionData getPotionData() { return this.potionData; } public EntityType getEntity() { return this.entity; } private boolean potionDataEquals(final ItemData o) { if (this.potionData == null && o.getPotionData() == null) { return true; } else if (this.potionData != null && o.getPotionData() != null) { return this.potionData.equals(o.getPotionData()); } else { return false; } } private boolean entityEquals(final ItemData o) { if (this.entity == null && o.getEntity() == null) { // neither have an entity return true; } else if (this.entity != null && o.getEntity() != null) { // both have an entity; check if it's the same one return this.entity.equals(o.getEntity()); } else { // one has an entity but the other doesn't, so they can't be equal return false; } } } }