This commit is contained in:
BuildTools 2023-11-28 18:49:21 +05:00
parent daa3e40c65
commit 9d7c98cddb
9 changed files with 156 additions and 112 deletions

View File

@ -108,6 +108,7 @@ public class ExcellentEnchants extends NexPlugin<ExcellentEnchants> {
public void loadLang() {
this.getLangManager().loadMissing(Lang.class);
this.getLangManager().loadEnum(FitItemType.class);
this.getLangManager().loadEnum(ObtainType.class);
this.getLang().saveChanges();
}

View File

@ -8,6 +8,7 @@ public class Placeholders extends su.nexmedia.engine.utils.Placeholders {
public static final String URL_ENGINE_ITEMS = "https://github.com/nulli0n/NexEngine-spigot/wiki/Configuration-Tips#item-sections";
public static final String GENERIC_TYPE = "%type%";
public static final String GENERIC_NAME = "%name%";
public static final String GENERIC_ITEM = "%item%";
public static final String GENERIC_LEVEL = "%level%";
public static final String GENERIC_AMOUNT = "%amount%";

View File

@ -9,7 +9,6 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.command.AbstractCommand;
import su.nexmedia.engine.api.command.CommandResult;
import su.nexmedia.engine.lang.LangManager;
import su.nexmedia.engine.utils.*;
import su.nexmedia.engine.utils.random.Rnd;
import su.nightexpress.excellentenchants.ExcellentEnchants;
@ -90,7 +89,7 @@ public class EnchantCommand extends AbstractCommand<ExcellentEnchants> {
plugin.getMessage(sender == player ? Lang.COMMAND_ENCHANT_DONE_SELF : Lang.COMMAND_ENCHANT_DONE_OTHERS)
.replace(Placeholders.forPlayer(player))
.replace(Placeholders.GENERIC_ITEM, ItemUtil.getItemName(item))
.replace(Placeholders.GENERIC_ENCHANT, LangManager.getEnchantment(enchantment))
.replace(Placeholders.GENERIC_ENCHANT, EnchantUtils.getLocalized(enchantment))
.replace(Placeholders.GENERIC_LEVEL, NumberUtil.toRoman(level))
.send(sender);
}

View File

@ -19,6 +19,8 @@ import java.util.stream.Stream;
public class Config {
public static final String DIR_MENU = "/menu/";
public static final JOption<Long> TASKS_ARROW_TRAIL_TICKS_INTERVAL = JOption.create("Tasks.Arrow_Trail.Tick_Interval",
1L,
"Sets how often (in ticks) arrow trail particle effects will be spawned behind the arrow."

View File

@ -69,10 +69,7 @@ public class EnchantPopulator {
Set<ExcellentEnchant> enchants = EnchantRegistry.getOfTier(tier);
enchants.removeIf(enchant -> {
if (enchant.getObtainChance(this.getObtainType()) <= 0D) return true;
if (!enchant.canEnchantItem(this.getItem())) return true;
return this.getObtainType() == ObtainType.ENCHANTING && (enchant.isTreasure() || enchant.isCursed());
return !enchant.isObtainable(this.getObtainType()) || !enchant.canEnchantItem(this.getItem());
});
this.candidates.put(tier, enchants);

View File

@ -195,6 +195,13 @@ public abstract class ExcellentEnchant extends Enchantment implements IEnchantme
return description;
}
@NotNull
public List<String> formatDescription() {
return new ArrayList<>(this.getDescription().stream()
.map(line -> Config.ENCHANTMENTS_DESCRIPTION_FORMAT.get().replace(Placeholders.GENERIC_DESCRIPTION, line))
.toList());
}
@NotNull
public List<String> formatDescription(int level) {
return new ArrayList<>(this.getDescription(level).stream()
@ -202,6 +209,10 @@ public abstract class ExcellentEnchant extends Enchantment implements IEnchantme
.toList());
}
public boolean hasConflicts() {
return !this.getConflicts().isEmpty();
}
@NotNull
public Set<String> getConflicts() {
return this.getDefaults().getConflicts();
@ -234,6 +245,12 @@ public abstract class ExcellentEnchant extends Enchantment implements IEnchantme
return get != 0 ? this.fineLevel(get, ObtainType.ENCHANTING) : 0;
}
public boolean isObtainable(@NotNull ObtainType obtainType) {
if (obtainType == ObtainType.ENCHANTING && (this.isTreasure() || this.isCursed())) return false;
return this.getObtainChance(obtainType) > 0D;
}
public double getObtainChance(@NotNull ObtainType obtainType) {
return this.getDefaults().getObtainChance().getOrDefault(obtainType, 0D);
}

View File

@ -1,9 +1,12 @@
package su.nightexpress.excellentenchants.enchantment.menu;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import su.nexmedia.engine.api.config.JOption;
import su.nexmedia.engine.api.config.JYML;
import su.nexmedia.engine.api.menu.AutoPaged;
import su.nexmedia.engine.api.menu.MenuItemType;
@ -12,49 +15,50 @@ import su.nexmedia.engine.api.menu.click.ItemClick;
import su.nexmedia.engine.api.menu.impl.ConfigMenu;
import su.nexmedia.engine.api.menu.impl.MenuOptions;
import su.nexmedia.engine.api.menu.impl.MenuViewer;
import su.nexmedia.engine.api.menu.item.MenuItem;
import su.nexmedia.engine.utils.Colorizer;
import su.nexmedia.engine.utils.ItemReplacer;
import su.nexmedia.engine.utils.ItemUtil;
import su.nexmedia.engine.utils.PDCUtil;
import su.nexmedia.engine.utils.StringUtil;
import su.nightexpress.excellentenchants.ExcellentEnchants;
import su.nightexpress.excellentenchants.Placeholders;
import su.nightexpress.excellentenchants.config.Config;
import su.nightexpress.excellentenchants.enchantment.impl.ExcellentEnchant;
import su.nightexpress.excellentenchants.enchantment.registry.EnchantRegistry;
import su.nightexpress.excellentenchants.enchantment.type.ObtainType;
import su.nightexpress.excellentenchants.enchantment.util.EnchantUtils;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import static su.nexmedia.engine.utils.Colors2.*;
import static su.nightexpress.excellentenchants.Placeholders.*;
public class EnchantmentsListMenu extends ConfigMenu<ExcellentEnchants> implements AutoPaged<ExcellentEnchant> {
private static final String PATH = "/menu/enchants_list.yml";
private static final String FILE = "enchants.yml";
private static final String PLACEHOLDER_CONFLICTS = "%conflicts%";
private static final String PLACEHOLDER_CHARGES = "%charges%";
private static final String PLACEHOLDER_OBTAINING = "%obtaining%";
private final ItemStack enchantIcon;
private final List<String> enchantLoreConflicts;
private final List<String> enchantLoreCharges;
private final List<String> enchantLoreObtaining;
private final int[] enchantSlots;
private final NamespacedKey keyLevel;
private final Map<String, Map<Integer, ItemStack>> iconCache;
private String enchantName;
private List<String> enchantLoreMain;
private List<String> enchantLoreConflicts;
private List<String> enchantLoreCharges;
private List<String> enchantLoreObtaining;
private int[] enchantSlots;
public EnchantmentsListMenu(@NotNull ExcellentEnchants plugin) {
super(plugin, JYML.loadOrExtract(plugin, PATH));
super(plugin, new JYML(plugin.getDataFolder() + Config.DIR_MENU, FILE));
this.keyLevel = new NamespacedKey(plugin, "list_display_level");
this.iconCache = new HashMap<>();
this.enchantIcon = cfg.getItem("Enchantments.Icon");
this.enchantLoreConflicts = Colorizer.apply(cfg.getStringList("Enchantments.Lore.Conflicts"));
this.enchantLoreCharges = Colorizer.apply(cfg.getStringList("Enchantments.Lore.Charges"));
this.enchantLoreObtaining = Colorizer.apply(cfg.getStringList("Enchantments.Lore.Obtaining"));
this.enchantSlots = cfg.getIntArray("Enchantments.Slots");
this.registerHandler(MenuItemType.class)
.addClick(MenuItemType.CLOSE, (viewer, event) -> plugin.runTask(task -> viewer.getPlayer().closeInventory()))
.addClick(MenuItemType.CLOSE, ClickHandler.forClose(this))
.addClick(MenuItemType.PAGE_NEXT, ClickHandler.forNextPage(this))
.addClick(MenuItemType.PAGE_PREVIOUS, ClickHandler.forPreviousPage(this));
@ -67,6 +71,85 @@ public class EnchantmentsListMenu extends ConfigMenu<ExcellentEnchants> implemen
this.iconCache.clear();
}
// ----------
@Override
public boolean isCodeCreation() {
return true;
}
@Override
protected void loadAdditional() {
this.enchantName = JOption.create("Enchantment.Name", ENCHANTMENT_NAME_FORMATTED).read(cfg);
this.enchantLoreMain = JOption.create("Enchantment.Lore.Main",
Arrays.asList(
ENCHANTMENT_DESCRIPTION,
DARK_GRAY + "(click to switch level)",
"",
LIGHT_YELLOW + BOLD + "Info:",
LIGHT_YELLOW + "" + LIGHT_GRAY + "Tier: " + LIGHT_YELLOW + ENCHANTMENT_TIER,
LIGHT_YELLOW + "" + LIGHT_GRAY + "Applies to: " + LIGHT_YELLOW + ENCHANTMENT_FIT_ITEM_TYPES,
LIGHT_YELLOW + "" + LIGHT_GRAY + "Levels: " + LIGHT_YELLOW + ENCHANTMENT_LEVEL_MIN + GRAY + " - " + LIGHT_YELLOW + ENCHANTMENT_LEVEL_MAX,
PLACEHOLDER_CHARGES,
PLACEHOLDER_CONFLICTS,
PLACEHOLDER_OBTAINING
)).read(cfg);
this.enchantLoreConflicts = JOption.create("Enchantment.Lore.Conflicts",
Arrays.asList(
"",
LIGHT_RED + BOLD + "Conflicts:",
LIGHT_RED + "" + LIGHT_GRAY + GENERIC_NAME
)).read(cfg);
this.enchantLoreCharges = JOption.create("Enchantment.Lore.Charges",
Arrays.asList(
LIGHT_YELLOW + "" + LIGHT_GRAY + "Charges: " + LIGHT_YELLOW + ENCHANTMENT_CHARGES_MAX_AMOUNT + "" + LIGHT_GRAY + " (" + WHITE + ENCHANTMENT_CHARGES_FUEL_ITEM + LIGHT_GRAY + ")"
)).read(cfg);
this.enchantLoreObtaining = JOption.create("Enchantment.Lore.Obtaining",
Arrays.asList(
"",
LIGHT_GREEN + BOLD + "Obtaining:",
LIGHT_GREEN + "" + LIGHT_GRAY + GENERIC_TYPE
)).read(cfg);
this.enchantSlots = new JOption<int[]>("Enchantment.Slots",
(cfg, path, def) -> cfg.getIntArray(path),
() -> IntStream.range(0, 27).toArray()
).setWriter(JYML::setIntArray).read(cfg);
}
@Override
@NotNull
protected MenuOptions createDefaultOptions() {
return new MenuOptions(DARK_GRAY + BOLD + "Custom Enchants", 36, InventoryType.CHEST);
}
@Override
@NotNull
protected List<MenuItem> createDefaultItems() {
List<MenuItem> list = new ArrayList<>();
ItemStack nextPageStack = ItemUtil.createCustomHead("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjMyY2E2NjA1NmI3Mjg2M2U5OGY3ZjMyYmQ3ZDk0YzdhMGQ3OTZhZjY5MWM5YWMzYTkxMzYzMzEzNTIyODhmOSJ9fX0=");
ItemUtil.mapMeta(nextPageStack, meta -> {
meta.setDisplayName(WHITE + "Next Page" + LIGHT_GRAY + " (→)");
});
ItemStack prevPageStack = ItemUtil.createCustomHead("eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODY5NzFkZDg4MWRiYWY0ZmQ2YmNhYTkzNjE0NDkzYzYxMmY4Njk2NDFlZDU5ZDFjOTM2M2EzNjY2YTVmYTYifX19");
ItemUtil.mapMeta(prevPageStack, meta -> {
meta.setDisplayName(LIGHT_GRAY + "(←) " + WHITE + "Previous Page");
});
list.add(new MenuItem(nextPageStack).setSlots(35).setType(MenuItemType.PAGE_NEXT).setPriority(5));
list.add(new MenuItem(prevPageStack).setSlots(27).setType(MenuItemType.PAGE_PREVIOUS).setPriority(5));
return list;
}
// -----------
@Override
public void onPrepare(@NotNull MenuViewer viewer, @NotNull MenuOptions options) {
super.onPrepare(viewer, options);
@ -118,26 +201,42 @@ public class EnchantmentsListMenu extends ConfigMenu<ExcellentEnchants> implemen
@NotNull
private ItemStack buildEnchantIcon(@NotNull ExcellentEnchant enchant, int level) {
ItemStack icon = new ItemStack(this.enchantIcon);
ItemUtil.mapMeta(icon, meta -> {
List<String> lore = meta.getLore();
if (lore == null) lore = new ArrayList<>();
ItemStack icon = new ItemStack(Material.ENCHANTED_BOOK);
List<String> conflicts = enchant.getConflicts().isEmpty() ? Collections.emptyList() : new ArrayList<>(this.enchantLoreConflicts);
List<String> conflictNames = enchant.getConflicts().stream().map(EnchantUtils::getLocalized).filter(Objects::nonNull).toList();
conflicts = StringUtil.replace(conflicts, Placeholders.ENCHANTMENT_NAME, true, conflictNames);
List<String> conflicts = new ArrayList<>();
if (enchant.hasConflicts()) {
for (String line : this.enchantLoreConflicts) {
if (line.contains(GENERIC_NAME)) {
enchant.getConflicts().stream().map(EnchantUtils::getLocalized).filter(Objects::nonNull).forEach(conf -> {
conflicts.add(line.replace(GENERIC_NAME, conf));
});
}
else conflicts.add(line);
}
}
List<String> charges = enchant.isChargesEnabled() ? new ArrayList<>(this.enchantLoreCharges) : Collections.emptyList();
List<String> obtaining = new ArrayList<>(this.enchantLoreObtaining);
List<String> obtaining = new ArrayList<>();
for (String line : this.enchantLoreObtaining) {
if (line.contains(GENERIC_TYPE)) {
for (ObtainType obtainType : ObtainType.values()) {
if (enchant.isObtainable(obtainType)) {
obtaining.add(line.replace(GENERIC_TYPE, plugin.getLangManager().getEnum(obtainType)));
}
}
}
else obtaining.add(line);
}
lore = StringUtil.replaceInList(lore, PLACEHOLDER_CONFLICTS, conflicts);
lore = StringUtil.replaceInList(lore, PLACEHOLDER_CHARGES, charges);
lore = StringUtil.replaceInList(lore, PLACEHOLDER_OBTAINING, obtaining);
lore = StringUtil.replace(lore, Placeholders.ENCHANTMENT_DESCRIPTION, true, enchant.getDescription());
meta.setLore(lore);
ItemUtil.replace(meta, enchant.getPlaceholders(level).replacer());
});
ItemReplacer.create(icon).hideFlags().trimmed()
.setDisplayName(this.enchantName)
.setLore(this.enchantLoreMain)
.replaceLoreExact(PLACEHOLDER_CHARGES, enchant.isChargesEnabled() ? new ArrayList<>(this.enchantLoreCharges) : Collections.emptyList())
.replaceLoreExact(PLACEHOLDER_CONFLICTS, conflicts)
.replaceLoreExact(PLACEHOLDER_OBTAINING, obtaining)
.replaceLoreExact(ENCHANTMENT_DESCRIPTION, enchant.formatDescription())
.replace(enchant.getPlaceholders(level))
.replace(Colorizer::apply)
.writeMeta();
return icon;
}

View File

@ -1,72 +0,0 @@
Title: ' #a267f3&lCustom Enchants'
Size: 36
Inventory_Type: CHEST
Use_Mini_Message: false
Enchantments:
Icon:
Material: ENCHANTED_BOOK
Name: '%enchantment_name_formatted%'
Lore:
- '#aeb6bf%enchantment_description%'
- ''
- '#bcff9a&lInfo:'
- '#bcff9a▪ #ddeceeTier: #bcff9a%enchantment_tier%'
- '#bcff9a▪ #ddeceeApplies to: #bcff9a%enchantment_fit_item_types%'
- '#bcff9a▪ #ddeceeLevels: #bcff9a%enchantment_level_min% #ddecee- #bcff9a%enchantment_level_max%'
- '%conflicts%'
- '%charges%'
- '%obtaining%'
- ''
- '#a5ff9a&lActions:'
- '#a5ff9a▪ #ddeceeLeft-Click: #a5ff9aSwitch Level'
Lore:
Conflicts:
- ''
- '#ff9a9a[!] #ddeceeCan not be used together with:'
- '#ff9a9a▸ %enchantment_name%'
Charges:
- ''
- '#d39aff&lCharges:'
- '#d39aff◈ #ddeceeMaximum: #d39aff%enchantment_charges_max_amount%⚡'
- '#d39aff◈ #ddeceePer Use: #d39aff-%enchantment_charges_consume_amount%⚡'
- '#d39aff◈ #ddeceePer Recharge: #d39aff+%enchantment_charges_recharge_amount%⚡'
- '#d39aff◈ #ddeceeFuel Item: #d39aff%enchantment_charges_fuel_item%'
Obtaining:
- ''
- '#9af7ff&lObtain Chance:'
- '#9af7ff┃ #ddeceeEnchanting Table: #9af7ff%enchantment_obtain_chance_enchanting%%'
- '#9af7ff┃ #ddeceeVillager Trade: #9af7ff%enchantment_obtain_chance_villager%%'
- '#9af7ff┃ #ddeceeLoot Generation: #9af7ff%enchantment_obtain_chance_loot_generation%%'
- '#9af7ff┃ #ddeceeFishing: #9af7ff%enchantment_obtain_chance_fishing%%'
- '#9af7ff┃ #ddeceeMob Spawning: #9af7ff%enchantment_obtain_chance_mob_spawning%%'
Slots: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26
Content:
return:
Priority: 5
Item:
Material: PLAYER_HEAD
Head_Texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmU5YWU3YTRiZTY1ZmNiYWVlNjUxODEzODlhMmY3ZDQ3ZTJlMzI2ZGI1OWVhM2ViNzg5YTkyYzg1ZWE0NiJ9fX0=
Name: '#ffee9a(↓) &fClose Menu'
Lore: []
Slots: 31
Type: CLOSE
page_next:
Slots: 35
Type: PAGE_NEXT
Item:
Material: PLAYER_HEAD
Head_Texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjMyY2E2NjA1NmI3Mjg2M2U5OGY3ZjMyYmQ3ZDk0YzdhMGQ3OTZhZjY5MWM5YWMzYTkxMzYzMzEzNTIyODhmOSJ9fX0=
Name: '#ffee9a(→) &fNext Page'
Priority: 5
page_previous:
Slots: 27
Type: PAGE_PREVIOUS
Item:
Material: PLAYER_HEAD
Head_Texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODY5NzFkZDg4MWRiYWY0ZmQ2YmNhYTkzNjE0NDkzYzYxMmY4Njk2NDFlZDU5ZDFjOTM2M2EzNjY2YTVmYTYifX19
Name: '#ffee9a(←) &fPrevious Page'
Priority: 5