Improve Tab completion and MineEditGui
Tab completion improvements: - Add true/false suggestions for reset silent parameter - Add smart leaderboard limits (5,10,15,20,25,50) for top command - Fix permission mapping to match plugin.yml exactly - Remove incorrect wand/group suggestions - Add isNumericPartial() and filterStartsWith() helpers - Reduce code from 200+ to 170 lines MineEditGui improvements: - Better item descriptions and lore formatting - Show more useful information in each section
This commit is contained in:
parent
8dd9703c67
commit
8981214b18
2 changed files with 353 additions and 158 deletions
|
|
@ -18,118 +18,153 @@ public class LoMinesTabCompleter implements TabCompleter {
|
||||||
|
|
||||||
private final LoMinesPlugin plugin;
|
private final LoMinesPlugin plugin;
|
||||||
|
|
||||||
// Static command lists for fast lookup
|
|
||||||
private static final List<String> ADMIN_COMMANDS = List.of(
|
|
||||||
"create", "delete", "reset", "reload", "list", "maskscan",
|
|
||||||
"edit", "setteleport", "setspawn", "clearspawn"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final List<String> PLAYER_COMMANDS = List.of(
|
|
||||||
"wand", "group", "stats", "top"
|
|
||||||
);
|
|
||||||
|
|
||||||
private static final List<String> ALL_COMMANDS = List.of(
|
private static final List<String> ALL_COMMANDS = List.of(
|
||||||
"create", "delete", "reset", "reload", "list", "wand", "group",
|
"create", "delete", "reset", "reload", "list", "wand", "group",
|
||||||
"stats", "top", "maskscan", "edit", "setteleport", "setspawn",
|
"stats", "top", "maskscan", "edit", "setteleport", "setspawn",
|
||||||
"clearspawn", "help"
|
"clearspawn", "help"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static final List<String> BOOLEAN_VALUES = List.of("true", "false");
|
||||||
|
private static final List<String> TOP_LIMITS = List.of("5", "10", "15", "20", "25", "50");
|
||||||
|
|
||||||
public LoMinesTabCompleter(LoMinesPlugin plugin) {
|
public LoMinesTabCompleter(LoMinesPlugin plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||||
if (!command.getName().equalsIgnoreCase("lm") &&
|
if (!isLoMinesCommand(command.getName())) {
|
||||||
!command.getName().equalsIgnoreCase("lomines") &&
|
|
||||||
!command.getName().equalsIgnoreCase("mine") &&
|
|
||||||
!command.getName().equalsIgnoreCase("mines")) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String partial = args.length > 0 ? args[args.length - 1].toLowerCase() : "";
|
||||||
|
|
||||||
|
return switch (args.length) {
|
||||||
|
case 1 -> completeSubcommands(sender, partial);
|
||||||
|
case 2 -> completeSecondArg(sender, args[0].toLowerCase(), partial);
|
||||||
|
case 3 -> completeThirdArg(args[0].toLowerCase(), args[1], partial);
|
||||||
|
default -> new ArrayList<>();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLoMinesCommand(String name) {
|
||||||
|
return name.equalsIgnoreCase("lm") ||
|
||||||
|
name.equalsIgnoreCase("lomines") ||
|
||||||
|
name.equalsIgnoreCase("mine") ||
|
||||||
|
name.equalsIgnoreCase("mines");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeSubcommands(CommandSender sender, String partial) {
|
||||||
|
List<String> completions = new ArrayList<>();
|
||||||
|
for (String cmd : ALL_COMMANDS) {
|
||||||
|
if (cmd.startsWith(partial) && hasPermission(sender, cmd)) {
|
||||||
|
completions.add(cmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return completions;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeSecondArg(CommandSender sender, String subcommand, String partial) {
|
||||||
|
return switch (subcommand) {
|
||||||
|
case "create" -> completeCreate(partial);
|
||||||
|
case "delete", "maskscan", "edit", "setteleport", "setspawn", "clearspawn" ->
|
||||||
|
filterStartsWith(getMineNames(), partial);
|
||||||
|
case "reset" -> completeReset(partial);
|
||||||
|
case "stats" -> completeStats(sender, partial);
|
||||||
|
case "top" -> completeTopFirstArg(partial);
|
||||||
|
default -> new ArrayList<>();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeThirdArg(String subcommand, String arg2, String partial) {
|
||||||
|
return switch (subcommand) {
|
||||||
|
case "reset" -> filterStartsWith(BOOLEAN_VALUES, partial);
|
||||||
|
case "top" -> completeTopSecondArg(arg2, partial);
|
||||||
|
default -> new ArrayList<>();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeCreate(String partial) {
|
||||||
|
if (partial.isEmpty()) {
|
||||||
|
return new ArrayList<>(List.of("<name>"));
|
||||||
|
}
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeReset(String partial) {
|
||||||
|
List<String> mines = filterStartsWith(getMineNames(), partial);
|
||||||
|
if (partial.isEmpty() || "true".startsWith(partial) || "false".startsWith(partial)) {
|
||||||
|
mines.addAll(filterStartsWith(BOOLEAN_VALUES, partial));
|
||||||
|
}
|
||||||
|
return mines;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeStats(CommandSender sender, String partial) {
|
||||||
|
if (!sender.hasPermission("lomines.stats.others")) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
return filterStartsWith(getOnlinePlayerNames(), partial);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> completeTopFirstArg(String partial) {
|
||||||
List<String> completions = new ArrayList<>();
|
List<String> completions = new ArrayList<>();
|
||||||
|
|
||||||
if (args.length == 1) {
|
completions.addAll(filterStartsWith(getMineNames(), partial));
|
||||||
// First argument - suggest subcommands
|
|
||||||
String partial = args[0].toLowerCase();
|
|
||||||
|
|
||||||
for (String cmd : ALL_COMMANDS) {
|
if (isNumericPartial(partial)) {
|
||||||
if (cmd.startsWith(partial)) {
|
completions.addAll(filterStartsWith(TOP_LIMITS, partial));
|
||||||
// Check permission
|
|
||||||
if (hasPermission(sender, cmd)) {
|
|
||||||
completions.add(cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (args.length == 2) {
|
|
||||||
// Second argument - context-sensitive
|
|
||||||
String subcommand = args[0].toLowerCase();
|
|
||||||
String partial = args[1].toLowerCase();
|
|
||||||
|
|
||||||
switch (subcommand) {
|
|
||||||
case "delete", "reset", "maskscan", "edit", "setteleport", "setspawn", "clearspawn" ->
|
|
||||||
completions.addAll(getMineNames(partial));
|
|
||||||
case "create" -> {
|
|
||||||
if (partial.isEmpty()) {
|
|
||||||
completions.add("<name>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "stats" -> {
|
|
||||||
if (sender.hasPermission("lomines.stats.others")) {
|
|
||||||
completions.addAll(getOnlinePlayerNames(partial));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "group" -> {
|
|
||||||
completions.add("add");
|
|
||||||
completions.add("remove");
|
|
||||||
completions.add("clear");
|
|
||||||
}
|
|
||||||
case "wand" -> {
|
|
||||||
completions.add("give");
|
|
||||||
completions.add("toggle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (args.length == 3) {
|
|
||||||
// Third argument
|
|
||||||
String subcommand = args[0].toLowerCase();
|
|
||||||
String partial = args[2].toLowerCase();
|
|
||||||
|
|
||||||
switch (subcommand) {
|
|
||||||
case "group" -> {
|
|
||||||
if (args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) {
|
|
||||||
completions.addAll(getMineNames(partial));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return completions;
|
return completions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasPermission(CommandSender sender, String command) {
|
private List<String> completeTopSecondArg(String firstArg, String partial) {
|
||||||
return switch (command) {
|
boolean firstArgWasMine = plugin.getMines().find(firstArg).isPresent();
|
||||||
case "create", "delete", "reset", "reload", "list", "maskscan", "edit" ->
|
|
||||||
|
if (firstArgWasMine && isNumericPartial(partial)) {
|
||||||
|
return filterStartsWith(TOP_LIMITS, partial);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firstArgWasMine && isNumericPartial(firstArg)) {
|
||||||
|
return filterStartsWith(getMineNames(), partial);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNumericPartial(String partial) {
|
||||||
|
return partial.isEmpty() || partial.matches("\\d*");
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> filterStartsWith(List<String> options, String partial) {
|
||||||
|
return options.stream()
|
||||||
|
.filter(s -> s.toLowerCase().startsWith(partial))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getMineNames() {
|
||||||
|
return plugin.getMines().getAll().stream()
|
||||||
|
.map(mine -> mine.getName())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> getOnlinePlayerNames() {
|
||||||
|
return plugin.getServer().getOnlinePlayers().stream()
|
||||||
|
.map(Player::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasPermission(CommandSender sender, String cmd) {
|
||||||
|
return switch (cmd) {
|
||||||
|
case "create", "delete", "reload", "list", "maskscan", "edit" ->
|
||||||
sender.hasPermission("lomines.admin");
|
sender.hasPermission("lomines.admin");
|
||||||
|
case "reset" -> sender.hasPermission("lomines.admin.reset");
|
||||||
case "setteleport" -> sender.hasPermission("lomines.admin.setteleport");
|
case "setteleport" -> sender.hasPermission("lomines.admin.setteleport");
|
||||||
case "setspawn", "clearspawn" -> sender.hasPermission("lomines.admin.setspawn");
|
case "setspawn", "clearspawn" -> sender.hasPermission("lomines.admin.setspawn");
|
||||||
case "wand", "group" -> sender.hasPermission("lomines.admin.wand");
|
case "wand", "group" -> sender.hasPermission("lomines.admin.wand");
|
||||||
case "stats" -> sender.hasPermission("lomines.stats");
|
case "stats", "top" -> sender.hasPermission("lomines.stats");
|
||||||
case "top" -> sender.hasPermission("lomines.stats");
|
case "help" -> sender.hasPermission("lomines.use");
|
||||||
default -> true;
|
default -> true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getMineNames(String partial) {
|
|
||||||
return plugin.getMines().getAll().stream()
|
|
||||||
.map(mine -> mine.getName())
|
|
||||||
.filter(name -> name.toLowerCase().startsWith(partial))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getOnlinePlayerNames(String partial) {
|
|
||||||
return plugin.getServer().getOnlinePlayers().stream()
|
|
||||||
.map(Player::getName)
|
|
||||||
.filter(name -> name.toLowerCase().startsWith(partial))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,27 @@ import dev.loki.lomines.data.config.MineConfig;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main GUI for editing a mine.
|
* Main GUI for editing a mine.
|
||||||
* Provides navigation to sub-editors for different configuration sections.
|
* Provides navigation to sub-editors for different configuration sections.
|
||||||
|
* Improved UX with better materials, enhanced lore, and clearer information display.
|
||||||
*/
|
*/
|
||||||
public final class MineEditGui {
|
public final class MineEditGui {
|
||||||
|
|
||||||
private static final int SIZE = 54;
|
private static final int SIZE = 54;
|
||||||
private static final String TITLE_PREFIX = "Редактор шахты: ";
|
private static final String TITLE_PREFIX = "Редактор шахты: ";
|
||||||
|
|
||||||
// Slot constants
|
// Slot constants - organized in visual groups
|
||||||
public static final int SLOT_BACK = 49;
|
public static final int SLOT_BACK = 49;
|
||||||
public static final int SLOT_BLOCKS = 10;
|
public static final int SLOT_BLOCKS = 10;
|
||||||
public static final int SLOT_REGIONS = 12;
|
public static final int SLOT_REGIONS = 12;
|
||||||
|
|
@ -35,6 +38,16 @@ public final class MineEditGui {
|
||||||
public static final int SLOT_DELETE = 34;
|
public static final int SLOT_DELETE = 34;
|
||||||
public static final int SLOT_INFO = 40;
|
public static final int SLOT_INFO = 40;
|
||||||
|
|
||||||
|
// UI Constants
|
||||||
|
private static final String CLICK_EDIT = "§e▸ Нажмите для редактирования";
|
||||||
|
private static final String CLICK_BACK = "§c▸ Нажмите чтобы закрыть";
|
||||||
|
private static final String CLICK_SAVE = "§a▸ Нажмите для сохранения";
|
||||||
|
private static final String CLICK_DELETE = "§c▸ Нажмите для удаления";
|
||||||
|
private static final String SECTION_CONTENT = "§7Содержимое:";
|
||||||
|
private static final String SECTION_SETTINGS = "§7Настройки:";
|
||||||
|
private static final String SEPARATOR = "§8────────────────";
|
||||||
|
private static final String COMMANDS_HEADER = "§8Команды:";
|
||||||
|
|
||||||
private MineEditGui() {
|
private MineEditGui() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,37 +119,87 @@ public final class MineEditGui {
|
||||||
return pane;
|
return pane;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats location as short readable string.
|
||||||
|
*/
|
||||||
|
private static String formatLocation(Location loc) {
|
||||||
|
if (loc == null) return "§7не задана";
|
||||||
|
return String.format("§7%.0f §8/§7 %.0f §8/§7 %.0f §8(§7%s§8)",
|
||||||
|
loc.getX(), loc.getY(), loc.getZ(), loc.getWorld().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates string for preview display.
|
||||||
|
*/
|
||||||
|
private static String truncate(String str, int maxLen) {
|
||||||
|
if (str == null || str.isEmpty()) return "§7не задан";
|
||||||
|
if (str.length() <= maxLen) return str;
|
||||||
|
return str.substring(0, maxLen - 3) + "...";
|
||||||
|
}
|
||||||
|
|
||||||
private static ItemStack blocksItem(MineConfig config) {
|
private static ItemStack blocksItem(MineConfig config) {
|
||||||
ItemStack stack = new ItemStack(Material.DIAMOND_PICKAXE);
|
ItemStack stack = new ItemStack(Material.DIAMOND_PICKAXE);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aБлоки", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lБлоки", NamedTextColor.GREEN));
|
||||||
|
|
||||||
int blockCount = config.blocks().blockCount();
|
int blockCount = config.blocks().blockCount();
|
||||||
String fillMode = config.blocks().fillMode().name();
|
String fillMode = config.blocks().fillMode().name();
|
||||||
meta.lore(List.of(
|
boolean hasCustom = config.blocks().hasCustomBlocks();
|
||||||
Component.text("Типов блоков: " + blockCount, NamedTextColor.GRAY),
|
|
||||||
Component.text("Режим заполнения: " + fillMode, NamedTextColor.GRAY),
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.empty(),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.text("§eНажмите для редактирования", NamedTextColor.YELLOW)
|
lore.add(Component.text(SECTION_SETTINGS, NamedTextColor.GRAY));
|
||||||
));
|
lore.add(Component.text(" §fТипов: §7" + blockCount, NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §fРежим: §7" + fillMode, NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §fКастомные: " + (hasCustom ? "§aДа" : "§7Нет"), NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
// Show first few blocks as preview
|
||||||
|
var weights = config.blocks().weights();
|
||||||
|
if (!weights.isEmpty()) {
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§7Топ блоков:", NamedTextColor.GRAY));
|
||||||
|
weights.entrySet().stream()
|
||||||
|
.sorted((a, b) -> Double.compare(b.getValue(), a.getValue()))
|
||||||
|
.limit(3)
|
||||||
|
.forEach(e -> lore.add(Component.text(
|
||||||
|
String.format(" §8• §7%s §8(§7%.0f%%§8)",
|
||||||
|
e.getKey().serialize(), e.getValue() * 100),
|
||||||
|
NamedTextColor.GRAY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_EDIT, NamedTextColor.YELLOW));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack regionsItem(MineConfig config) {
|
private static ItemStack regionsItem(MineConfig config) {
|
||||||
ItemStack stack = new ItemStack(Material.GRASS_BLOCK);
|
ItemStack stack = new ItemStack(Material.COMPASS);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aРегионы", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lРегионы", NamedTextColor.GREEN));
|
||||||
|
|
||||||
int regionCount = config.region().regionCount();
|
int regionCount = config.region().regionCount();
|
||||||
int volume = config.region().totalVolume();
|
int volume = config.region().totalVolume();
|
||||||
meta.lore(List.of(
|
|
||||||
Component.text("Количество регионов: " + regionCount, NamedTextColor.GRAY),
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.text("Общий объём: " + volume + " блоков", NamedTextColor.GRAY),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.empty(),
|
lore.add(Component.text(SECTION_SETTINGS, NamedTextColor.GRAY));
|
||||||
Component.text("§7Только просмотр (изменяется через палочку)", NamedTextColor.GRAY)
|
lore.add(Component.text(" §fКоличество: §7" + regionCount, NamedTextColor.WHITE));
|
||||||
));
|
lore.add(Component.text(" §fОбщий объём: §7" + volume + " §8блоков", NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
// Show world info
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(" §fМир: §7" + config.worldName(), NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§8Изменяется через палочку", NamedTextColor.DARK_GRAY));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
|
|
@ -146,17 +209,32 @@ public final class MineEditGui {
|
||||||
ItemStack stack = new ItemStack(Material.CLOCK);
|
ItemStack stack = new ItemStack(Material.CLOCK);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aСброс", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lСброс", NamedTextColor.GREEN));
|
||||||
|
|
||||||
String interval = config.reset().intervalDisplay();
|
String interval = config.reset().intervalDisplay();
|
||||||
double percent = config.reset().percentTrigger();
|
double percent = config.reset().percentTrigger();
|
||||||
boolean percentEnabled = config.reset().isPercentTriggerEnabled();
|
boolean percentEnabled = config.reset().isPercentTriggerEnabled();
|
||||||
meta.lore(List.of(
|
int cmdCount = config.reset().commands().size();
|
||||||
Component.text("Интервал: " + interval, NamedTextColor.GRAY),
|
String broadcast = config.reset().broadcastMessage();
|
||||||
Component.text("Триггер по %: " + (percentEnabled ? percent + "%" : "выключен"), NamedTextColor.GRAY),
|
|
||||||
Component.text("Команд при сбросе: " + config.reset().commands().size(), NamedTextColor.GRAY),
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.empty(),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.text("§eНажмите для редактирования", NamedTextColor.YELLOW)
|
lore.add(Component.text(SECTION_SETTINGS, NamedTextColor.GRAY));
|
||||||
));
|
lore.add(Component.text(" §fИнтервал: §7" + interval, NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §fТриггер по %: " + (percentEnabled ? "§a" + percent + "%" : "§7выключен"), NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §fКоманд: §7" + cmdCount, NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
// Show broadcast status
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(" §fСообщение: " + (broadcast.isEmpty() ? "§7нет" : "§aесть"), NamedTextColor.WHITE));
|
||||||
|
if (!broadcast.isEmpty()) {
|
||||||
|
lore.add(Component.text(" §8" + truncate(broadcast, 25), NamedTextColor.DARK_GRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_EDIT, NamedTextColor.YELLOW));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
|
|
@ -166,13 +244,38 @@ public final class MineEditGui {
|
||||||
ItemStack stack = new ItemStack(Material.GOLD_INGOT);
|
ItemStack stack = new ItemStack(Material.GOLD_INGOT);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aНаграды", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lНаграды", NamedTextColor.GREEN));
|
||||||
int rewardCount = config.rewards().entries().size();
|
|
||||||
meta.lore(List.of(
|
var entries = config.rewards().entries();
|
||||||
Component.text("Настроено наград: " + rewardCount, NamedTextColor.GRAY),
|
int rewardCount = entries.size();
|
||||||
Component.empty(),
|
|
||||||
Component.text("§eНажмите для редактирования", NamedTextColor.YELLOW)
|
// Count reward types
|
||||||
));
|
long itemRewards = entries.stream()
|
||||||
|
.flatMap(e -> e.items().stream()).count();
|
||||||
|
long cmdRewards = entries.stream()
|
||||||
|
.filter(e -> !e.commands().isEmpty()).count();
|
||||||
|
long preventDrops = entries.stream()
|
||||||
|
.filter(RewardConfig.RewardEntry::preventVanillaDrops).count();
|
||||||
|
|
||||||
|
List<Component> lore = new ArrayList<>();
|
||||||
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
|
lore.add(Component.text(SECTION_SETTINGS, NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §fЗаписей: §7" + rewardCount, NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
if (rewardCount > 0) {
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§7Типы наград:", NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §8• §fПредметов: §7" + itemRewards, NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §8• §fКоманд: §7" + cmdRewards, NamedTextColor.WHITE));
|
||||||
|
if (preventDrops > 0) {
|
||||||
|
lore.add(Component.text(" §8• §cБлокируют дроп: §7" + preventDrops, NamedTextColor.WHITE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_EDIT, NamedTextColor.YELLOW));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
|
|
@ -182,87 +285,144 @@ public final class MineEditGui {
|
||||||
ItemStack stack = new ItemStack(Material.ENDER_PEARL);
|
ItemStack stack = new ItemStack(Material.ENDER_PEARL);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aТелепорт", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lТелепорт", NamedTextColor.GREEN));
|
||||||
boolean enabled = config.teleport().enabled();
|
|
||||||
|
boolean tpEnabled = config.teleport().enabled();
|
||||||
boolean spawnEnabled = config.playerSpawn().enabled();
|
boolean spawnEnabled = config.playerSpawn().enabled();
|
||||||
meta.lore(List.of(
|
|
||||||
Component.text("Включено: " + (enabled ? "§aДа" : "§cНет"), NamedTextColor.GRAY),
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.text("Точка спавна (застрявших): " + (spawnEnabled ? "§aДа" : "§7Нет"), NamedTextColor.GRAY),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.empty(),
|
lore.add(Component.text(SECTION_SETTINGS, NamedTextColor.GRAY));
|
||||||
Component.text("§eНажмите для редактирования", NamedTextColor.YELLOW),
|
|
||||||
Component.empty(),
|
// Teleport location
|
||||||
Component.text("§7Команды:", NamedTextColor.DARK_GRAY),
|
lore.add(Component.text(" §fТелепорт: " + (tpEnabled ? "§aвкл" : "§7выкл"), NamedTextColor.WHITE));
|
||||||
Component.text("§7/lm setteleport <mine>", NamedTextColor.GRAY),
|
if (tpEnabled) {
|
||||||
Component.text("§7/lm setspawn <mine>", NamedTextColor.GRAY),
|
config.teleport().getLocation().ifPresent(loc ->
|
||||||
Component.text("§7/lm clearspawn <mine>", NamedTextColor.GRAY)
|
lore.add(Component.text(" " + formatLocation(loc), NamedTextColor.WHITE)));
|
||||||
));
|
}
|
||||||
|
|
||||||
|
// Spawn location (for stuck players)
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(" §fСпавн (застрявших): " + (spawnEnabled ? "§aвкл" : "§7выкл"), NamedTextColor.WHITE));
|
||||||
|
if (spawnEnabled) {
|
||||||
|
config.playerSpawn().getLocation().ifPresent(loc ->
|
||||||
|
lore.add(Component.text(" " + formatLocation(loc), NamedTextColor.WHITE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command hints
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(COMMANDS_HEADER, NamedTextColor.DARK_GRAY));
|
||||||
|
lore.add(Component.text(" §8• §7/lm setteleport §f<mine>", NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §8• §7/lm setspawn §f<mine>", NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §8• §7/lm clearspawn §f<mine>", NamedTextColor.GRAY));
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_EDIT, NamedTextColor.YELLOW));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack uiItem(MineConfig config) {
|
private static ItemStack uiItem(MineConfig config) {
|
||||||
ItemStack stack = new ItemStack(Material.OAK_SIGN);
|
ItemStack stack = new ItemStack(Material.PAINTING);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aИнтерфейс", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lИнтерфейс", NamedTextColor.GREEN));
|
||||||
|
|
||||||
boolean actionBarEnabled = config.ui().actionBarEnabled();
|
boolean actionBarEnabled = config.ui().actionBarEnabled();
|
||||||
double range = config.ui().actionBarRange();
|
double range = config.ui().actionBarRange();
|
||||||
meta.lore(List.of(
|
String format = config.ui().actionBarFormat();
|
||||||
Component.text("Action Bar: " + (actionBarEnabled ? "§aВкл" : "§cВыкл"), NamedTextColor.GRAY),
|
String timerFmt = config.ui().timerFormat();
|
||||||
Component.text("Радиус: " + range, NamedTextColor.GRAY),
|
|
||||||
Component.empty(),
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.text("§eНажмите для редактирования", NamedTextColor.YELLOW)
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
));
|
lore.add(Component.text(SECTION_SETTINGS, NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §fAction Bar: " + (actionBarEnabled ? "§aвкл" : "§7выкл"), NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §fРадиус: §7" + (int) range + " §8блоков", NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
// Show format previews
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§7Формат ActionBar:", NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §8" + truncate(format, 28), NamedTextColor.DARK_GRAY));
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§7Формат таймера: §8" + timerFmt, NamedTextColor.GRAY));
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_EDIT, NamedTextColor.YELLOW));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack saveItem() {
|
private static ItemStack saveItem() {
|
||||||
ItemStack stack = new ItemStack(Material.LIME_CONCRETE);
|
ItemStack stack = new ItemStack(Material.LIME_DYE);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§aСохранить изменения", NamedTextColor.GREEN));
|
meta.displayName(Component.text("§a§lСохранить изменения", NamedTextColor.GREEN));
|
||||||
meta.lore(List.of(
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.text("§7Сохраняет текущую конфигурацию", NamedTextColor.GRAY),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.text("§7в файл шахты", NamedTextColor.GRAY)
|
lore.add(Component.text("§7Сохраняет конфигурацию шахты", NamedTextColor.GRAY));
|
||||||
));
|
lore.add(Component.text("§7в файл на диске", NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_SAVE, NamedTextColor.GREEN));
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack deleteItem(String mineName) {
|
private static ItemStack deleteItem(String mineName) {
|
||||||
ItemStack stack = new ItemStack(Material.RED_CONCRETE);
|
ItemStack stack = new ItemStack(Material.TNT);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§cУдалить шахту", NamedTextColor.RED));
|
meta.displayName(Component.text("§c§lУдалить шахту", NamedTextColor.RED));
|
||||||
meta.lore(List.of(
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.text("§cВнимание! Это действие нельзя отменить!", NamedTextColor.RED),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.empty(),
|
lore.add(Component.text("§c§lВнимание!", NamedTextColor.RED));
|
||||||
Component.text("§7Шахта: " + mineName, NamedTextColor.GRAY)
|
lore.add(Component.text("§cЭто действие нельзя отменить!", NamedTextColor.RED));
|
||||||
));
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§7Шахта: §f" + mineName, NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text(CLICK_DELETE, NamedTextColor.RED));
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack infoItem(Mine mine) {
|
private static ItemStack infoItem(Mine mine) {
|
||||||
ItemStack stack = new ItemStack(Material.PAPER);
|
ItemStack stack = new ItemStack(Material.BOOK);
|
||||||
ItemMeta meta = stack.getItemMeta();
|
ItemMeta meta = stack.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
meta.displayName(Component.text("§bИнформация", NamedTextColor.AQUA));
|
meta.displayName(Component.text("§b§lИнформация", NamedTextColor.AQUA));
|
||||||
|
|
||||||
int blocks = mine.getBlocks();
|
int blocks = mine.getBlocks();
|
||||||
int total = mine.getTotalVolume();
|
int total = mine.getTotalVolume();
|
||||||
double percent = mine.getPercentFilled();
|
double percent = mine.getPercentFilled();
|
||||||
meta.lore(List.of(
|
String statusColor = percent > 50 ? "§a" : percent > 25 ? "§e" : "§c";
|
||||||
Component.text("Название: " + mine.getName(), NamedTextColor.GRAY),
|
|
||||||
Component.text("Мир: " + mine.getConfig().worldName(), NamedTextColor.GRAY),
|
List<Component> lore = new ArrayList<>();
|
||||||
Component.empty(),
|
lore.add(Component.text(SEPARATOR, NamedTextColor.DARK_GRAY));
|
||||||
Component.text("Заполнено: " + blocks + "/" + total, NamedTextColor.GRAY),
|
lore.add(Component.text("§7Базовые данные:", NamedTextColor.GRAY));
|
||||||
Component.text("Процент: " + String.format("%.1f%%", percent), NamedTextColor.GRAY)
|
lore.add(Component.text(" §fНазвание: §7" + mine.getName(), NamedTextColor.WHITE));
|
||||||
));
|
lore.add(Component.text(" §fМир: §7" + mine.getConfig().worldName(), NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
lore.add(Component.empty());
|
||||||
|
lore.add(Component.text("§7Состояние заполнения:", NamedTextColor.GRAY));
|
||||||
|
lore.add(Component.text(" §fБлоков: " + statusColor + blocks + "§8/§7" + total, NamedTextColor.WHITE));
|
||||||
|
lore.add(Component.text(" §fПроцент: " + statusColor + String.format("%.1f%%", percent), NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
// Visual percentage bar
|
||||||
|
int barLen = 10;
|
||||||
|
int filled = (int) Math.round(percent / 100.0 * barLen);
|
||||||
|
String bar = "§a" + "█".repeat(filled) + "§8" + "░".repeat(barLen - filled);
|
||||||
|
lore.add(Component.text(" " + bar, NamedTextColor.WHITE));
|
||||||
|
|
||||||
|
meta.lore(lore);
|
||||||
stack.setItemMeta(meta);
|
stack.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
return stack;
|
return stack;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue