Resource Simpler command executor: onCommand(Player player, String[] args)

Discussion in 'Spigot Plugin Development' started by JacobCrofts, Jun 28, 2016.

  1. This will make your life easier if your command is only meant to be executed in-game by a Player. You may also use this principle to check for command formatting issues, and to separate all that tedious format checking from your actual command logic.

    Feel free to modify this to fit your needs. I feel like every plugin with a lot of commands would benefit from its own tailored command executor.

    Code (Text):

    public abstract class InGameCommandExecutor implements CommandExecutor {

        private final int minArgsLength;
        private final int maxArgsLength;

        // you may choose to accept a Permission level as part of the constructor
        // and check if the player has it before executing the command

        public InGameCommandExecutor(int minArgsLength, int maxArgsLength) {
            this.minArgsLength = minArgsLength;
            this.maxArgsLength = maxArgsLength;
        }

        @Override
        public final boolean onCommand(CommandSender sender, Command command, String label, String[] args) {

            if (!(sender instanceof Player)) {
                // TODO: send your own error message to the console here
                return true;
            }

            Player player = (Player) sender;

            int length = args.length;

            if (length < this.minArgsLength || length > this.maxArgsLength) {
                // TODO: your own error message here
                // return false if you don't wish to provide your own message
                return true;
            }

            // now, allow the subclass to handle the command logic
            this.onCommand(player, args);

            return true;
        }

        // make this a boolean if you want the subclass to do more command format checks
        // then, instead of returning true above, return the outcome of this method
        abstract void onCommand(Player player, String[] args);

    }
     
    Tired of casting CommandSender to Player over and over? Let's see how simple this is now:

    Code (Text):

    public class CommandSayHello extends InGameCommandExecutor {

        public CommandSayHello() {
            // the minimum and maximum number of agruments are 0 and 0 respectively
            super(0, 0);
        }

        // all command logic goes here
        // this will not run at all if the command sender wasn't a player, so no need for casting
        // no need to return anything, either, since the superclass handles that as well
        @Override
        public final void onCommand(Player player, String[] args) {
            player.sendMessage("Hello!");
        }

    }
     
    This does not change the way in which you register commands or configure plugin.yml.
     
    • Like Like x 1
  2. Choco

    Moderator

    But this completely removes the purpose of the console. It also limits the fact that we can't return true or false depending on if the command is valid or not. You're returning true automatically (When you can set the abstract method to return a boolean as per usual and just return that method call instead) I don't think this is much of a resource in my opinion as it's limiting more features than it's adding. I personally see no purpose in this as all you're doing is calling a method from onCommand. Not really sure if it's all that useful in my opinion, but others may disagree with me and that's fine. Opinions vary.
     
    • Agree Agree x 1
  3. I always return true in my commands because I provide my own reason for why the command failed in the event that it does. A player may easily modify this code to make the abstract method a boolean and return the result. The InGameCommandExecutor does some of that format checking for me, and can be expanded to check for other things (such as whether an argument may be parsed as Integer, or whether the player has sufficient permissions to run the command).

    The general principle I'm aiming for is: do the format checking first, and do it as automatically as possible. Then, run the command logic as if everything will work fine. In the long run, for me, it has saved hundreds of lines of code because I have so many commands and almost all of them must be executed in-game. Simply reducing length doesn't necessarily make it better, but in my opinion it makes my code easier to read and modify.
     
  4. While this has its flaws, I have to say you're on the right track. I like that you're using your knowledge of abstraction here. If you wanted to take this further you could and another class. it can handle CommandSender for co sole and command block support. Then your player command can extend that one for players only. If you wanted to go even further you could implement permissions into it, and/or even a subcommand system into it to register and handle subcommands.

    All in all, good starting example to introduce people to abstraction.
     
  5. I made a generic command system that also handles subcommands. With it you can define command for a specific type of sender, be it any CommandSender in general, Players, ConsoleCommandSenders, CommandBlockSenders or even any new type of sender that might pop up in the future or one that you create yourself (for whatever reason). I wrote it in Kotlin, though, but it should be usable in Java as well. I did it mainly as a fun project for getting to know Kotlin. Check it out on github: https://github.com/rocoty/BukkitGenericCommandSystem

    Looking to add description and usage when I get the time. It is still a work in progress.
     
  6. YOU USE KOTLIN TOO? :D
     
  7. Yeah. I think it is a wonderful language. Although I imagine not many people around here uses it.
     
  8. This is a great way to promote spoonfeeding x.x

    Also, it doesn't make a way to have Console send commands as it will stop it from continuing. Also, you never show anyone how to register these commands.
     
  9. I USE IT! ITS AWESOME