From 3e2b63c99dad5e61402fc5e0650a8285d8566190 Mon Sep 17 00:00:00 2001 From: MC_XiaoHei Date: Sun, 24 Aug 2025 12:09:21 +0800 Subject: [PATCH] feat: add bot remove, fix stupid me --- .../org/leavesmc/leaves/LeavesConfig.java | 11 +- .../java/org/leavesmc/leaves/bot/BotList.java | 2 +- .../leavesmc/leaves/entity/bot/CraftBot.java | 3 +- .../leaves/neo_command/bot/BotCommand.java | 8 +- .../bot/subcommands/RemoveCommand.java | 155 ++++++++++++++++++ .../bot/subcommands/SaveCommand.java | 21 +-- 6 files changed, 174 insertions(+), 26 deletions(-) create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/RemoveCommand.java diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java b/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java index c613b9e3..3bb30b2e 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/LeavesConfig.java @@ -54,7 +54,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Random; import java.util.function.Predicate; @@ -127,13 +126,6 @@ public final class LeavesConfig { MinecraftServer.getServer().server.syncCommands(); } - public static void unregisterCommand(String name) { - name = name.toLowerCase(Locale.ENGLISH).trim(); - MinecraftServer.getServer().server.getCommandMap().getKnownCommands().remove(name); - MinecraftServer.getServer().server.getCommandMap().getKnownCommands().remove("leaves:" + name); - MinecraftServer.getServer().server.syncCommands(); - } - public static ModifyConfig modify = new ModifyConfig(); @GlobalConfigCategory("modify") @@ -152,10 +144,9 @@ public final class LeavesConfig { @Override public void verify(Boolean old, Boolean value) throws IllegalArgumentException { if (value) { - BotCommand.INSTANCE.register(); Actions.registerAll(); + BotCommand.INSTANCE.register(); } else { - unregisterCommand("bot"); BotCommand.INSTANCE.unregister(); } if (old != null && !old.equals(value)) { diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotList.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotList.java index 9a7ba737..f0581ef1 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotList.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotList.java @@ -191,7 +191,7 @@ public class BotList { this.server.server.getPluginManager().callEvent(event); if (event.isCancelled() && event.getReason() != BotRemoveEvent.RemoveReason.INTERNAL) { - return true; + return false; } if (bot.removeTaskId != -1) { diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java b/leaves-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java index e8205d26..3ce7adac 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java @@ -70,8 +70,7 @@ public class CraftBot extends CraftPlayer implements Bot { @Override public boolean remove(boolean save) { - BotList.INSTANCE.removeBot(this.getHandle(), BotRemoveEvent.RemoveReason.PLUGIN, null, save); - return true; + return BotList.INSTANCE.removeBot(this.getHandle(), BotRemoveEvent.RemoveReason.PLUGIN, null, save); } @Override diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/BotCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/BotCommand.java index 89947169..ce526286 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/BotCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/BotCommand.java @@ -12,6 +12,7 @@ import org.leavesmc.leaves.neo_command.bot.subcommands.ConfigCommand; import org.leavesmc.leaves.neo_command.bot.subcommands.CreateCommand; import org.leavesmc.leaves.neo_command.bot.subcommands.ListCommand; import org.leavesmc.leaves.neo_command.bot.subcommands.LoadCommand; +import org.leavesmc.leaves.neo_command.bot.subcommands.RemoveCommand; import org.leavesmc.leaves.neo_command.bot.subcommands.SaveCommand; import java.util.ArrayList; @@ -24,12 +25,13 @@ public class BotCommand extends LiteralNode { private BotCommand() { super("bot"); this.children( - ActionCommand::new, ListCommand::new, - CreateCommand::new, + ConfigCommand::new, + RemoveCommand::new, LoadCommand::new, SaveCommand::new, - ConfigCommand::new + ActionCommand::new, + CreateCommand::new ); } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/RemoveCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/RemoveCommand.java new file mode 100644 index 00000000..34b11317 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/RemoveCommand.java @@ -0,0 +1,155 @@ +package org.leavesmc.leaves.neo_command.bot.subcommands; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import io.papermc.paper.adventure.PaperAdventure; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.event.bot.BotRemoveEvent; +import org.leavesmc.leaves.neo_command.ArgumentNode; +import org.leavesmc.leaves.neo_command.CommandContext; +import org.leavesmc.leaves.neo_command.CustomArgumentNode; +import org.leavesmc.leaves.neo_command.bot.BotSubcommand; +import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static net.kyori.adventure.text.Component.join; +import static net.kyori.adventure.text.Component.text; +import static net.kyori.adventure.text.JoinConfiguration.spaces; +import static net.kyori.adventure.text.format.NamedTextColor.*; +import static net.minecraft.network.chat.Component.literal; + +public class RemoveCommand extends BotSubcommand { + + public RemoveCommand() { + super("remove"); + children(BotArgument::new); + } + + private static boolean removeBot(@NotNull ServerBot bot, @Nullable CommandSender sender) { + boolean success = BotList.INSTANCE.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); + if (!success) { + sender = sender == null ? Bukkit.getConsoleSender() : sender; + sender.sendMessage(text("Bot remove canceled by a plugin", RED)); + } + return success; + } + + private static class BotArgument extends CustomArgumentNode { + + public BotArgument() { + super("bot", new org.leavesmc.leaves.neo_command.bot.BotArgument()); + children(RemoveTimeArgument::new); + } + + @Override + protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { + ServerBot bot = context.getCustomArgument(BotArgument.class); + return removeBot(bot, context.getSender()); + } + } + + private static class RemoveTimeArgument extends ArgumentNode { + + private RemoveTimeArgument() { + super("remove_time", StringArgumentType.word()); + } + + @Override + protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { + String removeTimeStr = context.getArgument("remove_time", String.class); + int removeTimeSeconds = parseRemoveTime(removeTimeStr); + ServerBot bot = context.getCustomArgument(BotArgument.class); + CommandSender sender = context.getSender(); + + boolean isReschedule = bot.removeTaskId != -1; + + if (isReschedule) { + Bukkit.getScheduler().cancelTask(bot.removeTaskId); + } + bot.removeTaskId = Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> { + bot.removeTaskId = -1; + removeBot(bot, sender); + }, removeTimeSeconds * 20L).getTaskId(); + + sender.sendMessage(join(spaces(), + text("Bot", GRAY), + PaperAdventure.asAdventure(bot.getDisplayName()), + text("scheduled for removal in", GRAY), + text(formatSeconds(removeTimeSeconds), AQUA), + text(isReschedule ? "(rescheduled)" : "", GRAY) + )); + return true; + } + + private static int parseRemoveTime(String timeStr) throws CommandSyntaxException { + if (timeStr == null || timeStr.trim().isEmpty()) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); + } + + if (!timeStr.matches("^[\\d\\shmsHMS]+$")) { + throw new CommandSyntaxException( + CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException(), + literal("Invalid time format: " + timeStr) + ); + } + + String remaining = timeStr.replaceAll("\\d+[hmsHMS]", "").trim(); + if (!remaining.isEmpty() && remaining.matches(".*\\d+.*")) { + throw new CommandSyntaxException( + CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException(), + literal("Found trailing numbers without unit: " + timeStr) + ); + } + + Matcher matcher = Pattern.compile("(\\d+)([hmsHMS])").matcher(timeStr); + int seconds = 0; + boolean foundMatch = false; + + while (matcher.find()) { + foundMatch = true; + int value = Integer.parseInt(matcher.group(1)); + switch (matcher.group(2).toLowerCase()) { + case "h": seconds += value * 3600; break; + case "m": seconds += value * 60; break; + case "s": seconds += value; break; + } + } + + if (!foundMatch) { + throw new CommandSyntaxException( + CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException(), + literal("No valid time units found in: " + timeStr) + ); + } + + return seconds; + } + + private static @NotNull String formatSeconds(int totalSeconds) { + int h = totalSeconds / 3600; + int m = (totalSeconds % 3600) / 60; + int s = totalSeconds % 60; + StringBuilder sb = new StringBuilder(); + if (h > 0) { + sb.append(h).append("h"); + } + if (m > 0) { + sb.append(m).append("m"); + } + if (s > 0) { + sb.append(s).append("s"); + } + if (sb.isEmpty()) { + sb.append("0s"); + } + return sb.toString(); + } + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/SaveCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/SaveCommand.java index f3a32bd8..0c15afbc 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/SaveCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/neo_command/bot/subcommands/SaveCommand.java @@ -32,7 +32,7 @@ public class SaveCommand extends BotSubcommand { private static class BotArgument extends CustomArgumentNode { - public BotArgument() { + private BotArgument() { super("bot", new org.leavesmc.leaves.neo_command.bot.BotArgument()); } @@ -42,16 +42,17 @@ public class SaveCommand extends BotSubcommand { CommandSender sender = context.getSender(); BotList botList = BotList.INSTANCE; - if (!botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true)) { - sender.sendMessage(text("Failed to save bot, please check log", NamedTextColor.RED)); - return false; + boolean success = botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true); + if (success) { + sender.sendMessage(join(spaces(), + text("Successfully saved bot", NamedTextColor.GRAY), + asAdventure(bot.getDisplayName()), + text("as " + bot.createState.realName(), NamedTextColor.GRAY) + )); + } else { + sender.sendMessage(text("Bot save canceled by a plugin", NamedTextColor.RED)); } - sender.sendMessage(join(spaces(), - text("Successfully saved bot", NamedTextColor.GRAY), - asAdventure(bot.getDisplayName()), - text("as " + bot.createState.realName(), NamedTextColor.GRAY) - )); - return true; + return success; } } }