-
New Feature
-
Resolution: Invalid
-
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) { sender.getListener(); }
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.