Uploaded image for project: 'Spigot'
  1. Spigot
  2. SPIGOT-7023

Custom inheritors of CommandSender should be able to run Vanilla commands


    • Icon: New Feature New Feature
    • Resolution: Invalid
    • Icon: Minor Minor
    • None
    • None
    • This server is running Paper version git-Paper-283 (MC: 1.18.2) (Implementing API version 1.18.2-R0.1-SNAPSHOT) (Git: f8e8d6c)
    • Yes

      Currently, when a Vanilla command is attempted to be run using a custom object inheriting from CommandSender, an IllegalArgumentException is thrown since the CommandSender cannot be made into a vanilla command listener. This is intended behavior and stems from the getListener() method of the VanillaCommandWrapper class.

      public static CommandListenerWrapper getListener(CommandSender sender) {
              if (sender instanceof Player) {
                  return ((CraftPlayer) sender).getHandle().createCommandSourceStack();
              if (sender instanceof BlockCommandSender) {
                  return ((CraftBlockCommandSender) sender).getWrapper();
              if (sender instanceof CommandMinecart) {
                  return ((EntityMinecartCommandBlock) ((CraftMinecartCommand) sender).getHandle()).getCommandBlock().createCommandSourceStack();
              if (sender instanceof RemoteConsoleCommandSender) {
                  return ((DedicatedServer) MinecraftServer.getServer()).rconConsoleSource.createCommandSourceStack();
              if (sender instanceof ConsoleCommandSender) {
                  return ((CraftServer) sender.getServer()).getServer().createCommandSourceStack();
              if (sender instanceof ProxiedCommandSender) {
                  return ((ProxiedNativeCommandSender) sender).getHandle();
              throw new IllegalArgumentException("Cannot make " + sender + " a vanilla command listener");

      I suggest that developers should have the ability to easily make their custom CommandSenders run Vanilla commands. To make this possible, a new method should be added to the CommandSender interface, like so:

      public interface CommandSender ...{
              default CommandListenerWrapper getListener(){
                     throw new IllegalArgumentException("Cannot make " + this + " a vanilla command listener");

      the getListener() method in VanillaCommandWrapper should be changed to:

      public static CommandListenerWrapper getListener(CommandSender sender) {

      and the functionality previously held in the if-block in the old version of getListener should be moved to the corresponding concrete classes, for example, CraftPlayer:

      public class CraftPlayer ...{
              public CommandListenerWrapper getListener(){
                      return this.getHandle().createCommandSourceStack();

       Then, developers can allow their own custom CommandSenders to run Vanilla commands by implementing CommandSender#getListener(). If they do not, the default implementation in CommandSender will cause everything to act exactly the same as before and just throw an IllegalArgumentException.

      This code change also avoids incurring a confusing CastClassException if an object, for example, implements Player but not CraftPlayer or ConsoleCommandSender but not CraftServer, and is passed into getListener(). The custom Player that is not a CraftPlayer can either implement getListener() or throw a much more understandable IllegalArgumentException.

      This suggestion is related to SPIGOT-742, which seems to have changed getListener() and made it throw the IllegalArgumentException instead of returning null, which ends up causing a NullPointerException. The comments suggest that custom CommandSenders running VanillaCommands can't be supported because Vanilla uses a different command system. As far as I can tell, the CommandListenerWrapper class is meant for making this transition, wrapping relevant information in a way that can be used by the VanillaCommandWrapper.

            Unassigned Unassigned
            WillKroboth Will Kroboth
            0 Vote for this issue
            3 Start watching this issue