From 3ac248b34eb74e130b56c79056e365177ecb387f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 08:16:13 +0000 Subject: [PATCH 1/3] Initial plan From 7ad4d598846d62bb470a65e2f983de44588ee773 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 08:34:37 +0000 Subject: [PATCH 2/3] feat: add usable slot configuration for item-generator items (#enhancement) Co-authored-by: MaksyKun <77341370+MaksyKun@users.noreply.github.com> --- .../itemgenerator/ItemGeneratorManager.java | 18 +++++ .../list/itemgenerator/editor/EditorGUI.java | 23 ++++++- .../itemgenerator/editor/UsableSlotsGUI.java | 66 +++++++++++++++++++ .../divinity/stats/items/ItemStats.java | 28 ++++++++ .../divinity/stats/items/ItemTags.java | 5 +- .../magemonkey/divinity/utils/ItemUtils.java | 4 ++ 6 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/UsableSlotsGUI.java diff --git a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java index 00f4c4b8..eb0c3281 100644 --- a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java +++ b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java @@ -10,6 +10,7 @@ import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BlockStateMeta; @@ -211,6 +212,8 @@ public class GeneratorItem extends LimitedItem { private Set attributeGenerators; private AbilityGenerator abilityGenerator; + @Getter + private Set usableSlots; public GeneratorItem(@NotNull Divinity plugin, @NotNull JYML cfg) { super(plugin, cfg, ItemGeneratorManager.this); @@ -590,6 +593,18 @@ public GeneratorItem(@NotNull Divinity plugin, @NotNull JYML cfg) { this.attributeGenerators = new HashSet<>(); + // Load Usable Slots + this.usableSlots = new HashSet<>(); + for (String slotName : cfg.getStringList("generator.usable-slots")) { + try { + EquipmentSlot slot = EquipmentSlot.valueOf(slotName.trim().toUpperCase()); + this.usableSlots.add(slot); + } catch (IllegalArgumentException e) { + this.error("Invalid equipment slot '" + slotName + "' in 'generator.usable-slots'. File: " + + cfg.getFile().getName()); + } + } + // Pre-cache Ammo Attributes this.addAttributeGenerator(new SingleAttributeGenerator<>(this.plugin, this, @@ -952,6 +967,9 @@ protected ItemStack build(int itemLvl, int uses, @Nullable ItemType mat) { } ItemUT.addSkullTexture(item, this.hash, this.getId()); + if (!this.usableSlots.isEmpty()) { + ItemStats.setUsableSlots(item, this.usableSlots); + } this.getAttributeGenerators().forEach(generator -> generator.generate(item, itemLvl)); LoreUT.replacePlaceholder(item, PLACE_GEN_DAMAGE, null); diff --git a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/EditorGUI.java b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/EditorGUI.java index 8f2640b8..f5f7f3c8 100644 --- a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/EditorGUI.java +++ b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/EditorGUI.java @@ -22,7 +22,6 @@ import studio.magemonkey.divinity.modules.list.itemgenerator.editor.sockets.MainSocketsGUI; import studio.magemonkey.divinity.modules.list.itemgenerator.editor.stats.MainStatsGUI; import studio.magemonkey.divinity.modules.list.itemgenerator.editor.trimmings.TrimmingListGUI; - import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -519,6 +518,27 @@ public void onLeftClick() { openSubMenu(new HandTypesGUI(player, itemGenerator)); } }); + lore = new ArrayList<>(); + for (String slot : this.itemGenerator.getConfig().getStringList(ItemType.USABLE_SLOTS.getPath())) { + lore.add("&a " + slot); + } + setSlot(25, new Slot(createItem(Material.COMPASS, + "&eUsable Slots", StringUT.replace(CURRENT_PLACEHOLDER, lore, + "&bCurrent:", + "%current%", + "&6Left-Click: &eModify", + "&6Right-Click: &eSet to default value"))) { + @Override + public void onLeftClick() { + openSubMenu(new UsableSlotsGUI(player, itemGenerator)); + } + + @Override + public void onRightClick() { + setDefault(ItemType.USABLE_SLOTS.getPath()); + saveAndReopen(); + } + }); setSlot(27, new Slot(createItem(Material.IRON_SWORD, "&eDamage Types", "&6Left-Click: &eModify")) { @@ -626,6 +646,7 @@ public enum ItemType { TIER("tier"), AMMO_TYPES("generator.ammo-types"), HAND_TYPES("generator.hand-types"), + USABLE_SLOTS("generator.usable-slots"), DAMAGE_TYPES("generator.damage-types"), DEFENSE_TYPES("generator.defense-types"), ITEM_STATS("generator.item-stats"), diff --git a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/UsableSlotsGUI.java b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/UsableSlotsGUI.java new file mode 100644 index 00000000..53da20a2 --- /dev/null +++ b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/editor/UsableSlotsGUI.java @@ -0,0 +1,66 @@ +package studio.magemonkey.divinity.modules.list.itemgenerator.editor; + +import org.bukkit.Material; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.entity.Player; +import studio.magemonkey.codex.manager.api.menu.Slot; + +import java.util.ArrayList; +import java.util.List; + +public class UsableSlotsGUI extends AbstractEditorGUI { + + private static final EquipmentSlot[] SLOTS = { + EquipmentSlot.HEAD, + EquipmentSlot.CHEST, + EquipmentSlot.LEGS, + EquipmentSlot.FEET, + EquipmentSlot.HAND, + EquipmentSlot.OFF_HAND + }; + + public UsableSlotsGUI(Player player, ItemGeneratorReference itemGenerator) { + super(player, + 1, + "Editor/" + EditorGUI.ItemType.USABLE_SLOTS.getTitle(), + itemGenerator); + } + + @Override + public void setContents() { + List configuredSlots = itemGenerator.getConfig() + .getStringList(EditorGUI.ItemType.USABLE_SLOTS.getPath()); + + int i = 0; + for (EquipmentSlot equipmentSlot : SLOTS) { + String slotName = equipmentSlot.name(); + boolean isActive = configuredSlots.stream() + .anyMatch(s -> s.equalsIgnoreCase(slotName)); + + Material icon = isActive ? Material.LIME_DYE : Material.GRAY_DYE; + String status = isActive ? "&aEnabled" : "&cDisabled"; + + this.setSlot(i, new Slot(createItem(icon, + "&e" + slotName, + "&bStatus: " + status, + "&6Left-Click: &eToggle")) { + @Override + public void onLeftClick() { + List current = new ArrayList<>(itemGenerator.getConfig() + .getStringList(EditorGUI.ItemType.USABLE_SLOTS.getPath())); + boolean found = current.removeIf(s -> s.equalsIgnoreCase(slotName)); + if (!found) { + current.add(slotName); + } + if (current.isEmpty()) { + itemGenerator.getConfig().remove(EditorGUI.ItemType.USABLE_SLOTS.getPath()); + } else { + itemGenerator.getConfig().set(EditorGUI.ItemType.USABLE_SLOTS.getPath(), current); + } + saveAndReopen(); + } + }); + i++; + } + } +} diff --git a/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java b/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java index 6e052ddb..4be11cfd 100644 --- a/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java +++ b/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java @@ -31,6 +31,7 @@ import studio.magemonkey.divinity.utils.ItemUtils; import java.util.*; +import java.util.stream.Collectors; public class ItemStats { @@ -76,6 +77,8 @@ public class ItemStats { "prorpgitems:qrpg_" + ItemTags.TAG_ITEM_SOCKET_RATE.toLowerCase())), Objects.requireNonNull(NamespacedKey.fromString( "quantumrpg:qrpg_" + ItemTags.TAG_ITEM_SOCKET_RATE.toLowerCase()))); + private static final NamespacedKey KEY_USABLE_SLOTS = + new NamespacedKey(plugin, ItemTags.TAG_ITEM_USABLE_SLOTS.toLowerCase()); private static DamageAttribute DAMAGE_DEFAULT; private static DefenseAttribute DEFENSE_DEFAULT; @@ -566,4 +569,29 @@ public static int getSocketRate(@NotNull ItemStack item) { } return 0; } + + public static void setUsableSlots(@NotNull ItemStack item, @NotNull Set slots) { + if (slots.isEmpty()) { + DataUT.removeData(item, KEY_USABLE_SLOTS); + return; + } + String slotString = slots.stream().map(EquipmentSlot::name).collect(Collectors.joining(",")); + DataUT.setData(item, KEY_USABLE_SLOTS, slotString); + } + + @Nullable + public static EquipmentSlot[] getUsableSlots(@NotNull ItemStack item) { + String data = DataUT.getStringData(item, KEY_USABLE_SLOTS); + if (data == null || data.isEmpty()) return null; + return Arrays.stream(data.split(",")) + .map(s -> { + try { + return EquipmentSlot.valueOf(s.trim().toUpperCase()); + } catch (IllegalArgumentException ignored) { + return null; + } + }) + .filter(Objects::nonNull) + .toArray(EquipmentSlot[]::new); + } } diff --git a/src/main/java/studio/magemonkey/divinity/stats/items/ItemTags.java b/src/main/java/studio/magemonkey/divinity/stats/items/ItemTags.java index 0dd2fc39..3d7d5df5 100644 --- a/src/main/java/studio/magemonkey/divinity/stats/items/ItemTags.java +++ b/src/main/java/studio/magemonkey/divinity/stats/items/ItemTags.java @@ -7,8 +7,9 @@ public class ItemTags { public static final String TAG_ITEM_LEVEL = "ITEM_LEVEL"; public static final String TAG_ITEM_SOCKET_RATE = "ITEM_SOCKET_RATE"; public static final String TAG_ITEM_SOCKET = "ITEM_SOCKET_"; - public static final String TAG_ITEM_AMMO = "ITEM_AMMO_"; - public static final String TAG_ITEM_HAND = "ITEM_HAND_"; + public static final String TAG_ITEM_AMMO = "ITEM_AMMO_"; + public static final String TAG_ITEM_HAND = "ITEM_HAND_"; + public static final String TAG_ITEM_USABLE_SLOTS = "ITEM_USABLE_SLOTS"; public static final String TAG_ITEM_CHARGES = "ITEM_CHARGES"; public static final String TAG_ITEM_STAT = "ITEM_STAT_"; public static final String TAG_ITEM_DAMAGE = "ITEM_DAMAGE_"; diff --git a/src/main/java/studio/magemonkey/divinity/utils/ItemUtils.java b/src/main/java/studio/magemonkey/divinity/utils/ItemUtils.java index 91d18de2..1eef0347 100644 --- a/src/main/java/studio/magemonkey/divinity/utils/ItemUtils.java +++ b/src/main/java/studio/magemonkey/divinity/utils/ItemUtils.java @@ -113,6 +113,10 @@ public static GameProfile getNonPlayerProfile(String hash) { @NotNull public static EquipmentSlot[] getItemSlots(@NotNull ItemStack item) { + EquipmentSlot[] custom = ItemStats.getUsableSlots(item); + if (custom != null && custom.length > 0) { + return custom; + } if (isArmor(item) || !EngineCfg.ATTRIBUTES_EFFECTIVE_IN_OFFHAND) { return new EquipmentSlot[]{getEquipmentSlotByItemType(item)}; } From 32b41435b9b1d2de3fc5f2e093d995279126a662 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 16 Mar 2026 08:41:08 +0000 Subject: [PATCH 3/3] Changes before error encountered Co-authored-by: MaksyKun <77341370+MaksyKun@users.noreply.github.com> --- .../itemgenerator/ItemGeneratorManager.java | 21 +++++++---- .../divinity/stats/items/ItemStats.java | 35 +++++++++++++++---- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java index eb0c3281..6bf0aac1 100644 --- a/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java +++ b/src/main/java/studio/magemonkey/divinity/modules/list/itemgenerator/ItemGeneratorManager.java @@ -213,7 +213,7 @@ public class GeneratorItem extends LimitedItem { private Set attributeGenerators; private AbilityGenerator abilityGenerator; @Getter - private Set usableSlots; + private Set usableSlots; public GeneratorItem(@NotNull Divinity plugin, @NotNull JYML cfg) { super(plugin, cfg, ItemGeneratorManager.this); @@ -593,15 +593,22 @@ public GeneratorItem(@NotNull Divinity plugin, @NotNull JYML cfg) { this.attributeGenerators = new HashSet<>(); - // Load Usable Slots + // Load Usable Slots (supports EquipmentSlot names and numeric inventory slot indices) this.usableSlots = new HashSet<>(); for (String slotName : cfg.getStringList("generator.usable-slots")) { + String trimmed = slotName.trim(); try { - EquipmentSlot slot = EquipmentSlot.valueOf(slotName.trim().toUpperCase()); - this.usableSlots.add(slot); - } catch (IllegalArgumentException e) { - this.error("Invalid equipment slot '" + slotName + "' in 'generator.usable-slots'. File: " - + cfg.getFile().getName()); + int index = Integer.parseInt(trimmed); + this.usableSlots.add(String.valueOf(index)); + } catch (NumberFormatException ignored) { + try { + EquipmentSlot slot = EquipmentSlot.valueOf(trimmed.toUpperCase()); + this.usableSlots.add(slot.name()); + } catch (IllegalArgumentException e) { + this.error("Invalid slot '" + trimmed + "' in 'generator.usable-slots'. " + + "Use an EquipmentSlot name (e.g. CHEST) or an inventory slot index. File: " + + cfg.getFile().getName()); + } } } diff --git a/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java b/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java index 4be11cfd..f9b4f07a 100644 --- a/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java +++ b/src/main/java/studio/magemonkey/divinity/stats/items/ItemStats.java @@ -570,28 +570,49 @@ public static int getSocketRate(@NotNull ItemStack item) { return 0; } - public static void setUsableSlots(@NotNull ItemStack item, @NotNull Set slots) { + public static void setUsableSlots(@NotNull ItemStack item, @NotNull Set slots) { if (slots.isEmpty()) { DataUT.removeData(item, KEY_USABLE_SLOTS); return; } - String slotString = slots.stream().map(EquipmentSlot::name).collect(Collectors.joining(",")); - DataUT.setData(item, KEY_USABLE_SLOTS, slotString); + DataUT.setData(item, KEY_USABLE_SLOTS, String.join(",", slots)); } @Nullable public static EquipmentSlot[] getUsableSlots(@NotNull ItemStack item) { String data = DataUT.getStringData(item, KEY_USABLE_SLOTS); if (data == null || data.isEmpty()) return null; - return Arrays.stream(data.split(",")) + EquipmentSlot[] slots = Arrays.stream(data.split(",")) .map(s -> { try { - return EquipmentSlot.valueOf(s.trim().toUpperCase()); - } catch (IllegalArgumentException ignored) { - return null; + Integer.parseInt(s.trim()); + return null; // numeric slot — skip for equipment-slot purposes + } catch (NumberFormatException ignored2) { + try { + return EquipmentSlot.valueOf(s.trim().toUpperCase()); + } catch (IllegalArgumentException ignored) { + return null; + } } }) .filter(Objects::nonNull) .toArray(EquipmentSlot[]::new); + return slots.length == 0 ? null : slots; + } + + public static int[] getUsableSlotIndices(@NotNull ItemStack item) { + String data = DataUT.getStringData(item, KEY_USABLE_SLOTS); + if (data == null || data.isEmpty()) return new int[0]; + return Arrays.stream(data.split(",")) + .map(String::trim) + .mapToInt(s -> { + try { + return Integer.parseInt(s); + } catch (NumberFormatException ignored) { + return -1; + } + }) + .filter(i -> i >= 0) + .toArray(); } }