diff --git a/config/checkstyle/suppression.xml b/config/checkstyle/suppression.xml index 4821bb6e..86f19c96 100644 --- a/config/checkstyle/suppression.xml +++ b/config/checkstyle/suppression.xml @@ -19,6 +19,7 @@ + diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantDisplay.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantDisplay.java index f4b11427..79a6d1be 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantDisplay.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantDisplay.java @@ -6,18 +6,21 @@ import com.willfp.eco.core.display.Display; import com.willfp.eco.core.display.DisplayModule; import com.willfp.eco.core.display.DisplayPriority; import com.willfp.eco.core.fast.FastItemStack; +import com.willfp.eco.util.StringUtils; import com.willfp.ecoenchants.display.options.DisplayOptions; import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget; import com.willfp.ecoenchants.enchantments.util.ItemConversionOptions; import lombok.Getter; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.EnchantmentStorageMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.HashMap; @@ -73,8 +76,10 @@ public class EnchantDisplay extends DisplayModule { EnchantmentCache.update(); } + @SuppressWarnings("checkstyle:OperatorWrap") @Override protected void display(@NotNull final ItemStack itemStack, + @Nullable final Player player, @NotNull final Object... args) { if (options.isRequireTarget()) { if (!EnchantmentTarget.ALL.getMaterials().contains(itemStack.getType())) { @@ -102,6 +107,7 @@ public class EnchantDisplay extends DisplayModule { List itemLore = fastItemStack.getLore(); List lore = new ArrayList<>(); + List requirementLore = new ArrayList<>(); LinkedHashMap enchantments = new LinkedHashMap<>(fastItemStack.getEnchantmentsOnItem(true)); @@ -118,7 +124,9 @@ public class EnchantDisplay extends DisplayModule { unsorted.forEach(enchantment -> enchantments.put(enchantment, tempEnchantments.get(enchantment))); enchantments.forEach((enchantment, level) -> { - String name = EnchantmentCache.getEntry(enchantment).getNameWithLevel(level); + String name = player == null + ? EnchantmentCache.getEntry(enchantment).getNameWithLevel(level) + : EnchantmentCache.getEntry(enchantment).getNameWithLevel(level, player); lore.add(Display.PREFIX + name); if (!options.getDescriptionOptions().isShowingAtBottom()) { @@ -126,6 +134,10 @@ public class EnchantDisplay extends DisplayModule { lore.addAll(EnchantmentCache.getEntry(enchantment).getDescription(level)); } } + + if (player != null) { + requirementLore.addAll(StringUtils.formatList(EnchantmentCache.getEntry(enchantment).getRequirementLore(), player)); + } }); if (options.getShrinkOptions().isEnabled() && (enchantments.size() > options.getShrinkOptions().getThreshold())) { @@ -158,6 +170,7 @@ public class EnchantDisplay extends DisplayModule { } else { lore.addAll(0, itemLore); } + lore.addAll(requirementLore); itemStack.setItemMeta(meta); fastItemStack.setLore(lore); diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantmentCache.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantmentCache.java index c31598f5..ee2d8d6e 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantmentCache.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/EnchantmentCache.java @@ -18,6 +18,7 @@ import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.EnchantmentWrapper; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -206,6 +207,9 @@ public class EnchantmentCache { @Getter private final EnchantmentType type; + @Getter + private final List requirementLore; + /** * The rarity of the enchantment. */ @@ -225,6 +229,12 @@ public class EnchantmentCache { this.type = type; this.rarity = rarity; this.stringDescription = new HashMap<>(); + this.requirementLore = new ArrayList<>(); + if (enchantment instanceof EcoEnchant ecoEnchant) { + for (String s : ecoEnchant.getRequirementLore()) { + requirementLore.add(Display.PREFIX + s); + } + } for (Integer level : description.keySet()) { StringBuilder descriptionBuilder = new StringBuilder(); @@ -240,6 +250,32 @@ public class EnchantmentCache { } } + /** + * Get the name with the level for a player. + * + * @param level The level. + * @param player The player. + * @return The name with the level for the player. + */ + public String getNameWithLevel(final int level, + @NotNull final Player player) { + String name = getNameWithLevel(level); + if (enchantment instanceof EcoEnchant enchant) { + boolean meets = enchant.doesPlayerMeetRequirement(player); + if (meets) { + return name; + } + + String color = PLUGIN.getDisplayModule().getOptions().getRequirementsOptions().getRequirementColor(); + if (color.contains("{}")) { + name = name.replace("{}", name); + } else { + name = color + name; + } + } + return name; + } + /** * Get enchantment with level. * diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/DisplayOptions.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/DisplayOptions.java index c3e4bd9a..6d3c8e7f 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/DisplayOptions.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/DisplayOptions.java @@ -39,6 +39,11 @@ public class DisplayOptions extends PluginDependent { */ @Getter private final MaxLevelOptions maxLevelOptions = new MaxLevelOptions(this.getPlugin()); + /** + * The requirements options being used. + */ + @Getter + private final RequirementsOptions requirementsOptions = new RequirementsOptions(this.getPlugin()); /** * The enchantment types, sorted according to config. */ @@ -86,6 +91,7 @@ public class DisplayOptions extends PluginDependent { numbersOptions.update(); shrinkOptions.update(); maxLevelOptions.update(); + requirementsOptions.update(); sortedTypes.clear(); sortedTypes.addAll(this.getPlugin().getConfigYml().getStrings("lore.type-ordering").stream() diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/RequirementsOptions.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/RequirementsOptions.java new file mode 100644 index 00000000..7b73e6ff --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/display/options/RequirementsOptions.java @@ -0,0 +1,32 @@ +package com.willfp.ecoenchants.display.options; + +import com.willfp.eco.core.EcoPlugin; +import com.willfp.eco.core.PluginDependent; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +public class RequirementsOptions extends PluginDependent { + /** + * If numerals should be used. + *

+ * If false then numbers will be used instead. + */ + @Getter + private String requirementColor; + + /** + * Create new numbers options. + * + * @param plugin EcoEnchants. + */ + public RequirementsOptions(@NotNull final EcoPlugin plugin) { + super(plugin); + } + + /** + * Update the options. + */ + public void update() { + requirementColor = this.getPlugin().getLangYml().getString("missing-requirements-format", false); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java index ab70b6b3..acc2a2cb 100644 --- a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/EcoEnchant.java @@ -6,6 +6,8 @@ import com.willfp.ecoenchants.config.configs.EnchantmentConfig; import com.willfp.ecoenchants.enchantments.meta.EnchantmentRarity; import com.willfp.ecoenchants.enchantments.meta.EnchantmentTarget; import com.willfp.ecoenchants.enchantments.meta.EnchantmentType; +import com.willfp.ecoenchants.enchantments.meta.requirements.EnchantmentRequirement; +import com.willfp.ecoenchants.enchantments.meta.requirements.EnchantmentRequirements; import com.willfp.ecoenchants.enchantments.util.EnchantmentUtils; import com.willfp.ecoenchants.enchantments.util.Watcher; import lombok.AccessLevel; @@ -17,6 +19,7 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; import org.bukkit.permissions.Permission; @@ -26,10 +29,13 @@ import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; @SuppressWarnings({"deprecation", "RedundantSuppression"}) @@ -146,6 +152,22 @@ public abstract class EcoEnchant extends Enchantment implements Listener, Watche */ private final List flags = new ArrayList<>(); + /** + * All the requirements needed in order to use the enchantment. + */ + private final Map> requirements = new HashMap<>(); + + /** + * Cached players to see if they meet requirements. + */ + private final Map cachedRequirements = new HashMap<>(); + + /** + * The requirement lore shown if the player doesn't meet the requirements. + */ + @Getter + private final List requirementLore = new ArrayList<>(); + /** * Create a new EcoEnchant. * @@ -221,9 +243,27 @@ public abstract class EcoEnchant extends Enchantment implements Listener, Watche flags.clear(); flags.addAll(config.getStrings(EcoEnchants.GENERAL_LOCATION + "flags")); EnchantmentUtils.registerPlaceholders(this); + for (String req : config.getStrings(EcoEnchants.GENERAL_LOCATION + "requirements.list", false)) { + List split = Arrays.asList(req.split(":")); + if (split.size() < 2) { + continue; + } + + EnchantmentRequirement requirement = EnchantmentRequirements.getByID(split.get(0).toLowerCase()); + + if (requirement == null) { + continue; + } + + this.requirements.put(requirement, split.subList(1, split.size() - 1)); + } + requirementLore.clear(); + requirementLore.addAll(config.getStrings("requirements.not-met-lore", false)); postUpdate(); this.register(); + + this.getPlugin().getScheduler().runTimer(this.cachedRequirements::clear, 3000, 3000); } protected void postUpdate() { @@ -248,6 +288,28 @@ public abstract class EcoEnchant extends Enchantment implements Listener, Watche return "unknown"; } + /** + * Does the player meet the requirements to use this enchantment. + * + * @param player The player. + * @return If the requirements are met. + */ + public boolean doesPlayerMeetRequirement(@NotNull final Player player) { + if (cachedRequirements.containsKey(player.getUniqueId())) { + return cachedRequirements.get(player.getUniqueId()); + } + + for (Map.Entry> entry : requirements.entrySet()) { + if (!entry.getKey().doesPlayerMeet(player, entry.getValue())) { + cachedRequirements.put(player.getUniqueId(), false); + return false; + } + } + + cachedRequirements.put(player.getUniqueId(), true); + return true; + } + /** * Get description of enchantment line-wrapped. * diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/EnchantmentRequirement.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/EnchantmentRequirement.java new file mode 100644 index 00000000..3eef6341 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/EnchantmentRequirement.java @@ -0,0 +1,31 @@ +package com.willfp.ecoenchants.enchantments.meta.requirements; + +import lombok.Getter; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public abstract class EnchantmentRequirement { + /** + * The ID of the requirement. + */ + @Getter + private final String id; + + protected EnchantmentRequirement(@NotNull final String id) { + this.id = id; + + EnchantmentRequirements.addNewRequirement(this); + } + + /** + * Test if the player meets the requirement. + * + * @param player The player. + * @param args The arguments. + * @return The requirement. + */ + public abstract boolean doesPlayerMeet(@NotNull Player player, + @NotNull List args); +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/EnchantmentRequirements.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/EnchantmentRequirements.java new file mode 100644 index 00000000..e7907519 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/EnchantmentRequirements.java @@ -0,0 +1,68 @@ +package com.willfp.ecoenchants.enchantments.meta.requirements; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.ImmutableList; +import com.willfp.ecoenchants.enchantments.EcoEnchant; +import com.willfp.ecoenchants.enchantments.meta.requirements.requirements.RequirementHasPermission; +import com.willfp.ecoenchants.enchantments.meta.requirements.requirements.RequirementPlaceholderEquals; +import com.willfp.ecoenchants.enchantments.meta.requirements.requirements.RequirementPlaceholderGreaterThan; +import com.willfp.ecoenchants.enchantments.meta.requirements.requirements.RequirementPlaceholderLessThan; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +@UtilityClass +@SuppressWarnings({"unused", "checkstyle:JavadocVariable"}) +public class EnchantmentRequirements { + /** + * All registered requirements. + */ + private static final BiMap BY_ID = HashBiMap.create(); + + public static final EnchantmentRequirement HAS_PERMISSION = new RequirementHasPermission(); + public static final EnchantmentRequirement PLACEHOLDER_EQUALS = new RequirementPlaceholderEquals(); + public static final EnchantmentRequirement PLACEHOLDER_GREATER_THAN = new RequirementPlaceholderGreaterThan(); + public static final EnchantmentRequirement PLACEHOLDER_LESS_THAN = new RequirementPlaceholderLessThan(); + + /** + * Get all registered {@link EcoEnchant}s. + * + * @return A list of all {@link EcoEnchant}s. + */ + public static List values() { + return ImmutableList.copyOf(BY_ID.values()); + } + + /** + * Get {@link EnchantmentRequirement} matching ID. + * + * @param name The ID to search for. + * @return The matching {@link EnchantmentRequirement}, or null if not found. + */ + public static EnchantmentRequirement getByID(@NotNull final String name) { + return BY_ID.get(name); + } + + /** + * Add new {@link EnchantmentRequirement} to EcoEnchants. + *

+ * Only for internal use, requirements are automatically added in the constructor. + * + * @param req The {@link EnchantmentRequirement} to add. + */ + public static void addNewRequirement(@NotNull final EnchantmentRequirement req) { + BY_ID.inverse().remove(req); + BY_ID.put(req.getId(), req); + } + + /** + * Remove {@link EnchantmentRequirement} from EcoEnchants. + * + * @param req The {@link EnchantmentRequirement} to remove. + */ + public static void removeRequirement(@NotNull final EnchantmentRequirement req) { + BY_ID.inverse().remove(req); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementHasPermission.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementHasPermission.java new file mode 100644 index 00000000..671833d0 --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementHasPermission.java @@ -0,0 +1,23 @@ +package com.willfp.ecoenchants.enchantments.meta.requirements.requirements; + +import com.willfp.ecoenchants.enchantments.meta.requirements.EnchantmentRequirement; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class RequirementHasPermission extends EnchantmentRequirement { + /** + * Create new requirement. + */ + public RequirementHasPermission() { + super("has-permission"); + } + + @Override + public boolean doesPlayerMeet(@NotNull final Player player, + @NotNull final List args) { + String permission = args.get(0); + return player.hasPermission(permission); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderEquals.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderEquals.java new file mode 100644 index 00000000..cd76e1be --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderEquals.java @@ -0,0 +1,26 @@ +package com.willfp.ecoenchants.enchantments.meta.requirements.requirements; + +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; +import com.willfp.ecoenchants.enchantments.meta.requirements.EnchantmentRequirement; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class RequirementPlaceholderEquals extends EnchantmentRequirement { + /** + * Create new requirement. + */ + public RequirementPlaceholderEquals() { + super("placeholder-equals"); + } + + @Override + public boolean doesPlayerMeet(@NotNull final Player player, + @NotNull final List args) { + String placeholder = args.get(0); + String equals = args.get(1); + + return PlaceholderManager.translatePlaceholders(placeholder, player).equalsIgnoreCase(equals); + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderGreaterThan.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderGreaterThan.java new file mode 100644 index 00000000..4e9d24ec --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderGreaterThan.java @@ -0,0 +1,30 @@ +package com.willfp.ecoenchants.enchantments.meta.requirements.requirements; + +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; +import com.willfp.ecoenchants.enchantments.meta.requirements.EnchantmentRequirement; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class RequirementPlaceholderGreaterThan extends EnchantmentRequirement { + /** + * Create new requirement. + */ + public RequirementPlaceholderGreaterThan() { + super("placeholder-greater-than"); + } + + @Override + public boolean doesPlayerMeet(@NotNull final Player player, + @NotNull final List args) { + String placeholder = args.get(0); + double equals = Double.parseDouble(args.get(1)); + + try { + return Double.parseDouble(PlaceholderManager.translatePlaceholders(placeholder, player)) >= equals; + } catch (NumberFormatException e) { + return false; + } + } +} diff --git a/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderLessThan.java b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderLessThan.java new file mode 100644 index 00000000..41ab9dbb --- /dev/null +++ b/eco-core/core-plugin/src/main/java/com/willfp/ecoenchants/enchantments/meta/requirements/requirements/RequirementPlaceholderLessThan.java @@ -0,0 +1,30 @@ +package com.willfp.ecoenchants.enchantments.meta.requirements.requirements; + +import com.willfp.eco.core.integrations.placeholder.PlaceholderManager; +import com.willfp.ecoenchants.enchantments.meta.requirements.EnchantmentRequirement; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class RequirementPlaceholderLessThan extends EnchantmentRequirement { + /** + * Create new requirement. + */ + public RequirementPlaceholderLessThan() { + super("placeholder-less-than"); + } + + @Override + public boolean doesPlayerMeet(@NotNull final Player player, + @NotNull final List args) { + String placeholder = args.get(0); + double equals = Double.parseDouble(args.get(1)); + + try { + return Double.parseDouble(PlaceholderManager.translatePlaceholders(placeholder, player)) < equals; + } catch (NumberFormatException e) { + return false; + } + } +} diff --git a/eco-core/core-plugin/src/main/resources/enchants/normal/abattoir.yml b/eco-core/core-plugin/src/main/resources/enchants/normal/abattoir.yml index 5528ba0c..e0baec19 100644 --- a/eco-core/core-plugin/src/main/resources/enchants/normal/abattoir.yml +++ b/eco-core/core-plugin/src/main/resources/enchants/normal/abattoir.yml @@ -26,6 +26,12 @@ general-config: - impaling maximum-level: 5 disabled-in-worlds: [ ] + requirements: + list: + - 'has-permission:ecoenchants.testpermission' + not-met-lore: + - "&f" + - "&cNo bueno" config: multiplier: 0.4 # Formula is (multiplier * (level + 1) + 1)*damage | Power is 0.25 \ No newline at end of file diff --git a/eco-core/core-plugin/src/main/resources/lang.yml b/eco-core/core-plugin/src/main/resources/lang.yml index 7b711a7d..c72fbe5a 100644 --- a/eco-core/core-plugin/src/main/resources/lang.yml +++ b/eco-core/core-plugin/src/main/resources/lang.yml @@ -34,6 +34,8 @@ messages: no-targets: "&cCannot be applied" no-conflicts: "&cNo conflicts" +missing-requirements-format: "&m" + curse-color: "&c" normal-color: "&7" special-color: "{}&d"