Always try every route to find a matching command

This commit is contained in:
Nathan Adams
2014-09-29 11:56:24 +02:00
parent 4b6abf4084
commit 6a8d067cf9
3 changed files with 60 additions and 21 deletions
@@ -3,6 +3,7 @@ package net.minecraft.commands;
import net.minecraft.commands.builder.LiteralArgumentBuilder; import net.minecraft.commands.builder.LiteralArgumentBuilder;
import net.minecraft.commands.context.CommandContext; import net.minecraft.commands.context.CommandContext;
import net.minecraft.commands.context.CommandContextBuilder; import net.minecraft.commands.context.CommandContextBuilder;
import net.minecraft.commands.exceptions.ArgumentValidationException;
import net.minecraft.commands.exceptions.CommandException; import net.minecraft.commands.exceptions.CommandException;
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException; import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
import net.minecraft.commands.exceptions.UnknownCommandException; import net.minecraft.commands.exceptions.UnknownCommandException;
@@ -19,35 +20,33 @@ public class CommandDispatcher {
} }
public void execute(String command) throws CommandException { public void execute(String command) throws CommandException {
CommandContextBuilder contextBuilder = new CommandContextBuilder(); CommandContext context = parseNodes(root, command, new CommandContextBuilder());
CommandNode node = root; context.getCommand().run(context);
}
while (command.length() > 0 && !node.getChildren().isEmpty()) { protected CommandContext parseNodes(CommandNode node, String command, CommandContextBuilder contextBuilder) throws IllegalArgumentSyntaxException, ArgumentValidationException, UnknownCommandException {
IllegalArgumentSyntaxException exception = null; IllegalArgumentSyntaxException exception = null;
for (CommandNode child : node.getChildren()) { for (CommandNode child : node.getChildren()) {
try { try {
command = child.parse(command, contextBuilder); CommandContextBuilder context = contextBuilder.copy();
if (child.getCommand() != null) { String remaining = child.parse(command, context);
contextBuilder.withCommand(child.getCommand()); if (child.getCommand() != null) {
} context.withCommand(child.getCommand());
node = child;
break;
} catch (IllegalArgumentSyntaxException ex) {
exception = ex;
} }
} return parseNodes(child, remaining, context);
} catch (IllegalArgumentSyntaxException ex) {
if (exception != null) { exception = ex;
break;
} }
} }
if (exception != null) {
throw exception;
}
if (command.length() > 0) { if (command.length() > 0) {
throw new UnknownCommandException(); throw new UnknownCommandException();
} }
CommandContext context = contextBuilder.build(); return contextBuilder.build();
context.getCommand().run(context);
} }
} }
@@ -26,6 +26,13 @@ public class CommandContextBuilder {
return this; return this;
} }
public CommandContextBuilder copy() {
CommandContextBuilder copy = new CommandContextBuilder();
copy.command = this.command;
copy.arguments.putAll(this.arguments);
return copy;
}
public CommandContext build() { public CommandContext build() {
return new CommandContext(arguments, command); return new CommandContext(arguments, command);
} }
@@ -1,6 +1,7 @@
package net.minecraft.commands; package net.minecraft.commands;
import net.minecraft.commands.context.CommandContext; import net.minecraft.commands.context.CommandContext;
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
import net.minecraft.commands.exceptions.UnknownCommandException; import net.minecraft.commands.exceptions.UnknownCommandException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -44,6 +45,38 @@ public class CommandDispatcherTest {
verify(command, times(2)).run(any(CommandContext.class)); verify(command, times(2)).run(any(CommandContext.class));
} }
@Test
public void testCreateAndExecuteOverlappingCommands() throws Exception {
Command one = mock(Command.class);
Command two = mock(Command.class);
Command three = mock(Command.class);
subject.register(
literal("foo").then(
argument("one", integer()).then(
literal("one").executes(one)
)
).then(
argument("two", integer()).then(
literal("two").executes(two)
)
).then(
argument("three", integer()).then(
literal("three").executes(three)
)
)
);
subject.execute("foo 1 one");
verify(one).run(any(CommandContext.class));
subject.execute("foo 2 two");
verify(two).run(any(CommandContext.class));
subject.execute("foo 3 three");
verify(three).run(any(CommandContext.class));
}
@Test(expected = UnknownCommandException.class) @Test(expected = UnknownCommandException.class)
public void testExecuteUnknownCommand() throws Exception { public void testExecuteUnknownCommand() throws Exception {
subject.execute("foo"); subject.execute("foo");
@@ -71,7 +104,7 @@ public class CommandDispatcherTest {
verify(subCommand).run(any(CommandContext.class)); verify(subCommand).run(any(CommandContext.class));
} }
@Test(expected = UnknownCommandException.class) @Test(expected = IllegalArgumentSyntaxException.class)
public void testExecuteInvalidSubcommand() throws Exception { public void testExecuteInvalidSubcommand() throws Exception {
subject.register(literal("foo").then( subject.register(literal("foo").then(
argument("bar", integer()) argument("bar", integer())