--- a/net/minecraft/commands/CommandSourceStack.java
+++ b/net/minecraft/commands/CommandSourceStack.java
@@ -1,7 +1,6 @@
 package net.minecraft.commands;
 
 import com.google.common.collect.Lists;
-import com.mojang.brigadier.CommandDispatcher;
 import com.mojang.brigadier.Message;
 import com.mojang.brigadier.context.CommandContext;
 import com.mojang.brigadier.exceptions.CommandExceptionType;
@@ -10,6 +9,7 @@
 import com.mojang.brigadier.suggestion.Suggestions;
 import com.mojang.brigadier.suggestion.SuggestionsBuilder;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
@@ -26,6 +26,7 @@
 import net.minecraft.network.chat.ChatType;
 import net.minecraft.network.chat.Component;
 import net.minecraft.network.chat.ComponentUtils;
+import net.minecraft.network.chat.MutableComponent;
 import net.minecraft.network.chat.OutgoingChatMessage;
 import net.minecraft.resources.ResourceKey;
 import net.minecraft.resources.ResourceLocation;
@@ -42,8 +43,9 @@
 import net.minecraft.world.level.dimension.DimensionType;
 import net.minecraft.world.phys.Vec2;
 import net.minecraft.world.phys.Vec3;
+import com.mojang.brigadier.tree.CommandNode; // CraftBukkit
 
-public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider {
+public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, 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;
@@ -61,52 +63,14 @@
     private final Vec2 rotation;
     private final CommandSigningContext signingContext;
     private final TaskChainer chatMessageChainer;
+    public java.util.Map<Thread, 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 output,
-        Vec3 pos,
-        Vec2 rot,
-        ServerLevel world,
-        int level,
-        String name,
-        Component displayName,
-        MinecraftServer server,
-        @Nullable Entity entity
-    ) {
-        this(
-            output,
-            pos,
-            rot,
-            world,
-            level,
-            name,
-            displayName,
-            server,
-            entity,
-            false,
-            CommandResultCallback.EMPTY,
-            EntityAnchorArgument.Anchor.FEET,
-            CommandSigningContext.ANONYMOUS,
-            TaskChainer.immediate(server)
-        );
+    public CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity) {
+        this(output, pos, rot, world, level, name, displayName, server, entity, false, CommandResultCallback.EMPTY, EntityAnchorArgument.Anchor.FEET, CommandSigningContext.ANONYMOUS, TaskChainer.immediate(server));
     }
 
