aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNassim Jahnke <[email protected]>2024-07-08 23:05:29 +0200
committerNassim Jahnke <[email protected]>2024-07-08 23:23:03 +0200
commit0ba70dc1ad377db00e2ae1b99bbd2bc50a83b3f0 (patch)
tree501cdc6217ba62c5c529b31256fd9159cf7cc031
parent70b0e844767131681400b3dbace06c2dea13f87c (diff)
downloadPaper-0ba70dc1ad377db00e2ae1b99bbd2bc50a83b3f0.tar.gz
Paper-0ba70dc1ad377db00e2ae1b99bbd2bc50a83b3f0.zip
Add builder-like registration for BasicCommandbasiccommand-builder
-rw-r--r--patches/api/0469-Brigadier-based-command-API.patch121
-rw-r--r--patches/server/0975-Brigadier-based-command-API.patch127
2 files changed, 233 insertions, 15 deletions
diff --git a/patches/api/0469-Brigadier-based-command-API.patch b/patches/api/0469-Brigadier-based-command-API.patch
index a47c1b82c5..1ccb383df1 100644
--- a/patches/api/0469-Brigadier-based-command-API.patch
+++ b/patches/api/0469-Brigadier-based-command-API.patch
@@ -502,16 +502,21 @@ index 0000000000000000000000000000000000000000..9df87708206e26167a2c4934deff7fc6
+}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/BasicCommand.java b/src/main/java/io/papermc/paper/command/brigadier/BasicCommand.java
new file mode 100644
-index 0000000000000000000000000000000000000000..0f6b921b4bcf983cf25188823f78a061eec5263d
+index 0000000000000000000000000000000000000000..2722a855f16d5f5c0104854dedadea3eb54b8bad
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/brigadier/BasicCommand.java
-@@ -0,0 +1,36 @@
+@@ -0,0 +1,121 @@
+package io.papermc.paper.command.brigadier;
+
++import io.papermc.paper.plugin.configuration.PluginMeta;
+import java.util.Collection;
+import java.util.Collections;
++import java.util.function.Consumer;
++import java.util.function.Predicate;
++import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
+
+/**
+ * Implementing this interface allows for easily creating "Bukkit-style" {@code String[] args} commands.
@@ -541,6 +546,86 @@ index 0000000000000000000000000000000000000000..0f6b921b4bcf983cf25188823f78a061
+ default @NotNull Collection<String> suggest(final @NotNull CommandSourceStack commandSourceStack, final @NotNull String[] args) {
+ return Collections.emptyList();
+ }
++
++ /**
++ * Registration builder for {@link BasicCommand} to be used in {@link Commands#register(Consumer)}.
++ * <p>
++ * The command handler and label always have to be specified, the rest will default to {@code null} or an empty collection.
++ * However, <b>it is highly recommended to add a root permission/requirement</b>, which is also used to limit the commands sent to players.
++ * <p>
++ * {@link PluginMeta} may be automatically infered via the registration context, such as during bootstrap,
++ * but will otherwise also have to be defined.
++ */
++ interface RegistrationBuilder {
++
++ /**
++ * Sets the owning plugin's meta. This is not required to be set during plugin bootstrap.
++ *
++ * @param pluginMeta the owning plugin's meta
++ * @return self
++ */
++ @NotNull RegistrationBuilder pluginMeta(@NotNull PluginMeta pluginMeta);
++
++ /**
++ * Sets the command label.
++ *
++ * @param label the label of the to-be-registered command
++ * @return self
++ */
++ @NotNull RegistrationBuilder label(@NotNull String label);
++
++ /**
++ * Sets the command handler.
++ *
++ * @param basicCommand the basic command instance to register
++ * @return self
++ */
++ @NotNull RegistrationBuilder commandHandler(@NotNull BasicCommand basicCommand);
++
++ /**
++ * Sets the root permission node. Null by default.
++ *
++ * @param permission the root permission node
++ * @see #requires(Predicate) for a more flexible permission predicate
++ * @return self
++ */
++ default @NotNull RegistrationBuilder permission(@Nullable String permission) {
++ return this.requires(permission == null ? s -> true : sender -> sender.hasPermission(permission));
++ }
++
++ /**
++ * Sets the root permission predicate. Is always true by default.
++ *
++ * @param requirement the root command permission predicate
++ * @see #permission(String) for a simple permission node
++ * @return self
++ */
++ @NotNull RegistrationBuilder requires(@NotNull Predicate<CommandSender> requirement);
++
++ /**
++ * Sets the help description for the root literal node. Null by default.
++ *
++ * @param description the help description for the root literal node
++ * @return self
++ */
++ @NotNull RegistrationBuilder description(@Nullable String description);
++
++ /**
++ * Sets the aliases to register the basic command under. Empty by default.
++ *
++ * @param aliases a collection of aliases to register the basic command under
++ * @return self
++ */
++ @NotNull RegistrationBuilder aliases(@NotNull String... aliases);
++
++ /**
++ * Sets the aliases to register the basic command under. Empty by default.
++ *
++ * @param aliases a collection of aliases to register the basic command under
++ * @return self
++ */
++ @NotNull RegistrationBuilder aliases(@NotNull Collection<String> aliases);
++ }
+}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/CommandRegistrationFlag.java b/src/main/java/io/papermc/paper/command/brigadier/CommandRegistrationFlag.java
new file mode 100644
@@ -620,10 +705,10 @@ index 0000000000000000000000000000000000000000..54288dbe7185b875a74184f002ee4de4
+}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/Commands.java b/src/main/java/io/papermc/paper/command/brigadier/Commands.java
new file mode 100644
-index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe02600465c
+index 0000000000000000000000000000000000000000..9260cf56e62859b1d5b181d10fd1b75f95e1578f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/brigadier/Commands.java
-@@ -0,0 +1,266 @@
+@@ -0,0 +1,292 @@
+package io.papermc.paper.command.brigadier;
+
+import com.mojang.brigadier.CommandDispatcher;
@@ -639,6 +724,7 @@ index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe0
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
++import java.util.function.Consumer;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
@@ -838,7 +924,9 @@ index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe0
+ * @param label the label of the to-be-registered command
+ * @param basicCommand the basic command instance to register
+ * @return successfully registered root command labels (including aliases and namespaced variants)
++ * @deprecated use {@link #register(Consumer)}, including its new permission field
+ */
++ @Deprecated(forRemoval = true)
+ default @Unmodifiable @NotNull Set<String> register(final @NotNull String label, final @NotNull BasicCommand basicCommand) {
+ return this.register(label, null, Collections.emptyList(), basicCommand);
+ }
@@ -850,7 +938,9 @@ index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe0
+ * @param description the help description for the root literal node
+ * @param basicCommand the basic command instance to register
+ * @return successfully registered root command labels (including aliases and namespaced variants)
++ * @deprecated use {@link #register(Consumer)}, including its new permission field
+ */
++ @Deprecated(forRemoval = true)
+ default @Unmodifiable @NotNull Set<String> register(final @NotNull String label, final @Nullable String description, final @NotNull BasicCommand basicCommand) {
+ return this.register(label, description, Collections.emptyList(), basicCommand);
+ }
@@ -862,7 +952,9 @@ index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe0
+ * @param aliases a collection of aliases to register the basic command under.
+ * @param basicCommand the basic command instance to register
+ * @return successfully registered root command labels (including aliases and namespaced variants)
++ * @deprecated use {@link #register(Consumer)}, including its new permission field
+ */
++ @Deprecated(forRemoval = true)
+ default @Unmodifiable @NotNull Set<String> register(final @NotNull String label, final @NotNull Collection<String> aliases, final @NotNull BasicCommand basicCommand) {
+ return this.register(label, null, aliases, basicCommand);
+ }
@@ -875,7 +967,9 @@ index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe0
+ * @param aliases a collection of aliases to register the basic command under.
+ * @param basicCommand the basic command instance to register
+ * @return successfully registered root command labels (including aliases and namespaced variants)
++ * @deprecated use {@link #register(Consumer)}, including its new permission field
+ */
++ @Deprecated(forRemoval = true)
+ @Unmodifiable @NotNull Set<String> register(@NotNull String label, @Nullable String description, @NotNull Collection<String> aliases, @NotNull BasicCommand basicCommand);
+
+ /**
@@ -887,8 +981,25 @@ index 0000000000000000000000000000000000000000..ce60b618de10da7638f5aefa974aebe0
+ * @param aliases a collection of aliases to register the basic command under.
+ * @param basicCommand the basic command instance to register
+ * @return successfully registered root command labels (including aliases and namespaced variants)
++ * @deprecated use {@link #register(Consumer)}, including its new permission field
++ */
++ @Deprecated(forRemoval = true)
++ default @Unmodifiable @NotNull Set<String> register(@NotNull PluginMeta pluginMeta, @NotNull String label, @Nullable String description, @NotNull Collection<String> aliases, @NotNull BasicCommand basicCommand) {
++ return this.register(registrationBuilder -> registrationBuilder.pluginMeta(pluginMeta)
++ .label(label)
++ .commandHandler(basicCommand)
++ .description(description)
++ .aliases(aliases));
++ }
++
++ /**
++ * Registers a command under the same logic as {@link Commands#register(PluginMeta, LiteralCommandNode, String, Collection)}
++ * but with {@link BasicCommand} and the builder parameters as a simplified handler interface.
++ *
++ * @param basicCommandRegistration the registration builder consumer
++ * @return successfully registered root command labels (including aliases and namespaced variants)
+ */
-+ @Unmodifiable @NotNull Set<String> register(@NotNull PluginMeta pluginMeta, @NotNull String label, @Nullable String description, @NotNull Collection<String> aliases, @NotNull BasicCommand basicCommand);
++ @Unmodifiable @NotNull Set<String> register(@NotNull Consumer<BasicCommand.RegistrationBuilder> basicCommandRegistration);
+}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializer.java b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializer.java
new file mode 100644
diff --git a/patches/server/0975-Brigadier-based-command-API.patch b/patches/server/0975-Brigadier-based-command-API.patch
index 71f121c880..5f16c419c6 100644
--- a/patches/server/0975-Brigadier-based-command-API.patch
+++ b/patches/server/0975-Brigadier-based-command-API.patch
@@ -510,6 +510,99 @@ index 0000000000000000000000000000000000000000..23525592d880f340745a28c956fa38d3
+ }
+
+}
+diff --git a/src/main/java/io/papermc/paper/command/brigadier/BasicCommandRegistration.java b/src/main/java/io/papermc/paper/command/brigadier/BasicCommandRegistration.java
+new file mode 100644
+index 0000000000000000000000000000000000000000..9a07b3da38df6d38ed31360ab70565365e7f4076
+--- /dev/null
++++ b/src/main/java/io/papermc/paper/command/brigadier/BasicCommandRegistration.java
+@@ -0,0 +1,87 @@
++package io.papermc.paper.command.brigadier;
++
++import io.papermc.paper.plugin.configuration.PluginMeta;
++import java.util.Collection;
++import java.util.Collections;
++import java.util.List;
++import java.util.Objects;
++import java.util.function.Predicate;
++import org.bukkit.command.CommandSender;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++
++public final class BasicCommandRegistration implements BasicCommand.RegistrationBuilder {
++
++ private Collection<String> aliases = Collections.emptyList();
++ private PluginMeta pluginMeta;
++ private String label;
++ private Predicate<CommandSender> requirement;
++ private String description;
++ private BasicCommand commandHandler;
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder pluginMeta(@NotNull final PluginMeta pluginMeta) {
++ this.pluginMeta = pluginMeta;
++ return this;
++ }
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder label(@NotNull final String label) {
++ this.label = Objects.requireNonNull(label);
++ return this;
++ }
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder description(@Nullable final String description) {
++ this.description = description;
++ return this;
++ }
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder aliases(final @NotNull String... aliases) {
++ this.aliases = List.of(aliases);
++ return this;
++ }
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder aliases(@NotNull final Collection<String> aliases) {
++ this.aliases = Collections.unmodifiableCollection(aliases);
++ return this;
++ }
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder commandHandler(@NotNull final BasicCommand basicCommand) {
++ this.commandHandler = Objects.requireNonNull(basicCommand);
++ return this;
++ }
++
++ @Override
++ public BasicCommand.@NotNull RegistrationBuilder requires(@NotNull final Predicate<CommandSender> requirement) {
++ this.requirement = Objects.requireNonNull(requirement);
++ return this;
++ }
++
++ public @Nullable PluginMeta pluginMeta() {
++ return this.pluginMeta;
++ }
++
++ public @NotNull String label() {
++ return Objects.requireNonNull(this.label, "Label missing in registration");
++ }
++
++ public @NotNull Predicate<CommandSender> requirement() {
++ return this.requirement;
++ }
++
++ public @Nullable String description() {
++ return this.description;
++ }
++
++ public @NotNull Collection<String> aliases() {
++ return this.aliases;
++ }
++
++ public @NotNull BasicCommand commandHandler() {
++ return Objects.requireNonNull(this.commandHandler, "BasicCommand handler missing in registration");
++ }
++}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerImpl.java b/src/main/java/io/papermc/paper/command/brigadier/MessageComponentSerializerImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b33c6cf2366568641e6f2fd7f74fb74f6ea0145
@@ -686,10 +779,10 @@ index 0000000000000000000000000000000000000000..1b1642f306771f029e6214a2e2ebebb6
+}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java b/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java
new file mode 100644
-index 0000000000000000000000000000000000000000..27509813a90980be1dfc7bde27d0eba60adfc820
+index 0000000000000000000000000000000000000000..9893c6409613471251cf2b2064f1e1e5068b3cc4
--- /dev/null
+++ b/src/main/java/io/papermc/paper/command/brigadier/PaperCommands.java
-@@ -0,0 +1,193 @@
+@@ -0,0 +1,207 @@
+package io.papermc.paper.command.brigadier;
+
+import com.google.common.base.Preconditions;
@@ -709,6 +802,7 @@ index 0000000000000000000000000000000000000000..27509813a90980be1dfc7bde27d0eba6
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
++import java.util.function.Consumer;
+import net.minecraft.commands.CommandBuildContext;
+import org.apache.commons.lang3.StringUtils;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@@ -854,33 +948,46 @@ index 0000000000000000000000000000000000000000..27509813a90980be1dfc7bde27d0eba6
+
+ @Override
+ public @Unmodifiable Set<String> register(final String label, final @Nullable String description, final Collection<String> aliases, final BasicCommand basicCommand) {
-+ return this.register(requireNonNull(this.currentContext, "No lifecycle owner context is set").getPluginMeta(), label, description, aliases, basicCommand);
++ return this.register(
++ requireNonNull(this.currentContext, "No lifecycle owner context is set").getPluginMeta(),
++ label,
++ description,
++ aliases,
++ basicCommand
++ );
+ }
+
+ @Override
-+ public @Unmodifiable Set<String> register(final PluginMeta pluginMeta, final String label, final @Nullable String description, final Collection<String> aliases, final BasicCommand basicCommand) {
-+ final LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal(label)
++ public @Unmodifiable @NotNull Set<String> register(@NotNull final Consumer<BasicCommand.RegistrationBuilder> registrationConsumer) {
++ final BasicCommandRegistration registration = new BasicCommandRegistration();
++ registrationConsumer.accept(registration);
++ final LiteralArgumentBuilder<CommandSourceStack> builder = Commands.literal(registration.label())
++ .requires(stack -> registration.requirement().test(stack.getSender()))
+ .then(
+ Commands.argument("args", StringArgumentType.greedyString())
+ .suggests((context, suggestionsBuilder) -> {
+ final String[] args = StringUtils.split(suggestionsBuilder.getRemaining());
-+ final SuggestionsBuilder offsetSuggestionsBuilder = suggestionsBuilder.createOffset(suggestionsBuilder.getInput().lastIndexOf(' ') + 1);;
++ final SuggestionsBuilder offsetSuggestionsBuilder = suggestionsBuilder.createOffset(suggestionsBuilder.getInput().lastIndexOf(' ') + 1);
+
-+ final Collection<String> suggestions = basicCommand.suggest(context.getSource(), args);
++ final Collection<String> suggestions = registration.commandHandler().suggest(context.getSource(), args);
+ suggestions.forEach(offsetSuggestionsBuilder::suggest);
+ return offsetSuggestionsBuilder.buildFuture();
+ })
+ .executes((stack) -> {
-+ basicCommand.execute(stack.getSource(), StringUtils.split(stack.getArgument("args", String.class), ' '));
++ registration.commandHandler().execute(stack.getSource(), StringUtils.split(stack.getArgument("args", String.class), ' '));
+ return com.mojang.brigadier.Command.SINGLE_SUCCESS;
+ })
+ )
+ .executes((stack) -> {
-+ basicCommand.execute(stack.getSource(), new String[0]);
++ registration.commandHandler().execute(stack.getSource(), new String[0]);
+ return com.mojang.brigadier.Command.SINGLE_SUCCESS;
+ });
+
-+ return this.register(pluginMeta, builder.build(), description, aliases);
++ PluginMeta pluginMeta = registration.pluginMeta();
++ if (pluginMeta == null) {
++ pluginMeta = requireNonNull(this.currentContext, "No lifecycle owner context is set").getPluginMeta();
++ }
++ return this.register(pluginMeta, builder.build(), registration.description(), registration.aliases());
+ }
+}
diff --git a/src/main/java/io/papermc/paper/command/brigadier/PluginCommandNode.java b/src/main/java/io/papermc/paper/command/brigadier/PluginCommandNode.java