Improved help system with category selector and main page
This commit is contained in:
parent
0f664e317e
commit
f43db6a527
10 changed files with 275 additions and 52 deletions
|
|
@ -100,4 +100,9 @@ public class ClearCommand implements Command {
|
|||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Модерация";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class MinusRepCommand implements Command {
|
|||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Развлечения";
|
||||
return "Статистика";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class RepCommand implements Command {
|
|||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Развлечения";
|
||||
return "Статистика";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class RepTopCommand implements Command {
|
|||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Развлечения";
|
||||
return "Статистика";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public class StatsCommand implements Command {
|
|||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Развлечения";
|
||||
return "Статистика";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import creator.loki.command.CommandContext;
|
|||
import creator.loki.config.BotConfig;
|
||||
import creator.loki.core.CommandRegistry;
|
||||
import creator.loki.embed.EmbedFactory;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -18,17 +20,32 @@ public class HelpCommand implements Command {
|
|||
|
||||
private static final Map<String, String> CATEGORY_EMOJIS = new HashMap<>();
|
||||
private static final Map<String, Color> CATEGORY_COLORS = new HashMap<>();
|
||||
private static final Map<String, String> CATEGORY_DESCRIPTIONS = new HashMap<>();
|
||||
|
||||
static {
|
||||
CATEGORY_EMOJIS.put("Общие", "📋");
|
||||
CATEGORY_EMOJIS.put("Роли", "🎭");
|
||||
CATEGORY_EMOJIS.put("Развлечения", "🎮");
|
||||
CATEGORY_EMOJIS.put("Модерация", "🛡️");
|
||||
CATEGORY_EMOJIS.put("Статистика", "📊");
|
||||
CATEGORY_EMOJIS.put("Утилиты", "🔧");
|
||||
CATEGORY_EMOJIS.put("Настройка", "⚙️");
|
||||
|
||||
CATEGORY_COLORS.put("Общие", new Color(52, 152, 219));
|
||||
CATEGORY_COLORS.put("Роли", new Color(155, 89, 182));
|
||||
CATEGORY_COLORS.put("Развлечения", new Color(241, 196, 15));
|
||||
CATEGORY_COLORS.put("Модерация", new Color(231, 76, 60));
|
||||
CATEGORY_COLORS.put("Статистика", new Color(46, 204, 113));
|
||||
CATEGORY_COLORS.put("Утилиты", new Color(52, 152, 219));
|
||||
CATEGORY_COLORS.put("Настройка", new Color(149, 165, 166));
|
||||
|
||||
CATEGORY_DESCRIPTIONS.put("Общие", "Основные команды бота");
|
||||
CATEGORY_DESCRIPTIONS.put("Роли", "Управление кастомными ролями");
|
||||
CATEGORY_DESCRIPTIONS.put("Развлечения", "Игры и взаимодействия");
|
||||
CATEGORY_DESCRIPTIONS.put("Модерация", "Команды модерации сервера");
|
||||
CATEGORY_DESCRIPTIONS.put("Статистика", "Уровни, репутация и статистика");
|
||||
CATEGORY_DESCRIPTIONS.put("Утилиты", "Полезные инструменты");
|
||||
CATEGORY_DESCRIPTIONS.put("Настройка", "Настройка систем бота (только админы)");
|
||||
}
|
||||
|
||||
public HelpCommand(CommandRegistry registry, BotConfig config) {
|
||||
|
|
@ -49,65 +66,94 @@ public class HelpCommand implements Command {
|
|||
@Override
|
||||
public void execute(CommandContext context) {
|
||||
var commands = registry.getAllCommands();
|
||||
|
||||
// Группируем команды по категориям
|
||||
Map<String, List<Command>> commandsByCategory = commands.stream()
|
||||
.collect(Collectors.groupingBy(Command::getCategory));
|
||||
|
||||
// Создаём красивый embed
|
||||
EmbedFactory embed = EmbedFactory.create()
|
||||
.setTitle("📚 Справка по командам")
|
||||
.setDescription(
|
||||
"**Префикс:** `" + config.getPrefix() + "`\n" +
|
||||
"**Всего команд:** " + commands.size() + "\n\n" +
|
||||
"Используй `" + config.getPrefix() + "<команда>` для выполнения"
|
||||
)
|
||||
.setColor(new Color(88, 101, 242))
|
||||
.setThumbnail(context.getGuild() != null ?
|
||||
context.getGuild().getIconUrl() : null);
|
||||
// Главная страница
|
||||
EmbedFactory embed = createMainPage(context, commandsByCategory);
|
||||
|
||||
// Добавляем команды по категориям
|
||||
commandsByCategory.forEach((category, cmds) -> {
|
||||
String emoji = CATEGORY_EMOJIS.getOrDefault(category, "📌");
|
||||
StringBuilder commandList = new StringBuilder();
|
||||
// Создаём селектор категорий
|
||||
StringSelectMenu.Builder menuBuilder = StringSelectMenu.create("help:category")
|
||||
.setPlaceholder("📂 Выберите категорию");
|
||||
|
||||
int count = 0;
|
||||
int part = 1;
|
||||
boolean isAdmin = context.getAuthor() != null &&
|
||||
context.getAuthor().hasPermission(Permission.ADMINISTRATOR);
|
||||
|
||||
for (Command cmd : cmds) {
|
||||
String cmdText = "`" + config.getPrefix() + cmd.getUsage() + "`\n" +
|
||||
cmd.getDescription() + "\n\n";
|
||||
|
||||
// Если добавление команды превысит лимит, создаём новое поле
|
||||
if (commandList.length() + cmdText.length() > 1000) {
|
||||
embed.addField(
|
||||
emoji + " " + category + (part > 1 ? " (" + part + ")" : ""),
|
||||
commandList.toString().trim(),
|
||||
false
|
||||
);
|
||||
commandList = new StringBuilder();
|
||||
part++;
|
||||
commandsByCategory.keySet().stream()
|
||||
.sorted()
|
||||
.forEach(category -> {
|
||||
// Скрываем категорию "Настройка" для не-админов
|
||||
if (category.equals("Настройка") && !isAdmin) {
|
||||
return;
|
||||
}
|
||||
|
||||
commandList.append(cmdText);
|
||||
count++;
|
||||
}
|
||||
String emoji = CATEGORY_EMOJIS.getOrDefault(category, "📌");
|
||||
String description = CATEGORY_DESCRIPTIONS.getOrDefault(category, "Команды категории");
|
||||
int count = commandsByCategory.get(category).size();
|
||||
|
||||
// Добавляем оставшиеся команды
|
||||
if (commandList.length() > 0) {
|
||||
embed.addField(
|
||||
emoji + " " + category + (part > 1 ? " (" + part + ")" : ""),
|
||||
commandList.toString().trim(),
|
||||
false
|
||||
menuBuilder.addOption(
|
||||
category,
|
||||
"category:" + category,
|
||||
description + " (" + count + " команд)",
|
||||
net.dv8tion.jda.api.entities.emoji.Emoji.fromUnicode(emoji)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
embed.setFooter(
|
||||
"Запросил: " + context.getAuthor().getUser().getName(),
|
||||
context.getAuthor().getUser().getAvatarUrl()
|
||||
);
|
||||
context.getChannel()
|
||||
.sendMessageEmbeds(embed.build())
|
||||
.addActionRow(menuBuilder.build())
|
||||
.queue();
|
||||
}
|
||||
|
||||
context.getChannel().sendMessageEmbeds(embed.build()).queue();
|
||||
private EmbedFactory createMainPage(CommandContext context, Map<String, List<Command>> commandsByCategory) {
|
||||
int totalCommands = commandsByCategory.values().stream()
|
||||
.mapToInt(List::size)
|
||||
.sum();
|
||||
|
||||
boolean isAdmin = context.getAuthor() != null &&
|
||||
context.getAuthor().hasPermission(Permission.ADMINISTRATOR);
|
||||
|
||||
StringBuilder categoriesText = new StringBuilder();
|
||||
commandsByCategory.keySet().stream()
|
||||
.sorted()
|
||||
.forEach(category -> {
|
||||
// Скрываем категорию "Настройка" для не-админов
|
||||
if (category.equals("Настройка") && !isAdmin) {
|
||||
return;
|
||||
}
|
||||
|
||||
String emoji = CATEGORY_EMOJIS.getOrDefault(category, "📌");
|
||||
int count = commandsByCategory.get(category).size();
|
||||
categoriesText.append(emoji).append(" **").append(category)
|
||||
.append("** — ").append(count).append(" команд\n");
|
||||
});
|
||||
|
||||
return EmbedFactory.create()
|
||||
.setTitle("📚 Справка по командам Loki Bot")
|
||||
.setDescription(
|
||||
"Привет! Я многофункциональный Discord бот с системой уровней, " +
|
||||
"личными голосовыми каналами и множеством развлекательных команд.\n\n" +
|
||||
"**Префикс команд:** `" + config.getPrefix() + "`\n" +
|
||||
"**Всего команд:** " + totalCommands + "\n\n" +
|
||||
"**📂 Категории команд:**\n" + categoriesText.toString() + "\n" +
|
||||
"Используй селектор ниже для просмотра команд категории."
|
||||
)
|
||||
.setColor(new Color(88, 101, 242))
|
||||
.setThumbnail(context.getGuild() != null ? context.getGuild().getIconUrl() : null)
|
||||
.addField("💡 Как использовать",
|
||||
"Большинство команд используют префикс `!`\n" +
|
||||
"Пример: `!rank`, `!ship @user1 @user2`\n\n" +
|
||||
"Некоторые важные команды используют `/`\n" +
|
||||
"Пример: `/voice-setup`, `/counter-setup`",
|
||||
false)
|
||||
.setFooter(
|
||||
"Запросил: " + context.getAuthor().getUser().getName(),
|
||||
context.getAuthor().getUser().getAvatarUrl()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Утилиты";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,4 +113,9 @@ public class InfoCommand implements Command {
|
|||
.build()
|
||||
).queue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Утилиты";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,4 +36,9 @@ public class PingCommand implements Command {
|
|||
).queue();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return "Утилиты";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public class BotInitializer {
|
|||
private final VoiceButtonHandler voiceButtonHandler;
|
||||
private final ModerationLogger moderationLogger;
|
||||
private final LevelUpNotifier levelUpNotifier;
|
||||
private final HelpMenuHandler helpMenuHandler;
|
||||
|
||||
@Inject
|
||||
public BotInitializer(
|
||||
|
|
@ -102,6 +103,7 @@ public class BotInitializer {
|
|||
this.logSetupCommand = new LogSetupCommand(configRepo);
|
||||
this.voiceButtonHandler = new VoiceButtonHandler(voiceChannelManager);
|
||||
this.moderationLogger = new ModerationLogger(configRepo);
|
||||
this.helpMenuHandler = new HelpMenuHandler(registry, config);
|
||||
}
|
||||
|
||||
public JDA start() {
|
||||
|
|
@ -160,6 +162,7 @@ public class BotInitializer {
|
|||
logSetupCommand,
|
||||
voiceButtonHandler,
|
||||
moderationLogger,
|
||||
helpMenuHandler,
|
||||
new LeaderboardButtonListener(levelSystem)
|
||||
)
|
||||
.build();
|
||||
|
|
|
|||
159
src/main/java/creator/loki/listener/HelpMenuHandler.java
Normal file
159
src/main/java/creator/loki/listener/HelpMenuHandler.java
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
package creator.loki.listener;
|
||||
|
||||
import creator.loki.command.Command;
|
||||
import creator.loki.config.BotConfig;
|
||||
import creator.loki.core.CommandRegistry;
|
||||
import creator.loki.embed.EmbedFactory;
|
||||
import net.dv8tion.jda.api.Permission;
|
||||
import net.dv8tion.jda.api.events.interaction.component.StringSelectInteractionEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.interactions.components.selections.StringSelectMenu;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class HelpMenuHandler extends ListenerAdapter {
|
||||
private final CommandRegistry registry;
|
||||
private final BotConfig config;
|
||||
|
||||
private static final Map<String, String> CATEGORY_EMOJIS = new HashMap<>();
|
||||
private static final Map<String, Color> CATEGORY_COLORS = new HashMap<>();
|
||||
|
||||
static {
|
||||
CATEGORY_EMOJIS.put("Общие", "📋");
|
||||
CATEGORY_EMOJIS.put("Роли", "🎭");
|
||||
CATEGORY_EMOJIS.put("Развлечения", "🎮");
|
||||
CATEGORY_EMOJIS.put("Модерация", "🛡️");
|
||||
CATEGORY_EMOJIS.put("Статистика", "📊");
|
||||
CATEGORY_EMOJIS.put("Утилиты", "🔧");
|
||||
CATEGORY_EMOJIS.put("Настройка", "⚙️");
|
||||
|
||||
CATEGORY_COLORS.put("Общие", new Color(52, 152, 219));
|
||||
CATEGORY_COLORS.put("Роли", new Color(155, 89, 182));
|
||||
CATEGORY_COLORS.put("Развлечения", new Color(241, 196, 15));
|
||||
CATEGORY_COLORS.put("Модерация", new Color(231, 76, 60));
|
||||
CATEGORY_COLORS.put("Статистика", new Color(46, 204, 113));
|
||||
CATEGORY_COLORS.put("Утилиты", new Color(52, 152, 219));
|
||||
CATEGORY_COLORS.put("Настройка", new Color(149, 165, 166));
|
||||
}
|
||||
|
||||
public HelpMenuHandler(CommandRegistry registry, BotConfig config) {
|
||||
this.registry = registry;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStringSelectInteraction(StringSelectInteractionEvent event) {
|
||||
if (!event.getComponentId().equals("help:category")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String selectedValue = event.getValues().get(0);
|
||||
if (!selectedValue.startsWith("category:")) {
|
||||
return;
|
||||
}
|
||||
|
||||
String category = selectedValue.substring("category:".length());
|
||||
|
||||
// Проверка прав для категории "Настройка"
|
||||
if (category.equals("Настройка") && event.getMember() != null &&
|
||||
!event.getMember().hasPermission(Permission.ADMINISTRATOR)) {
|
||||
event.reply("❌ Эта категория доступна только администраторам!")
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
var commands = registry.getAllCommands();
|
||||
Map<String, List<Command>> commandsByCategory = commands.stream()
|
||||
.collect(Collectors.groupingBy(Command::getCategory));
|
||||
|
||||
List<Command> categoryCommands = commandsByCategory.get(category);
|
||||
if (categoryCommands == null || categoryCommands.isEmpty()) {
|
||||
event.reply("❌ В этой категории нет команд!")
|
||||
.setEphemeral(true)
|
||||
.queue();
|
||||
return;
|
||||
}
|
||||
|
||||
// Создаём embed для категории
|
||||
EmbedFactory embed = createCategoryEmbed(category, categoryCommands, event);
|
||||
|
||||
// Пересоздаём селектор
|
||||
StringSelectMenu.Builder menuBuilder = StringSelectMenu.create("help:category")
|
||||
.setPlaceholder("📂 Выберите категорию");
|
||||
|
||||
boolean isAdmin = event.getMember() != null &&
|
||||
event.getMember().hasPermission(Permission.ADMINISTRATOR);
|
||||
|
||||
commandsByCategory.keySet().stream()
|
||||
.sorted()
|
||||
.forEach(cat -> {
|
||||
if (cat.equals("Настройка") && !isAdmin) {
|
||||
return;
|
||||
}
|
||||
|
||||
String emoji = CATEGORY_EMOJIS.getOrDefault(cat, "📌");
|
||||
int count = commandsByCategory.get(cat).size();
|
||||
|
||||
menuBuilder.addOption(
|
||||
cat,
|
||||
"category:" + cat,
|
||||
count + " команд",
|
||||
net.dv8tion.jda.api.entities.emoji.Emoji.fromUnicode(emoji)
|
||||
);
|
||||
});
|
||||
|
||||
event.editMessageEmbeds(embed.build())
|
||||
.setActionRow(menuBuilder.build())
|
||||
.queue();
|
||||
}
|
||||
|
||||
private EmbedFactory createCategoryEmbed(String category, List<Command> commands,
|
||||
StringSelectInteractionEvent event) {
|
||||
String emoji = CATEGORY_EMOJIS.getOrDefault(category, "📌");
|
||||
Color color = CATEGORY_COLORS.getOrDefault(category, new Color(88, 101, 242));
|
||||
|
||||
EmbedFactory embed = EmbedFactory.create()
|
||||
.setTitle(emoji + " " + category)
|
||||
.setDescription("Список команд категории **" + category + "**\n" +
|
||||
"Префикс: `" + config.getPrefix() + "`")
|
||||
.setColor(color);
|
||||
|
||||
// Группируем команды по 8 в поле
|
||||
StringBuilder commandList = new StringBuilder();
|
||||
int count = 0;
|
||||
|
||||
for (Command cmd : commands) {
|
||||
String prefix = cmd.getName().startsWith("/") ? "" : config.getPrefix();
|
||||
commandList.append("`").append(prefix).append(cmd.getUsage()).append("`\n")
|
||||
.append(cmd.getDescription()).append("\n\n");
|
||||
count++;
|
||||
|
||||
// Если достигли 8 команд или лимита символов, создаём новое поле
|
||||
if (count % 8 == 0 || commandList.length() > 900) {
|
||||
embed.addField("", commandList.toString().trim(), false);
|
||||
commandList = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем оставшиеся команды
|
||||
if (commandList.length() > 0) {
|
||||
embed.addField("", commandList.toString().trim(), false);
|
||||
}
|
||||
|
||||
embed.addField("💡 Подсказка",
|
||||
"Используй селектор ниже для переключения между категориями",
|
||||
false);
|
||||
|
||||
embed.setFooter(
|
||||
"Запросил: " + event.getUser().getName() + " • Всего команд: " + commands.size(),
|
||||
event.getUser().getAvatarUrl()
|
||||
);
|
||||
|
||||
return embed;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue