Improved the speed of redirected commands

This commit is contained in:
Nathan Adams 2018-01-16 13:36:25 +01:00
parent 5a8a8a29d2
commit f329f927e7
7 changed files with 43 additions and 30 deletions

View file

@ -1,7 +1,6 @@
package com.mojang.brigadier;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@ -92,29 +91,33 @@ public class CommandDispatcher<S> {
int successfulForks = 0;
boolean forked = false;
boolean foundCommand = false;
final Deque<CommandContextBuilder<S>> contexts = new ArrayDeque<>();
contexts.add(parse.getContext());
final Deque<CommandContext<S>> contexts = new ArrayDeque<>(8);
final String command = parse.getReader().getString();
contexts.add(parse.getContext().build(command));
while (!contexts.isEmpty()) {
final CommandContextBuilder<S> builder = contexts.removeFirst();
final CommandContextBuilder<S> child = builder.getChild();
final CommandContext<S> context = builder.build(parse.getReader().getString());
final CommandContext<S> context = contexts.removeFirst();
final CommandContext<S> child = context.getChild();
if (child != null) {
if (!child.getNodes().isEmpty()) {
foundCommand = true;
final RedirectModifier<S> modifier = Iterators.getLast(builder.getNodes().keySet().iterator()).getRedirectModifier();
final Collection<S> results = modifier.apply(context);
if (results.size() > 1) {
forked = true;
}
for (final S source : results) {
contexts.add(child.copy().withSource(source));
final RedirectModifier<S> modifier = context.getRedirectModifier();
if (modifier == null) {
contexts.add(child);
} else {
final Collection<S> results = modifier.apply(context);
if (results.size() > 1) {
forked = true;
}
for (final S source : results) {
contexts.add(child.copyFor(source));
}
}
}
} else if (builder.getCommand() != null) {
} else if (context.getCommand() != null) {
foundCommand = true;
try {
final int value = builder.getCommand().run(context);
final int value = context.getCommand().run(context);
result += value;
consumer.onCommandComplete(context, true, value);
successfulForks++;
@ -128,7 +131,7 @@ public class CommandDispatcher<S> {
}
if (!foundCommand) {
consumer.onCommandComplete(parse.getContext().build(parse.getReader().getString()), false, 0);
consumer.onCommandComplete(parse.getContext().build(command), false, 0);
throw ERROR_UNKNOWN_COMMAND.createWithContext(parse.getReader());
}

View file

@ -6,7 +6,6 @@ import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Predicate;
public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
@ -14,7 +13,7 @@ public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
private Command<S> command;
private Predicate<S> requirement = s -> true;
private CommandNode<S> target;
private RedirectModifier<S> modifier = s -> Collections.singleton(s.getSource());
private RedirectModifier<S> modifier = null;
protected abstract T getThis();
@ -57,7 +56,7 @@ public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
}
public T redirect(final CommandNode<S> target) {
return redirect(target, modifier);
return redirect(target, null);
}
public T redirect(final CommandNode<S> target, final RedirectModifier<S> modifier) {

View file

@ -3,6 +3,7 @@ package com.mojang.brigadier.context;
import com.google.common.collect.Iterables;
import com.google.common.primitives.Primitives;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.RedirectModifier;
import com.mojang.brigadier.tree.CommandNode;
import java.util.Map;
@ -15,8 +16,9 @@ public class CommandContext<S> {
private final Map<CommandNode<S>, StringRange> nodes;
private final StringRange range;
private final CommandContext<S> child;
private final RedirectModifier<S> modifier;
public CommandContext(final S source, final String input, final Map<String, ParsedArgument<S, ?>> arguments, final Command<S> command, final Map<CommandNode<S>, StringRange> nodes, final StringRange range, final CommandContext<S> child) {
public CommandContext(final S source, final String input, final Map<String, ParsedArgument<S, ?>> arguments, final Command<S> command, final Map<CommandNode<S>, StringRange> nodes, final StringRange range, final CommandContext<S> child, final RedirectModifier<S> modifier) {
this.source = source;
this.input = input;
this.arguments = arguments;
@ -24,6 +26,11 @@ public class CommandContext<S> {
this.nodes = nodes;
this.range = range;
this.child = child;
this.modifier = modifier;
}
public CommandContext<S> copyFor(final S source) {
return new CommandContext<>(source, input, arguments, command, nodes, range, child, modifier);
}
public CommandContext<S> getChild() {
@ -88,6 +95,10 @@ public class CommandContext<S> {
return result;
}
public RedirectModifier<S> getRedirectModifier() {
return modifier;
}
public StringRange getRange() {
return range;
}

View file

@ -3,6 +3,7 @@ package com.mojang.brigadier.context;
import com.google.common.collect.Maps;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.RedirectModifier;
import com.mojang.brigadier.tree.CommandNode;
import java.util.Map;
@ -15,6 +16,7 @@ public class CommandContextBuilder<S> {
private Command<S> command;
private CommandContextBuilder<S> child;
private StringRange range;
private RedirectModifier<S> modifier = null;
public CommandContextBuilder(final CommandDispatcher<S> dispatcher, final S source, final int start) {
this.dispatcher = dispatcher;
@ -48,6 +50,7 @@ public class CommandContextBuilder<S> {
public CommandContextBuilder<S> withNode(final CommandNode<S> node, final StringRange range) {
nodes.put(node, range);
this.range = StringRange.encompassing(this.range, range);
this.modifier = node.getRedirectModifier();
return this;
}
@ -87,7 +90,7 @@ public class CommandContextBuilder<S> {
}
public CommandContext<S> build(final String input) {
return new CommandContext<>(source, input, arguments, command, nodes, range, child == null ? null : child.build(input));
return new CommandContext<>(source, input, arguments, command, nodes, range, child == null ? null : child.build(input), modifier);
}
public CommandDispatcher<S> getDispatcher() {

View file

@ -250,7 +250,7 @@ public class CommandDispatcherTest {
@Test
public void testExecuteRedirectedMultipleTimes() throws Exception {
subject.register(literal("actual").executes(command));
subject.register(literal("redirected").redirect(subject.getRoot(), Collections::singleton));
subject.register(literal("redirected").redirect(subject.getRoot()));
final String input = "redirected redirected actual";
final ParseResults<Object> parse = subject.parse(input, source);

View file

@ -90,11 +90,11 @@ public class CommandDispatcherUsagesTest {
);
subject.register(
literal("j")
.redirect(subject.getRoot(), Collections::singleton)
.redirect(subject.getRoot())
);
subject.register(
literal("k")
.redirect(get("h"), Collections::singleton)
.redirect(get("h"))
);
}

View file

@ -3,9 +3,6 @@ package com.mojang.brigadier.builder;
import com.mojang.brigadier.tree.CommandNode;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.Collections;
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
@ -37,7 +34,7 @@ public class ArgumentBuilderTest {
@Test
public void testRedirect() throws Exception {
final CommandNode<Object> target = mock(CommandNode.class);
builder.redirect(target, Collections::singleton);
builder.redirect(target);
assertThat(builder.getRedirect(), is(target));
}
@ -45,13 +42,13 @@ public class ArgumentBuilderTest {
public void testRedirect_withChild() throws Exception {
final CommandNode<Object> target = mock(CommandNode.class);
builder.then(literal("foo"));
builder.redirect(target, Collections::singleton);
builder.redirect(target);
}
@Test(expected = IllegalStateException.class)
public void testThen_withRedirect() throws Exception {
final CommandNode<Object> target = mock(CommandNode.class);
builder.redirect(target, Collections::singleton);
builder.redirect(target);
builder.then(literal("foo"));
}