From dba36eb12bfc5ee9aab76370832613f37fff94ff Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:30:50 +0000 Subject: [PATCH 1/2] Initial plan From db58af76963dad7dbafeb13a52bc8d07da959977 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Mar 2026 20:42:15 +0000 Subject: [PATCH 2/2] feat: add enchantmentlevel condition type and item_in_hand_enchant placeholder - Add GenesisConditionTypeEnchantmentLevel for checking enchantment levels on item in player's main hand via: type:enchantmentlevel / EFFICIENCY:equals:9 - Register ENCHANTMENTLEVEL in GenesisConditionType.loadTypes() - Add %item_in_hand_enchant_ENCHANTMENTNAME% placeholder in StringManager for use with placeholdernumber conditions and lore display - Handle both regular enchantments and enchantment books (EnchantmentStorageMeta) Co-authored-by: MaksyKun <77341370+MaksyKun@users.noreply.github.com> --- .../core/conditions/GenesisConditionType.java | 4 +- .../GenesisConditionTypeEnchantmentLevel.java | 128 ++++++++++++++++++ .../genesis/managers/misc/StringManager.java | 39 +++++- 3 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionTypeEnchantmentLevel.java diff --git a/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionType.java b/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionType.java index 9d3dc75..f70910d 100644 --- a/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionType.java +++ b/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionType.java @@ -40,7 +40,8 @@ public abstract class GenesisConditionType { WORLD, WEATHER, PLACEHOLDERNUMBER, - PLACEHOLDERMATCH; + PLACEHOLDERMATCH, + ENCHANTMENTLEVEL; private static List types; @@ -77,6 +78,7 @@ public static void loadTypes() { WEATHER = registerType(new GenesisConditionTypeWeather()); PLACEHOLDERNUMBER = registerType(new GenesisConditionTypePlaceholderNumber()); PLACEHOLDERMATCH = registerType(new GenesisConditionTypePlaceholderMatch()); + ENCHANTMENTLEVEL = registerType(new GenesisConditionTypeEnchantmentLevel()); } public static GenesisConditionType registerType(GenesisConditionType type) { diff --git a/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionTypeEnchantmentLevel.java b/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionTypeEnchantmentLevel.java new file mode 100644 index 0000000..1c5262c --- /dev/null +++ b/src/main/java/studio/magemonkey/genesis/core/conditions/GenesisConditionTypeEnchantmentLevel.java @@ -0,0 +1,128 @@ +package studio.magemonkey.genesis.core.conditions; + +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import studio.magemonkey.genesis.core.GenesisBuy; +import studio.magemonkey.genesis.core.GenesisShopHolder; +import studio.magemonkey.genesis.managers.ClassManager; +import studio.magemonkey.genesis.managers.misc.InputReader; +import studio.magemonkey.genesis.misc.Misc; + +public class GenesisConditionTypeEnchantmentLevel extends GenesisConditionType { + + @Override + public boolean meetsCondition(GenesisShopHolder holder, + GenesisBuy shopItem, + Player p, + String conditiontype, + String condition) { + // conditiontype = enchantment name (e.g., "EFFICIENCY") + // condition = "over:5" / "under:3" / "equals:10" / "between:5-10" + + String[] realparts = condition.split(":", 2); + if (realparts.length < 2) { + ClassManager.manager.getBugFinder() + .warn("Unable to read enchantmentlevel condition '" + conditiontype + ":" + condition + + "'. It should look like: '::'. " + + "Example: 'EFFICIENCY:equals:10'."); + return false; + } + + String operator = realparts[0]; + String value = realparts[1]; + double level = getEnchantmentLevel(p, conditiontype); + + if (operator.equalsIgnoreCase("over") || operator.equalsIgnoreCase(">")) { + return level > InputReader.getDouble(value, -1); + } + if (operator.equalsIgnoreCase("under") || operator.equalsIgnoreCase("<") + || operator.equalsIgnoreCase("below")) { + return level < InputReader.getDouble(value, -1); + } + if (operator.equalsIgnoreCase("equals") || operator.equalsIgnoreCase("=")) { + for (String option : value.split(",")) { + if (level == InputReader.getDouble(option.trim(), -1)) { + return true; + } + } + return false; + } + if (operator.equalsIgnoreCase("between") || operator.equalsIgnoreCase("inbetween")) { + String separator = value.contains(":") ? ":" : "-"; + String[] parts = value.split(separator); + if (parts.length == 2) { + double start = InputReader.getDouble(parts[0], -1); + double end = InputReader.getDouble(parts[1], -1); + return level >= start && level <= end; + } else { + ClassManager.manager.getBugFinder() + .warn("Unable to read enchantmentlevel condition '" + conditiontype + ":" + condition + + "' of conditiontype 'between'. " + + "It has to look like following: ':between:-'."); + return false; + } + } + + return false; + } + + /** + * Returns the level of the given enchantment on the item in the player's main hand, + * or 0 if the item does not have the enchantment. + */ + private double getEnchantmentLevel(Player p, String enchantmentName) { + ItemStack item = Misc.getItemInMainHand(p); + if (item == null || item.getType().isAir()) { + return 0; + } + + Enchantment enchantment = InputReader.readEnchantment(enchantmentName); + if (enchantment == null) { + ClassManager.manager.getBugFinder() + .warn("Unknown enchantment '" + enchantmentName + "' in enchantmentlevel condition."); + return 0; + } + + // Check regular item enchantments first + if (item.getEnchantments().containsKey(enchantment)) { + return item.getEnchantments().get(enchantment); + } + + // Fallback: check enchantment books (EnchantmentStorageMeta) + if (item.getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) item.getItemMeta(); + if (meta.getStoredEnchants().containsKey(enchantment)) { + return meta.getStoredEnchants().get(enchantment); + } + } + + return 0; + } + + @Override + public boolean dependsOnPlayer() { + return true; + } + + @Override + public String[] createNames() { + return new String[]{"enchantmentlevel", "enchlevel", "enchantlevel"}; + } + + @Override + public void enableType() { + } + + @Override + public String[] showStructure() { + return new String[]{ + "[enchantment]:over:[int]", + "[enchantment]:under:[int]", + "[enchantment]:equals:[int]", + "[enchantment]:between:[int]-[int]" + }; + } + +} diff --git a/src/main/java/studio/magemonkey/genesis/managers/misc/StringManager.java b/src/main/java/studio/magemonkey/genesis/managers/misc/StringManager.java index 77e884c..28efd3c 100644 --- a/src/main/java/studio/magemonkey/genesis/managers/misc/StringManager.java +++ b/src/main/java/studio/magemonkey/genesis/managers/misc/StringManager.java @@ -4,8 +4,10 @@ import lombok.NonNull; import org.bukkit.Bukkit; import org.bukkit.ChatColor; +import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; import studio.magemonkey.genesis.core.GenesisBuy; import studio.magemonkey.genesis.core.GenesisShop; import studio.magemonkey.genesis.core.GenesisShopHolder; @@ -20,15 +22,19 @@ import studio.magemonkey.genesis.misc.VersionManager; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; public class StringManager { - private static final Pattern hexPattern = Pattern.compile("(#[a-fA-F0-9]{6})"); - private static final Pattern placeholderPattern = Pattern.compile("%(.*?)%"); + private static final Pattern hexPattern = Pattern.compile("(#[a-fA-F0-9]{6})"); + private static final Pattern placeholderPattern = Pattern.compile("%(.*?)%"); + private static final Pattern enchantLevelPattern = Pattern.compile("%item_in_hand_enchant_([a-zA-Z0-9_]+)%", + Pattern.CASE_INSENSITIVE); /** * Transform specific strings from one thing to another @@ -190,6 +196,31 @@ public String transform(String s, Player target, boolean colorize) { s = s.replace("%item_in_hand%", Misc.getItemInMainHand(target).getType().name()); } + if (s.contains("%item_in_hand_enchant_")) { + ItemStack handItem = Misc.getItemInMainHand(target); + Matcher em = enchantLevelPattern.matcher(s); + Map replacements = new LinkedHashMap<>(); + while (em.find()) { + String enchantName = em.group(1); + Enchantment enchantment = InputReader.readEnchantment(enchantName); + int level = 0; + if (enchantment != null && handItem != null && !handItem.getType().isAir()) { + if (handItem.getEnchantments().containsKey(enchantment)) { + level = handItem.getEnchantments().get(enchantment); + } else if (handItem.getItemMeta() instanceof EnchantmentStorageMeta) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) handItem.getItemMeta(); + if (meta.getStoredEnchants().containsKey(enchantment)) { + level = meta.getStoredEnchants().get(enchantment); + } + } + } + replacements.put(em.group(0), String.valueOf(level)); + } + for (Map.Entry entry : replacements.entrySet()) { + s = s.replace(entry.getKey(), entry.getValue()); + } + } + if (s.contains("%input%")) { s = s.replace("%input%", ClassManager.manager.getPlayerDataHandler().getInput(target)); } @@ -237,6 +268,10 @@ public boolean checkStringForFeatures(GenesisShop shop, b = true; } + if (s.contains("%item_in_hand%") || s.contains("%item_in_hand_enchant_")) { + b = true; + } + if (buy != null && shop != null && ClassManager.manager.getSettings().getServerPingingEnabled(true)) { String serverNames = StringManipulationLib.figureOutVariable(s, 0, "players", "motd"); if (serverNames != null) {