From d399788b9fb627376ccd6d8494b6e260db9d59d0 Mon Sep 17 00:00:00 2001 From: William Date: Tue, 18 Jun 2024 23:45:41 +0100 Subject: [PATCH] refactor: change approach with <1.20.6 Paper commands Fixes issues with custom arg types on Paper --- .../src/main/resources/paper-plugin.yml | 4 +- gradle.properties | 2 +- .../uniform/paper/LegacyPaperCommand.java | 114 +++++++++++------- .../uniform/paper/LegacyPaperCommandUser.java | 19 ++- .../uniform/paper/PaperUniform.java | 29 +++-- 5 files changed, 97 insertions(+), 71 deletions(-) diff --git a/example-plugin/src/main/resources/paper-plugin.yml b/example-plugin/src/main/resources/paper-plugin.yml index bf8e80c..ffabb56 100644 --- a/example-plugin/src/main/resources/paper-plugin.yml +++ b/example-plugin/src/main/resources/paper-plugin.yml @@ -1,4 +1,4 @@ name: UniformExample -version: 1.0 -api-version: "1.19" +version: "1.0" +api-version: "1.20" main: net.william278.uniform.UniformExample \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index cedcc50..eb2e130 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,6 @@ javaVersion=17 org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.daemon=true -library_version=1.1.4 +library_version=1.1.5 library_archive=uniform library_description=Cross-platform wrapper for making Brigadier commands, based on BrigadierWrapper by Tofaa2, itself inspired by emortalmcs command system. \ No newline at end of file diff --git a/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommand.java b/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommand.java index 07e1387..6b31e00 100644 --- a/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommand.java +++ b/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommand.java @@ -21,43 +21,96 @@ package net.william278.uniform.paper; -import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; -import com.destroystokyo.paper.event.brigadier.CommandRegisteredEvent; -import com.google.common.collect.Sets; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.tree.LiteralCommandNode; -import lombok.AllArgsConstructor; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestion; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.william278.uniform.BaseCommand; import net.william278.uniform.Command; import net.william278.uniform.CommandUser; import net.william278.uniform.Uniform; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.command.CommandException; +import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import java.util.List; -import java.util.Locale; -import java.util.Set; import java.util.function.Function; -@SuppressWarnings({"removal", "deprecation", "UnstableApiUsage"}) -public class LegacyPaperCommand extends BaseCommand { +@SuppressWarnings("unused") +public class LegacyPaperCommand extends BaseCommand { static final Function USER_SUPPLIER = (user) -> new LegacyPaperCommandUser( - (BukkitBrigadierCommandSource) user + (CommandSender) user ); public LegacyPaperCommand(@NotNull Command command) { super(command); } + public LegacyPaperCommand(@NotNull String name, @NotNull String description, @NotNull List aliases) { + super(name, description, aliases); + } + public LegacyPaperCommand(@NotNull String name, @NotNull List aliases) { super(name, aliases); } - public LegacyPaperCommand(@NotNull String name, @NotNull String description, @NotNull List aliases) { - super(name, description, aliases); + @NotNull + Impl getImpl(@NotNull Uniform uniform) { + return new Impl(uniform, this); + } + + static final class Impl extends org.bukkit.command.Command { + + private static final int COMMAND_SUCCESS = com.mojang.brigadier.Command.SINGLE_SUCCESS; + + private final CommandDispatcher dispatcher = new CommandDispatcher<>(); + + public Impl(@NotNull Uniform uniform, @NotNull LegacyPaperCommand command) { + super(command.getName()); + this.dispatcher.register(command.createBuilder()); + this.setDescription(command.getDescription()); + this.setAliases(command.getAliases()); + } + + @SuppressWarnings("deprecation") + @Override + public boolean execute(@NotNull CommandSender commandSender, @NotNull String alias, @NotNull String[] args) { + try { + return dispatcher.execute(getInput(args), commandSender) == COMMAND_SUCCESS; + } catch (CommandSyntaxException e) { + commandSender.sendMessage(Component + .translatable("command.context.parse_error", NamedTextColor.RED) + .args( + Component.text(e.getRawMessage().getString()), + Component.text(e.getCursor()), + Component.text(e.getContext()) + )); + return false; + } catch (CommandException e) { + commandSender.sendMessage(Component.text(e.getMessage(), NamedTextColor.RED)); + return false; + } + } + + @NotNull + @Override + public List tabComplete(@NotNull CommandSender sender, @NotNull String alias, @NotNull String[] args) + throws IllegalArgumentException { + final String passed = getInput(args); + return dispatcher.getCompletionSuggestions( + dispatcher.parse(passed, sender), + passed.length() // Spigot API limitation - we can only TAB complete the full text length :( + ) + .thenApply(suggestions -> suggestions.getList().stream().map(Suggestion::getText).toList()) + .join(); + } + + @NotNull + private String getInput(@NotNull String[] args) { + return args.length == 0 ? getName() : "%s %s".formatted(getName(), String.join(" ", args)); + } } @Override @@ -70,33 +123,4 @@ public class LegacyPaperCommand extends BaseCommand commands; - - @EventHandler - public void commandRegisterEvent(CommandRegisteredEvent event) { - commands.forEach(command -> { - // Register root command - final LiteralCommandNode built = command.build(); - event.getRoot().addChild(built); - - // Register aliases - final String namespace = plugin.getName().toLowerCase(Locale.ENGLISH).replaceAll("[^a-z0-9_-]", ""); - final Set aliases = Sets.newHashSet(command.getAliases()); - command.getAliases().forEach(a -> aliases.add(namespace + ":" + a)); - aliases.add(namespace + ":" + command.getName()); - aliases.forEach(alias -> event.getRoot().addChild( - LiteralArgumentBuilder.literal(alias) - .requires(built.getRequirement()).executes(built.getCommand()).redirect(built) - .build() - )); - }); - commands.clear(); - } - } - } diff --git a/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java b/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java index c0082f4..3ebe5f8 100644 --- a/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java +++ b/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java @@ -21,44 +21,43 @@ package net.william278.uniform.paper; -import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; import net.kyori.adventure.audience.Audience; import net.william278.uniform.CommandUser; import net.william278.uniform.Permission; +import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.UUID; -@SuppressWarnings("removal") -public record LegacyPaperCommandUser(@NotNull BukkitBrigadierCommandSource source) implements CommandUser { +public record LegacyPaperCommandUser(@NotNull CommandSender sender) implements CommandUser { @Override @NotNull public Audience getAudience() { - return source.getBukkitSender(); + return sender; } @Override - @Nullable public String getName() { - return source.getBukkitEntity() != null ? source.getBukkitEntity().getName() : null; + return sender.getName(); } @Override @Nullable public UUID getUuid() { - return source.getBukkitEntity() != null ? source.getBukkitEntity().getUniqueId() : null; + return sender instanceof Player player ? player.getUniqueId() : null; } @Override public boolean checkPermission(@NotNull Permission permission) { - if (source.getBukkitSender().isPermissionSet(permission.node())) { - return source.getBukkitSender().hasPermission(permission.node()); + if (sender.isPermissionSet(permission.node())) { + return sender.hasPermission(permission.node()); } return permission.defaultValue().check( - source.getBukkitSender().isOp() || source.getBukkitSender() instanceof ConsoleCommandSender + sender.isOp() || sender instanceof ConsoleCommandSender ); } diff --git a/paper/src/main/java/net/william278/uniform/paper/PaperUniform.java b/paper/src/main/java/net/william278/uniform/paper/PaperUniform.java index d680bfe..8d7fd26 100644 --- a/paper/src/main/java/net/william278/uniform/paper/PaperUniform.java +++ b/paper/src/main/java/net/william278/uniform/paper/PaperUniform.java @@ -32,8 +32,10 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; import java.util.Arrays; +import java.util.Locale; import java.util.Set; import java.util.function.Function; +import java.util.stream.Stream; /** * A class for registering commands with the Paper server's command manager @@ -44,27 +46,23 @@ public final class PaperUniform implements Uniform { static PaperUniform INSTANCE; - private final Set legacyCommands = Sets.newHashSet(); private final Set commands = Sets.newHashSet(); private final boolean useModernApi = isUseModernApi(); + private final JavaPlugin plugin; @Getter @Setter Function commandUserSupplier; private PaperUniform(@NotNull JavaPlugin plugin) { + this.plugin = plugin; // Modern (1.20.6+) Lifecycle event based Paper Brigadier API if (useModernApi) { this.commandUserSupplier = PaperCommand.USER_SUPPLIER; PaperCommand.register(plugin, commands); return; } - - // Legacy (1.17-1.20.4) event-based Paper Brigadier API this.commandUserSupplier = LegacyPaperCommand.USER_SUPPLIER; - plugin.getServer().getPluginManager().registerEvents( - new LegacyPaperCommand.Registrar(plugin, legacyCommands), plugin - ); } /** @@ -100,13 +98,18 @@ public final class PaperUniform implements Uniform { @SafeVarargs @Override public final > void register(T... commands) { - Arrays.stream(commands).forEach(c -> { - if (useModernApi) { - this.commands.add((PaperCommand) c); - } else { - this.legacyCommands.add((LegacyPaperCommand) c); - } - }); + // Mark as to be registered with modern API + final Stream s = Arrays.stream(commands); + if (useModernApi) { + s.forEach(c -> this.commands.add((PaperCommand) c)); + return; + } + + // Register with the legacy API + plugin.getServer().getCommandMap().registerAll( + plugin.getName().toLowerCase(Locale.ENGLISH).replaceAll("[^a-z0-9_]", ""), + s.map(c -> (LegacyPaperCommand) c).map(c -> (org.bukkit.command.Command) c.getImpl(this)).toList() + ); } /**