diff --git a/README.md b/README.md index 7ab69d2..234ed58 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,10 @@ Currently, there is not a lot of compatible plugin Here is a list of supported plugins with support status: - [Enchantment²](https://www.spigotmc.org/resources/enchants-squared-the-enchantsplus-rewrite-custom-enchantments-that-act-like-vanilla-ones.86747/): -Officially supported but still experimental. Automatic configuration translation. +Officially supported but still experimental. Automatic configuration. +- [EcoEnchant](https://www.spigotmc.org/resources/50-sale-%E2%8C%9B-ecoenchants-%E2%AD%95-250-enchantments-%E2%9C%85-create-custom-enchants-%E2%9C%A8-essentials-cmi-support.79573/): +Officially supported but still experimental. Need a server restart to add newly added enchantment. +Automatic configuration on restart. If you like Custom Anvil to support a specific custom enchantment plugin. You can ask, but please note implementing compatibility will be considered diff --git a/build.gradle.kts b/build.gradle.kts index 7cffc9c..fc654d2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,11 @@ plugins { - kotlin("jvm") version "1.6.21" + kotlin("jvm") version "1.9.24" java + id("com.github.johnrengelman.shadow").version("7.1.2") } group = "xyz.alexcrea" -version = "1.5.0" +version = "1.5.1" repositories { mavenCentral() @@ -12,6 +13,9 @@ repositories { // ProtocoLib maven (url = "https://repo.dmulloy2.net/repository/public/" ) + + // EcoEnchants + maven(url = "https://repo.auxilor.io/repository/maven-public/") } dependencies { @@ -21,7 +25,7 @@ dependencies { compileOnly("org.spigotmc:spigot-api:1.18-R0.1-SNAPSHOT") // Gui library - compileOnly("com.github.stefvanschie.inventoryframework:IF:0.10.14") + implementation("com.github.stefvanschie.inventoryframework:IF:0.10.14") // Protocolib compileOnly("com.comphenix.protocol:ProtocolLib:5.1.0") @@ -29,6 +33,10 @@ dependencies { // EnchantsSquaredRewritten compileOnly(files("libs/EnchantsSquared.jar")) + // EcoEnchants + compileOnly("com.willfp:EcoEnchants:12.5.1") + compileOnly("com.willfp:eco:6.70.1") + testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.0") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") @@ -54,4 +62,9 @@ val fatJar = tasks.register("fatJar") { // Ensure fatJar and copyJar are run tasks.getByName("build") { dependsOn(fatJar) -} \ No newline at end of file +} + +// Shadow recesary dependency +tasks.shadowJar { + relocate("com.github.stefvanschie.inventoryframework", "xyz.alexcrea.inventoryframework") +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/AdditionalTestEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/AdditionalTestEnchantment.java new file mode 100644 index 0000000..832e5af --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/AdditionalTestEnchantment.java @@ -0,0 +1,34 @@ +package xyz.alexcrea.cuanvil.enchant; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public interface AdditionalTestEnchantment { + + /** + * Test if the provided enchantments can be compatible with this enchantment. only non-Custom Anvil conflict. + * @param enchantments Immutable map of validated enchantments for the item. + * @param itemMat Material of the tested item. + * @return If there is a conflict with the enchantments. + */ + boolean isEnchantConflict( + @NotNull Map enchantments, + @NotNull Material itemMat); + + + /** + * Test if the provided item can be compatible with this enchantment. only non-Custom Anvil conflict. + * @param enchantments Immutable map of validated enchantments for the item. + * @param itemMat Material of the tested item. + * @param item Provide a new instance of the used item stack with the partial enchantment applied. + * @return If there is a conflict with the enchantment and the item. + */ + boolean isItemConflict( + @NotNull Map enchantments, + @NotNull Material itemMat, + @NotNull ItemStack item); + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java new file mode 100644 index 0000000..4a9a766 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantment.java @@ -0,0 +1,243 @@ +package xyz.alexcrea.cuanvil.enchant; + +import io.delilaheve.util.ItemUtil; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.HumanEntity; +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.dependency.DependencyManager; +import xyz.alexcrea.cuanvil.dependency.EnchantmentSquaredDependency; +import xyz.alexcrea.cuanvil.group.ConflictType; +import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +/** + * Represent an enchantment compatible with Custom Anvil. + * One issue with custom anvil is: it does not handle well duplicate key name (ignoring namespace) as the plugin was coded with vanilla enchantment in head + */ +public interface CAEnchantment { + + + /** + * Get the default rarity of this enchant. + * @return The default rarity of this enchant. + */ + @NotNull + EnchantmentRarity defaultRarity(); + + /** + * Get the enchantment key. + * @return The enchantment key. + */ + @NotNull + NamespacedKey getKey(); + + /** + * Get the enchantment name. + * @return The enchantment name. + */ + @NotNull + String getName(); + + /** + * Get the default maximum level of this enchantment. + * @return The default maximum level of this enchantment. + */ + int defaultMaxLevel(); + + /** + * Check if the enchantment have specialised group operation. + * @return If the enchantment is optimised for group operation. + */ + boolean isOptimised(); + + /** + * Check if the player is allowed to use this enchantment. + * @param player The player to test. + * @return If the player is allowed to use this enchantment. + */ + boolean isAllowed(@NotNull HumanEntity player); + + /** + * Add a conflict to this enchantment conflict list. + * @param conflict The conflict to add. + */ + void addConflict(@NotNull EnchantConflictGroup conflict); + + /** + * Remove a conflict from the conflict list of this enchantment. + * @param conflict The conflict to remove from this enchantment. + */ + void removeConflict(@NotNull EnchantConflictGroup conflict); + + /** + * Clear Custom Anvil conflicts for this enchantment. + */ + void clearConflict(); + + /** + * Get a collection of Custom Anvil conflict containing this enchantment. + * @return A collection of Custom Anvil conflict containing this enchantment. + */ + @NotNull Collection getConflicts(); + + /** + * Get current level of the enchantment. + * @param item Item to search the level for. + */ + int getLevel(@NotNull ItemStack item); + + /** + * 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. + */ + 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. + */ + boolean isEnchantmentPresent(@NotNull ItemStack item); + + /** + * 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. + */ + 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 level The level to set the enchantment to. + */ + void addEnchantmentUnsafe(@NotNull ItemStack item, int level); + + /** + * Remove this enchantment from the provided ItemStack. + * @param item The item to remove the enchantment. + */ + void removeFrom(@NotNull ItemStack item); + + // Static functions + /** + * Clear every enchantment from this item. + * @param item Item to be cleared from enchantments. + */ + 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 Enchant Squared enchants + EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility(); + if(enchantmentSquared != null){ + enchantmentSquared.clearEnchantments(item); + } + + // Clean unoptimised enchants + for (CAEnchantment enchant : CAEnchantmentRegistry.getInstance().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. + */ + static Map getEnchants(@NotNull ItemStack item){ + Map enchantments = new HashMap<>(); + CAEnchantmentRegistry registry = CAEnchantmentRegistry.getInstance(); + + ItemMeta meta = item.getItemMeta(); + if(meta == null) return enchantments; + + // Vanilla optimised get + if (ItemUtil.INSTANCE.isEnchantedBook(item)) { + ((EnchantmentStorageMeta)meta).getStoredEnchants().forEach( + (enchantment, level) -> enchantments.put(registry.getByKey(enchantment.getKey()), level) + ); + } else { + item.getEnchantments().forEach( + (enchantment, level) -> enchantments.put(registry.getByKey(enchantment.getKey()), level) + ); + } + + // Enchants Squared get + EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility(); + if(enchantmentSquared != null){ + enchantmentSquared.getEnchantmentsSquared(item, enchantments); + } + + // Unoptimised enchantment get + findEnchantsFromSelectedList(item, meta, enchantments, registry.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 + */ + static void findEnchantsFromSelectedList( + @NotNull ItemStack item, + @NotNull ItemMeta meta, + @NotNull Map enchantments, + @NotNull Collection enchantmentToTest){ + + for (CAEnchantment enchantment : enchantmentToTest) { + if(enchantment.isEnchantmentPresent(item, meta)){ + enchantments.put(enchantment, enchantment.getLevel(item, meta)); + } + } + + } + + /** + * Gets an array of all the registered enchantments. + * @return Array of enchantment. + */ + static @Nullable CAEnchantment getByKey(@NotNull NamespacedKey key){ + return CAEnchantmentRegistry.getInstance().getByKey(key); + } + + /** + * Gets a list of all the unoptimised enchantments. + * @return List of enchantment. + */ + static @Nullable CAEnchantment getByName(@NotNull String name){ + return CAEnchantmentRegistry.getInstance().getByName(name); + } + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentBase.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentBase.java new file mode 100644 index 0000000..7ea4666 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentBase.java @@ -0,0 +1,115 @@ +package xyz.alexcrea.cuanvil.enchant; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.entity.HumanEntity; +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.group.ConflictType; +import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Supplier; + +public abstract class CAEnchantmentBase implements CAEnchantment { + + @NotNull + private final NamespacedKey key; + @NotNull + private final String name; + @NotNull + private final EnchantmentRarity defaultRarity; + private final int defaultMaxLevel; + + private final List conflicts; + + /** + * Constructor of Wrapped Enchantment. + * @param key The enchantment's key. + * @param defaultRarity Default rarity the enchantment should be. + * @param defaultMaxLevel Default max level the enchantment can be applied with. + */ + protected CAEnchantmentBase( + @NotNull NamespacedKey key, + @Nullable EnchantmentRarity defaultRarity, + int defaultMaxLevel){ + this.key = key; + this.name = key.getKey(); + this.defaultMaxLevel = defaultMaxLevel; + + this.defaultRarity = Objects.requireNonNullElse(defaultRarity, EnchantmentRarity.COMMON); + + this.conflicts = new ArrayList<>(); + } + + @NotNull + @Override + public final EnchantmentRarity defaultRarity(){ + return defaultRarity; + } + + @NotNull + @Override + public final NamespacedKey getKey(){ + return key; + } + + @NotNull + @Override + public final String getName(){ + return name; + } + + @Override + public final int defaultMaxLevel(){ + return defaultMaxLevel; + } + + @Override + public boolean isOptimised(){ + return false; + } + + @Override + public boolean isAllowed(@NotNull HumanEntity player){ + return true; + } + + public int getLevel(@NotNull ItemStack item){ + ItemMeta meta = item.getItemMeta(); + if(meta == null) return 0; + return getLevel(item, meta); + } + + public boolean isEnchantmentPresent(@NotNull ItemStack item){ + ItemMeta meta = item.getItemMeta(); + if(meta == null) return false; + return isEnchantmentPresent(item, meta); + } + + @Override + public void addConflict(@NotNull EnchantConflictGroup conflict){ + this.conflicts.add(conflict); + } + + @Override + public void removeConflict(@NotNull EnchantConflictGroup conflict){ + this.conflicts.remove(conflict); + } + + @Override + public void clearConflict(){ + this.conflicts.clear(); + } + + @Override + public @NotNull List getConflicts() { + return conflicts; + } + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java new file mode 100644 index 0000000..c00c7c2 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/CAEnchantmentRegistry.java @@ -0,0 +1,135 @@ +package xyz.alexcrea.cuanvil.enchant; + +import io.delilaheve.CustomAnvil; +import org.bukkit.NamespacedKey; +import org.bukkit.enchantments.Enchantment; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.alexcrea.cuanvil.dependency.DependencyManager; +import xyz.alexcrea.cuanvil.enchant.wrapped.CAVanillaEnchantment; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; + +public class CAEnchantmentRegistry { + + private static final CAEnchantmentRegistry instance = new CAEnchantmentRegistry(); + public static CAEnchantmentRegistry getInstance() { + return instance; + } + + // Register enchantment functions + private final HashMap byKeyMap; + private final HashMap byNameMap; + private final List unoptimisedValues; + + private CAEnchantmentRegistry() { + byKeyMap = new HashMap<>(); + byNameMap = new HashMap<>(); + unoptimisedValues = new ArrayList<>(); + } + + /** + * 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 void registerStartupEnchantments(){ + for (Enchantment enchantment : Enchantment.values()) { + register(new CAVanillaEnchantment(enchantment)); + } + + if(DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility() != null){ + DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility().registerEnchantments(); + } + if(DependencyManager.INSTANCE.getEcoEnchantCompatibility() != null){ + DependencyManager.INSTANCE.getEcoEnchantCompatibility().registerEnchantments(); + } + + } + + /** + * 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 be registered. + */ + public void register(@NotNull CAEnchantment enchantment){ + if(byKeyMap.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(byNameMap.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")); + } + + byKeyMap.put(enchantment.getKey(), enchantment); + byNameMap.put(enchantment.getName(), enchantment); + + if(!enchantment.isOptimised()){ + unoptimisedValues.add(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 be unregistered. + */ + public void unregister(CAEnchantment enchantment){ + if(enchantment == null) return; + byKeyMap.remove(enchantment.getKey()); + byNameMap.remove(enchantment.getName()); + + unoptimisedValues.remove(enchantment); + } + + /** + * Gets the enchantment by the provided key. + * @param key Key to fetch. + * @return Registered enchantment. null if absent. + */ + public @Nullable CAEnchantment getByKey(@NotNull NamespacedKey key){ + return byKeyMap.get(key); + } + + /** + * Gets the enchantment by the provided name. + * @param name Name to fetch. + * @return Registered enchantment. null if absent. + */ + public @Nullable CAEnchantment getByName(@NotNull String name){ + return byNameMap.get(name); + } + + /** + * Gets an array of all the registered enchantments. + * @return Array of enchantment. + */ + @NotNull + public Collection values() { + return byKeyMap.values(); + } + + /** + * Gets a list of all the unoptimised enchantments. + * @return List of enchantment. + */ + @NotNull + public List unoptimisedValues() { + return unoptimisedValues; + } + +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java deleted file mode 100644 index f5c6633..0000000 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/WrappedEnchantment.java +++ /dev/null @@ -1,344 +0,0 @@ -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.entity.HumanEntity; -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.dependency.DependencyManager; -import xyz.alexcrea.cuanvil.dependency.EnchantmentSquaredDependency; -import xyz.alexcrea.cuanvil.enchant.wrapped.VanillaEnchantment; - -import java.util.*; -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 - private final NamespacedKey key; - @NotNull - private final String name; - @NotNull - private final EnchantmentRarity defaultRarity; - private final int defaultMaxLevel; - - /** - * Constructor of Wrapped Enchantment. - * @param key The enchantment's key. - * @param defaultRarity Default rarity the enchantment should be. - * @param defaultMaxLevel Default max level the enchantment can be applied with. - */ - protected WrappedEnchantment( - @NotNull NamespacedKey key, - @Nullable EnchantmentRarity defaultRarity, - int defaultMaxLevel){ - this.key = key; - this.name = key.getKey(); - this.defaultMaxLevel = defaultMaxLevel; - - 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. - */ - @NotNull - 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 final String getName(){ - return name; - } - - /** - * Get the default maximum level of this enchantment. - * @return The default maximum level of this enchantment. - */ - public final int defaultMaxLevel(){return defaultMaxLevel;} - - /** - * Check if the enchantment have specialised group operation. - * @return If the enchantment is optimised for group operation. - */ - protected boolean isOptimised(){ - return false; - } - - /** - * Check if the player is allowed to use this enchantment. - * @param player The player to test. - * @return If the player is allowed to use this enchantment. - */ - public boolean isAllowed(@NotNull HumanEntity player){ - return true; - } - - /** - * 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. - * @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. - * @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. - * @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 level The level to set the enchantment to. - */ - public abstract void addEnchantmentUnsafe(@NotNull ItemStack item, int level); - - /** - * Remove this enchantment from the provided ItemStack. - * @param item The item to remove the enchantment. - */ - public abstract void removeFrom(@NotNull ItemStack item); - - // Static functions - /** - * Clear every enchantment from this item. - * @param item Item to be cleared from enchantments. - */ - 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 Enchant Squared enchants - EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility(); - if(enchantmentSquared != null){ - enchantmentSquared.clearEnchantments(item); - } - - // 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. - */ - public static Map getEnchants(@NotNull ItemStack item){ - Map enchantments = new HashMap<>(); - - ItemMeta meta = item.getItemMeta(); - if(meta == null) return enchantments; - - // 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) - ); - } - - // Enchants Squared get - EnchantmentSquaredDependency enchantmentSquared = DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility(); - if(enchantmentSquared != null){ - enchantmentSquared.getEnchantmentsSquared(item, enchantments); - } - - // 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)); - } - } - - } - - - // 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. - * If called more than one time, chance of thing being broken will be high. - */ - public static void registerEnchantments(){ - for (Enchantment enchantment : Enchantment.values()) { - register(new VanillaEnchantment(enchantment)); - } - - if(DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility() != null){ - DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility().registerEnchantments(); - } - - } - - /** - * 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 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); - - if(!enchantment.isOptimised()){ - UNOPTIMISED_ENCHANTMENT.add(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 be unregistered. - */ - 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 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. - */ - @NotNull - public static WrappedEnchantment[] values() { - 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/CAEcoEnchant.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEcoEnchant.java new file mode 100644 index 0000000..31991f4 --- /dev/null +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEcoEnchant.java @@ -0,0 +1,59 @@ +package xyz.alexcrea.cuanvil.enchant.wrapped; + +import com.willfp.ecoenchants.enchant.EcoEnchant; +import com.willfp.ecoenchants.target.EnchantmentTarget; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; +import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; +import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment; +import xyz.alexcrea.cuanvil.group.ConflictType; + +import java.util.Map; +import java.util.function.Supplier; + +public class CAEcoEnchant extends CAVanillaEnchantment implements AdditionalTestEnchantment { + + private final @NotNull EcoEnchant ecoEnchant; + + public CAEcoEnchant(@NotNull EcoEnchant enchant) { + super(enchant.getEnchantment(), EnchantmentRarity.COMMON); + this.ecoEnchant = enchant; + } + + @Override + public boolean isEnchantConflict(@NotNull Map enchantments, @NotNull Material itemMat) { + if(!enchantments.isEmpty()) { + if (this.ecoEnchant.getConflictsWithEverything()) { + return true; + } + + for (CAEnchantment other : enchantments.keySet()) { + if(other instanceof CAVanillaEnchantment otherVanilla + && this.ecoEnchant.conflictsWith(otherVanilla.getEnchant())){ + return true; + } + } + + } + return false; + } + + @Override + public boolean isItemConflict(@NotNull Map enchantments, + @NotNull Material itemMat, + @NotNull ItemStack item) { + if(Material.ENCHANTED_BOOK.equals(itemMat)){ + return false; + } + + for (EnchantmentTarget target : this.ecoEnchant.getTargets()) { + if(target.matches(item)){ + return false; + } + } + + return true; + } +} diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/EnchantSquaredEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java similarity index 90% rename from src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/EnchantSquaredEnchantment.java rename to src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java index 52e7171..ffc9415 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/EnchantSquaredEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAEnchantSquaredEnchantment.java @@ -8,16 +8,16 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import xyz.alexcrea.cuanvil.dependency.DependencyManager; +import xyz.alexcrea.cuanvil.enchant.CAEnchantmentBase; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import java.util.Map; import java.util.Objects; -public class EnchantSquaredEnchantment extends WrappedEnchantment { +public class CAEnchantSquaredEnchantment extends CAEnchantmentBase { public final @NotNull CustomEnchant enchant; - public EnchantSquaredEnchantment(@NotNull CustomEnchant enchant) { + public CAEnchantSquaredEnchantment(@NotNull CustomEnchant enchant) { super(Objects.requireNonNull( Objects.requireNonNull(DependencyManager.INSTANCE.getEnchantmentSquaredCompatibility()).getKeyFromEnchant(enchant)), EnchantmentRarity.COMMON, @@ -27,7 +27,7 @@ public class EnchantSquaredEnchantment extends WrappedEnchantment { } @Override - protected boolean isOptimised() { + public boolean isOptimised() { return true; } diff --git a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchantment.java b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAVanillaEnchantment.java similarity index 82% rename from src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchantment.java rename to src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAVanillaEnchantment.java index 375ad66..9fef4c1 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/VanillaEnchantment.java +++ b/src/main/java/xyz/alexcrea/cuanvil/enchant/wrapped/CAVanillaEnchantment.java @@ -6,26 +6,30 @@ 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.CAEnchantmentBase; import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import java.util.Locale; -public class VanillaEnchantment extends WrappedEnchantment { +public class CAVanillaEnchantment extends CAEnchantmentBase { private final @NotNull Enchantment enchantment; - public VanillaEnchantment(@NotNull Enchantment enchantment){ + public CAVanillaEnchantment(@NotNull Enchantment enchantment, @Nullable EnchantmentRarity rarity){ super(enchantment.getKey(), - getRarity(enchantment), + rarity, enchantment.getMaxLevel()); this.enchantment = enchantment; + } + public CAVanillaEnchantment(@NotNull Enchantment enchantment){ + this(enchantment, getRarity(enchantment)); } @Override - protected boolean isOptimised() { + public boolean isOptimised() { return true; } @@ -77,6 +81,7 @@ public class VanillaEnchantment extends WrappedEnchantment { } + @NotNull public static EnchantmentRarity getRarity(Enchantment enchantment){ try { return EnchantmentProperties.valueOf(enchantment.getKey().getKey().toUpperCase(Locale.ENGLISH)).getRarity(); @@ -85,4 +90,8 @@ public class VanillaEnchantment extends WrappedEnchantment { } } + @NotNull + protected Enchantment getEnchant() { + return this.enchantment; + } } 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 95bf586..1174209 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 xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; 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 40e43c1..369924b 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 @@ -3,7 +3,7 @@ package xyz.alexcrea.cuanvil.gui.config.global; import com.github.stefvanschie.inventoryframework.gui.GuiItem; import com.github.stefvanschie.inventoryframework.pane.util.Pattern; import org.bukkit.event.inventory.InventoryClickEvent; -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.config.list.SettingGuiListConfigGui; import xyz.alexcrea.cuanvil.gui.config.settings.SettingGui; @@ -19,7 +19,7 @@ import java.util.function.Consumer; * * @param Type of the factory of the type of setting the gui should edit. */ -public abstract class AbstractEnchantConfigGui extends SettingGuiListConfigGui implements ValueUpdatableGui { +public abstract class AbstractEnchantConfigGui extends SettingGuiListConfigGui implements ValueUpdatableGui { /** * Constructor for a gui displaying available enchantment to edit a enchantment setting. @@ -36,7 +36,7 @@ public abstract class AbstractEnchantConfigGui getEveryDisplayableInstanceOfGeneric() { + protected Collection getEveryDisplayableInstanceOfGeneric() { return GuiSharedConstant.SORTED_ENCHANTMENT_LIST; } diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java index 02fc651..797a3ab 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/CustomRecipeConfigGui.java @@ -13,7 +13,6 @@ import xyz.alexcrea.cuanvil.util.CasedStringUtil; import java.util.Arrays; import java.util.Collection; -import java.util.List; public class CustomRecipeConfigGui extends MappedGuiListConfigGui { diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java index 1b04f06..6020df6 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/EnchantConflictGui.java @@ -15,7 +15,6 @@ import xyz.alexcrea.cuanvil.util.CasedStringUtil; import java.util.Arrays; import java.util.Collection; -import java.util.List; public class EnchantConflictGui extends MappedGuiListConfigGui { 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 a74f26e..73e11ac 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 @@ -5,14 +5,17 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import xyz.alexcrea.cuanvil.config.ConfigHolder; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.enchant.EnchantmentProperties; import xyz.alexcrea.cuanvil.enchant.EnchantmentRarity; -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; import xyz.alexcrea.cuanvil.gui.config.settings.EnchantCostSettingsGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.util.CasedStringUtil; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; /** * Global Config gui for enchantment cost settings. @@ -36,7 +39,7 @@ public class EnchantCostConfigGui extends AbstractEnchantConfigGui { diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/UnitRepairConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/UnitRepairConfigGui.java index 2358d0a..30c5d2e 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/UnitRepairConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/global/UnitRepairConfigGui.java @@ -15,7 +15,6 @@ import xyz.alexcrea.cuanvil.util.CasedStringUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.List; public class UnitRepairConfigGui extends MappedGuiListConfigGui { diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/ElementListConfigGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/ElementListConfigGui.java index aa8095f..f11cdf5 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/ElementListConfigGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/ElementListConfigGui.java @@ -20,7 +20,10 @@ import xyz.alexcrea.cuanvil.gui.config.MainConfigGui; import xyz.alexcrea.cuanvil.gui.util.GuiGlobalItems; import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.UUID; public abstract class ElementListConfigGui< T > extends ChestGui implements ValueUpdatableGui { diff --git a/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java b/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java index a3d95b4..8c17f39 100644 --- a/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java +++ b/src/main/java/xyz/alexcrea/cuanvil/gui/config/list/elements/EnchantConflictSubSettingGui.java @@ -10,7 +10,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import xyz.alexcrea.cuanvil.config.ConfigHolder; -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; import xyz.alexcrea.cuanvil.group.AbstractMaterialGroup; import xyz.alexcrea.cuanvil.group.EnchantConflictGroup; import xyz.alexcrea.cuanvil.group.EnchantConflictManager; @@ -117,9 +117,9 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl Supplier deleteSupplier = () -> { EnchantConflictManager manager = ConfigHolder.CONFLICT_HOLDER.getConflictManager(); - // Remove from manager - for (WrappedEnchantment enchantment : this.enchantConflict.getEnchants()) { - manager.removeConflictFromMap(enchantment, this.enchantConflict); + // Remove from enchantment + for (CAEnchantment enchantment : this.enchantConflict.getEnchants()) { + enchantment.removeConflict(this.enchantConflict); } manager.conflictList.remove(this.enchantConflict); @@ -164,12 +164,12 @@ public class EnchantConflictSubSettingGui extends MappedToListSubSettingGui impl // Prepare enchantment lore ArrayList 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 (WrappedEnchantment enchantment : enchantments) { + for (CAEnchantment 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 c909c41..308d51f 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 @@ -12,7 +12,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.jetbrains.annotations.NotNull; import xyz.alexcrea.cuanvil.config.ConfigHolder; -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment; +import xyz.alexcrea.cuanvil.enchant.CAEnchantment; +import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry; import xyz.alexcrea.cuanvil.gui.ValueUpdatableGui; import xyz.alexcrea.cuanvil.gui.config.SelectEnchantmentContainer; import xyz.alexcrea.cuanvil.gui.config.list.SettingGuiListConfigGui; @@ -22,14 +23,13 @@ import xyz.alexcrea.cuanvil.util.CasedStringUtil; import java.util.*; import java.util.function.Consumer; -import java.util.stream.Collectors; import java.util.stream.Stream; -public class EnchantSelectSettingGui extends SettingGuiListConfigGui implements SettingGui { +public class EnchantSelectSettingGui extends SettingGuiListConfigGui implements SettingGui { private final SelectEnchantmentContainer enchantContainer; - private final Set selectedEnchant; + private final Set selectedEnchant; private final GuiItem saveItem; private boolean displayUnselected; @@ -62,19 +62,19 @@ public class EnchantSelectSettingGui extends SettingGuiListConfigGui getEveryDisplayableInstanceOfGeneric() { - Stream toDisplayStream; + protected Collection getEveryDisplayableInstanceOfGeneric() { + Stream toDisplayStream; if(this.displayUnselected){ - toDisplayStream = Arrays.stream(WrappedEnchantment.values()); + toDisplayStream = CAEnchantmentRegistry.getInstance().values().stream(); }else{ toDisplayStream = this.selectedEnchant.stream(); } - Set illegalEnchantments = this.enchantContainer.illegalEnchantments(); + Set illegalEnchantments = this.enchantContainer.illegalEnchantments(); return toDisplayStream .filter(enchantment -> !illegalEnchantments.contains(enchantment)) - .collect(Collectors.toList()); + .toList(); } @Override @@ -84,7 +84,7 @@ public class EnchantSelectSettingGui extends SettingGuiListConfigGui getEnchantItemConsumer(WrappedEnchantment enchant, GuiItem guiItem) { + private Consumer getEnchantItemConsumer(CAEnchantment enchant, GuiItem guiItem) { return event -> { event.setCancelled(true); @@ -180,7 +180,7 @@ public class EnchantSelectSettingGui extends SettingGuiListConfigGui baseGroup = this.enchantContainer.getSelectedEnchantments(); + Set baseGroup = this.enchantContainer.getSelectedEnchantments(); return baseGroup.size() != this.selectedEnchant.size() || !baseGroup.containsAll(this.selectedEnchant); } @@ -209,7 +209,7 @@ public class EnchantSelectSettingGui extends SettingGuiListConfigGui SORTED_ENCHANTMENT_LIST; + public static final List SORTED_ENCHANTMENT_LIST; static { - SORTED_ENCHANTMENT_LIST = Arrays.asList(WrappedEnchantment.values()); + SORTED_ENCHANTMENT_LIST = new ArrayList<>(CAEnchantmentRegistry.getInstance().values()); SORTED_ENCHANTMENT_LIST.sort(Comparator.comparing(ench -> ench.getKey().getKey())); } diff --git a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt index a44a7c4..e432dca 100644 --- a/src/main/kotlin/io/delilaheve/AnvilEventListener.kt +++ b/src/main/kotlin/io/delilaheve/AnvilEventListener.kt @@ -99,7 +99,7 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { // Test for merge if (first.canMergeWith(second)) { val newEnchants = first.findEnchantments() - .combineWith(second.findEnchantments(), first.type, player) + .combineWith(second.findEnchantments(), first, player) val resultItem = first.clone() resultItem.setEnchantmentsUnsafe(newEnchants) @@ -436,20 +436,20 @@ class AnvilEventListener(private val packetManager: PacketManager) : Listener { val rightIsFormBook = right.isEnchantedBook() val resultEnchs = result.findEnchantments() - val resultEnchsKeys = HashSet(resultEnchs.keys) + val resultEnchsKeys = HashMap(resultEnchs) for (enchantment in right.findEnchantments()) { // count enchant as illegal enchant if it conflicts with another enchant or not in result if ((enchantment.key !in resultEnchsKeys)) { - resultEnchsKeys.add(enchantment.key) + resultEnchsKeys[enchantment.key] = enchantment.value val conflictType = ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting( resultEnchsKeys, - result.type, + result, enchantment.key ) resultEnchsKeys.remove(enchantment.key) - if (ConflictType.BIG_CONFLICT == conflictType) { + if (ConflictType.ENCHANTMENT_CONFLICT == conflictType) { illegalPenalty += ConfigOptions.sacrificeIllegalCost CustomAnvil.verboseLog("Big conflict. Adding illegal price penalty") } diff --git a/src/main/kotlin/io/delilaheve/CustomAnvil.kt b/src/main/kotlin/io/delilaheve/CustomAnvil.kt index bc43ec2..02423a6 100644 --- a/src/main/kotlin/io/delilaheve/CustomAnvil.kt +++ b/src/main/kotlin/io/delilaheve/CustomAnvil.kt @@ -8,7 +8,7 @@ import xyz.alexcrea.cuanvil.command.EditConfigExecutor import xyz.alexcrea.cuanvil.command.ReloadExecutor import xyz.alexcrea.cuanvil.config.ConfigHolder import xyz.alexcrea.cuanvil.dependency.DependencyManager -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry import xyz.alexcrea.cuanvil.gui.config.MainConfigGui import xyz.alexcrea.cuanvil.gui.util.GuiSharedConstant import xyz.alexcrea.cuanvil.listener.ChatEventListener @@ -94,7 +94,7 @@ class CustomAnvil : JavaPlugin() { DependencyManager.loadDependency() // Register enchantments - WrappedEnchantment.registerEnchantments() + CAEnchantmentRegistry.getInstance().registerStartupEnchantments() // Load chat listener chatListener = ChatEventListener() @@ -108,7 +108,7 @@ class CustomAnvil : JavaPlugin() { Update_1_21.handleUpdate() // Handle custom enchant config - DependencyManager.handleConfigChanges() + DependencyManager.handleConfigChanges(this) // Load gui constants //TODO maybe something better later MainConfigGui.getInstance().init(DependencyManager.packetManager) diff --git a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt index 930b9d0..03eedcf 100644 --- a/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt +++ b/src/main/kotlin/io/delilaheve/util/ConfigOptions.kt @@ -3,7 +3,7 @@ package io.delilaheve.util import io.delilaheve.CustomAnvil import io.delilaheve.util.EnchantmentUtil.enchantmentName import xyz.alexcrea.cuanvil.config.ConfigHolder -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantment /** * Config option accessors @@ -239,7 +239,7 @@ object ConfigOptions { /** * Get the given [enchantment]'s limit */ - fun enchantLimit(enchantment: WrappedEnchantment): Int { + fun enchantLimit(enchantment: CAEnchantment): Int { return enchantLimit(enchantment.enchantmentName) } @@ -273,7 +273,7 @@ object ConfigOptions { * it's source [isFromBook] */ fun enchantmentValue( - enchantment: WrappedEnchantment, + enchantment: CAEnchantment, isFromBook: Boolean ): Int { return enchantmentValue(enchantment.enchantmentName, isFromBook) @@ -307,7 +307,7 @@ object ConfigOptions { return enchantmentValue("sweeping", isFromBook) } - val enchantment = WrappedEnchantment.getByName(enchantmentName) + val enchantment = CAEnchantment.getByName(enchantmentName) if(enchantment != null){ val rarity = enchantment.defaultRarity() diff --git a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt index 7bf3e4b..95bdd36 100644 --- a/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/EnchantmentUtil.kt @@ -1,10 +1,10 @@ package io.delilaheve.util import io.delilaheve.CustomAnvil -import org.bukkit.Material import org.bukkit.entity.HumanEntity +import org.bukkit.inventory.ItemStack import xyz.alexcrea.cuanvil.config.ConfigHolder -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantment import xyz.alexcrea.cuanvil.group.ConflictType import kotlin.math.max import kotlin.math.min @@ -17,18 +17,19 @@ object EnchantmentUtil { /** * Enchantment name without namespace */ - val WrappedEnchantment.enchantmentName: String + val CAEnchantment.enchantmentName: String get() = key.key /** * Combine 2 sets of enchantments according to our configuration */ - fun Map.combineWith( - other: Map, - mat: Material, + fun Map.combineWith( + other: Map, + item: ItemStack, player: HumanEntity - ) = mutableMapOf().apply { + ) = mutableMapOf().apply { putAll(this@combineWith) + other.forEach { (enchantment, level) -> if(!enchantment.isAllowed(player)) return@forEach @@ -44,7 +45,7 @@ object EnchantmentUtil { // Add the enchantment if it doesn't have conflicts, or if player is allowed to bypass enchantment restrictions this[enchantment] = cappedLevel val conflictType = - ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this.keys, mat, enchantment) + ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this, item, enchantment) if (!player.hasPermission(CustomAnvil.bypassFusePermission) && (conflictType != ConflictType.NO_CONFLICT) ) { @@ -55,11 +56,11 @@ object EnchantmentUtil { } // Enchantment already in result list else { - val oldLevel = this[enchantment]!! // <- should not be null. see the comment above + val oldLevel = this[enchantment]!! // <- should not be null. (enchantment already in result list) // ... and they are conflicting val conflictType = - ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this.keys, mat, enchantment) + ConfigHolder.CONFLICT_HOLDER.conflictManager.isConflicting(this, item, enchantment) if ((conflictType != ConflictType.NO_CONFLICT) && !player.hasPermission(CustomAnvil.bypassFusePermission) ) { diff --git a/src/main/kotlin/io/delilaheve/util/ItemUtil.kt b/src/main/kotlin/io/delilaheve/util/ItemUtil.kt index 6c627ba..3c415f6 100644 --- a/src/main/kotlin/io/delilaheve/util/ItemUtil.kt +++ b/src/main/kotlin/io/delilaheve/util/ItemUtil.kt @@ -3,7 +3,7 @@ package io.delilaheve.util import org.bukkit.Material.ENCHANTED_BOOK import org.bukkit.inventory.ItemStack import org.bukkit.inventory.meta.Damageable -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantment import kotlin.math.ceil import kotlin.math.max import kotlin.math.min @@ -21,13 +21,13 @@ object ItemUtil { /** * Find the enchantment map for this [ItemStack] and return it as a [MutableMap] */ - fun ItemStack.findEnchantments(): MutableMap = WrappedEnchantment.getEnchants(this) + fun ItemStack.findEnchantments(): MutableMap = CAEnchantment.getEnchants(this) /** * Apply an [enchantments] map to this [ItemStack] */ - fun ItemStack.setEnchantmentsUnsafe(enchantments: Map) { - WrappedEnchantment.clearEnchants(this) + fun ItemStack.setEnchantmentsUnsafe(enchantments: Map) { + CAEnchantment.clearEnchants(this) //TODO maybe faster methode to add vanilla enchantment. maybe move this function to wrapped enchantment enchantments.forEach { (enchantment, level) -> diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt index 61bcb7a..57e27d7 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/DependencyManager.kt @@ -1,14 +1,17 @@ package xyz.alexcrea.cuanvil.dependency import org.bukkit.Bukkit +import org.bukkit.plugin.Plugin import xyz.alexcrea.cuanvil.dependency.protocolib.NoProtocoLib import xyz.alexcrea.cuanvil.dependency.protocolib.PacketManager import xyz.alexcrea.cuanvil.dependency.protocolib.ProtocoLibWrapper +import java.io.File object DependencyManager { lateinit var packetManager: PacketManager var enchantmentSquaredCompatibility: EnchantmentSquaredDependency? = null + var ecoEnchantCompatibility: EcoEnchantDependency? = null fun loadDependency(){ val pluginManager = Bukkit.getPluginManager() @@ -24,11 +27,19 @@ object DependencyManager { enchantmentSquaredCompatibility!!.disableAnvilListener() } + // EcoEnchants dependency + if(pluginManager.isPluginEnabled("EcoEnchants")){ + ecoEnchantCompatibility = EcoEnchantDependency(pluginManager.getPlugin("EcoEnchants")!!) + ecoEnchantCompatibility!!.disableAnvilListener() + } + } - fun handleConfigChanges() { + fun handleConfigChanges(plugin: Plugin) { + val folder = File(plugin.dataFolder, "compatibility") enchantmentSquaredCompatibility?.registerPluginConfiguration() + ecoEnchantCompatibility?.registerPluginConfiguration(folder) } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EcoEnchantDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EcoEnchantDependency.kt new file mode 100644 index 0000000..e37237e --- /dev/null +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EcoEnchantDependency.kt @@ -0,0 +1,78 @@ +package xyz.alexcrea.cuanvil.dependency + +import com.willfp.ecoenchants.enchant.EcoEnchants +import io.delilaheve.CustomAnvil +import org.bukkit.configuration.file.YamlConfiguration +import org.bukkit.event.inventory.PrepareAnvilEvent +import org.bukkit.plugin.Plugin +import xyz.alexcrea.cuanvil.config.ConfigHolder +import xyz.alexcrea.cuanvil.enchant.CAEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry +import xyz.alexcrea.cuanvil.enchant.wrapped.CAEcoEnchant +import java.io.File + +class EcoEnchantDependency(private val ecoEnchantPlugin: Plugin) { + + init { + CustomAnvil.instance.logger.info("Eco Enchant Detected !") + } + + fun disableAnvilListener(){ + PrepareAnvilEvent.getHandlerList().unregister(this.ecoEnchantPlugin) + } + + fun registerEnchantments() { + val registery = CAEnchantmentRegistry.getInstance() + for (ecoEnchant in EcoEnchants.values()) { + val enchantments: CAEnchantment = CAEcoEnchant(ecoEnchant) + + registery.unregister(registery.getByKey(ecoEnchant.enchantment.key)) // As eco enchants are considered real enchantment, we need to unregister it. + registery.register(enchantments) + } + } + + fun registerPluginConfiguration(folder: File){ + val compatibilityFile = File(folder, "ecoEnchant.yml") + + if(compatibilityFile.exists()){ + folder.mkdirs() + compatibilityFile.createNewFile() + } + + val config = YamlConfiguration.loadConfiguration(compatibilityFile) + val defaultConfig = ConfigHolder.DEFAULT_CONFIG.config + var doSave = false + + for (ecoEnchant in EcoEnchants.values()) { + val enchantment = CAEnchantmentRegistry.getInstance().getByKey(ecoEnchant.enchantmentKey) + + if(enchantment == null){ + CustomAnvil.instance.logger.warning("Could not find " + ecoEnchant.enchantmentKey + "testing compatibility.") + continue + } + + // Write enchantment value if needed + val testPath = "default.${enchantment.key.key}" + if(!config.getBoolean(testPath, false)){ + doSave = true + config[testPath] = true + + defaultConfig["enchant_limits.${enchantment.key.key}"] = enchantment.defaultMaxLevel() + + val rarity = enchantment.defaultRarity() + defaultConfig["enchant_values.${enchantment.key.key}.item"] = rarity.itemValue + defaultConfig["enchant_values.${enchantment.key.key}.book"] = rarity.bookValue + + } + } + + if(doSave){ + config.save(compatibilityFile) + ConfigHolder.DEFAULT_CONFIG.saveToDisk(true) + + CustomAnvil.instance.logger.info("Saved default for new eco enchant enchantments.") + } + + } + +} diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EnchantmentSquaredDependency.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EnchantmentSquaredDependency.kt index 13d27f4..15aa46e 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EnchantmentSquaredDependency.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/dependency/EnchantmentSquaredDependency.kt @@ -8,34 +8,40 @@ import org.bukkit.event.inventory.PrepareAnvilEvent import org.bukkit.inventory.ItemStack import org.bukkit.plugin.Plugin import xyz.alexcrea.cuanvil.config.ConfigHolder -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment -import xyz.alexcrea.cuanvil.enchant.wrapped.EnchantSquaredEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry +import xyz.alexcrea.cuanvil.enchant.wrapped.CAEnchantSquaredEnchantment import java.util.* -import kotlin.collections.ArrayList class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) { - fun disableAnvilListener(){ - PrepareAnvilEvent.getHandlerList().unregister(this.enchantmentSquaredPlugin) - + init { CustomAnvil.instance.logger.info("Enchantment Squared Detected !") CustomAnvil.instance.logger.info("Please be aware that Custom Anvil is bypassing Enchantment Squared ") CustomAnvil.instance.logger.info( "compatible_with, " + - "disable_anvil, " + - "incompatible_vanilla_enchantments, " + - "incompatible_custom_enchantments and max_level " + - "configuration values.") + "disable_anvil, " + + "incompatible_vanilla_enchantments, " + + "incompatible_custom_enchantments and max_level " + + "configuration values.") + } + + fun disableAnvilListener(){ + PrepareAnvilEvent.getHandlerList().unregister(this.enchantmentSquaredPlugin) } fun registerEnchantments(){ for (enchant in CustomEnchantManager.getInstance().allEnchants.values) { - WrappedEnchantment.register(EnchantSquaredEnchantment(enchant)) + CAEnchantmentRegistry.getInstance().register( + CAEnchantSquaredEnchantment( + enchant + ) + ) } } - fun getEnchantmentsSquared(item: ItemStack, enchantments: MutableMap) { + fun getEnchantmentsSquared(item: ItemStack, enchantments: MutableMap) { val customEnchants = CustomEnchantManager.getInstance().getItemsEnchantsFromPDC(item) customEnchants.forEach{ @@ -51,8 +57,8 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) fun getKeyFromEnchant(enchant: CustomEnchant): NamespacedKey{ return NamespacedKey.fromString(enchant.type.lowercase(Locale.getDefault()), this.enchantmentSquaredPlugin)!! } - private fun getWrappedEnchant(enchant: CustomEnchant): WrappedEnchantment{ - return WrappedEnchantment.getByKey(getKeyFromEnchant(enchant))!! + private fun getWrappedEnchant(enchant: CustomEnchant): CAEnchantment { + return CAEnchantment.getByKey(getKeyFromEnchant(enchant))!! } @@ -65,9 +71,9 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) CustomAnvil.instance.logger.info("Preparing configuration for Enchantment Squared...") // Prepare enchantments - val esEnchantments = ArrayList() + val esEnchantments = ArrayList() CustomEnchantManager.getInstance().allEnchants.forEach { (_, enchant) -> - esEnchantments.add(getWrappedEnchant(enchant) as EnchantSquaredEnchantment) + esEnchantments.add(getWrappedEnchant(enchant) as CAEnchantSquaredEnchantment) } // Write default level limit and xp cost @@ -114,7 +120,7 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) if(!groupConfig.isConfigurationSection("hoes")){ groupConfig["hoes.type"] = "include" - groupConfig["hoes.items"] = listOf("wooden_hoe", "stone_ho", "iron_hoe", "diamond_hoe", "golden_hoe", "netherite_hoe") + groupConfig["hoes.items"] = listOf("wooden_hoe", "stone_hoe", "iron_hoe", "diamond_hoe", "golden_hoe", "netherite_hoe") } if(!groupConfig.isConfigurationSection("shield")){ @@ -134,7 +140,7 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) } - private fun writeMaterialRestriction(esEnchantments: List){ + private fun writeMaterialRestriction(esEnchantments: List){ val conflictConfig = ConfigHolder.CONFLICT_HOLDER.config for (enchantment in esEnchantments) { val restrictionName = "restriction_${enchantment.key.key}" @@ -158,9 +164,9 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) } } - private fun writeEnchantmentConflicts(esEnchantments: List){ - val otherEnchants = ArrayList() - otherEnchants.addAll(WrappedEnchantment.values()) + private fun writeEnchantmentConflicts(esEnchantments: List){ + val otherEnchants = ArrayList() + otherEnchants.addAll(CAEnchantmentRegistry.getInstance().values()) for (enchantment in esEnchantments) { otherEnchants.remove(enchantment) @@ -174,7 +180,7 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) } } - private fun writeConflict(enchantment1: WrappedEnchantment, enchantment2: WrappedEnchantment){ + private fun writeConflict(enchantment1: CAEnchantment, enchantment2: CAEnchantment){ val conflictConfig = ConfigHolder.CONFLICT_HOLDER.config val conflictPath = "${enchantment1.name}_with_${enchantment2.name}_conflict" @@ -216,5 +222,5 @@ class EnchantmentSquaredDependency(private val enchantmentSquaredPlugin: Plugin) else -> null } } - + } diff --git a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictGroup.kt index 2885237..be8d085 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 xyz.alexcrea.cuanvil.enchant.WrappedEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantment 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: WrappedEnchantment) { + fun addEnchantment(enchant: CAEnchantment) { enchantments.add(enchant) } - fun allowed(enchants: Set, mat: Material): Boolean { + fun allowed(enchants: Set, mat: Material): Boolean { if (enchantments.size < minBeforeBlock) { CustomAnvil.verboseLog("Conflicting bc of to many enchantments") return true @@ -44,11 +44,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 c5dabc1..b2d54d4 100644 --- a/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt +++ b/src/main/kotlin/xyz/alexcrea/cuanvil/group/EnchantConflictManager.kt @@ -1,11 +1,15 @@ package xyz.alexcrea.cuanvil.group import io.delilaheve.CustomAnvil -import org.bukkit.Material import org.bukkit.NamespacedKey import org.bukkit.configuration.ConfigurationSection import org.bukkit.enchantments.Enchantment -import xyz.alexcrea.cuanvil.enchant.WrappedEnchantment +import org.bukkit.inventory.ItemStack +import xyz.alexcrea.cuanvil.enchant.AdditionalTestEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantment +import xyz.alexcrea.cuanvil.enchant.CAEnchantmentRegistry +import java.util.* +import kotlin.collections.ArrayList class EnchantConflictManager { @@ -28,48 +32,40 @@ class EnchantConflictManager { // 1.20.5 compatibility TODO better update system private val SWEEPING_EDGE_ENCHANT = - WrappedEnchantment.getByKey(NamespacedKey.minecraft("sweeping_edge")) ?: - WrappedEnchantment.getByKey(Enchantment.SWEEPING_EDGE.key) + CAEnchantment.getByKey(NamespacedKey.minecraft("sweeping_edge")) ?: + CAEnchantment.getByKey(Enchantment.SWEEPING_EDGE.key) } - private lateinit var conflictMap: HashMap> lateinit var conflictList: ArrayList // Read and prepare all conflict fun prepareConflicts(config: ConfigurationSection, itemManager: ItemGroupManager) { - conflictMap = HashMap() conflictList = ArrayList() + // Clear conflict if exist + for (enchant in CAEnchantmentRegistry.getInstance().values()) { + enchant.clearConflict() + } + val keys = config.getKeys(false) for (key in keys) { val section = config.getConfigurationSection(key)!! val conflict = createConflict(section, itemManager, key) - addToMap(conflict) + addConflictToEnchantments(conflict) conflictList.add(conflict) } } - // Add the conflict to the map - private fun addToMap(conflict: EnchantConflictGroup) { + // Add the conflict to enchantments + private fun addConflictToEnchantments(conflict: EnchantConflictGroup) { conflict.getEnchants().forEach { enchant -> - addConflictToConflictMap(enchant, conflict) + enchant.addConflict(conflict) } } - fun addConflictToConflictMap(enchant: WrappedEnchantment, conflict: EnchantConflictGroup) { - if (!conflictMap.containsKey(enchant)) { - conflictMap[enchant] = ArrayList() - } - conflictMap[enchant]!!.add(conflict) - } - - fun removeConflictFromMap(enchant: WrappedEnchantment, conflict: EnchantConflictGroup): Boolean { - return conflictMap[enchant]!!.remove(conflict) - } - // create and read a conflict from a yaml section private fun createConflict( section: ConfigurationSection, @@ -85,14 +81,14 @@ class EnchantConflictManager { for (enchantName in enchantList) { val enchant = getEnchantByName(enchantName) if (enchant == null) { - if (!futureUse) { + if (!futureUse) { //TODO future use will be deprecated once the new update system is finished CustomAnvil.instance.logger.warning("Enchantment $enchantName do not exist but was asked for conflict $conflictName") } continue } conflict.addEnchantment(enchant) } - if (conflict.getEnchants().size == 0) { + if (conflict.getEnchants().isEmpty()) { if (!futureUse) { //TODO future use will be deprecated once the new update system is finished CustomAnvil.instance.logger.warning("Conflict $conflictName do not have valid enchantment, it will not do anything") } @@ -101,7 +97,7 @@ class EnchantConflictManager { return conflict } - private fun getEnchantByName(enchantName: String): WrappedEnchantment? { + private fun getEnchantByName(enchantName: String): CAEnchantment? { // Temporary solution for 1.20.5 when(enchantName){ @@ -110,7 +106,7 @@ class EnchantConflictManager { } } - return WrappedEnchantment.getByName(enchantName) + return CAEnchantment.getByName(enchantName) } @@ -151,35 +147,87 @@ class EnchantConflictManager { return group } - fun isConflicting(base: Set, mat: Material, newEnchant: WrappedEnchantment): ConflictType { + fun isConflicting(appliedEnchants: Map, item: ItemStack, newEnchant: CAEnchantment): ConflictType { + val mat = item.type CustomAnvil.verboseLog("Testing conflict for ${newEnchant.key} on ${mat.key}") - val conflictList = conflictMap[newEnchant] ?: return ConflictType.NO_CONFLICT - CustomAnvil.verboseLog("Did not get skipped") + val conflictList = newEnchant.conflicts var result = ConflictType.NO_CONFLICT for (conflict in conflictList) { CustomAnvil.verboseLog("Is against $conflict") - val allowed = conflict.allowed(base, mat) + val allowed = conflict.allowed(appliedEnchants.keys, mat) CustomAnvil.verboseLog("Was against $conflict and conflicting: ${!allowed} ") if (!allowed) { if (conflict.getEnchants().size <= 1) { - result = ConflictType.SMALL_CONFLICT + result = ConflictType.ITEM_CONFLICT CustomAnvil.verboseLog("Small conflict, continuing") } else { CustomAnvil.verboseLog("Big conflict, probably stoping") - return ConflictType.BIG_CONFLICT + return ConflictType.ENCHANTMENT_CONFLICT } } } - return result + + val immutableEnchants = Collections.unmodifiableMap(appliedEnchants) + for (appliedEnchant in appliedEnchants) { + if(appliedEnchant is AdditionalTestEnchantment){ + val doConflict = appliedEnchant.isEnchantConflict(immutableEnchants, mat) + if(doConflict){ + return ConflictType.ENCHANTMENT_CONFLICT + } +; + } + } + + if((result != ConflictType.ITEM_CONFLICT) && (newEnchant is AdditionalTestEnchantment)){ + val partialItem = createPartialResult(item, immutableEnchants) + + if(newEnchant.isItemConflict(immutableEnchants, mat, partialItem)){ + return ConflictType.ITEM_CONFLICT + } + + } + + return result; + } + + private fun createPartialResult(item: ItemStack, enchantments: Map): ItemStack { + val newItem = item.clone() + + CAEnchantment.clearEnchants(newItem) + enchantments.forEach{//TODO maybe bulk add if possible + enchantment -> enchantment.key.addEnchantmentUnsafe(newItem, enchantment.value) + } + + return newItem } } -enum class ConflictType { - NO_CONFLICT, - SMALL_CONFLICT, - BIG_CONFLICT +/** + * Provide information about the current conflict. + */ +enum class ConflictType(private val importance: Int) { + /** + * Allowed to proceed the anvil process. + */ + NO_CONFLICT(0), + /** + * Inform that the anvil process should not change the current applied enchantment. + */ + ITEM_CONFLICT(1), + + /** + * Inform that the anvil process should not change the current applied enchantment. + * Also add sacrificeIllegalCost for every enchantment marked as big conflict. + */ + ENCHANTMENT_CONFLICT(2); + + fun getWorstConflict(otherConflict: ConflictType): ConflictType { + return if(this.importance > otherConflict.importance) this + else otherConflict + + } } \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5575db9..73e4029 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,14 +1,13 @@ main: io.delilaheve.CustomAnvil name: CustomAnvil prefix: "Custom Anvil" -version: 1.5.0 +version: 1.5.1 description: Allow to customise anvil mechanics api-version: 1.16 load: POSTWORLD authors: [ DelilahEve, alexcrea ] libraries: - - org.jetbrains.kotlin:kotlin-stdlib:1.6.21 - - com.github.stefvanschie.inventoryframework:IF:0.10.14 + - org.jetbrains.kotlin:kotlin-stdlib:1.9.24 commands: anvilconfigreload: @@ -47,3 +46,5 @@ softdepend: - UnsafeEnchantsPlus - ProtocolLib - EnchantsSquared + - EcoEnchants + - eco \ No newline at end of file