diff --git a/src/main/java/net/minecraft/commands/CommandDispatcher.java b/src/main/java/net/minecraft/commands/CommandDispatcher.java index 9e4dcc0..54d16e5 100644 --- a/src/main/java/net/minecraft/commands/CommandDispatcher.java +++ b/src/main/java/net/minecraft/commands/CommandDispatcher.java @@ -3,6 +3,7 @@ package net.minecraft.commands; import net.minecraft.commands.builder.LiteralArgumentBuilder; import net.minecraft.commands.context.CommandContext; import net.minecraft.commands.context.CommandContextBuilder; +import net.minecraft.commands.exceptions.ArgumentValidationException; import net.minecraft.commands.exceptions.CommandException; import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException; import net.minecraft.commands.exceptions.UnknownCommandException; @@ -19,35 +20,33 @@ public class CommandDispatcher { } public void execute(String command) throws CommandException { - CommandContextBuilder contextBuilder = new CommandContextBuilder(); - CommandNode node = root; + CommandContext context = parseNodes(root, command, new CommandContextBuilder()); + context.getCommand().run(context); + } - while (command.length() > 0 && !node.getChildren().isEmpty()) { - IllegalArgumentSyntaxException exception = null; + protected CommandContext parseNodes(CommandNode node, String command, CommandContextBuilder contextBuilder) throws IllegalArgumentSyntaxException, ArgumentValidationException, UnknownCommandException { + IllegalArgumentSyntaxException exception = null; - for (CommandNode child : node.getChildren()) { - try { - command = child.parse(command, contextBuilder); - if (child.getCommand() != null) { - contextBuilder.withCommand(child.getCommand()); - } - node = child; - break; - } catch (IllegalArgumentSyntaxException ex) { - exception = ex; + for (CommandNode child : node.getChildren()) { + try { + CommandContextBuilder context = contextBuilder.copy(); + String remaining = child.parse(command, context); + if (child.getCommand() != null) { + context.withCommand(child.getCommand()); } - } - - if (exception != null) { - break; + return parseNodes(child, remaining, context); + } catch (IllegalArgumentSyntaxException ex) { + exception = ex; } } + if (exception != null) { + throw exception; + } if (command.length() > 0) { throw new UnknownCommandException(); } - CommandContext context = contextBuilder.build(); - context.getCommand().run(context); + return contextBuilder.build(); } } diff --git a/src/main/java/net/minecraft/commands/context/CommandContextBuilder.java b/src/main/java/net/minecraft/commands/context/CommandContextBuilder.java index b4604cc..9649960 100644 --- a/src/main/java/net/minecraft/commands/context/CommandContextBuilder.java +++ b/src/main/java/net/minecraft/commands/context/CommandContextBuilder.java @@ -26,6 +26,13 @@ public class CommandContextBuilder { return this; } + public CommandContextBuilder copy() { + CommandContextBuilder copy = new CommandContextBuilder(); + copy.command = this.command; + copy.arguments.putAll(this.arguments); + return copy; + } + public CommandContext build() { return new CommandContext(arguments, command); } diff --git a/src/test/java/net/minecraft/commands/CommandDispatcherTest.java b/src/test/java/net/minecraft/commands/CommandDispatcherTest.java index 96f7c0b..f933b68 100644 --- a/src/test/java/net/minecraft/commands/CommandDispatcherTest.java +++ b/src/test/java/net/minecraft/commands/CommandDispatcherTest.java @@ -1,6 +1,7 @@ package net.minecraft.commands; import net.minecraft.commands.context.CommandContext; +import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException; import net.minecraft.commands.exceptions.UnknownCommandException; import org.junit.Before; import org.junit.Test; @@ -44,6 +45,38 @@ public class CommandDispatcherTest { 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) public void testExecuteUnknownCommand() throws Exception { subject.execute("foo"); @@ -71,7 +104,7 @@ public class CommandDispatcherTest { verify(subCommand).run(any(CommandContext.class)); } - @Test(expected = UnknownCommandException.class) + @Test(expected = IllegalArgumentSyntaxException.class) public void testExecuteInvalidSubcommand() throws Exception { subject.register(literal("foo").then( argument("bar", integer())