Distinguish forked redirect vs regular redirect
This commit is contained in:
parent
72817f8dd7
commit
9fbf7bfe42
15 changed files with 108 additions and 101 deletions
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue