diff --git a/Spigot-Server-Patches/0543-Thread-Safe-Vanilla-Command-permission-checking.patch b/Spigot-Server-Patches/0543-Thread-Safe-Vanilla-Command-permission-checking.patch new file mode 100644 index 000000000..27c4d1907 --- /dev/null +++ b/Spigot-Server-Patches/0543-Thread-Safe-Vanilla-Command-permission-checking.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 11 Jul 2020 03:54:28 -0400 +Subject: [PATCH] Thread Safe Vanilla Command permission checking + +Datapacks check this on load and are built concurrently. This was breaking them badly due +to race conditions. + +Plus, .canUse we want to be safe for async anyways. + +diff --git a/src/main/java/com/mojang/brigadier/tree/CommandNode.java b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +index 5e3fc338b0fe69a74465567e69721bc28c64dd17..ca0d664487a65a4768f0e65af6a320fd1875de8f 100644 +--- a/src/main/java/com/mojang/brigadier/tree/CommandNode.java ++++ b/src/main/java/com/mojang/brigadier/tree/CommandNode.java +@@ -75,10 +75,10 @@ public abstract class CommandNode implements Comparable> { + // CraftBukkit start + if (source instanceof CommandListenerWrapper) { + try { +- ((CommandListenerWrapper) source).currentCommand = this; ++ ((CommandListenerWrapper) source).currentCommand.set(this); // Paper + return requirement.test(source); + } finally { +- ((CommandListenerWrapper) source).currentCommand = null; ++ ((CommandListenerWrapper) source).currentCommand.set(null); // Paper + } + } + // CraftBukkit end +diff --git a/src/main/java/net/minecraft/server/CommandListenerWrapper.java b/src/main/java/net/minecraft/server/CommandListenerWrapper.java +index fa0f247e51c20ea0e3cbaccbc8dbb2a153d6121f..a4995ddc82100bc460cd2021dcfa8389769d5da0 100644 +--- a/src/main/java/net/minecraft/server/CommandListenerWrapper.java ++++ b/src/main/java/net/minecraft/server/CommandListenerWrapper.java +@@ -33,7 +33,7 @@ public class CommandListenerWrapper implements ICompletionProvider, com.destroys + private final ResultConsumer l; + private final ArgumentAnchor.Anchor m; + private final Vec2F n; +- public CommandNode currentCommand; // CraftBukkit ++ public ThreadLocal currentCommand = new ThreadLocal<>(); // CraftBukkit // Paper + + public CommandListenerWrapper(ICommandListener icommandlistener, Vec3D vec3d, Vec2F vec2f, WorldServer worldserver, int i, String s, IChatBaseComponent ichatbasecomponent, MinecraftServer minecraftserver, @Nullable Entity entity) { + this(icommandlistener, vec3d, vec2f, worldserver, i, s, ichatbasecomponent, minecraftserver, entity, false, (commandcontext, flag, j) -> { +@@ -143,8 +143,11 @@ public class CommandListenerWrapper implements ICompletionProvider, com.destroys + @Override + public boolean hasPermission(int i) { + // CraftBukkit start ++ // Paper start - fix concurrency issue ++ CommandNode currentCommand = this.currentCommand.get(); + if (currentCommand != null) { + return hasPermission(i, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand)); ++ // Paper end + } + // CraftBukkit end +