Resource Easier way to make commands

Discussion in 'Spigot Plugin Development' started by zLegendXP, Oct 9, 2018.

?

Did you find this helpful

  1. Yes

    3 vote(s)
    15.8%
  2. No

    5 vote(s)
    26.3%
  3. Somewhat useful

    11 vote(s)
    57.9%
  1. Hello!
    As my first resource, I want to show all of you how to make commands in the easiest possible way.
    Why would you want this?
    If you're making a plugin that has a lot of individual commands, this can save time and make life easier.
    What does it do?
    • It makes it so you don't have to register them in your plugin.yml
    • Allows you can create useful methods in your super class
    • Makes it so the onCommand method doesn't return a boolean
    • Automatically does player and permission checks
    • Makes the onCommand parameters shorter
    • Simplifies command registry
    How is this done?
    You need to create this class:
    Code (Java):

    package me.legendxp.ezcommand;

    import java.util.Arrays;
    import java.util.List;

    import org.bukkit.command.CommandSender;
    import org.bukkit.command.defaults.BukkitCommand;
    import org.bukkit.entity.Player;

    import net.md_5.bungee.api.ChatColor;

    public abstract class EzCommand extends BukkitCommand {

        protected EzCommand() {
            super("");
            setName(info.name());
            setAliases(Arrays.asList(info.aliases()));
            setDescription(info.description());
            setPermission(info.permission());
        }

        private CommandInfo info = getClass().getAnnotation(CommandInfo.class); //Command info (name, description, permission, aliases)
       
        public abstract void onCommand(Player p, String[] args); //What will be done
       
        public String getName() {
            return info.name();
        }
       
        public List<String> getAliases() {
            return Arrays.asList(info.aliases());
        }
       
        public String getDescription() {
            return info.description();
        }
       
        public String getPermission() {
            return info.permission();
        }

        public void info(Player p, String... msgs) { //Easier way of messaging player in sub-class
            for(String msg : msgs) p.sendMessage(ChatColor.GREEN + msg);
        }
       
        public void severe(Player p, String... msgs) { //Easier way of messaging player in sub-class
            for(String msg : msgs) p.sendMessage(ChatColor.RED + msg);
        }
       
        @Override
        public boolean execute(CommandSender sender, String label, String[] args) {
            if(!(sender instanceof Player)) {
                sender.sendMessage(ChatColor.RED + "Only players can use this command");
                return true;
            }
           
            Player p = (Player) sender;
           
            if(!(p.hasPermission(info.permission()))) {
                p.sendMessage(ChatColor.RED + "You do not have permission to use this command");
                return true;
            }
           
            onCommand(p, args);
            return true;
        }
       
    }
     
    And this one:
    Code (Java):

    package me.legendxp.ezcommand;

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CommandInfo {

        String name();
        String description();
        String permission();
        String[] aliases() default {};
       
    }
     
    And this one:
    Code (Java):

    package me.legendxp.ezcommand;

    import org.bukkit.Bukkit;
    import org.bukkit.craftbukkit.v1_13_R2.CraftServer;

    public class CommandRegistry {

        @SafeVarargs
        public static void register(EzCommand... cmds) {
            for(EzCommand cmd : cmds) ((CraftServer) Bukkit.[I]getServer[/I]()).getCommandMap().register(cmd.getName(), cmd);
        }

    }
     
    Now you can extend the EzCommand class to make your own command (Example)
    Code (Java):

    package me.legendxp.ezcommand;

    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;

    @CommandInfo(name = "Info", description = "Get a players info", permission = "ezcommand.info")
    public class Info extends EzCommand {
     
        public void onCommand(Player p, String[] args) {
            if(args.length == 0) {
                severe(p, "You must specify a player to get info from");
                return;
            }
         
            Player target = Bukkit.getPlayer(args[0]);
         
            if(target == null) {
                severe(p, "Could not find '" + args[0] + "'");
                return;
            }
         
            String health = String.valueOf(p.getHealth());
            String gamemode = p.getGameMode().name();
            String world = p.getWorld().getName();
            String op = Boolean.toString(p.isOp());
         
            info(p, "Health: " + health, "GameMode: " + gamemode, "World: " + world, "OP: " + op);
         
        }

    }
     
    Now compare this to the regular method:
    Code (Java):

    package me.legendxp.ezcommand;

    import org.bukkit.Bukkit;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;

    import net.md_5.bungee.api.ChatColor;

    public class InfoTwo implements CommandExecutor {

        public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
            if(cmd.getName().equalsIgnoreCase("infotwo")) {
                if(!(sender instanceof Player)) {
                    sender.sendMessage(ChatColor.RED + "Only players can use this command");
                    return true;
                }

                Player p = (Player) sender;

                if(!(p.hasPermission("ezcommand.info2"))) {
                    p.sendMessage(ChatColor.RED + "You do not have permission to use this command");
                    return true;
                }

                if(args.length == 0) {
                    p.sendMessage(ChatColor.RED + "You must specify a player to get info from");
                    return true;
                }

                Player target = Bukkit.getPlayer(args[0]);

                if(target == null) {
                    p.sendMessage(ChatColor.RED + "Could not find player '" + args[0] + "'");
                    return true;
                }

                String health = String.valueOf(p.getHealth());
                String gamemode = p.getGameMode().name();
                String world = p.getWorld().getName();
                String op = Boolean.toString(p.isOp());
               
                p.sendMessage(ChatColor.GREEN + "Health: " + health);
                p.sendMessage(ChatColor.GREEN + "GameMode: " + gamemode);
                p.sendMessage(ChatColor.GREEN + "World: " + world);
                p.sendMessage(ChatColor.GREEN + "OP: " + op);
            }
            return true;
        }

    }
     
    As can be seen, my EzCommand class is shorter to write. When you are making a lot of commands, this can save a lot of time. Don't forget, using the slow method also requires you to write a plugin.yml!

    How to register
    In your onEnable() all you need to do is:
    Code (Java):

    package me.legendxp.ezcommand;

    import org.bukkit.plugin.java.JavaPlugin;

    public class Main extends JavaPlugin {

        public void onEnable() {
            CommandRegistry.register(new Info());
        }

    }
     

    This is the end
    Please tell me your honest opinion is the comment section. Also vote if this was useful or not. I really hope this helped you!

    For the future
    I definitely want to add more features. Let me know in the comments how I can improve this. Things I plan on adding are tab completion, allowing console to use commands and sub-commands. I also plan to make this an api that you can include in your plugin so you don't need to write this.
     
    #1 zLegendXP, Oct 9, 2018
    Last edited: Oct 14, 2018
    • Like Like x 4
  2. Wow. I think I will try this but the old way is good too :p
     
  3. Having just "new Dog()" may be seen as redundant and confusing to programmers not used to this setup, perhaps have a command registry of some sort?

    Also how do you do multiple aliases?
     
    • Agree Agree x 1
  4. Benz56

    Junior Mod Supporter

    The main drawback is that this isn’t version independent. To change that you’d have to add a lot of bloat/per version stuff or reflection as well as caching.

    If you know which version the plugin will be used on this is a good alternative.
     
  5. I would've personally used a command listener rather than forcing it into the command map tbh
     
  6. MiniDigger

    Supporter

    That would remove compatibilities with many plugins tho. Injecting it into the command map is definitely the nicer way.
    In 1.13 it might be an even better option to register them with brigadier tho.
     
  7. I really don't get what people have against writing a few lines to plugin.yml
     
    • Agree Agree x 1
  8. Perhaps they wish to have configurable commands :unsure:? This is the only reason I can think of where this is useful.
     
  9. There's this really useful feature in Bukkit, the commands.yml file, which already allows you to remap commands and inject default arguments (i.e. having a /survival command that runs /server survival - which is a horrible example, I know)
     
  10. why do you register it in the constructor? have the constructor serve one purpose; mapping the variables. register the command through some manager or in its own method. this can also be said for events.

    also, that whole static thing you got going on there for getting the pl instance, just pass the class around through DI
     
  11. Updated this resource:

    Added aliases, command registry, and better example.
     
    • Like Like x 2

Share This Page