-    protected CommandSourceStack(
-        CommandSource output,
-        Vec3 pos,
-        Vec2 rot,
-        ServerLevel world,
-        int level,
-        String name,
-        Component displayName,
-        MinecraftServer server,
-        @Nullable Entity entity,
-        boolean silent,
-        CommandResultCallback resultStorer,
-        EntityAnchorArgument.Anchor entityAnchor,
-        CommandSigningContext signedArguments,
-        TaskChainer messageChainTaskQueue
-    ) {
+    protected CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity, boolean silent, CommandResultCallback resultStorer, EntityAnchorArgument.Anchor entityAnchor, CommandSigningContext signedArguments, TaskChainer messageChainTaskQueue) {
         this.source = output;
         this.worldPosition = pos;
         this.level = world;
@@ -124,222 +88,56 @@
     }
 
     public CommandSourceStack withSource(CommandSource output) {
-        return this.source == output
-            ? this
-            : new CommandSourceStack(
-                output,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return this.source == output ? this : new CommandSourceStack(output, this.worldPosition, this.rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withEntity(Entity entity) {
-        return this.entity == entity
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                entity.getName().getString(),
-                entity.getDisplayName(),
-                this.server,
-                entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return this.entity == entity ? this : new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, this.permissionLevel, entity.getName().getString(), entity.getDisplayName(), this.server, entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withPosition(Vec3 position) {
-        return this.worldPosition.equals(position)
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                position,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return this.worldPosition.equals(position) ? this : new CommandSourceStack(this.source, position, this.rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withRotation(Vec2 rotation) {
-        return this.rotation.equals(rotation)
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return this.rotation.equals(rotation) ? this : new CommandSourceStack(this.source, this.worldPosition, rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     @Override
-    public CommandSourceStack withCallback(CommandResultCallback commandResultCallback) {
-        return Objects.equals(this.resultCallback, commandResultCallback)
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                commandResultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+    public CommandSourceStack withCallback(CommandResultCallback returnValueConsumer) {
+        return Objects.equals(this.resultCallback, returnValueConsumer) ? this : new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, returnValueConsumer, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withCallback(CommandResultCallback returnValueConsumer, BinaryOperator<CommandResultCallback> merger) {
-        CommandResultCallback commandResultCallback = merger.apply(this.resultCallback, returnValueConsumer);
-        return this.withCallback(commandResultCallback);
+        CommandResultCallback commandresultcallback1 = (CommandResultCallback) merger.apply(this.resultCallback, returnValueConsumer);
+
+        return this.withCallback(commandresultcallback1);
     }
 
     public CommandSourceStack withSuppressedOutput() {
-        return !this.silent && !this.source.alwaysAccepts()
-            ? new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                true,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            )
-            : this;
+        return !this.silent && !this.source.alwaysAccepts() ? new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, true, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer) : this;
     }
 
     public CommandSourceStack withPermission(int level) {
-        return level == this.permissionLevel
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                level,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return level == this.permissionLevel ? this : new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, level, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withMaximumPermission(int level) {
-        return level <= this.permissionLevel
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                level,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return level <= this.permissionLevel ? this : new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, level, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withAnchor(EntityAnchorArgument.Anchor anchor) {
-        return anchor == this.anchor
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+        return anchor == this.anchor ? this : new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, anchor, this.signingContext, this.chatMessageChainer);
     }
 
     public CommandSourceStack withLevel(ServerLevel world) {
         if (world == this.level) {
             return this;
         } else {
-            double d = DimensionType.getTeleportationScale(this.level.dimensionType(), world.dimensionType());
-            Vec3 vec3 = new Vec3(this.worldPosition.x * d, this.worldPosition.y, this.worldPosition.z * d);
-            return new CommandSourceStack(
-                this.source,
-                vec3,
-                this.rotation,
-                world,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                this.signingContext,
-                this.chatMessageChainer
-            );
+            double d0 = DimensionType.getTeleportationScale(this.level.dimensionType(), world.dimensionType());
+            Vec3 vec3d = new Vec3(this.worldPosition.x * d0, this.worldPosition.y, this.worldPosition.z * d0);
+
+            return new CommandSourceStack(this.source, vec3d, this.rotation, world, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, this.signingContext, this.chatMessageChainer);
         }
     }
 
@@ -348,35 +146,19 @@
     }
 
     public CommandSourceStack facing(Vec3 position) {
-        Vec3 vec3 = this.anchor.apply(this);
-        double d = position.x - vec3.x;
-        double e = position.y - vec3.y;
-        double f = position.z - vec3.z;
-        double g = Math.sqrt(d * d + f * f);
-        float h = Mth.wrapDegrees((float)(-(Mth.atan2(e, g) * 180.0F / (float)Math.PI)));
-        float i = Mth.wrapDegrees((float)(Mth.atan2(f, d) * 180.0F / (float)Math.PI) - 90.0F);
-        return this.withRotation(new Vec2(h, i));
+        Vec3 vec3d1 = this.anchor.apply(this);
+        double d0 = position.x - vec3d1.x;
+        double d1 = position.y - vec3d1.y;
+        double d2 = position.z - vec3d1.z;
+        double d3 = Math.sqrt(d0 * d0 + d2 * d2);
+        float f = Mth.wrapDegrees((float) (-(Mth.atan2(d1, d3) * 57.2957763671875D)));
+        float f1 = Mth.wrapDegrees((float) (Mth.atan2(d2, d0) * 57.2957763671875D) - 90.0F);
+
+        return this.withRotation(new Vec2(f, f1));
     }
 
     public CommandSourceStack withSigningContext(CommandSigningContext signedArguments, TaskChainer messageChainTaskQueue) {
-        return signedArguments == this.signingContext && messageChainTaskQueue == this.chatMessageChainer
-            ? this
-            : new CommandSourceStack(
-                this.source,
-                this.worldPosition,
-                this.rotation,
-                this.level,
-                this.permissionLevel,
-                this.textName,
-                this.displayName,
-                this.server,
-                this.entity,
-                this.silent,
-                this.resultCallback,
-                this.anchor,
-                signedArguments,
-                messageChainTaskQueue
-            );
+        return signedArguments == this.signingContext && messageChainTaskQueue == this.chatMessageChainer ? this : new CommandSourceStack(this.source, this.worldPosition, this.rotation, this.level, this.permissionLevel, this.textName, this.displayName, this.server, this.entity, this.silent, this.resultCallback, this.anchor, signedArguments, messageChainTaskQueue);
     }
 
     public Component getDisplayName() {
@@ -389,9 +171,44 @@
 
     @Override
     public boolean hasPermission(int level) {
+        // CraftBukkit start
+        // Paper start - Thread Safe Vanilla Command permission checking
+        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
+
         return this.permissionLevel >= level;
     }
 
+    // Paper start - Fix permission levels for command blocks
+    private boolean forceRespectPermissionLevel() {
+        return this.source == CommandSource.NULL || (this.source instanceof final net.minecraft.world.level.BaseCommandBlock commandBlock && commandBlock.getLevel().paperConfig().commandBlocks.forceFollowPermLevel);
+    }
+    // Paper end - Fix permission levels for command blocks
+
+    // CraftBukkit start
+    public boolean hasPermission(int i, String bukkitPermission) {
+        // Paper start - Fix permission levels for command blocks
+        final java.util.function.BooleanSupplier hasBukkitPerm = () -> this.source == CommandSource.NULL /*treat NULL as having all bukkit perms*/ || this.getBukkitSender().hasPermission(bukkitPermission); // lazily check bukkit perms to the benefit of custom permission setups
+        // if the server is null, we must check the vanilla perm level system
+        // if ignoreVanillaPermissions is true, we can skip vanilla perms and just run the bukkit perm check
+        //noinspection ConstantValue
+        if (this.getServer() == null || !this.getServer().server.ignoreVanillaPermissions) { // server & level are null for command function loading
+            final boolean hasPermLevel = this.permissionLevel >= i;
+            if (this.forceRespectPermissionLevel()) { // NULL CommandSource and command blocks (if setting is enabled) should always pass the vanilla perm check
+                return hasPermLevel && hasBukkitPerm.getAsBoolean();
+            } else { // otherwise check vanilla perm first then bukkit perm, matching upstream behavior
+                return hasPermLevel || hasBukkitPerm.getAsBoolean();
+            }
+        }
+        return hasBukkitPerm.getAsBoolean();
+        // Paper end - Fix permission levels for command blocks
+    }
+    // CraftBukkit end
+
     public Vec3 getPosition() {
         return this.worldPosition;
     }
@@ -407,24 +224,34 @@
 
     public Entity getEntityOrException() throws CommandSyntaxException {
         if (this.entity == null) {
-            throw ERROR_NOT_ENTITY.create();
+            throw CommandSourceStack.ERROR_NOT_ENTITY.create();
         } else {
             return this.entity;
         }
     }
 
     public ServerPlayer getPlayerOrException() throws CommandSyntaxException {
-        Entity var2 = this.entity;
-        if (var2 instanceof ServerPlayer) {
-            return (ServerPlayer)var2;
+        Entity entity = this.entity;
+
+        if (entity instanceof ServerPlayer entityplayer) {
+            return entityplayer;
         } else {
-            throw ERROR_NOT_PLAYER.create();
+            throw CommandSourceStack.ERROR_NOT_PLAYER.create();
         }
     }
 
     @Nullable
     public ServerPlayer getPlayer() {
-        return this.entity instanceof ServerPlayer serverPlayer ? serverPlayer : null;
+        Entity entity = this.entity;
+        ServerPlayer entityplayer;
+
+        if (entity instanceof ServerPlayer entityplayer1) {
+            entityplayer = entityplayer1;
+        } else {
+            entityplayer = null;
+        }
+
+        return entityplayer;
     }
 
     public boolean isPlayer() {
@@ -452,66 +279,86 @@
     }
 
     public boolean shouldFilterMessageTo(ServerPlayer recipient) {
-        ServerPlayer serverPlayer = this.getPlayer();
-        return recipient != serverPlayer && (serverPlayer != null && serverPlayer.isTextFilteringEnabled() || recipient.isTextFilteringEnabled());
+        ServerPlayer entityplayer1 = this.getPlayer();
+
+        return recipient == entityplayer1 ? false : entityplayer1 != null && entityplayer1.isTextFilteringEnabled() || recipient.isTextFilteringEnabled();
     }
 
     public void sendChatMessage(OutgoingChatMessage message, boolean filterMaskEnabled, ChatType.Bound params) {
         if (!this.silent) {
-            ServerPlayer serverPlayer = this.getPlayer();
-            if (serverPlayer != null) {
-                serverPlayer.sendChatMessage(message, filterMaskEnabled, params);
+            ServerPlayer entityplayer = this.getPlayer();
+
+            if (entityplayer != null) {
+                entityplayer.sendChatMessage(message, filterMaskEnabled, params);
             } else {
                 this.source.sendSystemMessage(params.decorate(message.content()));
             }
+
         }
     }
 
     public void sendSystemMessage(Component message) {
         if (!this.silent) {
-            ServerPlayer serverPlayer = this.getPlayer();
-            if (serverPlayer != null) {
-                serverPlayer.sendSystemMessage(message);
+            ServerPlayer entityplayer = this.getPlayer();
+
+            if (entityplayer != null) {
+                entityplayer.sendSystemMessage(message);
             } else {
                 this.source.sendSystemMessage(message);
             }
+
         }
     }
 
     public void sendSuccess(Supplier<Component> feedbackSupplier, boolean broadcastToOps) {
-        boolean bl = this.source.acceptsSuccess() && !this.silent;
-        boolean bl2 = broadcastToOps && this.source.shouldInformAdmins() && !this.silent;
-        if (bl || bl2) {
-            Component component = feedbackSupplier.get();
-            if (bl) {
-                this.source.sendSystemMessage(component);
+        boolean flag1 = this.source.acceptsSuccess() && !this.silent;
+        boolean flag2 = broadcastToOps && this.source.shouldInformAdmins() && !this.silent;
+
+        if (flag1 || flag2) {
+            Component ichatbasecomponent = (Component) feedbackSupplier.get();
+
+            if (flag1) {
+                this.source.sendSystemMessage(ichatbasecomponent);
             }
 
-            if (bl2) {
-                this.broadcastToAdmins(component);
+            if (flag2) {
+                this.broadcastToAdmins(ichatbasecomponent);
             }
+
         }
     }
 
     private void broadcastToAdmins(Component message) {
-        Component component = Component.translatable("chat.type.admin", this.getDisplayName(), message).withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC);
+        MutableComponent ichatmutablecomponent = 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()) {
-                if (serverPlayer != this.source && this.server.getPlayerList().isOp(serverPlayer.getGameProfile())) {
-                    serverPlayer.sendSystemMessage(component);
+            Iterator iterator = this.server.getPlayerList().getPlayers().iterator();
+
+            while (iterator.hasNext()) {
+                ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+
+                if (entityplayer != this.source && entityplayer.getBukkitEntity().hasPermission("minecraft.admin.command_feedback")) { // CraftBukkit
+                    entityplayer.sendSystemMessage(ichatmutablecomponent);
                 }
             }
         }
 
-        if (this.source != this.server && this.server.getGameRules().getBoolean(GameRules.RULE_LOGADMINCOMMANDS)) {
-            this.server.sendSystemMessage(component);
+        if (this.source != this.server && this.server.getGameRules().getBoolean(GameRules.RULE_LOGADMINCOMMANDS) && !org.spigotmc.SpigotConfig.silentCommandBlocks) { // Spigot
+            this.server.sendSystemMessage(ichatmutablecomponent);
         }
+
     }
 
     public void sendFailure(Component message) {
+        // Paper start - Add UnknownCommandEvent
+        this.sendFailure(message, true);
+    }
+    public void sendFailure(Component message, boolean withStyle) {
+        // Paper end - Add UnknownCommandEvent
         if (this.source.acceptsFailure() && !this.silent) {
-            this.source.sendSystemMessage(Component.empty().append(message).withStyle(ChatFormatting.RED));
+            this.source.sendSystemMessage(withStyle ? Component.empty().append(message).withStyle(ChatFormatting.RED) : message); // Paper - Add UnknownCommandEvent
         }
+
     }
 
     @Override
@@ -545,14 +392,9 @@
     }
 
     @Override
-    public CompletableFuture<Suggestions> suggestRegistryElements(
-        ResourceKey<? extends Registry<?>> registryRef,
-        SharedSuggestionProvider.ElementSuggestionType suggestedIdType,
-        SuggestionsBuilder builder,
-        CommandContext<?> context
-    ) {
-        return this.registryAccess().registry(registryRef).map(registry -> {
-            this.suggestRegistryElements((Registry<?>)registry, suggestedIdType, builder);
+    public CompletableFuture<Suggestions> suggestRegistryElements(ResourceKey<? extends Registry<?>> registryRef, SharedSuggestionProvider.ElementSuggestionType suggestedIdType, SuggestionsBuilder builder, CommandContext<?> context) {
+        return (CompletableFuture) this.registryAccess().registry(registryRef).map((iregistry) -> {
+            this.suggestRegistryElements(iregistry, suggestedIdType, builder);
             return builder.buildFuture();
         }).orElseGet(Suggestions::empty);
     }
@@ -573,7 +415,7 @@
     }
 
     @Override
-    public CommandDispatcher<CommandSourceStack> dispatcher() {
+    public com.mojang.brigadier.CommandDispatcher<CommandSourceStack> dispatcher() {
         return this.getServer().getFunctions().getDispatcher();
     }
 
@@ -586,10 +428,39 @@
         if (!silent) {
             this.sendFailure(ComponentUtils.fromMessage(message));
         }
+
     }
 
     @Override
     public boolean isSilent() {
         return this.silent;
     }
+
+    // Paper start
+    @Override
+    public CommandSourceStack getHandle() {
+        return this;
+    }
+    // Paper end
+    // CraftBukkit start
+    public org.bukkit.command.CommandSender getBukkitSender() {
+        return this.source.getBukkitSender(this);
+    }
+    // CraftBukkit end
+    // Paper start - tell clients to ask server for suggestions for EntityArguments
+    @Override
+    public Collection<String> getSelectedEntities() {
+        if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) {
+            final Entity cameraEntity = player.getCamera();
+            final double pickDistance = player.entityInteractionRange();
+            final Vec3 min = cameraEntity.getEyePosition(1.0F);
+            final Vec3 viewVector = cameraEntity.getViewVector(1.0F);
+            final Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance);
+            final net.minecraft.world.phys.AABB aabb = cameraEntity.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D);
+            final net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(cameraEntity, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance * pickDistance);
+            return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities();
+        }
+        return SharedSuggestionProvider.super.getSelectedEntities();
+    }
+    // Paper end - tell clients to ask server for suggestions for EntityArguments
 }
