From 73d218c1549dfad218f9a425210a8bfd59f02fbd Mon Sep 17 00:00:00 2001 From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> Date: Fri, 6 Jun 2025 22:11:49 -0400 Subject: [PATCH] Improve command permission lookups This allows us to append to the vanilla permission check object to avoid having to look into a map. This also fixes non vanilla commands from technically being able to be skipped through permissions. --- .../brigadier/tree/CommandNode.java.patch | 19 --------------- .../commands/CommandSourceStack.java.patch | 17 ++----------- .../minecraft/commands/Commands.java.patch | 4 +++- .../commands/PermissionSource.java.patch | 24 +++++++++++++++++++ 4 files changed, 29 insertions(+), 35 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/commands/PermissionSource.java.patch diff --git a/paper-server/patches/sources/com/mojang/brigadier/tree/CommandNode.java.patch b/paper-server/patches/sources/com/mojang/brigadier/tree/CommandNode.java.patch index 2ceeeb760b..13c5dc9238 100644 --- a/paper-server/patches/sources/com/mojang/brigadier/tree/CommandNode.java.patch +++ b/paper-server/patches/sources/com/mojang/brigadier/tree/CommandNode.java.patch @@ -24,25 +24,6 @@ protected CommandNode(final Command command, final Predicate requirement, final CommandNode redirect, final RedirectModifier modifier, final boolean forks) { this.command = command; -@@ -61,7 +_,17 @@ - return modifier; - } - -- public boolean canUse(final S source) { -+ // CraftBukkit start -+ public synchronized boolean canUse(final S source) { -+ if (source instanceof final net.minecraft.commands.CommandSourceStack css) { -+ try { -+ css.currentCommand.put(Thread.currentThread(), this); // Paper - Thread Safe Vanilla Command permission checking -+ return this.requirement.test(source); -+ } finally { -+ css.currentCommand.remove(Thread.currentThread()); // Paper - Thread Safe Vanilla Command permission checking -+ } -+ } -+ // CraftBukkit end - return requirement.test(source); - } - @@ -151,6 +_,12 @@ protected abstract String getSortedKey(); diff --git a/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch b/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch index 2a3034b8db..ebf5edef1b 100644 --- a/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/CommandSourceStack.java.patch @@ -9,11 +9,10 @@ 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; -@@ -65,6 +_,8 @@ +@@ -65,6 +_,7 @@ private final Vec2 rotation; private final CommandSigningContext signingContext; private final TaskChainer chatMessageChainer; -+ public java.util.Map 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( @@ -49,19 +48,7 @@ public CommandSourceStack withRotation(Vec2 rotation) { return this.rotation.equals(rotation) ? this -@@ -393,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; } diff --git a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch index c0d21264fb..f8bbd89127 100644 --- a/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch +++ b/paper-server/patches/sources/net/minecraft/commands/Commands.java.patch @@ -12,7 +12,7 @@ AdvancementCommands.register(this.dispatcher); AttributeCommand.register(this.dispatcher, context); ExecuteCommand.register(this.dispatcher, context); -@@ -280,6 +_,40 @@ +@@ -280,6 +_,42 @@ PublishCommand.register(this.dispatcher); } @@ -20,6 +20,8 @@ + for (final CommandNode node : this.dispatcher.getRoot().getChildren()) { + if (node.getRequirement() == com.mojang.brigadier.builder.ArgumentBuilder.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 check) { ++ check.vanillaNode().set(node); + } + } + // Paper end - Vanilla command permission fixes diff --git a/paper-server/patches/sources/net/minecraft/commands/PermissionSource.java.patch b/paper-server/patches/sources/net/minecraft/commands/PermissionSource.java.patch new file mode 100644 index 0000000000..d71a268e02 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/commands/PermissionSource.java.patch @@ -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(@Override int requiredLevel) implements PermissionCheck { ++ public record Check(@Override int requiredLevel, java.util.concurrent.atomic.AtomicReference> vanillaNode) implements PermissionCheck { // 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 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); + } + }