Changed how parsing is done, performed by dispatcher and can now look as deep as needed
This commit is contained in:
parent
8da6087618
commit
d678a5cb21
11 changed files with 171 additions and 103 deletions
|
@ -1,32 +1,51 @@
|
||||||
package net.minecraft.commands;
|
package net.minecraft.commands;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
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.ParsedArgument;
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
import net.minecraft.commands.exceptions.CommandException;
|
import net.minecraft.commands.exceptions.CommandException;
|
||||||
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
import net.minecraft.commands.exceptions.UnknownCommandException;
|
import net.minecraft.commands.exceptions.UnknownCommandException;
|
||||||
import net.minecraft.commands.tree.LiteralCommandNode;
|
import net.minecraft.commands.tree.CommandNode;
|
||||||
|
import net.minecraft.commands.tree.RootCommandNode;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class CommandDispatcher {
|
public class CommandDispatcher {
|
||||||
private final Map<String, LiteralCommandNode> commands = Maps.newHashMap();
|
private final RootCommandNode root = new RootCommandNode();
|
||||||
|
|
||||||
public void register(LiteralArgumentBuilder command) {
|
public void register(LiteralArgumentBuilder command) {
|
||||||
if (commands.containsKey(command.getLiteral())) {
|
root.addChild(command.build());
|
||||||
throw new IllegalArgumentException("New command " + command.getLiteral() + " conflicts with existing command " + command.getLiteral());
|
|
||||||
}
|
|
||||||
commands.put(command.getLiteral(), command.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute(String command) throws CommandException {
|
public void execute(String command) throws CommandException {
|
||||||
LiteralCommandNode node = commands.get(command);
|
CommandContextBuilder contextBuilder = new CommandContextBuilder();
|
||||||
if (node == null) {
|
CommandNode node = root;
|
||||||
|
|
||||||
|
while (command.length() > 0 && !node.getChildren().isEmpty()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.length() > 0) {
|
||||||
throw new UnknownCommandException();
|
throw new UnknownCommandException();
|
||||||
}
|
}
|
||||||
|
|
||||||
node.getCommand().run(new CommandContext(new HashMap<String, ParsedArgument<?>>()));
|
CommandContext context = contextBuilder.build();
|
||||||
|
context.getCommand().run(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,21 @@
|
||||||
package net.minecraft.commands.context;
|
package net.minecraft.commands.context;
|
||||||
|
|
||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
|
import net.minecraft.commands.Command;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class CommandContext {
|
public class CommandContext {
|
||||||
private final Map<String, ParsedArgument<?>> arguments;
|
private final Map<String, ParsedArgument<?>> arguments;
|
||||||
|
private final Command command;
|
||||||
|
|
||||||
public CommandContext(Map<String, ParsedArgument<?>> arguments) {
|
public CommandContext(Map<String, ParsedArgument<?>> arguments, Command command) {
|
||||||
this.arguments = arguments;
|
this.arguments = arguments;
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Command getCommand() {
|
||||||
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package net.minecraft.commands.context;
|
package net.minecraft.commands.context;
|
||||||
|
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
|
import net.minecraft.commands.Command;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class CommandContextBuilder {
|
public class CommandContextBuilder {
|
||||||
private final Map<String, ParsedArgument<?>> arguments = Maps.newHashMap();
|
private final Map<String, ParsedArgument<?>> arguments = Maps.newHashMap();
|
||||||
|
private Command command;
|
||||||
|
|
||||||
public CommandContextBuilder() {
|
public CommandContextBuilder() {
|
||||||
}
|
}
|
||||||
|
@ -15,7 +17,16 @@ public class CommandContextBuilder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, ParsedArgument<?>> getArguments() {
|
||||||
|
return arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandContextBuilder withCommand(Command command) {
|
||||||
|
this.command = command;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public CommandContext build() {
|
public CommandContext build() {
|
||||||
return new CommandContext(arguments);
|
return new CommandContext(arguments, command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package net.minecraft.commands.tree;
|
||||||
|
|
||||||
import net.minecraft.commands.Command;
|
import net.minecraft.commands.Command;
|
||||||
import net.minecraft.commands.arguments.CommandArgumentType;
|
import net.minecraft.commands.arguments.CommandArgumentType;
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
import net.minecraft.commands.context.ParsedArgument;
|
import net.minecraft.commands.context.ParsedArgument;
|
||||||
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
||||||
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
|
@ -25,23 +26,16 @@ public class ArgumentCommandNode<T> extends CommandNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandNode parse(String command) throws IllegalArgumentSyntaxException, ArgumentValidationException {
|
public String parse(String command, CommandContextBuilder contextBuilder) throws IllegalArgumentSyntaxException, ArgumentValidationException {
|
||||||
ParsedArgument<T> parsed = type.parse(command);
|
ParsedArgument<T> parsed = type.parse(command);
|
||||||
int start = parsed.getRaw().length() + 1;
|
int start = parsed.getRaw().length();
|
||||||
|
|
||||||
if (start < command.length()) {
|
contextBuilder.withArgument(name, parsed);
|
||||||
String result = command.substring(start);
|
|
||||||
|
|
||||||
for (CommandNode node : getChildren()) {
|
if (command.length() > start) {
|
||||||
try {
|
return command.substring(start + 1);
|
||||||
return node.parse(result);
|
|
||||||
} catch (IllegalArgumentSyntaxException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentSyntaxException();
|
|
||||||
} else {
|
} else {
|
||||||
return this;
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package net.minecraft.commands.tree;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import net.minecraft.commands.Command;
|
import net.minecraft.commands.Command;
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
||||||
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
|
|
||||||
|
@ -27,5 +28,5 @@ public abstract class CommandNode {
|
||||||
children.add(node);
|
children.add(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract CommandNode parse(String command) throws IllegalArgumentSyntaxException, ArgumentValidationException;
|
public abstract String parse(String command, CommandContextBuilder contextBuilder) throws IllegalArgumentSyntaxException, ArgumentValidationException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package net.minecraft.commands.tree;
|
package net.minecraft.commands.tree;
|
||||||
|
|
||||||
import net.minecraft.commands.Command;
|
import net.minecraft.commands.Command;
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
||||||
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
|
|
||||||
|
@ -17,26 +18,16 @@ public class LiteralCommandNode extends CommandNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandNode parse(String command) throws IllegalArgumentSyntaxException, ArgumentValidationException {
|
public String parse(String command, CommandContextBuilder contextBuilder) throws IllegalArgumentSyntaxException, ArgumentValidationException {
|
||||||
if (command.startsWith(literal)) {
|
if (!command.startsWith(literal)) {
|
||||||
int start = literal.length() + 1;
|
|
||||||
|
|
||||||
if (start < command.length()) {
|
|
||||||
String result = command.substring(start);
|
|
||||||
|
|
||||||
for (CommandNode node : getChildren()) {
|
|
||||||
try {
|
|
||||||
return node.parse(result);
|
|
||||||
} catch (IllegalArgumentSyntaxException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentSyntaxException();
|
|
||||||
} else {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentSyntaxException();
|
throw new IllegalArgumentSyntaxException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int start = literal.length();
|
||||||
|
if (command.length() > start) {
|
||||||
|
return command.substring(start + 1);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package net.minecraft.commands.tree;
|
||||||
|
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
|
import net.minecraft.commands.exceptions.ArgumentValidationException;
|
||||||
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
|
|
||||||
|
public class RootCommandNode extends CommandNode {
|
||||||
|
public RootCommandNode() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String parse(String command, CommandContextBuilder contextBuilder) throws IllegalArgumentSyntaxException, ArgumentValidationException {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,8 +8,11 @@ import org.junit.runner.RunWith;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.arguments.IntegerArgumentType.integer;
|
||||||
import static net.minecraft.commands.builder.LiteralArgumentBuilder.literal;
|
import static net.minecraft.commands.builder.LiteralArgumentBuilder.literal;
|
||||||
|
import static net.minecraft.commands.builder.RequiredArgumentBuilder.argument;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
@ -22,12 +25,6 @@ public class CommandDispatcherTest {
|
||||||
subject = new CommandDispatcher();
|
subject = new CommandDispatcher();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
|
||||||
public void testDuplicateCommand() throws Exception {
|
|
||||||
subject.register(literal("foo").executes(command));
|
|
||||||
subject.register(literal("foo").executes(command));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateAndExecuteCommand() throws Exception {
|
public void testCreateAndExecuteCommand() throws Exception {
|
||||||
subject.register(literal("foo").executes(command));
|
subject.register(literal("foo").executes(command));
|
||||||
|
@ -40,4 +37,35 @@ public class CommandDispatcherTest {
|
||||||
public void testExecuteUnknownCommand() throws Exception {
|
public void testExecuteUnknownCommand() throws Exception {
|
||||||
subject.execute("foo");
|
subject.execute("foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = UnknownCommandException.class)
|
||||||
|
public void testExecuteUnknownSubcommand() throws Exception {
|
||||||
|
subject.register(literal("foo").executes(command));
|
||||||
|
subject.execute("foo bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecuteSubcommand() throws Exception {
|
||||||
|
Command subCommand = mock(Command.class);
|
||||||
|
|
||||||
|
subject.register(literal("foo").then(
|
||||||
|
literal("a")
|
||||||
|
).then(
|
||||||
|
literal("b").executes(subCommand)
|
||||||
|
).then(
|
||||||
|
literal("c")
|
||||||
|
).executes(command));
|
||||||
|
|
||||||
|
subject.execute("foo b");
|
||||||
|
verify(subCommand).run(any(CommandContext.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = UnknownCommandException.class)
|
||||||
|
public void testExecuteInvalidSubcommand() throws Exception {
|
||||||
|
subject.register(literal("foo").then(
|
||||||
|
argument("bar", integer())
|
||||||
|
).executes(command));
|
||||||
|
|
||||||
|
subject.execute("foo bar");
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package net.minecraft.commands.tree;
|
package net.minecraft.commands.tree;
|
||||||
|
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -11,40 +12,32 @@ import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
public class ArgumentCommandNodeTest {
|
public class ArgumentCommandNodeTest {
|
||||||
ArgumentCommandNode node;
|
ArgumentCommandNode node;
|
||||||
|
CommandContextBuilder contextBuilder;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
node = argument("foo", integer()).build();
|
node = argument("foo", integer()).build();
|
||||||
|
contextBuilder = new CommandContextBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParse() throws Exception {
|
public void testParse() throws Exception {
|
||||||
assertThat((ArgumentCommandNode) node.parse("123"), is(node));
|
assertThat(node.parse("123 456", contextBuilder), is("456"));
|
||||||
|
|
||||||
|
assertThat(contextBuilder.getArguments().containsKey("foo"), is(true));
|
||||||
|
assertThat(contextBuilder.getArguments().get("foo").getResult(), is((Object) 123));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseExact() throws Exception {
|
||||||
|
assertThat(node.parse("123", contextBuilder), is(""));
|
||||||
|
|
||||||
|
assertThat(contextBuilder.getArguments().containsKey("foo"), is(true));
|
||||||
|
assertThat(contextBuilder.getArguments().get("foo").getResult(), is((Object) 123));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentSyntaxException.class)
|
@Test(expected = IllegalArgumentSyntaxException.class)
|
||||||
public void testParseInvalid() throws Exception {
|
public void testParseInvalid() throws Exception {
|
||||||
node.parse("bar");
|
node.parse("foo", contextBuilder);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseChild() throws Exception {
|
|
||||||
CommandNode child = argument("bar", integer()).build();
|
|
||||||
|
|
||||||
node.addChild(child);
|
|
||||||
|
|
||||||
assertThat(node.parse("123 123"), is(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentSyntaxException.class)
|
|
||||||
public void testParseInvalidChild() throws Exception {
|
|
||||||
node.addChild(argument("bar", integer()).build());
|
|
||||||
|
|
||||||
node.parse("123 bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentSyntaxException.class)
|
|
||||||
public void testParseNoChildren() throws Exception {
|
|
||||||
node.parse("123 123");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,51 +1,36 @@
|
||||||
package net.minecraft.commands.tree;
|
package net.minecraft.commands.tree;
|
||||||
|
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
import net.minecraft.commands.exceptions.IllegalArgumentSyntaxException;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static net.minecraft.commands.arguments.IntegerArgumentType.integer;
|
|
||||||
import static net.minecraft.commands.builder.LiteralArgumentBuilder.literal;
|
import static net.minecraft.commands.builder.LiteralArgumentBuilder.literal;
|
||||||
import static net.minecraft.commands.builder.RequiredArgumentBuilder.argument;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
public class LiteralCommandNodeTest {
|
public class LiteralCommandNodeTest {
|
||||||
LiteralCommandNode node;
|
LiteralCommandNode node;
|
||||||
|
CommandContextBuilder contextBuilder;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
node = literal("foo").build();
|
node = literal("foo").build();
|
||||||
|
contextBuilder = new CommandContextBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParse() throws Exception {
|
public void testParse() throws Exception {
|
||||||
assertThat((LiteralCommandNode) node.parse("foo"), is(node));
|
assertThat(node.parse("foo bar", contextBuilder), is("bar"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseExact() throws Exception {
|
||||||
|
assertThat(node.parse("foo", contextBuilder), is(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentSyntaxException.class)
|
@Test(expected = IllegalArgumentSyntaxException.class)
|
||||||
public void testParseInvalid() throws Exception {
|
public void testParseInvalid() throws Exception {
|
||||||
node.parse("bar");
|
node.parse("bar", contextBuilder);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseChild() throws Exception {
|
|
||||||
CommandNode child = argument("bar", integer()).build();
|
|
||||||
|
|
||||||
node.addChild(child);
|
|
||||||
|
|
||||||
assertThat(node.parse("foo 123"), is(child));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentSyntaxException.class)
|
|
||||||
public void testParseInvalidChild() throws Exception {
|
|
||||||
node.addChild(argument("bar", integer()).build());
|
|
||||||
|
|
||||||
node.parse("foo bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentSyntaxException.class)
|
|
||||||
public void testParseNoChildren() throws Exception {
|
|
||||||
node.parse("foo 123");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package net.minecraft.commands.tree;
|
||||||
|
|
||||||
|
import net.minecraft.commands.context.CommandContextBuilder;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
public class RootCommandNodeTest {
|
||||||
|
RootCommandNode node;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
node = new RootCommandNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParse() throws Exception {
|
||||||
|
assertThat(node.parse("foo bar baz", new CommandContextBuilder()), is("foo bar baz"));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue