diff --git a/pom.xml b/pom.xml index 27fe408..4a061c4 100644 --- a/pom.xml +++ b/pom.xml @@ -24,17 +24,19 @@ - - apache.snapshots - https://repository.apache.org/snapshots/ - - spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + apache.snapshots + https://repository.apache.org/snapshots/ + + + org.spigotmc diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java b/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java index 1f549b9..efd0710 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/ConfigLoader.java @@ -11,10 +11,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; +import java.util.*; import java.util.logging.Level; public class ConfigLoader @@ -37,7 +34,7 @@ public class ConfigLoader private boolean useTierDurability; private boolean dropNetheriteAsChestplate; private LinkedHashSet allowedEnchantments; - private boolean allowMultipleProtectionEnchantments; + private List> mutuallyExclusiveEnchantments; private boolean craftingInSmithingTable; private boolean allowUpgradeToNetherite; private boolean bypassWearPerm; @@ -81,11 +78,22 @@ public class ConfigLoader { "List of enchantments that are allowed to be put on an armored elytra.", "If you do not want to allow any enchantments at all, remove them all and add \"NONE\"", - "You can find supported enchantments here:", - "https://github.com/PimvanderLoos/ArmoredElytra/blob/master/vanillaEnchantments", + "You can find supported enchantments by running the command:", + "\"armoredelytra listAvailableEnchantments\" in console", "If you install additional enchantment plugins, you can add their enchantments as well.", "Just add their 'NamespacedKey'. Ask the enchantment plugin dev for more info if you need it." }; + String[] mutuallyExclusiveEnchantmentsComment = + { + "The lists of enchantments that are mutually exclusive.", + "Each group [] on this list is treated as mutually exclusive, so only one of them can be on an ArmoredElytra.", + "The default follows modern vanilla rules by making the different types of protection mutually exclusive.", + "If you do not want any enchantments to be mutually exclusive, replace all the entries in this list with \"[]\"", + "You can find supported enchantments by running the command:", + "\"armoredelytra listAvailableEnchantments\" in console", + "If you install additional enchant plugins, you can make their enchantments mutually exclusive as well.", + "Just add their 'NamespacedKey'. Ask the enchantment plugin dev for more info if you need it." + }; String[] dropNetheriteAsChestplateComment = { "Whether to drop Netherite Armored Elytras as netherite chestplates when they are dropped", @@ -120,16 +128,6 @@ public class ConfigLoader { "Specify a language file to be used." }; - String[] allowMultipleProtectionEnchantmentsComment = - { - "Allow more than 1 type of protection enchantment on a single armored elytra. ", - "If true, you could have both blast protection and environmental protection at the same time.", - "If false, the second enchantment (while crafting) will override the first. So combining an armored", - "elytra that has the protection enchantment with an enchanted book that " + - "has the blast protection enchantment", - "would result in removal of the protection enchantment and addition of the " + - "blast protection enchantment." - }; String[] permissionsComment = { "Globally bypass permissions for wearing and/or crafting armored elytras.", @@ -164,6 +162,14 @@ public class ConfigLoader "minecraft:thorns", "minecraft:binding_curse", "minecraft:vanishing_curse", "minecraft:mending")); + // Set a default list of lists of mutually exclusive enchantments + // Default only has a list for the protection enchantments + List> defaultMutuallyExclusiveEnchantments = new ArrayList<>(); + defaultMutuallyExclusiveEnchantments.add(List.of("minecraft:protection", + "minecraft:projectile_protection", + "minecraft:blast_protection", + "minecraft:fire_protection")); + FileConfiguration config = plugin.getConfig(); @@ -199,8 +205,11 @@ public class ConfigLoader allowedEnchantments = new LinkedHashSet<>(); defaultAllowedEnchantments.forEach(this::addNameSpacedKey); - allowMultipleProtectionEnchantments = addNewConfigOption(config, "allowMultipleProtectionEnchantments", false, - allowMultipleProtectionEnchantmentsComment); + defaultMutuallyExclusiveEnchantments = addNewConfigOption(config, "mutuallyExclusiveEnchantments", + defaultMutuallyExclusiveEnchantments, mutuallyExclusiveEnchantmentsComment); + mutuallyExclusiveEnchantments = new LinkedList<>(); + defaultMutuallyExclusiveEnchantments.forEach(this::addMutuallyExclusiveEnchantments); + allowAddingEnchantments = addNewConfigOption(config, "allowAddingEnchantments", true, allowAddingEnchantmentsComment); allowRenaming = addNewConfigOption(config, "allowRenaming", true, allowRenamingComment); @@ -244,6 +253,35 @@ public class ConfigLoader } } + private void addMutuallyExclusiveEnchantments(List fullKeys) + { + List enchantments = new LinkedList<>(); + for (String fullKey : fullKeys) { + try { + final String[] keyParts = fullKey.strip().split(":", 2); + if (keyParts.length < 2) + { + Bukkit.getLogger().warning("\"" + fullKey + "\" is not a valid NamespacedKey!"); + return; + } + //noinspection deprecation + final NamespacedKey key = new NamespacedKey(keyParts[0], keyParts[1]); + final Enchantment enchantment = Enchantment.getByKey(key); + if (enchantment == null) + { + Bukkit.getLogger().warning("The enchantment \"" + fullKey + "\" could not be found!"); + return; + } + enchantments.add(enchantment); + } + catch (Exception e) + { + plugin.getLogger().log(Level.WARNING, e, () -> "Failed to register NamespacedKey key: '" + fullKey + "'"); + } + } + mutuallyExclusiveEnchantments.add(enchantments); + } + private T addNewConfigOption(FileConfiguration config, String optionName, T defaultValue, String[] comment) { ConfigOption option = new ConfigOption<>(plugin, config, optionName, defaultValue, comment); @@ -318,11 +356,6 @@ public class ConfigLoader return repairCounts[armorTier.ordinal()]; } - public boolean allowMultipleProtectionEnchantments() - { - return allowMultipleProtectionEnchantments; - } - public boolean allowRenaming() { return allowRenaming; @@ -358,6 +391,11 @@ public class ConfigLoader return allowedEnchantments; } + public List> getMutuallyExclusiveEnchantments() + { + return mutuallyExclusiveEnchantments; + } + public boolean bypassWearPerm() { return bypassWearPerm; diff --git a/src/main/java/nl/pim16aap2/armoredElytra/util/EnchantmentContainer.java b/src/main/java/nl/pim16aap2/armoredElytra/util/EnchantmentContainer.java index 57fb876..3d5a640 100644 --- a/src/main/java/nl/pim16aap2/armoredElytra/util/EnchantmentContainer.java +++ b/src/main/java/nl/pim16aap2/armoredElytra/util/EnchantmentContainer.java @@ -6,11 +6,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.util.*; public class EnchantmentContainer implements Iterable> { @@ -27,6 +23,7 @@ public class EnchantmentContainer implements IterableThis does not include the provided enchantment + * + * @param enchantment The enchantment to get the mutually exclusives of + * @return A linked list containing all the mutually exclusive enchantments + */ + private static List getMutuallyExclusiveEnchantments(Enchantment enchantment) + { + List enchantments = new LinkedList<>(); + for (List mutuallyExclusiveEnchantments : ArmoredElytra.getInstance().getConfigLoader().getMutuallyExclusiveEnchantments()) + for (Enchantment mutuallyExclusiveEnchantment : mutuallyExclusiveEnchantments) + if (mutuallyExclusiveEnchantment.equals(enchantment)) + { + enchantments.addAll(mutuallyExclusiveEnchantments.stream() + .filter(i -> !i.equals(enchantment)).toList()); + break; + } + return enchantments; + } + /** * Gets the total number of enchantments in this container. * @@ -116,6 +134,21 @@ public class EnchantmentContainer implements IterableFirst instance of a mutually exclusive enchantment gets priority + */ + public void filterMutuallyExclusive() + { + final List disallowedEnchantments = new LinkedList<>(); + for (Map.Entry entry : enchantments.entrySet()) + { + if (disallowedEnchantments.contains(entry.getKey())) continue; + disallowedEnchantments.addAll(getMutuallyExclusiveEnchantments(entry.getKey())); + } + disallowedEnchantments.forEach(enchantments.keySet()::remove); + } + /** * Applies the enchantments to an itemstack. * @@ -123,6 +156,10 @@ public class EnchantmentContainer implements Iterable blackList = + second.keySet().stream() + .flatMap(ench -> getMutuallyExclusiveEnchantments(ench).stream()) + .toList(); + blackList.forEach(first.keySet()::remove); + final Map combined = new HashMap<>(first); for (Map.Entry entry : second.entrySet()) { - Integer enchantLevel = first.get(entry.getKey()); + // Check for enchants with higher level + Integer enchantLevel = combined.get(entry.getKey()); if (enchantLevel != null) { if (entry.getValue().equals(enchantLevel) && entry.getValue() < entry.getKey().getMaxLevel()) @@ -194,7 +238,7 @@ public class EnchantmentContainer implements Iterable