命令系统4

This commit is contained in:
Xujiayao 2026-01-13 15:01:46 +08:00
parent 38f4839c4f
commit d6d0307ea0
8 changed files with 268 additions and 13 deletions

View file

@ -0,0 +1,86 @@
package com.xujiayao.discord_mc_chat.commands;
import com.xujiayao.discord_mc_chat.commands.impl.HelpCommand;
import com.xujiayao.discord_mc_chat.commands.impl.ReloadCommand;
import com.xujiayao.discord_mc_chat.commands.impl.ShutdownCommand;
import com.xujiayao.discord_mc_chat.utils.config.ModeManager;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.xujiayao.discord_mc_chat.Constants.LOGGER;
/**
* Central registry and dispatcher for DMCC commands.
*
* @author Xujiayao
*/
public class CommandManager {
private static final Map<String, Command> COMMANDS = new ConcurrentHashMap<>();
/**
* Initialize and register built-in commands based on the current operating mode.
*/
public static void initialize() {
COMMANDS.clear();
register(new HelpCommand());
register(new ReloadCommand());
if ("standalone".equals(ModeManager.getMode())) {
register(new ShutdownCommand());
}
}
/**
* Register a command.
*
* @param command The command to register
*/
public static void register(Command command) {
COMMANDS.put(command.name().toLowerCase(), command);
}
/**
* Get all registered commands.
*
* @return A collection of registered commands
*/
public static Collection<Command> getCommands() {
return new ArrayList<>(COMMANDS.values());
}
/**
* Execute a command line.
*
* @param sender The command sender
* @param rawInput The raw command line
*/
public static void execute(CommandSender sender, String rawInput) {
String line = rawInput == null ? "" : rawInput.trim();
if (line.isEmpty()) {
sender.reply(I18nManager.getDmccTranslation("terminal.unknown_command", rawInput));
return;
}
String[] parts = line.split("\\s+");
String name = parts[0].toLowerCase();
String[] args = parts.length > 1 ? line.substring(line.indexOf(' ') + 1).split("\\s+") : new String[0];
Command command = COMMANDS.get(name);
if (command == null) {
sender.reply(I18nManager.getDmccTranslation("terminal.unknown_command", rawInput));
return;
}
try {
command.execute(sender, args);
} catch (Exception e) {
sender.reply("Command execution failed: " + e.getMessage());
}
}
}

View file

@ -0,0 +1,47 @@
package com.xujiayao.discord_mc_chat.commands.impl;
import com.xujiayao.discord_mc_chat.commands.Command;
import com.xujiayao.discord_mc_chat.commands.CommandManager;
import com.xujiayao.discord_mc_chat.commands.CommandSender;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
import java.util.Comparator;
/**
* Help command implementation.
*
* @author Xujiayao
*/
public class HelpCommand implements Command {
@Override
public String name() {
return "help";
}
@Override
public CommandArgument[] args() {
return new CommandArgument[0];
}
@Override
public String description() {
return I18nManager.getDmccTranslation("commands.help.description");
}
@Override
public void execute(CommandSender sender, String... args) {
StringBuilder builder = new StringBuilder();
builder.append(I18nManager.getDmccTranslation("commands.help.description")).append("\n");
CommandManager.getCommands().stream()
.sorted(Comparator.comparing(Command::name))
.forEach(cmd -> builder.append("- ")
.append(cmd.name())
.append(": ")
.append(cmd.description())
.append("\n"));
sender.reply(builder.toString().trim());
}
}

View file

@ -0,0 +1,41 @@
package com.xujiayao.discord_mc_chat.commands.impl;
import com.xujiayao.discord_mc_chat.DMCC;
import com.xujiayao.discord_mc_chat.commands.Command;
import com.xujiayao.discord_mc_chat.commands.CommandSender;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
/**
* Reload command implementation.
*
* @author Xujiayao
*/
public class ReloadCommand implements Command {
@Override
public String name() {
return "reload";
}
@Override
public CommandArgument[] args() {
return new CommandArgument[0];
}
@Override
public String description() {
return I18nManager.getDmccTranslation("commands.reload.description");
}
@Override
public void execute(CommandSender sender, String... args) {
Thread thread = new Thread(() -> {
if (DMCC.reload()) {
sender.reply(I18nManager.getDmccTranslation("commands.reload.success"));
} else {
sender.reply(I18nManager.getDmccTranslation("commands.reload.failure", "See logs for details"));
}
}, "DMCC-ReloadCommand");
thread.start();
}
}

View file

