Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -211,6 +212,8 @@ public class GeneratorItem extends LimitedItem {

private Set<IAttributeGenerator> attributeGenerators;
private AbilityGenerator abilityGenerator;
@Getter
private Set<String> usableSlots;

public GeneratorItem(@NotNull Divinity plugin, @NotNull JYML cfg) {
super(plugin, cfg, ItemGeneratorManager.this);
Expand Down Expand Up @@ -590,6 +593,25 @@ public GeneratorItem(@NotNull Divinity plugin, @NotNull JYML cfg) {

this.attributeGenerators = new HashSet<>();

// 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 {
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());
}
}
}

// Pre-cache Ammo Attributes
this.addAttributeGenerator(new SingleAttributeGenerator<>(this.plugin,
this,
Expand Down Expand Up @@ -952,6 +974,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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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")) {
Expand Down Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
@@ -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<String> 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<String> 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++;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import studio.magemonkey.divinity.utils.ItemUtils;

import java.util.*;
import java.util.stream.Collectors;

public class ItemStats {

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -566,4 +569,50 @@ public static int getSocketRate(@NotNull ItemStack item) {
}
return 0;
}

public static void setUsableSlots(@NotNull ItemStack item, @NotNull Set<String> slots) {
if (slots.isEmpty()) {
DataUT.removeData(item, KEY_USABLE_SLOTS);
return;
}
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;
EquipmentSlot[] slots = Arrays.stream(data.split(","))
.map(s -> {
try {
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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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_";
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/studio/magemonkey/divinity/utils/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -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)};
}
Expand Down