Integrate SubcommandData with CoreCommandBuilder and document it

Also made the sender type nicer in the error message
This commit is contained in:
Norbi Peti 2022-10-29 22:29:01 +02:00
parent b59a090e13
commit 8f20ca9b5a
4 changed files with 79 additions and 16 deletions

View file

@ -224,13 +224,24 @@ public abstract class Command2<TC extends ICommand2<TP>, TP extends Command2Send
&& cg.getClass() == sendertype) //The command expects a user of our system
params.add(cg);
else {
sender.sendMessage("§cYou need to be a " + sendertype.getSimpleName() + " to use this command.");
String type = sendertype.getSimpleName().chars().mapToObj(ch -> Character.isUpperCase(ch)
? " " + Character.toLowerCase(ch)
: ch + "").collect(Collectors.joining());
sender.sendMessage("§cYou need to be a " + type + " to use this command.");
sender.sendMessage(sd.getHelpText(sender)); //Send what the command is about, could be useful for commands like /member where some subcommands aren't player-only
return true;
}
return false;
}
/**
* Constructs a command node for the given subcommand that can be used for a custom registering logic (Discord).
*
* @param command The command object
* @param method The subcommand method
* @return The processed command node
* @throws Exception Something broke
*/
protected LiteralCommandNode<TP> processSubcommand(TC command, Method method) throws Exception {
val params = new ArrayList<Object>(method.getParameterCount());
Class<?>[] parameterTypes = method.getParameterTypes();

View file

@ -1,32 +1,59 @@
package buttondevteam.lib.chat;
import buttondevteam.lib.chat.commands.CommandArgument;
import buttondevteam.lib.chat.commands.SubcommandData;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.CommandNode;
public class CoreCommandBuilder<S> extends LiteralArgumentBuilder<S> {
private String[] helpText;
import java.util.Map;
import java.util.function.Function;
protected CoreCommandBuilder(String literal) {
public class CoreCommandBuilder<S, TC extends ICommand2<?>> extends LiteralArgumentBuilder<S> {
private final SubcommandData.SubcommandDataBuilder<TC> dataBuilder;
protected CoreCommandBuilder(String literal, Class<?> senderType, Map<String, CommandArgument> arguments, TC command) {
super(literal);
dataBuilder = SubcommandData.<TC>builder().senderType(senderType).arguments(arguments).command(command);
}
@Override
protected CoreCommandBuilder<S> getThis() {
protected CoreCommandBuilder<S, TC> getThis() {
return this;
}
public static <S> CoreCommandBuilder<S> literal(String name) {
return new CoreCommandBuilder<>(name);
public static <S, TC extends ICommand2<?>> CoreCommandBuilder<S, TC> literal(String name, Class<?> senderType, Map<String, CommandArgument> arguments, TC command) {
return new CoreCommandBuilder<>(name, senderType, arguments, command);
}
public CoreCommandBuilder<S> helps(String[] helpText) {
this.helpText = helpText;
/**
* Static help text added through annotations. May be overwritten with the getter.
*
* @param helpText Help text shown to the user
* @return This instance
*/
public CoreCommandBuilder<S, TC> helps(String[] helpText) {
dataBuilder.staticHelpText(helpText);
return this;
}
/**
* Custom help text that depends on the context. Overwrites the static one.
* The function receives the sender but its type is not guaranteed to match the one at the subcommand.
* It will either match or be a Command2Sender, however.
*
* @param getter The getter function receiving the sender and returning the help text
* @return This instance
*/
public CoreCommandBuilder<S, TC> helps(Function<Object, String[]> getter) {
dataBuilder.helpTextGetter(getter);
return this;
}
@Override
public CoreCommandNode<S> build() {
var result = new CoreCommandNode<>(this.getLiteral(), this.getCommand(), this.getRequirement(), this.getRedirect(), this.getRedirectModifier(), this.isFork(), helpText);
public CoreCommandNode<S, TC> build() {
var result = new CoreCommandNode<>(this.getLiteral(), this.getCommand(), this.getRequirement(),
this.getRedirect(), this.getRedirectModifier(), this.isFork(),
dataBuilder.build());
for (CommandNode<S> node : this.getArguments()) {
result.addChild(node);

View file

@ -1,5 +1,6 @@
package buttondevteam.lib.chat;
import buttondevteam.lib.chat.commands.SubcommandData;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.RedirectModifier;
import com.mojang.brigadier.tree.CommandNode;
@ -8,12 +9,12 @@ import lombok.Getter;
import java.util.function.Predicate;
public class CoreCommandNode<T> extends LiteralCommandNode<T> {
public class CoreCommandNode<T, TC extends ICommand2<?>> extends LiteralCommandNode<T> {
@Getter
private final String[] helpText;
private final SubcommandData<TC> data;
public CoreCommandNode(String literal, Command<T> command, Predicate<T> requirement, CommandNode<T> redirect, RedirectModifier<T> modifier, boolean forks, String[] helpText) {
public CoreCommandNode(String literal, Command<T> command, Predicate<T> requirement, CommandNode<T> redirect, RedirectModifier<T> modifier, boolean forks, SubcommandData<TC> data) {
super(literal, command, requirement, redirect, modifier, forks);
this.helpText = helpText;
this.data = data;
}
}

View file

@ -1,16 +1,34 @@
package buttondevteam.lib.chat.commands;
import buttondevteam.lib.chat.ICommand2;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import java.util.Map;
import java.util.function.Function;
/**
* Stores information about the subcommand that can be used to construct the Brigadier setup and to get information while executing the command.
*
* @param <TC> Command class type
*/
@Builder
@RequiredArgsConstructor
public final class SubcommandData<TC extends ICommand2<?>> {
// The actual sender type may not be represented by Command2Sender (TP)
/**
* The type of the sender running the command.
* The actual sender type may not be represented by Command2Sender (TP).
* In that case it has to match the expected type.
*/
public final Class<?> senderType;
/**
* Command arguments collected from the subcommand method.
* Used to construct the arguments for Brigadier and to hold extra information.
*/
public final Map<String, CommandArgument> arguments;
/**
* The original command class that this data belongs to.
*/
public final TC command;
/**
@ -24,6 +42,12 @@ public final class SubcommandData<TC extends ICommand2<?>> {
*/
private final Function<Object, String[]> helpTextGetter;
/**
* Get help text for this subcommand.
*
* @param sender The sender running the command
* @return Help text shown to the user
*/
public String[] getHelpText(Object sender) {
return staticHelpText == null ? helpTextGetter.apply(sender) : staticHelpText;
}