From ed27474efc19e37ba201b45e887f70451aaeb0bd Mon Sep 17 00:00:00 2001 From: MATRIX-feather Date: Thu, 5 Dec 2024 18:53:29 +0800 Subject: [PATCH] Hello brigadier --- .../java/xyz/nifeather/morph/MorphPlugin.java | 11 +- .../morph/commands/AnimationCommand.java | 110 +++- .../morph/commands/IHaveFormattableHelp.java | 24 + .../morph/commands/MorphCommand.java | 131 ++-- .../morph/commands/MorphCommandManager.java | 61 +- .../morph/commands/MorphPlayerCommand.java | 84 ++- .../morph/commands/MorphPluginCommand.java | 34 +- .../morph/commands/MorphTabCompleter.java | 40 -- .../morph/commands/RequestCommand.java | 70 +- .../morph/commands/UnMorphCommand.java | 39 +- .../commands/brigadier/BrigadierCommand.java | 23 + .../brigadier/IConvertibleBrigadier.java | 47 ++ .../help/FormattableHelpContainer.java | 43 ++ .../subcommands/MorphSubCommandHandler.java | 29 - .../subcommands/OptionSubCommands.java | 552 ++++++++++++++++ .../subcommands/SubCommandGenerator.java | 94 --- .../subcommands/plugin/BackendSubCommand.java | 93 --- .../plugin/CheckUpdateSubCommand.java | 43 +- .../plugin/DisguiseManageSubCommand.java | 24 +- .../subcommands/plugin/HelpSubCommand.java | 121 ++-- .../subcommands/plugin/LookupSubCommand.java | 62 +- .../plugin/MakeSkillItemSubCommand.java | 37 +- .../subcommands/plugin/OptionSubCommand.java | 239 ++----- .../plugin/QueryAllSubCommand.java | 32 +- .../subcommands/plugin/QuerySubCommand.java | 113 ++-- .../subcommands/plugin/ReloadSubCommand.java | 142 ++-- .../plugin/SkinCacheSubCommand.java | 604 +++++++++--------- .../subcommands/plugin/StatSubCommand.java | 35 +- .../plugin/ToggleSelfSubCommand.java | 37 +- .../plugin/helpsections/Entry.java | 3 +- .../management/ForceMorphSubCommand.java | 103 +-- .../management/ForceUnmorphSubCommand.java | 93 +-- .../management/GrantDisguiseSubCommand.java | 94 ++- .../management/RevokeDisguiseSubCommand.java | 110 ++-- .../skincache/cmdTree/CommandBuilder.java | 9 - .../plugin/skincache/cmdTree/TreeCommand.java | 182 ------ .../subcommands/request/AcceptSubCommand.java | 71 +- .../subcommands/request/DenySubCommand.java | 80 +-- .../subcommands/request/SendSubCommand.java | 88 ++- .../morph/config/MorphConfigManager.java | 2 +- 40 files changed, 2146 insertions(+), 1663 deletions(-) create mode 100644 src/main/java/xyz/nifeather/morph/commands/IHaveFormattableHelp.java delete mode 100644 src/main/java/xyz/nifeather/morph/commands/MorphTabCompleter.java create mode 100644 src/main/java/xyz/nifeather/morph/commands/brigadier/BrigadierCommand.java create mode 100644 src/main/java/xyz/nifeather/morph/commands/brigadier/IConvertibleBrigadier.java create mode 100644 src/main/java/xyz/nifeather/morph/commands/help/FormattableHelpContainer.java delete mode 100644 src/main/java/xyz/nifeather/morph/commands/subcommands/MorphSubCommandHandler.java create mode 100644 src/main/java/xyz/nifeather/morph/commands/subcommands/OptionSubCommands.java delete mode 100644 src/main/java/xyz/nifeather/morph/commands/subcommands/SubCommandGenerator.java delete mode 100644 src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/BackendSubCommand.java delete mode 100644 src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/CommandBuilder.java delete mode 100644 src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/TreeCommand.java diff --git a/src/main/java/xyz/nifeather/morph/MorphPlugin.java b/src/main/java/xyz/nifeather/morph/MorphPlugin.java index 85eb8719..b4d0004b 100644 --- a/src/main/java/xyz/nifeather/morph/MorphPlugin.java +++ b/src/main/java/xyz/nifeather/morph/MorphPlugin.java @@ -1,6 +1,7 @@ package xyz.nifeather.morph; import com.ticxo.modelengine.api.ModelEngineAPI; +import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; import net.kyori.adventure.text.minimessage.MiniMessage; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; @@ -9,7 +10,7 @@ import org.bukkit.scoreboard.Scoreboard; import org.jetbrains.annotations.ApiStatus; import xyz.nifeather.morph.abilities.AbilityManager; -import xyz.nifeather.morph.commands.MorphCommandManager; +import xyz.nifeather.morph.commands.*; import xyz.nifeather.morph.config.MorphConfigManager; import xyz.nifeather.morph.events.*; import xyz.nifeather.morph.interfaces.IManagePlayerData; @@ -32,7 +33,6 @@ import xyz.nifeather.morph.storage.skill.SkillsConfigurationStoreNew; import xyz.nifeather.morph.transforms.Transformer; import xyz.nifeather.morph.updates.UpdateHandler; -import xiamomc.pluginbase.Command.CommandHelper; import xiamomc.pluginbase.Messages.MessageStore; import xiamomc.pluginbase.XiaMoJavaPlugin; @@ -68,7 +68,7 @@ public String getNameSpace() return getMorphNameSpace(); } - private CommandHelper cmdHelper; + private MorphCommandManager cmdHelper; private MorphManager morphManager; @@ -234,6 +234,11 @@ public void onEnable() mirrorProcessor = new InteractionMirrorProcessor(); + // Commands + var lifecycleManager = this.getLifecycleManager(); + lifecycleManager.registerEventHandler(LifecycleEvents.COMMANDS, event -> + cmdHelper.register(event)); + //注册EventProcessor this.schedule(() -> { diff --git a/src/main/java/xyz/nifeather/morph/commands/AnimationCommand.java b/src/main/java/xyz/nifeather/morph/commands/AnimationCommand.java index 6c4a27b1..312f0870 100644 --- a/src/main/java/xyz/nifeather/morph/commands/AnimationCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/AnimationCommand.java @@ -1,26 +1,31 @@ package xyz.nifeather.morph.commands; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.IPluginCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.EmoteStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.gui.AnimSelectScreenWrapper; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class AnimationCommand extends MorphPluginObject implements IPluginCommand +public class AnimationCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public String getCommandName() + public String name() { return "play-action"; } @@ -31,69 +36,114 @@ public FormattableMessage getHelpMessage() return HelpStrings.animationDescription(); } + @Override + public boolean register(Commands dispatcher) + { + dispatcher.register( + Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::executeOpenGui) + .then( + Commands.argument("action", StringArgumentType.greedyString()) + .suggests(this::suggests) + .executes(this::execWithArg) + ) + .build() + ); + + return IConvertibleBrigadier.super.register(dispatcher); + } + @Resolved private MorphManager morphManager; - @Override - public List onTabComplete(List args, CommandSender source) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) { + var source = context.getSource().getExecutor(); + if (!(source instanceof Player player)) - return List.of("nil"); + return CompletableFuture.completedFuture(suggestionsBuilder.build()); var state = morphManager.getDisguiseStateFor(player); - if (state == null) return List.of(); - - if (args.size() >= 2) return List.of(); + if (state == null) return CompletableFuture.completedFuture(suggestionsBuilder.build()); var animations = state.getProvider() - .getAnimationProvider() - .getAnimationSetFor(state.getDisguiseIdentifier()) - .getAvailableAnimationsForClient(); + .getAnimationProvider() + .getAnimationSetFor(state.getDisguiseIdentifier()) + .getAvailableAnimationsForClient(); - var arg = args.get(0); - return animations.stream().filter(id -> id.startsWith(arg)).toList(); + var name = suggestionsBuilder.getRemainingLowerCase(); + return CompletableFuture.supplyAsync(() -> + { + animations.stream().filter(id -> id.startsWith(name)) + .forEach(suggestionsBuilder::suggest); + + return suggestionsBuilder.build(); + }); } - @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String label, @NotNull String[] args) + public int executeOpenGui(CommandContext context) { + var commandSender = context.getSource().getExecutor(); + if (!(commandSender instanceof Player player)) - return true; + return Command.SINGLE_SUCCESS; var state = morphManager.getDisguiseStateFor(player); if (state == null) { player.sendMessage(MessageUtils.prefixes(player, CommandStrings.notDisguised())); - return true; + return Command.SINGLE_SUCCESS; } var animationSet = state.getProvider() .getAnimationProvider() .getAnimationSetFor(state.getDisguiseIdentifier()); - if (args.length == 0) - { - var screen = new AnimSelectScreenWrapper(state, animationSet.getAvailableAnimationsForClient()); - screen.show(); + var screen = new AnimSelectScreenWrapper(state, animationSet.getAvailableAnimationsForClient()); + screen.show(); + + return Command.SINGLE_SUCCESS; + } - //player.sendMessage(MessageUtils.prefixes(player, CommandStrings.listNoEnoughArguments())); - return true; + private int execWithArg(CommandContext context) + { + var commandSender = context.getSource().getExecutor(); + + if (!(commandSender instanceof Player player)) + return Command.SINGLE_SUCCESS; + + var state = morphManager.getDisguiseStateFor(player); + if (state == null) + { + player.sendMessage(MessageUtils.prefixes(player, CommandStrings.notDisguised())); + return Command.SINGLE_SUCCESS; } - var animationId = args[0]; + var animationSet = state.getProvider() + .getAnimationProvider() + .getAnimationSetFor(state.getDisguiseIdentifier()); + + String animationId = StringArgumentType.getString(context, "action"); var animations = animationSet.getAvailableAnimationsForClient(); if (!animations.contains(animationId)) { player.sendMessage(MessageUtils.prefixes(player, CommandStrings.noSuchAnimation())); - return true; + return Command.SINGLE_SUCCESS; } var sequencePair = animationSet.sequenceOf(animationId); if (!state.tryScheduleSequence(animationId, sequencePair.left(), sequencePair.right())) player.sendMessage(MessageUtils.prefixes(player, EmoteStrings.notAvailable())); - return false; + return Command.SINGLE_SUCCESS; + } + + @Override + public boolean checkPermission(CommandSourceStack cmdSourceStack) + { + return true; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/IHaveFormattableHelp.java b/src/main/java/xyz/nifeather/morph/commands/IHaveFormattableHelp.java new file mode 100644 index 00000000..c992c3d2 --- /dev/null +++ b/src/main/java/xyz/nifeather/morph/commands/IHaveFormattableHelp.java @@ -0,0 +1,24 @@ +package xyz.nifeather.morph.commands; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xiamomc.pluginbase.Messages.FormattableMessage; +import xyz.nifeather.morph.MorphPlugin; + +import java.util.List; + +public interface IHaveFormattableHelp +{ + @Nullable + public String permission(); + + @NotNull + public String name(); + + public FormattableMessage getHelpMessage(); + + default public List getNotes() + { + return List.of(new FormattableMessage(MorphPlugin.getMorphNameSpace(), "_", "_")); + } +} diff --git a/src/main/java/xyz/nifeather/morph/commands/MorphCommand.java b/src/main/java/xyz/nifeather/morph/commands/MorphCommand.java index 4208a1a6..cedfde91 100644 --- a/src/main/java/xyz/nifeather/morph/commands/MorphCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/MorphCommand.java @@ -1,57 +1,34 @@ package xyz.nifeather.morph.commands; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.IPluginCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.messages.MorphStrings; +import xyz.nifeather.morph.misc.DisguiseMeta; import xyz.nifeather.morph.misc.gui.DisguiseSelectScreenWrapper; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class MorphCommand extends MorphPluginObject implements IPluginCommand +public class MorphCommand extends MorphPluginObject implements IConvertibleBrigadier { @Resolved private MorphManager morphManager; @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) - { - if (sender instanceof Player player) - { - //伪装冷却 - if (!morphManager.canMorph(player)) - { - sender.sendMessage(MessageUtils.prefixes(player, MorphStrings.disguiseCoolingDownString())); - - return true; - } - - if (args.length >= 1) - { - morphManager.morph(sender, player, args[0], player.getTargetEntity(5)); - } - else - { - var gui = new DisguiseSelectScreenWrapper(player, 0); - gui.show(); - //sender.sendMessage(MessageUtils.prefixes(sender, MorphStrings.disguiseNotDefinedString())); - } - } - - return true; - } - - @Override - public String getCommandName() + public @NotNull String name() { return "morph"; } @@ -60,36 +37,88 @@ public String getCommandName() private MorphManager morphs; @Override - public List onTabComplete(List args, CommandSender source) + public boolean register(Commands dispatcher) { - var list = new ObjectArrayList(); + dispatcher.register(Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::executeNoArg) + .then( + Commands.argument("id", StringArgumentType.greedyString()) + .suggests(this::suggests) + .executes(this::execWithArg) + ) + .build()); - if (args.size() > 1) return list; + return true; + } - if (source instanceof Player player) - { - //Logger.warn("BUFFERS: " + Arrays.toString(buffers)); + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + var source = context.getSource().getExecutor(); - var arg = args.get(0); + if (!(source instanceof Player player)) + return CompletableFuture.completedFuture(suggestionsBuilder.build()); - var infos = morphs.getAvaliableDisguisesFor(player); + String input = suggestionsBuilder.getRemainingLowerCase(); - for (var di : infos) + var availableDisguises = morphs.getAvaliableDisguisesFor(player); + + return CompletableFuture.supplyAsync(() -> + { + for (DisguiseMeta disguiseMeta : availableDisguises) { - var name = di.getKey(); - if (!name.toLowerCase().contains(arg.toLowerCase())) continue; + var name = disguiseMeta.getKey(); + + if (!name.toLowerCase().contains(input)) + continue; - list.add(name); + suggestionsBuilder.suggest(name); } + + return suggestionsBuilder.build(); + }); + } + + public int executeNoArg(CommandContext context) + { + var sender = context.getSource().getExecutor(); + + if (!(sender instanceof Player player)) + return Command.SINGLE_SUCCESS; + + //伪装冷却 + if (!morphManager.canMorph(player)) + { + sender.sendMessage(MessageUtils.prefixes(player, MorphStrings.disguiseCoolingDownString())); + + return Command.SINGLE_SUCCESS; } - return list; + var gui = new DisguiseSelectScreenWrapper(player, 0); + gui.show(); + + return 1; } - @Override - public String getPermissionRequirement() + private int execWithArg(CommandContext context) { - return null; + var sender = context.getSource().getExecutor(); + + if (!(sender instanceof Player player)) + return Command.SINGLE_SUCCESS; + + //伪装冷却 + if (!morphManager.canMorph(player)) + { + sender.sendMessage(MessageUtils.prefixes(player, MorphStrings.disguiseCoolingDownString())); + + return Command.SINGLE_SUCCESS; + } + + String inputID = StringArgumentType.getString(context, "id"); + morphManager.morph(sender, player, inputID, player.getTargetEntity(5)); + + return 1; } @Override diff --git a/src/main/java/xyz/nifeather/morph/commands/MorphCommandManager.java b/src/main/java/xyz/nifeather/morph/commands/MorphCommandManager.java index d6f4fe5f..aefcfab7 100644 --- a/src/main/java/xyz/nifeather/morph/commands/MorphCommandManager.java +++ b/src/main/java/xyz/nifeather/morph/commands/MorphCommandManager.java @@ -1,19 +1,16 @@ package xyz.nifeather.morph.commands; -import it.unimi.dsi.fastutil.objects.ObjectList; -import org.bukkit.Bukkit; -import xyz.nifeather.morph.MorphPlugin; -import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.CommandHelper; -import xiamomc.pluginbase.Command.IPluginCommand; -import xiamomc.pluginbase.XiaMoJavaPlugin; +import io.papermc.paper.command.brigadier.Commands; +import io.papermc.paper.plugin.lifecycle.event.registrar.ReloadableRegistrarEvent; +import org.jetbrains.annotations.NotNull; +import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import java.util.List; -import java.util.Objects; -public class MorphCommandManager extends CommandHelper +public class MorphCommandManager extends MorphPluginObject { - private final List commands = ObjectList.of( + private final List commands = List.of( new MorphCommand(), new MorphPlayerCommand(), new UnMorphCommand(), @@ -21,48 +18,16 @@ public class MorphCommandManager extends CommandHelper new MorphPluginCommand(), new AnimationCommand()); - @Override - public boolean registerCommand(IPluginCommand command) + public List commands() { - if (Objects.equals(command.getCommandName(), "")) - throw new IllegalArgumentException("Trying to register a command with empty basename!"); - - var cmd = Bukkit.getPluginCommand(command.getCommandName()); - - if (cmd == null) - throw new NullPointerException("'%s' doesn't have a command defined in the server.".formatted(command.getCommandName())); - - if (cmd.getExecutor().equals(this.getPlugin())) - { - cmd.setExecutor(command); - cmd.setTabCompleter(new MorphTabCompleter(command)); - return true; - } - else - { - logger.warn("Ignoring command '%s' that doesn't belongs to us.".formatted(command.getCommandName())); - return false; - } + return this.commands; } - @Override - public List getCommands() + public void register(ReloadableRegistrarEvent<@NotNull Commands> event) { - return commands; - } - - @Resolved - private MorphPlugin plugin; + var registrar = event.registrar(); - @Override - protected XiaMoJavaPlugin getPlugin() - { - return plugin; - } - - @Override - protected String getPluginNamespace() - { - return MorphPlugin.getMorphNameSpace(); + for (var brigadierConvertable : commands) + brigadierConvertable.register(registrar); } } diff --git a/src/main/java/xyz/nifeather/morph/commands/MorphPlayerCommand.java b/src/main/java/xyz/nifeather/morph/commands/MorphPlayerCommand.java index 3e9cf93f..ed37f31e 100644 --- a/src/main/java/xyz/nifeather/morph/commands/MorphPlayerCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/MorphPlayerCommand.java @@ -1,75 +1,91 @@ package xyz.nifeather.morph.commands; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.IPluginCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.misc.DisguiseMeta; import xyz.nifeather.morph.misc.DisguiseTypes; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class MorphPlayerCommand extends MorphPluginObject implements IPluginCommand +public class MorphPlayerCommand extends MorphPluginObject implements IConvertibleBrigadier { @Resolved private MorphManager morphManager; @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) + public String name() { - if (sender instanceof Player sourcePlayer) - { - var targetName = args.length >= 1 ? args[0] : ""; + return "morphplayer"; + } - sourcePlayer.performCommand("morph" + " " + DisguiseTypes.PLAYER.toId(targetName)); - } + @Override + public boolean register(Commands dispatcher) + { + dispatcher.register( + Commands.literal(name()) + .requires(this::checkPermission) + .then( + Commands.argument("who", StringArgumentType.greedyString()) + .executes(this::executes) + .suggests(this::suggests) + ) + .build() + ); return true; } - @Override - public String getCommandName() + public int executes(CommandContext context) { - return "morphplayer"; + if (!(context.getSource().getExecutor() instanceof Player player)) + return com.mojang.brigadier.Command.SINGLE_SUCCESS; + + var targetName = StringArgumentType.getString(context, "name"); + + player.performCommand("morph" + " " + DisguiseTypes.PLAYER.toId(targetName)); + + return com.mojang.brigadier.Command.SINGLE_SUCCESS; } - @Override - public List onTabComplete(List args, CommandSender source) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - var list = new ObjectArrayList(); + if (!(context.getSource().getExecutor() instanceof Player player)) + return CompletableFuture.completedFuture(suggestionsBuilder.build()); - if (args.size() > 1) return list; + var input = suggestionsBuilder.getRemainingLowerCase(); - if (source instanceof Player player) - { - var arg = args.get(0).toLowerCase(); + var availableDisguises = morphManager.getAvaliableDisguisesFor(player); - var infos = morphManager.getAvaliableDisguisesFor(player) - .stream().filter(DisguiseMeta::isPlayerDisguise).toList(); + return CompletableFuture.supplyAsync(() -> + { + var infoStream = availableDisguises.stream().filter(DisguiseMeta::isPlayerDisguise); - for (var di : infos) + infoStream.forEach(info -> { - var name = di.playerDisguiseTargetName; - if (!name.toLowerCase().contains(arg.toLowerCase())) continue; - - list.add(name); - } - } + if (info.playerDisguiseTargetName.toLowerCase().contains(input)) + suggestionsBuilder.suggest(info.playerDisguiseTargetName); + }); - return list; + return suggestionsBuilder.build(); + }); } @Override - public String getPermissionRequirement() + public boolean checkPermission(CommandSourceStack cmdSourceStack) { - return null; + return true; } @Override diff --git a/src/main/java/xyz/nifeather/morph/commands/MorphPluginCommand.java b/src/main/java/xyz/nifeather/morph/commands/MorphPluginCommand.java index 0be6926a..dfa9b4a8 100644 --- a/src/main/java/xyz/nifeather/morph/commands/MorphPluginCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/MorphPluginCommand.java @@ -1,18 +1,20 @@ package xyz.nifeather.morph.commands; +import io.papermc.paper.command.brigadier.Commands; import it.unimi.dsi.fastutil.objects.ObjectList; -import xiamomc.pluginbase.Command.ISubCommand; +import org.jetbrains.annotations.Unmodifiable; import xiamomc.pluginbase.Messages.FormattableMessage; -import xyz.nifeather.morph.commands.subcommands.MorphSubCommandHandler; +import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.commands.subcommands.plugin.*; import xyz.nifeather.morph.messages.HelpStrings; import java.util.List; -public class MorphPluginCommand extends MorphSubCommandHandler +public class MorphPluginCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public String getCommandName() + public String name() { return "feathermorph"; } @@ -20,15 +22,22 @@ public String getCommandName() private final List aliases = List.of("fm"); @Override - public List getAliases() + public boolean register(Commands dispatcher) { - return aliases; + this.registerAs("fm", dispatcher); + this.registerAs("feathermorph", dispatcher); + + return true; } - @Override - public String getPermissionRequirement() + private void registerAs(String name, Commands dispatcher) { - return null; + var cmd = Commands.literal(name); + + for (IConvertibleBrigadier child : this.children) + child.registerAsChild(cmd); + + dispatcher.register(cmd.build()); } @Override @@ -37,7 +46,7 @@ public FormattableMessage getHelpMessage() return HelpStrings.mmorphDescription(); } - private final List subCommands = ObjectList.of( + private final List children = ObjectList.of( new ReloadSubCommand(), new HelpSubCommand(), new ToggleSelfSubCommand(), @@ -50,13 +59,12 @@ public FormattableMessage getHelpMessage() new LookupSubCommand(), new SkinCacheSubCommand(), new MakeSkillItemSubCommand() - //new BackendSubCommand() ); @Override - public List getSubCommands() + public @Unmodifiable List children() { - return subCommands; + return children; } private final List notes = List.of(); diff --git a/src/main/java/xyz/nifeather/morph/commands/MorphTabCompleter.java b/src/main/java/xyz/nifeather/morph/commands/MorphTabCompleter.java deleted file mode 100644 index b7cdcf94..00000000 --- a/src/main/java/xyz/nifeather/morph/commands/MorphTabCompleter.java +++ /dev/null @@ -1,40 +0,0 @@ -package xyz.nifeather.morph.commands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import xiamomc.pluginbase.Command.IPluginCommand; - -import java.util.Arrays; -import java.util.List; - -public class MorphTabCompleter implements TabCompleter -{ - private final IPluginCommand command; - - public MorphTabCompleter(IPluginCommand command) - { - this.command = command; - } - - /** - * Requests a list of possible completions for a command argument. - * - * @param sender Source of the command. For players tab-completing a - * command inside of a command block, this will be the player, not - * the command block. - * @param command Command which was executed - * @param label Alias of the command which was used - * @param args The arguments passed to the command, including final - * partial argument to be completed - * @return A List of possible completions for the final argument, or null - * to default to the command executor - */ - @Override - public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) - { - return this.command.onTabComplete(Arrays.stream(args).toList(), sender); - } -} diff --git a/src/main/java/xyz/nifeather/morph/commands/RequestCommand.java b/src/main/java/xyz/nifeather/morph/commands/RequestCommand.java index 49b17e7d..4631ae7f 100644 --- a/src/main/java/xyz/nifeather/morph/commands/RequestCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/RequestCommand.java @@ -1,9 +1,13 @@ package xyz.nifeather.morph.commands; +import com.mojang.brigadier.arguments.StringArgumentType; +import io.papermc.paper.command.brigadier.Commands; import it.unimi.dsi.fastutil.objects.ObjectList; -import xiamomc.pluginbase.Command.ISubCommand; +import org.jetbrains.annotations.Unmodifiable; import xiamomc.pluginbase.Messages.FormattableMessage; -import xyz.nifeather.morph.commands.subcommands.MorphSubCommandHandler; +import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; +import xyz.nifeather.morph.commands.help.FormattableHelpContainer; import xyz.nifeather.morph.commands.subcommands.request.AcceptSubCommand; import xyz.nifeather.morph.commands.subcommands.request.DenySubCommand; import xyz.nifeather.morph.commands.subcommands.request.SendSubCommand; @@ -11,18 +15,58 @@ import java.util.List; -public class RequestCommand extends MorphSubCommandHandler +public class RequestCommand extends MorphPluginObject implements IConvertibleBrigadier { - private final List subCommands = ObjectList.of( - new SendSubCommand(), - new AcceptSubCommand(), - new DenySubCommand() + private final List children = List.of( + new FormattableHelpContainer("send", HelpStrings.requestSendDescription()), + new FormattableHelpContainer("accept", HelpStrings.requestAcceptDescription()), + new FormattableHelpContainer("deny", HelpStrings.requestDenyDescription()) ); @Override - public List getSubCommands() + public @Unmodifiable List children() { - return subCommands; + return children; + } + + @Override + public boolean register(Commands dispatcher) + { + var sendCommand = new SendSubCommand(); + var acceptSubCommand = new AcceptSubCommand(); + var denySubCommand = new DenySubCommand(); + + dispatcher.register( + Commands.literal("request") + .requires(this::checkPermission) + .then( + Commands.literal("send") + .then( + Commands.argument("who", StringArgumentType.greedyString()) + .suggests(sendCommand::suggests) + .executes(sendCommand::executes) + ) + ) + .then( + Commands.literal("accept") + .then( + Commands.argument("who", StringArgumentType.greedyString()) + .suggests(acceptSubCommand::suggests) + .executes(acceptSubCommand::executes) + ) + ) + .then( + Commands.literal("deny") + .then( + Commands.argument("who", StringArgumentType.greedyString()) + .suggests(denySubCommand::suggests) + .executes(denySubCommand::executes) + ) + ) + .build() + ); + + return true; } private final List notes = ObjectList.of( @@ -36,17 +80,11 @@ public List getNotes() } @Override - public String getCommandName() + public String name() { return "request"; } - @Override - public String getPermissionRequirement() - { - return null; - } - @Override public FormattableMessage getHelpMessage() { diff --git a/src/main/java/xyz/nifeather/morph/commands/UnMorphCommand.java b/src/main/java/xyz/nifeather/morph/commands/UnMorphCommand.java index 894245c4..8ac51a28 100644 --- a/src/main/java/xyz/nifeather/morph/commands/UnMorphCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/UnMorphCommand.java @@ -1,29 +1,42 @@ package xyz.nifeather.morph.commands; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.IPluginCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -public class UnMorphCommand extends MorphPluginObject implements IPluginCommand +public class UnMorphCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public String getCommandName() + public String name() { return "unmorph"; } @Override - public String getPermissionRequirement() + public boolean register(Commands dispatcher) { - return CommonPermissions.UNMORPH; + dispatcher.register( + Commands.literal("unmorph") + .requires(this::checkPermission) + .executes(this::executes) + .build() + ); + + return true; + } + + @Override + public boolean checkPermission(CommandSourceStack cmdSourceStack) + { + return cmdSourceStack.getExecutor().hasPermission(CommonPermissions.UNMORPH); } @Override @@ -35,12 +48,12 @@ public FormattableMessage getHelpMessage() @Resolved private MorphManager morphs; - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) + public int executes(CommandContext context) { - if (sender instanceof Player player) - morphs.unMorph(player); + if (!(context.getSource().getExecutor() instanceof Player player)) + return 1; - return true; + morphs.unMorph(player); + return 1; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/brigadier/BrigadierCommand.java b/src/main/java/xyz/nifeather/morph/commands/brigadier/BrigadierCommand.java new file mode 100644 index 00000000..9e699358 --- /dev/null +++ b/src/main/java/xyz/nifeather/morph/commands/brigadier/BrigadierCommand.java @@ -0,0 +1,23 @@ +package xyz.nifeather.morph.commands.brigadier; + +import io.papermc.paper.command.brigadier.CommandSourceStack; +import org.jetbrains.annotations.Nullable; +import xyz.nifeather.morph.MorphPluginObject; + +public abstract class BrigadierCommand extends MorphPluginObject implements IConvertibleBrigadier +{ + public abstract String getPermissionRequirement(); + + @Override + public @Nullable final String permission() + { + return getPermissionRequirement(); + } + + @Override + public boolean checkPermission(CommandSourceStack cmdSourceStack) + { + var perm = this.getPermissionRequirement(); + return perm == null || cmdSourceStack.getSender().hasPermission(perm); + } +} diff --git a/src/main/java/xyz/nifeather/morph/commands/brigadier/IConvertibleBrigadier.java b/src/main/java/xyz/nifeather/morph/commands/brigadier/IConvertibleBrigadier.java new file mode 100644 index 00000000..67098292 --- /dev/null +++ b/src/main/java/xyz/nifeather/morph/commands/brigadier/IConvertibleBrigadier.java @@ -0,0 +1,47 @@ +package xyz.nifeather.morph.commands.brigadier; + +import com.mojang.brigadier.builder.ArgumentBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.Unmodifiable; +import xyz.nifeather.morph.commands.IHaveFormattableHelp; + +import java.util.List; + +// todo: Remove this +public interface IConvertibleBrigadier extends IHaveFormattableHelp +{ + /** + * @return Whether this command is self-registered + */ + public default boolean register(Commands dispatcher) + { + return false; + } + + public default void registerAsChild(ArgumentBuilder parentBuilder) + { + } + + public default boolean checkPermission(CommandSourceStack context) + { + var permission = this.permission(); + return permission == null || context.getSender().hasPermission(permission); + } + + @Nullable + public default String permission() + { + return null; + } + + /** + * @return List of valid children that can be used for building help messages + */ + @Unmodifiable + public default List children() + { + return List.of(); + } +} diff --git a/src/main/java/xyz/nifeather/morph/commands/help/FormattableHelpContainer.java b/src/main/java/xyz/nifeather/morph/commands/help/FormattableHelpContainer.java new file mode 100644 index 00000000..adbc640b --- /dev/null +++ b/src/main/java/xyz/nifeather/morph/commands/help/FormattableHelpContainer.java @@ -0,0 +1,43 @@ +package xyz.nifeather.morph.commands.help; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xiamomc.pluginbase.Messages.FormattableMessage; +import xyz.nifeather.morph.commands.IHaveFormattableHelp; + +import java.util.List; + +public record FormattableHelpContainer(@Nullable String perm, + String name, + FormattableMessage message, + @Nullable List notes) implements IHaveFormattableHelp +{ + public FormattableHelpContainer(String name, FormattableMessage message) + { + this(null, name, message, null); + } + + @Override + public List getNotes() + { + return notes != null ? notes : IHaveFormattableHelp.super.getNotes(); + } + + @Override + public @Nullable String permission() + { + return perm; + } + + @Override + public @NotNull String name() + { + return name; + } + + @Override + public FormattableMessage getHelpMessage() + { + return message; + } +} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/MorphSubCommandHandler.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/MorphSubCommandHandler.java deleted file mode 100644 index 36aa539e..00000000 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/MorphSubCommandHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.nifeather.morph.commands.subcommands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; -import xiamomc.pluginbase.Command.SubCommandHandler; -import xyz.nifeather.morph.MorphPlugin; -import xyz.nifeather.morph.messages.CommonStrings; -import xyz.nifeather.morph.messages.MessageUtils; - -public abstract class MorphSubCommandHandler extends SubCommandHandler -{ - @Override - protected String getPluginNamespace() - { - return MorphPlugin.getMorphNameSpace(); - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) - { - var result = super.onCommand(sender, command, label, args); - - if (!result) - sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.commandNotFoundString())); - - return true; - } -} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/OptionSubCommands.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/OptionSubCommands.java new file mode 100644 index 00000000..9977099d --- /dev/null +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/OptionSubCommands.java @@ -0,0 +1,552 @@ +package xyz.nifeather.morph.commands.subcommands; + +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import xiamomc.pluginbase.Messages.FormattableMessage; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; +import xyz.nifeather.morph.config.ConfigOption; +import xyz.nifeather.morph.config.MorphConfigManager; +import xyz.nifeather.morph.messages.CommandStrings; +import xyz.nifeather.morph.messages.MessageUtils; +import xyz.nifeather.morph.utilities.BindableUtils; + +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@SuppressWarnings("UnstableApiUsage") +public class OptionSubCommands +{ + protected abstract static class BasicOptionCommand extends BrigadierCommand + { + protected final String name; + protected final MorphConfigManager config; + protected final ConfigOption option; + + protected BasicOptionCommand(String name, MorphConfigManager configManager, ConfigOption option) + { + this.name = name; + this.config = configManager; + this.option = option; + } + + protected void setConfig(CommandSender sender, T value) + { + config.set(option, value); + + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.optionSetString() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("what", name) + .resolve("value", value + ""))); + } + + protected void lookupConfig(CommandSender sender, Class type) + { + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.optionValueString() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("what", name) + .resolve("value", config.get(type, option) + ""))); + } + + @Override + public String name() + { + return name; + } + } + + public static class LimiterStringListOptionCommand extends BasicOptionCommand + { + private final List knownValues; + + public LimiterStringListOptionCommand(String name, + MorphConfigManager configManager, + ConfigOption option, + List knownValues) + { + super(name, configManager, option); + + this.knownValues = knownValues; + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .executes(this::executesNoArg) + .then( + Commands.argument("value", StringArgumentType.greedyString()) + .executes(this::execSetConfig) + .suggests(this::suggests) + ) + ); + + super.registerAsChild(parentBuilder); + } + + public int executesNoArg(CommandContext context) + { + lookupConfig(context.getSource().getSender(), String.class); + return 0; + } + + private int execSetConfig(CommandContext context) + { + var input = StringArgumentType.getString(context, "value"); + var target = knownValues.stream() + .filter(str -> str.equalsIgnoreCase(input)) + .findFirst() + .orElse(null); + + if (target == null) + { + return 1; + } + + setConfig(context.getSource().getSender(), target); + return 1; + } + + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> + { + var input = suggestionsBuilder.getRemainingLowerCase(); + + this.knownValues.forEach(str -> + { + var lowerCase = str.toLowerCase(); + if (lowerCase.contains(input)) + suggestionsBuilder.suggest(str); + }); + + return suggestionsBuilder.build(); + }); + } + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } + + public static class StringListOptionBaseCommand extends BasicOptionCommand> + { + public StringListOptionBaseCommand(String name, MorphConfigManager configManager, ConfigOption option) + { + super(name, configManager, option); + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + var operationList = new OperationListCommand(config, option, name); + var operationAdd = new OperationAddCommand(config, option, name); + var operationRemove = new OperationRemoveCommand(config, option, name); + + var thisBuilder = Commands.literal(name()); + + operationList.registerAsChild(thisBuilder); + operationAdd.registerAsChild(thisBuilder); + operationRemove.registerAsChild(thisBuilder); + + super.registerAsChild(parentBuilder); + } + + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } + + private abstract static class OperationCommand extends BrigadierCommand + { + protected final MorphConfigManager configManager; + protected final ConfigOption configOption; + protected final String optionName; + + public OperationCommand(MorphConfigManager configManager, ConfigOption option, String optionName) + { + this.configManager = configManager; + this.configOption = option; + this.optionName = optionName; + } + + } + + protected static class OperationRemoveCommand extends OperationCommand + { + public OperationRemoveCommand(MorphConfigManager configManager, ConfigOption option, String optionName) + { + super(configManager, option, optionName); + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public String name() + { + return "remove"; + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .then( + Commands.argument("value", StringArgumentType.greedyString()) + .executes(this::executes) + ) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) + { + var bindableList = configManager.getBindableList(String.class, configOption); + var sender = context.getSource().getSender(); + var value = StringArgumentType.getString(context, "value"); + + var listChanged = bindableList.remove(value); + + if (listChanged) + { + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.listRemoveSuccess() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("value", value) + .resolve("option", optionName))); + } + else + { + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.listRemoveFailUnknown() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("value", value) + .resolve("option", optionName))); + } + + return 1; + } + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } + + protected static class OperationAddCommand extends OperationCommand + { + public OperationAddCommand(MorphConfigManager configManager, ConfigOption option, String optionName) + { + super(configManager, option, optionName); + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public String name() + { + return "add"; + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .then( + Commands.argument("value", StringArgumentType.greedyString()) + .executes(this::executes) + ) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) + { + var bindableList = configManager.getBindableList(String.class, configOption); + var sender = context.getSource().getSender(); + var value = StringArgumentType.getString(context, "value"); + + try + { + bindableList.add(value); + + //workaround: List的add方法传入非null时永远返回true + if (bindableList.contains(value)) + { + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.listAddSuccess() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("value", value) + .resolve("option", optionName))); + } + else + { + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.listAddFailUnknown() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("value", value) + .resolve("option", optionName))); + } + } + catch (Throwable t) + { + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.listAddFailUnknown() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("value", value) + .resolve("option", optionName))); + + logger.error("Error adding option to bindable list: " + t.getMessage()); + } + + return 0; + } + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } + + protected static class OperationListCommand extends OperationCommand + { + public OperationListCommand(MorphConfigManager configManager, ConfigOption option, String optionName) + { + super(configManager, option, optionName); + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public String name() + { + return "list"; + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .executes(this::executes) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) + { + var bindableList = configManager.getBindableList(String.class, configOption); + var displayValue = BindableUtils.bindableListToString(bindableList); + + var sender = context.getSource().getSender(); + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.optionValueString() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("what", optionName) + .resolve("value", displayValue))); + + return 1; + } + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } + + public static class IntegerOptionCommand extends BasicOptionCommand + { + protected IntegerOptionCommand(String name, MorphConfigManager configManager, ConfigOption option) + { + super(name, configManager, option); + } + + private int min = Integer.MIN_VALUE; + private int max = Integer.MAX_VALUE; + + public IntegerOptionCommand min(int min) + { + this.min = min; + return this; + } + + public IntegerOptionCommand max(int max) + { + this.max = max; + return this; + } + + public IntegerOptionCommand withRange(int min, int max) + { + this.min = min; + this.max = max; + + return this; + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public String name() + { + return this.name; + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name) + .executes(this::executes) + .then( + Commands.argument("value", IntegerArgumentType.integer()) + .executes(this::execSetConfig) + ) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) + { + lookupConfig(context.getSource().getSender(), Integer.class); + return 1; + } + + private int execSetConfig(CommandContext context) + { + var sender = context.getSource().getSender(); + sender.sendMessage(MessageUtils.prefixes(sender, + CommandStrings.optionValueString() + .withLocale(MessageUtils.getLocale(sender)) + .resolve("what", name) + .resolve("value", config.get(Integer.class, option) + ""))); + return 1; + } + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } + + public static class BooleanOptionCommand extends BasicOptionCommand + { + public BooleanOptionCommand(String name, + MorphConfigManager config, + ConfigOption option) + { + super(name, config, option); + } + + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name) + .executes(this::executes) + .then( + Commands.argument("value", BoolArgumentType.bool()) + .suggests(this::suggests) + .executes(this::execSetConfig) + ) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) + { + lookupConfig(context.getSource().getSender(), Boolean.class); + return 1; + } + + private int execSetConfig(CommandContext context) + { + boolean value = BoolArgumentType.getBool(context, "value"); + + this.setConfig(context.getSource().getSender(), value); + return 1; + } + + private final List booleanValues = List.of("true", "false"); + + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> + { + var input = suggestionsBuilder.getRemainingLowerCase(); + + booleanValues.stream().filter(bv -> bv.contains(input)) + .forEach(suggestionsBuilder::suggest); + + return suggestionsBuilder.build(); + }); + } + + @Override + public String getPermissionRequirement() + { + return null; + } + + @Override + public FormattableMessage getHelpMessage() + { + return null; + } + } +} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/SubCommandGenerator.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/SubCommandGenerator.java deleted file mode 100644 index bc62c4f4..00000000 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/SubCommandGenerator.java +++ /dev/null @@ -1,94 +0,0 @@ -package xyz.nifeather.morph.commands.subcommands; - -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import xiamomc.pluginbase.Command.ISubCommand; -import xiamomc.pluginbase.Messages.FormattableMessage; -import xyz.nifeather.morph.MorphPluginObject; - -import java.util.function.BiFunction; - -public class SubCommandGenerator -{ - public static GeneratedCommand command(String name, BiFunction execute) - { - return command(name, null, execute); - } - - public static GeneratedCommand command(String name, String permission, BiFunction execute) - { - return new GeneratedCommand(name, permission, execute); - } - - public static GeneratedCommand command() - { - return new GeneratedCommand(); - } - - public static class GeneratedCommand extends MorphPluginObject implements ISubCommand - { - public GeneratedCommand(String name, BiFunction exec) - { - this(name, null, exec); - } - - public GeneratedCommand(String name, String permission, BiFunction exec) - { - this.name = name; - this.perm = permission; - this.exec = exec; - } - - public GeneratedCommand() - { - } - - private String name = "???"; - private BiFunction exec; - private String perm; - - public GeneratedCommand setName(String name) - { - this.name = name; - return this; - } - - public GeneratedCommand setExec(BiFunction exec) - { - this.exec = exec; - return this; - } - - public GeneratedCommand setPerm(String perm) - { - this.perm = perm; - return this; - } - - @Override - public @Nullable String getPermissionRequirement() - { - return perm; - } - - @Override - public @NotNull String getCommandName() - { - return name; - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { - if (exec != null) return exec.apply(sender, args); - else return false; - } - - @Override - public FormattableMessage getHelpMessage() - { - return new FormattableMessage(plugin, name); - } - } -} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/BackendSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/BackendSubCommand.java deleted file mode 100644 index 091f39dc..00000000 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/BackendSubCommand.java +++ /dev/null @@ -1,93 +0,0 @@ -package xyz.nifeather.morph.commands.subcommands.plugin; - -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; -import xiamomc.pluginbase.Messages.FormattableMessage; -import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPlugin; -import xyz.nifeather.morph.MorphPluginObject; -import xyz.nifeather.morph.backends.DisguiseBackend; -import xyz.nifeather.morph.messages.BackendStrings; -import xyz.nifeather.morph.messages.CommandStrings; -import xyz.nifeather.morph.messages.MessageUtils; -import xyz.nifeather.morph.misc.permissions.CommonPermissions; - -import java.util.List; - -public class BackendSubCommand extends MorphPluginObject implements ISubCommand -{ - @Resolved(shouldSolveImmediately = true) - private MorphManager manager; - - @Override - public @NotNull String getCommandName() - { - return "switch_backend"; - } - - @Override - public @Nullable List onTabComplete(List args, CommandSender source) - { - var targetName = args.isEmpty() ? "" : args.get(0); - targetName = targetName.toLowerCase(); - - String finalTargetName = targetName; - return manager.listManagedBackends() - .stream() - .map(DisguiseBackend::getIdentifier) - .filter(id -> id.contains(finalTargetName)) - .toList(); - } - - @Override - public @Nullable String getPermissionRequirement() - { - return CommonPermissions.SET_BACKEND; - } - - @Override - public FormattableMessage getHelpMessage() - { - return new FormattableMessage(MorphPlugin.getInstance(), "Switch backend"); - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { - if (args.length < 1) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } - - var targetName = args[0]; - var backend = manager.getBackend(targetName); - - if (backend == null) - { - sender.sendMessage(MessageUtils.prefixes(sender, BackendStrings.noSuchBackend())); - return true; - } - - if (!manager.switchBackend(backend)) - sender.sendMessage(MessageUtils.prefixes(sender, BackendStrings.switchFailed())); - - sender.sendMessage( - MessageUtils.prefixes( - sender, - BackendStrings.switchSuccess() - .resolve("name", - backend.getDisplayName() - .withLocale(MessageUtils.getLocale(sender)) - ) - ) - ); - - sender.sendMessage(MessageUtils.prefixes(sender, BackendStrings.experimentalWarning())); - - return true; - } -} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/CheckUpdateSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/CheckUpdateSubCommand.java index 62f788d4..73cd840b 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/CheckUpdateSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/CheckUpdateSubCommand.java @@ -1,32 +1,57 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.messages.UpdateStrings; import xyz.nifeather.morph.misc.permissions.CommonPermissions; import xyz.nifeather.morph.updates.UpdateHandler; -public class CheckUpdateSubCommand extends MorphPluginObject implements ISubCommand +public class CheckUpdateSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "check_update"; } @Override - public @Nullable String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.CHECK_UPDATE; } + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::execute) + ); + } + + private int execute(CommandContext context) + { + var sender = context.getSource().getSender(); + + sender.sendMessage(MessageUtils.prefixes(sender, UpdateStrings.checkingUpdate())); + handler.checkUpdate(true, result -> + this.onRequestFinish(result, sender), sender); + + return 1; + } + /** * 获取此指令的帮助信息 * @@ -41,16 +66,6 @@ public FormattableMessage getHelpMessage() @Resolved private UpdateHandler handler; - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { - sender.sendMessage(MessageUtils.prefixes(sender, UpdateStrings.checkingUpdate())); - handler.checkUpdate(true, result -> - this.onRequestFinish(result, sender), sender); - - return true; - } - private void onRequestFinish(UpdateHandler.CheckResult result, CommandSender sender) { if (result == UpdateHandler.CheckResult.ALREADY_LATEST) diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/DisguiseManageSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/DisguiseManageSubCommand.java index e4f7e6d4..c3f82da2 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/DisguiseManageSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/DisguiseManageSubCommand.java @@ -1,11 +1,14 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.builder.ArgumentBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import it.unimi.dsi.fastutil.objects.ObjectList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.commands.subcommands.plugin.management.ForceMorphSubCommand; import xyz.nifeather.morph.commands.subcommands.plugin.management.ForceUnmorphSubCommand; import xyz.nifeather.morph.commands.subcommands.plugin.management.GrantDisguiseSubCommand; @@ -15,9 +18,9 @@ import java.util.List; -public class DisguiseManageSubCommand extends MorphPluginObject implements ISubCommand +public class DisguiseManageSubCommand extends MorphPluginObject implements IConvertibleBrigadier { - private final List subCommands = ObjectList.of( + private final List subCommands = ObjectList.of( new GrantDisguiseSubCommand(), new RevokeDisguiseSubCommand(), new ForceUnmorphSubCommand(), @@ -25,19 +28,24 @@ public class DisguiseManageSubCommand extends MorphPluginObject implements ISubC ); @Override - public @Nullable String getPermissionRequirement() + public void registerAsChild(ArgumentBuilder parentBuilder) { - return CommonPermissions.MANAGE_DISGUISES; + var thisBuilder = Commands.literal(name()) + .requires(this::checkPermission); + + this.subCommands.forEach(s -> s.registerAsChild(thisBuilder)); + + parentBuilder.then(thisBuilder); } @Override - public List getSubCommands() + public @Nullable String permission() { - return subCommands; + return CommonPermissions.MANAGE_DISGUISES; } @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "manage"; } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/HelpSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/HelpSubCommand.java index d14d4022..4c285465 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/HelpSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/HelpSubCommand.java @@ -1,5 +1,12 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import it.unimi.dsi.fastutil.objects.ObjectList; import net.kyori.adventure.text.Component; @@ -7,27 +14,24 @@ import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.TextDecoration; import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Initializer; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; -import xiamomc.pluginbase.Command.SubCommandHandler; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphPluginObject; import xyz.nifeather.morph.commands.MorphCommandManager; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.commands.subcommands.plugin.helpsections.Entry; import xyz.nifeather.morph.commands.subcommands.plugin.helpsections.Section; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import java.util.List; +import java.util.concurrent.CompletableFuture; -public class HelpSubCommand extends MorphPluginObject implements ISubCommand +public class HelpSubCommand extends MorphPluginObject implements IConvertibleBrigadier { - @Override - public String getCommandName() + public String name() { return "help"; } @@ -57,25 +61,25 @@ private void setupCommandSections() commandSections.add(miscCommandSection); //遍历所有指令 - for (var c : cmdHelper.getCommands()) + for (var c : cmdHelper.commands()) { //如果指令拥有子指令,新建section - if (c instanceof SubCommandHandler sch) + if (!c.children().isEmpty()) { //此section下所有指令的父级指令 - var parentCommandName = sch.getCommandName(); + var parentCommandName = c.name(); - List notes = new ObjectArrayList<>(sch.getNotes()); + List notes = new ObjectArrayList<>(c.getNotes()); var section = new Section(parentCommandName, - sch.getHelpMessage(), + c.getHelpMessage(), notes); //添加指令到section中 - for (var sc : sch.getSubCommands()) + for (var sc : c.children()) { - var cmdName = parentCommandName + " " + sc.getCommandName() + " "; - section.add(new Entry(sc.getPermissionRequirement(), + var cmdName = parentCommandName + " " + sc.name(); + section.add(new Entry(sc.permission(), cmdName, sc.getHelpMessage(), "/" + cmdName)); @@ -84,10 +88,12 @@ private void setupCommandSections() commandSections.add(section); } else - miscCommandSection.add(new Entry(c.getPermissionRequirement(), - c.getCommandName(), + { + miscCommandSection.add(new Entry(c.permission(), + c.name(), c.getHelpMessage(), - "/" + c.getCommandName() + " ")); + "/" + c.name())); + } } } @@ -123,7 +129,7 @@ private List constructSectionMessage(CommandSender sender, Section se } } - if (section.getNotes() != null && section.getNotes().size() >= 1) + if (section.getNotes() != null && !section.getNotes().isEmpty()) { list.addAll(ObjectList.of( Component.empty(), @@ -162,7 +168,7 @@ private List constructHelpMessage(CommandSender sender) .resolve("description", section.getDescription(), null) .toComponent(locale) .decorate(TextDecoration.UNDERLINED) - .clickEvent(ClickEvent.runCommand("/feathermorph " + getCommandName() + " " + section.getCommandBaseName())) + .clickEvent(ClickEvent.runCommand("/feathermorph " + name() + " " + section.getCommandBaseName())) .hoverEvent(HoverEvent.showText(HelpStrings.clickToViewString().toComponent(locale))); list.add(msg); @@ -171,56 +177,65 @@ private List constructHelpMessage(CommandSender sender) return list; } - @Override - public String getPermissionRequirement() + public void registerAsChild(ArgumentBuilder parentBuilder) { - return null; + parentBuilder.then( + Commands.literal(name()) + .executes(this::executeNoArgs) + .then( + Commands.argument("section", StringArgumentType.greedyString()) + .suggests(this::suggestSection) + .executes(this::executeWithArgs) + ) + ); } - @Override - public FormattableMessage getHelpMessage() + private int executeNoArgs(CommandContext context) { - return HelpStrings.helpDescription(); + var sender = context.getSource().getSender(); + + for (var s : constructHelpMessage(sender)) + sender.sendMessage(MessageUtils.prefixes(sender, s)); + + return 1; } - @Override - public @Nullable List onTabComplete(List args, CommandSender source) + private int executeWithArgs(CommandContext context) { - var baseName = args.size() >= 1 ? args.get(0) : ""; - var matchedSections = commandSections.stream() - .filter(s -> s.getCommandBaseName().toLowerCase().startsWith(baseName.toLowerCase())).toList(); + var sender = context.getSource().getSender(); - var list = new ObjectArrayList(); + var sectionName = StringArgumentType.getString(context, "section"); + var section = commandSections.stream() + .filter(s -> s.getCommandBaseName().equalsIgnoreCase(sectionName)).findFirst().orElse(null); - for (var s : matchedSections) - list.add(s.getCommandBaseName()); + if (section != null) + { + for (var s : constructSectionMessage(sender, section)) + sender.sendMessage(MessageUtils.prefixes(sender, s)); + } + else + sender.sendMessage(MessageUtils.prefixes(sender, HelpStrings.sectionNotFoundString().withLocale(MessageUtils.getLocale(sender)))); - return list; + return 1; } - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) + private CompletableFuture suggestSection(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - if (args.length >= 1) - { - var section = commandSections.stream() - .filter(s -> s.getCommandBaseName().equalsIgnoreCase(args[0])).findFirst().orElse(null); + var baseName = suggestionsBuilder.getRemainingLowerCase(); - if (section != null) - { - for (var s : constructSectionMessage(sender, section)) - sender.sendMessage(MessageUtils.prefixes(sender, s)); - } - else - sender.sendMessage(MessageUtils.prefixes(sender, HelpStrings.sectionNotFoundString().withLocale(MessageUtils.getLocale(sender)))); + var matchedSections = commandSections.stream() + .filter(s -> s.getCommandBaseName().toLowerCase().startsWith(baseName.toLowerCase())).toList(); - return true; - } + for (var s : matchedSections) + suggestionsBuilder.suggest(s.getCommandBaseName()); - for (var s : constructHelpMessage(sender)) - sender.sendMessage(MessageUtils.prefixes(sender, s)); + return suggestionsBuilder.buildFuture(); + } - return true; + @Override + public FormattableMessage getHelpMessage() + { + return HelpStrings.helpDescription(); } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/LookupSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/LookupSubCommand.java index 63c352bf..27aa77dd 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/LookupSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/LookupSubCommand.java @@ -1,24 +1,28 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.permissions.CommonPermissions; import java.util.List; -public class LookupSubCommand extends MorphPluginObject implements ISubCommand +public class LookupSubCommand extends BrigadierCommand { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "lookup"; } @@ -44,23 +48,52 @@ public FormattableMessage getHelpMessage() private MorphManager manager; @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) + public void registerAsChild(ArgumentBuilder parentBuilder) { - if (args.length == 0) return false; + parentBuilder.then( + Commands.literal("lookup") + .then( + Commands.argument("who", StringArgumentType.string()) + .executes(this::execWithName) + .then( + Commands.argument("filter", StringArgumentType.string()) + .executes(this::execWithNameFilter) + ) + ) + ); - var targetLookupName = args[0]; - var offlinePlayer = Bukkit.getOfflinePlayer(targetLookupName); - var targetLookupKey = args.length >= 2 ? args[1] : "any"; + super.registerAsChild(parentBuilder); + } + + private int execWithName(CommandContext context) + { + var targetLookupName = StringArgumentType.getString(context, "who"); + LookupSubCommand.this.doLookup(context.getSource().getSender(), targetLookupName, null); + + return 1; + } + + private int execWithNameFilter(CommandContext context) + { + var targetLookupName = StringArgumentType.getString(context, "who"); + var filterName = StringArgumentType.getString(context, "filter"); + LookupSubCommand.this.doLookup(context.getSource().getSender(), targetLookupName, filterName); + + return 1; + } + private void doLookup(CommandSender sender, String who, @Nullable String filterName) + { + var offlinePlayer = Bukkit.getOfflinePlayer(who); var configuration = manager.getPlayerMeta(offlinePlayer); List matches; //filter keys - if (!targetLookupKey.equals("any")) + if (filterName != null) { matches = configuration.getUnlockedDisguiseIdentifiers() - .stream().filter(k -> k.toUpperCase().contains(targetLookupKey.toUpperCase())) + .stream().filter(k -> k.toUpperCase().contains(filterName.toUpperCase())) .toList(); } else @@ -69,11 +102,6 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) } sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.lookupFilterCommand())); - matches.forEach(m -> - { - sender.sendMessage(MessageUtils.prefixes(sender, m)); - }); - - return true; + matches.forEach(m -> sender.sendMessage(MessageUtils.prefixes(sender, m))); } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/MakeSkillItemSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/MakeSkillItemSubCommand.java index b27c6345..28034ea3 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/MakeSkillItemSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/MakeSkillItemSubCommand.java @@ -1,23 +1,22 @@ package xyz.nifeather.morph.commands.subcommands.plugin; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; -import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.permissions.CommonPermissions; import xyz.nifeather.morph.utilities.ItemUtils; -import java.util.List; - -public class MakeSkillItemSubCommand extends MorphPluginObject implements ISubCommand +public class MakeSkillItemSubCommand extends BrigadierCommand { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "make_disguise_tool"; } @@ -34,28 +33,34 @@ public FormattableMessage getHelpMessage() return new FormattableMessage(plugin, "make selected a disguise tool"); } - private final List emptyList = List.of(); - @Override - public @Nullable List onTabComplete(List args, CommandSender source) + public boolean register(Commands dispatcher) { - return emptyList; + dispatcher.register( + Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::executes) + .build() + ); + + return super.register(dispatcher); } - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) + public int executes(CommandContext context) { + var sender = context.getSource().getSender(); + if (!(sender instanceof Player player)) { sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.noPermissionMessage())); - return true; + return 1; } var item = player.getEquipment().getItemInMainHand(); if (item.isEmpty() || item.getType().isAir()) { sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.illegalArgumentString().resolve("detail", "air... :("))); - return true; + return 1; } item = ItemUtils.buildDisguiseToolFrom(item); @@ -63,6 +68,6 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.success())); - return true; + return 1; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/OptionSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/OptionSubCommand.java index 29021ed0..1a792a9c 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/OptionSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/OptionSubCommand.java @@ -1,28 +1,33 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; -import xiamomc.pluginbase.Exceptions.NullDependencyException; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphPluginObject; -import xyz.nifeather.morph.commands.subcommands.SubCommandGenerator; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; +import xyz.nifeather.morph.commands.subcommands.OptionSubCommands; import xyz.nifeather.morph.config.ConfigOption; import xyz.nifeather.morph.config.MorphConfigManager; import xyz.nifeather.morph.events.InteractionMirrorProcessor; -import xyz.nifeather.morph.messages.*; +import xyz.nifeather.morph.messages.CommandNameStrings; +import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -import xyz.nifeather.morph.utilities.BindableUtils; import java.util.List; -import java.util.function.Function; +import java.util.concurrent.CompletableFuture; -public class OptionSubCommand extends MorphPluginObject implements ISubCommand +public class OptionSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "option"; } @@ -87,214 +92,47 @@ public OptionSubCommand() subCommands.add(getToggle("towny_allow_flight_in_wilderness", ConfigOption.TOWNY_ALLOW_FLY_IN_WILDERNESS)); } - private ISubCommand getList(String optionName, ConfigOption option, - @Nullable FormattableMessage displayName) + private CompletableFuture suggestListOperation(CommandContext context, + SuggestionsBuilder suggestionsBuilder) { - var targetDisplay = displayName == null ? new FormattableMessage(plugin, optionName) : displayName; - - var bindableList = config.getBindableList(String.class, option); - - return SubCommandGenerator.command() - .setName(optionName) - .setPerm(this.getPermissionRequirement()) - .setExec((sender, args) -> - { - if (args.length < 1) - { - var displayValue = BindableUtils.bindableListToString(bindableList); - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.optionValueString() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("what", targetDisplay, null) - .resolve("value", displayValue))); - - return true; - } - - if (args.length < 2) - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.listNoEnoughArguments() - .withLocale(MessageUtils.getLocale(sender)))); - - return true; - } - - var operation = args[0]; - if (operation.equalsIgnoreCase("add")) - { - var value = args[1]; - try - { - bindableList.add(value); - - //workaround: List的add方法传入非null时永远返回true - if (bindableList.contains(value)) - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.listAddSuccess() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("value", value) - .resolve("option", optionName))); - } - else - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.listAddFailUnknown() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("value", value) - .resolve("option", optionName))); - } - } - catch (Throwable t) - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.listAddFailUnknown() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("value", value) - .resolve("option", optionName))); - - logger.error("Error adding option to bindable list: " + t.getMessage()); - } - - return true; - } - else if (operation.equalsIgnoreCase("remove")) - { - var value = args[1]; - var listChanged = bindableList.remove(value); - - if (listChanged) - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.listRemoveSuccess() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("value", value) - .resolve("option", optionName))); - } - else - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.listRemoveFailUnknown() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("value", value) - .resolve("option", optionName))); - } - - return true; - } - else - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.unknownOperation() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("operation", operation))); - - return true; - } - }); - } + suggestionsBuilder.suggest("list").suggest("add").suggest("remove"); - private ISubCommand getGeneric(String name, ConfigOption option, - @Nullable FormattableMessage displayName, Class targetClass, - Function func, String typeName) - { - return getGeneric(name, option, displayName, targetClass, func, new FormattableMessage(plugin, typeName)); - } - - private ISubCommand getGeneric(String name, ConfigOption option, - @Nullable FormattableMessage displayName, Class targetClass, - Function func, FormattableMessage typeName) - { - var targetDisplay = displayName == null ? new FormattableMessage(plugin, name) : displayName; - - return SubCommandGenerator.command() - .setName(name) - .setPerm(this.getPermissionRequirement()) - .setExec((sender, args) -> - { - if (args.length < 1) - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.optionValueString() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("what", targetDisplay, null) - .resolve("value", config.get(targetClass, option) + ""))); - - return true; - } - - T value = null; - - try - { - value = func.apply(args[0]); - - if (value == null) - throw new NullDependencyException(""); - } - catch (Throwable ignored) - { - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.argumentTypeErrorString() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("type", typeName))); - - return true; - } - - config.set(option, value); - - sender.sendMessage(MessageUtils.prefixes(sender, - CommandStrings.optionSetString() - .withLocale(MessageUtils.getLocale(sender)) - .resolve("what", targetDisplay, null) - .resolve("value", value + ""))); - return true; - }); + return suggestionsBuilder.buildFuture(); } - private ISubCommand getMirrorMode(String name, ConfigOption option, @Nullable FormattableMessage displayName) + private IConvertibleBrigadier getList(String optionName, ConfigOption option, + @Nullable FormattableMessage displayName) { - return getGeneric(name, option, displayName, String.class, enumName -> - { - String value = null; - - var byName = InteractionMirrorProcessor.InteractionMirrorSelectionMode.BY_NAME.toLowerCase(); - var bySight = InteractionMirrorProcessor.InteractionMirrorSelectionMode.BY_SIGHT.toLowerCase(); - - if (enumName.equalsIgnoreCase(byName)) - value = byName; - else if (enumName.equalsIgnoreCase(bySight)) - value = bySight; - - return value; - }, "by_sight/by_name"); + return new OptionSubCommands.StringListOptionBaseCommand(optionName, config, option); } - private ISubCommand getDouble(String name, ConfigOption option, @Nullable FormattableMessage displayName) + private IConvertibleBrigadier getMirrorMode(String name, ConfigOption option, @Nullable FormattableMessage displayName) { - return getGeneric(name, option, displayName, Double.class, Double::parseDouble, TypesString.typeDouble()); + return new OptionSubCommands.LimiterStringListOptionCommand( + name, config, option, List.of( + InteractionMirrorProcessor.InteractionMirrorSelectionMode.BY_NAME.toLowerCase(), + InteractionMirrorProcessor.InteractionMirrorSelectionMode.BY_SIGHT.toLowerCase()) + ); } - private ISubCommand getInteger(String name, ConfigOption option) + private IConvertibleBrigadier getInteger(String name, ConfigOption option) { return getInteger(name, option, null); } - private ISubCommand getInteger(String name, ConfigOption option, @Nullable FormattableMessage displayName) + private IConvertibleBrigadier getInteger(String name, ConfigOption option, @Nullable FormattableMessage displayName) { - return getGeneric(name, option, displayName, Integer.class, Integer::parseInt, TypesString.typeInteger()); + return new OptionSubCommands.BooleanOptionCommand(name, config, option); } - private ISubCommand getToggle(String name, ConfigOption option) + private IConvertibleBrigadier getToggle(String name, ConfigOption option) { return getToggle(name, option, null); } - private ISubCommand getToggle(String name, ConfigOption option, @Nullable FormattableMessage displayName) + private IConvertibleBrigadier getToggle(String name, ConfigOption option, @Nullable FormattableMessage displayName) { - return getGeneric(name, option, displayName, Boolean.class, this::parseBoolean, "true/false"); + return new OptionSubCommands.BooleanOptionCommand(name, config, option); } private boolean parseBoolean(String input) @@ -307,18 +145,23 @@ private boolean parseBoolean(String input) || "enabled".equalsIgnoreCase(input); } - private final List subCommands = new ObjectArrayList<>(); + private final List subCommands = new ObjectArrayList<>(); @Override - public String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.SET_OPTIONS; } @Override - public List getSubCommands() + public void registerAsChild(ArgumentBuilder parentBuilder) { - return subCommands; + var thisBuilder = Commands.literal(name()).requires(this::checkPermission); + + for (IConvertibleBrigadier subCommand : this.subCommands) + subCommand.registerAsChild(thisBuilder); + + parentBuilder.then(thisBuilder); } @Override diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QueryAllSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QueryAllSubCommand.java index 1a1c6fe9..424b20a3 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QueryAllSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QueryAllSubCommand.java @@ -1,21 +1,22 @@ package xyz.nifeather.morph.commands.subcommands.plugin; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -public class QueryAllSubCommand extends MorphPluginObject implements ISubCommand +public class QueryAllSubCommand extends BrigadierCommand { @Override - public String getCommandName() + public String name() { return "queryall"; } @@ -36,15 +37,28 @@ public String getPermissionRequirement() private MorphManager manager; @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] strings) + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::executes) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) { var list = manager.getActiveDisguises(); var offlineStates = manager.getAvaliableOfflineStates(); + var commandSender = context.getSource().getSender(); + if (list.size() == 0 && offlineStates.size() == 0) { commandSender.sendMessage(MessageUtils.prefixes(commandSender, CommandStrings.qaNoBodyDisguisingString())); - return true; + return 1; } var msg = CommandStrings.qaDisguisedString(); @@ -76,6 +90,6 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] .resolve("what", s.disguiseID))); } - return true; + return 1; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QuerySubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QuerySubCommand.java index 8e92cf32..1ea3dd74 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QuerySubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/QuerySubCommand.java @@ -1,26 +1,30 @@ package xyz.nifeather.morph.commands.subcommands.plugin; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class QuerySubCommand extends MorphPluginObject implements ISubCommand +public class QuerySubCommand extends BrigadierCommand { @Override - public String getCommandName() + public String name() { return "query"; } @@ -38,61 +42,76 @@ public String getPermissionRequirement() } @Override - public List onTabComplete(List args, CommandSender sender) + public void registerAsChild(ArgumentBuilder parentBuilder) { - var list = new ObjectArrayList(); - if (args.size() > 1) return list; + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .then( + Commands.argument("who", StringArgumentType.greedyString()) + .suggests(this::suggests) + .executes(this::executes) + ) + ); - var name = args.size() == 1 ? args.get(0) : ""; + super.registerAsChild(parentBuilder); + } - for (Player onlinePlayer : Bukkit.getOnlinePlayers()) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> { - var playerName = onlinePlayer.getName(); - if (playerName.toLowerCase().startsWith(name.toLowerCase())) list.add(playerName); - } + var name = suggestionsBuilder.getRemainingLowerCase(); - return list; + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) + { + var playerName = onlinePlayer.getName(); + if (playerName.toLowerCase().startsWith(name.toLowerCase())) + suggestionsBuilder.suggest(playerName); + } + + return suggestionsBuilder.build(); + }); } @Resolved private MorphManager manager; - @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] args) + public int executes(CommandContext context) { - if (args.length >= 1) - { - var targetPlayer = Bukkit.getPlayerExact(args[0]); - String locale = null; + var targetPlayer = Bukkit.getPlayerExact(StringArgumentType.getString(context, "who")); + String locale = null; + + var commandSender = context.getSource().getSender(); - if (commandSender instanceof Player player) - locale = MessageUtils.getLocale(player); + if (commandSender instanceof Player player) + locale = MessageUtils.getLocale(player); + + if (targetPlayer != null) + { + var state = manager.getDisguiseStateFor(targetPlayer); - if (targetPlayer != null) + if (state != null) { - var state = manager.getDisguiseStateFor(targetPlayer); - - if (state != null) - { - commandSender.sendMessage(MessageUtils.prefixes(commandSender, - CommandStrings.qDisguisedString() - .withLocale(locale) - .resolve("who", targetPlayer.getName()) - .resolve("what", state.getDisguiseIdentifier()) - .resolve("storage_status", - state.showingDisguisedItems() - ? CommandStrings.qaShowingDisguisedItemsString() - : CommandStrings.qaNotShowingDisguisedItemsString(), - null) - )); - } - else - { - commandSender.sendMessage(MessageUtils.prefixes(commandSender, - CommandStrings.qNotDisguisedString().resolve("who", targetPlayer.getName()))); - } + commandSender.sendMessage(MessageUtils.prefixes(commandSender, + CommandStrings.qDisguisedString() + .withLocale(locale) + .resolve("who", targetPlayer.getName()) + .resolve("what", state.getDisguiseIdentifier()) + .resolve("storage_status", + state.showingDisguisedItems() + ? CommandStrings.qaShowingDisguisedItemsString() + : CommandStrings.qaNotShowingDisguisedItemsString(), + null) + )); + } + else + { + commandSender.sendMessage(MessageUtils.prefixes(commandSender, + CommandStrings.qNotDisguisedString().resolve("who", targetPlayer.getName()))); } } - return true; + + return 1; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ReloadSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ReloadSubCommand.java index 43b051e7..dcc4fec2 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ReloadSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ReloadSubCommand.java @@ -1,14 +1,20 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import it.unimi.dsi.fastutil.objects.ObjectImmutableList; -import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xiamomc.pluginbase.Messages.MessageStore; import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.config.MorphConfigManager; import xyz.nifeather.morph.events.api.lifecycle.ConfigurationReloadEvent; import xyz.nifeather.morph.messages.CommandStrings; @@ -23,19 +29,19 @@ import xyz.nifeather.morph.storage.skill.SkillsConfigurationStoreNew; import java.util.List; +import java.util.concurrent.CompletableFuture; -public class ReloadSubCommand extends MorphPluginObject implements ISubCommand +public class ReloadSubCommand extends BrigadierCommand { @Override @NotNull - public String getCommandName() + public String name() { return "reload"; } @Override - @NotNull - public String getPermissionRequirement() + public @Nullable String getPermissionRequirement() { return CommonPermissions.DO_RELOAD; } @@ -70,63 +76,83 @@ public FormattableMessage getHelpMessage() private final List subcommands = ObjectImmutableList.of("data", "message", "update_message"); @Override - public List onTabComplete(List args, CommandSender source) + public void registerAsChild(ArgumentBuilder parentBuilder) { - if (source.hasPermission(getPermissionRequirement()) && args.size() >= 1) - return subcommands.stream().filter(s -> s.startsWith(args.get(0))).toList(); - else - return null; + parentBuilder.then( + Commands.literal("reload") + .requires(this::checkPermission) + .then( + Commands.argument("operation", StringArgumentType.greedyString()) + .suggests(this::suggests) + .executes(this::executes) + ) + ); + + super.registerAsChild(parentBuilder); } - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> + { + suggestionsBuilder.suggest("*"); + + var input = suggestionsBuilder.getRemainingLowerCase(); + + var target = subcommands.stream() + .filter(s -> s.startsWith(input)) + .toList(); + + target.forEach(suggestionsBuilder::suggest); + + return suggestionsBuilder.build(); + }); + } + + public int executes(CommandContext context) { - if (sender.hasPermission(getPermissionRequirement())) + var reloadsData = false; + var reloadsMessage = false; + var reloadOverwriteNonDefMsg = false; + String option = StringArgumentType.getString(context, "operation"); + + switch (option) { - var reloadsData = false; - var reloadsMessage = false; - var reloadOverwriteNonDefMsg = false; - String option = args.length >= 1 ? args[0] : "*"; - - switch (option) - { - case "data" -> reloadsData = true; - case "message" -> reloadsMessage = true; - case "update_message" -> reloadsMessage = reloadOverwriteNonDefMsg = true; - default -> reloadsMessage = reloadsData = true; - } - - if (reloadsData) - { - config.reload(); - skills.clearCache(); - morphManager.reloadConfiguration(); - - PlayerSkinProvider.getInstance().reload(); - - multiInstanceService.onReload(); - - recipeManager.reload(); - } - - if (reloadsMessage) - { - if (reloadOverwriteNonDefMsg && messageStore instanceof MorphMessageStore morphMessageStore) - morphMessageStore.reloadOverwriteNonDefault(); - else - messageStore.reloadConfiguration(); - - vanillaMessageStore.reloadConfiguration(); - } - - var event = new ConfigurationReloadEvent(reloadsData, reloadsMessage); - event.callEvent(); - - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.reloadCompleteMessage())); + case "data" -> reloadsData = true; + case "message" -> reloadsMessage = true; + case "update_message" -> reloadsMessage = reloadOverwriteNonDefMsg = true; + default -> reloadsMessage = reloadsData = true; } - else - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.noPermissionMessage())); - return true; + if (reloadsData) + { + config.reload(); + skills.clearCache(); + morphManager.reloadConfiguration(); + + PlayerSkinProvider.getInstance().reload(); + + multiInstanceService.onReload(); + + recipeManager.reload(); + } + + if (reloadsMessage) + { + if (reloadOverwriteNonDefMsg && messageStore instanceof MorphMessageStore morphMessageStore) + morphMessageStore.reloadOverwriteNonDefault(); + else + messageStore.reloadConfiguration(); + + vanillaMessageStore.reloadConfiguration(); + } + + var event = new ConfigurationReloadEvent(reloadsData, reloadsMessage); + event.callEvent(); + + var sender = context.getSource().getSender(); + sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.reloadCompleteMessage())); + + return 0; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/SkinCacheSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/SkinCacheSubCommand.java index 720ac9a6..2bc62bf5 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/SkinCacheSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/SkinCacheSubCommand.java @@ -1,7 +1,13 @@ package xyz.nifeather.morph.commands.subcommands.plugin; import com.destroystokyo.paper.profile.CraftPlayerProfile; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.TextDecoration; @@ -12,11 +18,10 @@ import xiamomc.pluginbase.Annotations.Initializer; import xiamomc.pluginbase.Annotations.Resolved; import xiamomc.pluginbase.Bindables.Bindable; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; -import xyz.nifeather.morph.commands.subcommands.plugin.skincache.cmdTree.CommandBuilder; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.config.ConfigOption; import xyz.nifeather.morph.config.MorphConfigManager; import xyz.nifeather.morph.messages.CommandStrings; @@ -29,18 +34,19 @@ import xyz.nifeather.morph.misc.permissions.CommonPermissions; import xyz.nifeather.morph.misc.skins.PlayerSkinProvider; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class SkinCacheSubCommand extends MorphPluginObject implements ISubCommand +@SuppressWarnings("UnstableApiUsage") +public class SkinCacheSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "skin_cache"; } @Override - public @Nullable String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.ACCESS_SKIN_CACHE; } @@ -53,290 +59,334 @@ public FormattableMessage getHelpMessage() private final PlayerSkinProvider skinProvider = PlayerSkinProvider.getInstance(); - private List genSubCmd() + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) { - return CommandBuilder.builder() - .startNew() - .name("list") - //.permission("dddd") - .onFilter(args -> List.of("all")) - .executes((sender, args) -> - { - var currentTime = System.currentTimeMillis(); - var skins = skinProvider.getAllSkins(); - var str = Component.empty(); + parentBuilder.then( + Commands.literal(name()) + .then( + Commands.literal("list") + .executes(ctx -> this.executeList(ctx, null)) + .then( + Commands.argument("amount", StringArgumentType.string()) + .suggests((ctx, builder) -> builder.suggest("all").buildFuture()) + .executes(ctx -> this.executeList(ctx, StringArgumentType.getString(ctx, "amount"))) + ) + ).then( + Commands.literal("drop") + .then( + Commands.argument("skin", StringArgumentType.string()) + .suggests((ctx, builder) -> + { + var allSkin = skinProvider.getAllSkins(); + + return CompletableFuture.supplyAsync(() -> + { + var input = builder.getRemainingLowerCase(); + + allSkin.forEach(singleSkin -> + { + var skinName = singleSkin.name; + + if (skinName.toLowerCase().contains(input)) + builder.suggest(skinName); + }); + + return builder.build(); + }); + }) + .executes(this::executeDrop) + ) + ).then( + Commands.literal("cache") + .then( + Commands.argument("name", StringArgumentType.string()) + .executes(this::executeCache) + ) + ).then( + Commands.literal("info") + .then( + Commands.argument("skin", StringArgumentType.string()) + .suggests(this::filterSkinName) + .executes(this::executeInfo) + ) + ).then( + Commands.literal("disguise") + .then( + Commands.argument("skin", StringArgumentType.string()) + .suggests(this::filterSkinName) + .executes(this::executeDisguise) + ) + ).then( + Commands.literal("copy") + .then( + Commands.argument("source", StringArgumentType.string()) + .suggests(this::filterSkinName) + .then( + Commands.argument("target", StringArgumentType.string()) + .executes(this::executeCopy) + ) + ) + ).then( + Commands.literal("rename") + .then( + Commands.argument("from", StringArgumentType.string()) + .suggests(this::filterSkinName) + .then( + Commands.argument("to", StringArgumentType.string()) + .executes(this::executeRename) + ) + ) + ) + ); + } - sender.sendMessage( - MessageUtils.prefixes(sender, SkinCacheStrings.listHeader().resolve("count", skins.size() + "")) - ); + private CompletableFuture filterSkinName(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + var targetName = suggestionsBuilder.getRemainingLowerCase(); - var limit = args.isEmpty() - ? 20 - : args.get(0).equalsIgnoreCase("all") - ? Integer.MAX_VALUE - : 20; + var allSkin = skinProvider.getAllSkins(); - var current = 0; + return CompletableFuture.supplyAsync(() -> + { + allSkin.forEach(singleSkin -> + { + var skinName = singleSkin.name; - var overallLine = SkinCacheStrings.skinInfoOverallLine(); - var expiredString = SkinCacheStrings.skinExpired().toComponent(MessageUtils.getLocale(sender)); + if (skinName.toLowerCase().contains(targetName)) + suggestionsBuilder.suggest(skinName); + }); - overallLine.resolve("x_more", Component.empty()); + return suggestionsBuilder.build(); + }); + } - var it = skins.iterator(); - while (it.hasNext()) - { - current++; + private int executeDrop(CommandContext context) + { + var sender = context.getSource().getSender(); + var targetName = StringArgumentType.getString(context, "skin"); - var next = it.next(); - str = str.append(Component.text(next.name)); + if (targetName.equals("*")) + { + var skinCount = skinProvider.getAllSkins().size(); + skinProvider.dropAll(); - if (currentTime > next.expiresAt) - str = str.append(expiredString); + sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.droppedAllSkins().resolve("count", skinCount + ""))); + } + else + { + skinProvider.dropSkin(targetName); - if (it.hasNext() && !(current == limit)) - str = str.append(Component.text(", ")); + sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.droppedSkin().resolve("name", targetName))); + } - if (current == limit) - { - var remaining = skins.size() - current; - overallLine.resolve("x_more", - SkinCacheStrings.andXMore() - .resolve("count", remaining + "") - .withLocale(MessageUtils.getLocale(sender))); + return 1; + } - break; - } - } + private int executeList(CommandContext context, @Nullable String exInput) + { + var sender = context.getSource().getSender(); + var currentTime = System.currentTimeMillis(); + var skins = skinProvider.getAllSkins(); + var str = Component.empty(); - overallLine.resolve("info_line", str); + sender.sendMessage( + MessageUtils.prefixes(sender, SkinCacheStrings.listHeader().resolve("count", skins.size() + "")) + ); - sender.sendMessage(MessageUtils.prefixes(sender, overallLine)); + int limit = 20; - return true; - }) + if (exInput != null) + { + try + { + if (exInput.equals("all")) + limit = Integer.MAX_VALUE; + else + limit = Integer.parseInt(exInput); + } + catch (Throwable ignored) + { + } + } - .startNew() - .name("drop") - //.permission("dddd") - .onFilter(args -> - { - var stream = skinProvider.getAllSkins() - .stream() - .map(sk -> sk.name); + limit = Math.min(1, limit); - var filterName = args.isEmpty() ? "" : args.get(0); + var current = 0; - var list = new ObjectArrayList<>(stream - .filter(name -> name.toLowerCase().contains(filterName.toLowerCase())) - .toList()); + var overallLine = SkinCacheStrings.skinInfoOverallLine(); + var expiredString = SkinCacheStrings.skinExpired().toComponent(MessageUtils.getLocale(sender)); - if (filterName.isBlank()) - list.add("*"); + overallLine.resolve("x_more", Component.empty()); - return list; - }) - .executes((sender, args) -> - { - if (args.isEmpty()) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } - - var targetName = args.get(0); - - if (targetName.equals("*")) - { - var skinCount = skinProvider.getAllSkins().size(); - skinProvider.dropAll(); - - sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.droppedAllSkins().resolve("count", skinCount + ""))); - } - else - { - skinProvider.dropSkin(targetName); - - sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.droppedSkin().resolve("name", targetName))); - } - - return true; - }) - - .startNew() - .name("cache") - //.permission("dddd") - .executes((sender, args) -> - { - if (args.isEmpty()) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } - - var targetName = args.get(0); - - sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.fetchingSkin().resolve("name", targetName))); - - skinProvider.invalidate(targetName); - skinProvider.fetchSkin(targetName) - .thenAccept(optional -> - { - optional.ifPresentOrElse(profile -> sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.fetchSkinSuccess().resolve("name", targetName))), - () -> sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.targetSkinNotFound()))); - }); - - return true; - }) - - .startNew() - .name("info") - .onFilter(this::filterSkinName) - .executes((sender, args) -> - { - if (args.isEmpty()) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } - - var targetName = args.get(0); - var skinMatch = skinProvider.getCachedProfile(targetName); - - if (skinMatch == null) - { - sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.targetSkinNotFound())); - return true; - } - - var texDesc = ""; - var capeDesc = ""; - var tex = skinMatch.getProperties().get("textures").stream().findFirst().orElse(null); - - if (tex != null) - { - var playerProfile = CraftPlayerProfile.asBukkitCopy(skinMatch); - - var skinURL = playerProfile.getTextures().getSkin(); - if (skinURL != null) - texDesc = skinURL.toString(); - - var capeURL = playerProfile.getTextures().getCape(); - if (capeURL != null) - capeDesc = capeURL.toString(); - } - - sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.infoLine().resolve("name", skinMatch.getName()))); - - sender.sendMessage( - MessageUtils.prefixes( - sender, - SkinCacheStrings.infoSkinLine().resolve( - "url", - Component.text(texDesc) - .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, texDesc)) - .decorate(TextDecoration.UNDERLINED) - ) - ) - ); - - sender.sendMessage( - MessageUtils.prefixes( - sender, - SkinCacheStrings.infoCapeLine().resolve( - "cape", - CapeURL.findMatching(capeDesc).withLocale(MessageUtils.getLocale(sender)) - ) - ) - ); - - if (debug.get()) - sender.sendMessage("Cape " + capeDesc); - - return true; - }) - - .startNew() - .name("disguise") - .onFilter(this::filterSkinName) - .executes((sender, args) -> - { - if (args.isEmpty()) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } - - if (!(sender instanceof Player player)) - { - sender.sendMessage( - MessageUtils.prefixes( - sender, - CommandStrings.unknownOperation().resolve("operation", "disguise_from_skin_cache_in_console") - ) - ); - - return true; - } - - var targetName = args.get(0); - var skinMatch = skinProvider.getCachedProfile(targetName); - - if (skinMatch == null) - { - sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.targetSkinNotFound())); - return true; - } - - var parameters = MorphParameters - .create(player, DisguiseTypes.PLAYER.toId(skinMatch.getName())) - .setSource(sender) - .setBypassAvailableCheck(true); - - morphManager.morph(parameters); - - return true; - }) - - .startNew() - .name("copy") - .onFilter(this::filterSkinName) - .executes((sender, args) -> - { - if (args.size() < 2) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } + var it = skins.iterator(); + while (it.hasNext()) + { + current++; + + var next = it.next(); + str = str.append(Component.text(next.name)); + + if (currentTime > next.expiresAt) + str = str.append(expiredString); + + if (it.hasNext() && !(current == limit)) + str = str.append(Component.text(", ")); + + if (current == limit) + { + var remaining = skins.size() - current; + overallLine.resolve("x_more", + SkinCacheStrings.andXMore() + .resolve("count", remaining + "") + .withLocale(MessageUtils.getLocale(sender))); + + break; + } + } + + overallLine.resolve("info_line", str); + + sender.sendMessage(MessageUtils.prefixes(sender, overallLine)); - var sourceName = args.get(0); - var targetName = args.get(1); + return 1; + } + + private int executeCache(CommandContext context) + { + var sender = context.getSource().getSender(); - copyOrMoveSkin(sender, sourceName, targetName, false); + var targetName = StringArgumentType.getString(context, "name"); - return true; - }) + sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.fetchingSkin().resolve("name", targetName))); - .startNew() - .name("rename") - .onFilter(this::filterSkinName) - .executes((sender, args) -> + skinProvider.invalidate(targetName); + skinProvider.fetchSkin(targetName) + .thenAccept(optional -> { - if (args.size() < 2) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.listNoEnoughArguments())); - return true; - } + optional.ifPresentOrElse(profile -> sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.fetchSkinSuccess().resolve("name", targetName))), + () -> sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.targetSkinNotFound()))); + }); - var sourceName = args.get(0); - var targetName = args.get(1); + return 1; + } + + private int executeInfo(CommandContext context) + { + var sender = context.getSource().getSender(); + var targetName = StringArgumentType.getString(context, "skin"); + var skinMatch = skinProvider.getCachedProfile(targetName); - copyOrMoveSkin(sender, sourceName, targetName, true); + if (skinMatch == null) + { + sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.targetSkinNotFound())); + return 1; + } - return true; - }) + var texDesc = ""; + var capeDesc = ""; + var tex = skinMatch.getProperties().get("textures").stream().findFirst().orElse(null); - .buildAll(); + if (tex != null) + { + var playerProfile = CraftPlayerProfile.asBukkitCopy(skinMatch); + + var skinURL = playerProfile.getTextures().getSkin(); + if (skinURL != null) + texDesc = skinURL.toString(); + + var capeURL = playerProfile.getTextures().getCape(); + if (capeURL != null) + capeDesc = capeURL.toString(); + } + + sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.infoLine().resolve("name", skinMatch.getName()))); + + sender.sendMessage( + MessageUtils.prefixes( + sender, + SkinCacheStrings.infoSkinLine().resolve( + "url", + Component.text(texDesc) + .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.OPEN_URL, texDesc)) + .decorate(TextDecoration.UNDERLINED) + ) + ) + ); + + sender.sendMessage( + MessageUtils.prefixes( + sender, + SkinCacheStrings.infoCapeLine().resolve( + "cape", + CapeURL.findMatching(capeDesc).withLocale(MessageUtils.getLocale(sender)) + ) + ) + ); + + if (debug.get()) + sender.sendMessage("Cape " + capeDesc); + + return 1; + } + + private int executeDisguise(CommandContext context) + { + var sender = context.getSource().getSender(); + + if (!(sender instanceof Player player)) + { + sender.sendMessage( + MessageUtils.prefixes( + sender, + CommandStrings.unknownOperation().resolve("operation", "disguise_from_skin_cache_in_console") + ) + ); + + return 1; + } + + var targetName = StringArgumentType.getString(context, "skin"); + var skinMatch = skinProvider.getCachedProfile(targetName); + + if (skinMatch == null) + { + sender.sendMessage(MessageUtils.prefixes(sender, SkinCacheStrings.targetSkinNotFound())); + return 1; + } + + var parameters = MorphParameters + .create(player, DisguiseTypes.PLAYER.toId(skinMatch.getName())) + .setSource(sender) + .setBypassAvailableCheck(true); + + morphManager.morph(parameters); + + return 1; + } + + private int executeCopy(CommandContext context) + { + var sender = context.getSource().getSender(); + + var sourceName = StringArgumentType.getString(context, "source"); + var targetName = StringArgumentType.getString(context, "target"); + + copyOrMoveSkin(sender, sourceName, targetName, false); + + return 1; + } + + private int executeRename(CommandContext context) + { + var sender = context.getSource().getSender(); + + var sourceName = StringArgumentType.getString(context, "from"); + var targetName = StringArgumentType.getString(context, "to"); + + copyOrMoveSkin(sender, sourceName, targetName, true); + + return 1; } private void copyOrMoveSkin(CommandSender sender, String sourceName, String targetName, boolean isMoveOperation) @@ -425,19 +475,6 @@ private CopyMoveResult moveSkin(String sourceName, String targetName) return CopyMoveResult.SUCCESS; } - private List filterSkinName(List args) - { - var targetName = args.isEmpty() ? "" : args.get(0); - - if (args.size() > 1) return List.of(); - - return skinProvider.getAllSkins() - .stream() - .map(ss -> ss.name) - .filter(name -> name.toLowerCase().contains(targetName.toLowerCase())) - .toList(); - } - @Resolved(shouldSolveImmediately = true) private MorphManager morphManager; @@ -448,21 +485,4 @@ private void load(MorphConfigManager config) { config.bind(debug, ConfigOption.DEBUG_OUTPUT); } - - private List getSubCmd() - { - if (subCommands == null) - subCommands = genSubCmd(); - - return subCommands; - } - - @Nullable - private List subCommands; - - @Override - public @Nullable List getSubCommands() - { - return getSubCmd(); - } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/StatSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/StatSubCommand.java index 869a55f4..4db83988 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/StatSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/StatSubCommand.java @@ -1,14 +1,16 @@ package xyz.nifeather.morph.commands.subcommands.plugin; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPluginObject; import xyz.nifeather.morph.abilities.AbilityManager; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.messages.StatStrings; @@ -16,14 +18,26 @@ import xyz.nifeather.morph.network.server.MorphClientHandler; import xyz.nifeather.morph.skills.MorphSkillHandler; -public class StatSubCommand extends MorphPluginObject implements ISubCommand +public class StatSubCommand extends BrigadierCommand { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "stat"; } + @Override + public void registerAsChild(ArgumentBuilder parentBuilder) + { + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::executes) + ); + + super.registerAsChild(parentBuilder); + } + /** * 获取此指令的帮助信息 * @@ -47,14 +61,15 @@ public FormattableMessage getHelpMessage() @Resolved private MorphManager morphManager; - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) + public int executes(CommandContext context) { var disguisesActive = morphManager.getActiveDisguises().stream() .filter(s -> s.getPlayer().isOnline()).toArray().length; var authors = "MATRIX-feather"; //plugin.getPluginMeta().getAuthors(); + var sender = context.getSource().getSender(); + var listString = new StringBuilder(); var backends = morphManager.listManagedBackends(); var locale = MessageUtils.getLocale(sender); @@ -87,10 +102,10 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) .resolve("proto", String.valueOf(clientHandler.targetApiVersion)), StatStrings.defaultBackendString() - .resolve("backend", defaultBackendString), + .resolve("backend", defaultBackendString), StatStrings.activeBackends() - .resolve("list", listString.toString()), + .resolve("list", listString.toString()), StatStrings.providersString() .resolve("count", String.valueOf(MorphManager.getProviders().size())), @@ -115,7 +130,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) for (FormattableMessage formattableMessage : msg) sender.sendMessage(MessageUtils.prefixes(sender, formattableMessage)); - return true; + return 1; } private FormattableMessage getFormattable(String str) diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ToggleSelfSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ToggleSelfSubCommand.java index 55a6aa22..8bae7fab 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ToggleSelfSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/ToggleSelfSubCommand.java @@ -1,20 +1,21 @@ package xyz.nifeather.morph.commands.subcommands.plugin; -import org.bukkit.command.CommandSender; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; -import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.BrigadierCommand; import xyz.nifeather.morph.interfaces.IManagePlayerData; import xyz.nifeather.morph.messages.HelpStrings; -public class ToggleSelfSubCommand extends MorphPluginObject implements ISubCommand +public class ToggleSelfSubCommand extends BrigadierCommand { @Override - public String getCommandName() + public String name() { return "toggleself"; } @@ -38,12 +39,24 @@ public FormattableMessage getHelpMessage() private IManagePlayerData data; @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) + public void registerAsChild(ArgumentBuilder parentBuilder) { - if (sender instanceof Player player) - { - manager.setSelfDisguiseVisible(player, !data.getPlayerMeta(player).showDisguiseToSelf, true); - } - return true; + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .executes(this::executes) + ); + + super.registerAsChild(parentBuilder); + } + + public int executes(CommandContext context) + { + if (!(context.getSource().getExecutor() instanceof Player player)) + return 1; + + manager.setSelfDisguiseVisible(player, !data.getPlayerMeta(player).showDisguiseToSelf, true); + + return 1; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/helpsections/Entry.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/helpsections/Entry.java index 2d5ca65f..22303ade 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/helpsections/Entry.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/helpsections/Entry.java @@ -1,8 +1,9 @@ package xyz.nifeather.morph.commands.subcommands.plugin.helpsections; +import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Messages.FormattableMessage; -public record Entry(String permission, String baseName, FormattableMessage description, String suggestingCommand) +public record Entry(@Nullable String permission, String baseName, FormattableMessage description, String suggestingCommand) { @Override public String toString() diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceMorphSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceMorphSubCommand.java index e93c17a4..1a7912ad 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceMorphSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceMorphSubCommand.java @@ -1,33 +1,38 @@ package xyz.nifeather.morph.commands.subcommands.plugin.management; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.CommonStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.MorphParameters; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class ForceMorphSubCommand extends MorphPluginObject implements ISubCommand +public class ForceMorphSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "morph"; } @Override - public @Nullable String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.MANAGE_MORPH_DISGUISE; } @@ -36,61 +41,87 @@ public class ForceMorphSubCommand extends MorphPluginObject implements ISubComma private MorphManager manager; @Override - public @Nullable List onTabComplete(List args, CommandSender source) + public void registerAsChild(ArgumentBuilder parentBuilder) { - var list = new ObjectArrayList(); - - if (args.size() == 1) - { - var name = args.get(0); - - var onlinePlayers = Bukkit.getOnlinePlayers(); + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .then( + Commands.argument("who", StringArgumentType.string()) + .suggests(this::suggestPlayer) + .then( + Commands.argument("as_what", StringArgumentType.greedyString()) + .suggests(this::suggestDisguise) + .executes(this::execute) + ) + ) + ); + } - for (var p : onlinePlayers) - if (p.getName().toLowerCase().contains(name.toLowerCase())) list.add(p.getName()); - } - else if (args.size() == 2) + private CompletableFuture suggestDisguise(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> { - var targetLowerCase = args.get(1).toLowerCase(); + var input = suggestionsBuilder.getRemainingLowerCase(); for (var p : MorphManager.getProviders()) { + if (p == MorphManager.fallbackProvider) continue; + var ns = p.getNameSpace(); p.getAllAvailableDisguises().forEach(s -> { var str = ns + ":" + s; - if (str.toLowerCase().contains(targetLowerCase)) list.add(str); + if (str.toLowerCase().contains(input)) + suggestionsBuilder.suggest(str); }); } - } - return list; + return suggestionsBuilder.build(); + }); } - @Override - public boolean onCommand(@NotNull CommandSender commandSender, String[] strings) + private CompletableFuture suggestPlayer(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - if (strings.length != 2) return false; + var online = Bukkit.getOnlinePlayers(); + + return CompletableFuture.supplyAsync(() -> + { + var input = suggestionsBuilder.getRemainingLowerCase(); + + online.stream().forEach(player -> + { + var name = player.getName(); + if (name.toLowerCase().contains(input)) + suggestionsBuilder.suggest(name); + }); + + return suggestionsBuilder.build(); + }); + } - var who = Bukkit.getPlayerExact(strings[0]); - var targetName = strings[1]; + private int execute(CommandContext context) + { + var who = Bukkit.getPlayerExact(StringArgumentType.getString(context, "who")); + var targetName = StringArgumentType.getString(context, "as_what"); + var commandSender = context.getSource().getSender(); if (who == null || !who.isOnline()) { commandSender.sendMessage(MessageUtils.prefixes(commandSender, CommonStrings.playerNotFoundString())); - return false; + return 1; } var parameters = MorphParameters - .create(who, targetName) - .setSource(commandSender) - //.setTargetedEntity(who.getTargetEntity(3)) - .setForceExecute(true) - .setBypassAvailableCheck(true) - .setBypassPermission(true); + .create(who, targetName) + .setSource(commandSender) + //.setTargetedEntity(who.getTargetEntity(3)) + .setForceExecute(true) + .setBypassAvailableCheck(true) + .setBypassPermission(true); manager.morph(parameters); - return true; + return 1; } @Override diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceUnmorphSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceUnmorphSubCommand.java index cdbb9fc8..1dbf5c65 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceUnmorphSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/ForceUnmorphSubCommand.java @@ -1,84 +1,75 @@ package xyz.nifeather.morph.commands.subcommands.plugin.management; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.CommonStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -import java.util.List; -import java.util.Objects; +import java.util.concurrent.CompletableFuture; -public class ForceUnmorphSubCommand extends MorphPluginObject implements ISubCommand +public class ForceUnmorphSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "unmorph"; } @Override - public @Nullable String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.MANAGE_UNMORPH_DISGUISE; } - @Resolved - private MorphManager manager; - @Override - public @Nullable List onTabComplete(List args, CommandSender source) + public void registerAsChild(ArgumentBuilder parentBuilder) { - var list = new ObjectArrayList(); - if (args.size() != 1) return list; - - var name = args.get(0); - - var onlinePlayers = Bukkit.getOnlinePlayers(); - - if (name.isBlank()) - list.add("*"); - - for (var p : onlinePlayers) - if (p.getName().toLowerCase().contains(name.toLowerCase())) list.add(p.getName()); - - return list; + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .then( + Commands.argument("who", StringArgumentType.greedyString()) + .suggests(this::suggestPlayer) + .executes(this::execute) + ) + ); } - @Override - public boolean onCommand(@NotNull CommandSender sender, String[] args) + private int execute(CommandContext context) { - if (args.length < 1) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotDefinedString())); - - return true; - } + var sender = context.getSource().getSender(); + var who = StringArgumentType.getString(context, "who"); - if (Objects.equals(args[0], "*")) + if (who.equals("*")) { manager.unMorphAll(true); sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.unMorphedAllString())); - return true; + return 1; } - var player = Bukkit.getPlayerExact(args[0]); + var player = Bukkit.getPlayerExact(who); if (player == null) { sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotFoundString())); - return true; + return 1; } manager.unMorph(sender, player, true, true); @@ -86,9 +77,33 @@ public boolean onCommand(@NotNull CommandSender sender, String[] args) sender.sendMessage(MessageUtils.prefixes(sender, CommandStrings.unMorphedSomeoneString() .resolve("who", player.getName()))); - return true; + return 1; } + private CompletableFuture suggestPlayer(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + var online = Bukkit.getOnlinePlayers(); + + return CompletableFuture.supplyAsync(() -> + { + var input = suggestionsBuilder.getRemainingLowerCase(); + + suggestionsBuilder.suggest("*"); + + online.stream().forEach(player -> + { + var name = player.getName(); + if (name.toLowerCase().contains(input)) + suggestionsBuilder.suggest(name); + }); + + return suggestionsBuilder.build(); + }); + } + + @Resolved + private MorphManager manager; + @Override public FormattableMessage getHelpMessage() { diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/GrantDisguiseSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/GrantDisguiseSubCommand.java index 3b9abf90..3df643df 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/GrantDisguiseSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/GrantDisguiseSubCommand.java @@ -1,6 +1,12 @@ package xyz.nifeather.morph.commands.subcommands.plugin.management; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -8,20 +14,20 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.*; import xyz.nifeather.morph.misc.DisguiseTypes; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class GrantDisguiseSubCommand extends MorphPluginObject implements ISubCommand +public class GrantDisguiseSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "grant"; } @@ -33,30 +39,53 @@ public FormattableMessage getHelpMessage() } @Override - public @Nullable String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.MANAGE_GRANT_DISGUISE; } @Override - public List onTabComplete(List args, CommandSender source) + public void registerAsChild(ArgumentBuilder parentBuilder) { - var list = new ObjectArrayList(); - if (args.size() > 2) return list; - - var name = args.size() >= 1 ? args.get(0) : ""; - var target = args.size() == 2 ? args.get(1) : ""; + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .then( + Commands.argument("who", StringArgumentType.string()) + .suggests(this::suggestPlayer) + .then( + Commands.argument("what", StringArgumentType.greedyString()) + .executes(this::execute) + .suggests(this::suggestDisguise) + ) + ) + ); + } - var onlinePlayers = Bukkit.getOnlinePlayers(); + private CompletableFuture suggestPlayer(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + var online = Bukkit.getOnlinePlayers(); - if (args.size() == 1) //size == 1: 补全玩家 + return CompletableFuture.supplyAsync(() -> { - for (var p : onlinePlayers) - if (p.getName().toLowerCase().contains(name.toLowerCase())) list.add(p.getName()); - } - else if (args.size() == 2) //size == 2: 补全生物和玩家 + var input = suggestionsBuilder.getRemainingLowerCase(); + + online.stream().forEach(player -> + { + var name = player.getName(); + if (name.toLowerCase().contains(input)) + suggestionsBuilder.suggest(name); + }); + + return suggestionsBuilder.build(); + }); + } + + private CompletableFuture suggestDisguise(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> { - var targetLowerCase = target.toLowerCase(); + var input = suggestionsBuilder.getRemainingLowerCase(); for (var p : MorphManager.getProviders()) { @@ -66,31 +95,30 @@ else if (args.size() == 2) //size == 2: 补全生物和玩家 p.getAllAvailableDisguises().forEach(s -> { var str = ns + ":" + s; - if (str.toLowerCase().contains(targetLowerCase)) list.add(str); + if (str.toLowerCase().contains(input)) + suggestionsBuilder.suggest(str); }); - list.add(ns + ":" + "@all"); + suggestionsBuilder.suggest(ns + ":" + "@all"); } - } - return list; + return suggestionsBuilder.build(); + }); } @Resolved private MorphManager morphs; - @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] strings) + private int execute(CommandContext context) { - if (strings.length != 2) return false; - - var who = Bukkit.getPlayerExact(strings[0]); - var targetName = strings[1]; + var who = Bukkit.getPlayerExact(StringArgumentType.getString(context, "who")); + var targetName = StringArgumentType.getString(context, "what"); + var commandSender = context.getSource().getSender(); if (who == null || !who.isOnline()) { commandSender.sendMessage(MessageUtils.prefixes(commandSender, CommonStrings.playerNotFoundString())); - return false; + return 1; } if (!targetName.contains(":")) @@ -105,17 +133,17 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] var allDisg = provider.getAllAvailableDisguises(); allDisg.forEach(id -> grantDisguise(who, nameType.toId(id), commandSender)); - return true; + return 1; } else if (!provider.isValid(targetName)) { commandSender.sendMessage(MessageUtils.prefixes(commandSender, MorphStrings.invalidIdentityString())); - return true; + return 1; } grantDisguise(who, targetName, commandSender); - return true; + return 1; } private void grantDisguise(Player who, String targetName, CommandSender commandSender) diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/RevokeDisguiseSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/RevokeDisguiseSubCommand.java index 9aad5c6f..1646daef 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/RevokeDisguiseSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/management/RevokeDisguiseSubCommand.java @@ -1,28 +1,33 @@ package xyz.nifeather.morph.commands.subcommands.plugin.management; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.Commands; import net.kyori.adventure.text.Component; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.messages.CommandStrings; import xyz.nifeather.morph.messages.CommonStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.misc.permissions.CommonPermissions; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class RevokeDisguiseSubCommand extends MorphPluginObject implements ISubCommand +public class RevokeDisguiseSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Override - public @NotNull String getCommandName() + public @NotNull String name() { return "revoke"; } @@ -34,63 +39,84 @@ public FormattableMessage getHelpMessage() } @Override - public @Nullable String getPermissionRequirement() + public @Nullable String permission() { return CommonPermissions.MANAGE_REVOKE_DISGUISE; } + @Resolved + private MorphManager morphs; + @Override - public List onTabComplete(List args, CommandSender source) + public void registerAsChild(ArgumentBuilder parentBuilder) { - var list = new ObjectArrayList(); - if (args.size() > 2) return list; - - var name = args.size() >= 1 ? args.get(0) : ""; - var target = args.size() == 2 ? args.get(1) : ""; - - var onlinePlayers = Bukkit.getOnlinePlayers(); + parentBuilder.then( + Commands.literal(name()) + .requires(this::checkPermission) + .then( + Commands.argument("who", StringArgumentType.string()) + .suggests(this::suggestPlayer) + .then( + Commands.argument("id", StringArgumentType.greedyString()) + .suggests(this::suggestDisguise) + .executes(this::execute) + ) + ) + ); + } - if (args.size() == 1) //size == 1: 补全玩家 - { - for (var p : onlinePlayers) - if (p.getName().toLowerCase().contains(name.toLowerCase())) list.add(p.getName()); - } - else if (args.size() == 2) //size == 2: 补全拥有的伪装 + private CompletableFuture suggestDisguise(CommandContext context, SuggestionsBuilder suggestionsBuilder) + { + return CompletableFuture.supplyAsync(() -> { - var player = Bukkit.getPlayerExact(name); + var input = suggestionsBuilder.getRemainingLowerCase(); - if (player != null) + for (var p : MorphManager.getProviders()) { - var disguises = morphs.getAvaliableDisguisesFor(player); + if (p == MorphManager.fallbackProvider) continue; - for (var d : disguises) + var ns = p.getNameSpace(); + p.getAllAvailableDisguises().forEach(s -> { - if (d.getKey().toLowerCase().contains(target.toLowerCase())) - { - list.add(d.getKey()); - } - } + var str = ns + ":" + s; + if (str.toLowerCase().contains(input)) + suggestionsBuilder.suggest(str); + }); } - } - return list; + return suggestionsBuilder.build(); + }); } - @Resolved - private MorphManager morphs; - - @Override - public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] strings) + private CompletableFuture suggestPlayer(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - if (strings.length != 2) return false; + var online = Bukkit.getOnlinePlayers(); + + return CompletableFuture.supplyAsync(() -> + { + var input = suggestionsBuilder.getRemainingLowerCase(); - var who = Bukkit.getPlayerExact(strings[0]); - var targetName = strings[1]; + online.stream().forEach(player -> + { + var name = player.getName(); + if (name.toLowerCase().contains(input)) + suggestionsBuilder.suggest(name); + }); + + return suggestionsBuilder.build(); + }); + } + + private int execute(CommandContext context) + { + var who = Bukkit.getPlayerExact(StringArgumentType.getString(context, "who")); + var targetName = StringArgumentType.getString(context, "id"); + var commandSender = context.getSource().getSender(); if (who == null || !who.isOnline()) { commandSender.sendMessage(MessageUtils.prefixes(commandSender, CommonStrings.playerNotFoundString())); - return false; + return 1; } if (!targetName.contains(":")) @@ -110,6 +136,6 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull String[] commandSender.sendMessage(MessageUtils.prefixes(commandSender, msg)); - return true; + return 1; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/CommandBuilder.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/CommandBuilder.java deleted file mode 100644 index 0965052b..00000000 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/CommandBuilder.java +++ /dev/null @@ -1,9 +0,0 @@ -package xyz.nifeather.morph.commands.subcommands.plugin.skincache.cmdTree; - -public class CommandBuilder -{ - public static TreeCommand.TreeCommandBuilder builder() - { - return new TreeCommand.TreeCommandBuilder(); - } -} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/TreeCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/TreeCommand.java deleted file mode 100644 index f06e51fe..00000000 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/plugin/skincache/cmdTree/TreeCommand.java +++ /dev/null @@ -1,182 +0,0 @@ -package xyz.nifeather.morph.commands.subcommands.plugin.skincache.cmdTree; - -import com.google.common.collect.ImmutableList; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import xiamomc.pluginbase.Command.ISubCommand; -import xiamomc.pluginbase.Messages.FormattableMessage; -import xyz.nifeather.morph.MorphPlugin; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.function.BiFunction; -import java.util.function.Function; - -public class TreeCommand implements ISubCommand -{ - @NotNull - private final String cmdName; - - @Nullable - private String permRequirement; - - @Nullable - private Function, List> onTabComplete; - - @Nullable - private BiFunction, Boolean> executeFunction; - - @NotNull - private FormattableMessage helpDescription = new FormattableMessage(MorphPlugin.getInstance(), "Nil"); - - public TreeCommand(@NotNull String cmdName) - { - this.cmdName = cmdName; - } - - @Override - public @NotNull String getCommandName() - { - return cmdName; - } - - private static final List emptyList = ImmutableList.of(); - - @Override - public @Nullable List onTabComplete(List args, CommandSender source) - { - return (this.onTabComplete == null) ? emptyList : this.onTabComplete.apply(args); - - //return ISubCommand.super.onTabComplete(args, source); - } - - @Override - public @Nullable String getPermissionRequirement() - { - return this.permRequirement; - } - - @Override - public FormattableMessage getHelpMessage() - { - return this.helpDescription; - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { - return this.executeFunction == null - || this.executeFunction.apply(sender, Arrays.stream(args).toList()); - - //return ISubCommand.super.onCommand(sender, args); - } - - public static class TreeCommandBuilder - { - private static class BuildMeta - { - public String name; - public Function, List> onTabComplete; - public BiFunction, Boolean> executes; - public String perm; - public FormattableMessage helpMessage; - - public boolean isValid() - { - return name != null && !name.isBlank(); - } - - public TreeCommand toCmd() - { - if (!isValid()) - throw new IllegalStateException("Invalid Command Meta!"); - - var instance = new TreeCommand(name); - instance.onTabComplete = this.onTabComplete; - instance.executeFunction = this.executes; - instance.permRequirement = this.perm; - instance.helpDescription = (this.helpMessage == null) - ? new FormattableMessage(MorphPlugin.getInstance(), "Nil") - : this.helpMessage; - - return instance; - } - } - - @Nullable - private BuildMeta currentMeta; - - private final List metaList = new ObjectArrayList<>(); - - public TreeCommandBuilder startNew() - { - if (currentMeta != null) - metaList.add(currentMeta); - - currentMeta = new BuildMeta(); - - return this; - } - - public TreeCommandBuilder name(String name) - { - Objects.requireNonNull(currentMeta, "CurrentMeta is null!"); - - if (name == null || name.isBlank()) - throw new IllegalArgumentException("Command name may not be blank or null"); - - currentMeta.name = name; - return this; - } - - public TreeCommandBuilder onFilter(Function, List> func) - { - Objects.requireNonNull(currentMeta, "CurrentMeta is null!"); - - currentMeta.onTabComplete = func; - return this; - } - - public TreeCommandBuilder executes(BiFunction, Boolean> func) - { - Objects.requireNonNull(currentMeta, "CurrentMeta is null!"); - - currentMeta.executes = func; - return this; - } - - public TreeCommandBuilder permission(String perm) - { - Objects.requireNonNull(currentMeta, "CurrentMeta is null!"); - - currentMeta.perm = perm; - return this; - } - - public TreeCommandBuilder helpMessage(FormattableMessage msg) - { - Objects.requireNonNull(currentMeta, "CurrentMeta is null!"); - - currentMeta.helpMessage = msg; - return this; - } - - public List buildAll() - { - if (currentMeta != null) - { - metaList.add(currentMeta); - currentMeta = null; - } - - var list = new ObjectArrayList(); - - metaList.forEach(meta -> list.add(meta.toCmd())); - - return list; - } - } -} diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/request/AcceptSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/request/AcceptSubCommand.java index 9a217f51..28d83b21 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/request/AcceptSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/request/AcceptSubCommand.java @@ -1,80 +1,77 @@ package xyz.nifeather.morph.commands.subcommands.request; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.interfaces.IManageRequests; import xyz.nifeather.morph.messages.CommonStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class AcceptSubCommand extends MorphPluginObject implements ISubCommand +public class AcceptSubCommand extends MorphPluginObject implements IConvertibleBrigadier { + @Override + public FormattableMessage getHelpMessage() + { + return HelpStrings.requestAcceptDescription(); + } + @Resolved private IManageRequests requests; - @Override - public List onTabComplete(List args, CommandSender source) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - var list = new ObjectArrayList(); + var source = context.getSource().getSender(); - if (source instanceof Player player) - { - var reqs = requests.getAvailableRequestsFor(player); + if (!(source instanceof Player player)) + return CompletableFuture.completedFuture(suggestionsBuilder.build()); - reqs.forEach(r -> list.add(r.sourcePlayer.getName())); - } + var reqs = requests.getAvailableRequestsFor(player); - return list; + return CompletableFuture.supplyAsync(() -> + { + reqs.forEach(r -> suggestionsBuilder.suggest(r.sourcePlayer.getName())); + return suggestionsBuilder.build(); + }); } @Override - public String getCommandName() + public String name() { return "accept"; } - @Override - public String getPermissionRequirement() + public int executes(CommandContext context) { - return null; - } + var sender = context.getSource().getSender(); - @Override - public FormattableMessage getHelpMessage() - { - return HelpStrings.requestAcceptDescription(); - } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { if (!(sender instanceof Player sourcePlayer)) - return true; + return Command.SINGLE_SUCCESS; - if (args.length < 1) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotDefinedString())); - return true; - } + var playerName = StringArgumentType.getString(context, "who"); - var targetPlayer = Bukkit.getPlayerExact(args[0]); + var targetPlayer = Bukkit.getPlayerExact(playerName); if (targetPlayer == null) { sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotFoundString())); - return true; + return Command.SINGLE_SUCCESS; } requests.acceptRequest(sourcePlayer, targetPlayer); - return true; + + return Command.SINGLE_SUCCESS; } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/request/DenySubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/request/DenySubCommand.java index 718c0f92..a5833828 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/request/DenySubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/request/DenySubCommand.java @@ -1,51 +1,76 @@ package xyz.nifeather.morph.commands.subcommands.request; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.interfaces.IManageRequests; import xyz.nifeather.morph.messages.CommonStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class DenySubCommand extends MorphPluginObject implements ISubCommand +public class DenySubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Resolved private IManageRequests requests; - @Override - public List onTabComplete(List args, CommandSender source) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - var list = new ObjectArrayList(); + var source = context.getSource().getSender(); + + if (!(source instanceof Player player)) + return CompletableFuture.completedFuture(suggestionsBuilder.build()); + + var reqs = requests.getAvailableRequestsFor(player); - if (source instanceof Player player) + return CompletableFuture.supplyAsync(() -> { - var reqs = requests.getAvailableRequestsFor(player); + reqs.forEach(r -> suggestionsBuilder.suggest(r.sourcePlayer.getName())); + return suggestionsBuilder.build(); + }); + } + + public int executes(CommandContext context) + { + var sender = context.getSource().getSender(); + + if (!(sender instanceof Player sourcePlayer)) + return Command.SINGLE_SUCCESS; + + var targetPlayer = Bukkit.getPlayerExact(StringArgumentType.getString(context, "who")); - reqs.forEach(r -> list.add(r.sourcePlayer.getName())); + if (targetPlayer == null) + { + sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotFoundString())); + return Command.SINGLE_SUCCESS; } - return list; + requests.denyRequest(sourcePlayer, targetPlayer); + + return Command.SINGLE_SUCCESS; } @Override - public String getCommandName() + public String name() { return "deny"; } @Override - public String getPermissionRequirement() + public boolean checkPermission(CommandSourceStack cmdSourceStack) { - return null; + return true; } @Override @@ -53,29 +78,4 @@ public FormattableMessage getHelpMessage() { return HelpStrings.requestDenyDescription(); } - - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { - if (!(sender instanceof Player sourcePlayer)) - return true; - - if (args.length < 1) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotDefinedString())); - return true; - } - - var targetPlayer = Bukkit.getPlayerExact(args[0]); - - if (targetPlayer == null) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotFoundString())); - return true; - } - - requests.denyRequest(sourcePlayer, targetPlayer); - - return true; - } } diff --git a/src/main/java/xyz/nifeather/morph/commands/subcommands/request/SendSubCommand.java b/src/main/java/xyz/nifeather/morph/commands/subcommands/request/SendSubCommand.java index f6c95a05..46ca990f 100644 --- a/src/main/java/xyz/nifeather/morph/commands/subcommands/request/SendSubCommand.java +++ b/src/main/java/xyz/nifeather/morph/commands/subcommands/request/SendSubCommand.java @@ -1,24 +1,29 @@ package xyz.nifeather.morph.commands.subcommands.request; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import xiamomc.pluginbase.Annotations.Resolved; -import xiamomc.pluginbase.Command.ISubCommand; import xiamomc.pluginbase.Messages.FormattableMessage; import xyz.nifeather.morph.MorphManager; import xyz.nifeather.morph.MorphPluginObject; +import xyz.nifeather.morph.commands.brigadier.IConvertibleBrigadier; import xyz.nifeather.morph.interfaces.IManageRequests; import xyz.nifeather.morph.messages.CommonStrings; import xyz.nifeather.morph.messages.HelpStrings; import xyz.nifeather.morph.messages.MessageUtils; import xyz.nifeather.morph.messages.RequestStrings; +import xyz.nifeather.morph.misc.DisguiseTypes; -import java.util.List; +import java.util.concurrent.CompletableFuture; -public class SendSubCommand extends MorphPluginObject implements ISubCommand +public class SendSubCommand extends MorphPluginObject implements IConvertibleBrigadier { @Resolved private IManageRequests requests; @@ -26,74 +31,67 @@ public class SendSubCommand extends MorphPluginObject implements ISubCommand @Resolved private MorphManager morphs; - @Override - public List onTabComplete(List args, CommandSender source) + public @NotNull CompletableFuture suggests(CommandContext context, SuggestionsBuilder suggestionsBuilder) { - var list = new ObjectArrayList(); + var source = context.getSource().getSender(); - if (source instanceof Player player) - { - Bukkit.getOnlinePlayers().stream() - .filter(p -> !p.getUniqueId().equals(player.getUniqueId())) - .forEach(p -> list.add(p.getName())); - } + if (!(source instanceof Player player)) + return CompletableFuture.completedFuture(suggestionsBuilder.build()); - return list; - } + var currentOnline = Bukkit.getOnlinePlayers(); - @Override - public String getCommandName() - { - return "send"; - } + return CompletableFuture.supplyAsync(() -> + { + currentOnline.stream().filter(p -> !p.getUniqueId().equals(player.getUniqueId())) + .forEach(p -> suggestionsBuilder.suggest(p.getName())); - @Override - public String getPermissionRequirement() - { - return null; + return suggestionsBuilder.build(); + }); } - @Override - public FormattableMessage getHelpMessage() + public int executes(CommandContext context) { - return HelpStrings.requestSendDescription(); - } + var sender = context.getSource().getSender(); - @Override - public boolean onCommand(@NotNull CommandSender sender, @NotNull String[] args) - { if (!(sender instanceof Player sourcePlayer)) - return true; - - if (args.length < 1) - { - sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotDefinedString())); - return true; - } + return Command.SINGLE_SUCCESS; - var targetPlayer = Bukkit.getPlayerExact(args[0]); + var targetPlayer = Bukkit.getPlayerExact(StringArgumentType.getString(context, "who")); if (targetPlayer == null) { sender.sendMessage(MessageUtils.prefixes(sender, CommonStrings.playerNotFoundString())); - return true; + return Command.SINGLE_SUCCESS; } if (targetPlayer.getUniqueId().equals(sourcePlayer.getUniqueId())) { sourcePlayer.sendMessage(MessageUtils.prefixes(sender, RequestStrings.cantSendToSelfString())); - return true; + return Command.SINGLE_SUCCESS; } + var id = DisguiseTypes.PLAYER.toId(targetPlayer.getName()); if (morphs.getAvaliableDisguisesFor(sourcePlayer).stream() - .anyMatch(c -> c.isPlayerDisguise() && c.playerDisguiseTargetName.equals(args[0]))) + .anyMatch(c -> c.rawIdentifier.equals(id))) { sourcePlayer.sendMessage(MessageUtils.prefixes(sender, RequestStrings.alreadyHaveDisguiseString())); - return true; + return Command.SINGLE_SUCCESS; } requests.createRequest(sourcePlayer, targetPlayer); - return true; + return Command.SINGLE_SUCCESS; + } + + @Override + public String name() + { + return "send"; + } + + @Override + public FormattableMessage getHelpMessage() + { + return HelpStrings.requestSendDescription(); } } diff --git a/src/main/java/xyz/nifeather/morph/config/MorphConfigManager.java b/src/main/java/xyz/nifeather/morph/config/MorphConfigManager.java index eca2b46d..fb92fb29 100644 --- a/src/main/java/xyz/nifeather/morph/config/MorphConfigManager.java +++ b/src/main/java/xyz/nifeather/morph/config/MorphConfigManager.java @@ -154,6 +154,7 @@ private void ensureBindableListNotNull() bindableLists = new Object2ObjectOpenHashMap<>(); } + @SuppressWarnings("removal") @Override public void reload() { @@ -228,7 +229,6 @@ public void reload() if (configVersion < 15) { //skill item - //noinspection removal var oldSkillItem = get(String.class, ConfigOption.ACTION_ITEM); //noinspection removal