Add new item database API (#2472)

* Allow resolver functions to be added to item databases

* Allow resolvers to add item names to list

* Make getResolverNames package-private
This commit is contained in:
md678685 2019-04-15 10:09:16 +01:00 committed by GitHub
parent 8e4fc77244
commit e230cee91e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 247 additions and 18 deletions

View File

@ -33,6 +33,9 @@ public interface IItemDb {
/**
* Create a stack from the given name with the maximum stack size for that material.
*
* Note that this will always check against resolver functions from other plugins as well.
* To avoid this behaviour, use net.ess3.api.IItemDb#get(String name, boolean useResolvers).
*
* @param name Item name to look up in the database
* @return The requested item stack with the maximum stack size
* @throws Exception if the item stack cannot be created

View File

@ -1,34 +1,114 @@
package com.earth2me.essentials.items;
import com.earth2me.essentials.Essentials;
import com.earth2me.essentials.IConf;
import com.earth2me.essentials.User;
import com.earth2me.essentials.utils.MaterialUtil;
import com.earth2me.essentials.utils.StringUtil;
import com.earth2me.essentials.utils.VersionUtil;
import org.bukkit.Color;
import org.bukkit.DyeColor;
import org.bukkit.FireworkEffect;
import org.bukkit.Material;
import net.ess3.api.IEssentials;
import net.ess3.api.PluginKey;
import org.bukkit.*;
import org.bukkit.block.Banner;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.*;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionEffect;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.earth2me.essentials.I18n.tl;
public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb {
protected final IEssentials ess;
protected boolean ready = false;
private Map<PluginKey, ItemResolver> resolverMap = new HashMap<>();
AbstractItemDb(IEssentials ess) {
this.ess = ess;
}
@Override
public void registerResolver(Plugin plugin, String name, ItemResolver resolver) throws Exception {
PluginKey key = PluginKey.fromKey(plugin, name);
if (resolverMap.containsKey(key)) {
throw new Exception("Tried to add a duplicate resolver with name " + key.toString());
}
resolverMap.put(key, resolver);
}
@Override
public void unregisterResolver(Plugin plugin, String name) throws Exception {
PluginKey key = PluginKey.fromKey(plugin, name);
if (!resolverMap.containsKey(key)) {
throw new Exception("Tried to remove nonexistent resolver with name " + key.toString());
}
resolverMap.remove(key);
}
@Override
public boolean isResolverPresent(Plugin plugin, String name) {
return resolverMap.containsKey(PluginKey.fromKey(plugin, name));
}
@Override
public Map<PluginKey, ItemResolver> getResolvers() {
return new HashMap<>(resolverMap);
}
@Override
public Map<PluginKey, ItemResolver> getResolvers(Plugin plugin) {
Map<PluginKey, ItemResolver> matchingResolvers = new HashMap<>();
for (PluginKey key : resolverMap.keySet()) {
if (key.getPlugin().equals(plugin)) {
matchingResolvers.put(key, resolverMap.get(key));
}
}
return matchingResolvers;
}
@Override
public ItemResolver getResolver(Plugin plugin, String name) {
return resolverMap.get(PluginKey.fromKey(plugin, name));
}
@Override
public ItemStack get(String id) throws Exception {
return get(id, true);
}
ItemStack tryResolvers(String id) {
for (PluginKey key : resolverMap.keySet()) {
if (ess.getSettings().isDebug()) {
ess.getLogger().info(String.format("Trying resolver '%s' for item '%s'...", key, id));
}
Function<String, ItemStack> resolver = resolverMap.get(key);
ItemStack stack = resolver.apply(id);
if (stack != null) {
return stack;
}
}
return null;
}
Collection<String> getResolverNames() {
return resolverMap.values().stream()
.map(ItemResolver::getNames)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
@Override
public List<ItemStack> getMatching(User user, String[] args) throws Exception {
List<ItemStack> is = new ArrayList<>();

View File

@ -25,7 +25,7 @@ import static com.earth2me.essentials.I18n.tl;
public class FlatItemDb extends AbstractItemDb {
protected static final Logger LOGGER = Logger.getLogger("Essentials");
private static Gson gson = new Gson();
private final transient IEssentials ess;
// Maps primary name to ItemData
private final transient Map<String, ItemData> items = new HashMap<>();
@ -38,7 +38,7 @@ public class FlatItemDb extends AbstractItemDb {
private transient ManagedFile file = null;
public FlatItemDb(final IEssentials ess) {
this.ess = ess;
super(ess);
}
@Override
@ -99,7 +99,14 @@ public class FlatItemDb extends AbstractItemDb {
}
@Override
public ItemStack get(String id) throws Exception {
public ItemStack get(String id, boolean useResolvers) throws Exception {
if (useResolvers) {
ItemStack resolved = tryResolvers(id);
if (resolved != null) {
return resolved;
}
}
id = id.toLowerCase();
final String[] split = id.split(":");
@ -204,7 +211,9 @@ public class FlatItemDb extends AbstractItemDb {
@Override
public Collection<String> listNames() {
return Collections.unmodifiableSet(allAliases);
Set<String> names = new HashSet<>(allAliases);
names.addAll(getResolverNames());
return names;
}
public static class ItemData {

View File

@ -20,7 +20,6 @@ import static com.earth2me.essentials.I18n.tl;
public class LegacyItemDb extends AbstractItemDb {
protected static final Logger LOGGER = Logger.getLogger("Essentials");
private final transient IEssentials ess;
private final transient Map<String, Integer> items = new HashMap<>();
private final transient Map<ItemData, List<String>> names = new HashMap<>();
private final transient Map<ItemData, String> primaryName = new HashMap<>();
@ -32,7 +31,7 @@ public class LegacyItemDb extends AbstractItemDb {
private final transient Pattern csvSplitPattern = Pattern.compile("(\"([^\"]*)\"|[^,]*)(,|$)");
public LegacyItemDb(final IEssentials ess) {
this.ess = ess;
super(ess);
file = new ManagedFile("items.csv", ess);
}
@ -121,7 +120,14 @@ public class LegacyItemDb extends AbstractItemDb {
}
@Override
public ItemStack get(final String id) throws Exception {
public ItemStack get(final String id, final boolean useResolvers) throws Exception {
if (useResolvers) {
ItemStack resolved = tryResolvers(id);
if (resolved != null) {
return resolved;
}
}
int itemid = 0;
String itemname;
short metaData = 0;
@ -243,7 +249,9 @@ public class LegacyItemDb extends AbstractItemDb {
@Override
public Collection<String> listNames() {
return primaryName.values();
Collection<String> values = primaryName.values();
values.addAll(getResolverNames());
return values;
}
static class ItemData {

View File

@ -1,6 +1,84 @@
package net.ess3.api;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
public interface IItemDb extends com.earth2me.essentials.api.IItemDb {
/**
* Add an item resolver that is called before looking up the item in the item database.
*
* @param plugin The owning plugin
* @param name The name of the resolver
* @param resolver The resolver accepting a String and returning an ItemStack, or null if
* none was found
* @throws Exception If a resolver with a conflicting name is found
*/
void registerResolver(Plugin plugin, String name, ItemResolver resolver) throws Exception;
/**
* Remove an item resolver from the given plugin with the given name.
*
* @param plugin The owning plugin
* @param name The name of the resolver
* @throws Exception If no matching resolver was found
*/
void unregisterResolver(Plugin plugin, String name) throws Exception;
/**
* Check whether a resolver with a given name from a given plugin has been registered.
*
* @param plugin The owning plugin
* @param name The name of the resolver
* @return Whether the resolver could be found
*/
boolean isResolverPresent(Plugin plugin, String name);
/**
* Get all registered resolvers.
*
* @return A map of all registered resolvers
*/
Map<PluginKey, ItemResolver> getResolvers();
/**
* Get all registered resolvers from the given plugin.
*
* @param plugin The owning plugin
* @return A map of all matching resolvers
*/
Map<PluginKey, ItemResolver> getResolvers(Plugin plugin);
/**
* Get the resolver function with the given name from the given plugin.
*
* @param plugin The owning plugin
* @param name The name of the resolver
* @return The resolver function, or null if not found
*/
ItemResolver getResolver(Plugin plugin, String name);
/**
* Create a stack from the given name with the maximum stack size for that material.
*
* @param name Item name to look up in the database
* @param useResolvers Whether to call other plugins' resolver functions before looking the
* item up in the database
* @return The requested item stack with the maximum stack size
* @throws Exception if the item stack cannot be created
*/
ItemStack get(String name, boolean useResolvers) throws Exception;
@FunctionalInterface
interface ItemResolver extends Function<String, ItemStack> {
default Collection<String> getNames() {
return null;
}
}
}

View File

@ -0,0 +1,51 @@
package net.ess3.api;
import org.bukkit.plugin.Plugin;
import java.util.Objects;
import java.util.UUID;
public final class PluginKey {
private final Plugin plugin;
private final String key;
private PluginKey(Plugin plugin, String key) {
this.plugin = plugin;
this.key = key;
}
public Plugin getPlugin() {
return plugin;
}
public String getKey() {
return key;
}
@Override
public int hashCode() {
return Objects.hash(plugin, key);
}
@Override
public String toString() {
return plugin.getName().toLowerCase() + ":" + key;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof PluginKey || o.getClass().getName().equals("org.bukkit.NamespacedKey"))) {
return false;
}
return this == o || this.toString().equals(o.toString());
}
public static PluginKey random(Plugin plugin) {
return new PluginKey(plugin, UUID.randomUUID().toString());
}
public static PluginKey fromKey(Plugin plugin, String key) {
return new PluginKey(plugin, key);
}
}