From ea57e4ae01a880e29f5743e32ee183dff51c887e Mon Sep 17 00:00:00 2001 From: MD <1917406+md678685@users.noreply.github.com> Date: Mon, 15 Jun 2020 13:46:44 +0100 Subject: [PATCH] Add serialize method to ItemResolvers for custom serialization (#3307) Add an optional `serialize` method to `ItemResolver`s which plugins can implement in order to add custom items to `/createkit`. Also improves ItemResolver docs. Closes #3305, closes #3216. --- .../com/earth2me/essentials/api/IItemDb.java | 13 ++--- .../essentials/items/AbstractItemDb.java | 55 +++++++++++++++---- .../earth2me/essentials/items/FlatItemDb.java | 2 +- .../essentials/items/LegacyItemDb.java | 2 +- Essentials/src/net/ess3/api/IItemDb.java | 42 ++++++++++++++ 5 files changed, 94 insertions(+), 20 deletions(-) diff --git a/Essentials/src/com/earth2me/essentials/api/IItemDb.java b/Essentials/src/com/earth2me/essentials/api/IItemDb.java index 90e4655d2..f61da9bbc 100644 --- a/Essentials/src/com/earth2me/essentials/api/IItemDb.java +++ b/Essentials/src/com/earth2me/essentials/api/IItemDb.java @@ -1,11 +1,9 @@ package com.earth2me.essentials.api; -import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.User; import com.earth2me.essentials.utils.MaterialUtil; import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.StringUtil; -import net.ess3.api.IEssentials; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -85,13 +83,12 @@ public interface IItemDb { List getMatching(User user, String[] args) throws Exception; /** - * Serialise an ItemStack into a format that can be decoded by - * {@link #get(String) get} and - * {@link com.earth2me.essentials.MetaItemStack#parseStringMeta(CommandSource, boolean, String[], int, IEssentials)} MetaItemStack#parseStringMeta}. - * Used to encode items for kits. + * Converts the given {@link ItemStack} to a string representation that can be saved. + * This is typically used for /createkit but can be used by other plugins for various purposes too. + * Note that this will try registered resolvers first - to avoid this, use {@link net.ess3.api.IItemDb#serialize(ItemStack, boolean)} instead. * - * @param is Stack to serialise - * @return Serialised stack + * @param is The stack to serialize + * @return A string representing the given stack */ String serialize(ItemStack is); diff --git a/Essentials/src/com/earth2me/essentials/items/AbstractItemDb.java b/Essentials/src/com/earth2me/essentials/items/AbstractItemDb.java index 17b6086c6..40a07bef7 100644 --- a/Essentials/src/com/earth2me/essentials/items/AbstractItemDb.java +++ b/Essentials/src/com/earth2me/essentials/items/AbstractItemDb.java @@ -6,7 +6,10 @@ import com.earth2me.essentials.utils.MaterialUtil; import com.earth2me.essentials.utils.VersionUtil; import net.ess3.api.IEssentials; import net.ess3.api.PluginKey; -import org.bukkit.*; +import org.bukkit.Color; +import org.bukkit.DyeColor; +import org.bukkit.FireworkEffect; +import org.bukkit.Material; import org.bukkit.block.Banner; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemFlag; @@ -18,7 +21,6 @@ import org.bukkit.potion.PotionEffect; import java.util.*; import java.util.function.Function; -import java.util.stream.Collectors; import static com.earth2me.essentials.I18n.tl; @@ -85,10 +87,10 @@ public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb { return get(id, true); } - ItemStack tryResolvers(String id) { + ItemStack tryResolverDeserialize(String id) { for (PluginKey key : resolverMap.keySet()) { if (ess.getSettings().isDebug()) { - ess.getLogger().info(String.format("Trying resolver '%s' for item '%s'...", key, id)); + ess.getLogger().info(String.format("Trying to deserialize item '%s' with resolver '%s'...", id, key)); } Function resolver = resolverMap.get(key); @@ -102,11 +104,32 @@ public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb { return null; } + String tryResolverSerialize(ItemStack stack) { + for (PluginKey key : resolverMap.keySet()) { + if (ess.getSettings().isDebug()) { + ess.getLogger().info(String.format("Trying to serialize '%s' with resolver '%s'...", stack.toString(), key)); + } + + ItemResolver resolver = resolverMap.get(key); + String serialized = resolver.serialize(stack); + + if (serialized != null) { + return serialized; + } + } + + return null; + } + Collection getResolverNames() { - return resolverMap.values().stream() - .map(ItemResolver::getNames) - .flatMap(Collection::stream) - .collect(Collectors.toList()); + List result = new ArrayList<>(); + for (ItemResolver resolver : resolverMap.values()) { + Collection resolverNames = resolver.getNames(); + if (resolverNames != null) { + result.addAll(resolverNames); + } + } + return result; } @Override @@ -144,6 +167,18 @@ public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb { @Override public String serialize(ItemStack is) { + return serialize(is, true); + } + + @Override + public String serialize(ItemStack is, boolean useResolvers) { + if (useResolvers) { + String serialized = tryResolverSerialize(is); + if (serialized != null) { + return serialized; + } + } + String mat = name(is); if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01) && is.getData().getData() != 0) { mat = mat + ":" + is.getData().getData(); @@ -287,8 +322,8 @@ public abstract class AbstractItemDb implements IConf, net.ess3.api.IItemDb { } if (baseDyeColor != null) { int basecolor = baseDyeColor - .getColor() - .asRGB(); + .getColor() + .asRGB(); sb.append("basecolor:").append(basecolor).append(" "); } for (org.bukkit.block.banner.Pattern p : bannerMeta.getPatterns()) { diff --git a/Essentials/src/com/earth2me/essentials/items/FlatItemDb.java b/Essentials/src/com/earth2me/essentials/items/FlatItemDb.java index 90f9e5959..202052956 100644 --- a/Essentials/src/com/earth2me/essentials/items/FlatItemDb.java +++ b/Essentials/src/com/earth2me/essentials/items/FlatItemDb.java @@ -102,7 +102,7 @@ public class FlatItemDb extends AbstractItemDb { @Override public ItemStack get(String id, boolean useResolvers) throws Exception { if (useResolvers) { - ItemStack resolved = tryResolvers(id); + ItemStack resolved = tryResolverDeserialize(id); if (resolved != null) { return resolved; } diff --git a/Essentials/src/com/earth2me/essentials/items/LegacyItemDb.java b/Essentials/src/com/earth2me/essentials/items/LegacyItemDb.java index 759616e38..ea9a47107 100644 --- a/Essentials/src/com/earth2me/essentials/items/LegacyItemDb.java +++ b/Essentials/src/com/earth2me/essentials/items/LegacyItemDb.java @@ -122,7 +122,7 @@ public class LegacyItemDb extends AbstractItemDb { @Override public ItemStack get(final String id, final boolean useResolvers) throws Exception { if (useResolvers) { - ItemStack resolved = tryResolvers(id); + ItemStack resolved = tryResolverDeserialize(id); if (resolved != null) { return resolved; } diff --git a/Essentials/src/net/ess3/api/IItemDb.java b/Essentials/src/net/ess3/api/IItemDb.java index dddd29f59..23efa958d 100644 --- a/Essentials/src/net/ess3/api/IItemDb.java +++ b/Essentials/src/net/ess3/api/IItemDb.java @@ -74,11 +74,53 @@ public interface IItemDb extends com.earth2me.essentials.api.IItemDb { */ ItemStack get(String name, boolean useResolvers) throws Exception; + /** + * Converts the given {@link ItemStack} to a string representation that can be saved. + * This is typically used for /createkit but may be used by other plugins for various purposes too. + * + * @param itemStack The stack to serialize + * @param useResolvers Whether to call other plugins' item resolvers before looking the + * item up in the database + * @return A string representation of the given item stack + */ + String serialize(ItemStack itemStack, boolean useResolvers); + @FunctionalInterface interface ItemResolver extends Function { + + /** + * Creates an item stack from the given name, if the given name is recognised by this resolver. + * + * @param name The name of the item to resolve + * @return A default stack of the item, or null if not recognised by this resolver. + */ + @Override + ItemStack apply(String name); + + /** + * Get all possible names that are recognised by this item resolver. + *

+ * Implementing this method is optional but recommended, since it enables custom items to be seen in tab complete. + * + * @return A collection of all the possible names for items that this resolver recognises. + */ default Collection getNames() { return null; } + + /** + * Get a name recognised by this resolver for the given ItemStack, and return null if none was found. + * The implementation of {@link ItemResolver#apply(String)} must recognise any string returned here. + * Note that if you return a string here, no extra meta will be added - if you want to add extra meta, you need to return it with your serialized string. + *

+ * Implementing this method is optional but recommended, since it enables custom items to be saved by /createkit. + * + * @param stack The stack to serialize + * @return The name of the item if a suitable name was found, else null + */ + default String serialize(ItemStack stack) { + return null; + } } }