Mostly javadoc, and also some fixes there and there
This commit is contained in:
@@ -6,91 +6,111 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.context.ParsedCommandNode;
|
||||
import com.mojang.brigadier.context.StringRange;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import fr.pandacube.lib.reflect.Reflect;
|
||||
import fr.pandacube.lib.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Abstract class that holds the logic of a specific command to be integrated in a Brigadier command dispatcher.
|
||||
* Subclasses may use any mechanism to integrate this command in the environment’s Brigadier instance, during the
|
||||
* instantiation of this object.
|
||||
* Subclasses may use any mechanism to integrate this command in the environment’s Brigadier instance (or in a
|
||||
* {@link BrigadierDispatcher} instance), during the instantiation of this object.
|
||||
* @param <S> the command source (or command sender) type.
|
||||
*/
|
||||
public abstract class BrigadierCommand<S> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a builder for this command.
|
||||
* Concrete class should include any element in the builder that is needed to build the command (sub-commands and
|
||||
* arguments, requirements, redirection, ...).
|
||||
* If any of the sub-commands and arguments needs to know the {@link LiteralCommandNode} builded from the returned
|
||||
* {@link LiteralArgumentBuilder}, this can be done by overriding {@link #postBuildCommand(LiteralCommandNode)}.
|
||||
* @return a builder for this command.
|
||||
*/
|
||||
protected abstract LiteralArgumentBuilder<S> buildCommand();
|
||||
|
||||
/**
|
||||
* Method to implement if the reference to the command node has to be known when building the subcommands.
|
||||
* Method to override if the reference to the command node has to be known when building the subcommands.
|
||||
* @param commandNode the command node builded from {@link #buildCommand()}.
|
||||
*/
|
||||
protected void postBuildCommand(LiteralCommandNode<S> commandNode) {
|
||||
// default implementation does nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to override if this command have any aliases.
|
||||
* @return an array of string corresponding to the aliases. This must not include the orignal command name (that
|
||||
* is the name of the literal command node builded from {@link #buildCommand()}).
|
||||
*/
|
||||
protected String[] getAliases() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link LiteralArgumentBuilder} that has the provided name.
|
||||
* @param name the name of the command node.
|
||||
* @return a new {@link LiteralArgumentBuilder} that has the provided name.
|
||||
*/
|
||||
public LiteralArgumentBuilder<S> literal(String name) {
|
||||
return LiteralArgumentBuilder.literal(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link RequiredArgumentBuilder} that has the provided name.
|
||||
* @param name the name of the command node.
|
||||
* @param type the type of the argument.
|
||||
* @param <T> the argument type.
|
||||
* @return a new {@link RequiredArgumentBuilder} that has the provided name.
|
||||
*/
|
||||
public <T> RequiredArgumentBuilder<S, T> argument(String name, ArgumentType<T> type) {
|
||||
return RequiredArgumentBuilder.argument(name, type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tells if the provided command sender is a player.
|
||||
* @param sender the sender to test if it’s a player or not.
|
||||
* @return true if the sender is a player, false otherwise.
|
||||
*/
|
||||
public abstract boolean isPlayer(S sender);
|
||||
|
||||
/**
|
||||
* Tells if the provided command sender is the console.
|
||||
* @param sender the sender to test if it’s the console or not.
|
||||
* @return true if the sender is the console, false otherwise.
|
||||
*/
|
||||
public abstract boolean isConsole(S sender);
|
||||
|
||||
/**
|
||||
* Provides a {@link Predicate} that tests if the command sender is a player.
|
||||
* @return a {@link Predicate} that tests if the command sender is a player.
|
||||
* @see #isPlayer(Object)
|
||||
*/
|
||||
public Predicate<S> isPlayer() {
|
||||
return this::isPlayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a {@link Predicate} that tests if the command sender is the console.
|
||||
* @return a {@link Predicate} that tests if the command sender is the console.
|
||||
* @see #isConsole(Object)
|
||||
*/
|
||||
public Predicate<S> isConsole() {
|
||||
return this::isConsole;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a {@link Predicate} that tests if the command sender has the provided permission.
|
||||
* @param permission the permission tested by the returned predicate on the command sender.
|
||||
* @return a {@link Predicate} that tests if the command sender has the provided permission.
|
||||
*/
|
||||
public abstract Predicate<S> hasPermission(String permission);
|
||||
|
||||
|
||||
@@ -99,8 +119,15 @@ public abstract class BrigadierCommand<S> {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determines if the literal node is found in the command.
|
||||
* <p>
|
||||
* <b>Be aware that this method search even beyond any fork or redirection, so it may encounter literal nodes that
|
||||
* have the provided name but belong to other commands, so it can produce a false positive.</b>
|
||||
* @param context the context of the command execution.
|
||||
* @param literal the literal command node to search for in the typed command.
|
||||
* @return true if the provided literal is in the typed command, false otherwise.
|
||||
*/
|
||||
public static boolean isLiteralParsed(CommandContext<?> context, String literal) {
|
||||
for (ParsedCommandNode<?> node : context.getNodes()) {
|
||||
if (node.getNode() instanceof LiteralCommandNode<?> lNode
|
||||
@@ -111,24 +138,60 @@ public abstract class BrigadierCommand<S> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the argument value from the provided context, silently returning null (instead of throwing an exception)
|
||||
* if the argument is not found.
|
||||
* @param context the context of the command execution.
|
||||
* @param argument the argument to search for.
|
||||
* @param type the type of the argument.
|
||||
* @param <T> the argument type.
|
||||
* @return the value of the argument, or null if not found.
|
||||
*/
|
||||
public static <T> T tryGetArgument(CommandContext<?> context, String argument, Class<T> type) {
|
||||
return tryGetArgument(context, argument, type, Function.identity(), null);
|
||||
}
|
||||
|
||||
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound) {
|
||||
return tryGetArgument(context, argument, sourceType, transformIfFound, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument value from the provided context, silently returning a default value (instead of throwing an
|
||||
* exception) if the argument is not found.
|
||||
* @param context the context of the command execution.
|
||||
* @param argument the argument to search for.
|
||||
* @param type the type of the argument.
|
||||
* @param deflt the default value if not found.
|
||||
* @param <T> the argument type.
|
||||
* @return the value of the argument, or {@code deflt} if not found.
|
||||
*/
|
||||
public static <T> T tryGetArgument(CommandContext<?> context, String argument, Class<T> type, T deflt) {
|
||||
return tryGetArgument(context, argument, type, Function.identity(), deflt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument value from the provided context and transform it using the provided function, or silently
|
||||
* returning null (instead of throwing an exception) if the argument is not found.
|
||||
* @param context the context of the command execution.
|
||||
* @param argument the argument to search for.
|
||||
* @param sourceType the type of the argument in the command context.
|
||||
* @param transformIfFound the function to transform the argument value before returning.
|
||||
* @param <ST> the argument type in the command context.
|
||||
* @param <T> the returned type.
|
||||
* @return the value of the argument, transformed by {@code transformIfFound}, or null if not found.
|
||||
*/
|
||||
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound) {
|
||||
return tryGetArgument(context, argument, sourceType, transformIfFound, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the argument value from the provided context and transform it using the provided function, or silently
|
||||
* returning a default value (instead of throwing an exception) if the argument is not found.
|
||||
* @param context the context of the command execution.
|
||||
* @param argument the argument to search for.
|
||||
* @param sourceType the type of the argument in the command context.
|
||||
* @param transformIfFound the function to transform the argument value before returning.
|
||||
* @param deflt the default value if not found.
|
||||
* @param <ST> the argument type in the command context.
|
||||
* @param <T> the returned type.
|
||||
* @return the value of the argument, transformed by {@code transformIfFound}, or {@code deflt} if not found.
|
||||
*/
|
||||
public static <ST, T> T tryGetArgument(CommandContext<?> context, String argument, Class<ST> sourceType, Function<ST, T> transformIfFound, T deflt) {
|
||||
ST sourceValue;
|
||||
try {
|
||||
@@ -140,25 +203,25 @@ public abstract class BrigadierCommand<S> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link CommandSyntaxException} with the provided message.
|
||||
* @param message the exception message.
|
||||
* @return a new instance of {@link CommandSyntaxException} with the provided message.
|
||||
*/
|
||||
public static CommandSyntaxException newCommandException(String message) {
|
||||
return new SimpleCommandExceptionType(new LiteralMessage(message)).create();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Wraps the provided {@link SuggestionsSupplier} into a Brigadier’s {@link SuggestionProvider}.
|
||||
* @param suggestions the suggestions to wrap.
|
||||
* @param senderUnwrapper function to convert the command sender provided by brigadier into the command sender
|
||||
* supported by {@link SuggestionsSupplier}.
|
||||
* @return a {@link SuggestionProvider} generating the suggestions from the provided {@link SuggestionsSupplier}.
|
||||
* @param <AS> the type of command sender supported by the {@link SuggestionsSupplier}.
|
||||
*/
|
||||
protected <AS> SuggestionProvider<S> wrapSuggestions(SuggestionsSupplier<AS> suggestions, Function<S, AS> senderUnwrapper) {
|
||||
return (context, builder) -> {
|
||||
AS sender = senderUnwrapper.apply(context.getSource());
|
||||
|
@@ -11,28 +11,41 @@ import net.kyori.adventure.text.ComponentLike;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Abstract class that holds a Brigadier {@link CommandDispatcher} instance.
|
||||
* Subclasses contains logic to integrate this commands dispatcher into their environment (like Bungee or CLI app).
|
||||
* @param <S> the command source (or command sender) type.
|
||||
*/
|
||||
public abstract class BrigadierDispatcher<S> {
|
||||
|
||||
|
||||
private final CommandDispatcher<S> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Registers the provided command node into this dispatcher.
|
||||
* @param node the node to register.
|
||||
*/
|
||||
public void register(LiteralCommandNode<S> node) {
|
||||
dispatcher.getRoot().addChild(node);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Brigadier dispatcher.
|
||||
* @return the Brigadier dispatcher.
|
||||
*/
|
||||
public CommandDispatcher<S> getDispatcher() {
|
||||
return dispatcher;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the provided command as the provided sender.
|
||||
* @param sender the command sender.
|
||||
* @param commandWithoutSlash the command, without the eventual slash at the begining.
|
||||
* @return the value returned by the executed command.
|
||||
*/
|
||||
public int execute(S sender, String commandWithoutSlash) {
|
||||
ParseResults<S> parsed = dispatcher.parse(commandWithoutSlash, sender);
|
||||
|
||||
@@ -46,11 +59,15 @@ public abstract class BrigadierDispatcher<S> {
|
||||
Log.severe(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the suggestions for the currenlty being typed command.
|
||||
* @param sender the command sender.
|
||||
* @param buffer the command that is being typed.
|
||||
* @return the suggestions for the currenlty being typed command.
|
||||
*/
|
||||
public Suggestions getSuggestions(S sender, String buffer) {
|
||||
ParseResults<S> parsed = dispatcher.parse(buffer, sender);
|
||||
try {
|
||||
@@ -64,10 +81,11 @@ public abstract class BrigadierDispatcher<S> {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sends the provided message to the sender.
|
||||
* @param sender the sender to send the message to.
|
||||
* @param message the message to send.
|
||||
*/
|
||||
protected abstract void sendSenderMessage(S sender, ComponentLike message);
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,6 @@
|
||||
package fr.pandacube.lib.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.ParseResults;
|
||||
import com.mojang.brigadier.context.CommandContextBuilder;
|
||||
import com.mojang.brigadier.context.StringRange;
|
||||
@@ -22,7 +23,16 @@ import java.util.concurrent.CompletableFuture;
|
||||
public class BrigadierSuggestionsUtil {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets suggestions with the provided parsed command.
|
||||
* <p>
|
||||
* This is a reimplementation of {@link CommandDispatcher#getCompletionSuggestions(ParseResults, int)} that
|
||||
* keeps the original ordering of the suggestions.
|
||||
* @param parsed the parsed command.
|
||||
* @return the suggestions.
|
||||
* @param <S> the sender type.
|
||||
* @see CommandDispatcher#getCompletionSuggestions(ParseResults, int)
|
||||
*/
|
||||
public static <S> CompletableFuture<Suggestions> buildSuggestionBrigadier(ParseResults<S> parsed) {
|
||||
int cursor = parsed.getReader().getTotalLength();
|
||||
final CommandContextBuilder<S> context = parsed.getContext();
|
||||
@@ -55,7 +65,17 @@ public class BrigadierSuggestionsUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
// inspired from com.mojang.brigadier.suggestion.Suggestions#merge, but without the sorting part
|
||||
|
||||
/**
|
||||
* Merges the provided {@link Suggestions}.
|
||||
* <p>
|
||||
* This is a reimplementation of {@link Suggestions#merge(String, Collection)} that keeps the original ordering of
|
||||
* the suggestions.
|
||||
* @param input the command on which are based the suggestions.
|
||||
* @param suggestions the {@link Suggestions} to merge.
|
||||
* @return a {@link Suggestions}.
|
||||
* @see Suggestions#create(String, Collection)
|
||||
*/
|
||||
public static Suggestions mergeSuggestionsOriginalOrdering(String input, Collection<Suggestions> suggestions) {
|
||||
if (suggestions.isEmpty()) {
|
||||
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
||||
@@ -72,8 +92,16 @@ public class BrigadierSuggestionsUtil {
|
||||
|
||||
|
||||
|
||||
|
||||
// inspired from com.mojang.brigadier.suggestion.Suggestions#create, but without the sorting part
|
||||
/**
|
||||
* Creates a {@link Suggestions} from the provided Collection of {@link Suggestion}.
|
||||
* <p>
|
||||
* This is a reimplementation of {@link Suggestions#create(String, Collection)} that keeps the original ordering of
|
||||
* the suggestions.
|
||||
* @param command the command on which are based the suggestions.
|
||||
* @param suggestions the Collection of {@link Suggestion}.
|
||||
* @return a {@link Suggestions}.
|
||||
* @see Suggestions#create(String, Collection)
|
||||
*/
|
||||
public static Suggestions createSuggestionsOriginalOrdering(String command, Collection<Suggestion> suggestions) {
|
||||
if (suggestions.isEmpty()) {
|
||||
return new Suggestions(StringRange.at(0), new ArrayList<>(0));
|
||||
@@ -96,7 +124,7 @@ public class BrigadierSuggestionsUtil {
|
||||
|
||||
|
||||
|
||||
public static CompletableFuture<Suggestions> completableFutureSuggestionsKeepsOriginalOrdering(SuggestionsBuilder builder) {
|
||||
/* package */ static CompletableFuture<Suggestions> completableFutureSuggestionsKeepsOriginalOrdering(SuggestionsBuilder builder) {
|
||||
return CompletableFuture.completedFuture(
|
||||
createSuggestionsOriginalOrdering(builder.getInput(), getSuggestionsFromSuggestionsBuilder(builder))
|
||||
);
|
||||
|
Reference in New Issue
Block a user