Distinguish forked redirect vs regular redirect

This commit is contained in:
Nathan Adams 2018-01-17 12:13:29 +01:00
parent 72817f8dd7
commit 9fbf7bfe42
15 changed files with 108 additions and 101 deletions

View file

@ -3,7 +3,7 @@ import groovy.io.FileType
apply plugin: 'java-library'
apply plugin: 'maven'
version = '0.1.18'
version = '0.1.19'
group = 'com.mojang'
task wrapper(type: Wrapper) {

View file

@ -101,6 +101,7 @@ public class CommandDispatcher<S> {
final CommandContext<S> context = contexts.get(i);
final CommandContext<S> child = context.getChild();
if (child != null) {
forked |= context.isForked();
if (!child.getNodes().isEmpty()) {
foundCommand = true;
final RedirectModifier<S> modifier = context.getRedirectModifier();
@ -112,9 +113,6 @@ public class CommandDispatcher<S> {
} else {
final Collection<S> results = modifier.apply(context);
if (!results.isEmpty()) {
if (results.size() > 1) {
forked = true;
}
if (next == null) {
next = new ArrayList<>(results.size());
}

View file

@ -2,10 +2,13 @@ package com.mojang.brigadier.builder;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.RedirectModifier;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Predicate;
public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
@ -14,6 +17,7 @@ public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
private Predicate<S> requirement = s -> true;
private CommandNode<S> target;
private RedirectModifier<S> modifier = null;
private boolean forks;
protected abstract T getThis();
@ -56,15 +60,24 @@ public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
}
public T redirect(final CommandNode<S> target) {
return redirect(target, null);
return forward(target, null, false);
}
public T redirect(final CommandNode<S> target, final RedirectModifier<S> modifier) {
public T redirect(final CommandNode<S> target, final Function<CommandContext<S>, S> modifier) {
return forward(target, modifier == null ? null : o -> Collections.singleton(modifier.apply(o)), false);
}
public T fork(final CommandNode<S> target, final RedirectModifier<S> modifier) {
return forward(target, modifier, true);
}
public T forward(final CommandNode<S> target, final RedirectModifier<S> modifier, final boolean fork) {
if (!arguments.getChildren().isEmpty()) {
throw new IllegalStateException("Cannot redirect a node with children");
throw new IllegalStateException("Cannot forward a node with children");
}
this.target = target;
this.modifier = modifier;
this.forks = fork;
return getThis();
}
@ -76,5 +89,9 @@ public abstract class ArgumentBuilder<S, T extends ArgumentBuilder<S, T>> {
return modifier;
}
public boolean isFork() {
return forks;
}
public abstract CommandNode<S> build();
}

View file

@ -25,7 +25,7 @@ public class LiteralArgumentBuilder<S> extends ArgumentBuilder<S, LiteralArgumen
@Override
public LiteralCommandNode<S> build() {
final LiteralCommandNode<S> result = new LiteralCommandNode<>(getLiteral(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier());
final LiteralCommandNode<S> result = new LiteralCommandNode<>(getLiteral(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork());
for (final CommandNode<S> argument : getArguments()) {
result.addChild(argument);

View file

@ -42,7 +42,7 @@ public class RequiredArgumentBuilder<S, T> extends ArgumentBuilder<S, RequiredAr
}
public ArgumentCommandNode<S, T> build() {
final ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), getSuggestionsProvider());
final ArgumentCommandNode<S, T> result = new ArgumentCommandNode<>(getName(), getType(), getCommand(), getRequirement(), getRedirect(), getRedirectModifier(), isFork(), getSuggestionsProvider());
for (final CommandNode<S> argument : getArguments()) {
result.addChild(argument);

View file

@ -17,8 +17,9 @@ public class CommandContext<S> {
private final StringRange range;
private final CommandContext<S> child;
private final RedirectModifier<S> modifier;
private final boolean forks;
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) {
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, boolean forks) {
this.source = source;
this.input = input;
this.arguments = arguments;
@ -27,13 +28,14 @@ public class CommandContext<S> {
this.range = range;
this.child = child;
this.modifier = modifier;
this.forks = forks;
}
public CommandContext<S> copyFor(final S source) {
if (this.source == source) {
return this;
}
return new CommandContext<>(source, input, arguments, command, nodes, range, child, modifier);
return new CommandContext<>(source, input, arguments, command, nodes, range, child, modifier, forks);
}
public CommandContext<S> getChild() {
@ -113,4 +115,8 @@ public class CommandContext<S> {
public Map<CommandNode<S>, StringRange> getNodes() {
return nodes;
}
public boolean isForked() {
return forks;
}
}

View file

@ -17,6 +17,7 @@ public class CommandContextBuilder<S> {
private CommandContextBuilder<S> child;
private StringRange range;
private RedirectModifier<S> modifier = null;
private boolean forks;
public CommandContextBuilder(final CommandDispatcher<S> dispatcher, final S source, final int start) {
this.dispatcher = dispatcher;
@ -51,6 +52,7 @@ public class CommandContextBuilder<S> {
nodes.put(node, range);
this.range = StringRange.encompassing(this.range, range);
this.modifier = node.getRedirectModifier();
this.forks = node.isFork();
return this;
}
@ -61,6 +63,7 @@ public class CommandContextBuilder<S> {
copy.nodes.putAll(nodes);
copy.child = child;
copy.range = range;
copy.forks = forks;
return copy;
}
@ -90,7 +93,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), modifier);
return new CommandContext<>(source, input, arguments, command, nodes, range, child == null ? null : child.build(input), modifier, forks);
}
public CommandDispatcher<S> getDispatcher() {

View file

@ -24,8 +24,8 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
private final ArgumentType<T> type;
private final SuggestionProvider<S> customSuggestions;
public ArgumentCommandNode(final String name, final ArgumentType<T> type, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final SuggestionProvider<S> customSuggestions) {
super(command, requirement, redirect, modifier);
public ArgumentCommandNode(final String name, final ArgumentType<T> type, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks, final SuggestionProvider<S> customSuggestions) {
super(command, requirement, redirect, modifier, forks);
this.name = name;
this.type = type;
this.customSuggestions = customSuggestions;
@ -72,7 +72,7 @@ public class ArgumentCommandNode<S, T> extends CommandNode<S> {
public RequiredArgumentBuilder<S, T> createBuilder() {
final RequiredArgumentBuilder<S, T> builder = RequiredArgumentBuilder.argument(name, type);
builder.requires(getRequirement());
builder.redirect(getRedirect(), getRedirectModifier());
builder.forward(getRedirect(), getRedirectModifier(), isFork());
builder.suggests(customSuggestions);
if (getCommand() != null) {
builder.executes(getCommand());

View file

@ -27,13 +27,15 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
private final Predicate<S> requirement;
private final CommandNode<S> redirect;
private final RedirectModifier<S> modifier;
private final boolean forks;
private Command<S> command;
protected CommandNode(final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier) {
protected CommandNode(final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
this.command = command;
this.requirement = requirement;
this.redirect = redirect;
this.modifier = modifier;
this.forks = forks;
}
public Command<S> getCommand() {
@ -144,4 +146,8 @@ public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
.compare(getSortedKey(), o.getSortedKey())
.result();
}
public boolean isFork() {
return forks;
}
}

View file

@ -20,8 +20,8 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
private final String literal;
public LiteralCommandNode(final String literal, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier) {
super(command, requirement, redirect, modifier);
public LiteralCommandNode(final String literal, final Command<S> command, final Predicate<S> requirement, final CommandNode<S> redirect, final RedirectModifier<S> modifier, final boolean forks) {
super(command, requirement, redirect, modifier, forks);
this.literal = literal;
}
@ -86,7 +86,7 @@ public class LiteralCommandNode<S> extends CommandNode<S> {
public LiteralArgumentBuilder<S> createBuilder() {
final LiteralArgumentBuilder<S> builder = LiteralArgumentBuilder.literal(this.literal);
builder.requires(getRequirement());
builder.redirect(getRedirect(), getRedirectModifier());
builder.forward(getRedirect(), getRedirectModifier(), isFork());
if (getCommand() != null) {
builder.executes(getCommand());
}

View file

@ -13,7 +13,7 @@ import java.util.concurrent.CompletableFuture;
public class RootCommandNode<S> extends CommandNode<S> {
public RootCommandNode() {
super(null, c -> true, null, s -> Collections.singleton(s.getSource()));
super(null, c -> true, null, s -> Collections.singleton(s.getSource()), false);
}
@Override

View file

@ -281,7 +281,7 @@ public class CommandDispatcherTest {
when(modifier.apply(argThat(hasProperty("source", is(source))))).thenReturn(Lists.newArrayList(source1, source2));
subject.register(literal("actual").executes(command));
subject.register(literal("redirected").redirect(subject.getRoot(), modifier));
subject.register(literal("redirected").redirect(subject.getRoot()));
final String input = "redirected actual";
final ParseResults<Object> parse = subject.parse(input, source);

View file

@ -0,0 +1,57 @@
package com.mojang.brigadier.benchmarks;
import com.google.common.collect.Lists;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import java.util.concurrent.TimeUnit;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
@State(Scope.Benchmark)
public class ExecuteBenchmarks {
private CommandDispatcher<Object> dispatcher;
private ParseResults<Object> simple;
private ParseResults<Object> singleRedirect;
private ParseResults<Object> forkedRedirect;
@Setup
public void setup() {
dispatcher = new CommandDispatcher<>();
dispatcher.register(literal("command").executes(c -> 0));
dispatcher.register(literal("redirect").redirect(dispatcher.getRoot()));
dispatcher.register(literal("fork").fork(dispatcher.getRoot(), o -> Lists.newArrayList(new Object(), new Object(), new Object())));
simple = dispatcher.parse("command", new Object());
singleRedirect = dispatcher.parse("redirect command", new Object());
forkedRedirect = dispatcher.parse("fork command", new Object());
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void execute_simple() throws CommandSyntaxException {
dispatcher.execute(simple);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void execute_single_redirect() throws CommandSyntaxException {
dispatcher.execute(singleRedirect);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void execute_forked_redirect() throws CommandSyntaxException {
dispatcher.execute(forkedRedirect);
}
}

View file

@ -1,44 +0,0 @@
package com.mojang.brigadier.benchmarks;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.tree.LiteralCommandNode;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import java.util.concurrent.TimeUnit;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
@State(Scope.Benchmark)
public class RedirectedCommand {
private CommandDispatcher<Object> dispatcher;
private ParseResults<Object> parse;
public static void main(final String[] args) throws CommandSyntaxException {
final RedirectedCommand command = new RedirectedCommand();
command.setup();
command.execute();
}
@Setup
public void setup() {
dispatcher = new CommandDispatcher<>();
dispatcher.register(literal("command").executes(c -> 0));
dispatcher.register(literal("redirect").redirect(dispatcher.getRoot()));
parse = dispatcher.parse("redirect command", new Object());
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void execute() throws CommandSyntaxException {
dispatcher.execute(parse);
}
}

View file

@ -1,36 +0,0 @@
package com.mojang.brigadier.benchmarks;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import java.util.concurrent.TimeUnit;
import static com.mojang.brigadier.builder.LiteralArgumentBuilder.literal;
@State(Scope.Benchmark)
public class SimpleCommand {
private CommandDispatcher<Object> dispatcher;
private ParseResults<Object> parse;
@Setup
public void setup() {
dispatcher = new CommandDispatcher<>();
dispatcher.register(literal("command").executes(c -> 0));
parse = dispatcher.parse("command", new Object());
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void execute() throws CommandSyntaxException {
dispatcher.execute(parse);
}
}