Improved the speed of redirected commands
This commit is contained in:
parent
5a8a8a29d2
commit
f329f927e7
7 changed files with 43 additions and 30 deletions
|
@ -1,7 +1,6 @@
|
||||||
package com.mojang.brigadier;
|
package com.mojang.brigadier;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
@ -92,29 +91,33 @@ public class CommandDispatcher<S> {
|
||||||
int successfulForks = 0;
|
int successfulForks = 0;
|
||||||
boolean forked = false;
|
boolean forked = false;
|
||||||
boolean foundCommand = false;
|
boolean foundCommand = false;
|
||||||
final Deque<CommandContextBuilder<S>> contexts = new ArrayDeque<>();
|
final Deque<CommandContext<S>> contexts = new ArrayDeque<>(8);
|
||||||
contexts.add(parse.getContext());
|
final String command = parse.getReader().getString();
|
||||||
|
contexts.add(parse.getContext().build(command));
|
||||||
|
|
||||||
while (!contexts.isEmpty()) {
|
while (!contexts.isEmpty()) {
|
||||||
final CommandContextBuilder<S> builder = contexts.removeFirst();
|
final CommandContext<S> context = contexts.removeFirst();
|
||||||
final CommandContextBuilder<S> child = builder.getChild();
|
final CommandContext<S> child = context.getChild();
|
||||||
final CommandContext<S> context = builder.build(parse.getReader().getString());
|
|
||||||
if (child != null) {
|
if (child != null) {
|
||||||
if (!child.getNodes().isEmpty()) {
|
if (!child.getNodes().isEmpty()) {
|
||||||
foundCommand = true;
|
foundCommand = true;
|
||||||
final RedirectModifier<S> modifier = Iterators.getLast(builder.getNodes().keySet().iterator()).getRedirectModifier();
|
final RedirectModifier<S> modifier = context.getRedirectModifier();
|
||||||
final Collection<S> results = modifier.apply(context);
|
if (modifier == null) {
|
||||||
if (results.size() > 1) {
|
contexts.add(child);
|
||||||
forked = true;
|
} else {
|
||||||
}
|
final Collection<S> results = modifier.apply(context);
|
||||||
for (final S source : results) {
|
if (results.size() > 1) {
|
||||||
contexts.add(child.copy().withSource(source));
|
forked = true;
|
||||||
|
}
|
||||||
|
for (final S source : results) {
|
||||||
|
contexts.add(child.copyFor(source));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (builder.getCommand() != null) {
|
} else if (context.getCommand() != null) {
|
||||||
foundCommand = true;
|
foundCommand = true;
|
||||||
try {
|
try {
|
||||||
final int value = builder.getCommand().run(context);
|
final int value = context.getCommand().run(context);
|
||||||
result += value;
|
result += value;
|
||||||
consumer.onCommandComplete(context, true, value);
|
consumer.onCommandComplete(context, true, value);
|
||||||
successfulForks++;
|
successfulForks++;
|
||||||
|
@ -128,7 +131,7 @@ public class CommandDispatcher<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundCommand) {
|
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());
|
throw ERROR_UNKNOWN_COMMAND.createWithContext(parse.getReader());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ 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.Collections;
|
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
|
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 Command<S> command;
|
||||||
private Predicate<S> requirement = s -> true;
|
private Predicate<S> requirement = s -> true;
|
||||||
private CommandNode<S> target;
|
private CommandNode<S> target;
|
||||||
private RedirectModifier<S> modifier = s -> Collections.singleton(s.getSource());
|
private RedirectModifier<S> modifier = null;
|
||||||
|
|
||||||
protected abstract T getThis();
|
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) {
|
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) {
|
public T redirect(final CommandNode<S> target, final RedirectModifier<S> modifier) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.mojang.brigadier.context;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
import com.mojang.brigadier.Command;
|
import com.mojang.brigadier.Command;
|
||||||
|
import com.mojang.brigadier.RedirectModifier;
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -15,8 +16,9 @@ public class CommandContext<S> {
|
||||||
private final Map<CommandNode<S>, StringRange> nodes;
|
private final Map<CommandNode<S>, StringRange> nodes;
|
||||||
private final StringRange range;
|
private final StringRange range;
|
||||||
private final CommandContext<S> child;
|
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.source = source;
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.arguments = arguments;
|
this.arguments = arguments;
|
||||||
|
@ -24,6 +26,11 @@ public class CommandContext<S> {
|
||||||
this.nodes = nodes;
|
this.nodes = nodes;
|
||||||
this.range = range;
|
this.range = range;
|
||||||
this.child = child;
|
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() {
|
public CommandContext<S> getChild() {
|
||||||
|
@ -88,6 +95,10 @@ public class CommandContext<S> {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RedirectModifier<S> getRedirectModifier() {
|
||||||
|
return modifier;
|
||||||
|
}
|
||||||
|
|
||||||
public StringRange getRange() {
|
public StringRange getRange() {
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.mojang.brigadier.context;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.mojang.brigadier.Command;
|
import com.mojang.brigadier.Command;
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.RedirectModifier;
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -15,6 +16,7 @@ public class CommandContextBuilder<S> {
|
||||||
private Command<S> command;
|
private Command<S> command;
|
||||||
private CommandContextBuilder<S> child;
|
private CommandContextBuilder<S> child;
|
||||||
private StringRange range;
|
private StringRange range;
|
||||||
|
private RedirectModifier<S> modifier = null;
|
||||||
|
|
||||||
public CommandContextBuilder(final CommandDispatcher<S> dispatcher, final S source, final int start) {
|
public CommandContextBuilder(final CommandDispatcher<S> dispatcher, final S source, final int start) {
|
||||||
this.dispatcher = dispatcher;
|
this.dispatcher = dispatcher;
|
||||||
|
@ -48,6 +50,7 @@ public class CommandContextBuilder<S> {
|
||||||
public CommandContextBuilder<S> withNode(final CommandNode<S> node, final StringRange range) {
|
public CommandContextBuilder<S> withNode(final CommandNode<S> node, final StringRange range) {
|
||||||
nodes.put(node, range);
|
nodes.put(node, range);
|
||||||
this.range = StringRange.encompassing(this.range, range);
|
this.range = StringRange.encompassing(this.range, range);
|
||||||
|
this.modifier = node.getRedirectModifier();
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +90,7 @@ public class CommandContextBuilder<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandContext<S> build(final String input) {
|
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() {
|
public CommandDispatcher<S> getDispatcher() {
|
||||||
|
|
|
@ -250,7 +250,7 @@ public class CommandDispatcherTest {
|
||||||
@Test
|
@Test
|
||||||
public void testExecuteRedirectedMultipleTimes() throws Exception {
|
public void testExecuteRedirectedMultipleTimes() throws Exception {
|
||||||
subject.register(literal("actual").executes(command));
|
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 String input = "redirected redirected actual";
|
||||||
final ParseResults<Object> parse = subject.parse(input, source);
|
final ParseResults<Object> parse = subject.parse(input, source);
|
||||||
|
|
|
@ -90,11 +90,11 @@ public class CommandDispatcherUsagesTest {
|
||||||
);
|
);
|
||||||
subject.register(
|
subject.register(
|
||||||
literal("j")
|
literal("j")
|
||||||
.redirect(subject.getRoot(), Collections::singleton)
|
.redirect(subject.getRoot())
|
||||||
);
|
);
|
||||||
subject.register(
|
subject.register(
|
||||||
literal("k")
|
literal("k")
|
||||||
.redirect(get("h"), Collections::singleton)
|
.redirect(get("h"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,6 @@ package com.mojang.brigadier.builder;
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
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.arguments.IntegerArgumentType.integer;
|
||||||
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
|
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
|
||||||
|
@ -37,7 +34,7 @@ public class ArgumentBuilderTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRedirect() throws Exception {
|
public void testRedirect() throws Exception {
|
||||||
final CommandNode<Object> target = mock(CommandNode.class);
|
final CommandNode<Object> target = mock(CommandNode.class);
|
||||||
builder.redirect(target, Collections::singleton);
|
builder.redirect(target);
|
||||||
assertThat(builder.getRedirect(), is(target));
|
assertThat(builder.getRedirect(), is(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,13 +42,13 @@ public class ArgumentBuilderTest {
|
||||||
public void testRedirect_withChild() throws Exception {
|
public void testRedirect_withChild() throws Exception {
|
||||||
final CommandNode<Object> target = mock(CommandNode.class);
|
final CommandNode<Object> target = mock(CommandNode.class);
|
||||||
builder.then(literal("foo"));
|
builder.then(literal("foo"));
|
||||||
builder.redirect(target, Collections::singleton);
|
builder.redirect(target);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testThen_withRedirect() throws Exception {
|
public void testThen_withRedirect() throws Exception {
|
||||||
final CommandNode<Object> target = mock(CommandNode.class);
|
final CommandNode<Object> target = mock(CommandNode.class);
|
||||||
builder.redirect(target, Collections::singleton);
|
builder.redirect(target);
|
||||||
builder.then(literal("foo"));
|
builder.then(literal("foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue