diff --git a/buildSrc/src/main/kotlin/com.wolfyscript.wolfyutils.spigot.java-conventions.gradle.kts b/buildSrc/src/main/kotlin/com.wolfyscript.wolfyutils.spigot.java-conventions.gradle.kts index 0a2c4e41..af8f200c 100644 --- a/buildSrc/src/main/kotlin/com.wolfyscript.wolfyutils.spigot.java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/com.wolfyscript.wolfyutils.spigot.java-conventions.gradle.kts @@ -37,7 +37,7 @@ java { } group = "com.wolfyscript.wolfyutils.spigot" -version = "4.16.14.1" +version = "4.16.15-beta.2" val apiVersion = "4.16.1-SNAPSHOT" dependencies { diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryStackIdentifierParsers.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryStackIdentifierParsers.java new file mode 100644 index 00000000..e13f632c --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryStackIdentifierParsers.java @@ -0,0 +1,66 @@ +package com.wolfyscript.utilities.bukkit.registry; + +import com.google.common.base.Preconditions; +import com.wolfyscript.utilities.bukkit.world.items.reference.BukkitStackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackReference; +import me.wolfyscript.utilities.registry.Registries; +import me.wolfyscript.utilities.registry.RegistrySimple; +import me.wolfyscript.utilities.util.NamespacedKey; +import org.bukkit.inventory.ItemStack; + +import java.util.Comparator; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +public class RegistryStackIdentifierParsers extends RegistrySimple> { + + private List> priorityIndexedParsers = List.of(); + private final Registries registries; + + public RegistryStackIdentifierParsers(Registries registries) { + super(new NamespacedKey(registries.getCore(), "stack_identifier/parsers"), registries, (Class>)(Object) StackIdentifierParser.class); + this.registries = registries; + } + + @Override + public void register(NamespacedKey namespacedKey, StackIdentifierParser value) { + if (value != null) { + Preconditions.checkState(!this.map.containsKey(namespacedKey), "namespaced key '%s' already has an associated value!", namespacedKey); + map.put(namespacedKey, value); + reIndexParsers(); + } + } + + public List> sortedParsers() { + return priorityIndexedParsers; + } + + public StackIdentifier parseIdentifier(ItemStack stack) { + for (StackIdentifierParser parser : sortedParsers()) { + Optional identifierOptional = parser.from(stack); + if (identifierOptional.isPresent()) return identifierOptional.get(); + } + return new BukkitStackIdentifier(stack); + } + + public List> matchingParsers(ItemStack stack) { + return sortedParsers().stream().sorted().filter(stackIdentifierParser -> stackIdentifierParser.from(stack).isPresent()).toList(); + } + + /** + * + * + * @param stack + * @return + */ + public StackReference parseFrom(ItemStack stack) { + return new StackReference(registries.getCore(), parseIdentifier(stack), 1, 1, stack); + } + + private void reIndexParsers() { + priorityIndexedParsers = map.values().stream().sorted(Comparator.naturalOrder()).filter(Objects::nonNull).toList(); + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BukkitStackIdentifier.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BukkitStackIdentifier.java new file mode 100644 index 00000000..922b9179 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BukkitStackIdentifier.java @@ -0,0 +1,68 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import me.wolfyscript.utilities.util.NamespacedKey; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public class BukkitStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("bukkit"); + + private final ItemStack stack; + + public BukkitStackIdentifier(ItemStack stack) { + this.stack = stack; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + ItemStack cloned = stack.clone(); + cloned.setAmount(context.amount()); + return cloned; + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + if (other.getType() != stack.getType()) return false; + if (!ignoreAmount && other.getAmount() < stack.getAmount() * count) return false; + if (!stack.hasItemMeta() && !exact) return false; + return stack.isSimilar(other); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return -2048; + } + + @Override + public Optional from(ItemStack itemStack) { + return Optional.of(new BukkitStackIdentifier(itemStack.clone())); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("Bukkit").color(NamedTextColor.WHITE).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.LAVA_BUCKET) + ); + } + } + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemCreateContext.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemCreateContext.java new file mode 100644 index 00000000..b2f77bee --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemCreateContext.java @@ -0,0 +1,112 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public interface ItemCreateContext { + + int amount(); + + default Optional reference() { + return Optional.empty(); + } + + default Optional player() { + return Optional.empty(); + } + + default Optional world() { + return Optional.empty(); + } + + /** + * An empty implementation only containing the required values. + * + * @return An empty context only containing the required values + */ + static ItemCreateContext empty(int amount) { + return () -> amount; + } + + static Builder of(int amount) { + return new Builder.BuilderImpl(amount); + } + + static Builder of(StackReference reference) { + return of(reference.amount()).reference(reference); + } + + /** + * Builder to construct an ItemCreateContext + * + */ + interface Builder { + + Builder reference(StackReference reference); + + Builder player(Player player); + + Builder world(World world); + + ItemCreateContext build(); + + class BuilderImpl implements Builder { + + private final int amount; + private StackReference reference; + private Player player; + private World world; + + public BuilderImpl(int amount) { + this.amount = amount; + } + + @Override + public Builder reference(StackReference reference) { + this.reference = reference; + return this; + } + + @Override + public Builder player(Player player) { + this.player = player; + return this; + } + + @Override + public Builder world(World world) { + this.world = world; + return this; + } + + @Override + public ItemCreateContext build() { + return new ItemCreateContext() { + @Override + public int amount() { + return amount; + } + + @Override + public Optional reference() { + return Optional.ofNullable(reference); + } + + @Override + public Optional player() { + return Optional.ofNullable(player); + } + + @Override + public Optional world() { + return Optional.ofNullable(world); + } + }; + } + } + + } + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifier.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifier.java new file mode 100644 index 00000000..e38581da --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifier.java @@ -0,0 +1,211 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import me.wolfyscript.utilities.api.WolfyUtilCore; +import me.wolfyscript.utilities.api.inventory.custom_items.CustomItem; +import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; +import me.wolfyscript.utilities.api.inventory.custom_items.references.VanillaRef; +import me.wolfyscript.utilities.util.Keyed; +import me.wolfyscript.utilities.util.NamespacedKey; +import me.wolfyscript.utilities.util.inventory.ItemUtils; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.BiFunction; + +public interface StackIdentifier extends Keyed { + + /** + * Creates an item stack, this identifier points to, using the provided {@link ItemCreateContext}.
+ * The context can be used to create player specific stacks, specify the stack amount, and more. + * + * @param context The context for the item stack creation + * @return The item stack, that this identifier points to, created using the provided context + */ + ItemStack stack(ItemCreateContext context); + + /** + * Checks if the specified item stack matches the reference stack from this identifier. + * + * @param other The other stack to check for a match + * @return true if the other stack matches this identifier + */ + default boolean matches(ItemStack other) { + return matches(other, true, false); + } + + default boolean matches(ItemStack other, boolean exact) { + return matches(other, exact, false); + } + + default boolean matches(ItemStack other, boolean exact, boolean ignoreAmount) { + return matches(other, 1, exact, ignoreAmount); + } + + boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount); + + /** + * Gets the optional permission string this identifier requires + * + * @return Optional containing the permission string, or empty if not available + */ + default Optional permission() { + return Optional.empty(); + } + + /** + * Shrinks the specified stack by the given amount and returns the manipulated or replaced item! + *

+ *

Stackable ({@link #stack(ItemCreateContext)}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} > 1 or stack count > 1):

+ *

+ * The stack is shrunk by the specified amount ({@link #stack(ItemCreateContext)}.{@link ItemStack#getAmount() getAmount()} * count).
+ * For applying stackable replacements it calls the stackReplacement function with the already shrunken stack and this reference.
+ * Default behaviour can be found here: + *

    + *
  • {@link #shrink(ItemStack, int, boolean, Inventory, Player, Location)}
  • + *
  • {@link #shrinkUnstackableItem(ItemStack, boolean)}
  • + *
+ *

+ *

Un-stackable ({@link #stack(ItemCreateContext)}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} == 1 and stack count == 1):

+ *

+ * Redirects to {@link #shrinkUnstackableItem(ItemStack, boolean)}
+ *

+ * + * @param stack The input ItemStack, that is also going to be edited. + * @param count The amount of this custom item that should be removed from the input. + * @param useRemains If the Item should be replaced by the default craft remains. + * @param stackReplacement Behaviour of how to apply the replacements of stackable items. + * @return The manipulated stack, default remain, or custom remains. + */ + default ItemStack shrink(@NotNull ItemStack stack, int count, boolean useRemains, @NotNull BiFunction stackReplacement) { + if (stack(ItemCreateContext.empty(count)).getMaxStackSize() == 1 && stack.getAmount() == 1) { + return shrinkUnstackableItem(stack, useRemains); + } + int amount = stack.getAmount() - (stack(ItemCreateContext.empty(count)).getAmount() * count); + if (amount <= 0) { + stack = new ItemStack(Material.AIR); + } else { + stack.setAmount(amount); + } + return stackReplacement.apply(this, stack); + } + + /** + * Shrinks the specified stack by the given amount and returns the manipulated or replaced item! + *

+ *

Stackable ({@link #stack(ItemCreateContext)}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} > 1 or stack count > 1):

+ * The stack is shrunk by the specified amount ({@link #stack(ItemCreateContext)}.{@link ItemStack#getAmount() getAmount()} * count) + *

+ * If this stack has craft remains:
+ *

    + *
  • Location: Used as the drop location for remaining items.
    May be overridden by options below.
  • + *
  • + * Player: Adds items to the players inventory. + *
    Remaining items are still in the pool for the next options below. + *
    Player location is used as the drop location for remaining items.
  • + *
  • + * Inventory: Adds items to the inventory. + *
    Remaining items are still in the pool for the next options below. + *
    If location not available yet: uses inventory location as drop location for remaining items. + *
  • + *
+ * All remaining items that cannot be added to player or the other inventory are dropped at the specified location.
+ * Warning! If you do not provide a location via player, inventory, or location, then the remaining items are discarded!
+ * For custom behaviour see {@link #shrink(ItemStack, int, boolean, BiFunction)}. + *

+ *

+ *

+ *

Un-stackable ({@link #stack(ItemCreateContext)}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} == 1 and stack count == 1):

+ * Redirects to {@link #shrinkUnstackableItem(ItemStack, boolean)}
+ *

+ *

+ *
+ * + * @param stack The input ItemStack, that is also going to be edited. + * @param count The amount of this custom item that should be removed from the input. + * @param useRemains If the Item should be replaced by the default craft remains. + * @param inventory The optional inventory to add the replacements to. (Only for stackable items) + * @param player The player to give the items to. If the players' inventory has space the craft remains are added. (Only for stackable items) + * @param location The location where the replacements should be dropped. (Only for stackable items) + * @return The manipulated stack, default remain, or custom remains. + */ + default ItemStack shrink(ItemStack stack, int count, boolean useRemains, @Nullable final Inventory inventory, @Nullable final Player player, @Nullable final Location location) { + return shrink(stack, count, useRemains, (customItem, resultStack) -> CustomItem.craftRemain(stack(ItemCreateContext.empty(count))) + .map(material -> useRemains ? new ItemStack(material) : null) + .map(replacement -> { + var originalStack = resultStack; + int replacementAmount = count; + if (ItemUtils.isAirOrNull(originalStack)) { + int returnableAmount = Math.min(replacement.getMaxStackSize(), replacementAmount); + replacementAmount -= returnableAmount; + originalStack = replacement.clone(); + originalStack.setAmount(replacementAmount); + } + if (replacementAmount > 0) { + replacement.setAmount(replacementAmount); + Location loc = location; + if (player != null) { + replacement = player.getInventory().addItem(replacement).get(0); + loc = player.getLocation(); + } + if (inventory != null && replacement != null) { + replacement = inventory.addItem(replacement).get(0); + if (loc == null) loc = inventory.getLocation(); + } + if (loc != null && replacement != null && loc.getWorld() != null) { + loc.getWorld().dropItemNaturally(loc.add(0.5, 1.0, 0.5), replacement); + } + } + return originalStack; + }).orElse(new ItemStack(Material.AIR))); + } + + /** + * Shrinks the specified stack and returns the manipulated or replaced item! + *

+ * This firstly checks for custom replacements (remains) and sets it as the result.
+ * Then handles damaging of the stack, if there is a specified durability cost.
+ * In case the stack breaks due damage it is replaced by the result, specified earlier. + *

+ * + * @param stack The stack to shrink + * @param useRemains If the Item should be replaced by the default craft remains. + * @return The manipulated (damaged) stack, default remain, or custom remains. + */ + default ItemStack shrinkUnstackableItem(ItemStack stack, boolean useRemains) { + return CustomItem.craftRemain(stack(ItemCreateContext.empty(1))).map(material -> useRemains ? new ItemStack(material) : null).orElse(new ItemStack(Material.AIR)); + } + + default StackIdentifierParser parser() { + return WolfyUtilCore.getInstance().getRegistries().getStackIdentifierParsers().get(getNamespacedKey()); + } + + @Override + NamespacedKey getNamespacedKey(); + + /** + * Used for backwards compatibility with {@link APIReference}s. + * By default, this returns a {@link VanillaRef} build using the {@link #stack(ItemCreateContext)} method. + * Other implementations may choose to return their old related APIReference implementation. + *

+ * Note that the new Identifiers are one level lower than APIReferences, so they no longer share the weight, and amount properties. + * Those properties are now part of the higher level {@link StackReference}. + *

+ * + * @param weight The weight of the StackReference + * @param amount The amount of the StackReference + * @return The old APIReference, either implementation specific, or {@link VanillaRef} by default + */ + @Deprecated + default APIReference convert(double weight, int amount) { + var ref = new VanillaRef(stack(ItemCreateContext.empty(1))); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifierParser.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifierParser.java new file mode 100644 index 00000000..3b16a2a8 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifierParser.java @@ -0,0 +1,45 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import me.wolfyscript.utilities.util.Keyed; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; + +public interface StackIdentifierParser extends Keyed, Comparable> { + + int priority(); + + default DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text(getNamespacedKey().toString()), + new DisplayConfiguration.MaterialIconSettings(Material.WRITABLE_BOOK) + ); + } + + Optional from(ItemStack itemStack); + + @Override + default int compareTo(@NotNull StackIdentifierParser that) { + return Integer.compare(that.priority(), this.priority()); + } + + interface DisplayConfiguration { + + Component name(); + + IconSettings icon(); + + interface IconSettings { } + + record StackIconSettings(ItemStack stack) implements IconSettings { } + + record MaterialIconSettings(Material material) implements IconSettings { } + + record SimpleDisplayConfig(Component name, IconSettings icon) implements DisplayConfiguration { } + + } + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifierParserSettings.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifierParserSettings.java new file mode 100644 index 00000000..1bc64f78 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackIdentifierParserSettings.java @@ -0,0 +1,59 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import me.wolfyscript.utilities.api.WolfyUtilCore; +import me.wolfyscript.utilities.util.NamespacedKey; +import org.bukkit.inventory.ItemStack; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Set; + +@Retention(RetentionPolicy.RUNTIME) +public @interface StackIdentifierParserSettings { + + /** + * The priority of this parser.
+ * Parser with higher priority are called before Parsers with lower priority.
+ * Each time it chooses the next parser, if and only if the current parser returns null.
+ * The moment it returns a non-null value that value is used. + * + * @return The priority of this parser. + */ + short priority() default 0; + + /** + * The class of the custom Reference Parser + * + * @return The Parser for this ItemReference Type + */ + Class> parser(); + + String plugin() default ""; + + @interface ParseMethod { + + + } + + class Builder { + + public static StackIdentifierParser create(NamespacedKey id, Class identifierType) { + StackIdentifierParserSettings annotation = identifierType.getAnnotation(StackIdentifierParserSettings.class); + if (annotation == null) return null; + + Set potentialParserMethods = WolfyUtilCore.getInstance().getReflections().getMethodsAnnotatedWith(ParseMethod.class); + for (Method potentialParserMethod : potentialParserMethods) { + if (Arrays.equals(potentialParserMethod.getParameterTypes(), new Class[]{ ItemStack.class })) { + + } + } + + return null; + } + + } + + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackReference.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackReference.java new file mode 100644 index 00000000..097a9929 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/StackReference.java @@ -0,0 +1,343 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdNodeBasedDeserializer; +import com.wolfyscript.utilities.Copyable; +import me.wolfyscript.utilities.api.WolfyUtilCore; +import me.wolfyscript.utilities.api.inventory.custom_items.CustomItem; +import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; +import me.wolfyscript.utilities.util.NamespacedKey; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Consumer; + +/** + * Acts as a wrapper for {@link StackIdentifier}, that links to an external ItemStack (like other Plugins). + * This keeps track of the original ItemStack, as a fallback, and the parser used to get the wrapped {@link StackIdentifier}. + * Additionally, it stores the amount, and other extra settings. + *
+ * This is usually stored in JSON (HOCON) files, while the {@link StackIdentifier} is not. + */ +@JsonDeserialize(using = StackReference.Deserializer.class) +public class StackReference implements Copyable { + + private final WolfyUtilCore core; + private final int customAmount; + private final double weight; + /** + * Used to store the original stack + */ + private final ItemStack stack; + /** + * Used to store the previous parser result + */ + private final StackIdentifier identifier; + private StackIdentifierParser parser; + + public static StackReference of(ItemStack itemStack) { + return new StackReference(WolfyUtilCore.getInstance(), new BukkitStackIdentifier(itemStack), 1, 1, itemStack); + } + + public StackReference(WolfyUtilCore core, NamespacedKey parser, double weight, int customAmount, ItemStack item) { + this.customAmount = customAmount; + this.weight = weight; + this.core = core; + this.parser = core.getRegistries().getStackIdentifierParsers().get(parser); + this.stack = item; + this.identifier = parseIdentifier(); + } + + public StackReference(WolfyUtilCore core, @NotNull StackIdentifierParser parser, double weight, int customAmount, ItemStack item) { + this.customAmount = customAmount; + this.weight = weight; + this.core = core; + this.parser = parser; + this.stack = item; + this.identifier = parseIdentifier(); + } + + public StackReference(WolfyUtilCore core, @NotNull StackIdentifier identifier, double weight, int customAmount, ItemStack item) { + this.customAmount = customAmount; + this.weight = weight; + this.core = core; + this.parser = core.getRegistries().getStackIdentifierParsers().get(identifier.getNamespacedKey()); + this.stack = item; + this.identifier = identifier; + } + + private StackReference(StackReference stackReference) { + this.weight = stackReference.weight; + this.customAmount = stackReference.customAmount; + this.core = stackReference.core; + this.parser = stackReference.parser; + this.stack = stackReference.stack; + this.identifier = parseIdentifier(); + } + + private StackIdentifier parseIdentifier() { + Optional identifierOptional = parser.from(stack); + if (identifierOptional.isPresent()) return identifierOptional.get(); + return new BukkitStackIdentifier(stack); + } + + /** + * Gets the currently wrapped StackIdentifier, parsed by the current {@link StackIdentifierParser} + * + * @return The currently wrapped StackIdentifier + */ + public StackIdentifier identifier() { + return identifier; + } + + public boolean matches(ItemStack other) { + return matches(other, true, false); + } + + public boolean matches(ItemStack other, boolean exact) { + return matches(other, exact, false); + } + + public boolean matches(ItemStack other, boolean exact, boolean ignoreAmount) { + return identifier().matches(other, customAmount, exact, ignoreAmount); + } + + /** + * Convenience method to get the stack the identifier points to.
+ * This is the same as {@link #identifier() identifier()}.{@link StackIdentifier#stack(ItemCreateContext) stack}({@link ItemCreateContext#of(StackReference) ItemCreateContext.of}({@link StackReference this}).{@link ItemCreateContext.Builder#build() build()}) + * + * @return The stack the {@link #identifier()} points to + */ + public ItemStack referencedStack() { + return identifier().stack(ItemCreateContext.of(this).build()); + } + + /** + * Convenience method to get the stack the identifier points to.
+ * This is the same as {@link #identifier() identifier()}.{@link StackIdentifier#stack(ItemCreateContext) stack}({@link ItemCreateContext#of(StackReference) ItemCreateContext.of}({@link StackReference this}).{@link ItemCreateContext.Builder#build() build()}) + * + * @param contextBuild provides a {@link ItemCreateContext.Builder} with this reference already applied + * @return The stack the {@link #identifier()} points to + */ + public ItemStack referencedStack(Consumer contextBuild) { + ItemCreateContext.Builder builder = ItemCreateContext.of(this); + contextBuild.accept(builder); + return identifier().stack(builder.build()); + } + + /** + * Gets the ORIGINAL stack, from which this reference was created from!
+ * For the linked stack from for example an external plugin use {@link #identifier()}! + * + * @return The ORIGINAL stack this reference was created from + * @see #identifier() Get the StackIdentifier pointing to the external stack + * @see #referencedStack() Get the externally referenced ItemStack + */ + @JsonGetter("stack") + public ItemStack originalStack() { + return stack; + } + + /** + * Gets the weight associated with this reference inside a collection.
+ * For example inside of a {@link me.wolfyscript.utilities.util.RandomCollection} + * + * @return The weight of this reference + */ + @JsonGetter("weight") + public double weight() { + return weight; + } + + /** + * Gets the stack amount for the referenced ItemStack + * + * @return The stack amount of the referenced ItemStack + */ + @JsonGetter("amount") + public int amount() { + return customAmount; + } + + /** + * Gets the currently used {@link StackIdentifierParser} + * + * @return The current {@link StackIdentifierParser} + */ + public StackIdentifierParser parser() { + return parser; + } + + /** + * Swaps the current parser with the specified parser and parses the original stack to get the new StackIdentifier. + * + * @param parser The new parser to use to get the StackIdentifier + */ + public void swapParser(StackIdentifierParser parser) { + this.parser = parser; + parseIdentifier(); + } + + /** + * Gets the id of the current parser + * + * @return The id of the current parser + */ + @JsonGetter("parser") + private NamespacedKey parserId() { + return parser.getNamespacedKey(); + } + + @Override + public StackReference copy() { + return new StackReference(this); + } + + /** + * Shrinks the specified stack by the given amount and returns the manipulated or replaced item! + *

+ *

Stackable ({@link #originalStack()}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} > 1 or stack count > 1):

+ *

+ * The stack is shrunk by the specified amount ({@link #amount()} * totalAmount).
+ * For applying stackable replacements it calls the stackReplacement function with the already shrunken stack and this reference.
+ * Default behaviour can be found here: + *

    + *
  • {@link #shrink(ItemStack, int, boolean, Inventory, Player, Location)}
  • + *
  • {@link #shrinkUnstackableItem(ItemStack, boolean)}
  • + *
+ *

+ *

Un-stackable ({@link #originalStack()}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} == 1 and stack count == 1):

+ *

+ * Redirects to {@link #shrinkUnstackableItem(ItemStack, boolean)}
+ *

+ * + * @param stack The input ItemStack, that is also going to be edited. + * @param count The amount of this custom item that should be removed from the input. + * @param useRemains If the Item should be replaced by the default craft remains. + * @param stackReplacement Behaviour of how to apply the replacements of stackable items. + * @return The manipulated stack, default remain, or custom remains. + */ + public ItemStack shrink(@NotNull ItemStack stack, int count, boolean useRemains, @NotNull BiFunction stackReplacement) { + return identifier().shrink(stack, count * amount(), useRemains, stackReplacement); + } + + /** + * Shrinks the specified stack by the given amount and returns the manipulated or replaced item! + *

+ *

Stackable ({@link #originalStack()}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} > 1 or stack count > 1):

+ * The stack is shrunk by the specified amount ({@link #amount()} * count) + *

+ * If this stack has craft remains:
+ *

    + *
  • Location: Used as the drop location for remaining items.
    May be overridden by options below.
  • + *
  • + * Player: Adds items to the players inventory. + *
    Remaining items are still in the pool for the next options below. + *
    Player location is used as the drop location for remaining items.
  • + *
  • + * Inventory: Adds items to the inventory. + *
    Remaining items are still in the pool for the next options below. + *
    If location not available yet: uses inventory location as drop location for remaining items. + *
  • + *
+ * All remaining items that cannot be added to player or the other inventory are dropped at the specified location.
+ * Warning! If you do not provide a location via player, inventory, or location, then the remaining items are discarded!
+ * For custom behaviour see {@link #shrink(ItemStack, int, boolean, BiFunction)}. + *

+ *

+ *

+ *

Un-stackable ({@link #originalStack()}.{@link ItemStack#getMaxStackSize() getMaxStackSize()} == 1 and stack count == 1):

+ * Redirects to {@link #shrinkUnstackableItem(ItemStack, boolean)}
+ *

+ *

+ *
+ * + * @param stack The input ItemStack, that is also going to be edited. + * @param count The amount of this custom item that should be removed from the input. + * @param useRemains If the Item should be replaced by the default craft remains. + * @param inventory The optional inventory to add the replacements to. (Only for stackable items) + * @param player The player to give the items to. If the players' inventory has space the craft remains are added. (Only for stackable items) + * @param location The location where the replacements should be dropped. (Only for stackable items) + * @return The manipulated stack, default remain, or custom remains. + */ + public ItemStack shrink(ItemStack stack, int count, boolean useRemains, @Nullable final Inventory inventory, @Nullable final Player player, @Nullable final Location location) { + return identifier().shrink(stack, count, useRemains, inventory, player, location); + } + + /** + * Shrinks the specified stack and returns the manipulated or replaced item! + *

+ * This firstly checks for custom replacements (remains) and sets it as the result.
+ * Then handles damaging of the stack, if there is a specified durability cost.
+ * In case the stack breaks due damage it is replaced by the result, specified earlier. + *

+ * + * @param stack The stack to shrink + * @param useRemains If the Item should be replaced by the default craft remains. + * @return The manipulated (damaged) stack, default remain, or custom remains. + */ + public ItemStack shrinkUnstackableItem(ItemStack stack, boolean useRemains) { + return identifier().shrinkUnstackableItem(stack, useRemains); + } + + /** + * Converts this StackReference into a legacy APIReference. + */ + @Deprecated + public APIReference convert() { + return identifier().convert(weight, customAmount); + } + + /** + * Converts this reference to the old behaviour of the CustomItem. + * If the reference points to a WolfyUtils CustomItem, then that item is returned. + * Otherwise, it returns a CustomItem wrapping this reference. + * + * @return A CustomItem wrapping this reference, or the saved CustomItem if pointing to a WolfyUtils Item + */ + @Deprecated + public CustomItem convertToLegacy() { + if (identifier() instanceof WolfyUtilsStackIdentifier wolfyUtilsStackIdentifier) { + return wolfyUtilsStackIdentifier.customItem().orElse(new CustomItem(Material.AIR)); + } + return new CustomItem(this); + } + + public static class Deserializer extends StdNodeBasedDeserializer { + + private final WolfyUtilCore core; + + protected Deserializer() { + super(StackReference.class); + this.core = WolfyUtilCore.getInstance(); + } + + @Override + public StackReference convert(JsonNode root, DeserializationContext ctxt) throws IOException { + if (root.has("parser")) { + // New ItemReference used! No conversion required! + return new StackReference(core, + ctxt.readTreeAsValue(root.get("parser"), NamespacedKey.class), + root.get("weight").asDouble(1), + root.get("amount").asInt(1), + ctxt.readTreeAsValue(root.get("stack"), ItemStack.class) + ); + } + // Need to convert APIReference + APIReference apiReference = ctxt.readTreeAsValue(root, APIReference.class); + return apiReference.convertToStackReference(); + } + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/WolfyUtilsStackIdentifier.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/WolfyUtilsStackIdentifier.java new file mode 100644 index 00000000..ba8ae59f --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/WolfyUtilsStackIdentifier.java @@ -0,0 +1,103 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import me.wolfyscript.utilities.api.WolfyUtilCore; +import me.wolfyscript.utilities.api.WolfyUtilities; +import me.wolfyscript.utilities.api.inventory.custom_items.CustomItem; +import me.wolfyscript.utilities.util.NamespacedKey; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +import java.util.Objects; +import java.util.Optional; + +public class WolfyUtilsStackIdentifier implements StackIdentifier { + + private static final org.bukkit.NamespacedKey CUSTOM_ITEM_KEY = new org.bukkit.NamespacedKey(WolfyUtilities.getWUPlugin(), "custom_item"); + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("wolfyutils"); + + private final NamespacedKey namespacedKey; + + public WolfyUtilsStackIdentifier(NamespacedKey namespacedKey) { + this.namespacedKey = namespacedKey; + } + + /** + * Gets the stack this identifier references. + * It uses the {@link CustomItem#create()} method to create the stack, or returns null if the referenced {@link CustomItem} is unavailable. + * + * @return The referenced ItemStack or null if referenced {@link CustomItem} is unavailable + */ + @Override + public ItemStack stack(ItemCreateContext context) { + return customItem().map(customItem -> customItem.create(context.amount())).orElseGet(() -> { + WolfyUtilities.getWUCore().getConsole().warn("Couldn't find CustomItem for " + namespacedKey.toString()); + return null; + }); + } + + /** + * Gets the {@link CustomItem} this identifier references. + * + * @return The referenced {@link CustomItem} of this identifier + */ + public Optional customItem() { + return Optional.ofNullable(WolfyUtilCore.getInstance().getRegistries().getCustomItems().get(namespacedKey)); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + if (other == null) return false; + var itemMeta = other.getItemMeta(); + if (itemMeta == null) return false; + var container = itemMeta.getPersistentDataContainer(); + if (container.has(CUSTOM_ITEM_KEY, PersistentDataType.STRING)) { + return Objects.equals(this.namespacedKey, NamespacedKey.of(container.get(CUSTOM_ITEM_KEY, PersistentDataType.STRING))); + } + return false; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + if (itemStack == null) return Optional.empty(); + var itemMeta = itemStack.getItemMeta(); + if (itemMeta != null) { + var container = itemMeta.getPersistentDataContainer(); + if (container.has(CUSTOM_ITEM_KEY, PersistentDataType.STRING)) { + return Optional.of(new WolfyUtilsStackIdentifier(NamespacedKey.of(container.get(CUSTOM_ITEM_KEY, PersistentDataType.STRING)))); + } + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("WolfyUtils").color(NamedTextColor.DARK_AQUA).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.CRAFTING_TABLE) + ); + } + } + + +} diff --git a/core/src/main/java/me/wolfyscript/utilities/api/WolfyUtilCore.java b/core/src/main/java/me/wolfyscript/utilities/api/WolfyUtilCore.java index 9abfc279..1479aaf2 100644 --- a/core/src/main/java/me/wolfyscript/utilities/api/WolfyUtilCore.java +++ b/core/src/main/java/me/wolfyscript/utilities/api/WolfyUtilCore.java @@ -38,6 +38,8 @@ import com.wolfyscript.utilities.bukkit.persistent.player.CustomPlayerData; import com.wolfyscript.utilities.bukkit.persistent.player.PlayerParticleEffectData; import com.wolfyscript.utilities.bukkit.persistent.world.CustomBlockData; +import com.wolfyscript.utilities.bukkit.world.items.reference.BukkitStackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.WolfyUtilsStackIdentifier; import com.wolfyscript.utilities.common.WolfyCore; import com.wolfyscript.utilities.bukkit.commands.ChatActionCommand; import com.wolfyscript.utilities.bukkit.commands.InfoCommand; @@ -209,6 +211,13 @@ protected WolfyUtilCore() { this.messageFactory = new MessageFactory(this); this.persistentStorage = new PersistentStorage(this); this.functionalRecipeGenerator = FunctionalRecipeGenerator.create(this); + + // Data that needs to be registered + getLogger().info("Register Default StackIdentifiers"); + var stackIdentifierParsers = getRegistries().getStackIdentifierParsers(); + stackIdentifierParsers.register(new BukkitStackIdentifier.Parser()); + stackIdentifierParsers.register(new WolfyUtilsStackIdentifier.Parser()); + } protected abstract CompatibilityManager createCompatibilityManager(); diff --git a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/CustomItem.java b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/CustomItem.java index 5537d79c..f6d86f9e 100644 --- a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/CustomItem.java +++ b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/CustomItem.java @@ -26,6 +26,10 @@ import com.google.common.collect.Streams; import com.wolfyscript.utilities.bukkit.items.CustomBlockSettings; import com.wolfyscript.utilities.bukkit.items.CustomItemData; +import com.wolfyscript.utilities.bukkit.world.items.reference.BukkitStackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.WolfyUtilsStackIdentifier; import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.api.WolfyUtilities; import me.wolfyscript.utilities.api.inventory.custom_items.meta.CustomItemTagMeta; @@ -40,7 +44,6 @@ import me.wolfyscript.utilities.registry.Registries; import me.wolfyscript.utilities.util.Keyed; import me.wolfyscript.utilities.util.NamespacedKey; -import me.wolfyscript.utilities.util.Reflection; import me.wolfyscript.utilities.util.inventory.InventoryUtils; import me.wolfyscript.utilities.util.inventory.ItemUtils; import me.wolfyscript.utilities.util.inventory.item_builder.AbstractItemBuilder; @@ -62,7 +65,6 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.lang.reflect.Method; import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; @@ -126,8 +128,8 @@ public static void registerAPIReferenceParser(APIReference.Parser parser) { @JsonIgnore private final Material craftRemain; - @JsonAlias("api_reference") - private final APIReference apiReference; + @JsonAlias({"api_reference", "apiReference", "item"}) + private final StackReference reference; @JsonAlias("custom_data") private final CustomData.DeprecatedCustomDataWrapper customDataMap = new CustomData.DeprecatedCustomDataWrapper(this); @@ -144,7 +146,7 @@ public static void registerAPIReferenceParser(APIReference.Parser parser) { private double rarityPercentage; private String permission; private MetaSettings nbtChecks; - private APIReference replacement; + private StackReference replacement; @JsonAlias("fuel") private FuelSettings fuelSettings; @JsonAlias("durability_cost") @@ -158,15 +160,15 @@ public static void registerAPIReferenceParser(APIReference.Parser parser) { private boolean checkOldMetaSettings = true; @JsonCreator - public CustomItem(@JsonProperty("apiReference") @JsonAlias({"item", "api_reference"}) APIReference apiReference) { + public CustomItem(@JsonProperty("reference") @JsonAlias({"item", "api_reference", "apiReference"}) StackReference reference) { super(CustomItem.class); - this.apiReference = apiReference; + this.reference = reference; this.namespacedKey = null; this.fuelSettings = new FuelSettings(); setMetaSettings(new MetaSettings()); this.permission = ""; - this.rarityPercentage = apiReference.getWeight() > 0 ? apiReference.getWeight() : 1.0d; + this.rarityPercentage = reference.weight() > 0 ? reference.weight() : 1.0d; for (CustomData.Provider customData : WolfyUtilCore.getInstance().getRegistries().getCustomItemData().values()) { addCustomData(customData.getNamespacedKey(), customData.createData()); } @@ -226,7 +228,7 @@ protected void setOldProperties(String fieldKey, JsonNode value) throws JsonProc * @param itemStack the itemstack this CustomItem will be linked to */ public CustomItem(ItemStack itemStack) { - this(new VanillaRef(itemStack)); + this(new StackReference(WolfyUtilCore.getInstance(), BukkitStackIdentifier.ID, 1, 1, itemStack)); } /** @@ -243,7 +245,7 @@ public CustomItem(Material material) { */ private CustomItem(CustomItem customItem) { super(CustomItem.class); - this.apiReference = customItem.apiReference.clone(); + this.reference = customItem.reference.copy(); this.namespacedKey = customItem.getNamespacedKey(); this.fuelSettings = customItem.fuelSettings.clone(); @@ -282,6 +284,21 @@ public CustomItem clone() { return new CustomItem(this); } + /** + *

+ * This will create a new {@link CustomItem} that wraps the specified reference. + *

+ *

+ *

+ * + * @param reference The reference to wrap + * @return A new CustomItem instance that wraps the specified reference + */ + public static Optional wrap(StackReference reference) { + if (reference == null) return Optional.empty(); + return Optional.of(new CustomItem(reference)); + } + /** *

* This will create a new {@link CustomItem} instance with the specified APIReference. @@ -296,10 +313,12 @@ public CustomItem clone() { * * @param reference The reference to link the item to. * @return A new CustomItem instance with the specified APIReference. + * @deprecated APIReferences were replaced by {@link StackReference}s! Use {@link #wrap(StackReference)} instead! */ + @Deprecated(forRemoval = true) public static CustomItem with(APIReference reference) { if (reference == null) return null; - return new CustomItem(reference); + return new CustomItem(reference.convertToStackReference()); } /** @@ -318,8 +337,10 @@ public static CustomItem with(APIReference reference) { * * @param reference The reference that points to an API Item. * @return The actual CustomItem of the APIReference. + * @deprecated APIReferences were replaced by {@link StackReference}s! Use {@link WolfyUtilsStackIdentifier#customItem()} or {@link #wrap(StackReference)} instead! */ @Nullable + @Deprecated(forRemoval = true) public static CustomItem of(APIReference reference) { if (reference == null) return null; return reference instanceof WolfyUtilitiesRef ? WolfyUtilCore.getInstance().getRegistries().getCustomItems().get(((WolfyUtilitiesRef) reference).getNamespacedKey()) : with(reference); @@ -335,12 +356,15 @@ public static CustomItem of(APIReference reference) { */ public static CustomItem getReferenceByItemStack(ItemStack itemStack) { if (itemStack != null) { - APIReference apiReference = API_REFERENCE_PARSER.values().stream().sorted(Comparator.reverseOrder()).map(parser -> parser.construct(itemStack)).filter(Objects::nonNull).findFirst().orElse(null); - if (apiReference != null) { - apiReference.setAmount(itemStack.getAmount()); - return new CustomItem(apiReference); - } - return new CustomItem(itemStack); + WolfyUtilCore core = WolfyUtilCore.getInstance(); + StackReference reference = new StackReference( + core, + core.getRegistries().getStackIdentifierParsers().parseIdentifier(itemStack), + 1d, + itemStack.getAmount(), + itemStack + ); + return new CustomItem(reference); } return null; } @@ -391,29 +415,35 @@ public void setNamespacedKey(NamespacedKey namespacedKey) { /** * The replacement can be any of {@link APIReference} and it will replace this item when it is removed from the inventory using {@link #remove(ItemStack, int, Inventory, Location, boolean)}. * - * @return True if this item has an replacement that is not AIR, else false. + * @return True if this item has a replacement that is not AIR, else false. + * @deprecated APIReferences were replaced by {@link StackReference}s! Use {@link #replacement()}, which returns an {@link Optional} instead! */ + @Deprecated(forRemoval = true) public boolean hasReplacement() { - return replacement != null && !replacement.getLinkedItem().getType().equals(Material.AIR); + return replacement().isPresent(); } /** * The replacement can be any of {@link APIReference} and it will replace this item when it is removed from the inventory using {@link #remove(ItemStack, int, Inventory, Location, boolean)}. * * @return The {@link APIReference} of the custom replacement. + * @deprecated APIReferences were replaced by {@link StackReference}s! Use {@link #replacement()} instead! */ @Nullable + @Deprecated(forRemoval = true) public APIReference getReplacement() { - return hasReplacement() ? replacement : null; + return hasReplacement() ? replacement.convert() : null; } /** * The replacement can be any of {@link APIReference} and it will replace this item when it is removed from the inventory using {@link #remove(ItemStack, int, Inventory, Location, boolean)}. * * @param replacement The replacement for this item. + * @deprecated APIReferences were replaced by {@link StackReference}s! Use {@link #replacement(StackReference)} instead! */ + @Deprecated(forRemoval = true) public void setReplacement(@Nullable APIReference replacement) { - this.replacement = replacement; + this.replacement = replacement.convertToStackReference(); } /** @@ -644,7 +674,7 @@ public boolean equals(Object o) { Objects.equals(fuelSettings, that.fuelSettings) && Objects.equals(permission, that.permission) && Objects.equals(equipmentSlots, that.equipmentSlots) && - Objects.equals(apiReference, that.apiReference) && + Objects.equals(reference, that.reference) && Objects.equals(particleContent, that.particleContent) && Objects.equals(nbtChecks, that.nbtChecks); } @@ -662,7 +692,7 @@ public int hashCode() { */ @Override public ItemStack getItemStack() { - return apiReference.getLinkedItem(); + return reference.identifier().stack(ItemCreateContext.empty(getAmount())); } /** @@ -686,7 +716,7 @@ public ItemStack create() { * @return the item from the external API that is linked to this object */ public ItemStack create(int amount) { - var itemStack = apiReference.getLinkedItem().clone(); + var itemStack = reference.identifier().stack(ItemCreateContext.empty(amount)).clone(); if (this.hasNamespacedKey()) { var itemMeta = itemStack.getItemMeta(); var container = itemMeta.getPersistentDataContainer(); @@ -707,7 +737,7 @@ public ItemStack create(int amount) { * @return ItemStack that visually represents the namespacekey * @see #getIDItem(int) */ - @Deprecated + @Deprecated(forRemoval = true) public ItemStack getIDItem() { return getIDItem(getAmount()); } @@ -719,17 +749,23 @@ public ItemStack getIDItem() { * @param amount The stacksize of the item * @return ItemStack that visually represents the namespacekey */ - @Deprecated + @Deprecated(forRemoval = true) public ItemStack getIDItem(int amount) { - var itemStack = apiReference.getIdItem(); + var itemStack = reference.originalStack().clone(); if (amount > 0) { itemStack.setAmount(amount); } return itemStack; } + @Deprecated(forRemoval = true) public APIReference getApiReference() { - return apiReference; + return reference.convert(); + } + + @JsonGetter("reference") + public StackReference stackReference() { + return reference; } /** @@ -739,7 +775,7 @@ public APIReference getApiReference() { * @param location The location where the replacements should be dropped. (Only for stackable items) * @deprecated Renamed to {@link #remove(ItemStack, int, Inventory, Location)} to better show it's functionality. */ - @Deprecated + @Deprecated(forRemoval = true, since = "4.16.14") public void consumeItem(ItemStack input, int totalAmount, Inventory inventory, Location location) { remove(input, totalAmount, inventory, location); } @@ -750,7 +786,7 @@ public void consumeItem(ItemStack input, int totalAmount, Inventory inventory, L * @param inventory The optional inventory to add the replacements to. (Only for stackable items) * @deprecated Renamed to {@link #remove(ItemStack, int, Inventory)} to better show it's functionality. */ - @Deprecated + @Deprecated(forRemoval = true, since = "4.16.14") public void consumeItem(ItemStack input, int totalAmount, Inventory inventory) { remove(input, totalAmount, inventory); } @@ -761,7 +797,7 @@ public void consumeItem(ItemStack input, int totalAmount, Inventory inventory) { * @param location The location where the replacements should be dropped. (Only for stackable items) * @deprecated Renamed to {@link #remove(ItemStack, int, Location)} to better show it's functionality. */ - @Deprecated + @Deprecated(forRemoval = true, since = "4.16.14") public ItemStack consumeItem(ItemStack input, int totalAmount, Location location) { return remove(input, totalAmount, location); } @@ -770,7 +806,7 @@ public ItemStack consumeItem(ItemStack input, int totalAmount, Location location * @param input The input ItemStack, that is going to be edited. * @deprecated Replaced by {@link #removeUnStackableItem(ItemStack)} */ - @Deprecated + @Deprecated(forRemoval = true, since = "4.16.14") public void consumeUnstackableItem(ItemStack input) { removeUnStackableItem(input); } @@ -974,11 +1010,9 @@ public ItemStack remove(ItemStack input, int totalAmount, Location location) { } private void applyStackableReplacement(int totalAmount, boolean replaceWithRemains, @Nullable Player player, @Nullable Inventory inventory, @Nullable Location location) { - ItemStack replacement = isConsumed() && replaceWithRemains && craftRemain != null ? new ItemStack(craftRemain) : null; - if (this.hasReplacement()) { - assert getReplacement() != null; - replacement = new CustomItem(getReplacement()).create(); - } + ItemStack replacement = replacement() + .map(StackReference::originalStack) + .orElseGet(() -> isConsumed() && replaceWithRemains && craftRemain != null ? new ItemStack(craftRemain) : null); if (replacement != null) { replacement.setAmount(replacement.getAmount() * totalAmount); if (player != null) { @@ -1003,6 +1037,29 @@ private void applyStackableReplacement(int totalAmount, boolean replaceWithRemai } } + /** + * Gets the replacement of this CustomItem. + * + * @return Optional containing the current replacement, or empty if unset + */ + public Optional replacement() { + return Optional.ofNullable(replacement); + } + + /** + * Sets the new replacement of this CustomItem. + * The reference may be null, in which case it unsets any existing replacement. + * + * @param replacement The new replacement, or null to unset it + */ + public void replacement(StackReference replacement) { + if(replacement != null && replacement.identifier() != null && !ItemUtils.isAirOrNull(replacement.identifier().stack(ItemCreateContext.empty(getAmount())))) { + this.replacement = replacement; + } else { + this.replacement = null; + } + } + /** * Removes the input as an un-stackable item. *

@@ -1043,13 +1100,13 @@ public void removeUnStackableItem(ItemStack input, boolean replaceWithRemains) { input.setAmount(0); } } - if (this.hasReplacement()) { - ItemStack replace = new CustomItem(this.getReplacement()).create(); + replacement().ifPresentOrElse(stackReference1 -> { + ItemStack replace = new CustomItem(stackReference1).create(); input.setType(replace.getType()); input.setItemMeta(replace.getItemMeta()); input.setData(replace.getData()); input.setAmount(replace.getAmount()); - } else if (this.getDurabilityCost() != 0) { + }, () -> { var itemBuilder = new ItemBuilder(input); if (itemBuilder.hasCustomDurability()) { itemBuilder.setCustomDamage(itemBuilder.getCustomDamage() + this.getDurabilityCost()); @@ -1065,7 +1122,7 @@ public void removeUnStackableItem(ItemStack input, boolean replaceWithRemains) { } } input.setItemMeta(itemMeta); - } + }); } /** @@ -1152,11 +1209,9 @@ public ItemStack shrink(@NotNull ItemStack stack, int count, boolean useRemains, */ public ItemStack shrink(ItemStack stack, int count, boolean useRemains, @Nullable final Inventory inventory, @Nullable final Player player, @Nullable final Location location) { return shrink(stack, count, useRemains, (customItem, resultStack) -> { - ItemStack replacement = isConsumed() && useRemains && craftRemain != null ? new ItemStack(craftRemain) : null; - if (this.hasReplacement()) { - assert getReplacement() != null; - replacement = new CustomItem(getReplacement()).create(); - } + ItemStack replacement = replacement() + .map(StackReference::originalStack) + .orElseGet(() -> isConsumed() && useRemains && craftRemain != null ? new ItemStack(craftRemain) : null); if (!ItemUtils.isAirOrNull(replacement)) { int replacementAmount = replacement.getAmount() * count; if (ItemUtils.isAirOrNull(resultStack)) { @@ -1198,12 +1253,14 @@ public ItemStack shrink(ItemStack stack, int count, boolean useRemains, @Nullabl * @return The manipulated (damaged) stack, default remain, or custom remains. */ public ItemStack shrinkUnstackableItem(ItemStack stack, boolean useRemains) { - ItemStack result = new ItemStack(Material.AIR); - if (this.hasReplacement()) { - result = this.getReplacement() == null ? new ItemStack(Material.AIR) : new CustomItem(this.getReplacement()).create(); - } else if (this.isConsumed() && craftRemain != null && useRemains) { - result = new ItemStack(craftRemain); - } + ItemStack result = replacement() + .map(StackReference::originalStack) + .orElseGet(() -> { + if (this.isConsumed() && craftRemain != null && useRemains) { + return new ItemStack(craftRemain); + } + return new ItemStack(Material.AIR); + }); if (this.getDurabilityCost() != 0) { // handle custom durability var itemBuilder = new ItemBuilder(stack); @@ -1229,20 +1286,23 @@ public ItemStack shrinkUnstackableItem(ItemStack stack, boolean useRemains) { return result; } - private Material getCraftRemain() { - var item = getItemStack(); - if (!ItemUtils.isAirOrNull(item) && item.getType().isItem()) { - Material replaceType = item.getType().getCraftingRemainingItem(); - if (replaceType != null) return replaceType; - return switch (item.getType().name()) { + public static Optional craftRemain(ItemStack stack) { + if (!ItemUtils.isAirOrNull(stack) && stack.getType().isItem()) { + Material replaceType = stack.getType().getCraftingRemainingItem(); + if (replaceType != null) return Optional.of(replaceType); + return switch (stack.getType().name()) { case "LAVA_BUCKET", "MILK_BUCKET", "WATER_BUCKET", "COD_BUCKET", "SALMON_BUCKET", "PUFFERFISH_BUCKET", "TROPICAL_FISH_BUCKET" -> - Material.BUCKET; - case "POTION" -> Material.GLASS_BOTTLE; - case "BEETROOT_SOUP", "MUSHROOM_STEW", "RABBIT_STEW" -> Material.BOWL; - default -> null; + Optional.of(Material.BUCKET); + case "POTION" -> Optional.of(Material.GLASS_BOTTLE); + case "BEETROOT_SOUP", "MUSHROOM_STEW", "RABBIT_STEW" -> Optional.of(Material.BOWL); + default -> Optional.empty(); }; } - return null; + return Optional.empty(); + } + + private Material getCraftRemain() { + return CustomItem.craftRemain(getItemStack()).orElse(null); } /** @@ -1368,7 +1428,7 @@ private static NamespacedKey getKeyForData(Class type) * Used to deserialize the old CustomData content.
* This is replaced by a better modular system {@link CustomItemData} */ - @Deprecated + @Deprecated(forRemoval = true) @JsonAlias("custom_data") @JsonSetter("customDataMap") private void setCustomDataMap(JsonNode dataNode) { @@ -1394,18 +1454,18 @@ private void setCustomDataMap(JsonNode dataNode) { } } - @Deprecated + @Deprecated(forRemoval = true) @JsonGetter("customDataMap") public Map getCustomDataMap() { return customDataMap; } - @Deprecated + @Deprecated(forRemoval = true) public CustomData getCustomData(NamespacedKey namespacedKey) { return customDataMap.get(namespacedKey); } - @Deprecated + @Deprecated(forRemoval = true) public void addCustomData(NamespacedKey namespacedKey, CustomData customData) { this.customDataMap.put(namespacedKey, customData); } @@ -1494,6 +1554,21 @@ public boolean isBlock() { .evaluateIfAvailable("ItemsAdder", ItemsAdderIntegration.class, ia -> ia.getStackInstance(iaRef.getItemID()).map(CustomStack::isBlock).orElse(false))); } + /** + * Converts Legacy CustomItems, that can behave as a reference or saved item. + * If the CustomItem is an actual saved item, then it returns a StackReference using the WolfyUtilsStackIdentifier. + * Otherwise, it simply returns the reference of this CustomItem. + * + * @return The reference, or a reference to this item when it is a saved item. + */ + @Deprecated + public StackReference convertToReference() { + if (hasNamespacedKey()) { + return new StackReference(WolfyUtilCore.getInstance(), new WolfyUtilsStackIdentifier(getNamespacedKey()), getWeight(), getAmount(), getItemStack()); + } + return reference; + } + @Override public String toString() { return "CustomItem{" + @@ -1510,7 +1585,7 @@ public String toString() { ", blockVanillaEquip=" + blockVanillaEquip + ", blockVanillaRecipes=" + blockVanillaRecipes + ", equipmentSlots=" + equipmentSlots + - ", apiReference=" + apiReference + + ", apiReference=" + reference + ", particleContent=" + particleContent + ", metaSettings=" + nbtChecks + "} " + super.toString(); diff --git a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/APIReference.java b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/APIReference.java index d4079dbc..e0d2957f 100644 --- a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/APIReference.java +++ b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/APIReference.java @@ -21,6 +21,11 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; +import com.wolfyscript.utilities.bukkit.world.items.reference.BukkitStackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackReference; +import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.compatibility.plugins.itemsadder.ItemsAdderRef; import me.wolfyscript.utilities.compatibility.plugins.mmoitems.MMOItemsRef; import me.wolfyscript.utilities.compatibility.plugins.mythicmobs.MythicMobsRef; @@ -52,6 +57,7 @@ *

* You can register additional references inside your plugin (onEnable) using {@link me.wolfyscript.utilities.api.inventory.custom_items.CustomItem#registerAPIReferenceParser(Parser)}. */ +@Deprecated public abstract class APIReference { protected int amount; @@ -142,6 +148,32 @@ public void setWeight(double weight) { */ public abstract void serialize(JsonGenerator gen, SerializerProvider provider) throws IOException; + /** + * Converts this old APIReference to the new {@link StackReference} system. + * By default, the StackReference will be using the {@link BukkitStackIdentifier}, + * but APIReference implementations may choose to return their related StackReference implementation. + *

+ * Note that the {@link StackReference} contains the weight and amount, while the other data is + * stored in the {@link StackIdentifier} and is one level lower. + *

+ * + * @return The implementation related StackReference, or {@link BukkitStackIdentifier} by default + */ + public final StackReference convertToStackReference() { + StackIdentifier identifier = convert(); + return new StackReference(WolfyUtilCore.getInstance(), identifier, weight, amount, identifier.stack(ItemCreateContext.empty(amount))); + } + + /** + * Custom implementation may choose to implement this to return their new implementation + * of {@link StackIdentifier}, for better integration, other plugins may use to detect the origin of the stack. + * + * @return The implementation related StackIdentifier, or {@link BukkitStackIdentifier} by default + */ + protected StackIdentifier convert() { + return new BukkitStackIdentifier(getLinkedItem()); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/VanillaRef.java b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/VanillaRef.java index 6f88c370..47521366 100644 --- a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/VanillaRef.java +++ b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/VanillaRef.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; +import com.wolfyscript.utilities.bukkit.world.items.reference.BukkitStackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import me.wolfyscript.utilities.api.inventory.custom_items.CustomItem; import me.wolfyscript.utilities.util.json.jackson.JacksonUtil; import org.bukkit.inventory.ItemStack; @@ -51,6 +53,7 @@ public ItemStack getLinkedItem() { return itemStack; } + @Deprecated @Override public ItemStack getIdItem() { return itemStack; @@ -67,6 +70,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE JacksonUtil.getObjectMapper().writeValue(gen, itemStack); } + @Override + protected StackIdentifier convert() { + return new BukkitStackIdentifier(itemStack); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/WolfyUtilitiesRef.java b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/WolfyUtilitiesRef.java index e0a1d358..abdc55eb 100644 --- a/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/WolfyUtilitiesRef.java +++ b/core/src/main/java/me/wolfyscript/utilities/api/inventory/custom_items/references/WolfyUtilitiesRef.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.WolfyUtilsStackIdentifier; import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.api.WolfyUtilities; import me.wolfyscript.utilities.util.NamespacedKey; @@ -91,6 +93,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE } } + @Override + protected StackIdentifier convert() { + return new WolfyUtilsStackIdentifier(namespacedKey); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/core/src/main/java/me/wolfyscript/utilities/compatibility/PluginIntegration.java b/core/src/main/java/me/wolfyscript/utilities/compatibility/PluginIntegration.java index 43a43760..5576947e 100644 --- a/core/src/main/java/me/wolfyscript/utilities/compatibility/PluginIntegration.java +++ b/core/src/main/java/me/wolfyscript/utilities/compatibility/PluginIntegration.java @@ -44,6 +44,7 @@ public interface PluginIntegration { * @param reference The {@link APIReference} to check. * @return True if the reference is part of this integration; else false. */ + @Deprecated(forRemoval = true, since = "4.16.15") default boolean isAPIReferenceIncluded(APIReference reference) { return false; } /** diff --git a/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java b/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java index 9f085626..fbdcdd9d 100644 --- a/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java +++ b/core/src/main/java/me/wolfyscript/utilities/registry/Registries.java @@ -23,6 +23,8 @@ import com.wolfyscript.utilities.bukkit.nbt.QueryNode; import com.wolfyscript.utilities.bukkit.persistent.player.CustomPlayerData; import com.wolfyscript.utilities.bukkit.persistent.world.CustomBlockData; +import com.wolfyscript.utilities.bukkit.registry.RegistryStackIdentifierParsers; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.api.WolfyUtilities; import me.wolfyscript.utilities.api.inventory.custom_items.CustomData; @@ -80,6 +82,7 @@ public class Registries { private final RegistryParticleAnimation particleAnimations; private final Registry> customItemActionValues; private final Registry> customItemEventValues; + private final RegistryStackIdentifierParsers stackIdentifierParsers; //Tags private final Tags itemTags; //Class Registries @@ -108,6 +111,7 @@ public Registries(WolfyUtilCore core) { particleAnimations = new RegistryParticleAnimation(this); customItemActionValues = new RegistrySimple<>(ITEM_ACTION_VALUES, this, (Class>)(Object) Action.class); customItemEventValues = new RegistrySimple<>(ITEM_EVENT_VALUES, this, (Class>)(Object) Event.class); + stackIdentifierParsers = new RegistryStackIdentifierParsers(this); itemTags = new Tags<>(this); @@ -279,4 +283,8 @@ public TypeRegistry getCustomBlockData() { public TypeRegistry> getNbtQueryNodes() { return nbtQueryNodes; } + + public RegistryStackIdentifierParsers getStackIdentifierParsers() { + return stackIdentifierParsers; + } } diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/EcoIntegrationImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/EcoIntegrationImpl.java index 21b43817..bdbb4029 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/EcoIntegrationImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/EcoIntegrationImpl.java @@ -25,6 +25,7 @@ import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; import me.wolfyscript.utilities.compatibility.plugins.eco.EcoRefImpl; +import me.wolfyscript.utilities.compatibility.plugins.eco.EcoStackIdentifier; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; @@ -45,6 +46,7 @@ protected EcoIntegrationImpl(WolfyUtilCore core) { @Override public void init(Plugin plugin) { core.registerAPIReference(new EcoRefImpl.Parser()); + core.getRegistries().getStackIdentifierParsers().register(new EcoStackIdentifier.Parser()); } @Override diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ExecutableItemsImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ExecutableItemsImpl.java index 2785d5b4..df7e1d65 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ExecutableItemsImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ExecutableItemsImpl.java @@ -6,6 +6,7 @@ import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; import me.wolfyscript.utilities.compatibility.plugins.executableitems.ExecutableItemsRef; +import me.wolfyscript.utilities.compatibility.plugins.executableitems.ExecutableItemsStackIdentifier; import org.bukkit.plugin.Plugin; import java.util.List; @@ -30,6 +31,7 @@ public boolean isAPIReferenceIncluded(APIReference reference) { @Override public void init(Plugin plugin) { core.registerAPIReference(new ExecutableItemsRef.Parser(ExecutableItemsAPI.getExecutableItemsManager())); + core.getRegistries().getStackIdentifierParsers().register(new ExecutableItemsStackIdentifier.Parser(ExecutableItemsAPI.getExecutableItemsManager())); } @Override diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/FancyBagsImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/FancyBagsImpl.java index c7699667..6f1df1bd 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/FancyBagsImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/FancyBagsImpl.java @@ -4,6 +4,7 @@ import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; import me.wolfyscript.utilities.compatibility.plugins.fancybags.FancyBagsItemsRef; +import me.wolfyscript.utilities.compatibility.plugins.fancybags.FancyBagsStackIdentifier; import org.bukkit.plugin.Plugin; @WUPluginIntegration(pluginName = FancyBagsImpl.KEY) @@ -23,6 +24,7 @@ protected FancyBagsImpl(WolfyUtilCore core) { @Override public void init(Plugin plugin) { core.registerAPIReference(new FancyBagsItemsRef.Parser()); + core.getRegistries().getStackIdentifierParsers().register(new FancyBagsStackIdentifier.Parser()); } @Override diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ItemsAdderImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ItemsAdderImpl.java index 6985631f..ed4a505a 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ItemsAdderImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/ItemsAdderImpl.java @@ -24,12 +24,7 @@ import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; -import me.wolfyscript.utilities.compatibility.plugins.itemsadder.CustomBlock; -import me.wolfyscript.utilities.compatibility.plugins.itemsadder.CustomItemListener; -import me.wolfyscript.utilities.compatibility.plugins.itemsadder.CustomBlockWrapper; -import me.wolfyscript.utilities.compatibility.plugins.itemsadder.CustomStack; -import me.wolfyscript.utilities.compatibility.plugins.itemsadder.CustomStackWrapper; -import me.wolfyscript.utilities.compatibility.plugins.itemsadder.ItemsAdderRefImpl; +import me.wolfyscript.utilities.compatibility.plugins.itemsadder.*; import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; @@ -48,6 +43,7 @@ protected ItemsAdderImpl(WolfyUtilCore core) { @Override public void init(Plugin plugin) { core.registerAPIReference(new ItemsAdderRefImpl.Parser()); + core.getRegistries().getStackIdentifierParsers().register(new ItemsAdderStackIdentifier.Parser()); Bukkit.getPluginManager().registerEvents(this, core); Bukkit.getPluginManager().registerEvents(new CustomItemListener(this), core); } diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MMOItemsImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MMOItemsImpl.java index 63587d21..0cdebdfa 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MMOItemsImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MMOItemsImpl.java @@ -23,6 +23,7 @@ import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; import me.wolfyscript.utilities.compatibility.plugins.mmoitems.MMOItemsRefImpl; +import me.wolfyscript.utilities.compatibility.plugins.mmoitems.MMOItemsStackIdentifier; import org.bukkit.plugin.Plugin; @WUPluginIntegration(pluginName = MMOItemsImpl.PLUGIN_NAME) @@ -37,6 +38,7 @@ protected MMOItemsImpl(WolfyUtilCore core) { @Override public void init(Plugin plugin) { core.registerAPIReference(new MMOItemsRefImpl.Parser()); + core.getRegistries().getStackIdentifierParsers().register(new MMOItemsStackIdentifier.Parser()); } @Override diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MagicImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MagicImpl.java index fcb89e2d..3e09f5e0 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MagicImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MagicImpl.java @@ -19,11 +19,13 @@ package me.wolfyscript.utilities.compatibility.plugins; import com.elmakers.mine.bukkit.api.event.LoadEvent; +import com.elmakers.mine.bukkit.api.magic.MagicAPI; import me.wolfyscript.utilities.annotations.WUPluginIntegration; import me.wolfyscript.utilities.api.WolfyUtilCore; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; import me.wolfyscript.utilities.compatibility.plugins.magic.MagicRefImpl; +import me.wolfyscript.utilities.compatibility.plugins.magic.MagicStackIdentifier; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -41,6 +43,7 @@ protected MagicImpl(WolfyUtilCore core) { @Override public void init(Plugin plugin) { core.registerAPIReference(new MagicRefImpl.Parser()); + core.getRegistries().getStackIdentifierParsers().register(new MagicStackIdentifier.Parser(Bukkit.getPluginManager().getPlugin("Magic") instanceof MagicAPI magicAPI ? magicAPI : null)); Bukkit.getPluginManager().registerEvents(this, core); } diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MythicMobsImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MythicMobsImpl.java index 4eaef48d..5020cde9 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MythicMobsImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/MythicMobsImpl.java @@ -28,6 +28,7 @@ import me.wolfyscript.utilities.compatibility.PluginIntegrationAbstract; import me.wolfyscript.utilities.compatibility.plugins.mythicmobs.MythicMobs5RefImpl; import me.wolfyscript.utilities.compatibility.plugins.mythicmobs.MythicMobsRefImpl; +import me.wolfyscript.utilities.compatibility.plugins.mythicmobs.MythicMobsStackIdentifier; import org.bukkit.Location; import org.bukkit.plugin.Plugin; @@ -45,6 +46,7 @@ public void init(Plugin plugin) { } else { core.registerAPIReference(new MythicMobsRefImpl.Parser()); } + core.getRegistries().getStackIdentifierParsers().register(new MythicMobsStackIdentifier.Parser()); } @Override diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoRefImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoRefImpl.java index 56967440..b69f803d 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoRefImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoRefImpl.java @@ -24,6 +24,8 @@ import com.willfp.eco.core.items.Items; import java.io.IOException; import java.util.Objects; + +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; @@ -59,6 +61,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE gen.writeStringField("eco", itemKey.toString()); } + @Override + protected EcoStackIdentifier convert() { + return new EcoStackIdentifier(itemKey); + } + @Override public APIReference clone() { return new EcoRefImpl(this); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoStackIdentifier.java new file mode 100644 index 00000000..7a3d83fc --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/eco/EcoStackIdentifier.java @@ -0,0 +1,83 @@ +package me.wolfyscript.utilities.compatibility.plugins.eco; + +import com.willfp.eco.core.items.Items; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import me.wolfyscript.utilities.util.NamespacedKey; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Objects; +import java.util.Optional; + +public class EcoStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("eco"); + + private final org.bukkit.NamespacedKey itemKey; + + public EcoStackIdentifier(org.bukkit.NamespacedKey itemKey) { + this.itemKey = itemKey; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + return Items.lookup(itemKey.toString()).getItem(); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + var item = Items.getCustomItem(other); + return item != null && Objects.equals(itemKey, item.getKey()); + } + + @Override + public EcoRefImpl convert(double weight, int amount) { + EcoRefImpl ref = new EcoRefImpl(itemKey); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + if (Items.isCustomItem(itemStack)) { + var customStack = Items.getCustomItem(itemStack); + if (customStack != null) { + return Optional.of(new EcoStackIdentifier(customStack.getKey())); + } + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("Eco").color(NamedTextColor.GREEN).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.EMERALD) + ); + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksRef.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksRef.java index b88b3993..dbe6a8bc 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksRef.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksRef.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.util.Locale; import java.util.Optional; + +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.plugins.ExecutableBlocksIntegration; import org.bukkit.Material; @@ -46,6 +48,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE gen.writeStringField(ExecutableBlocksIntegration.PLUGIN_NAME.toLowerCase(Locale.ROOT), id); } + @Override + protected StackIdentifier convert() { + return new ExecutableBlocksStackIdentifier(integration, manager, id); + } + @Override public APIReference clone() { return new ExecutableBlocksRef(this); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksStackIdentifier.java new file mode 100644 index 00000000..3623f107 --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableblocks/ExecutableBlocksStackIdentifier.java @@ -0,0 +1,84 @@ +package me.wolfyscript.utilities.compatibility.plugins.executableblocks; + +import com.ssomar.executableblocks.executableblocks.ExecutableBlocksManager; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import me.wolfyscript.utilities.compatibility.plugins.ExecutableBlocksIntegration; +import me.wolfyscript.utilities.util.NamespacedKey; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public class ExecutableBlocksStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("executableblocks"); + + private final ExecutableBlocksIntegration integration; + private final ExecutableBlocksManager manager; + private final String id; + + public ExecutableBlocksStackIdentifier(ExecutableBlocksIntegration integration, ExecutableBlocksManager manager, String id) { + this.id = id; + this.manager = manager; + this.integration = integration; + } + + private ExecutableBlocksStackIdentifier(ExecutableBlocksStackIdentifier other) { + this.id = other.id; + this.manager = other.manager; + this.integration = other.integration; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + return manager.getExecutableBlock(id).map(eb -> eb.buildItem(context.amount(), context.player())).orElseGet(() -> new ItemStack(Material.AIR)); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + if (!ignoreAmount && other.getAmount() < stack(ItemCreateContext.empty(count)).getAmount() * count) return false; + return integration.getExecutableBlock(other).map(eB -> eB.equals(id)).orElse(false); + } + + @Override + public ExecutableBlocksRef convert(double weight, int amount) { + ExecutableBlocksRef ref = new ExecutableBlocksRef(integration, manager, id); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + private final ExecutableBlocksIntegration integration; + private final ExecutableBlocksManager manager; + + public Parser(ExecutableBlocksIntegration integration, ExecutableBlocksManager manager) { + this.integration = integration; + this.manager = manager; + } + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + return integration.getExecutableBlock(itemStack).map(ebID -> new ExecutableBlocksStackIdentifier(integration, manager, ebID)); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsRef.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsRef.java index 9300c312..39311ede 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsRef.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsRef.java @@ -4,8 +4,10 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; import com.ssomar.score.api.executableitems.config.ExecutableItemsManagerInterface; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.compatibility.plugins.ExecutableItemsIntegration; +import me.wolfyscript.utilities.compatibility.plugins.executableblocks.ExecutableBlocksStackIdentifier; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; @@ -43,6 +45,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE gen.writeStringField("executableitems", id); } + @Override + protected StackIdentifier convert() { + return new ExecutableItemsStackIdentifier(manager, id); + } + @Override public APIReference clone() { return new ExecutableItemsRef(this); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsStackIdentifier.java new file mode 100644 index 00000000..ce45aa63 --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/executableitems/ExecutableItemsStackIdentifier.java @@ -0,0 +1,78 @@ +package me.wolfyscript.utilities.compatibility.plugins.executableitems; + +import com.ssomar.score.api.executableitems.config.ExecutableItemsManagerInterface; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import me.wolfyscript.utilities.util.NamespacedKey; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public class ExecutableItemsStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("executableitems"); + + private final ExecutableItemsManagerInterface manager; + private final String id; + + public ExecutableItemsStackIdentifier(ExecutableItemsManagerInterface manager, String id) { + this.id = id; + this.manager = manager; + } + + private ExecutableItemsStackIdentifier(ExecutableItemsStackIdentifier other) { + this.id = other.id; + this.manager = other.manager; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + return manager.getExecutableItem(id).map(item -> item.buildItem(context.amount(), context.player())).orElseGet(()-> new ItemStack(Material.AIR)); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + if (!ignoreAmount && other.getAmount() < stack(ItemCreateContext.empty(count)).getAmount() * count) return false; + return manager.getExecutableItem(other).map(exeItem -> exeItem.getId().equals(id)).orElse(false); + } + + @Override + public ExecutableItemsRef convert(double weight, int amount) { + ExecutableItemsRef ref = new ExecutableItemsRef(manager, id); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + private final ExecutableItemsManagerInterface manager; + + public Parser(ExecutableItemsManagerInterface manager) { + this.manager = manager; + } + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + return manager.getExecutableItem(itemStack).map(exeItem -> new ExecutableItemsStackIdentifier(manager, exeItem.getId())); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsItemsRef.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsItemsRef.java index 4c1cb763..e6175477 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsItemsRef.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsItemsRef.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import de.tr7zw.changeme.nbtapi.NBTItem; import de.tr7zw.changeme.nbtapi.NBTType; import java.io.IOException; @@ -51,6 +52,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE gen.writeNumberField("fancybags", id); } + @Override + protected StackIdentifier convert() { + return new FancyBagsStackIdentifier(id); + } + @Override public APIReference clone() { return new FancyBagsItemsRef(this); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsStackIdentifier.java new file mode 100644 index 00000000..f993a27d --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/fancybags/FancyBagsStackIdentifier.java @@ -0,0 +1,85 @@ +package me.wolfyscript.utilities.compatibility.plugins.fancybags; + +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import de.tr7zw.changeme.nbtapi.NBTItem; +import de.tr7zw.changeme.nbtapi.NBTType; +import me.chickenstyle.backpack.Backpack; +import me.chickenstyle.backpack.Utils; +import me.chickenstyle.backpack.configs.CustomBackpacks; +import me.wolfyscript.utilities.util.NamespacedKey; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Optional; + +public class FancyBagsStackIdentifier implements StackIdentifier { + + private static final String ID_TAG = "BackpackID"; + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("fancybags"); + + private final int id; + + public FancyBagsStackIdentifier(int id) { + this.id = id; + } + + public int id() { + return id; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + Backpack bag = CustomBackpacks.getBackpack(id); + if (bag != null) { + return Utils.createBackpackItemStack(bag.getName(), bag.getTexture(), bag.getSlotsAmount(), bag.getId()); + } + return new ItemStack(Material.AIR); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + NBTItem nbtItem = new NBTItem(other); + if (nbtItem.hasTag(ID_TAG, NBTType.NBTTagInt)) { + return nbtItem.getInteger(ID_TAG) == id; + } + return false; + } + + @Override + public FancyBagsItemsRef convert(double weight, int amount) { + FancyBagsItemsRef ref = new FancyBagsItemsRef(id); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + NBTItem nbtItem = new NBTItem(itemStack); + if (nbtItem.hasTag(ID_TAG, NBTType.NBTTagInt)) { + return Optional.of(new FancyBagsStackIdentifier(nbtItem.getInteger(ID_TAG))); + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderRefImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderRefImpl.java index a7ab23d9..ebb89774 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderRefImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderRefImpl.java @@ -23,6 +23,8 @@ import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.util.Objects; + +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.util.inventory.ItemUtils; import org.bukkit.inventory.ItemStack; @@ -48,6 +50,10 @@ public ItemsAdderRefImpl(ItemsAdderRefImpl itemsAdderRefImpl) { this.itemID = itemsAdderRefImpl.itemID; } + public String itemId() { + return itemID; + } + /** * @return The latest ItemStack available in ItemsAdder under the specified itemID or AIR. */ @@ -99,6 +105,11 @@ public ItemsAdderRefImpl clone() { return new ItemsAdderRefImpl(this); } + @Override + protected StackIdentifier convert() { + return new ItemsAdderStackIdentifier(itemID); + } + public static class Parser extends PluginParser { public Parser() { diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderStackIdentifier.java new file mode 100644 index 00000000..7e9c6ca3 --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/itemsadder/ItemsAdderStackIdentifier.java @@ -0,0 +1,91 @@ +package me.wolfyscript.utilities.compatibility.plugins.itemsadder; + +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import dev.lone.itemsadder.api.CustomStack; +import me.wolfyscript.utilities.util.NamespacedKey; +import me.wolfyscript.utilities.util.inventory.ItemUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Objects; +import java.util.Optional; + +public class ItemsAdderStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("itemsadder"); + + private final String itemId; + + public ItemsAdderStackIdentifier(String itemId) { + this.itemId = itemId; + } + + public String itemId() { + return itemId; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + var customStack = CustomStack.getInstance(itemId); + if (customStack != null) { + return customStack.getItemStack(); + } + return ItemUtils.AIR; + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + if (!ignoreAmount && other.getAmount() < stack(ItemCreateContext.empty(count)).getAmount() * count) return false; + var customStack = CustomStack.byItemStack(other); + return customStack != null && Objects.equals(itemId, customStack.getNamespacedID()); + } + + @Override + public ItemsAdderRefImpl convert(double weight, int amount) { + ItemsAdderRefImpl ref = new ItemsAdderRefImpl(itemId); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + var customStack = CustomStack.byItemStack(itemStack); + if (customStack != null) { + return Optional.of(new ItemsAdderStackIdentifier(customStack.getNamespacedID())); + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("ItemsAdder").color(NamedTextColor.YELLOW).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.GRASS_BLOCK) + ); + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicRefImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicRefImpl.java index ad13b513..28722c04 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicRefImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicRefImpl.java @@ -24,6 +24,8 @@ import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.util.Objects; + +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import me.wolfyscript.utilities.api.inventory.custom_items.references.APIReference; import me.wolfyscript.utilities.util.inventory.ItemUtils; import org.bukkit.inventory.ItemStack; @@ -70,6 +72,11 @@ public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOE gen.writeStringField("magic", itemKey); } + @Override + protected StackIdentifier convert() { + return new MagicStackIdentifier(Parser.magicAPI, itemKey); + } + @Override public MagicRefImpl clone() { return new MagicRefImpl(this); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicStackIdentifier.java new file mode 100644 index 00000000..f719e387 --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/magic/MagicStackIdentifier.java @@ -0,0 +1,83 @@ +package me.wolfyscript.utilities.compatibility.plugins.magic; + +import com.elmakers.mine.bukkit.api.magic.MagicAPI; +import com.google.common.base.Preconditions; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import me.wolfyscript.utilities.util.NamespacedKey; +import me.wolfyscript.utilities.util.inventory.ItemUtils; +import org.bukkit.Bukkit; +import org.bukkit.inventory.ItemStack; + +import java.util.Objects; +import java.util.Optional; + +public class MagicStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("magic"); + + private final String itemKey; + private final MagicAPI magicAPI; + + public MagicStackIdentifier(String itemKey) { + this(Bukkit.getPluginManager().getPlugin("Magic") instanceof MagicAPI api ? api : null, itemKey); + } + + public MagicStackIdentifier(MagicAPI magicAPI, String itemKey) { + Preconditions.checkNotNull(magicAPI, "No MagicAPI specified when creating a MagicStackIdentifier"); + this.magicAPI = magicAPI; + this.itemKey = itemKey; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + return Objects.requireNonNullElse(magicAPI.getController().createItem(itemKey), ItemUtils.AIR); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + return Objects.equals(magicAPI.getController().getItemKey(other), itemKey); + } + + @Override + public MagicRefImpl convert(double weight, int amount) { + MagicRefImpl ref = new MagicRefImpl(itemKey); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + private final MagicAPI magicAPI; + + public Parser(MagicAPI magicAPI) { + this.magicAPI = magicAPI; + } + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + if(magicAPI.isBrush(itemStack) || magicAPI.isSpell(itemStack) || magicAPI.isUpgrade(itemStack) || magicAPI.isWand(itemStack)) { + return Optional.of(new MagicStackIdentifier(magicAPI.getItemKey(itemStack))); + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsRefImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsRefImpl.java index b6bc8b00..6ac80d52 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsRefImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsRefImpl.java @@ -71,6 +71,11 @@ public boolean isValidItem(ItemStack itemStack) { return false; } + @Override + protected MMOItemsStackIdentifier convert() { + return new MMOItemsStackIdentifier(itemType, itemName); + } + @Override public void serialize(JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeObjectFieldStart("mmoitems"); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsStackIdentifier.java new file mode 100644 index 00000000..4e2fb427 --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mmoitems/MMOItemsStackIdentifier.java @@ -0,0 +1,92 @@ +package me.wolfyscript.utilities.compatibility.plugins.mmoitems; + +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import io.lumine.mythic.lib.api.item.NBTItem; +import me.wolfyscript.utilities.util.NamespacedKey; +import net.Indyuce.mmoitems.MMOItems; +import net.Indyuce.mmoitems.api.Type; +import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Objects; +import java.util.Optional; + +public class MMOItemsStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("mmoitems"); + + private final Type itemType; + private final String itemName; + + public MMOItemsStackIdentifier(Type itemType, String itemName) { + this.itemType = itemType; + this.itemName = itemName; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + MMOItem item = MMOItems.plugin.getMMOItem(itemType, itemName); + return item != null ? item.newBuilder().buildSilently() : null; + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + var nbtItem = NBTItem.get(other); + if (nbtItem.hasType()) { + return Objects.equals(this.itemType, MMOItems.plugin.getTypes().get(nbtItem.getType())) && Objects.equals(this.itemName, nbtItem.getString("MMOITEMS_ITEM_ID")); + } + return false; + } + + @Override + public MMOItemsRefImpl convert(double weight, int amount) { + MMOItemsRefImpl ref = new MMOItemsRefImpl(itemType, itemName); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + NBTItem nbtItem = NBTItem.get(itemStack); + if (nbtItem.hasType()) { + Type type = MMOItems.plugin.getTypes().get(nbtItem.getType()); + String itemId = nbtItem.getString("MMOITEMS_ITEM_ID"); + return Optional.of(new MMOItemsStackIdentifier(type, itemId)); + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("MMOItems").color(NamedTextColor.DARK_GRAY).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.IRON_SWORD) + ); + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/AbstractMythicMobsRef.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/AbstractMythicMobsRef.java index 3317d824..afc83971 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/AbstractMythicMobsRef.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/AbstractMythicMobsRef.java @@ -74,6 +74,11 @@ public boolean equals(Object o) { return Objects.equals(itemName, that.itemName); } + @Override + protected MythicMobsStackIdentifier convert() { + return new MythicMobsStackIdentifier(itemName); + } + @Override public int hashCode() { return Objects.hash(super.hashCode(), itemName); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/MythicMobsStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/MythicMobsStackIdentifier.java new file mode 100644 index 00000000..d02496e8 --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/mythicmobs/MythicMobsStackIdentifier.java @@ -0,0 +1,88 @@ +package me.wolfyscript.utilities.compatibility.plugins.mythicmobs; + +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import de.tr7zw.changeme.nbtapi.NBTItem; +import io.lumine.mythic.bukkit.MythicBukkit; +import me.wolfyscript.utilities.util.NamespacedKey; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Objects; +import java.util.Optional; + +public class MythicMobsStackIdentifier implements StackIdentifier { + + protected static final String ITEM_KEY = "MYTHIC_TYPE"; + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("mythicmobs"); + + private final MythicBukkit mythicBukkit; + private final String itemName; + + public MythicMobsStackIdentifier(String itemName) { + this.itemName = itemName; + this.mythicBukkit = MythicBukkit.inst(); + } + + @Override + public ItemStack stack(ItemCreateContext context) { + return mythicBukkit.getItemManager().getItemStack(itemName); + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + var value = NBTItem.convertItemtoNBT(other).getString(ITEM_KEY); + if (value != null) { + return Objects.equals(this.itemName, value); + } + return false; + } + + @Override + public MythicMobs5RefImpl convert(double weight, int amount) { + MythicMobs5RefImpl ref = new MythicMobs5RefImpl(itemName); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + var value = NBTItem.convertItemtoNBT(itemStack).getString(ITEM_KEY); + if (value != null) { + return Optional.of(new MythicMobsStackIdentifier(value)); + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("MythicMobs").color(NamedTextColor.DARK_PURPLE).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.WITHER_SKELETON_SKULL) + ); + } + } + +} diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenImpl.java index 4f5dd513..1b7cf6dd 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenImpl.java @@ -42,6 +42,7 @@ public void init(Plugin plugin) { } else { core.registerAPIReference(new OraxenRefImpl.Parser()); } + core.getRegistries().getStackIdentifierParsers().register(new OraxenStackIdentifier.Parser()); } public boolean isLatestAPI() { diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenRefImpl.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenRefImpl.java index 177f43bc..3c948d49 100644 --- a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenRefImpl.java +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenRefImpl.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.SerializerProvider; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; import io.th0rgal.oraxen.api.OraxenItems; import java.io.IOException; import java.util.Objects; @@ -91,6 +92,11 @@ public int hashCode() { return Objects.hash(super.hashCode(), itemID); } + @Override + protected OraxenStackIdentifier convert() { + return new OraxenStackIdentifier(itemID); + } + @Override public OraxenRefImpl clone() { return new OraxenRefImpl(this); diff --git a/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenStackIdentifier.java b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenStackIdentifier.java new file mode 100644 index 00000000..0fee389f --- /dev/null +++ b/plugin-compatibility/src/main/java/me/wolfyscript/utilities/compatibility/plugins/oraxen/OraxenStackIdentifier.java @@ -0,0 +1,92 @@ +package me.wolfyscript.utilities.compatibility.plugins.oraxen; + +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemCreateContext; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifier; +import com.wolfyscript.utilities.bukkit.world.items.reference.StackIdentifierParser; +import io.th0rgal.oraxen.api.OraxenItems; +import me.wolfyscript.utilities.util.NamespacedKey; +import me.wolfyscript.utilities.util.inventory.ItemUtils; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import java.util.Objects; +import java.util.Optional; + +public class OraxenStackIdentifier implements StackIdentifier { + + public static final NamespacedKey ID = NamespacedKey.wolfyutilties("oraxen"); + + private final String itemID; + + public OraxenStackIdentifier(String itemID) { + this.itemID = itemID; + } + + public String itemId() { + return itemID; + } + + @Override + public ItemStack stack(ItemCreateContext context) { + if (OraxenItems.exists(itemID)) { + return OraxenItems.getItemById(itemID).build(); + } + return ItemUtils.AIR; + } + + @Override + public boolean matches(ItemStack other, int count, boolean exact, boolean ignoreAmount) { + String itemId = OraxenItems.getIdByItem(other); + if (itemId != null && !itemId.isEmpty()) { + return Objects.equals(this.itemID, itemId); + } + return false; + } + + @Override + public OraxenRefImpl convert(double weight, int amount) { + OraxenRefImpl ref = new OraxenRefImpl(itemID); + ref.setWeight(weight); + ref.setAmount(amount); + return ref; + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + public static class Parser implements StackIdentifierParser { + + @Override + public int priority() { + return 0; + } + + @Override + public Optional from(ItemStack itemStack) { + String itemId = OraxenItems.getIdByItem(itemStack); + if (itemId != null && !itemId.isEmpty()) { + return Optional.of(new OraxenStackIdentifier(itemId)); + } + return Optional.empty(); + } + + @Override + public NamespacedKey getNamespacedKey() { + return ID; + } + + @Override + public DisplayConfiguration displayConfig() { + return new DisplayConfiguration.SimpleDisplayConfig( + Component.text("Oraxen").color(NamedTextColor.DARK_AQUA).decorate(TextDecoration.BOLD), + new DisplayConfiguration.MaterialIconSettings(Material.DIAMOND) + ); + } + } + +}