mirror of
https://github.com/PaperMC/Paper.git
synced 2025-08-07 15:42:19 -07:00
1.21.6 dev
Co-authored-by: Bjarne Koll <git@lynxplay.dev> Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com> Co-authored-by: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Co-authored-by: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Co-authored-by: Noah van der Aa <ndvdaa@gmail.com> Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
This commit is contained in:
committed by
Nassim Jahnke
parent
39203a65e0
commit
a24f9b204c
@@ -1,24 +1,23 @@
|
||||
--- a/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -45,7 +_,7 @@
|
||||
@@ -47,7 +_,7 @@
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
-public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider {
|
||||
+public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider, io.papermc.paper.command.brigadier.PaperCommandSourceStack { // Paper - Brigadier API
|
||||
-public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, PermissionSource, SharedSuggestionProvider {
|
||||
+public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, PermissionSource, SharedSuggestionProvider, io.papermc.paper.command.brigadier.PaperCommandSourceStack { // Paper - Brigadier API
|
||||
public static final SimpleCommandExceptionType ERROR_NOT_PLAYER = new SimpleCommandExceptionType(Component.translatable("permissions.requires.player"));
|
||||
public static final SimpleCommandExceptionType ERROR_NOT_ENTITY = new SimpleCommandExceptionType(Component.translatable("permissions.requires.entity"));
|
||||
public final CommandSource source;
|
||||
@@ -63,6 +_,8 @@
|
||||
@@ -65,6 +_,7 @@
|
||||
private final Vec2 rotation;
|
||||
private final CommandSigningContext signingContext;
|
||||
private final TaskChainer chatMessageChainer;
|
||||
+ public java.util.Map<Thread, com.mojang.brigadier.tree.CommandNode> currentCommand = new java.util.concurrent.ConcurrentHashMap<>(); // CraftBukkit // Paper - Thread Safe Vanilla Command permission checking
|
||||
+ public boolean bypassSelectorPermissions = false; // Paper - add bypass for selector permissions
|
||||
|
||||
public CommandSourceStack(
|
||||
CommandSource source,
|
||||
@@ -188,6 +_,30 @@
|
||||
@@ -190,6 +_,30 @@
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,19 +48,7 @@
|
||||
public CommandSourceStack withRotation(Vec2 rotation) {
|
||||
return this.rotation.equals(rotation)
|
||||
? this
|
||||
@@ -391,9 +_,44 @@
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(int level) {
|
||||
+ // CraftBukkit start
|
||||
+ // Paper start - Thread Safe Vanilla Command permission checking
|
||||
+ com.mojang.brigadier.tree.CommandNode currentCommand = this.currentCommand.get(Thread.currentThread());
|
||||
+ if (currentCommand != null) {
|
||||
+ return this.hasPermission(level, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand));
|
||||
+ // Paper end - Thread Safe Vanilla Command permission checking
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
@@ -396,6 +_,32 @@
|
||||
return this.permissionLevel >= level;
|
||||
}
|
||||
|
||||
@@ -94,7 +81,7 @@
|
||||
public Vec3 getPosition() {
|
||||
return this.worldPosition;
|
||||
}
|
||||
@@ -498,20 +_,25 @@
|
||||
@@ -500,20 +_,25 @@
|
||||
Component component = Component.translatable("chat.type.admin", this.getDisplayName(), message).withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC);
|
||||
if (this.server.getGameRules().getBoolean(GameRules.RULE_SENDCOMMANDFEEDBACK)) {
|
||||
for (ServerPlayer serverPlayer : this.server.getPlayerList().getPlayers()) {
|
||||
@@ -123,7 +110,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,7 +_,7 @@
|
||||
@@ -524,7 +_,7 @@
|
||||
|
||||
@Override
|
||||
public Collection<String> getOnlinePlayerNames() {
|
||||
@@ -132,7 +119,7 @@
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -597,4 +_,16 @@
|
||||
@@ -604,4 +_,16 @@
|
||||
public boolean isSilent() {
|
||||
return this.silent;
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/commands/Commands.java
|
||||
+++ b/net/minecraft/commands/Commands.java
|
||||
@@ -150,6 +_,11 @@
|
||||
@@ -176,6 +_,11 @@
|
||||
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher<>();
|
||||
|
||||
public Commands(Commands.CommandSelection selection, CommandBuildContext context) {
|
||||
@@ -12,7 +12,7 @@
|
||||
AdvancementCommands.register(this.dispatcher);
|
||||
AttributeCommand.register(this.dispatcher, context);
|
||||
ExecuteCommand.register(this.dispatcher, context);
|
||||
@@ -251,6 +_,40 @@
|
||||
@@ -280,6 +_,42 @@
|
||||
PublishCommand.register(this.dispatcher);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
+ for (final CommandNode<CommandSourceStack> node : this.dispatcher.getRoot().getChildren()) {
|
||||
+ if (node.getRequirement() == com.mojang.brigadier.builder.ArgumentBuilder.<CommandSourceStack>defaultRequirement()) {
|
||||
+ node.requirement = stack -> stack.source == CommandSource.NULL || stack.getBukkitSender().hasPermission(org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(node));
|
||||
+ } else if (node.getRequirement() instanceof net.minecraft.commands.PermissionSource.Check<CommandSourceStack> check) {
|
||||
+ check.vanillaNode().set(node);
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Vanilla command permission fixes
|
||||
@@ -53,7 +55,7 @@
|
||||
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
|
||||
}
|
||||
|
||||
@@ -260,15 +_,58 @@
|
||||
@@ -289,9 +_,41 @@
|
||||
return new ParseResults<>(commandContextBuilder, parseResults.getReader(), parseResults.getExceptions());
|
||||
}
|
||||
|
||||
@@ -89,12 +91,16 @@
|
||||
+ }
|
||||
+
|
||||
+ public void performPrefixedCommand(CommandSourceStack source, String command, String label) {
|
||||
command = command.startsWith("/") ? command.substring(1) : command;
|
||||
command = trimOptionalPrefix(command);
|
||||
- this.performCommand(this.dispatcher.parse(command, source), command);
|
||||
+ this.performCommand(this.dispatcher.parse(command, source), command, label);
|
||||
+ // CraftBukkit end
|
||||
}
|
||||
|
||||
public static String trimOptionalPrefix(String command) {
|
||||
@@ -299,9 +_,20 @@
|
||||
}
|
||||
|
||||
public void performCommand(ParseResults<CommandSourceStack> parseResults, String command) {
|
||||
+ // CraftBukkit start
|
||||
+ this.performCommand(parseResults, command, command);
|
||||
@@ -114,7 +120,7 @@
|
||||
|
||||
try {
|
||||
if (contextChain != null) {
|
||||
@@ -280,9 +_,10 @@
|
||||
@@ -313,9 +_,10 @@
|
||||
);
|
||||
}
|
||||
} catch (Exception var12) {
|
||||
@@ -127,7 +133,7 @@
|
||||
StackTraceElement[] stackTrace = var12.getStackTrace();
|
||||
|
||||
for (int i = 0; i < Math.min(stackTrace.length, 3); i++) {
|
||||
@@ -308,18 +_,22 @@
|
||||
@@ -341,18 +_,22 @@
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -153,7 +159,7 @@
|
||||
if (min > 10) {
|
||||
mutableComponent.append(CommonComponents.ELLIPSIS);
|
||||
}
|
||||
@@ -331,7 +_,17 @@
|
||||
@@ -364,7 +_,17 @@
|
||||
}
|
||||
|
||||
mutableComponent.append(Component.translatable("command.context.here").withStyle(ChatFormatting.RED, ChatFormatting.ITALIC));
|
||||
@@ -172,13 +178,13 @@
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -359,26 +_,121 @@
|
||||
@@ -392,17 +_,110 @@
|
||||
}
|
||||
|
||||
public void sendCommands(ServerPlayer player) {
|
||||
+ // Paper start - Send empty commands if tab completion is disabled
|
||||
+ if (org.spigotmc.SpigotConfig.tabComplete < 0) {
|
||||
+ player.connection.send(new ClientboundCommandsPacket(new RootCommandNode<>()));
|
||||
+ player.connection.send(new ClientboundCommandsPacket(new RootCommandNode<>(), COMMAND_NODE_INSPECTOR));
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Send empty commands if tab completion is disabled
|
||||
@@ -203,11 +209,11 @@
|
||||
+
|
||||
+ private void sendAsync(ServerPlayer player, java.util.Collection<CommandNode<CommandSourceStack>> dispatcherRootChildren) {
|
||||
+ // Paper end - Perf: Async command map building
|
||||
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newHashMap();
|
||||
RootCommandNode<SharedSuggestionProvider> rootCommandNode = new RootCommandNode<>();
|
||||
Map<CommandNode<CommandSourceStack>, CommandNode<CommandSourceStack>> map = new HashMap<>();
|
||||
RootCommandNode<CommandSourceStack> rootCommandNode = new RootCommandNode<>();
|
||||
map.put(this.dispatcher.getRoot(), rootCommandNode);
|
||||
- this.fillUsableCommands(this.dispatcher.getRoot(), rootCommandNode, player.createCommandSourceStack(), map);
|
||||
+ this.fillUsableCommands(dispatcherRootChildren, rootCommandNode, player.createCommandSourceStack(), map); // Paper - Perf: Async command map building; pass copy of children
|
||||
- fillUsableCommands(this.dispatcher.getRoot(), rootCommandNode, player.createCommandSourceStack(), map);
|
||||
+ fillUsableCommands(dispatcherRootChildren, rootCommandNode, player.createCommandSourceStack(), map); // Paper - Perf: Async command map building; pass copy of children
|
||||
+
|
||||
+ java.util.Collection<String> bukkit = new java.util.LinkedHashSet<>();
|
||||
+ for (CommandNode node : rootCommandNode.getChildren()) {
|
||||
@@ -216,11 +222,11 @@
|
||||
+ // Paper start - Perf: Async command map building
|
||||
+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, false).callEvent(); // Paper - Brigadier API
|
||||
+ net.minecraft.server.MinecraftServer.getServer().execute(() -> {
|
||||
+ runSync(player, bukkit, rootCommandNode);
|
||||
+ runSync(player, bukkit, rootCommandNode);
|
||||
+ });
|
||||
+ }
|
||||
+
|
||||
+ private void runSync(ServerPlayer player, java.util.Collection<String> bukkit, RootCommandNode<SharedSuggestionProvider> rootCommandNode) {
|
||||
+ private void runSync(ServerPlayer player, java.util.Collection<String> bukkit, RootCommandNode<CommandSourceStack> rootCommandNode) {
|
||||
+ // Paper end - Perf: Async command map building
|
||||
+ new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent<CommandSourceStack>(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, true).callEvent(); // Paper - Brigadier API
|
||||
+ org.bukkit.event.player.PlayerCommandSendEvent event = new org.bukkit.event.player.PlayerCommandSendEvent(player.getBukkitEntity(), new java.util.LinkedHashSet<>(bukkit));
|
||||
@@ -233,28 +239,21 @@
|
||||
+ }
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+
|
||||
player.connection.send(new ClientboundCommandsPacket(rootCommandNode));
|
||||
player.connection.send(new ClientboundCommandsPacket(rootCommandNode, COMMAND_NODE_INSPECTOR));
|
||||
}
|
||||
|
||||
private void fillUsableCommands(
|
||||
- CommandNode<CommandSourceStack> rootCommandSource,
|
||||
+ java.util.Collection<CommandNode<CommandSourceStack>> children, // Paper - Perf: Async command map building; pass copy of children
|
||||
CommandNode<SharedSuggestionProvider> rootSuggestion,
|
||||
CommandSourceStack source,
|
||||
Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> commandNodeToSuggestionNode
|
||||
) {
|
||||
- for (CommandNode<CommandSourceStack> commandNode : rootCommandSource.getChildren()) {
|
||||
+ for (CommandNode<CommandSourceStack> commandNode : children) { // Paper - Perf: Async command map building; pass copy of children
|
||||
- private static <S> void fillUsableCommands(CommandNode<S> root, CommandNode<S> current, S source, Map<CommandNode<S>, CommandNode<S>> output) {
|
||||
- for (CommandNode<S> commandNode : root.getChildren()) {
|
||||
+ private static <S> void fillUsableCommands(java.util.Collection<CommandNode<S>> children, CommandNode<S> current, S source, Map<CommandNode<S>, CommandNode<S>> output) { // Paper - Perf: Async command map building; pass copy of children
|
||||
+ for (CommandNode<S> commandNode : children) { // Paper - Perf: Async command map building; pass copy of children
|
||||
+ // Paper start - Brigadier API
|
||||
+ if (commandNode.clientNode != null) {
|
||||
+ commandNode = commandNode.clientNode;
|
||||
+ }
|
||||
+ // Paper end - Brigadier API
|
||||
+ if (!org.spigotmc.SpigotConfig.sendNamespaced && commandNode.getName().contains(":")) continue; // Spigot
|
||||
+ if (commandNode.wrappedCached != null && commandNode.wrappedCached.apiCommandMeta != null && commandNode.wrappedCached.apiCommandMeta.serverSideOnly()) continue; // Paper
|
||||
if (commandNode.canUse(source)) {
|
||||
ArgumentBuilder<SharedSuggestionProvider, ?> argumentBuilder = (ArgumentBuilder) commandNode.createBuilder();
|
||||
ArgumentBuilder<S, ?> argumentBuilder = commandNode.createBuilder();
|
||||
+ // Paper start
|
||||
+ /*
|
||||
+ Because of how commands can be yeeted right left and center due to bad bukkit practices
|
||||
@@ -271,41 +270,34 @@
|
||||
+ - Do this :)
|
||||
+ */
|
||||
+ // Is there an invalid command redirect?
|
||||
+ if (argumentBuilder.getRedirect() != null && commandNodeToSuggestionNode.get(argumentBuilder.getRedirect()) == null) {
|
||||
+ if (argumentBuilder.getRedirect() != null && output.get(argumentBuilder.getRedirect()) == null) {
|
||||
+ // Create the argument builder with the same values as the specified node, but with a different literal and populated children
|
||||
+
|
||||
+ final CommandNode<SharedSuggestionProvider> redirect = argumentBuilder.getRedirect();
|
||||
+ final CommandNode<S> redirect = argumentBuilder.getRedirect();
|
||||
+ // Diff copied from LiteralCommand#createBuilder
|
||||
+ final com.mojang.brigadier.builder.LiteralArgumentBuilder<SharedSuggestionProvider> builder = com.mojang.brigadier.builder.LiteralArgumentBuilder.literal(commandNode.getName());
|
||||
+ final com.mojang.brigadier.builder.LiteralArgumentBuilder<S> builder = com.mojang.brigadier.builder.LiteralArgumentBuilder.literal(commandNode.getName());
|
||||
+ builder.requires(redirect.getRequirement());
|
||||
+ // builder.forward(redirect.getRedirect(), redirect.getRedirectModifier(), redirect.isFork()); We don't want to migrate the forward, since it's invalid.
|
||||
+ if (redirect.getCommand() != null) {
|
||||
+ builder.executes(redirect.getCommand());
|
||||
+ }
|
||||
+ // Diff copied from LiteralCommand#createBuilder
|
||||
+ for (final CommandNode<SharedSuggestionProvider> child : redirect.getChildren()) {
|
||||
+ for (final CommandNode<S> child : redirect.getChildren()) {
|
||||
+ builder.then(child);
|
||||
+ }
|
||||
+
|
||||
+ argumentBuilder = builder;
|
||||
+ }
|
||||
+ // Paper end
|
||||
argumentBuilder.requires(suggestions -> true);
|
||||
- if (argumentBuilder.getCommand() != null) {
|
||||
- argumentBuilder.executes(commandContext -> 0);
|
||||
- }
|
||||
+ // Paper - don't replace Command instance on suggestion node
|
||||
+ // we want the exact command instance to be used for equality checks
|
||||
+ // when assigning serialization ids to each command node
|
||||
|
||||
if (argumentBuilder instanceof RequiredArgumentBuilder requiredArgumentBuilder
|
||||
&& requiredArgumentBuilder.getSuggestionsProvider() != null) {
|
||||
@@ -393,7 +_,7 @@
|
||||
commandNodeToSuggestionNode.put(commandNode, commandNode1);
|
||||
rootSuggestion.addChild(commandNode1);
|
||||
if (argumentBuilder.getRedirect() != null) {
|
||||
argumentBuilder.redirect(output.get(argumentBuilder.getRedirect()));
|
||||
}
|
||||
@@ -411,7 +_,7 @@
|
||||
output.put(commandNode, commandNode1);
|
||||
current.addChild(commandNode1);
|
||||
if (!commandNode.getChildren().isEmpty()) {
|
||||
- this.fillUsableCommands(commandNode, commandNode1, source, commandNodeToSuggestionNode);
|
||||
+ this.fillUsableCommands(commandNode.getChildren(), commandNode1, source, commandNodeToSuggestionNode); // Paper - Perf: Async command map building; pass copy of children
|
||||
- fillUsableCommands(commandNode, commandNode1, source, output);
|
||||
+ fillUsableCommands(commandNode.getChildren(), commandNode1, source, output); // Paper - Perf: Async command map building; pass copy of children
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,24 @@
|
||||
--- a/net/minecraft/commands/PermissionSource.java
|
||||
+++ b/net/minecraft/commands/PermissionSource.java
|
||||
@@ -9,9 +_,20 @@
|
||||
return this.hasPermission(2);
|
||||
}
|
||||
|
||||
- public record Check<T extends PermissionSource>(@Override int requiredLevel) implements PermissionCheck<T> {
|
||||
+ public record Check<T extends PermissionSource>(@Override int requiredLevel, java.util.concurrent.atomic.AtomicReference<com.mojang.brigadier.tree.CommandNode<CommandSourceStack>> vanillaNode) implements PermissionCheck<T> { // Paper
|
||||
+ // Paper start - Vanilla Command permission checking
|
||||
+ public Check(int requiredLevel) {
|
||||
+ this(requiredLevel, new java.util.concurrent.atomic.AtomicReference<>());
|
||||
+ }
|
||||
+ // Paper end - Vanilla Command permission checking
|
||||
@Override
|
||||
public boolean test(T source) {
|
||||
+ // Paper start - Vanilla Command permission checking
|
||||
+ com.mojang.brigadier.tree.CommandNode<CommandSourceStack> currentCommand = vanillaNode.get();
|
||||
+ if (currentCommand != null && source instanceof CommandSourceStack commandSourceStack) {
|
||||
+ return commandSourceStack.hasPermission(this.requiredLevel, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand));
|
||||
+ }
|
||||
+ // Paper end - Vanilla Command permission checking
|
||||
return source.hasPermission(this.requiredLevel);
|
||||
}
|
||||
}
|
@@ -16,7 +16,7 @@
|
||||
if (entitySelector.getMaxResults() > 1 && this.single) {
|
||||
if (this.playersOnly) {
|
||||
reader.setCursor(0);
|
||||
@@ -129,7 +_,12 @@
|
||||
@@ -129,7 +_,13 @@
|
||||
if (context.getSource() instanceof SharedSuggestionProvider sharedSuggestionProvider) {
|
||||
StringReader stringReader = new StringReader(builder.getInput());
|
||||
stringReader.setCursor(builder.getStart());
|
||||
@@ -24,7 +24,8 @@
|
||||
+ // Paper start - Fix EntityArgument permissions
|
||||
+ final boolean permission = sharedSuggestionProvider instanceof CommandSourceStack stack
|
||||
+ ? stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector")
|
||||
+ : sharedSuggestionProvider.hasPermission(2);
|
||||
+ // Only CommandSourceStack implements SharedSuggestionProvider. If *somehow* anything else ends up here, try to query its permission level, otherwise yield false.
|
||||
+ : (sharedSuggestionProvider instanceof final net.minecraft.commands.PermissionSource permissionSource && permissionSource.hasPermission(2));
|
||||
+ EntitySelectorParser entitySelectorParser = new EntitySelectorParser(stringReader, permission);
|
||||
+ // Paper end - Fix EntityArgument permissions
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
}
|
||||
|
||||
private void checkPermissions(CommandSourceStack source) throws CommandSyntaxException {
|
||||
- if (this.usesSelector && !source.hasPermission(2)) {
|
||||
- if (this.usesSelector && !source.allowsSelectors()) {
|
||||
+ if (!source.bypassSelectorPermissions && (this.usesSelector && !source.hasPermission(2, "minecraft.command.selector"))) { // CraftBukkit // Paper - add bypass for selector perms
|
||||
throw EntityArgument.ERROR_SELECTORS_NOT_ALLOWED.create();
|
||||
}
|
||||
|
@@ -9,7 +9,7 @@
|
||||
+ return stack.bypassSelectorPermissions || stack.hasPermission(2, "minecraft.command.selector");
|
||||
+ }
|
||||
+ // Paper end - Fix EntityArgument permissions
|
||||
return suggestionProvider instanceof SharedSuggestionProvider sharedSuggestionProvider && sharedSuggestionProvider.hasPermission(2);
|
||||
return suggestionProvider instanceof PermissionSource permissionSource && permissionSource.allowsSelectors();
|
||||
}
|
||||
|
||||
@@ -198,8 +_,10 @@
|
||||
|
Reference in New Issue
Block a user