Implemented permissions (predicate on each node)
This commit is contained in:
parent
014caa2905
commit
6575257e0d
12 changed files with 70 additions and 9 deletions
|
@ -19,6 +19,7 @@ import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class CommandDispatcher<S> {
|
public class CommandDispatcher<S> {
|
||||||
public static final SimpleCommandExceptionType ERROR_UNKNOWN_COMMAND = new SimpleCommandExceptionType("command.unknown", "Unknown command");
|
public static final SimpleCommandExceptionType ERROR_UNKNOWN_COMMAND = new SimpleCommandExceptionType("command.unknown", "Unknown command");
|
||||||
|
public static final SimpleCommandExceptionType ERROR_IMPERMISSIBLE = new SimpleCommandExceptionType("command.impermissible", "Command not allowed");
|
||||||
public static final String ARGUMENT_SEPARATOR = " ";
|
public static final String ARGUMENT_SEPARATOR = " ";
|
||||||
private static final String USAGE_OPTIONAL_OPEN = "[";
|
private static final String USAGE_OPTIONAL_OPEN = "[";
|
||||||
private static final String USAGE_OPTIONAL_CLOSE = "]";
|
private static final String USAGE_OPTIONAL_CLOSE = "]";
|
||||||
|
@ -45,8 +46,13 @@ public class CommandDispatcher<S> {
|
||||||
|
|
||||||
private CommandContext<S> parseNodes(CommandNode<S> node, String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
|
private CommandContext<S> parseNodes(CommandNode<S> node, String command, CommandContextBuilder<S> contextBuilder) throws CommandException {
|
||||||
CommandException exception = null;
|
CommandException exception = null;
|
||||||
|
final S source = contextBuilder.getSource();
|
||||||
|
|
||||||
for (CommandNode<S> child : node.getChildren()) {
|
for (CommandNode<S> child : node.getChildren()) {
|
||||||
|
if (!child.canUse(source)) {
|
||||||
|
exception = ERROR_IMPERMISSIBLE.create();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
CommandContextBuilder<S> context = contextBuilder.copy();
|
CommandContextBuilder<S> context = contextBuilder.copy();
|
||||||
String remaining = child.parse(command, context);
|
String remaining = child.parse(command, context);
|
||||||
|
@ -113,7 +119,11 @@ public class CommandDispatcher<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Set<String> findSuggestions(CommandNode<S> node, String command, CommandContextBuilder<S> contextBuilder, Set<String> result) {
|
private Set<String> findSuggestions(CommandNode<S> node, String command, CommandContextBuilder<S> contextBuilder, Set<String> result) {
|
||||||
|
final S source = contextBuilder.getSource();
|
||||||
for (CommandNode<S> child : node.getChildren()) {
|
for (CommandNode<S> child : node.getChildren()) {
|
||||||
|
if (!child.canUse(source)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
CommandContextBuilder<S> context = contextBuilder.copy();
|
CommandContextBuilder<S> context = contextBuilder.copy();
|
||||||
String remaining = child.parse(command, context);
|
String remaining = child.parse(command, context);
|
||||||
|
|
|
@ -5,10 +5,12 @@ import com.mojang.brigadier.tree.CommandNode;
|
||||||
import com.mojang.brigadier.tree.RootCommandNode;
|
import com.mojang.brigadier.tree.RootCommandNode;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, ?>> {
|
public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, ?>> {
|
||||||
private final RootCommandNode<S> arguments = new RootCommandNode<>();
|
private final RootCommandNode<S> arguments = new RootCommandNode<>();
|
||||||
private Command<S> command;
|
private Command<S> command;
|
||||||
|
private Predicate<S> requirement = s -> true;
|
||||||
|
|
||||||
protected abstract T getThis();
|
protected abstract T getThis();
|
||||||
|
|
||||||
|
@ -30,5 +32,14 @@ public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, ?>> {
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public T requires(Predicate<S> requirement) {
|
||||||
|
this.requirement = requirement;
|
||||||
|
return getThis();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Predicate<S> getRequirement() {
|
||||||
|
return requirement;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract CommandNode<S> build();
|
public abstract CommandNode<S> build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class LiteralArgumentBuilder<S> extends ArgumentBuilder<S, LiteralArgumen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiteralCommandNode<S> build() {
|
public LiteralCommandNode<S> build() {
|
||||||
LiteralCommandNode<S> result = new LiteralCommandNode<>(getLiteral(), getCommand());
|
LiteralCommandNode<S> result = new LiteralCommandNode<>(getLiteral(), getCommand(), getRequirement());
|
||||||
|
|
||||||
for (CommandNode<S> argument : getArguments()) {
|
for (CommandNode<S> argument : getArguments()) {
|
||||||
result.addChild(argument);
|
result.addChild(argument);
|
||||||
|
|
|
@ -31,7 +31,7 @@ public class RequiredArgumentBuilder<S, T> extends ArgumentBuilder<S, RequiredAr
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArgumentCommandNode<S, T> build() {
|
public ArgumentCommandNode<S, T> build() {
|
||||||
ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand());
|
ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement());
|
||||||
|
|
||||||
for (CommandNode<S> argument : getArguments()) {
|
for (CommandNode<S> argument : getArguments()) {
|
||||||
result.addChild(argument);
|
result.addChild(argument);
|
||||||
|
|
|
@ -16,6 +16,10 @@ public class CommandContextBuilder<S> {
|
||||||
this.source = source;
|
this.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public S getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandContextBuilder<S> withArgument(String name, ParsedArgument<?> argument) {
|
public CommandContextBuilder<S> withArgument(String name, ParsedArgument<?> argument) {
|
||||||
this.arguments.put(name, argument);
|
this.arguments.put(name, argument);
|
||||||
return this;
|
return this;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.mojang.brigadier.context.ParsedArgument;
|
||||||
import com.mojang.brigadier.exceptions.CommandException;
|
import com.mojang.brigadier.exceptions.CommandException;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class ArgumentCommandNode<S, T> extends CommandNode<S> {
|
public class ArgumentCommandNode<S, T> extends CommandNode<S> {
|
||||||
private static final String USAGE_ARGUMENT_OPEN = "<";
|
private static final String USAGE_ARGUMENT_OPEN = "<";
|
||||||
|
@ -15,8 +16,8 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final CommandArgumentType<T> type;
|
private final CommandArgumentType<T> type;
|
||||||
|
|
||||||
public ArgumentCommandNode(String name, CommandArgumentType<T> type, Command<S> command) {
|
public ArgumentCommandNode(String name, CommandArgumentType<T> type, Command<S> command, Predicate<S> requirement) {
|
||||||
super(command);
|
super(command, requirement);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,16 @@ import com.mojang.brigadier.exceptions.CommandException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public abstract class CommandNode<S> {
|
public abstract class CommandNode<S> {
|
||||||
private final Map<Object, CommandNode<S>> children = Maps.newLinkedHashMap();
|
private final Map<Object, CommandNode<S>> children = Maps.newLinkedHashMap();
|
||||||
private Command<S> command;
|
private Command<S> command;
|
||||||
|
private Predicate<S> requirement;
|
||||||
|
|
||||||
protected CommandNode(Command<S> command) {
|
protected CommandNode(Command<S> command, Predicate<S> requirement) {
|
||||||
this.command = command;
|
this.command = command;
|
||||||
|
this.requirement = requirement;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command<S> getCommand() {
|
public Command<S> getCommand() {
|
||||||
|
@ -25,6 +28,10 @@ public abstract class CommandNode<S> {
|
||||||
return children.values();
|
return children.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canUse(S source) {
|
||||||
|
return requirement.test(source);
|
||||||
|
}
|
||||||
|
|
||||||
public void addChild(CommandNode<S> node) {
|
public void addChild(CommandNode<S> node) {
|
||||||
CommandNode<S> child = children.get(node.getMergeKey());
|
CommandNode<S> child = children.get(node.getMergeKey());
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
|
|
|
@ -7,14 +7,15 @@ import com.mojang.brigadier.exceptions.CommandException;
|
||||||
import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
|
import com.mojang.brigadier.exceptions.ParameterizedCommandExceptionType;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class LiteralCommandNode<S> extends CommandNode<S> {
|
public class LiteralCommandNode<S> extends CommandNode<S> {
|
||||||
public static final ParameterizedCommandExceptionType ERROR_INCORRECT_LITERAL = new ParameterizedCommandExceptionType("argument.literal.incorrect", "Expected literal ${expected}", "expected");
|
public static final ParameterizedCommandExceptionType ERROR_INCORRECT_LITERAL = new ParameterizedCommandExceptionType("argument.literal.incorrect", "Expected literal ${expected}", "expected");
|
||||||
|
|
||||||
private final String literal;
|
private final String literal;
|
||||||
|
|
||||||
public LiteralCommandNode(String literal, Command<S> command) {
|
public LiteralCommandNode(String literal, Command<S> command, Predicate<S> requirement) {
|
||||||
super(command);
|
super(command, requirement);
|
||||||
this.literal = literal;
|
this.literal = literal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import java.util.Set;
|
||||||
|
|
||||||
public class RootCommandNode<S> extends CommandNode<S> {
|
public class RootCommandNode<S> extends CommandNode<S> {
|
||||||
public RootCommandNode() {
|
public RootCommandNode() {
|
||||||
super(null);
|
super(null, c -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -35,6 +35,7 @@ public class CommandDispatcherCompletionsTest {
|
||||||
public void testCommand() throws Exception {
|
public void testCommand() throws Exception {
|
||||||
subject.register(literal("foo"));
|
subject.register(literal("foo"));
|
||||||
subject.register(literal("bar"));
|
subject.register(literal("bar"));
|
||||||
|
subject.register(literal("baz").requires(s -> false));
|
||||||
assertThat(subject.getCompletionSuggestions("", source), equalTo(new String[] {"foo", "bar"}));
|
assertThat(subject.getCompletionSuggestions("", source), equalTo(new String[] {"foo", "bar"}));
|
||||||
assertThat(subject.getCompletionSuggestions("f", source), equalTo(new String[] {"foo"}));
|
assertThat(subject.getCompletionSuggestions("f", source), equalTo(new String[] {"foo"}));
|
||||||
assertThat(subject.getCompletionSuggestions("b", source), equalTo(new String[] {"bar"}));
|
assertThat(subject.getCompletionSuggestions("b", source), equalTo(new String[] {"bar"}));
|
||||||
|
@ -43,7 +44,7 @@ public class CommandDispatcherCompletionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSubCommand() throws Exception {
|
public void testSubCommand() throws Exception {
|
||||||
subject.register(literal("foo").then(literal("abc")).then(literal("def")));
|
subject.register(literal("foo").then(literal("abc")).then(literal("def")).then(literal("ghi").requires(s -> false)));
|
||||||
subject.register(literal("bar"));
|
subject.register(literal("bar"));
|
||||||
assertThat(subject.getCompletionSuggestions("", source), equalTo(new String[] {"foo", "bar"}));
|
assertThat(subject.getCompletionSuggestions("", source), equalTo(new String[] {"foo", "bar"}));
|
||||||
assertThat(subject.getCompletionSuggestions("f", source), equalTo(new String[] {"foo"}));
|
assertThat(subject.getCompletionSuggestions("f", source), equalTo(new String[] {"foo"}));
|
||||||
|
|
|
@ -99,6 +99,19 @@ public class CommandDispatcherTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecuteImpermissibleCommand() throws Exception {
|
||||||
|
subject.register(literal("foo").requires(s -> false));
|
||||||
|
|
||||||
|
try {
|
||||||
|
subject.execute("foo", source);
|
||||||
|
fail();
|
||||||
|
} catch (CommandException ex) {
|
||||||
|
assertThat(ex.getType(), is(CommandDispatcher.ERROR_IMPERMISSIBLE));
|
||||||
|
assertThat(ex.getData(), is(Collections.<String, Object>emptyMap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExecuteUnknownSubcommand() throws Exception {
|
public void testExecuteUnknownSubcommand() throws Exception {
|
||||||
subject.register(literal("foo").executes(command));
|
subject.register(literal("foo").executes(command));
|
||||||
|
|
|
@ -42,6 +42,19 @@ public class CommandDispatcherUsagesTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInaccessibleCommand() throws Exception {
|
||||||
|
subject.register(literal("foo").requires(s -> false));
|
||||||
|
|
||||||
|
try {
|
||||||
|
subject.getUsage("foo", source);
|
||||||
|
fail();
|
||||||
|
} catch (CommandException ex) {
|
||||||
|
assertThat(ex.getType(), is(CommandDispatcher.ERROR_IMPERMISSIBLE));
|
||||||
|
assertThat(ex.getData(), is(Collections.<String, Object>emptyMap()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSubcommandUsage() throws Exception {
|
public void testSubcommandUsage() throws Exception {
|
||||||
subject.register(
|
subject.register(
|
||||||
|
|
Loading…
Reference in a new issue