From b20b5042238cf186c06dcff6146e61f76bf19b8a Mon Sep 17 00:00:00 2001 From: Bluemangoo Date: Wed, 26 Feb 2025 17:38:57 +0800 Subject: [PATCH] Rebase bot command (#421) --------- Co-authored-by: Lumine1909 <133463833+Lumine1909@users.noreply.github.com> --- .../org/leavesmc/leaves/bot/BotCommand.java | 553 ++---------------- .../bot/subcommands/BotActionCommand.java | 183 ++++++ .../bot/subcommands/BotConfigCommand.java | 104 ++++ .../bot/subcommands/BotCreateCommand.java | 105 ++++ .../bot/subcommands/BotListCommand.java | 82 +++ .../bot/subcommands/BotLoadCommand.java | 62 ++ .../bot/subcommands/BotRemoveCommand.java | 122 ++++ .../bot/subcommands/BotSaveCommand.java | 65 ++ .../leaves/command/LeavesCommand.java | 4 +- .../leaves/command/LeavesSubcommand.java | 3 +- .../command/subcommands/ConfigCommand.java | 3 +- .../command/subcommands/CounterCommand.java | 3 +- .../PeacefulModeSwitchCommand.java | 3 +- 13 files changed, 798 insertions(+), 494 deletions(-) create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java create mode 100644 leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java index f12216c3..8ac02d27 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/BotCommand.java @@ -1,49 +1,40 @@ package org.leavesmc.leaves.bot; +import it.unimi.dsi.fastutil.Pair; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.minecraft.Util; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.generator.WorldInfo; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.leavesmc.leaves.LeavesConfig; -import org.leavesmc.leaves.LeavesLogger; -import org.leavesmc.leaves.bot.agent.Actions; -import org.leavesmc.leaves.bot.agent.AbstractBotAction; -import org.leavesmc.leaves.bot.agent.AbstractBotConfig; -import org.leavesmc.leaves.bot.agent.Configs; -import org.leavesmc.leaves.bot.agent.actions.CraftCustomBotAction; -import org.leavesmc.leaves.command.CommandArgumentResult; +import org.leavesmc.leaves.bot.subcommands.BotActionCommand; +import org.leavesmc.leaves.bot.subcommands.BotConfigCommand; +import org.leavesmc.leaves.bot.subcommands.BotCreateCommand; +import org.leavesmc.leaves.bot.subcommands.BotListCommand; +import org.leavesmc.leaves.bot.subcommands.BotLoadCommand; +import org.leavesmc.leaves.bot.subcommands.BotRemoveCommand; +import org.leavesmc.leaves.bot.subcommands.BotSaveCommand; import org.leavesmc.leaves.command.LeavesCommandUtil; -import org.leavesmc.leaves.entity.Bot; -import org.leavesmc.leaves.event.bot.BotActionStopEvent; -import org.leavesmc.leaves.event.bot.BotConfigModifyEvent; -import org.leavesmc.leaves.event.bot.BotCreateEvent; -import org.leavesmc.leaves.event.bot.BotRemoveEvent; -import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; +import org.leavesmc.leaves.command.LeavesSubcommand; import java.util.*; +import java.util.stream.Collectors; import static net.kyori.adventure.text.Component.text; public class BotCommand extends Command { - private final Component unknownMessage; - public BotCommand(String name) { super(name); this.description = "FakePlayer Command"; - this.usageMessage = "/bot [create | remove | action | list | config]"; - this.unknownMessage = text("Usage: " + usageMessage, NamedTextColor.RED); + this.usageMessage = "/bot [" + String.join(" | ", usableSubcommands()) + "]"; this.setPermission("bukkit.command.bot"); final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); if (pluginManager.getPermission("bukkit.command.bot") == null) { @@ -51,494 +42,80 @@ public class BotCommand extends Command { } } + // subcommand label -> subcommand + private static final Map SUBCOMMANDS = Util.make(() -> { + final Map, LeavesSubcommand> commands = new HashMap<>(); + commands.put(Set.of("create"), new BotCreateCommand()); + commands.put(Set.of("remove"), new BotRemoveCommand()); + commands.put(Set.of("action"), new BotActionCommand()); + commands.put(Set.of("config"), new BotConfigCommand()); + commands.put(Set.of("save"), new BotSaveCommand()); + commands.put(Set.of("load"), new BotLoadCommand()); + commands.put(Set.of("list"), new BotListCommand()); + + return commands.entrySet().stream() + .flatMap(entry -> entry.getKey().stream().map(s -> Map.entry(s, entry.getValue()))) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + }); + + @NotNull @Override - public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, String @NotNull [] args, Location location) throws IllegalArgumentException { - List list = new ArrayList<>(); - BotList botList = BotList.INSTANCE; - + public List tabComplete(final @NotNull CommandSender sender, final @NotNull String alias, final String[] args, final @Nullable Location location) throws IllegalArgumentException { if (args.length <= 1) { - list.add("create"); - list.add("remove"); - if (LeavesConfig.modify.fakeplayer.canUseAction) { - list.add("action"); - } - if (LeavesConfig.modify.fakeplayer.canModifyConfig) { - list.add("config"); - } - if (LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - list.add("save"); - list.add("load"); - } - list.add("list"); + return LeavesCommandUtil.getListMatchingLast(sender, args, usableSubcommands(), "bukkit.command.bot.", "bukkit.command.bot"); } - if (args.length == 2) { - switch (args[0]) { - case "create" -> list.add(""); - case "remove", "action", "config", "save" -> list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); - case "list" -> list.addAll(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); - case "load" -> list.addAll(botList.getSavedBotList().getAllKeys()); - } + final @Nullable Pair subCommand = resolveCommand(args[0]); + if (subCommand != null) { + var list = subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location); + return LeavesCommandUtil.getListMatchingLast(sender, args, list, "bukkit.command.bot.", "bukkit.command.bot"); } - if (args.length == 3) { - switch (args[0]) { - case "action" -> { - list.add("list"); - list.add("stop"); - list.addAll(Actions.getNames()); - } - case "create" -> list.add(""); - case "config" -> list.addAll(acceptConfig); - case "remove" -> list.addAll(List.of("cancel", "[hour]")); - } - } - - if (args[0].equals("remove") && args.length >= 4) { - if (!Objects.equals(args[2], "cancel")) { - switch (args.length) { - case 4 -> list.add("[minute]"); - case 5 -> list.add("[second]"); - } - } - } - - if (args.length >= 4 && args[0].equals("action")) { - ServerBot bot = botList.getBotByName(args[1]); - - if (bot == null) { - return Collections.singletonList("<" + args[1] + " not found>"); - } - - if (args[2].equals("stop")) { - list.add("all"); - for (int i = 0; i < bot.getBotActions().size(); i++) { - list.add(String.valueOf(i)); - } - } else { - AbstractBotAction action = Actions.getForName(args[2]); - if (action != null) { - list.addAll(action.getArgument().tabComplete(args.length - 4)); - } - } - } - - if (args.length >= 4 && args[0].equals("config")) { - Configs config = Configs.getConfig(args[2]); - if (config != null) { - list.addAll(config.config.getArgument().tabComplete(args.length - 4)); - } - } - - return LeavesCommandUtil.getListMatchingLast(sender, args, list, "bukkit.command.bot.", "bukkit.command.bot"); + return Collections.emptyList(); } @Override - public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) { + public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String @NotNull [] args) { if (!testPermission(sender) || !LeavesConfig.modify.fakeplayer.enable) return true; if (args.length == 0) { - sender.sendMessage(unknownMessage); + sender.sendMessage(unknownMessage()); + return false; + } + final Pair subCommand = resolveCommand(args[0]); + + if (subCommand == null) { + sender.sendMessage(unknownMessage()); return false; } - switch (args[0]) { - case "create" -> this.onCreate(sender, args); - case "remove" -> this.onRemove(sender, args); - case "action" -> this.onAction(sender, args); - case "config" -> this.onConfig(sender, args); - case "list" -> this.onList(sender, args); - case "save" -> this.onSave(sender, args); - case "load" -> this.onLoad(sender, args); - default -> { - sender.sendMessage(unknownMessage); - return false; - } - } - - return true; + final String[] choppedArgs = Arrays.copyOfRange(args, 1, args.length); + return subCommand.second().execute(sender, subCommand.first(), choppedArgs); } - private void onCreate(CommandSender sender, String @NotNull [] args) { - if (args.length < 2) { - sender.sendMessage(text("Use /bot create [skin_name] to create a fakeplayer", NamedTextColor.RED)); - return; + @Nullable + private static Pair resolveCommand(String label) { + label = label.toLowerCase(Locale.ENGLISH); + LeavesSubcommand subCommand = SUBCOMMANDS.get(label); + + if (subCommand != null) { + return Pair.of(label, subCommand); } - String botName = args[1]; - if (this.canCreate(sender, botName)) { - BotCreateState.Builder builder = BotCreateState.builder(botName, Bukkit.getWorlds().getFirst().getSpawnLocation()).createReason(BotCreateEvent.CreateReason.COMMAND).creator(sender); - - if (args.length >= 3) { - builder.skinName(args[2]); - } - - if (sender instanceof Player player) { - builder.location(player.getLocation()); - } else if (sender instanceof ConsoleCommandSender) { - if (args.length >= 7) { - try { - World world = Bukkit.getWorld(args[3]); - double x = Double.parseDouble(args[4]); - double y = Double.parseDouble(args[5]); - double z = Double.parseDouble(args[6]); - if (world != null) { - builder.location(new Location(world, x, y, z)); - } - } catch (Exception e) { - LeavesLogger.LOGGER.warning("Can't build location", e); - } - } - } - - builder.spawnWithSkin(null); - } + return null; } - private boolean canCreate(CommandSender sender, @NotNull String name) { - BotList botList = BotList.INSTANCE; - if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) { - sender.sendMessage(text("This name is illegal", NamedTextColor.RED)); - return false; + public Collection usableSubcommands() { + List subcommands = new ArrayList<>(); + for (var entry : SUBCOMMANDS.entrySet()) { + if (entry.getValue().tabCompletes()) { + subcommands.add(entry.getKey()); + } } - - if (Bukkit.getPlayerExact(name) != null || botList.getBotByName(name) != null) { - sender.sendMessage(text("This player is in server", NamedTextColor.RED)); - return false; - } - - if (LeavesConfig.modify.fakeplayer.unableNames.contains(name)) { - sender.sendMessage(text("This name is not allowed", NamedTextColor.RED)); - return false; - } - - if (botList.bots.size() >= LeavesConfig.modify.fakeplayer.limit) { - sender.sendMessage(text("Fakeplayer limit is full", NamedTextColor.RED)); - return false; - } - - return true; + return subcommands; } - private void onRemove(CommandSender sender, String @NotNull [] args) { - if (args.length < 2 || args.length > 5) { - sender.sendMessage(text("Use /bot remove [hour] [minute] [second] to remove a fakeplayer", NamedTextColor.RED)); - return; - } - - BotList botList = BotList.INSTANCE; - ServerBot bot = botList.getBotByName(args[1]); - - if (bot == null) { - sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return; - } - - if (args.length > 2) { - if (args[2].equals("cancel")) { - if (bot.removeTaskId == -1) { - sender.sendMessage(text("This fakeplayer is not scheduled to be removed", NamedTextColor.RED)); - return; - } - Bukkit.getScheduler().cancelTask(bot.removeTaskId); - bot.removeTaskId = -1; - sender.sendMessage(text("Remove cancel")); - return; - } - - long time = 0; - int h; // Preventing out-of-range - long s = 0; - long m = 0; - - try { - h = Integer.parseInt(args[2]); - if (h < 0) { - throw new NumberFormatException(); - } - time += ((long) h) * 3600 * 20; - if (args.length > 3) { - m = Long.parseLong(args[3]); - if (m > 59 || m < 0) { - throw new NumberFormatException(); - } - time += m * 60 * 20; - } - if (args.length > 4) { - s = Long.parseLong(args[4]); - if (s > 59 || s < 0) { - throw new NumberFormatException(); - } - time += s * 20; - } - } catch (NumberFormatException e) { - sender.sendMessage(text("This fakeplayer is not scheduled to be removed", NamedTextColor.RED)); - return; - } - - boolean isReschedule = bot.removeTaskId != -1; - - if (isReschedule) { - Bukkit.getScheduler().cancelTask(bot.removeTaskId); - } - bot.removeTaskId = Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> { - bot.removeTaskId = -1; - botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); - }, time).getTaskId(); - - sender.sendMessage("This fakeplayer will be removed in " + h + "h " + m + "m " + s + "s" + (isReschedule ? " (rescheduled)" : "")); - - return; - } - - botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); + public Component unknownMessage() { + return text("Usage: /bot [" + String.join(" | ", usableSubcommands()) + "]", NamedTextColor.RED); } - - private void onAction(CommandSender sender, String @NotNull [] args) { - if (!LeavesConfig.modify.fakeplayer.canUseAction) { - return; - } - - if (args.length < 3) { - sender.sendMessage(text("Use /bot action to make fakeplayer do action", NamedTextColor.RED)); - return; - } - - ServerBot bot = BotList.INSTANCE.getBotByName(args[1]); - if (bot == null) { - sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return; - } - - if (args[2].equals("list")) { - sender.sendMessage(bot.getScoreboardName() + "'s action list:"); - for (int i = 0; i < bot.getBotActions().size(); i++) { - sender.sendMessage(i + " " + bot.getBotActions().get(i).getName()); - } - return; - } - - if (args[2].equals("stop")) { - if (args.length < 4) { - sender.sendMessage(text("Invalid index", NamedTextColor.RED)); - return; - } - - String index = args[3]; - if (index.equals("all")) { - Set> forRemoval = new HashSet<>(); - for (int i = 0; i < bot.getBotActions().size(); i++) { - AbstractBotAction action = bot.getBotActions().get(i); - BotActionStopEvent event = new BotActionStopEvent( - bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender - ); - event.callEvent(); - if (!event.isCancelled()) { - forRemoval.add(action); - } - } - bot.getBotActions().removeAll(forRemoval); - sender.sendMessage(bot.getScoreboardName() + "'s action list cleared."); - } else { - try { - int i = Integer.parseInt(index); - if (i < 0 || i >= bot.getBotActions().size()) { - sender.sendMessage(text("Invalid index", NamedTextColor.RED)); - return; - } - - AbstractBotAction action = bot.getBotActions().get(i); - BotActionStopEvent event = new BotActionStopEvent( - bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender - ); - event.callEvent(); - if (!event.isCancelled()) { - bot.getBotActions().remove(i); - sender.sendMessage(bot.getScoreboardName() + "'s " + action.getName() + " stopped."); - - } - } catch (NumberFormatException e) { - sender.sendMessage(text("Invalid index", NamedTextColor.RED)); - } - } - return; - } - - AbstractBotAction action = Actions.getForName(args[2]); - if (action == null) { - sender.sendMessage(text("Invalid action", NamedTextColor.RED)); - return; - } - - CraftPlayer player; - if (sender instanceof CraftPlayer) { - player = (CraftPlayer) sender; - } else { - player = bot.getBukkitEntity(); - } - - String[] realArgs = new String[args.length - 3]; - if (realArgs.length != 0) { - System.arraycopy(args, 3, realArgs, 0, realArgs.length); - } - - AbstractBotAction newAction; - try { - if (action instanceof CraftCustomBotAction customBotAction) { - newAction = customBotAction.createCraft(player, realArgs); - } else { - newAction = action.create(); - newAction.loadCommand(player.getHandle(), action.getArgument().parse(0, realArgs)); - } - } catch (IllegalArgumentException e) { - sender.sendMessage(text("Action create error, please check your arguments, " + e.getMessage(), NamedTextColor.RED)); - return; - } - - if (newAction == null) { - return; - } - - if (bot.addBotAction(newAction, sender)) { - sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString()); - } - } - - private static final List acceptConfig = Configs.getConfigs().stream().map(config -> config.config.getName()).toList(); - - private void onConfig(CommandSender sender, String @NotNull [] args) { - if (!LeavesConfig.modify.fakeplayer.canModifyConfig) { - return; - } - - if (args.length < 3) { - sender.sendMessage(text("Use /bot config to modify fakeplayer's config", NamedTextColor.RED)); - return; - } - - ServerBot bot = BotList.INSTANCE.getBotByName(args[1]); - if (bot == null) { - sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return; - } - - if (!acceptConfig.contains(args[2])) { - sender.sendMessage(text("This config is not accept", NamedTextColor.RED)); - return; - } - - AbstractBotConfig config = Objects.requireNonNull(Configs.getConfig(args[2])).config; - if (args.length < 4) { - config.getMessage().forEach(sender::sendMessage); - } else { - String[] realArgs = new String[args.length - 3]; - System.arraycopy(args, 3, realArgs, 0, realArgs.length); - - BotConfigModifyEvent event = new BotConfigModifyEvent(bot.getBukkitEntity(), config.getName(), realArgs, sender); - Bukkit.getPluginManager().callEvent(event); - - if (event.isCancelled()) { - return; - } - CommandArgumentResult result = config.getArgument().parse(0, realArgs); - - try { - config.setValue(result); - config.getChangeMessage().forEach(sender::sendMessage); - } catch (IllegalArgumentException e) { - sender.sendMessage(text(e.getMessage(), NamedTextColor.RED)); - } - } - } - - private void onSave(CommandSender sender, String @NotNull [] args) { - if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - return; - } - - if (args.length < 2) { - sender.sendMessage(text("Use /bot save to save a fakeplayer", NamedTextColor.RED)); - return; - } - - BotList botList = BotList.INSTANCE; - ServerBot bot = botList.getBotByName(args[1]); - - if (bot == null) { - sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); - return; - } - - if (botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true)) { - sender.sendMessage(bot.getScoreboardName() + " saved to " + bot.createState.realName()); - } - } - - private void onLoad(CommandSender sender, String @NotNull [] args) { - if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { - return; - } - - if (args.length < 2) { - sender.sendMessage(text("Use /bot save to save a fakeplayer", NamedTextColor.RED)); - return; - } - - String realName = args[1]; - BotList botList = BotList.INSTANCE; - if (!botList.getSavedBotList().contains(realName)) { - sender.sendMessage(text("This fakeplayer is not saved", NamedTextColor.RED)); - return; - } - - if (botList.loadNewBot(realName) == null) { - sender.sendMessage(text("Can't load bot, please check", NamedTextColor.RED)); - } - } - - private void onList(CommandSender sender, String @NotNull [] args) { - BotList botList = BotList.INSTANCE; - if (args.length < 2) { - Map> botMap = new HashMap<>(); - for (World world : Bukkit.getWorlds()) { - botMap.put(world, new ArrayList<>()); - } - - for (ServerBot bot : botList.bots) { - Bot bukkitBot = bot.getBukkitEntity(); - botMap.get(bukkitBot.getWorld()).add(bukkitBot.getName()); - } - - sender.sendMessage("Total number: (" + botList.bots.size() + "/" + LeavesConfig.modify.fakeplayer.limit + ")"); - for (World world : botMap.keySet()) { - sender.sendMessage(world.getName() + "(" + botMap.get(world).size() + "): " + formatPlayerNameList(botMap.get(world))); - } - } else { - World world = Bukkit.getWorld(args[1]); - - if (world == null) { - sender.sendMessage(text("Unknown world", NamedTextColor.RED)); - return; - } - - List snowBotList = new ArrayList<>(); - for (ServerBot bot : botList.bots) { - Bot bukkitBot = bot.getBukkitEntity(); - if (bukkitBot.getWorld() == world) { - snowBotList.add(bukkitBot.getName()); - } - } - - sender.sendMessage(world.getName() + "(" + botList.bots.size() + "): " + formatPlayerNameList(snowBotList)); - } - } - - @NotNull - private static String formatPlayerNameList(@NotNull List list) { - if (list.isEmpty()) { - return ""; - } - String string = list.toString(); - return string.substring(1, string.length() - 1); - } -} +} \ No newline at end of file diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java new file mode 100644 index 00000000..cfe1b38b --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotActionCommand.java @@ -0,0 +1,183 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.bot.agent.AbstractBotAction; +import org.leavesmc.leaves.bot.agent.Actions; +import org.leavesmc.leaves.bot.agent.actions.CraftCustomBotAction; +import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.event.bot.BotActionStopEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static net.kyori.adventure.text.Component.text; + +public class BotActionCommand implements LeavesSubcommand { + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + if (!LeavesConfig.modify.fakeplayer.canUseAction) { + return false; + } + + if (args.length < 2) { + sender.sendMessage(text("Use /bot action to make fakeplayer do action", NamedTextColor.RED)); + return false; + } + + ServerBot bot = BotList.INSTANCE.getBotByName(args[0]); + if (bot == null) { + sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); + return false; + } + + if (args[1].equals("list")) { + sender.sendMessage(bot.getScoreboardName() + "'s action list:"); + for (int i = 0; i < bot.getBotActions().size(); i++) { + sender.sendMessage(i + " " + bot.getBotActions().get(i).getName()); + } + return false; + } + + if (args[1].equals("stop")) { + if (args.length < 3) { + sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + return false; + } + + String index = args[4]; + if (index.equals("all")) { + Set> forRemoval = new HashSet<>(); + for (int i = 0; i < bot.getBotActions().size(); i++) { + AbstractBotAction action = bot.getBotActions().get(i); + BotActionStopEvent event = new BotActionStopEvent( + bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender + ); + event.callEvent(); + if (!event.isCancelled()) { + forRemoval.add(action); + } + } + bot.getBotActions().removeAll(forRemoval); + sender.sendMessage(bot.getScoreboardName() + "'s action list cleared."); + } else { + try { + int i = Integer.parseInt(index); + if (i < 0 || i >= bot.getBotActions().size()) { + sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + return false; + } + + AbstractBotAction action = bot.getBotActions().get(i); + BotActionStopEvent event = new BotActionStopEvent( + bot.getBukkitEntity(), action.getName(), action.getUUID(), BotActionStopEvent.Reason.COMMAND, sender + ); + event.callEvent(); + if (!event.isCancelled()) { + bot.getBotActions().remove(i); + sender.sendMessage(bot.getScoreboardName() + "'s " + action.getName() + " stopped."); + + } + } catch (NumberFormatException e) { + sender.sendMessage(text("Invalid index", NamedTextColor.RED)); + } + } + return false; + } + + AbstractBotAction action = Actions.getForName(args[1]); + if (action == null) { + sender.sendMessage(text("Invalid action", NamedTextColor.RED)); + return false; + } + + CraftPlayer player; + if (sender instanceof CraftPlayer) { + player = (CraftPlayer) sender; + } else { + player = bot.getBukkitEntity(); + } + + String[] realArgs = new String[args.length - 2]; + if (realArgs.length != 0) { + System.arraycopy(args, 2, realArgs, 0, realArgs.length); + } + + AbstractBotAction newAction; + try { + if (action instanceof CraftCustomBotAction customBotAction) { + newAction = customBotAction.createCraft(player, realArgs); + } else { + newAction = action.create(); + newAction.loadCommand(player.getHandle(), action.getArgument().parse(0, realArgs)); + } + } catch (IllegalArgumentException e) { + sender.sendMessage(text("Action create error, please check your arguments, " + e.getMessage(), NamedTextColor.RED)); + return false; + } + + if (newAction == null) { + return false; + } + + if (bot.addBotAction(newAction, sender)) { + sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString()); + } + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + if (!LeavesConfig.modify.fakeplayer.canUseAction) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(); + BotList botList = BotList.INSTANCE; + + if (args.length <= 1) { + list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); + } + + if (args.length == 2) { + list.add("list"); + list.add("stop"); + list.addAll(Actions.getNames()); + } + + if (args.length >= 3) { + ServerBot bot = botList.getBotByName(args[0]); + + if (bot == null) { + return Collections.singletonList("<" + args[0] + " not found>"); + } + + if (args[1].equals("stop")) { + list.add("all"); + for (int i = 0; i < bot.getBotActions().size(); i++) { + list.add(String.valueOf(i)); + } + } else { + AbstractBotAction action = Actions.getForName(args[1]); + if (action != null) { + list.addAll(action.getArgument().tabComplete(args.length - 3)); + } + } + } + + return list; + } + + @Override + public boolean tabCompletes() { + return LeavesConfig.modify.fakeplayer.canUseAction; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java new file mode 100644 index 00000000..46a410fb --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotConfigCommand.java @@ -0,0 +1,104 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.bot.agent.AbstractBotConfig; +import org.leavesmc.leaves.bot.agent.Configs; +import org.leavesmc.leaves.command.CommandArgumentResult; +import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.event.bot.BotConfigModifyEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static net.kyori.adventure.text.Component.text; + +public class BotConfigCommand implements LeavesSubcommand { + private static final List acceptConfig = Configs.getConfigs().stream().map(config -> config.config.getName()).toList(); + + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + if (!LeavesConfig.modify.fakeplayer.canModifyConfig) { + return false; + } + + if (args.length < 3) { + sender.sendMessage(text("Use /bot config to modify fakeplayer's config", NamedTextColor.RED)); + return false; + } + + ServerBot bot = BotList.INSTANCE.getBotByName(args[1]); + if (bot == null) { + sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); + return false; + } + + if (!acceptConfig.contains(args[2])) { + sender.sendMessage(text("This config is not accept", NamedTextColor.RED)); + return false; + } + + AbstractBotConfig config = Objects.requireNonNull(Configs.getConfig(args[2])).config; + if (args.length < 4) { + config.getMessage().forEach(sender::sendMessage); + } else { + String[] realArgs = new String[args.length - 3]; + System.arraycopy(args, 3, realArgs, 0, realArgs.length); + + BotConfigModifyEvent event = new BotConfigModifyEvent(bot.getBukkitEntity(), config.getName(), realArgs, sender); + Bukkit.getPluginManager().callEvent(event); + + if (event.isCancelled()) { + return false; + } + CommandArgumentResult result = config.getArgument().parse(0, realArgs); + + try { + config.setValue(result); + config.getChangeMessage().forEach(sender::sendMessage); + } catch (IllegalArgumentException e) { + sender.sendMessage(text(e.getMessage(), NamedTextColor.RED)); + } + } + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + if (!LeavesConfig.modify.fakeplayer.canModifyConfig) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(); + BotList botList = BotList.INSTANCE; + + if (args.length <= 1) { + list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); + } + + if (args.length == 2) { + list.addAll(acceptConfig); + } + + if (args.length >= 3) { + Configs config = Configs.getConfig(args[1]); + if (config != null) { + list.addAll(config.config.getArgument().tabComplete(args.length - 3)); + } + } + + return list; + } + + @Override + public boolean tabCompletes() { + return LeavesConfig.modify.fakeplayer.canModifyConfig; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java new file mode 100644 index 00000000..245766b0 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotCreateCommand.java @@ -0,0 +1,105 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.LeavesLogger; +import org.leavesmc.leaves.bot.BotCreateState; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.event.bot.BotCreateEvent; + +import java.util.ArrayList; +import java.util.List; + +import static net.kyori.adventure.text.Component.text; + +public class BotCreateCommand implements LeavesSubcommand { + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + if (args.length < 1) { + sender.sendMessage(text("Use /bot create [skin_name] to create a fakeplayer", NamedTextColor.RED)); + return false; + } + + String botName = args[0]; + if (this.canCreate(sender, botName)) { + BotCreateState.Builder builder = BotCreateState.builder(botName, Bukkit.getWorlds().getFirst().getSpawnLocation()).createReason(BotCreateEvent.CreateReason.COMMAND).creator(sender); + + if (args.length >= 2) { + builder.skinName(args[1]); + } + + if (sender instanceof Player player) { + builder.location(player.getLocation()); + } else if (sender instanceof ConsoleCommandSender) { + if (args.length >= 6) { + try { + World world = Bukkit.getWorld(args[2]); + double x = Double.parseDouble(args[3]); + double y = Double.parseDouble(args[4]); + double z = Double.parseDouble(args[5]); + if (world != null) { + builder.location(new Location(world, x, y, z)); + } + } catch (Exception e) { + LeavesLogger.LOGGER.warning("Can't build location", e); + } + } + } + + builder.spawnWithSkin(null); + } + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + List list = new ArrayList<>(); + if (args.length <= 1) { + list.add(""); + } + if (args.length == 2) { + list.add("[SkinName]"); + } + if (sender instanceof ConsoleCommandSender) { + if (args.length == 3) { + for (var world : sender.getServer().getWorlds()) { + list.add(world.getName()); + } + } + } + return list; + } + + private boolean canCreate(CommandSender sender, @NotNull String name) { + BotList botList = BotList.INSTANCE; + if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) { + sender.sendMessage(text("This name is illegal", NamedTextColor.RED)); + return false; + } + + if (Bukkit.getPlayerExact(name) != null || botList.getBotByName(name) != null) { + sender.sendMessage(text("This player is in server", NamedTextColor.RED)); + return false; + } + + if (LeavesConfig.modify.fakeplayer.unableNames.contains(name)) { + sender.sendMessage(text("This name is not allowed", NamedTextColor.RED)); + return false; + } + + if (botList.bots.size() >= LeavesConfig.modify.fakeplayer.limit) { + sender.sendMessage(text("Fakeplayer limit is full", NamedTextColor.RED)); + return false; + } + + return true; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java new file mode 100644 index 00000000..df523130 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotListCommand.java @@ -0,0 +1,82 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.CommandSender; +import org.bukkit.generator.WorldInfo; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.entity.Bot; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static net.kyori.adventure.text.Component.text; + +public class BotListCommand implements LeavesSubcommand { + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + BotList botList = BotList.INSTANCE; + if (args.length < 2) { + Map> botMap = new HashMap<>(); + for (World world : Bukkit.getWorlds()) { + botMap.put(world, new ArrayList<>()); + } + + for (ServerBot bot : botList.bots) { + Bot bukkitBot = bot.getBukkitEntity(); + botMap.get(bukkitBot.getWorld()).add(bukkitBot.getName()); + } + + sender.sendMessage("Total number: (" + botList.bots.size() + "/" + LeavesConfig.modify.fakeplayer.limit + ")"); + for (World world : botMap.keySet()) { + sender.sendMessage(world.getName() + "(" + botMap.get(world).size() + "): " + formatPlayerNameList(botMap.get(world))); + } + } else { + World world = Bukkit.getWorld(args[1]); + + if (world == null) { + sender.sendMessage(text("Unknown world", NamedTextColor.RED)); + return false; + } + + List snowBotList = new ArrayList<>(); + for (ServerBot bot : botList.bots) { + Bot bukkitBot = bot.getBukkitEntity(); + if (bukkitBot.getWorld() == world) { + snowBotList.add(bukkitBot.getName()); + } + } + + sender.sendMessage(world.getName() + "(" + botList.bots.size() + "): " + formatPlayerNameList(snowBotList)); + } + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + List list = new ArrayList<>(); + + if (args.length <= 1) { + list.addAll(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); + } + + return list; + } + + @NotNull + private static String formatPlayerNameList(@NotNull List list) { + if (list.isEmpty()) { + return ""; + } + String string = list.toString(); + return string.substring(1, string.length() - 1); + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java new file mode 100644 index 00000000..4e407ee5 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotLoadCommand.java @@ -0,0 +1,62 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.command.LeavesSubcommand; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static net.kyori.adventure.text.Component.text; + +public class BotLoadCommand implements LeavesSubcommand { + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { + return false; + } + + if (args.length < 2) { + sender.sendMessage(text("Use /bot load to save a fakeplayer", NamedTextColor.RED)); + return false; + } + + String realName = args[1]; + BotList botList = BotList.INSTANCE; + if (!botList.getSavedBotList().contains(realName)) { + sender.sendMessage(text("This fakeplayer is not saved", NamedTextColor.RED)); + return false; + } + + if (botList.loadNewBot(realName) == null) { + sender.sendMessage(text("Can't load bot, please check", NamedTextColor.RED)); + } + + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(); + BotList botList = BotList.INSTANCE; + + if (args.length <= 1) { + list.addAll(botList.getSavedBotList().getAllKeys()); + } + + return list; + } + + @Override + public boolean tabCompletes() { + return LeavesConfig.modify.fakeplayer.canManualSaveAndLoad; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java new file mode 100644 index 00000000..acb21ff9 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotRemoveCommand.java @@ -0,0 +1,122 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.event.bot.BotRemoveEvent; +import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; + +import java.util.ArrayList; +import java.util.List; + +import static net.kyori.adventure.text.Component.text; + +public class BotRemoveCommand implements LeavesSubcommand { + private final Component errorMessage = text("Usage: /bot remove [hour] [minute] [second]", NamedTextColor.RED); + + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + if (args.length < 1 || args.length > 4) { + sender.sendMessage(errorMessage); + return false; + } + + BotList botList = BotList.INSTANCE; + ServerBot bot = botList.getBotByName(args[0]); + + if (bot == null) { + sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); + return false; + } + + if (args.length == 2 && args[1].equals("cancel")) { + if (bot.removeTaskId == -1) { + sender.sendMessage(text("This fakeplayer is not scheduled to be removed", NamedTextColor.RED)); + return false; + } + Bukkit.getScheduler().cancelTask(bot.removeTaskId); + bot.removeTaskId = -1; + sender.sendMessage(text("Remove cancel")); + return false; + } + + if (args.length > 1) { + long time = 0; + int h; // Preventing out-of-range + long s = 0; + long m = 0; + + try { + h = Integer.parseInt(args[1]); + if (h < 0) { + throw new NumberFormatException(); + } + time += ((long) h) * 3600 * 20; + if (args.length > 2) { + m = Long.parseLong(args[2]); + if (m > 59 || m < 0) { + throw new NumberFormatException(); + } + time += m * 60 * 20; + } + if (args.length > 3) { + s = Long.parseLong(args[3]); + if (s > 59 || s < 0) { + throw new NumberFormatException(); + } + time += s * 20; + } + } catch (NumberFormatException e) { + sender.sendMessage(errorMessage); + return false; + } + + boolean isReschedule = bot.removeTaskId != -1; + + if (isReschedule) { + Bukkit.getScheduler().cancelTask(bot.removeTaskId); + } + bot.removeTaskId = Bukkit.getScheduler().runTaskLater(MinecraftInternalPlugin.INSTANCE, () -> { + bot.removeTaskId = -1; + botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); + }, time).getTaskId(); + + sender.sendMessage("This fakeplayer will be removed in " + h + "h " + m + "m " + s + "s" + (isReschedule ? " (rescheduled)" : "")); + + return false; + } + + botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + List list = new ArrayList<>(); + BotList botList = BotList.INSTANCE; + + if (args.length <= 1) { + list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); + } + + if (args.length == 2) { + list.add("cancel"); + list.add("[hour]"); + } + + if (args.length > 2 && !args[1].equals("cancel")) { + switch (args.length) { + case 3 -> list.add("[minute]"); + case 4 -> list.add("[second]"); + } + } + + + return list; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java new file mode 100644 index 00000000..f5c85066 --- /dev/null +++ b/leaves-server/src/main/java/org/leavesmc/leaves/bot/subcommands/BotSaveCommand.java @@ -0,0 +1,65 @@ +package org.leavesmc.leaves.bot.subcommands; + +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.leavesmc.leaves.LeavesConfig; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.command.LeavesSubcommand; +import org.leavesmc.leaves.event.bot.BotRemoveEvent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static net.kyori.adventure.text.Component.text; + +public class BotSaveCommand implements LeavesSubcommand { + @Override + public boolean execute(CommandSender sender, String subCommand, String[] args) { + if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { + return false; + } + + if (args.length < 2) { + sender.sendMessage(text("Use /bot save to save a fakeplayer", NamedTextColor.RED)); + return false; + } + + BotList botList = BotList.INSTANCE; + ServerBot bot = botList.getBotByName(args[1]); + + if (bot == null) { + sender.sendMessage(text("This fakeplayer is not in server", NamedTextColor.RED)); + return false; + } + + if (botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true)) { + sender.sendMessage(bot.getScoreboardName() + " saved to " + bot.createState.realName()); + } + + return true; + } + + @Override + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { + if (!LeavesConfig.modify.fakeplayer.canManualSaveAndLoad) { + return Collections.emptyList(); + } + + List list = new ArrayList<>(); + BotList botList = BotList.INSTANCE; + + if (args.length <= 1) { + list.addAll(botList.bots.stream().map(e -> e.getName().getString()).toList()); + } + + return list; + } + + @Override + public boolean tabCompletes() { + return LeavesConfig.modify.fakeplayer.canManualSaveAndLoad; + } +} diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java index bc8720e3..8fcd3824 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesCommand.java @@ -77,14 +77,14 @@ public final class LeavesCommand extends Command { final @Nullable Pair subCommand = resolveCommand(args[0]); if (subCommand != null) { - return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length)); + return subCommand.second().tabComplete(sender, subCommand.first(), Arrays.copyOfRange(args, 1, args.length), location); } return Collections.emptyList(); } @Override - public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String[] args) { + public boolean execute(final @NotNull CommandSender sender, final @NotNull String commandLabel, final String @NotNull [] args) { if (!testPermission(sender)) { return true; } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java index 4b61fccc..5f5bf347 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/LeavesSubcommand.java @@ -1,5 +1,6 @@ package org.leavesmc.leaves.command; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -8,7 +9,7 @@ import java.util.List; public interface LeavesSubcommand { boolean execute(CommandSender sender, String subCommand, String[] args); - default List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { + default List tabComplete(final CommandSender sender, final String subCommand, final String[] args, Location location) { return Collections.emptyList(); } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java index 56ad63ae..6884245f 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/ConfigCommand.java @@ -3,6 +3,7 @@ package org.leavesmc.leaves.command.subcommands; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.leavesmc.leaves.command.LeavesCommandUtil; import org.leavesmc.leaves.command.LeavesSubcommand; @@ -61,7 +62,7 @@ public class ConfigCommand implements LeavesSubcommand { } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args) { + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { switch (args.length) { case 1 -> { List list = new ArrayList<>(GlobalConfigManager.getVerifiedConfigPaths()); diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java index 6d0e3c9a..8cd610ea 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/CounterCommand.java @@ -6,6 +6,7 @@ import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.minecraft.server.MinecraftServer; import net.minecraft.world.item.DyeColor; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.LeavesConfig; @@ -87,7 +88,7 @@ public class CounterCommand implements LeavesSubcommand { } @Override - public List tabComplete(CommandSender sender, String subCommand, String[] args) { + public List tabComplete(CommandSender sender, String subCommand, String[] args, Location location) { if (!LeavesConfig.modify.hopperCounter) { return Collections.emptyList(); } diff --git a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java index 1fe1d08c..eb7c1df3 100644 --- a/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java +++ b/leaves-server/src/main/java/org/leavesmc/leaves/command/subcommands/PeacefulModeSwitchCommand.java @@ -7,6 +7,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.MobCategory; import net.minecraft.world.level.NaturalSpawner; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftWorld; @@ -73,7 +74,7 @@ public class PeacefulModeSwitchCommand implements LeavesSubcommand { } @Override - public List tabComplete(final CommandSender sender, final String subCommand, final String[] args) { + public List tabComplete(final CommandSender sender, final String subCommand, final String[] args, Location location) { return LeavesCommandUtil.getListMatchingLast(sender, args, this.suggestPeacefulModeSwitch(args)); }