Merge pull request #5 from bonn2/feature-mutually-exclusive-enchants
Add mutuallyExclusiveEnchantments config option
This commit is contained in:
commit
ccdd5b9af1
12
pom.xml
12
pom.xml
@ -24,17 +24,19 @@
|
|||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
|
||||||
<id>apache.snapshots</id>
|
|
||||||
<url>https://repository.apache.org/snapshots/</url>
|
|
||||||
</repository>
|
|
||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>spigot-repo</id>
|
<id>spigot-repo</id>
|
||||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
<pluginRepositories>
|
||||||
|
<pluginRepository>
|
||||||
|
<id>apache.snapshots</id>
|
||||||
|
<url>https://repository.apache.org/snapshots/</url>
|
||||||
|
</pluginRepository>
|
||||||
|
</pluginRepositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
|
@ -11,10 +11,7 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class ConfigLoader
|
public class ConfigLoader
|
||||||
@ -37,7 +34,7 @@ public class ConfigLoader
|
|||||||
private boolean useTierDurability;
|
private boolean useTierDurability;
|
||||||
private boolean dropNetheriteAsChestplate;
|
private boolean dropNetheriteAsChestplate;
|
||||||
private LinkedHashSet<Enchantment> allowedEnchantments;
|
private LinkedHashSet<Enchantment> allowedEnchantments;
|
||||||
private boolean allowMultipleProtectionEnchantments;
|
private List<List<Enchantment>> mutuallyExclusiveEnchantments;
|
||||||
private boolean craftingInSmithingTable;
|
private boolean craftingInSmithingTable;
|
||||||
private boolean allowUpgradeToNetherite;
|
private boolean allowUpgradeToNetherite;
|
||||||
private boolean bypassWearPerm;
|
private boolean bypassWearPerm;
|
||||||
@ -81,11 +78,22 @@ public class ConfigLoader
|
|||||||
{
|
{
|
||||||
"List of enchantments that are allowed to be put on an armored elytra.",
|
"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\"",
|
"If you do not want to allow any enchantments at all, remove them all and add \"NONE\"",
|
||||||
"You can find supported enchantments here:",
|
"You can find supported enchantments by running the command:",
|
||||||
"https://github.com/PimvanderLoos/ArmoredElytra/blob/master/vanillaEnchantments",
|
"\"armoredelytra listAvailableEnchantments\" in console",
|
||||||
"If you install additional enchantment plugins, you can add their enchantments as well.",
|
"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."
|
"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 =
|
String[] dropNetheriteAsChestplateComment =
|
||||||
{
|
{
|
||||||
"Whether to drop Netherite Armored Elytras as netherite chestplates when they are dropped",
|
"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."
|
"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 =
|
String[] permissionsComment =
|
||||||
{
|
{
|
||||||
"Globally bypass permissions for wearing and/or crafting armored elytras.",
|
"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:thorns", "minecraft:binding_curse", "minecraft:vanishing_curse",
|
||||||
"minecraft:mending"));
|
"minecraft:mending"));
|
||||||
|
|
||||||
|
// Set a default list of lists of mutually exclusive enchantments
|
||||||
|
// Default only has a list for the protection enchantments
|
||||||
|
List<List<String>> defaultMutuallyExclusiveEnchantments = new ArrayList<>();
|
||||||
|
defaultMutuallyExclusiveEnchantments.add(List.of("minecraft:protection",
|
||||||
|
"minecraft:projectile_protection",
|
||||||
|
"minecraft:blast_protection",
|
||||||
|
"minecraft:fire_protection"));
|
||||||
|
|
||||||
FileConfiguration config = plugin.getConfig();
|
FileConfiguration config = plugin.getConfig();
|
||||||
|
|
||||||
|
|
||||||
@ -199,8 +205,11 @@ public class ConfigLoader
|
|||||||
allowedEnchantments = new LinkedHashSet<>();
|
allowedEnchantments = new LinkedHashSet<>();
|
||||||
defaultAllowedEnchantments.forEach(this::addNameSpacedKey);
|
defaultAllowedEnchantments.forEach(this::addNameSpacedKey);
|
||||||
|
|
||||||
allowMultipleProtectionEnchantments = addNewConfigOption(config, "allowMultipleProtectionEnchantments", false,
|
defaultMutuallyExclusiveEnchantments = addNewConfigOption(config, "mutuallyExclusiveEnchantments",
|
||||||
allowMultipleProtectionEnchantmentsComment);
|
defaultMutuallyExclusiveEnchantments, mutuallyExclusiveEnchantmentsComment);
|
||||||
|
mutuallyExclusiveEnchantments = new LinkedList<>();
|
||||||
|
defaultMutuallyExclusiveEnchantments.forEach(this::addMutuallyExclusiveEnchantments);
|
||||||
|
|
||||||
allowAddingEnchantments = addNewConfigOption(config, "allowAddingEnchantments", true,
|
allowAddingEnchantments = addNewConfigOption(config, "allowAddingEnchantments", true,
|
||||||
allowAddingEnchantmentsComment);
|
allowAddingEnchantmentsComment);
|
||||||
allowRenaming = addNewConfigOption(config, "allowRenaming", true, allowRenamingComment);
|
allowRenaming = addNewConfigOption(config, "allowRenaming", true, allowRenamingComment);
|
||||||
@ -244,6 +253,35 @@ public class ConfigLoader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addMutuallyExclusiveEnchantments(List<String> fullKeys)
|
||||||
|
{
|
||||||
|
List<Enchantment> 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> T addNewConfigOption(FileConfiguration config, String optionName, T defaultValue, String[] comment)
|
private <T> T addNewConfigOption(FileConfiguration config, String optionName, T defaultValue, String[] comment)
|
||||||
{
|
{
|
||||||
ConfigOption<T> option = new ConfigOption<>(plugin, config, optionName, defaultValue, comment);
|
ConfigOption<T> option = new ConfigOption<>(plugin, config, optionName, defaultValue, comment);
|
||||||
@ -318,11 +356,6 @@ public class ConfigLoader
|
|||||||
return repairCounts[armorTier.ordinal()];
|
return repairCounts[armorTier.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean allowMultipleProtectionEnchantments()
|
|
||||||
{
|
|
||||||
return allowMultipleProtectionEnchantments;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean allowRenaming()
|
public boolean allowRenaming()
|
||||||
{
|
{
|
||||||
return allowRenaming;
|
return allowRenaming;
|
||||||
@ -358,6 +391,11 @@ public class ConfigLoader
|
|||||||
return allowedEnchantments;
|
return allowedEnchantments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<List<Enchantment>> getMutuallyExclusiveEnchantments()
|
||||||
|
{
|
||||||
|
return mutuallyExclusiveEnchantments;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean bypassWearPerm()
|
public boolean bypassWearPerm()
|
||||||
{
|
{
|
||||||
return bypassWearPerm;
|
return bypassWearPerm;
|
||||||
|
@ -6,11 +6,7 @@ import org.bukkit.enchantments.Enchantment;
|
|||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
import org.bukkit.inventory.meta.EnchantmentStorageMeta;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Integer>>
|
public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Integer>>
|
||||||
{
|
{
|
||||||
@ -27,6 +23,7 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
{
|
{
|
||||||
this(enchantments);
|
this(enchantments);
|
||||||
filter(plugin.getConfigLoader().allowedEnchantments());
|
filter(plugin.getConfigLoader().allowedEnchantments());
|
||||||
|
filterMutuallyExclusive();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,6 +92,27 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
return new EnchantmentContainer(meta.getStoredEnchants(), plugin);
|
return new EnchantmentContainer(meta.getStoredEnchants(), plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all enchantments that are mutually exclusive with the provided enchantment.
|
||||||
|
* <br>This does <b>not</b> 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<Enchantment> getMutuallyExclusiveEnchantments(Enchantment enchantment)
|
||||||
|
{
|
||||||
|
List<Enchantment> enchantments = new LinkedList<>();
|
||||||
|
for (List<Enchantment> 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.
|
* Gets the total number of enchantments in this container.
|
||||||
*
|
*
|
||||||
@ -116,6 +134,21 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
enchantments.keySet().retainAll(allowed);
|
enchantments.keySet().retainAll(allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any entries from the list of enchantments that are mutually exclusive to each other.
|
||||||
|
* <br>First instance of a mutually exclusive enchantment gets priority
|
||||||
|
*/
|
||||||
|
public void filterMutuallyExclusive()
|
||||||
|
{
|
||||||
|
final List<Enchantment> disallowedEnchantments = new LinkedList<>();
|
||||||
|
for (Map.Entry<Enchantment, Integer> 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.
|
* Applies the enchantments to an itemstack.
|
||||||
*
|
*
|
||||||
@ -123,6 +156,10 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
*/
|
*/
|
||||||
public void applyEnchantments(final ItemStack is)
|
public void applyEnchantments(final ItemStack is)
|
||||||
{
|
{
|
||||||
|
// Clear enchantments before applying new ones
|
||||||
|
for (Enchantment enchantment : is.getEnchantments().keySet())
|
||||||
|
is.removeEnchantment(enchantment);
|
||||||
|
|
||||||
is.addUnsafeEnchantments(enchantments);
|
is.addUnsafeEnchantments(enchantments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,10 +219,17 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
if (first == null || first.isEmpty())
|
if (first == null || first.isEmpty())
|
||||||
return second;
|
return second;
|
||||||
|
|
||||||
|
final List<Enchantment> blackList =
|
||||||
|
second.keySet().stream()
|
||||||
|
.flatMap(ench -> getMutuallyExclusiveEnchantments(ench).stream())
|
||||||
|
.toList();
|
||||||
|
blackList.forEach(first.keySet()::remove);
|
||||||
|
|
||||||
final Map<Enchantment, Integer> combined = new HashMap<>(first);
|
final Map<Enchantment, Integer> combined = new HashMap<>(first);
|
||||||
for (Map.Entry<Enchantment, Integer> entry : second.entrySet())
|
for (Map.Entry<Enchantment, Integer> 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 (enchantLevel != null)
|
||||||
{
|
{
|
||||||
if (entry.getValue().equals(enchantLevel) && entry.getValue() < entry.getKey().getMaxLevel())
|
if (entry.getValue().equals(enchantLevel) && entry.getValue() < entry.getKey().getMaxLevel())
|
||||||
@ -194,7 +238,7 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
enchantLevel = entry.getValue();
|
enchantLevel = entry.getValue();
|
||||||
|
|
||||||
// If the enchantment level has changed,
|
// If the enchantment level has changed,
|
||||||
if (!enchantLevel.equals(first.get(entry.getKey())))
|
if (!enchantLevel.equals(combined.get(entry.getKey())))
|
||||||
{
|
{
|
||||||
combined.remove(entry.getKey());
|
combined.remove(entry.getKey());
|
||||||
combined.put(entry.getKey(), enchantLevel);
|
combined.put(entry.getKey(), enchantLevel);
|
||||||
@ -204,35 +248,6 @@ public class EnchantmentContainer implements Iterable<Map.Entry<Enchantment, Int
|
|||||||
combined.put(entry.getKey(), entry.getValue());
|
combined.put(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ArmoredElytra.getInstance().getConfigLoader().allowMultipleProtectionEnchantments())
|
|
||||||
{
|
|
||||||
// Get the protection enchantment rating for both enchantment sets.
|
|
||||||
int protVal0 = Util.getProtectionEnchantmentsVal(first);
|
|
||||||
int protVal1 = Util.getProtectionEnchantmentsVal(second);
|
|
||||||
|
|
||||||
// If they have different protection enchantments, keep enchantment1's enchantments
|
|
||||||
// And remove the protection enchantment from enchantments0.
|
|
||||||
if (protVal0 != 0 && protVal1 != 0 && protVal0 != protVal1)
|
|
||||||
switch (protVal0)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
combined.remove(Enchantment.PROTECTION_ENVIRONMENTAL);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
combined.remove(Enchantment.PROTECTION_EXPLOSIONS);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
combined.remove(Enchantment.PROTECTION_FALL);
|
|
||||||
break;
|
|
||||||
case 8:
|
|
||||||
combined.remove(Enchantment.PROTECTION_FIRE);
|
|
||||||
break;
|
|
||||||
case 16:
|
|
||||||
combined.remove(Enchantment.PROTECTION_PROJECTILE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user