@ -0,0 +1,35 @@
package com.xujiayao.discord_mc_chat.commands.impl;
import com.xujiayao.discord_mc_chat.DMCC;
import com.xujiayao.discord_mc_chat.commands.Command;
import com.xujiayao.discord_mc_chat.commands.CommandSender;
import com.xujiayao.discord_mc_chat.standalone.StandaloneDMCC;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
/**
* Shutdown command implementation (standalone only).
*
* @author Xujiayao
*/
public class ShutdownCommand implements Command {
@Override
public String name() {
return "shutdown";
}
@Override
public CommandArgument[] args() {
return new CommandArgument[0];
}
@Override
public String description() {
return I18nManager.getDmccTranslation("commands.shutdown.description");
}
@Override
public void execute(CommandSender sender, String... args) {
System.exit(0);
}
}

View file

@ -1,5 +1,6 @@
package com.xujiayao.discord_mc_chat.server.discord;
import com.xujiayao.discord_mc_chat.commands.CommandManager;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.events.session.ReadyEvent;
@ -21,6 +22,9 @@ public class DiscordEventHandler extends ListenerAdapter {
@Override
public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) {
event.deferReply().queue();
// TODO Confirm whether event.getName() is correct
CommandManager.execute(new JdaCommandSender(event), event.getName());
}
@Override

View file

@ -1,14 +1,18 @@
package com.xujiayao.discord_mc_chat.server.discord;
import com.xujiayao.discord_mc_chat.utils.config.ConfigManager;
import com.xujiayao.discord_mc_chat.utils.config.ModeManager;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.JDABuilder;
import net.dv8tion.jda.api.interactions.commands.build.CommandData;
import net.dv8tion.jda.api.interactions.commands.build.Commands;
import net.dv8tion.jda.api.requests.GatewayIntent;
import net.dv8tion.jda.api.utils.MemberCachePolicy;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import static com.xujiayao.discord_mc_chat.Constants.LOGGER;
@ -47,10 +51,15 @@ public class DiscordManager {
LOGGER.info("Discord bot is ready. Logged in as tag: \"{}\"", jda.getSelfUser().getAsTag());
List<CommandData> commands = new ArrayList<>();
commands.add(Commands.slash("help", I18nManager.getDmccTranslation("commands.help.description")));
commands.add(Commands.slash("reload", I18nManager.getDmccTranslation("commands.reload.description")));
if ("standalone".equals(ModeManager.getMode())) {
commands.add(Commands.slash("shutdown", I18nManager.getDmccTranslation("commands.shutdown.description")));
}
jda.updateCommands()
.addCommands(Commands.slash("help", I18nManager.getDmccTranslation("commands.help.description")))
.addCommands(Commands.slash("reload", I18nManager.getDmccTranslation("commands.reload.description")))
.addCommands(Commands.slash("shutdown", I18nManager.getDmccTranslation("commands.shutdown.description")))
.addCommands(commands)
.queue();
return true;

View file

@ -0,0 +1,23 @@
package com.xujiayao.discord_mc_chat.server.discord;
import com.xujiayao.discord_mc_chat.commands.CommandSender;
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent;
/**
* Command sender implementation for JDA slash commands.
*
* @author Xujiayao
*/
public class JdaCommandSender implements CommandSender {
private final SlashCommandInteractionEvent event;
public JdaCommandSender(SlashCommandInteractionEvent event) {
this.event = event;
}
@Override
public void reply(String message) {
event.getHook().sendMessage("```" + message + "```").queue();
}
}

View file

@ -1,5 +1,7 @@
package com.xujiayao.discord_mc_chat.standalone;
import com.xujiayao.discord_mc_chat.commands.CommandManager;
import com.xujiayao.discord_mc_chat.commands.CommandSender;
import com.xujiayao.discord_mc_chat.utils.i18n.I18nManager;
import java.util.Scanner;
@ -33,20 +35,12 @@ public class TerminalManager {
if (scanner.hasNextLine()) {
String line = scanner.nextLine();
// Remove leading slash if present
if (line.startsWith("/")) {
line = line.substring(1);
}
String command = line.trim().split("\\s+")[0];
// Arguments do not include the command itself
String[] args = line.trim().split("\\s+").length > 1
? line.trim().split("\\s+", 2)[1].split("\\s+")
: new String[0];
// TODO Handle command
if (true) {
LOGGER.error(I18nManager.getDmccTranslation("terminal.unknown_command", line));
}
CommandManager.execute(new TerminalCommandSender(), line);
}
} catch (IllegalStateException e) {
// This can happen if System.in is closed externally, which signals the end.
@ -61,4 +55,20 @@ public class TerminalManager {
terminalThread.setDaemon(true);
terminalThread.start();
}
/**
* A CommandSender implementation for terminal commands.
*
* @author Xujiayao
*/
private static class TerminalCommandSender implements CommandSender {
@Override
public void reply(String message) {
// For each line in the message, send a separate log message
for (String line : message.split("\n")) {
LOGGER.info(line);
}
}
}
}