diff --git a/core/pom.xml b/core/pom.xml index 180fedd8..0db8fa84 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -37,6 +37,12 @@ worldguard-bukkit 7.1.0-SNAPSHOT provided + + + * + * + + diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/WolfyCoreBukkit.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/WolfyCoreBukkit.java index a8fc3e1a..ec639855 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/WolfyCoreBukkit.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/WolfyCoreBukkit.java @@ -1,5 +1,6 @@ package com.wolfyscript.utilities.bukkit; +import com.fasterxml.jackson.databind.InjectableValues; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; import com.wolfyscript.jackson.dataformat.hocon.HoconMapper; @@ -7,9 +8,10 @@ import com.wolfyscript.utilities.bukkit.commands.ChatActionCommand; import com.wolfyscript.utilities.bukkit.commands.InfoCommand; import com.wolfyscript.utilities.bukkit.commands.InputCommand; -import com.wolfyscript.utilities.bukkit.commands.QueryDebugCommand; +import com.wolfyscript.utilities.bukkit.commands.DebugNBTQueryCommand; import com.wolfyscript.utilities.bukkit.commands.SpawnParticleAnimationCommand; import com.wolfyscript.utilities.bukkit.commands.SpawnParticleEffectCommand; +import com.wolfyscript.utilities.bukkit.commands.DebugSimpleStackConfigCommand; import com.wolfyscript.utilities.bukkit.compatibility.CompatibilityManager; import com.wolfyscript.utilities.bukkit.compatibility.CompatibilityManagerBukkit; import com.wolfyscript.utilities.bukkit.config.WUConfig; @@ -47,6 +49,8 @@ import com.wolfyscript.utilities.bukkit.world.items.meta.PotionMeta; import com.wolfyscript.utilities.bukkit.world.items.meta.RepairCostMeta; import com.wolfyscript.utilities.bukkit.world.items.meta.UnbreakableMeta; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.SimpleBukkitItemReference; import com.wolfyscript.utilities.bukkit.world.items.references.APIReference; import com.wolfyscript.utilities.bukkit.world.items.references.VanillaRef; import com.wolfyscript.utilities.bukkit.world.items.references.WolfyUtilitiesRef; @@ -81,7 +85,27 @@ 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.BukkitItemReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.WolfyUtilsItemReference; import com.wolfyscript.utilities.common.WolfyUtils; +import com.wolfyscript.utilities.nbt.NBTTagConfig; +import com.wolfyscript.utilities.nbt.NBTTagConfigBoolean; +import com.wolfyscript.utilities.nbt.NBTTagConfigByte; +import com.wolfyscript.utilities.nbt.NBTTagConfigByteArray; +import com.wolfyscript.utilities.nbt.NBTTagConfigDouble; +import com.wolfyscript.utilities.nbt.NBTTagConfigFloat; +import com.wolfyscript.utilities.nbt.NBTTagConfigInt; +import com.wolfyscript.utilities.nbt.NBTTagConfigIntArray; +import com.wolfyscript.utilities.nbt.NBTTagConfigListCompound; +import com.wolfyscript.utilities.nbt.NBTTagConfigListDouble; +import com.wolfyscript.utilities.nbt.NBTTagConfigListFloat; +import com.wolfyscript.utilities.nbt.NBTTagConfigListInt; +import com.wolfyscript.utilities.nbt.NBTTagConfigListIntArray; +import com.wolfyscript.utilities.nbt.NBTTagConfigListLong; +import com.wolfyscript.utilities.nbt.NBTTagConfigListString; +import com.wolfyscript.utilities.nbt.NBTTagConfigLong; +import com.wolfyscript.utilities.nbt.NBTTagConfigShort; +import com.wolfyscript.utilities.nbt.NBTTagConfigString; import com.wolfyscript.utilities.eval.operator.BoolOperatorConst; import com.wolfyscript.utilities.eval.operator.ComparisonOperatorEqual; import com.wolfyscript.utilities.eval.operator.ComparisonOperatorGreater; @@ -235,6 +259,7 @@ public void onLoad() { // Jackson Serializer getLogger().info("Register JSON de-/serializers"); + KeyedTypeIdResolver.setCore(this); var module = new SimpleModule(); ItemStackSerialization.create(module); ColorSerialization.create(module); @@ -267,9 +292,17 @@ public void onLoad() { JacksonUtil.registerModule(valueReferenceModule); // Create Global WUCore Mapper and apply modules - api.getJacksonMapperUtil().setGlobalMapper(applyWolfyUtilsJsonMapperModules(new HoconMapper())); + HoconMapper mapper = applyWolfyUtilsJsonMapperModules(new HoconMapper()); + api.getJacksonMapperUtil().applyWolfyUtilsInjectableValues(mapper, new InjectableValues.Std()); + api.getJacksonMapperUtil().setGlobalMapper(mapper); // Initialise all the Registers + console.info("Register Item references"); + var itemReferences = getRegistries().getItemReferences(); + itemReferences.register(BukkitItemReference.class); + itemReferences.register(SimpleBukkitItemReference.class); + itemReferences.register(WolfyUtilsItemReference.class); + getLogger().info("Register JSON Operators"); var operators = getRegistries().getOperators(); operators.register(BoolOperatorConst.class); @@ -373,6 +406,29 @@ public void onLoad() { var customPlayerDataReg = getRegistries().getCustomPlayerData(); customPlayerDataReg.register(PlayerParticleEffectData.class); + getLogger().info("Register NBT Tag Configs"); + var nbtTagConfigs = getRegistries().getNbtTagConfigs(); + // Primitives + nbtTagConfigs.register(NBTTagConfigBoolean.class); + nbtTagConfigs.register(NBTTagConfigString.class); + // Primitive Numerals + nbtTagConfigs.register(NBTTagConfigByte.class); + nbtTagConfigs.register(NBTTagConfigByteArray.class); + nbtTagConfigs.register(NBTTagConfigShort.class); + nbtTagConfigs.register(NBTTagConfigInt.class); + nbtTagConfigs.register(NBTTagConfigIntArray.class); + nbtTagConfigs.register(NBTTagConfigLong.class); + nbtTagConfigs.register(NBTTagConfigFloat.class); + nbtTagConfigs.register(NBTTagConfigDouble.class); + // Lists + nbtTagConfigs.register(NBTTagConfigListCompound.class); + nbtTagConfigs.register(NBTTagConfigListInt.class); + nbtTagConfigs.register(NBTTagConfigListIntArray.class); + nbtTagConfigs.register(NBTTagConfigListLong.class); + nbtTagConfigs.register(NBTTagConfigListFloat.class); + nbtTagConfigs.register(NBTTagConfigListDouble.class); + nbtTagConfigs.register(NBTTagConfigListString.class); + getLogger().info("Register NBT Query Nodes"); var nbtQueryNodes = getRegistries().getNbtQueryNodes(); nbtQueryNodes.register(QueryNodeCompound.class); @@ -398,6 +454,7 @@ public void onLoad() { // Register the Registries to resolve type references in JSON KeyedTypeIdResolver.registerTypeRegistry(CustomItemData.class, registries.getCustomItemDataTypeRegistry()); + KeyedTypeIdResolver.registerTypeRegistry(ItemReference.class, itemReferences); KeyedTypeIdResolver.registerTypeRegistry(Meta.class, nbtChecks); KeyedTypeIdResolver.registerTypeRegistry(Animator.class, particleAnimators); KeyedTypeIdResolver.registerTypeRegistry(Shape.class, particleShapes); @@ -409,6 +466,7 @@ public void onLoad() { KeyedTypeIdResolver.registerTypeRegistry((Class>) (Object)QueryNode.class, nbtQueryNodes); KeyedTypeIdResolver.registerTypeRegistry(CustomBlockData.class, customBlockData); KeyedTypeIdResolver.registerTypeRegistry(CustomPlayerData.class, registries.getCustomPlayerData()); + KeyedTypeIdResolver.registerTypeRegistry(NBTTagConfig.class, nbtTagConfigs); } @Override @@ -421,8 +479,7 @@ public void onEnable() { this.config = new WUConfig(api.getConfigAPI(), this); compatibilityManager.init(); - // Register ReferenceParser - console.info("Register API references"); + // Register ItemReferences registerAPIReference(new VanillaRef.Parser()); registerAPIReference(new WolfyUtilitiesRef.Parser()); @@ -488,7 +545,8 @@ private void registerCommands() { Bukkit.getServer().getPluginCommand("wui").setTabCompleter(new InputCommand(this)); Bukkit.getServer().getPluginCommand("wua").setExecutor(new ChatActionCommand()); - Bukkit.getServer().getPluginCommand("query_item").setExecutor(new QueryDebugCommand(this)); + Bukkit.getServer().getPluginCommand("query_item").setExecutor(new DebugNBTQueryCommand(this)); + Bukkit.getServer().getPluginCommand("simple_bukkit_stack").setExecutor(new DebugSimpleStackConfigCommand(this)); } public MessageHandler getMessageHandler() { diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/QueryDebugCommand.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/DebugNBTQueryCommand.java similarity index 96% rename from core/src/main/java/com/wolfyscript/utilities/bukkit/commands/QueryDebugCommand.java rename to core/src/main/java/com/wolfyscript/utilities/bukkit/commands/DebugNBTQueryCommand.java index df80d6d9..a15c2a76 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/QueryDebugCommand.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/DebugNBTQueryCommand.java @@ -34,11 +34,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class QueryDebugCommand implements TabExecutor { +public class DebugNBTQueryCommand implements TabExecutor { private final WolfyCoreBukkit plugin; - public QueryDebugCommand(WolfyCoreBukkit plugin) { + public DebugNBTQueryCommand(WolfyCoreBukkit plugin) { this.plugin = plugin; } diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/DebugSimpleStackConfigCommand.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/DebugSimpleStackConfigCommand.java new file mode 100644 index 00000000..e3237e6c --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/commands/DebugSimpleStackConfigCommand.java @@ -0,0 +1,84 @@ +/* + * WolfyUtilities, APIs and Utilities for Minecraft Spigot plugins + * Copyright (C) 2021 WolfyScript + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.wolfyscript.utilities.bukkit.commands; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.wolfyscript.utilities.bukkit.WolfyCoreBukkit; +import com.wolfyscript.utilities.bukkit.world.inventory.ItemUtils; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.SimpleBukkitItemReference; +import java.io.File; +import java.io.IOException; +import java.util.List; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class DebugSimpleStackConfigCommand implements TabExecutor { + + private final WolfyCoreBukkit plugin; + + public DebugSimpleStackConfigCommand(WolfyCoreBukkit plugin) { + this.plugin = plugin; + } + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (!(sender instanceof Player player)) return true; + if (!player.hasPermission("wolfyutilities.command.simple_bukkit_stack_debug")) return true; + if (!ItemUtils.isAirOrNull(player.getEquipment().getItemInMainHand())) { + ItemReference reference = plugin.getRegistries().getItemReferences().parse(player.getEquipment().getItemInMainHand()); + System.out.println("Found Reference: " + reference); + System.out.println(reference.getItem()); + if (reference instanceof SimpleBukkitItemReference itemReference) { + System.out.println(itemReference.getConfig()); + try { + System.out.println(plugin.getWolfyUtils().getJacksonMapperUtil().getGlobalMapper().writeValueAsString(itemReference)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + return true; + } + File file = new File(plugin.getDataFolder(), "simple_bukkit_stack_debug.conf"); + if (file.exists()) { + try { + ItemReference reference = plugin.getWolfyUtils().getJacksonMapperUtil().getGlobalMapper().readValue(file, ItemReference.class); + System.out.println("Reference: " + reference.toString()); + System.out.println(reference.getItem()); + ItemStack stack = reference.getItem(); + if (stack != null) { + player.getInventory().addItem(stack); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return true; + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + return null; + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManager.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManager.java index 23cbc535..26dd58c2 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManager.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManager.java @@ -5,4 +5,6 @@ public interface CompatibilityManager { void init(); Plugins getPlugins(); + + boolean isPaper(); } diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManagerBukkit.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManagerBukkit.java index ec70c4a2..bc765909 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManagerBukkit.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/compatibility/CompatibilityManagerBukkit.java @@ -19,15 +19,21 @@ package com.wolfyscript.utilities.bukkit.compatibility; import com.wolfyscript.utilities.bukkit.WolfyUtilCore; +import java.util.HashMap; +import java.util.Map; public final class CompatibilityManagerBukkit implements CompatibilityManager { + + private static final Map classes = new HashMap<>(); private final WolfyUtilCore core; private final PluginsBukkit pluginsBukkit; + private final boolean isPaper; public CompatibilityManagerBukkit(WolfyUtilCore core) { this.core = core; this.pluginsBukkit = new PluginsBukkit(core); + this.isPaper = hasClass("com.destroystokyo.paper.utils.PaperPluginLogger"); } public void init() { @@ -37,4 +43,29 @@ public void init() { public Plugins getPlugins() { return pluginsBukkit; } + + @Override + public boolean isPaper() { + return isPaper; + } + + /** + * Check if the specific class exists. + * + * @param path The path to the class to check for. + * @return If the class exists. + */ + public static boolean hasClass(String path) { + if (classes.containsKey(path)) { + return classes.get(path); + } + try { + Class.forName(path); + classes.put(path, true); + return true; + } catch (Exception e) { + classes.put(path, false); + return false; + } + } } diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/BukkitRegistries.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/BukkitRegistries.java index faf9c136..b2a40c55 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/BukkitRegistries.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/BukkitRegistries.java @@ -87,6 +87,7 @@ public class BukkitRegistries extends Registries { private final TypeRegistry customBlockData; private final TypeRegistry customPlayerData; private final TypeRegistry customItemDataTypeRegistry; + private final RegistryItemReferences itemReferences; private final TypeRegistry> nbtQueryNodes; @@ -95,6 +96,7 @@ public BukkitRegistries(WolfyUtilCore core) { customItems = new RegistryCustomItem(this); customItemData = new RegistrySimple<>(new BukkitNamespacedKey(core, "custom_item_data"), this); + itemReferences = new RegistryItemReferences(this); particleEffects = new RegistryParticleEffect(this); particleAnimations = new RegistryParticleAnimation(this); customItemActionValues = new RegistrySimple<>(ITEM_ACTION_VALUES, this, (Class>)(Object) Action.class); @@ -228,4 +230,8 @@ public TypeRegistry getCustomBlockData() { public TypeRegistry> getNbtQueryNodes() { return nbtQueryNodes; } + + public RegistryItemReferences getItemReferences() { + return itemReferences; + } } diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryCustomItem.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryCustomItem.java index 0725b811..3cf0034b 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryCustomItem.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryCustomItem.java @@ -18,6 +18,7 @@ package com.wolfyscript.utilities.bukkit.registry; +import com.wolfyscript.utilities.bukkit.world.items.reference.WolfyUtilsItemReference; import com.wolfyscript.utilities.NamespacedKey; import com.wolfyscript.utilities.bukkit.BukkitNamespacedKey; import com.wolfyscript.utilities.bukkit.world.items.CustomItem; @@ -115,7 +116,7 @@ public void remove(NamespacedKey namespacedKey) { */ @Override public void register(NamespacedKey namespacedKey, CustomItem item) { - if (item == null || (item.getApiReference() instanceof WolfyUtilitiesRef && ((WolfyUtilitiesRef) item.getApiReference()).getNamespacedKey().equals(namespacedKey))) { + if (item == null || (item.getReference() instanceof WolfyUtilsItemReference wuRef && wuRef.getNamespacedKey().equals(namespacedKey))) { return; } this.map.put(namespacedKey, item); diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryItemReferences.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryItemReferences.java new file mode 100644 index 00000000..b86064ae --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/registry/RegistryItemReferences.java @@ -0,0 +1,63 @@ +package com.wolfyscript.utilities.bukkit.registry; + +import com.google.common.base.Preconditions; +import com.wolfyscript.utilities.NamespacedKey; +import com.wolfyscript.utilities.bukkit.BukkitNamespacedKey; +import com.wolfyscript.utilities.bukkit.WolfyCoreBukkit; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemReferenceParserSettings; +import com.wolfyscript.utilities.common.WolfyUtils; +import com.wolfyscript.utilities.common.registry.Registries; +import com.wolfyscript.utilities.common.registry.UniqueTypeRegistrySimple; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.bukkit.inventory.ItemStack; + +public class RegistryItemReferences extends UniqueTypeRegistrySimple { + + private final Map> parserMap = new HashMap<>(); + private List> priorityIndexedParsers; + + public RegistryItemReferences(Registries registries) { + super(new BukkitNamespacedKey((WolfyCoreBukkit) registries.getCore(), "item_references"), registries); + } + + @Override + public void register(NamespacedKey key, Class value) { + if (value != null) { + Objects.requireNonNull(key, "Can't register value " + value.getName() + " because key is null!"); + Preconditions.checkState(!this.map.containsKey(key), "namespaced key '%s' already has an associated value!", key); + map.put(key, value); + ItemReferenceParserSettings.Creator.AbstractParser parser = ItemReferenceParserSettings.Creator.constructParser(key, value); + parserMap.put(key, parser); + reIndexParsers(); + } + } + + public ItemReference parse(ItemStack stack) { + return parse(registries.getCore().getWolfyUtils(), stack); + } + + public ItemReference parse(WolfyUtils wolfyUtils, ItemStack stack) { + if (priorityIndexedParsers == null) { + reIndexParsers(); + } + Optional reference; + for (ItemReferenceParserSettings.Creator.AbstractParser parser : priorityIndexedParsers) { + reference = parser.parseFromStack(wolfyUtils, stack); + if (reference.isPresent()) { + return reference.get(); + } + } + return null; + } + + private void reIndexParsers() { + priorityIndexedParsers = parserMap.values().stream().filter(Objects::nonNull).sorted().toList(); + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/inventory/ItemUtils.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/inventory/ItemUtils.java index 80929c86..7b0cab81 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/inventory/ItemUtils.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/inventory/ItemUtils.java @@ -86,7 +86,7 @@ public static boolean isAirOrNull(ItemStack item) { } public static boolean isAirOrNull(CustomItem item) { - return item == null || item.getApiReference() == null || isAirOrNull(item.getItemStack()); + return item == null || item.getReference() == null || isAirOrNull(item.getItemStack()); } /* diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/BukkitItemStackConfig.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/BukkitItemStackConfig.java new file mode 100644 index 00000000..d0a00e33 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/BukkitItemStackConfig.java @@ -0,0 +1,320 @@ +package com.wolfyscript.utilities.bukkit.world.items; + +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wolfyscript.utilities.bukkit.WolfyCoreBukkit; +import com.wolfyscript.utilities.common.WolfyUtils; +import com.wolfyscript.utilities.common.items.ItemStackConfig; +import com.wolfyscript.utilities.nbt.NBTTagConfig; +import com.wolfyscript.utilities.nbt.NBTTagConfigBoolean; +import com.wolfyscript.utilities.nbt.NBTTagConfigByte; +import com.wolfyscript.utilities.nbt.NBTTagConfigByteArray; +import com.wolfyscript.utilities.nbt.NBTTagConfigCompound; +import com.wolfyscript.utilities.nbt.NBTTagConfigDouble; +import com.wolfyscript.utilities.nbt.NBTTagConfigFloat; +import com.wolfyscript.utilities.nbt.NBTTagConfigInt; +import com.wolfyscript.utilities.nbt.NBTTagConfigIntArray; +import com.wolfyscript.utilities.nbt.NBTTagConfigList; +import com.wolfyscript.utilities.nbt.NBTTagConfigListCompound; +import com.wolfyscript.utilities.nbt.NBTTagConfigListDouble; +import com.wolfyscript.utilities.nbt.NBTTagConfigListFloat; +import com.wolfyscript.utilities.nbt.NBTTagConfigListInt; +import com.wolfyscript.utilities.nbt.NBTTagConfigListIntArray; +import com.wolfyscript.utilities.nbt.NBTTagConfigListLong; +import com.wolfyscript.utilities.nbt.NBTTagConfigListPrimitive; +import com.wolfyscript.utilities.nbt.NBTTagConfigListString; +import com.wolfyscript.utilities.nbt.NBTTagConfigLong; +import com.wolfyscript.utilities.nbt.NBTTagConfigPrimitive; +import com.wolfyscript.utilities.nbt.NBTTagConfigShort; +import com.wolfyscript.utilities.nbt.NBTTagConfigString; +import com.wolfyscript.utilities.eval.context.EvalContext; +import com.wolfyscript.utilities.eval.operator.BoolOperatorConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProvider; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderByteArrayConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderByteConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderDoubleConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderFloatConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderIntArrayConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderIntegerConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderLongConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderShortConst; +import com.wolfyscript.utilities.eval.value_provider.ValueProviderStringConst; +import com.wolfyscript.utilities.versioning.MinecraftVersion; +import com.wolfyscript.utilities.versioning.ServerVersion; +import de.tr7zw.changeme.nbtapi.NBTCompound; +import de.tr7zw.changeme.nbtapi.NBTCompoundList; +import de.tr7zw.changeme.nbtapi.NBTItem; +import de.tr7zw.changeme.nbtapi.NBTList; +import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBT; +import de.tr7zw.changeme.nbtapi.iface.ReadableNBTList; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.stream.Collectors; +import net.kyori.adventure.platform.bukkit.BukkitComponentSerializer; +import net.kyori.adventure.text.minimessage.MiniMessage; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class BukkitItemStackConfig extends ItemStackConfig { + + private final boolean usePaperDisplayOptions; + private final Set HANDLED_NBT_TAGS = Set.of("display.Name", "display.Lore", "CustomModelData", "Damage", "Enchantments"); + + @JsonCreator + public BukkitItemStackConfig(@JacksonInject WolfyUtils wolfyUtils, @JsonProperty("itemId") String itemId) { + super(wolfyUtils, itemId); + this.usePaperDisplayOptions = ((WolfyCoreBukkit) wolfyUtils.getCore()).getCompatibilityManager().isPaper() && ServerVersion.isAfterOrEq(MinecraftVersion.of(1, 18, 2)); + } + + public BukkitItemStackConfig(WolfyUtils wolfyUtils, ItemStack stack) { + super(wolfyUtils, stack.getType().getKey().toString()); + this.usePaperDisplayOptions = ((WolfyCoreBukkit) wolfyUtils.getCore()).getCompatibilityManager().isPaper() && ServerVersion.isAfterOrEq(MinecraftVersion.of(1, 18, 2)); + + // Read from ItemStack + this.amount = new ValueProviderIntegerConst(wolfyUtils, stack.getAmount()); + ItemMeta meta = stack.getItemMeta(); + if (meta != null) { + MiniMessage miniMsg = wolfyUtils.getChat().getMiniMessage(); + if (usePaperDisplayOptions) { + if (meta.hasDisplayName()) { + this.name = new ValueProviderStringConst(wolfyUtils, miniMsg.serialize(meta.displayName())); + } + if (meta.hasLore()) { + this.lore = meta.lore().stream().map(component -> new ValueProviderStringConst(wolfyUtils, miniMsg.serialize(component))).toList(); + } + } else { + // First need to convert the Strings to Component and then back to mini message! + if (meta.hasDisplayName()) { + this.name = new ValueProviderStringConst(wolfyUtils, miniMsg.serialize(BukkitComponentSerializer.legacy().deserialize(meta.getDisplayName()))); + } + if (meta.hasLore()) { + this.lore = meta.getLore().stream().map(s -> new ValueProviderStringConst(wolfyUtils, miniMsg.serialize(BukkitComponentSerializer.legacy().deserialize(s)))).toList(); + } + } + this.unbreakable = new BoolOperatorConst(wolfyUtils, meta.isUnbreakable()); + this.customModelData = new ValueProviderIntegerConst(wolfyUtils, meta.getCustomModelData()); + } + this.enchants = stack.getEnchantments().entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey().getKey().toString(), entry -> new ValueProviderIntegerConst(wolfyUtils, entry.getValue()))); + + this.nbt = readFromItemStack(new NBTItem(stack), "", null); + } + + @Override + public ItemStack constructItemStack() { + return constructItemStack(new EvalContext()); + } + + @Override + public ItemStack constructItemStack(EvalContext context) { + Material type = Material.matchMaterial(itemId); + if (type != null) { + ItemStack itemStack = new ItemStack(type); + itemStack.setAmount(amount.getValue(context)); + + // Apply the NBT of the stack + NBTItem nbtItem = new NBTItem(itemStack); + applyCompound(nbtItem, getNbt(), context); + itemStack = nbtItem.getItem(); + + // Apply ItemMeta afterwards to override possible NBT Tags + ItemMeta meta = itemStack.getItemMeta(); + if (meta != null) { + MiniMessage miniMsg = wolfyUtils.getChat().getMiniMessage(); + if (usePaperDisplayOptions) { + if (this.name != null) { + meta.displayName(miniMsg.deserialize(this.name.getValue(context))); + } + if (this.lore != null && !this.lore.isEmpty()) { + meta.lore(this.lore.stream().filter(Objects::nonNull).map(stringValueProvider -> miniMsg.deserialize(stringValueProvider.getValue(context))).toList()); + } + } else { + meta.setDisplayName(name.getValue(context)); + meta.setLore(lore.stream().map(line -> line.getValue(context)).toList()); + } + for (Map.Entry> entry : enchants.entrySet()) { + Enchantment enchant = Enchantment.getByKey(NamespacedKey.fromString(entry.getKey())); + if (enchant != null) { + meta.addEnchant(enchant, entry.getValue().getValue(context), true); + } + } + meta.setCustomModelData(customModelData.getValue(context)); + meta.setUnbreakable(unbreakable.evaluate(context)); + itemStack.setItemMeta(meta); + } + return itemStack; + } + return null; + } + + private NBTTagConfigCompound readFromItemStack(ReadableNBT currentCompound, String path, NBTTagConfig parent) { + NBTTagConfigCompound configCompound = new NBTTagConfigCompound(wolfyUtils, parent); + Map children = new HashMap<>(); + for (String key : currentCompound.getKeys()) { + String childPath = path.isEmpty() ? key : (path + "." + key); + if (HANDLED_NBT_TAGS.contains(childPath)) { + // Skip already handled NBT Tags, so they are not both in common and NBT settings! + continue; + } + NBTTagConfig childConfig = switch (currentCompound.getType(key)) { + case NBTTagCompound -> { + NBTTagConfigCompound readConfigCompound = readFromItemStack(currentCompound.getCompound(key), childPath, configCompound); + if (readConfigCompound.getChildren().isEmpty()) { + yield null; + } + yield readConfigCompound; + } + case NBTTagList -> switch (currentCompound.getListType(key)) { + case NBTTagCompound -> { + NBTTagConfigListCompound compoundConfigList = new NBTTagConfigListCompound(wolfyUtils, parent, List.of()); + ReadableNBTList compoundList = currentCompound.getCompoundList(key); + List elements = new ArrayList<>(); + int index = 0; + for (ReadWriteNBT listCompound : compoundList) { + elements.add(readFromItemStack(listCompound, childPath + "." + index, compoundConfigList)); + index++; + } + compoundConfigList.setValues(elements); + yield compoundConfigList; + } + case NBTTagInt -> + readPrimitiveList(currentCompound.getIntegerList(key), new NBTTagConfigListInt(wolfyUtils, configCompound, new ArrayList<>()), (listInt, integer) -> new NBTTagConfigInt(wolfyUtils, listInt, new ValueProviderIntegerConst(wolfyUtils, integer))); + case NBTTagIntArray -> + readPrimitiveList(currentCompound.getIntArrayList(key), new NBTTagConfigListIntArray(wolfyUtils, configCompound, new ArrayList<>()), (listIntArray, intArray) -> new NBTTagConfigIntArray(wolfyUtils, listIntArray, new ValueProviderIntArrayConst(wolfyUtils, intArray))); + case NBTTagLong -> + readPrimitiveList(currentCompound.getLongList(key), new NBTTagConfigListLong(wolfyUtils, configCompound, new ArrayList<>()), (listConfig, aLong) -> new NBTTagConfigLong(wolfyUtils, listConfig, new ValueProviderLongConst(wolfyUtils, aLong))); + case NBTTagFloat -> + readPrimitiveList(currentCompound.getFloatList(key), new NBTTagConfigListFloat(wolfyUtils, configCompound, new ArrayList<>()), (listConfig, aFloat) -> new NBTTagConfigFloat(wolfyUtils, listConfig, new ValueProviderFloatConst(wolfyUtils, aFloat))); + case NBTTagDouble -> + readPrimitiveList(currentCompound.getDoubleList(key), new NBTTagConfigListDouble(wolfyUtils, configCompound, new ArrayList<>()), (listConfig, aDouble) -> new NBTTagConfigDouble(wolfyUtils, listConfig, new ValueProviderDoubleConst(wolfyUtils, aDouble))); + case NBTTagString -> + readPrimitiveList(currentCompound.getStringList(key), new NBTTagConfigListString(wolfyUtils, configCompound, new ArrayList<>()), (listConfig, aString) -> new NBTTagConfigString(wolfyUtils, listConfig, new ValueProviderStringConst(wolfyUtils, aString))); + default -> null; + }; + case NBTTagByte -> + new NBTTagConfigByte(wolfyUtils, configCompound, new ValueProviderByteConst(wolfyUtils, currentCompound.getByte(key))); + case NBTTagByteArray -> + new NBTTagConfigByteArray(wolfyUtils, configCompound,new ValueProviderByteArrayConst(wolfyUtils, currentCompound.getByteArray(key))); + case NBTTagShort -> + new NBTTagConfigShort(wolfyUtils, configCompound, new ValueProviderShortConst(wolfyUtils, currentCompound.getShort(key))); + case NBTTagInt -> + new NBTTagConfigInt(wolfyUtils, configCompound, new ValueProviderIntegerConst(wolfyUtils, currentCompound.getInteger(key))); + case NBTTagIntArray -> + new NBTTagConfigIntArray(wolfyUtils, configCompound, new ValueProviderIntArrayConst(wolfyUtils, currentCompound.getIntArray(key))); + case NBTTagLong -> + new NBTTagConfigLong(wolfyUtils, configCompound, new ValueProviderLongConst(wolfyUtils, currentCompound.getLong(key))); + case NBTTagFloat -> + new NBTTagConfigFloat(wolfyUtils, configCompound, new ValueProviderFloatConst(wolfyUtils, currentCompound.getFloat(key))); + case NBTTagDouble -> + new NBTTagConfigDouble(wolfyUtils, configCompound, new ValueProviderDoubleConst(wolfyUtils, currentCompound.getDouble(key))); + case NBTTagString -> + new NBTTagConfigString(wolfyUtils, configCompound, new ValueProviderStringConst(wolfyUtils, currentCompound.getString(key))); + default -> null; + }; + if (childConfig != null) { + children.put(key, childConfig); + } + } + configCompound.setChildren(children); + return configCompound; + } + + /** + * Reads the elements of a NBTList and converts them, using the given function, to the NBTTagConfig. + * + * @param nbtList The NBTList from the NBTItemAPI + * @param configList The instance of the NBTTagConfigList to load the elements into. + * @param elementConstructor This constructs each element of list. + * @param The primitive data type. + * @param The type of the Element config. + * @return The configList instance with the new elements. + */ + private > NBTTagConfigListPrimitive readPrimitiveList(ReadableNBTList nbtList, NBTTagConfigListPrimitive configList, BiFunction, T, VAL> elementConstructor) { + configList.setValues(nbtList.toListCopy().stream().map(value -> elementConstructor.apply(configList, value)).toList()); + return configList; + } + + private void applyCompound(NBTCompound compound, NBTTagConfigCompound config, EvalContext context) { + for (Map.Entry entry : config.getChildren().entrySet()) { + var tagConfig = entry.getValue(); + var tagName = entry.getKey(); + if (tagConfig instanceof NBTTagConfigCompound configCompound) { + applyCompound(compound.addCompound(entry.getKey()), configCompound, context); + } else if (tagConfig instanceof NBTTagConfigList configList) { + applyList(compound, tagName, configList, context); + } else if (tagConfig instanceof NBTTagConfigByte configByte) { + compound.setByte(entry.getKey(), configByte.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigByteArray configByteArray) { + compound.setByteArray(entry.getKey(), configByteArray.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigShort configShort) { + compound.setShort(entry.getKey(), configShort.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigInt configInt) { + compound.setInteger(entry.getKey(), configInt.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigIntArray configIntArray) { + compound.setIntArray(entry.getKey(), configIntArray.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigLong configLong) { + compound.setLong(entry.getKey(), configLong.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigFloat configFloat) { + compound.setFloat(entry.getKey(), configFloat.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigDouble configDouble) { + compound.setDouble(entry.getKey(), configDouble.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigString configString) { + compound.setString(entry.getKey(), configString.getValue().getValue(context)); + } else if (tagConfig instanceof NBTTagConfigBoolean configBoolean) { + compound.setBoolean(entry.getKey(), configBoolean.getValue(context)); + } + } + } + + private void applyList(NBTCompound compound, String tagName, NBTTagConfigList configList, EvalContext context) { + if (configList instanceof NBTTagConfigListCompound configListCompound) { + NBTCompoundList list = compound.getCompoundList(tagName); + for (NBTTagConfigList.Element element : configListCompound.getElements()) { + applyCompound(list.addCompound(), element.getValue(), context); + } + } else if (configList instanceof NBTTagConfigListInt configListInt) { + applyPrimitiveList(compound.getIntegerList(tagName), configListInt, context); + } else if (configList instanceof NBTTagConfigListLong configListLong) { + applyPrimitiveList(compound.getLongList(tagName), configListLong, context); + } else if (configList instanceof NBTTagConfigListFloat configListFloat) { + applyPrimitiveList(compound.getFloatList(tagName), configListFloat, context); + } else if (configList instanceof NBTTagConfigListDouble configListDouble) { + applyPrimitiveList(compound.getDoubleList(tagName), configListDouble, context); + } else if (configList instanceof NBTTagConfigListString configListString) { + applyPrimitiveList(compound.getStringList(tagName), configListString, context); + } else if (configList instanceof NBTTagConfigListIntArray configListIntArray) { + applyPrimitiveList(compound.getIntArrayList(tagName), configListIntArray, context); + } + } + + private void applyPrimitiveList(NBTList nbtList, NBTTagConfigList> configPrimitive, EvalContext context) { + for (NBTTagConfigList.Element> element : configPrimitive.getElements()) { + nbtList.add(element.getValue().getValue().getValue(context)); // This looks weird, but it will provide more options in the future. + } + } + + @Override + public String toString() { + return "BukkitItemStackConfig{" + + "itemId='" + itemId + '\'' + + ", name=" + name + + ", lore=" + lore + + ", amount=" + amount + + ", repairCost=" + repairCost + + ", damage=" + damage + + ", unbreakable=" + unbreakable + + ", customModelData=" + customModelData + + ", enchants=" + enchants + + ", nbt=" + nbt + + "} "; + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/CustomItem.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/CustomItem.java index 9c22c019..47c33d1b 100644 --- a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/CustomItem.java +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/CustomItem.java @@ -18,6 +18,7 @@ package com.wolfyscript.utilities.bukkit.world.items; +import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonAutoDetect; @@ -29,6 +30,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.collect.Streams; import com.wolfyscript.utilities.Keyed; @@ -46,7 +48,12 @@ import com.wolfyscript.utilities.bukkit.world.items.references.VanillaRef; import com.wolfyscript.utilities.bukkit.world.items.references.WolfyUtilitiesRef; import com.wolfyscript.utilities.bukkit.registry.BukkitRegistries; +import com.wolfyscript.utilities.common.WolfyUtils; import com.wolfyscript.utilities.json.jackson.JacksonUtil; +import com.wolfyscript.utilities.bukkit.world.items.reference.BackwardsWrapperReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.BukkitItemReference; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemRefCompDeserializer; +import com.wolfyscript.utilities.bukkit.world.items.reference.ItemReference; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -96,11 +103,11 @@ public class CustomItem extends AbstractItemBuilder implements Keyed { public static final org.bukkit.NamespacedKey PERSISTENT_KEY_TAG = new org.bukkit.NamespacedKey(WolfyCoreBukkit.getInstance(), "custom_item"); - private static final Map> API_REFERENCE_PARSER = new HashMap<>(); + @Deprecated @Nullable public static APIReference.Parser getApiReferenceParser(String id) { - return API_REFERENCE_PARSER.get(id); + return BackwardsWrapperReference.BackwardCompatibleParser.getApiReferenceParser(id); } /** @@ -108,19 +115,14 @@ public static APIReference.Parser getApiReferenceParser(String id) { * * @param parser an {@link APIReference.Parser} instance. */ + @Deprecated public static void registerAPIReferenceParser(APIReference.Parser parser) { - if (parser instanceof APIReference.PluginParser pluginParser) { - if (!WolfyCoreBukkit.getInstance().getCompatibilityManager().getPlugins().isPluginEnabled(pluginParser.getPluginName())) { - return; - } - pluginParser.init(Bukkit.getPluginManager().getPlugin(pluginParser.getPluginName())); - } - API_REFERENCE_PARSER.put(parser.getId(), parser); - if (!parser.getAliases().isEmpty()) { - parser.getAliases().forEach(s -> API_REFERENCE_PARSER.putIfAbsent(s, parser)); - } + BackwardsWrapperReference.BackwardCompatibleParser.registerAPIReferenceParser(parser); } + @JsonIgnore + private final WolfyUtils wolfyUtils; + @JsonIgnore private final Material type; @@ -137,8 +139,9 @@ public static void registerAPIReferenceParser(APIReference.Parser parser) { @JsonIgnore private final Material craftRemain; - @JsonAlias("api_reference") - private final APIReference apiReference; + // Converts old APIReferences to the new ItemReference, otherwise just deserializes the ItemReference. + @JsonDeserialize(using = ItemRefCompDeserializer.class) + private final ItemReference reference; @JsonAlias("custom_data") private final CustomData.DeprecatedCustomDataWrapper customDataMap = new CustomData.DeprecatedCustomDataWrapper(this); @@ -169,15 +172,16 @@ public static void registerAPIReferenceParser(APIReference.Parser parser) { private boolean checkOldMetaSettings = true; @JsonCreator - public CustomItem(@JsonProperty("apiReference") @JsonAlias({"item", "api_reference"}) APIReference apiReference) { + public CustomItem(@JacksonInject WolfyUtils wolfyUtils, @JsonProperty("reference") @JsonAlias({"item", "api_reference", "apiReference"}) @JsonDeserialize(using = ItemRefCompDeserializer.class) ItemReference reference) { super(CustomItem.class); - this.apiReference = apiReference; + this.wolfyUtils = wolfyUtils; + 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.getWeight() > 0 ? reference.getWeight() : 1.0d; for (CustomData.Provider customData : WolfyUtilCore.getInstance().getRegistries().getCustomItemData().values()) { addCustomData(customData.getNamespacedKey(), customData.createData()); } @@ -195,49 +199,13 @@ public CustomItem(@JsonProperty("apiReference") @JsonAlias({"item", "api_referen this.craftRemain = getCraftRemain(); } - @JsonAnySetter - protected void setOldProperties(String fieldKey, JsonNode value) throws JsonProcessingException { - if (fieldKey.equals("advanced")) { - checkOldMetaSettings = value.asBoolean(); - } else if (fieldKey.equals("metaSettings") || fieldKey.equals("meta")) { - //Since the new system has its new field we need to update old appearances to the new system. - JsonNode node = value.isTextual() ? JacksonUtil.getObjectMapper().readTree(value.asText()) : value; - final List checks; - if (!node.has(MetaSettings.CHECKS_KEY)) { - checks = new ArrayList<>(); - if (checkOldMetaSettings) { - //Convert old meta to new format. - node.fields().forEachRemaining(entry -> { - if (entry.getValue() instanceof ObjectNode entryVal) { - String key = entry.getKey().toLowerCase(Locale.ROOT); - BukkitNamespacedKey namespacedKey = key.contains(":") ? BukkitNamespacedKey.of(key) : BukkitNamespacedKey.wolfyutilties(key); - if (namespacedKey != null) { - entryVal.put("key", String.valueOf(namespacedKey)); - Meta meta = JacksonUtil.getObjectMapper().convertValue(entryVal, Meta.class); - if (meta != null && !meta.getOption().equals(MetaSettings.Option.IGNORE) && !meta.getOption().equals(MetaSettings.Option.EXACT)) { - checks.add(meta); - } - } - } - }); - } - } else { - checks = JacksonUtil.getObjectMapper().convertValue(node.get(MetaSettings.CHECKS_KEY), new TypeReference<>() { - }); - } - var nbtChecks = new MetaSettings(); - checks.forEach(nbtChecks::addCheck); - setMetaSettings(nbtChecks); - } - } - /** * Creates a CustomItem with a Vanilla Reference to the itemstack * * @param itemStack the itemstack this CustomItem will be linked to */ public CustomItem(ItemStack itemStack) { - this(new VanillaRef(itemStack)); + this(WolfyCoreBukkit.getInstance().getWolfyUtils(), new BukkitItemReference(WolfyCoreBukkit.getInstance().getWolfyUtils(), itemStack)); } /** @@ -254,7 +222,8 @@ public CustomItem(Material material) { */ private CustomItem(CustomItem customItem) { super(CustomItem.class); - this.apiReference = customItem.apiReference.clone(); + this.wolfyUtils = customItem.wolfyUtils; + this.reference = customItem.reference.copy(); this.namespacedKey = customItem.getNamespacedKey(); this.fuelSettings = customItem.fuelSettings.clone(); @@ -279,6 +248,47 @@ private CustomItem(CustomItem customItem) { this.craftRemain = getCraftRemain(); } + @Deprecated + public CustomItem(APIReference reference) { + this(WolfyCoreBukkit.getInstance().getWolfyUtils(), new BackwardsWrapperReference(WolfyCoreBukkit.getInstance().getWolfyUtils(), reference)); + } + + @JsonAnySetter + protected void setOldProperties(String fieldKey, JsonNode value) throws JsonProcessingException { + if (fieldKey.equals("advanced")) { + checkOldMetaSettings = value.asBoolean(); + } else if (fieldKey.equals("metaSettings") || fieldKey.equals("meta")) { + //Since the new system has its new field we need to update old appearances to the new system. + JsonNode node = value.isTextual() ? JacksonUtil.getObjectMapper().readTree(value.asText()) : value; + final List checks; + if (!node.has(MetaSettings.CHECKS_KEY)) { + checks = new ArrayList<>(); + if (checkOldMetaSettings) { + //Convert old meta to new format. + node.fields().forEachRemaining(entry -> { + if (entry.getValue() instanceof ObjectNode entryVal) { + String key = entry.getKey().toLowerCase(Locale.ROOT); + BukkitNamespacedKey namespacedKey = key.contains(":") ? BukkitNamespacedKey.of(key) : BukkitNamespacedKey.wolfyutilties(key); + if (namespacedKey != null) { + entryVal.put("key", String.valueOf(namespacedKey)); + Meta meta = JacksonUtil.getObjectMapper().convertValue(entryVal, Meta.class); + if (meta != null && !meta.getOption().equals(MetaSettings.Option.IGNORE) && !meta.getOption().equals(MetaSettings.Option.EXACT)) { + checks.add(meta); + } + } + } + }); + } + } else { + checks = JacksonUtil.getObjectMapper().convertValue(node.get(MetaSettings.CHECKS_KEY), new TypeReference<>() { + }); + } + var nbtChecks = new MetaSettings(); + checks.forEach(nbtChecks::addCheck); + setMetaSettings(nbtChecks); + } + } + /** * Clones the CustomItem and all the containing data. * @@ -304,6 +314,7 @@ public CustomItem clone() { * @param reference The reference to link the item to. * @return A new CustomItem instance with the specified APIReference. */ + @Deprecated public static CustomItem with(APIReference reference) { if (reference == null) return null; return new CustomItem(reference); @@ -326,6 +337,7 @@ public static CustomItem with(APIReference reference) { * @param reference The reference that points to an API Item. * @return The actual CustomItem of the APIReference. */ + @Deprecated @Nullable public static CustomItem of(APIReference reference) { if (reference == null) return null; @@ -342,10 +354,10 @@ public static CustomItem of(APIReference reference) { */ public static CustomItem getReferenceByItemStack(ItemStack itemStack) { if (itemStack != null) { - APIReference apiReference = API_REFERENCE_PARSER.values().stream().sorted(APIReference.Parser::compareTo).map(parser -> parser.construct(itemStack)).filter(Objects::nonNull).findFirst().orElse(null); - if (apiReference != null) { - apiReference.setAmount(itemStack.getAmount()); - return new CustomItem(apiReference); + ItemReference reference = WolfyUtilCore.getInstance().getRegistries().getItemReferences().parse(itemStack); + if (reference != null) { + reference.setAmount(itemStack.getAmount()); + return new CustomItem(WolfyCoreBukkit.getInstance().getWolfyUtils(), reference); } return new CustomItem(itemStack); } @@ -627,10 +639,10 @@ public boolean isSimilar(ItemStack otherItem, boolean exactMeta, boolean ignoreA if (otherItem != null && otherItem.getType().equals(this.type) && (ignoreAmount || otherItem.getAmount() >= getAmount())) { if (hasNamespacedKey()) { return getMetaSettings().check(this, new ItemBuilder(otherItem)); - } else if (getApiReference() instanceof VanillaRef && (!hasItemMeta() && !exactMeta)) { + } else if (getReference() instanceof BukkitItemReference && (!hasItemMeta() && !exactMeta)) { return true; } - return getApiReference().isValidItem(otherItem); + return getReference().isValidItem(otherItem); } return false; } @@ -651,14 +663,14 @@ 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); } @Override public int hashCode() { - return Objects.hash(getCustomDataMap(), getNamespacedKey(), getReplacement(), getPermission(), getRarityPercentage(), getFuelSettings(), getBlockSettings(), getDurabilityCost(), isConsumed(), blockPlacement, isBlockVanillaEquip(), isBlockVanillaRecipes(), getEquipmentSlots(), getApiReference(), getParticleContent(), getMetaSettings()); + return Objects.hash(getCustomDataMap(), getNamespacedKey(), getReplacement(), getPermission(), getRarityPercentage(), getFuelSettings(), getBlockSettings(), getDurabilityCost(), isConsumed(), blockPlacement, isBlockVanillaEquip(), isBlockVanillaRecipes(), getEquipmentSlots(), getReference(), getParticleContent(), getMetaSettings()); } /** @@ -669,7 +681,7 @@ public int hashCode() { */ @Override public ItemStack getItemStack() { - return apiReference.getLinkedItem(); + return reference.getItem(); } /** @@ -693,10 +705,10 @@ 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.getItem().clone(); if (this.hasNamespacedKey()) { var itemMeta = itemStack.getItemMeta(); - itemMeta.getPersistentDataContainer().set(new org.bukkit.NamespacedKey(WolfyCoreBukkit.getInstance(), "custom_item"), PersistentDataType.STRING, namespacedKey.toString()); + itemMeta.getPersistentDataContainer().set(PERSISTENT_KEY_TAG, PersistentDataType.STRING, namespacedKey.toString()); itemStack.setItemMeta(itemMeta); } if (amount > 0) { @@ -718,22 +730,33 @@ public ItemStack getIDItem() { /** * This item should only be used to visualize the namespacedkey! - * It doesn't include a NBT Tag with the namspacekey and non of the WU features! + * It doesn't include a NBT Tag with the namspacekey and none of the WU features! * * @param amount The stacksize of the item * @return ItemStack that visually represents the namespacekey + * @deprecated */ @Deprecated public ItemStack getIDItem(int amount) { - var itemStack = apiReference.getIdItem(); - if (amount > 0) { - itemStack.setAmount(amount); - } - return itemStack; + return create(amount); } + /** + * Returns the old APIReference as good as possible. + * Though, it either returns the wrapped APIReference from the {@link BackwardsWrapperReference} if available, otherwise it returns the {@link VanillaRef} + * + * @return the wrapped APIReference from the {@link BackwardsWrapperReference} if available; otherwise {@link VanillaRef} + */ + @Deprecated public APIReference getApiReference() { - return apiReference; + if (reference instanceof BackwardsWrapperReference backwardsRef) { + return backwardsRef.getWrappedApiReference(); + } + return new VanillaRef(getItemStack()); + } + + public ItemReference getReference() { + return reference; } /** @@ -741,7 +764,7 @@ public APIReference getApiReference() { * @param totalAmount The amount of this custom item that should be removed from the input. * @param inventory The optional inventory to add the replacements to. (Only for stackable items) * @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 Renamed to {@link #remove(ItemStack, int, Inventory, Location)} to better show its functionality. */ @Deprecated public void consumeItem(ItemStack input, int totalAmount, Inventory inventory, Location location) { @@ -752,7 +775,7 @@ public void consumeItem(ItemStack input, int totalAmount, Inventory inventory, L * @param input The input ItemStack, that is also going to be edited. * @param totalAmount The amount of this custom item that should be removed from the input. * @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 Renamed to {@link #remove(ItemStack, int, Inventory)} to better show its functionality. */ @Deprecated public void consumeItem(ItemStack input, int totalAmount, Inventory inventory) { @@ -763,7 +786,7 @@ public void consumeItem(ItemStack input, int totalAmount, Inventory inventory) { * @param input The input ItemStack, that is also going to be edited. * @param totalAmount The amount of this custom item that should be removed from the input. * @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 Renamed to {@link #remove(ItemStack, int, Location)} to better show its functionality. */ @Deprecated public ItemStack consumeItem(ItemStack input, int totalAmount, Location location) { @@ -1481,7 +1504,7 @@ public void setAdvanced(boolean advanced) { * @return actual amount of CustomItem */ public int getAmount() { - return getApiReference().getAmount(); + return getReference().getAmount(); } /** @@ -1490,7 +1513,7 @@ public int getAmount() { * @param amount The new amount of the item. */ public void setAmount(int amount) { - getApiReference().setAmount(amount); + getReference().setAmount(amount); } public boolean isBlock() { @@ -1514,7 +1537,7 @@ public String toString() { ", blockVanillaEquip=" + blockVanillaEquip + ", blockVanillaRecipes=" + blockVanillaRecipes + ", equipmentSlots=" + equipmentSlots + - ", apiReference=" + apiReference + + ", reference=" + reference + ", particleContent=" + particleContent + ", metaSettings=" + nbtChecks + "} " + super.toString(); diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BackwardsWrapperReference.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BackwardsWrapperReference.java new file mode 100644 index 00000000..2df1f929 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BackwardsWrapperReference.java @@ -0,0 +1,101 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.wolfyscript.utilities.KeyedStaticId; +import com.wolfyscript.utilities.bukkit.WolfyUtilCore; +import com.wolfyscript.utilities.bukkit.world.items.references.APIReference; +import com.wolfyscript.utilities.common.WolfyUtils; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import org.bukkit.Bukkit; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; + +// Don't use it to parse from ItemStack (Set priority lower than BukkitItemReference)! +@ItemReferenceParserSettings(priority = -999, parser = BackwardsWrapperReference.BackwardCompatibleParser.class) +@KeyedStaticId(key = "backwards_comp_wrapper") +public class BackwardsWrapperReference extends ItemReference { + + private final APIReference apiReference; + + public BackwardsWrapperReference(WolfyUtils wolfyUtils, APIReference apiReference) { + super(wolfyUtils); + this.apiReference = apiReference; + } + + public BackwardsWrapperReference(BackwardsWrapperReference reference) { + super(reference); + this.apiReference = reference.apiReference.clone(); + } + + public APIReference getWrappedApiReference() { + return apiReference; + } + + @Override + public ItemReference copy() { + return new BackwardsWrapperReference(this); + } + + @Override + public ItemStack getItem() { + return apiReference.getLinkedItem(); + } + + @Override + public boolean isValidItem(ItemStack itemStack) { + return apiReference.isValidItem(itemStack); + } + + @Override + public String toString() { + return "BackwardsWrapperReference{" + + "apiReference=" + apiReference + + "} " + super.toString(); + } + + public static class BackwardCompatibleParser implements Parser { + + private static final Map> PARSERS = new HashMap<>(); + + @Override + public Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack) { + return Optional.of(new BackwardsWrapperReference(wolfyUtils, parseOldAPIRef(stack))); + } + + private APIReference parseOldAPIRef(ItemStack stack) { + if (stack != null) { + APIReference apiReference = PARSERS.values().stream().sorted(APIReference.Parser::compareTo).map(parser -> parser.construct(stack)).filter(Objects::nonNull).findFirst().orElse(null); + if (apiReference != null) { + apiReference.setAmount(stack.getAmount()); + return apiReference; + } + } + return null; + } + + /** + * Register a new {@link APIReference.Parser} that can parse ItemStacks and keys from another plugin to a usable {@link APIReference} + * + * @param parser an {@link APIReference.Parser} instance. + */ + public static void registerAPIReferenceParser(APIReference.Parser parser) { + if (parser instanceof APIReference.PluginParser pluginParser) { + if (!WolfyUtilCore.getInstance().getCompatibilityManager().getPlugins().isPluginEnabled(pluginParser.getPluginName())) { + return; + } + pluginParser.init(Bukkit.getPluginManager().getPlugin(pluginParser.getPluginName())); + } + PARSERS.put(parser.getId(), parser); + if (!parser.getAliases().isEmpty()) { + parser.getAliases().forEach(s -> PARSERS.putIfAbsent(s, parser)); + } + } + + @Nullable + public static APIReference.Parser getApiReferenceParser(String id) { + return PARSERS.get(id); + } + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BukkitItemReference.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BukkitItemReference.java new file mode 100644 index 00000000..c8efd824 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/BukkitItemReference.java @@ -0,0 +1,59 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wolfyscript.utilities.KeyedStaticId; +import com.wolfyscript.utilities.common.WolfyUtils; +import java.util.Optional; +import org.bukkit.inventory.ItemStack; + +@ItemReferenceParserSettings(priority = Short.MIN_VALUE, parser = BukkitItemReference.Parser.class) +@KeyedStaticId(key = "bukkit") +public class BukkitItemReference extends ItemReference { + + private final ItemStack stack; + + @JsonCreator + public BukkitItemReference(@JacksonInject WolfyUtils wolfyUtils, @JsonProperty("stack") ItemStack stack) { + super(wolfyUtils); + this.stack = stack; + } + + protected BukkitItemReference(BukkitItemReference reference) { + super(reference); + this.stack = reference.stack; + } + + @Override + public BukkitItemReference copy() { + return new BukkitItemReference(this); + } + + @Override + public ItemStack getItem() { + return stack; + } + + @Override + public boolean isValidItem(ItemStack other) { + return stack.isSimilar(other); + } + + @Override + public String toString() { + return "BukkitItemReference{" + + "stack=" + stack + + "} " + super.toString(); + } + + public static class Parser implements ItemReference.Parser { + + @Override + public Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack) { + return Optional.of(new BukkitItemReference(wolfyUtils, stack)); + } + } + + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemRefCompDeserializer.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemRefCompDeserializer.java new file mode 100644 index 00000000..c2bbfab5 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemRefCompDeserializer.java @@ -0,0 +1,26 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdNodeBasedDeserializer; +import com.wolfyscript.utilities.bukkit.world.items.references.APIReference; +import com.wolfyscript.utilities.common.WolfyUtils; +import java.io.IOException; + +public class ItemRefCompDeserializer extends StdNodeBasedDeserializer { + + protected ItemRefCompDeserializer() { + super(ItemReference.class); + } + + @Override + public ItemReference convert(JsonNode root, DeserializationContext ctxt) throws IOException { + if (root.has("type")) { + // New ItemReference used! No conversion required! + return ctxt.readTreeAsValue(root, ItemReference.class); + } + // Need to convert APIReference + APIReference apiReference = ctxt.readTreeAsValue(root, APIReference.class); + return new BackwardsWrapperReference((WolfyUtils) ctxt.findInjectableValue(WolfyUtils.class.getName(), null, null), apiReference); + } +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemReference.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemReference.java new file mode 100644 index 00000000..e8ec6987 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemReference.java @@ -0,0 +1,130 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.databind.annotation.JsonTypeIdResolver; +import com.fasterxml.jackson.databind.annotation.JsonTypeResolver; +import com.wolfyscript.utilities.Copyable; +import com.wolfyscript.utilities.Keyed; +import com.wolfyscript.utilities.NamespacedKey; +import com.wolfyscript.utilities.bukkit.WolfyCoreBukkit; +import com.wolfyscript.utilities.bukkit.world.items.CustomItem; +import com.wolfyscript.utilities.common.WolfyUtils; +import com.wolfyscript.utilities.json.KeyedTypeIdResolver; +import com.wolfyscript.utilities.json.KeyedTypeResolver; +import java.util.Optional; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +@JsonTypeResolver(KeyedTypeResolver.class) +@JsonTypeIdResolver(KeyedTypeIdResolver.class) +@JsonTypeInfo(use = JsonTypeInfo.Id.CUSTOM, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type") +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@JsonPropertyOrder(value = {"type", "amount", "weight"}) +public abstract class ItemReference implements Keyed, Copyable { + + protected final NamespacedKey type; + + @JsonIgnore + protected WolfyUtils wolfyUtils; + protected int amount; + private double weight; + + protected ItemReference(WolfyUtils wolfyUtils) { + this.wolfyUtils = wolfyUtils; + this.type = wolfyUtils.getIdentifiers().getNamespaced(getClass()); + } + + protected ItemReference(ItemReference reference) { + this.type = WolfyCoreBukkit.getInstance().getWolfyUtils().getIdentifiers().getNamespaced(getClass()); + this.amount = reference.amount; + this.weight = reference.weight; + } + + public abstract ItemStack getItem(); + + public ItemStack getItem(Player player) { + return getItem(); + } + + public ItemStack getItem(Block block) { + return getItem(); + } + + public abstract boolean isValidItem(ItemStack itemStack); + + /** + * The amount of the reference. + *

+ * If the amount of this {@link ItemReference}: + *

    + *
  • is equal or less than 0, then this method will return the amount of the {@link ItemStack#getAmount()} from {@link #getItem()}.
  • + *
  • is greater than 0, then this method will return the amount
  • + *
+ *

+ * + * @return The correct amount of this reference or linked item. + */ + public int getAmount() { + return amount > 0 ? amount : getItem().getAmount(); + } + + /** + * Sets the amount of this APIReference. + * Note: That a value of 0 or less indicates that the amount of this APIReference is equal to the linked ItemStack. + * + * @param amount The amount of this APIReference. + */ + public void setAmount(int amount) { + this.amount = amount; + } + + /** + * The weight can be used to select an item randomly based on their weight. + * For example for recipes like CustomCrafting does. + *
+ * If the weight is bigger than 0 it will override the weight of the {@link CustomItem}, that is created from this reference. + * + * @return The weight of this reference. + */ + public double getWeight() { + return weight; + } + + /** + * The weight can be used to select an item randomly based on their weight. + * For example for recipes like CustomCrafting does. + *
+ * If the weight is bigger than 0 it will override the weight of the {@link CustomItem}, that is created from this reference. + * + * @param weight The weight of this reference. + */ + public void setWeight(double weight) { + this.weight = weight; + } + + @JsonIgnore + @Override + public NamespacedKey getNamespacedKey() { + return type; + } + + @Override + public String toString() { + return "ItemReference{" + + "type=" + type + + ", amount=" + amount + + ", weight=" + weight + + '}'; + } + + public interface Parser { + + Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack); + + } + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemReferenceParserSettings.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemReferenceParserSettings.java new file mode 100644 index 00000000..2b409bdd --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/ItemReferenceParserSettings.java @@ -0,0 +1,124 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.wolfyscript.utilities.Keyed; +import com.wolfyscript.utilities.NamespacedKey; +import com.wolfyscript.utilities.bukkit.WolfyCoreBukkit; +import com.wolfyscript.utilities.common.WolfyUtils; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Optional; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE}) +public @interface ItemReferenceParserSettings { + + /** + * 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 ""; + + class Creator { + + public static AbstractParser constructParser(NamespacedKey id, Class itemReferenceType) { + ItemReferenceParserSettings annotation = itemReferenceType.getAnnotation(ItemReferenceParserSettings.class); + if (annotation == null) { + // Annotation is not specified! No parser! + return null; + } + if (annotation.parser() != (Class>)(Object) ItemReference.Parser.class) { + // Specified Custom Parse class! + try { + Constructor constructor = annotation.parser().getConstructor(); + + final ItemReference.Parser parser = (ItemReference.Parser) constructor.newInstance(); + final int priority = annotation.priority(); + final String plugin = annotation.plugin(); + + if (plugin == null || plugin.isEmpty()) { + return new AbstractParser<>(id, priority, itemReferenceType) { + @Override + public Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack) { + return parser.parseFromStack(wolfyUtils, stack); + } + }; + } + return new AbstractParser<>(id, priority, itemReferenceType) { + @Override + public Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack) { + if (!((WolfyCoreBukkit)wolfyUtils.getCore()).getCompatibilityManager().getPlugins().isPluginEnabled(plugin)) { + return Optional.empty(); + } + return parser.parseFromStack(wolfyUtils, stack); + } + }; + } catch (NoSuchMethodException | SecurityException e) { + // Constructor not defined! + e.printStackTrace(); + } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) { + // Error creating parser! + e.printStackTrace(); + } + return null; + } + return null; + } + + /** + * Parser used to receive the correct {@link ItemReference} from {@link ItemStack}s. + * + * @param The type of the {@link ItemReference} + */ + public abstract static class AbstractParser implements Keyed, Comparable> { + + protected final NamespacedKey id; + protected final int priority; + final Class type; + + protected AbstractParser(NamespacedKey id, int priority, Class type) { + this.id = id; + this.priority = priority; + this.type = type; + } + + public abstract Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack); + + public int getPriority() { + return priority; + } + + @Override + public NamespacedKey getNamespacedKey() { + return id; + } + + @Override + public int compareTo(@NotNull ItemReferenceParserSettings.Creator.AbstractParser other) { + return -1 * Integer.compare(getPriority(), other.getPriority()); + } + } + + } + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/SimpleBukkitItemReference.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/SimpleBukkitItemReference.java new file mode 100644 index 00000000..86ab23b4 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/SimpleBukkitItemReference.java @@ -0,0 +1,76 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wolfyscript.utilities.KeyedStaticId; +import com.wolfyscript.utilities.bukkit.world.items.BukkitItemStackConfig; +import com.wolfyscript.utilities.common.WolfyUtils; +import java.util.Optional; +import org.bukkit.inventory.ItemStack; + +// At this moment of time, this reference does not save the complete ItemStack, therefor don't use it (Set priority lower than BukkitItemReference)! +@ItemReferenceParserSettings(priority = -1000, parser = SimpleBukkitItemReference.Parser.class) +@KeyedStaticId(key = "simple") +public class SimpleBukkitItemReference extends ItemReference { + + @JsonIgnore + private ItemStack cachedStack; + + private final BukkitItemStackConfig config; + @JsonCreator + public SimpleBukkitItemReference(@JacksonInject WolfyUtils wolfyUtils, @JsonProperty("config") BukkitItemStackConfig config) { + super(wolfyUtils); + this.config = config; + } + + protected SimpleBukkitItemReference(SimpleBukkitItemReference reference) { + super(reference); + this.cachedStack = null; + this.config = reference.config; + } + + @Override + public SimpleBukkitItemReference copy() { + return new SimpleBukkitItemReference(this); + } + + @JsonIgnore + @Override + public ItemStack getItem() { + if (cachedStack == null) { + cachedStack = config.constructItemStack(); + } + return cachedStack; + } + + @Override + public boolean isValidItem(ItemStack other) { + if (cachedStack == null) { + cachedStack = config.constructItemStack(); + } + return cachedStack.isSimilar(other); + } + + public BukkitItemStackConfig getConfig() { + return config; + } + + @Override + public String toString() { + return "SimpleBukkitItemReference{" + + "cachedStack=" + cachedStack + + ", config=" + config + + "} " + super.toString(); + } + + public static class Parser implements ItemReference.Parser { + + @Override + public Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack) { + return Optional.of(new SimpleBukkitItemReference(wolfyUtils, new BukkitItemStackConfig(wolfyUtils, stack))); + } + } + +} diff --git a/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/WolfyUtilsItemReference.java b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/WolfyUtilsItemReference.java new file mode 100644 index 00000000..8b3c9015 --- /dev/null +++ b/core/src/main/java/com/wolfyscript/utilities/bukkit/world/items/reference/WolfyUtilsItemReference.java @@ -0,0 +1,88 @@ +package com.wolfyscript.utilities.bukkit.world.items.reference; + +import com.fasterxml.jackson.annotation.JacksonInject; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.wolfyscript.utilities.KeyedStaticId; +import com.wolfyscript.utilities.NamespacedKey; +import com.wolfyscript.utilities.bukkit.BukkitNamespacedKey; +import com.wolfyscript.utilities.bukkit.WolfyCoreBukkit; +import com.wolfyscript.utilities.bukkit.WolfyUtilCore; +import com.wolfyscript.utilities.common.WolfyUtils; +import java.util.Objects; +import java.util.Optional; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataType; + +@ItemReferenceParserSettings(parser = WolfyUtilsItemReference.Parser.class) +@KeyedStaticId(key = "wolfyutils") +public class WolfyUtilsItemReference extends ItemReference { + + private static final org.bukkit.NamespacedKey CUSTOM_ITEM_KEY = new org.bukkit.NamespacedKey(WolfyCoreBukkit.getInstance(), "custom_item"); + + private final NamespacedKey itemID; + + @JsonCreator + public WolfyUtilsItemReference(@JacksonInject WolfyUtils wolfyUtils, @JsonProperty("itemID") NamespacedKey itemID) { + super(wolfyUtils); + this.itemID = itemID; + } + + protected WolfyUtilsItemReference(WolfyUtilsItemReference reference) { + super(reference); + this.itemID = reference.itemID; + } + + @Override + public WolfyUtilsItemReference copy() { + return new WolfyUtilsItemReference(this); + } + + @Override + public ItemStack getItem() { + var customItem = WolfyUtilCore.getInstance().getRegistries().getCustomItems().get(itemID); + if (customItem != null) { + return customItem.create(); + } + WolfyUtilCore.getInstance().getLogger().warning("Couldn't find CustomItem for " + itemID.toString()); + return null; + } + + @Override + public boolean isValidItem(ItemStack itemStack) { + if (itemStack != null) { + var itemMeta = itemStack.getItemMeta(); + if (itemMeta != null) { + var container = itemMeta.getPersistentDataContainer(); + if (container.has(CUSTOM_ITEM_KEY, PersistentDataType.STRING)) { + return Objects.equals(this.itemID, BukkitNamespacedKey.of(container.get(CUSTOM_ITEM_KEY, PersistentDataType.STRING))); + } + } + } + return false; + } + + @Override + public String toString() { + return "WolfyUtilsItemReference{" + + "itemID=" + itemID + + "} " + super.toString(); + } + + public static class Parser implements ItemReference.Parser { + + @Override + public Optional parseFromStack(WolfyUtils wolfyUtils, ItemStack stack) { + if (stack != null) { + var itemMeta = stack.getItemMeta(); + if (itemMeta != null) { + var container = itemMeta.getPersistentDataContainer(); + if (container.has(CUSTOM_ITEM_KEY, PersistentDataType.STRING)) { + return Optional.of(new WolfyUtilsItemReference(wolfyUtils, BukkitNamespacedKey.of(container.get(CUSTOM_ITEM_KEY, PersistentDataType.STRING)))); + } + } + } + return Optional.empty(); + } + } +} diff --git a/nmsutil/nmsutil-v1_16_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R1/NBTTagImpl.java b/nmsutil/nmsutil-v1_16_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R1/NBTTagImpl.java index ec9d641e..14a4a553 100644 --- a/nmsutil/nmsutil-v1_16_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R1/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_16_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R1/NBTTagImpl.java @@ -15,7 +15,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R1.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R1.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R1.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_16_R1.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/nmsutil/nmsutil-v1_16_R2/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R2/NBTTagImpl.java b/nmsutil/nmsutil-v1_16_R2/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R2/NBTTagImpl.java index 6b86ff8a..51daa481 100644 --- a/nmsutil/nmsutil-v1_16_R2/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R2/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_16_R2/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R2/NBTTagImpl.java @@ -15,7 +15,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R2.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R2.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R2.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_16_R2.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/nmsutil/nmsutil-v1_16_R3/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R3/NBTTagImpl.java b/nmsutil/nmsutil-v1_16_R3/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R3/NBTTagImpl.java index 8e49754f..ec9b9682 100644 --- a/nmsutil/nmsutil-v1_16_R3/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R3/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_16_R3/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_16_R3/NBTTagImpl.java @@ -15,7 +15,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R3.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R3.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_16_R3.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_16_R3.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/nmsutil/nmsutil-v1_17_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1/NBTTagImpl.java b/nmsutil/nmsutil-v1_17_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1/NBTTagImpl.java index a54f88a0..a6bb7d54 100644 --- a/nmsutil/nmsutil-v1_17_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_17_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1/NBTTagImpl.java @@ -15,7 +15,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_17_R1.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_17_R1.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_17_R1.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_17_R1.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/nmsutil/nmsutil-v1_17_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1_P1/NBTTagImpl.java b/nmsutil/nmsutil-v1_17_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1_P1/NBTTagImpl.java index 993f57fd..e805a9a1 100644 --- a/nmsutil/nmsutil-v1_17_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1_P1/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_17_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_17_R1_P1/NBTTagImpl.java @@ -15,7 +15,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_17_R1_P1.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_17_R1_P1.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_17_R1_P1.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_17_R1_P1.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/nmsutil/nmsutil-v1_18_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1/NBTTagImpl.java b/nmsutil/nmsutil-v1_18_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1/NBTTagImpl.java index e0725ff0..ae9e072e 100644 --- a/nmsutil/nmsutil-v1_18_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_18_R1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1/NBTTagImpl.java @@ -33,7 +33,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_18_R1.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_18_R1.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_18_R1.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_18_R1.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/nmsutil/nmsutil-v1_18_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1_P1/NBTTagImpl.java b/nmsutil/nmsutil-v1_18_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1_P1/NBTTagImpl.java index 13d02b10..61e26000 100644 --- a/nmsutil/nmsutil-v1_18_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1_P1/NBTTagImpl.java +++ b/nmsutil/nmsutil-v1_18_R1_P1/src/main/java/com/wolfyscript/utilities/bukkit/nms/api/v1_18_R1_P1/NBTTagImpl.java @@ -33,7 +33,6 @@ import com.wolfyscript.utilities.bukkit.nms.api.v1_18_R1_P1.nbt.NBTTagLongImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_18_R1_P1.nbt.NBTTagShortImpl; import com.wolfyscript.utilities.bukkit.nms.api.v1_18_R1_P1.nbt.NBTTagStringImpl; -import me.wolfyscript.utilities.api.nms.v1_18_R1_P1.nbt.*; public class NBTTagImpl extends NBTTag { diff --git a/pom.xml b/pom.xml index acf0f5e1..1435c2fc 100644 --- a/pom.xml +++ b/pom.xml @@ -45,7 +45,7 @@ 4.11.0 4.1.2 4.11.0 - 2.10.0 + 2.11.0 3.29.2-GA 5.9.0 4.8.0 @@ -123,9 +123,9 @@ - org.spigotmc - spigot-api - ${depend_version.spigotapi} + io.papermc.paper + paper-api + 1.18.2-R0.1-SNAPSHOT provided diff --git a/wolfyutils-spigot/src/main/resources/plugin.yml b/wolfyutils-spigot/src/main/resources/plugin.yml index 976cb778..778d3e38 100644 --- a/wolfyutils-spigot/src/main/resources/plugin.yml +++ b/wolfyutils-spigot/src/main/resources/plugin.yml @@ -56,6 +56,8 @@ commands: description: "DEBUG! Spawns a test particle effect on the target block." query_item: usage: "/query_item" + simple_bukkit_stack: + usage: "/simple_bukkit_stack" permissions: wolfyutilities.command.query_debug: default: op