Mirror von
https://github.com/PaperMC/Velocity.git
synchronisiert 2024-11-16 21:10:30 +01:00
Fix StackOverflowError in CommandGraphInjector when using redirects (#1335)
Dieser Commit ist enthalten in:
Ursprung
1c36b66dcb
Commit
deacdb6228
@ -27,6 +27,8 @@ import com.mojang.brigadier.tree.CommandNode;
|
|||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import com.mojang.brigadier.tree.RootCommandNode;
|
import com.mojang.brigadier.tree.RootCommandNode;
|
||||||
import com.velocitypowered.proxy.command.brigadier.VelocityArgumentCommandNode;
|
import com.velocitypowered.proxy.command.brigadier.VelocityArgumentCommandNode;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
import org.checkerframework.checker.lock.qual.GuardedBy;
|
import org.checkerframework.checker.lock.qual.GuardedBy;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
@ -66,6 +68,7 @@ public final class CommandGraphInjector<S> {
|
|||||||
public void inject(final RootCommandNode<S> dest, final S source) {
|
public void inject(final RootCommandNode<S> dest, final S source) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
|
final Map<CommandNode<S>, CommandNode<S>> done = new IdentityHashMap<>();
|
||||||
final RootCommandNode<S> origin = this.dispatcher.getRoot();
|
final RootCommandNode<S> origin = this.dispatcher.getRoot();
|
||||||
final CommandContextBuilder<S> rootContext =
|
final CommandContextBuilder<S> rootContext =
|
||||||
new CommandContextBuilder<>(this.dispatcher, source, origin, 0);
|
new CommandContextBuilder<>(this.dispatcher, source, origin, 0);
|
||||||
@ -88,7 +91,7 @@ public final class CommandGraphInjector<S> {
|
|||||||
VelocityCommands.getArgumentsNode(asLiteral);
|
VelocityCommands.getArgumentsNode(asLiteral);
|
||||||
if (argsNode == null) {
|
if (argsNode == null) {
|
||||||
// This literal is associated to a BrigadierCommand, filter normally.
|
// This literal is associated to a BrigadierCommand, filter normally.
|
||||||
this.copyChildren(node, copy, source);
|
this.copyChildren(node, copy, source, done);
|
||||||
} else {
|
} else {
|
||||||
// Copy all children nodes (arguments node and hints)
|
// Copy all children nodes (arguments node and hints)
|
||||||
for (final CommandNode<S> child : node.getChildren()) {
|
for (final CommandNode<S> child : node.getChildren()) {
|
||||||
@ -102,7 +105,10 @@ public final class CommandGraphInjector<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable CommandNode<S> filterNode(final CommandNode<S> node, final S source) {
|
private @Nullable CommandNode<S> filterNode(final CommandNode<S> node, final S source, final Map<CommandNode<S>, CommandNode<S>> done) {
|
||||||
|
if (done.containsKey(node)) {
|
||||||
|
return done.get(node);
|
||||||
|
}
|
||||||
// We only check the non-context requirement when filtering alias nodes.
|
// We only check the non-context requirement when filtering alias nodes.
|
||||||
// Otherwise, we would need to manually craft context builder and reader instances,
|
// Otherwise, we would need to manually craft context builder and reader instances,
|
||||||
// which is both incorrect and inefficient. The reason why we can do so for alias
|
// which is both incorrect and inefficient. The reason why we can do so for alias
|
||||||
@ -116,18 +122,18 @@ public final class CommandGraphInjector<S> {
|
|||||||
// Redirects to non-Brigadier commands are not supported. Luckily,
|
// Redirects to non-Brigadier commands are not supported. Luckily,
|
||||||
// we don't expose the root node to API users, so they can't access
|
// we don't expose the root node to API users, so they can't access
|
||||||
// nodes associated to other commands.
|
// nodes associated to other commands.
|
||||||
final CommandNode<S> target = this.filterNode(node.getRedirect(), source);
|
final CommandNode<S> target = this.filterNode(node.getRedirect(), source, done);
|
||||||
builder.forward(target, builder.getRedirectModifier(), builder.isFork());
|
builder.forward(target, builder.getRedirectModifier(), builder.isFork());
|
||||||
}
|
}
|
||||||
final CommandNode<S> result = builder.build();
|
final CommandNode<S> result = builder.build();
|
||||||
this.copyChildren(node, result, source);
|
done.put(node, result);
|
||||||
|
this.copyChildren(node, result, source, done);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyChildren(final CommandNode<S> parent, final CommandNode<S> dest,
|
private void copyChildren(final CommandNode<S> parent, final CommandNode<S> dest, final S source, final Map<CommandNode<S>, CommandNode<S>> done) {
|
||||||
final S source) {
|
|
||||||
for (final CommandNode<S> child : parent.getChildren()) {
|
for (final CommandNode<S> child : parent.getChildren()) {
|
||||||
final CommandNode<S> filtered = this.filterNode(child, source);
|
final CommandNode<S> filtered = this.filterNode(child, source, done);
|
||||||
if (filtered != null) {
|
if (filtered != null) {
|
||||||
dest.addChild(filtered);
|
dest.addChild(filtered);
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren