From f261e3c7957cc70e600a9834476fe6bb635c73e0 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Sun, 16 Jun 2024 02:16:38 +0200 Subject: [PATCH 1/6] Start the implementation of a custom wrapper for enchantment. This will aim to allow to implement support for custom implementation of enchantment --- .../cuanvil/enchant/WrappedEnchantment.java | 139 ++++++++++++++++++ .../enchant/wrapped/VanillaEnchant.java | 30 ++++ src/main/kotlin/io/delilaheve/CustomAnvil.kt | 4 + 3 files changed, 173 insertions(+) create mode 100644 src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java create mode 100644 src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java new file mode 100644 index 0000000..51c5d79 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java @@ -0,0 +1,139 @@ +package xyz.alexcrea.cuanvil.enchant; + +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.alexcrea.cuanvil.enchant.wrapped.VanillaEnchant; + +import java.util.HashMap; + +public abstract class WrappedEnchantment { + + @NotNull + private final NamespacedKey key; + @NotNull + private final String name; + @NotNull + private final EnchantmentRarity defaultRarity; + + /** + * Constructor of Wrapped Enchantment. + * @param key the enchantment's key. + * @param name the enchantment's name. + * @param defaultRarity default rarity the enchantment should be. + */ + public WrappedEnchantment( + @NotNull NamespacedKey key, + @NotNull String name, + @Nullable EnchantmentRarity defaultRarity){ + this.key = key; + this.name = name; + + if(defaultRarity == null) this.defaultRarity = EnchantmentRarity.COMMON; + else this.defaultRarity = defaultRarity; + } + + /** + * Get the default rarity of this enchant. + * @return the default rarity of this enchant. + */ + public final EnchantmentRarity defaultRarity(){ + return defaultRarity; + } + + /** + * Get the enchantment key. + * @return the enchantment key. + */ + @NotNull + public final NamespacedKey getKey(){ + return key; + } + + /** + * Get the enchantment name. + * @return the enchantment name. + */ + @NotNull + public String getName() { + return name; + } + + /** + * Get the default maximum level of this enchantment. + * @return the default maximum level of this enchantment. + */ + public abstract int defaultMaxLevel(); + + + public abstract int enchantmentLevel(ItemStack item, ItemMeta meta); + + + + + // Static functions + private static HashMap BY_KEY; + //private static HashMap BY_NAME; //TODO decide if I should implement it. + + /** + * This should only be called on main of custom anvil. + * If called more than one time, chance of thing being broken will be high. + */ + public static void registerEnchantments(){ + BY_KEY = new HashMap<>(); + //BY_NAME = new HashMap<>(); + + for (Enchantment enchantment : Enchantment.values()) { + register(new VanillaEnchant(enchantment)); + } + + } + + /** + * Can be used to register new enchantment. + *

+ * No guarantee that the enchantment will be present on the config gui if registered late. + * (by late I mean after custom anvil startup.) + * @param enchantment the enchantment to register. + */ + public static void register(@NotNull WrappedEnchantment enchantment){ + BY_KEY.put(enchantment.getKey(), enchantment); + //BY_NAME.put(enchantment.getName(), enchantment); + } + + /** + * Can be used to unregister new enchantment. + * Please be cautious with this function. + * It should probably rarely be used. + *

+ * No guarantee that the enchantment will absent if the config guis if unregistered late. + * (by late I mean after custom anvil startup.) + * @param enchantment the enchantment to unregister. + */ + public static void unregister(@NotNull WrappedEnchantment enchantment){ + BY_KEY.remove(enchantment.getKey()); + //BY_NAME.remove(enchantment.getName()); + } + + /** + * Gets the enchantment by the provided key. + * @param key key to fetch. + * @return registered enchantment. null if absent. + */ + public static @Nullable WrappedEnchantment getByKey(@NotNull NamespacedKey key){ + return BY_KEY.get(key); + } + + /** + * Gets an array of all the registered enchantments. + * @return array of enchantment. + */ + @NotNull + public static WrappedEnchantment[] values() { + return BY_KEY.values().toArray(new WrappedEnchantment[BY_KEY.size()]); + } + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java new file mode 100644 index 0000000..2ca3ebe --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java @@ -0,0 +1,30 @@ +package xyz.alexcrea.cuanvil.enchant.wrapped; + +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; + +public class VanillaEnchant extends WrappedEnchantment { + + private final @NotNull Enchantment enchantment; + public VanillaEnchant(@NotNull Enchantment enchantment){ + super(enchantment.getKey(), + enchantment.getName(), + EnchantmentRarity.COMMON);//TODO determine rarity + this.enchantment = enchantment; + } + + @Override + public int defaultMaxLevel() { + return this.enchantment.getMaxLevel(); + } + + @Override + public int enchantmentLevel(ItemStack item, ItemMeta meta) { + throw new UnsupportedOperationException("Not yet implemented"); + } +} diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index ec0ed16..212b82e 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -7,6 +7,7 @@ import org.bukkit.plugin.java.JavaPlugin import xyz.alexcrea.cuanvil.command.EditConfigExecutor import xyz.alexcrea.cuanvil.command.ReloadExecutor import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment import xyz.alexcrea.cuanvil.gui.config.MainConfigGui import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant import xyz.alexcrea.cuanvil.listener.ChatEventListener @@ -93,6 +94,9 @@ class CustomAnvil : JavaPlugin() { logger.warning("Please note CustomAnvil is a more recent version of UnsafeEnchantsPlus") } + // Register enchantments + WrappedEnchantment.registerEnchantments(); + // Load ProtocolLib dependency if exist packetManager = if(pluginManager.isPluginEnabled("ProtocolLib")) { ProtocoLibWrapper(); } From 9f74c2cfffdc92136cbb69d1561cef02932111b5 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Sun, 16 Jun 2024 03:42:33 +0200 Subject: [PATCH 2/6] Implemented multiples methods for enchantment wrapper. --- .../cuanvil/enchant/WrappedEnchantment.java | 96 +++++++++++++++---- .../enchant/wrapped/VanillaEnchant.java | 51 +++++++++- src/main/kotlin/io/delilaheve/CustomAnvil.kt | 2 +- 3 files changed, 129 insertions(+), 20 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java index 51c5d79..e5456d3 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable; import xyz.alexcrea.cuanvil.enchant.wrapped.VanillaEnchant; import java.util.HashMap; +import java.util.Map; public abstract class WrappedEnchantment { @@ -21,9 +22,9 @@ public abstract class WrappedEnchantment { /** * Constructor of Wrapped Enchantment. - * @param key the enchantment's key. - * @param name the enchantment's name. - * @param defaultRarity default rarity the enchantment should be. + * @param key The enchantment's key. + * @param name The enchantment's name. + * @param defaultRarity Default rarity the enchantment should be. */ public WrappedEnchantment( @NotNull NamespacedKey key, @@ -38,7 +39,7 @@ public abstract class WrappedEnchantment { /** * Get the default rarity of this enchant. - * @return the default rarity of this enchant. + * @return The default rarity of this enchant. */ public final EnchantmentRarity defaultRarity(){ return defaultRarity; @@ -46,7 +47,7 @@ public abstract class WrappedEnchantment { /** * Get the enchantment key. - * @return the enchantment key. + * @return The enchantment key. */ @NotNull public final NamespacedKey getKey(){ @@ -55,7 +56,7 @@ public abstract class WrappedEnchantment { /** * Get the enchantment name. - * @return the enchantment name. + * @return The enchantment name. */ @NotNull public String getName() { @@ -64,17 +65,80 @@ public abstract class WrappedEnchantment { /** * Get the default maximum level of this enchantment. - * @return the default maximum level of this enchantment. + * @return The default maximum level of this enchantment. */ public abstract int defaultMaxLevel(); + // TODO maybe methods that do not require itemmeta ? - public abstract int enchantmentLevel(ItemStack item, ItemMeta meta); + /** + * Get current level of the enchantment. + * @param item Item to search the level for. + * @param meta Meta of the provided item. It will not be changed and not be set on the item. + * @return Current leve of this enchantment on item. or 0 if absent. + */ + public abstract int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta); + /** + * Check if this enchantment is present on the provided level. + * @param item The item to set the enchantment level. + * @param meta Meta of the provided item. It will not be changed and not be set on the item. + * @return If the enchantment have been found. + */ + public abstract boolean isEnchantmentPresent(@NotNull ItemStack item, @NotNull ItemMeta meta); + /** + * Force add an enchantment at the provided level. + * @param item The item to set the enchantment level. + * @param meta Meta of the provided item. It can be changed, but will not be set on the item. + * @param level The level to set the enchantment to. + */ + public abstract void addEnchantmentUnsafe(@NotNull ItemStack item, @NotNull ItemMeta meta, int level); + /** + * Remove this enchantment from the provided ItemStack. + * @param item The item to remove the enchantment. + * @param meta Meta of the provided item. It can be changed, but will not be set on the item. + */ + public abstract void removeFrom(@NotNull ItemStack item, @NotNull ItemMeta meta); // Static functions + + /** + * Clear every enchantment from this item. + * @param item Item to be cleared from enchantments. + */ + public static void clearEnchants(@NotNull ItemStack item){ //TODO faster method to clear vanilla enchantment + ItemMeta meta = item.getItemMeta(); + if(meta == null) return; + + for (WrappedEnchantment enchant : getEnchants(item).keySet()) { + enchant.removeFrom(item, meta); + } + item.setItemMeta(meta); + } + + /** + * Get enchantments of an item. + * @param item item to get enchantment from. + * @return a map of the set enchantments and there's respective levels. + */ + public static Map getEnchants(@NotNull ItemStack item){ //TODO faster method to find vanilla enchantment + Map enchantments = new HashMap<>(); + + ItemMeta meta = item.getItemMeta(); + if(meta == null) return enchantments; + + for (WrappedEnchantment enchantment : WrappedEnchantment.values()) { + if(enchantment.isEnchantmentPresent(item, meta)){ + enchantments.put(enchantment, enchantment.getLevel(item, meta)); + } + } + + return enchantments; + } + + // Register enchantment functions private static HashMap BY_KEY; //private static HashMap BY_NAME; //TODO decide if I should implement it. @@ -96,8 +160,8 @@ public abstract class WrappedEnchantment { * Can be used to register new enchantment. *

* No guarantee that the enchantment will be present on the config gui if registered late. - * (by late I mean after custom anvil startup.) - * @param enchantment the enchantment to register. + * (By late I mean after custom anvil startup.) + * @param enchantment The enchantment to be registered. */ public static void register(@NotNull WrappedEnchantment enchantment){ BY_KEY.put(enchantment.getKey(), enchantment); @@ -110,8 +174,8 @@ public abstract class WrappedEnchantment { * It should probably rarely be used. *

* No guarantee that the enchantment will absent if the config guis if unregistered late. - * (by late I mean after custom anvil startup.) - * @param enchantment the enchantment to unregister. + * (By late I mean after custom anvil startup.) + * @param enchantment The enchantment to be unregistered. */ public static void unregister(@NotNull WrappedEnchantment enchantment){ BY_KEY.remove(enchantment.getKey()); @@ -120,8 +184,8 @@ public abstract class WrappedEnchantment { /** * Gets the enchantment by the provided key. - * @param key key to fetch. - * @return registered enchantment. null if absent. + * @param key Key to fetch. + * @return Registered enchantment. null if absent. */ public static @Nullable WrappedEnchantment getByKey(@NotNull NamespacedKey key){ return BY_KEY.get(key); @@ -129,11 +193,11 @@ public abstract class WrappedEnchantment { /** * Gets an array of all the registered enchantments. - * @return array of enchantment. + * @return Array of enchantment. */ @NotNull public static WrappedEnchantment[] values() { - return BY_KEY.values().toArray(new WrappedEnchantment[BY_KEY.size()]); + return BY_KEY.values().toArray(new WrappedEnchantment[0]); } } diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java index 2ca3ebe..c0db2f7 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java @@ -1,8 +1,10 @@ package xyz.alexcrea.cuanvil.enchant.wrapped; -import org.bukkit.NamespacedKey; +import io.delilaheve.util.ItemUtil; +import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; @@ -24,7 +26,50 @@ public class VanillaEnchant extends WrappedEnchantment { } @Override - public int enchantmentLevel(ItemStack item, ItemMeta meta) { - throw new UnsupportedOperationException("Not yet implemented"); + public int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta) { + if (isEnchantedBook(item)) { + return ((EnchantmentStorageMeta)meta).getStoredEnchantLevel(this.enchantment); + } else { + return meta.getEnchantLevel(this.enchantment); + } } + + @Override + public boolean isEnchantmentPresent(@NotNull ItemStack item, @NotNull ItemMeta meta) { + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { + EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)meta); + + return bookMeta.getStoredEnchants().containsKey(this.enchantment); + }else{ + return item.containsEnchantment(this.enchantment); + } + } + + @Override + public void addEnchantmentUnsafe(@NotNull ItemStack item, @NotNull ItemMeta meta, int level) { + if (isEnchantedBook(item)) { + EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)meta); + + bookMeta.addStoredEnchant(this.enchantment, level, true); + } else { + item.addUnsafeEnchantment(this.enchantment, level); + } + + } + + @Override + public void removeFrom(@NotNull ItemStack item, @NotNull ItemMeta meta) { + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { + EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)meta); + + bookMeta.removeStoredEnchant(this.enchantment); + } + item.removeEnchantment(this.enchantment); + + } + + public static boolean isEnchantedBook(@NotNull ItemStack item){ + return Material.ENCHANTED_BOOK.equals(item.getType()); + } + } diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index 212b82e..7d3503a 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -95,7 +95,7 @@ class CustomAnvil : JavaPlugin() { } // Register enchantments - WrappedEnchantment.registerEnchantments(); + WrappedEnchantment.registerEnchantments() // Load ProtocolLib dependency if exist packetManager = if(pluginManager.isPluginEnabled("ProtocolLib")) From 1eac81aef66bcbee22b25f9c567e5f93cfdf86ea Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Sun, 16 Jun 2024 03:58:18 +0200 Subject: [PATCH 3/6] Attempt to switch from Enchantment to WrapperEnchantment --- .../config/SelectEnchantmentContainer.java | 8 ++-- .../global/AbstractEnchantConfigGui.java | 6 +-- .../config/global/EnchantCostConfigGui.java | 4 +- .../config/global/EnchantLimitConfigGui.java | 6 +-- .../EnchantConflictSubSettingGui.java | 16 +++---- .../settings/EnchantSelectSettingGui.java | 13 +++--- .../cuanvil/gui/util/GuiSharedConstant.java | 6 +-- .../io/delilaheve/util/ConfigOptions.kt | 24 ++-------- .../io/delilaheve/util/EnchantmentUtil.kt | 10 ++--- .../kotlin/io/delilaheve/util/ItemUtil.kt | 45 +++++-------------- .../cuanvil/group/EnchantConflictGroup.kt | 12 ++--- .../cuanvil/group/EnchantConflictManager.kt | 17 +++---- 12 files changed, 63 insertions(+), 104 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/SelectEnchantmentContainer.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/SelectEnchantmentContainer.java index ee6ce77..95bf586 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/SelectEnchantmentContainer.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/SelectEnchantmentContainer.java @@ -1,15 +1,15 @@ package xyz.alexcrea.cuanvil.gui.config; -import org.bukkit.enchantments.Enchantment; +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import java.util.Set; public interface SelectEnchantmentContainer { - Set getSelectedEnchantments(); + Set getSelectedEnchantments(); - boolean setSelectedEnchantments(Set enchantments); + boolean setSelectedEnchantments(Set enchantments); - Set illegalEnchantments(); + Set illegalEnchantments(); } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java index 7c6d31e..4bbd48a 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/AbstractEnchantConfigGui.java @@ -4,7 +4,7 @@ import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.pane.Orientable; import com.github.stefvanschie.inventoryframework.pane.OutlinePane; import io.delilaheve.CustomAnvil; -import org.bukkit.enchantments.Enchantment; +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.config.settings.AbstractSettingGui; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; @@ -55,7 +55,7 @@ public abstract class AbstractEnchantConfigGui(); - for (Enchantment enchant : GuiSharedConstant.SORTED_ENCHANTMENT_LIST) { + for (WrappedEnchantment enchant : GuiSharedConstant.SORTED_ENCHANTMENT_LIST) { T factory = getFactoryFromEnchant(enchant); bookItemFactoryList.add(factory); @@ -80,7 +80,7 @@ public abstract class AbstractEnchantConfigGui enchantLore = new ArrayList<>(); enchantLore.add("\u00A77Allow you to select a list of \u00A75Enchantments \u00A77that this conflict should include"); - Set enchants = getSelectedEnchantments(); + Set enchants = getSelectedEnchantments(); if (enchants.isEmpty()) { enchantLore.add("\u00A77There is no included enchantment for this conflict."); } else { enchantLore.add("\u00A77List of included enchantment for this conflict:"); - Iterator enchantIterator = enchants.iterator(); + Iterator enchantIterator = enchants.iterator(); boolean greaterThanMax = enchants.size() > 5; int maxindex = (greaterThanMax ? 4 : enchants.size()); @@ -243,12 +243,12 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl // Select enchantment container methods @Override - public Set getSelectedEnchantments() { + public Set getSelectedEnchantments() { return this.enchantConflict.getEnchants(); } @Override - public boolean setSelectedEnchantments(Set enchantments) { + public boolean setSelectedEnchantments(Set enchantments) { if (!this.shouldWork) { CustomAnvil.instance.getLogger().info("Trying to save " + enchantConflict + " enchants but sub config is destroyed"); return false; @@ -260,7 +260,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl // Save on file configuration String[] enchantKeys = new String[enchantments.size()]; int index = 0; - for (Enchantment enchantment : enchantments) { + for (WrappedEnchantment enchantment : enchantments) { enchantKeys[index++] = enchantment.getKey().getKey(); } ConfigHolder.CONFLICT_HOLDER.getConfig().set(enchantConflict + ".enchantments", enchantKeys); @@ -280,7 +280,7 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl } @Override - public Set illegalEnchantments() { + public Set illegalEnchantments() { return Collections.emptySet(); } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantSelectSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantSelectSettingGui.java index f4d3337..6eeef37 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantSelectSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/settings/EnchantSelectSettingGui.java @@ -13,6 +13,7 @@ import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.config.SelectEnchantmentContainer; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; @@ -29,7 +30,7 @@ public class EnchantSelectSettingGui extends AbstractSettingGui { SelectEnchantmentContainer enchantContainer; int page; - Set selectedEnchant; + Set selectedEnchant; public EnchantSelectSettingGui(@NotNull String title, ValueUpdatableGui parent, SelectEnchantmentContainer enchantContainer, int page) { super(6, title, parent); @@ -64,8 +65,8 @@ public class EnchantSelectSettingGui extends AbstractSettingGui { filledEnchant.align(OutlinePane.Alignment.BEGIN); filledEnchant.setOrientation(Orientable.Orientation.HORIZONTAL); - Set illegalEnchant = this.enchantContainer.illegalEnchantments(); - for (Enchantment enchant : GuiSharedConstant.SORTED_ENCHANTMENT_LIST) { + Set illegalEnchant = this.enchantContainer.illegalEnchantments(); + for (WrappedEnchantment enchant : GuiSharedConstant.SORTED_ENCHANTMENT_LIST) { if (illegalEnchant.contains(enchant)) { return; } @@ -76,7 +77,7 @@ public class EnchantSelectSettingGui extends AbstractSettingGui { } - private GuiItem getGuiItemFromEnchant(Enchantment enchantment) { + private GuiItem getGuiItemFromEnchant(WrappedEnchantment enchantment) { boolean isIn = this.selectedEnchant.contains(enchantment); Material usedMaterial; @@ -122,7 +123,7 @@ public class EnchantSelectSettingGui extends AbstractSettingGui { item.setItemMeta(meta); } - private Consumer getEnchantItemConsumer(Enchantment enchant, GuiItem guiItem) { + private Consumer getEnchantItemConsumer(WrappedEnchantment enchant, GuiItem guiItem) { return event -> { event.setCancelled(true); @@ -151,7 +152,7 @@ public class EnchantSelectSettingGui extends AbstractSettingGui { @Override public boolean hadChange() { - Set baseGroup = this.enchantContainer.getSelectedEnchantments(); + Set baseGroup = this.enchantContainer.getSelectedEnchantments(); return baseGroup.size() != this.selectedEnchant.size() || !baseGroup.containsAll(this.selectedEnchant); } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java index d8bebca..1c33af2 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/util/GuiSharedConstant.java @@ -5,9 +5,9 @@ import com.github.stefvanschie.inventoryframework.pane.Pane; import com.github.stefvanschie.inventoryframework.pane.PatternPane; import com.github.stefvanschie.inventoryframework.pane.util.Pattern; import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import xyz.alexcrea.cuanvil.gui.config.MainConfigGui; import java.util.Arrays; @@ -17,10 +17,10 @@ import java.util.List; public class GuiSharedConstant { - public static final List SORTED_ENCHANTMENT_LIST; + public static final List SORTED_ENCHANTMENT_LIST; static { - SORTED_ENCHANTMENT_LIST = Arrays.asList(Enchantment.values()); + SORTED_ENCHANTMENT_LIST = Arrays.asList(WrappedEnchantment.values()); SORTED_ENCHANTMENT_LIST.sort(Comparator.comparing(ench -> ench.getKey().getKey())); } diff --git a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt index 2ee3749..0fefdf2 100644 --- a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt +++ b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt @@ -2,8 +2,8 @@ package io.delilaheve.util import io.delilaheve.CustomAnvil import io.delilaheve.util.EnchantmentUtil.enchantmentName -import org.bukkit.enchantments.Enchantment import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment /** * Config option accessors @@ -239,7 +239,7 @@ object ConfigOptions { /** * Get the given [enchantment]'s limit */ - fun enchantLimit(enchantment: Enchantment): Int { + fun enchantLimit(enchantment: WrappedEnchantment): Int { return enchantLimit(enchantment.enchantmentName) } @@ -273,7 +273,7 @@ object ConfigOptions { * it's source [isFromBook] */ fun enchantmentValue( - enchantment: Enchantment, + enchantment: WrappedEnchantment, isFromBook: Boolean ): Int { return enchantmentValue(enchantment.enchantmentName, isFromBook) @@ -309,22 +309,4 @@ object ConfigOptions { return DEFAULT_ENCHANT_VALUE } - /** - * Get an array of key of basic config options - */ - fun getBasicConfigKeys(): Array { - return arrayOf( - DEFAULT_LIMIT_PATH, - CAP_ANVIL_COST, - MAX_ANVIL_COST, - REPLACE_TOO_EXPENSIVE, - ITEM_REPAIR_COST, - UNIT_REPAIR_COST, - ITEM_RENAME_COST, - SACRIFICE_ILLEGAL_COST, - REMOVE_ANVIL_COST_LIMIT - ) - } - - } diff --git a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt index 0f1639c..9d3f95a 100644 --- a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt @@ -2,9 +2,9 @@ package io.delilaheve.util import io.delilaheve.CustomAnvil import org.bukkit.Material -import org.bukkit.enchantments.Enchantment import org.bukkit.entity.HumanEntity import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment import xyz.alexcrea.cuanvil.group.ConflictType import kotlin.math.max import kotlin.math.min @@ -17,17 +17,17 @@ object EnchantmentUtil { /** * Enchantment name without namespace */ - val Enchantment.enchantmentName: String + val WrappedEnchantment.enchantmentName: String get() = key.key /** * Combine 2 sets of enchantments according to our configuration */ - fun Map.combineWith( - other: Map, + fun Map.combineWith( + other: Map, mat: Material, player: HumanEntity - ) = mutableMapOf().apply { + ) = mutableMapOf().apply { putAll(this@combineWith) other.forEach { (enchantment, level) -> // Get max level or 255 if player can bypass diff --git a/src/main/kotlin/io/delilaheve/util/ItemUtil.kt b/src/main/kotlin/io/delilaheve/util/ItemUtil.kt index 7eed593..9d7d899 100644 --- a/src/main/kotlin/io/delilaheve/util/ItemUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/ItemUtil.kt @@ -1,11 +1,9 @@ package io.delilaheve.util -import io.delilaheve.CustomAnvil import org.bukkit.Material.ENCHANTED_BOOK -import org.bukkit.enchantments.Enchantment import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.Damageable -import org.bukkit.inventory.meta.EnchantmentStorageMeta +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment import kotlin.math.ceil import kotlin.math.max import kotlin.math.min @@ -23,44 +21,21 @@ object ItemUtil { /** * Find the enchantment map for this [ItemStack] and return it as a [MutableMap] */ - fun ItemStack.findEnchantments() = if (isEnchantedBook()) { - (itemMeta as? EnchantmentStorageMeta)?.storedEnchants ?: emptyMap() - } else { - itemMeta?.enchants ?: emptyMap() - } + fun ItemStack.findEnchantments(): MutableMap = WrappedEnchantment.getEnchants(this) /** * Apply an [enchantments] map to this [ItemStack] */ - fun ItemStack.setEnchantmentsUnsafe(enchantments: Map) { - if (isEnchantedBook()) { - /* For some god-forsaken reason, item meta is not mutable - * so, we have to get the instance, modify it, then set it - * back to the item... #BecauseMinecraft */ - val bookMeta = (itemMeta as? EnchantmentStorageMeta) - bookMeta?.replaceEnchants(enchantments) - itemMeta = bookMeta - } else { - itemMeta?.enchants?.forEach { (enchant, _) -> - removeEnchantment(enchant) - } - addUnsafeEnchantments(enchantments) - } - } + fun ItemStack.setEnchantmentsUnsafe(enchantments: Map) { + WrappedEnchantment.clearEnchants(this) - /** - * Apply an [enchantments] map to this book - */ - private fun EnchantmentStorageMeta.replaceEnchants( - enchantments: Map - ) { - storedEnchants.forEach { (enchant, _) -> - removeStoredEnchant(enchant) - } - enchantments.forEach { (enchant, level) -> - val added = addStoredEnchant(enchant, level, true) - CustomAnvil.log("${enchant.key} added to item? $added") + val meta = this.itemMeta ?: return + + enchantments.forEach { (enchantment, level) -> + enchantment.addEnchantmentUnsafe(this, meta, level) } + + this.itemMeta = meta } /** diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt index 76a07d8..edd98f3 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt @@ -2,7 +2,7 @@ package xyz.alexcrea.cuanvil.group import io.delilaheve.CustomAnvil import org.bukkit.Material -import org.bukkit.enchantments.Enchantment +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment class EnchantConflictGroup( private val name: String, @@ -10,13 +10,13 @@ class EnchantConflictGroup( var minBeforeBlock: Int ) { - private val enchantments = HashSet() + private val enchantments = HashSet() - fun addEnchantment(enchant: Enchantment) { + fun addEnchantment(enchant: WrappedEnchantment) { enchantments.add(enchant) } - fun allowed(enchants: Set, mat: Material): Boolean { + fun allowed(enchants: Set, mat: Material): Boolean { if (enchantments.size < minBeforeBlock) { return true } @@ -42,11 +42,11 @@ class EnchantConflictGroup( return this.cantConflict } - fun getEnchants(): HashSet { + fun getEnchants(): HashSet { return enchantments } - fun setEnchants(enchants: Set) { + fun setEnchants(enchants: Set) { enchantments.clear() enchantments.addAll(enchants) } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt index e295396..06260bf 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt @@ -5,6 +5,7 @@ import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.configuration.ConfigurationSection import org.bukkit.enchantments.Enchantment +import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment class EnchantConflictManager { @@ -27,12 +28,12 @@ class EnchantConflictManager { // 1.20.5 compatibility TODO better update system private val SWEEPING_EDGE_ENCHANT = - Enchantment.getByKey(NamespacedKey.minecraft("sweeping_edge")) ?: - Enchantment.SWEEPING_EDGE + WrappedEnchantment.getByKey(NamespacedKey.minecraft("sweeping_edge")) ?: + WrappedEnchantment.getByKey(Enchantment.SWEEPING_EDGE.key) } - private lateinit var conflictMap: HashMap> + private lateinit var conflictMap: HashMap> lateinit var conflictList: ArrayList // Read and prepare all conflict @@ -58,14 +59,14 @@ class EnchantConflictManager { } } - fun addConflictToConflictMap(enchant: Enchantment, conflict: EnchantConflictGroup) { + fun addConflictToConflictMap(enchant: WrappedEnchantment, conflict: EnchantConflictGroup) { if (!conflictMap.containsKey(enchant)) { conflictMap[enchant] = ArrayList() } conflictMap[enchant]!!.add(conflict) } - fun removeConflictFromMap(enchant: Enchantment, conflict: EnchantConflictGroup): Boolean { + fun removeConflictFromMap(enchant: WrappedEnchantment, conflict: EnchantConflictGroup): Boolean { return conflictMap[enchant]!!.remove(conflict) } @@ -100,7 +101,7 @@ class EnchantConflictManager { return conflict } - private fun getEnchantByName(enchantName: String): Enchantment? { + private fun getEnchantByName(enchantName: String): WrappedEnchantment? { // Temporary solution for 1.20.5 when(enchantName){ @@ -110,7 +111,7 @@ class EnchantConflictManager { } val enchantKey = NamespacedKey.minecraft(enchantName) - return Enchantment.getByKey(enchantKey) + return WrappedEnchantment.getByKey(enchantKey) } @@ -151,7 +152,7 @@ class EnchantConflictManager { return group } - fun isConflicting(base: Set, mat: Material, newEnchant: Enchantment): ConflictType { + fun isConflicting(base: Set, mat: Material, newEnchant: WrappedEnchantment): ConflictType { CustomAnvil.verboseLog("Testing conflict for ${newEnchant.key} on ${mat.key}") val conflictList = conflictMap[newEnchant] ?: return ConflictType.NO_CONFLICT CustomAnvil.verboseLog("Did not get skipped") From c7fee98d44c11a3077c5b728db6ddfdd4b496ce8 Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Sun, 16 Jun 2024 04:55:23 +0200 Subject: [PATCH 4/6] Fixed strange issue related to item meta. Added more verbose debug log. --- .../cuanvil/enchant/WrappedEnchantment.java | 13 ++++--------- .../cuanvil/enchant/wrapped/VanillaEnchant.java | 15 ++++++++++----- .../kotlin/io/delilaheve/AnvilEventListener.kt | 1 + src/main/kotlin/io/delilaheve/util/ItemUtil.kt | 6 ++---- .../cuanvil/group/EnchantConflictGroup.kt | 2 ++ .../cuanvil/group/EnchantConflictManager.kt | 7 ++++--- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java index e5456d3..7ec3be6 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java @@ -90,17 +90,15 @@ public abstract class WrappedEnchantment { /** * Force add an enchantment at the provided level. * @param item The item to set the enchantment level. - * @param meta Meta of the provided item. It can be changed, but will not be set on the item. * @param level The level to set the enchantment to. */ - public abstract void addEnchantmentUnsafe(@NotNull ItemStack item, @NotNull ItemMeta meta, int level); + public abstract void addEnchantmentUnsafe(@NotNull ItemStack item, int level); /** * Remove this enchantment from the provided ItemStack. * @param item The item to remove the enchantment. - * @param meta Meta of the provided item. It can be changed, but will not be set on the item. */ - public abstract void removeFrom(@NotNull ItemStack item, @NotNull ItemMeta meta); + public abstract void removeFrom(@NotNull ItemStack item); // Static functions @@ -109,13 +107,10 @@ public abstract class WrappedEnchantment { * @param item Item to be cleared from enchantments. */ public static void clearEnchants(@NotNull ItemStack item){ //TODO faster method to clear vanilla enchantment - ItemMeta meta = item.getItemMeta(); - if(meta == null) return; - for (WrappedEnchantment enchant : getEnchants(item).keySet()) { - enchant.removeFrom(item, meta); + enchant.removeFrom(item); } - item.setItemMeta(meta); + } /** diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java index c0db2f7..cfbde00 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java @@ -46,11 +46,13 @@ public class VanillaEnchant extends WrappedEnchantment { } @Override - public void addEnchantmentUnsafe(@NotNull ItemStack item, @NotNull ItemMeta meta, int level) { + public void addEnchantmentUnsafe(@NotNull ItemStack item, int level) { if (isEnchantedBook(item)) { - EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)meta); + EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)item.getItemMeta()); + assert bookMeta != null; bookMeta.addStoredEnchant(this.enchantment, level, true); + item.setItemMeta(bookMeta); } else { item.addUnsafeEnchantment(this.enchantment, level); } @@ -58,13 +60,16 @@ public class VanillaEnchant extends WrappedEnchantment { } @Override - public void removeFrom(@NotNull ItemStack item, @NotNull ItemMeta meta) { + public void removeFrom(@NotNull ItemStack item) { if (ItemUtil.INSTANCE.isEnchantedBook(item)) { - EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)meta); + EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)item.getItemMeta()); + assert bookMeta != null; bookMeta.removeStoredEnchant(this.enchantment); + item.setItemMeta(bookMeta); + }else{ + item.removeEnchantment(this.enchantment); } - item.removeEnchantment(this.enchantment); } diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index 53fedd0..ead5a1a 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -452,6 +452,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { if (ConflictType.BIG_CONFLICT == conflictType) { illegalPenalty += ConfigOptions.sacrificeIllegalCost + CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty") } continue } diff --git a/src/main/kotlin/io/delilaheve/util/ItemUtil.kt b/src/main/kotlin/io/delilaheve/util/ItemUtil.kt index 9d7d899..6c627ba 100644 --- a/src/main/kotlin/io/delilaheve/util/ItemUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/ItemUtil.kt @@ -29,13 +29,11 @@ object ItemUtil { fun ItemStack.setEnchantmentsUnsafe(enchantments: Map) { WrappedEnchantment.clearEnchants(this) - val meta = this.itemMeta ?: return - + //TODO maybe faster methode to add vanilla enchantment. maybe move this function to wrapped enchantment enchantments.forEach { (enchantment, level) -> - enchantment.addEnchantmentUnsafe(this, meta, level) + enchantment.addEnchantmentUnsafe(this, level) } - this.itemMeta = meta } /** diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt index edd98f3..2885237 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt @@ -18,6 +18,7 @@ class EnchantConflictGroup( fun allowed(enchants: Set, mat: Material): Boolean { if (enchantments.size < minBeforeBlock) { + CustomAnvil.verboseLog("Conflicting bc of to many enchantments") return true } @@ -31,6 +32,7 @@ class EnchantConflictGroup( if (enchantment !in enchantments) continue CustomAnvil.verboseLog("Enchant ${enchantment.key} is in: ${enchantAmount + 1}/$minBeforeBlock ") if (++enchantAmount > minBeforeBlock) { + CustomAnvil.verboseLog("it is not allowed bc of to many enchantment in conflict") return false } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt index 06260bf..ae3c59d 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt @@ -160,13 +160,14 @@ class EnchantConflictManager { var result = ConflictType.NO_CONFLICT for (conflict in conflictList) { CustomAnvil.verboseLog("Is against $conflict") - val conflicting = conflict.allowed(base, mat) - CustomAnvil.verboseLog("Was against $conflict and conflicting: $conflicting ") - if (!conflicting) { + val allowed = conflict.allowed(base, mat) + CustomAnvil.verboseLog("Was against $conflict and conflicting: ${!allowed} ") + if (!allowed) { if (conflict.getEnchants().size <= 1) { result = ConflictType.SMALL_CONFLICT CustomAnvil.verboseLog("Small conflict, continuing") } else { + CustomAnvil.verboseLog("Big conflict, probably stoping") return ConflictType.BIG_CONFLICT } } From 27e8fb57193309b200e651844d8a494882b8e37b Mon Sep 17 00:00:00 2001 From: alexcrea <42614139+alexcrea@users.noreply.github.com> Date: Sun, 16 Jun 2024 10:16:52 +0200 Subject: [PATCH 5/6] Cleaning up and add name map. --- .../cuanvil/enchant/WrappedEnchantment.java | 74 +++++++++++++++---- .../enchant/wrapped/VanillaEnchant.java | 19 +++-- .../config/global/EnchantCostConfigGui.java | 2 +- .../cuanvil/group/EnchantConflictManager.kt | 3 +- 4 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java index 7ec3be6..146f6db 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java @@ -1,5 +1,6 @@ package xyz.alexcrea.cuanvil.enchant; +import io.delilaheve.CustomAnvil; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; @@ -10,7 +11,12 @@ import xyz.alexcrea.cuanvil.enchant.wrapped.VanillaEnchant; import java.util.HashMap; import java.util.Map; +import java.util.logging.Level; +/** + * Represent any enchantment. + * One issue with the plugin is: it does not handle well duplicate key name (ignoring namespace) as the plugin was coded with vanilla enchantment in head + */ public abstract class WrappedEnchantment { @NotNull @@ -19,19 +25,21 @@ public abstract class WrappedEnchantment { private final String name; @NotNull private final EnchantmentRarity defaultRarity; + private final int defaultMaxLevel; /** * Constructor of Wrapped Enchantment. * @param key The enchantment's key. - * @param name The enchantment's name. * @param defaultRarity Default rarity the enchantment should be. + * @param defaultMaxLevel Default max level the enchantment can be applied with. */ public WrappedEnchantment( @NotNull NamespacedKey key, - @NotNull String name, - @Nullable EnchantmentRarity defaultRarity){ + @Nullable EnchantmentRarity defaultRarity, + int defaultMaxLevel){ this.key = key; - this.name = name; + this.name = key.getKey(); + this.defaultMaxLevel = defaultMaxLevel; if(defaultRarity == null) this.defaultRarity = EnchantmentRarity.COMMON; else this.defaultRarity = defaultRarity; @@ -59,7 +67,7 @@ public abstract class WrappedEnchantment { * @return The enchantment name. */ @NotNull - public String getName() { + public final String getName(){ return name; } @@ -67,9 +75,17 @@ public abstract class WrappedEnchantment { * Get the default maximum level of this enchantment. * @return The default maximum level of this enchantment. */ - public abstract int defaultMaxLevel(); + public final int defaultMaxLevel(){return defaultMaxLevel;} - // TODO maybe methods that do not require itemmeta ? + /** + * Get current level of the enchantment. + * @param item Item to search the level for. + */ + public int getLevel(@NotNull ItemStack item){ + ItemMeta meta = item.getItemMeta(); + if(meta == null) return 0; + return getLevel(item, meta); + } /** * Get current level of the enchantment. @@ -79,6 +95,17 @@ public abstract class WrappedEnchantment { */ public abstract int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta); + /** + * Check if this enchantment is present on the provided level. + * @param item The item to set the enchantment level. + * @return If the enchantment have been found. + */ + public boolean isEnchantmentPresent(@NotNull ItemStack item){ + ItemMeta meta = item.getItemMeta(); + if(meta == null) return false; + return isEnchantmentPresent(item, meta); + } + /** * Check if this enchantment is present on the provided level. * @param item The item to set the enchantment level. @@ -134,17 +161,14 @@ public abstract class WrappedEnchantment { } // Register enchantment functions - private static HashMap BY_KEY; - //private static HashMap BY_NAME; //TODO decide if I should implement it. + private static final HashMap BY_KEY = new HashMap<>(); + private static final HashMap BY_NAME = new HashMap<>(); /** * This should only be called on main of custom anvil. * If called more than one time, chance of thing being broken will be high. */ public static void registerEnchantments(){ - BY_KEY = new HashMap<>(); - //BY_NAME = new HashMap<>(); - for (Enchantment enchantment : Enchantment.values()) { register(new VanillaEnchant(enchantment)); } @@ -159,8 +183,21 @@ public abstract class WrappedEnchantment { * @param enchantment The enchantment to be registered. */ public static void register(@NotNull WrappedEnchantment enchantment){ + if(BY_KEY.containsKey(enchantment.getKey())){ + CustomAnvil.instance.getLogger().log(Level.WARNING, + "Duplicate registered enchantment. This should NOT happen.", + new IllegalStateException(enchantment.getKey()+" enchantment was already registered")); + return; + } + if(BY_NAME.containsKey(enchantment.getName())){ + CustomAnvil.instance.getLogger().log(Level.WARNING, + "Duplicate registered enchantment name. There will have issue. " + + "\nI hope this do not happen to you on a production server. If it do, there is probably a plugin trying to register an enchantment with the same name than another one", + new IllegalStateException(enchantment.getKey()+" enchantment name was already registered")); + } + BY_KEY.put(enchantment.getKey(), enchantment); - //BY_NAME.put(enchantment.getName(), enchantment); + BY_NAME.put(enchantment.getName(), enchantment); } /** @@ -174,7 +211,7 @@ public abstract class WrappedEnchantment { */ public static void unregister(@NotNull WrappedEnchantment enchantment){ BY_KEY.remove(enchantment.getKey()); - //BY_NAME.remove(enchantment.getName()); + BY_NAME.remove(enchantment.getName()); } /** @@ -186,6 +223,15 @@ public abstract class WrappedEnchantment { return BY_KEY.get(key); } + /** + * Gets the enchantment by the provided name. + * @param name Name to fetch. + * @return Registered enchantment. null if absent. + */ + public static @Nullable WrappedEnchantment getByName(@NotNull String name){ + return BY_NAME.get(name); + } + /** * Gets an array of all the registered enchantments. * @return Array of enchantment. diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java index cfbde00..5bfd436 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java @@ -7,22 +7,22 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; +import java.util.Locale; + public class VanillaEnchant extends WrappedEnchantment { private final @NotNull Enchantment enchantment; + public VanillaEnchant(@NotNull Enchantment enchantment){ super(enchantment.getKey(), - enchantment.getName(), - EnchantmentRarity.COMMON);//TODO determine rarity + getRarity(enchantment), + enchantment.getMaxLevel()); this.enchantment = enchantment; - } - @Override - public int defaultMaxLevel() { - return this.enchantment.getMaxLevel(); } @Override @@ -77,4 +77,11 @@ public class VanillaEnchant extends WrappedEnchantment { return Material.ENCHANTED_BOOK.equals(item.getType()); } + public static EnchantmentRarity getRarity(Enchantment enchantment){ + try {return EnchantmentProperties.valueOf(enchantment.getKey().getKey().toUpperCase(Locale.ENGLISH)).getRarity();} + catch (IllegalArgumentException ignored) {} + + return EnchantmentRarity.COMMON; + } + } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java index a07a5d4..928b795 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantCostConfigGui.java @@ -44,7 +44,7 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui Date: Sun, 16 Jun 2024 10:44:24 +0200 Subject: [PATCH 6/6] Add optimisation for vanilla enchantment. --- .../cuanvil/enchant/WrappedEnchantment.java | 90 +++++++++++++++++-- .../enchant/wrapped/VanillaEnchant.java | 14 +-- 2 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java index 146f6db..efe277c 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java @@ -1,16 +1,17 @@ package xyz.alexcrea.cuanvil.enchant; import io.delilaheve.CustomAnvil; +import io.delilaheve.util.ItemUtil; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xyz.alexcrea.cuanvil.enchant.wrapped.VanillaEnchant; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import java.util.logging.Level; /** @@ -77,6 +78,14 @@ public abstract class WrappedEnchantment { */ public final int defaultMaxLevel(){return defaultMaxLevel;} + /** + * If the enchantment have specialised group operation. + * @return If the enchantment is optimised for group operation. + */ + protected boolean isOptimised(){ + return false; + } + /** * Get current level of the enchantment. * @param item Item to search the level for. @@ -133,17 +142,35 @@ public abstract class WrappedEnchantment { * Clear every enchantment from this item. * @param item Item to be cleared from enchantments. */ - public static void clearEnchants(@NotNull ItemStack item){ //TODO faster method to clear vanilla enchantment - for (WrappedEnchantment enchant : getEnchants(item).keySet()) { - enchant.removeFrom(item); + public static void clearEnchants(@NotNull ItemStack item){ + ItemMeta meta = item.getItemMeta(); + if(meta == null) return; + + // Clean Vanilla enchants + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { + EnchantmentStorageMeta bookMeta = (EnchantmentStorageMeta) meta; + bookMeta.getStoredEnchants().forEach( + (enchantment, leve) -> bookMeta.removeStoredEnchant(enchantment) + ); + } else { + item.getEnchantments().forEach( + (enchantment, leve) -> item.removeEnchantment(enchantment) + ); + } + + // Clean unoptimised enchants + for (WrappedEnchantment enchant : unoptimisedValues()) { + if(enchant.isEnchantmentPresent(item)){ + enchant.removeFrom(item); + } } } /** * Get enchantments of an item. - * @param item item to get enchantment from. - * @return a map of the set enchantments and there's respective levels. + * @param item Item to get enchantment from. + * @return A map of the set enchantments and there's respective levels. */ public static Map getEnchants(@NotNull ItemStack item){ //TODO faster method to find vanilla enchantment Map enchantments = new HashMap<>(); @@ -151,18 +178,50 @@ public abstract class WrappedEnchantment { ItemMeta meta = item.getItemMeta(); if(meta == null) return enchantments; - for (WrappedEnchantment enchantment : WrappedEnchantment.values()) { + // Vanilla optimised get + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { + ((EnchantmentStorageMeta)meta).getStoredEnchants().forEach( + (enchantment, level) -> enchantments.put(getByKey(enchantment.getKey()), level) + ); + } else { + item.getEnchantments().forEach( + (enchantment, level) -> enchantments.put(getByKey(enchantment.getKey()), level) + ); + } + + // Unoptimised enchantment get + findEnchantsFromSelectedList(item, meta, enchantments, unoptimisedValues()); + + return enchantments; + } + + + /** + * Find enchantments of an item. only test the enchantment from the list. + * @param item Item to get enchantment from. + * @param meta Meta of the provided item. + * @param enchantments Map of enchantment to complete. + * @param enchantmentToTest Enchantment to test + */ + private static void findEnchantsFromSelectedList( + @NotNull ItemStack item, + @NotNull ItemMeta meta, + @NotNull Map enchantments, + @NotNull Collection enchantmentToTest){ + + for (WrappedEnchantment enchantment : enchantmentToTest) { if(enchantment.isEnchantmentPresent(item, meta)){ enchantments.put(enchantment, enchantment.getLevel(item, meta)); } } - return enchantments; } + // Register enchantment functions private static final HashMap BY_KEY = new HashMap<>(); private static final HashMap BY_NAME = new HashMap<>(); + private static final List UNOPTIMISED_ENCHANTMENT = new ArrayList<>(); /** * This should only be called on main of custom anvil. @@ -198,6 +257,10 @@ public abstract class WrappedEnchantment { BY_KEY.put(enchantment.getKey(), enchantment); BY_NAME.put(enchantment.getName(), enchantment); + + if(!enchantment.isOptimised()){ + UNOPTIMISED_ENCHANTMENT.add(enchantment); + } } /** @@ -241,4 +304,13 @@ public abstract class WrappedEnchantment { return BY_KEY.values().toArray(new WrappedEnchantment[0]); } + /** + * Gets a list of all the unoptimised enchantments. + * @return List of enchantment. + */ + @NotNull + private static List unoptimisedValues() { + return UNOPTIMISED_ENCHANTMENT; + } + } diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java index 5bfd436..3347d0e 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchant.java @@ -1,7 +1,6 @@ package xyz.alexcrea.cuanvil.enchant.wrapped; import io.delilaheve.util.ItemUtil; -import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; @@ -25,9 +24,14 @@ public class VanillaEnchant extends WrappedEnchantment { } + @Override + protected boolean isOptimised() { + return true; + } + @Override public int getLevel(@NotNull ItemStack item, @NotNull ItemMeta meta) { - if (isEnchantedBook(item)) { + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { return ((EnchantmentStorageMeta)meta).getStoredEnchantLevel(this.enchantment); } else { return meta.getEnchantLevel(this.enchantment); @@ -47,7 +51,7 @@ public class VanillaEnchant extends WrappedEnchantment { @Override public void addEnchantmentUnsafe(@NotNull ItemStack item, int level) { - if (isEnchantedBook(item)) { + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { EnchantmentStorageMeta bookMeta = ((EnchantmentStorageMeta)item.getItemMeta()); assert bookMeta != null; @@ -73,10 +77,6 @@ public class VanillaEnchant extends WrappedEnchantment { } - public static boolean isEnchantedBook(@NotNull ItemStack item){ - return Material.ENCHANTED_BOOK.equals(item.getType()); - } - public static EnchantmentRarity getRarity(Enchantment enchantment){ try {return EnchantmentProperties.valueOf(enchantment.getKey().getKey().toUpperCase(Locale.ENGLISH)).getRarity();} catch (IllegalArgumentException ignored) {}