Command Executor Plugin name prefix?

Discussion in 'Plugin Development' started by Malikk, May 25, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    Malikk

    Hey guys,

    Just wondering if anyone's come up with a good way to use command executors with a prefix. So, all my plugins commands would be /td reload, /td give <player> <amount>, etc.

    The obvious way, and from my searching it seems this is how most people do it, is by having only a single executor, which then reads the args as separate commands, which seems really awful to me. I'd really like to know if anyone has got a way to NOT to it this way. Separate CommandExecutors for each command, as well as a prefix for every command.

    Thanks in advance (unless you just tell me to read the args, lol)
     
  2. Offline

    LucasEmanuel

    You could remove the space in the command ("/tdreload" instead of "/td reload") and just create several command executors that handle the diffrent commands. Or you could have one main command executor wich handles all commands but simply calls external classes and their methods for doing the work instead of having all the logic in the executor :)

    Like this:
    Code:
    if(args[0].equalsIgnoreCase("reload") {
        PluginNameReload reload = new PluginNameReload();
     
        switch(args[1]):
     
            case "whatever":
                reload.whatever();
                return true;
            case "somethingelse":
                reload.somethingelse();
                return true;
            etc...
     
  3. switch statements with strings doesn't work in java.
     
  4. You can do that since Java 7: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html @ Using Strings in switch Statements, but it's recommended to compile against Java 6 at most because not everybody upgraded to Java 7 and plugins compiled on Java 7 that are run on Java 6 give the Major.Minor error.
     
  5. Thanks for the info though :3
     
  6. Offline

    Malikk

    hmmm.

    I've haven't tried any of this out yet. But does it seem like a really terrible idea to catch PlayerCommandPreprocess, check if its got my prefix, then if it does, set the message to something else so that I can have separate command executors?

    pseudo code, like this;

    Code:
     
    @EventHandler
    public void onCommandPreprocess(PlayerCommandPreprocessEvent event){
        String[] split = event.getMessage().split(" ");
           if (split[0] is my plugin name || an alias){
               event.setMessage(String.format("cmd-%s " + args, split[1]));
           }
    }
     
    
    And then I could have the Command Executor be checking for my reformatted commands

    Code:
    CmdReload reload = new CmdReload(this);
    this.getCommand("cmd-reload").setExecutor(reload);
    
    I'm not sure if that makes it cleaner or messier, but it does get me the separate executors that I want.

    Any thoughts?
     
  7. Offline

    LucasEmanuel

    Well it seems like an awfull amount of extra work to just have a cleaner command executor.
     
  8. Offline

    Tempelchat

    If you don't mind to make the implemention a bit more complicated but the final usage easier, you could have a look at the command implemention of worldguard and implement a simple one yourself in your plugin.

    I worte a basic version of this system myself for my plugin and vorks very well. (Thank you sk89q for making this code available!)

    edit: I don't know what it is actually used for but in my opinion it is a bad style to use onCommandPreprocess.
     
  9. Offline

    Sagacious_Zed Bukkit Docs

    You can delegate from one commandExecutor to another one, but you would need a handle to the other commandExecutor you are delegating to.
     
  10. Offline

    Malikk

    I'm not sure what exactly is going on in world guard's code. It still seems like they're handling a bunch of commands all in one class. Perhaps I'm just not understanding what command.setInjector is doing.
     
  11. Offline

    nicholasntp

    Thats what I do and it works well!
     
  12. Offline

    Malikk

    Is it poor practice to go the command preprocess route, tho?
     
  13. Kind of, the bukkit's new /help system can only detect registered commands, not commands processed in events.

    You should use the plugin.yml registered commands... best way would be to register them without spaces, but if you want spaces, the prefix registered as command and the 1st argument as sub-commands is just as fine.
     
  14. Offline

    Tempelchat

    I quite like the idea to use Annotations like WorldEdit does. You use it to specify a new subcommand for your maincommand. In my implementation it basically checks every method for the specific Command-Annotation and reads detailed information about the command from it.
    Although this code is fairly new written and some things could be done better, it works just fine for me.

    In the spoiler below is the code for an example CommandExecutor i currently use:
    Show Spoiler

    Code:java
    1.  
    2. import java.lang.annotation.Retention;
    3. import java.lang.annotation.RetentionPolicy;
    4. import java.lang.reflect.Method;
    5. import org.bukkit.command.CommandExecutor;
    6. import org.bukkit.command.CommandSender;
    7. import org.bukkit.entity.Player;
    8.  
    9.  
    10. public class MyCommandExecutor implements CommandExecutor
    11. {
    12. private <PluginClass> plugin;
    13.  
    14. public MyCommandExecutor(<PluginClass> plugin) {
    15. this.plugin = plugin;
    16. }
    17.  
    18. //##### HANDLER ITSELF #####
    19.  
    20. @Override
    21. public boolean onCommand(CommandSender sender, org.bukkit.command.Command cmd, String commandLabel, String[] args)
    22. {
    23. if(args.length >= 1) //a work was given
    24. {
    25. for (Method m: this.getClass().getMethods()) //search on every method a command annotation
    26. {
    27. Command ann = m.getAnnotation(Command.class);
    28.  
    29. if(ann == null) continue; //not a command method
    30.  
    31. if(ann.cmd().equals(args[0])) //if the method is responsible for issued command
    32. {
    33. if(hasPermission(sender, ann)) //and has the permission
    34. {
    35. if(hasEnoughArgs(ann, args)) //are there enough
    36. {
    37. try {
    38. m.invoke(this, sender, args); //run!
    39. }
    40. catch (Exception e) {
    41. e.printStackTrace();
    42. }
    43. }
    44. else
    45. {
    46. sender.sendMessage(ann.usage());
    47. }
    48. return true;
    49. }
    50. else
    51. {
    52. sender.sendMessage("You don't have the permission!");
    53. return true;
    54. }
    55. }
    56.  
    57. }
    58. sender.sendMessage("Subcommand was not found!");
    59. }
    60. else
    61. {
    62. cmdHelp(sender, args);
    63. }
    64. return true;
    65. }
    66.  
    67. private boolean hasPermission(CommandSender sender, Command ann) {
    68.  
    69. if(ann.permissions().length == 0) //no permissions needed
    70. {
    71. return true;
    72. }
    73.  
    74. if(!(sender instanceof Player)) //assume it came from console... Maybe TODO
    75. {
    76. return true;
    77. }
    78.  
    79. Player p = (Player) sender;
    80. for(String perm : ann.permissions()) //check for bukkit permission; OR system, to be changed into AND
    81. {
    82. if(p.hasPermission(perm))
    83. {
    84. return true;
    85. }
    86. }
    87.  
    88. return false;
    89. }
    90.  
    91. //##### COMMANDS #####
    92. @Command(cmd = "help", permissions={"ultrahardcoremc.gamemaster"})
    93. public void cmdHelp(CommandSender sender, String[] args)
    94. {
    95. sender.sendMessage("Helpfile to be written!"); //TODO Help file
    96. }
    97.  
    98. @Command(cmd = "reload")
    99. public void cmdReload(CommandSender sender, String[] args)
    100. {
    101. plugin.reloadConfig();
    102. sender.sendMessage("Config reloaded!");
    103. }
    104.  
    105. @Command(cmd = "by", permissions={"test.developer"})
    106. public void cmdBy(CommandSender sender, String[] args)
    107. {
    108. sender.sendMessage("Plugin created by Someone!");
    109. }
    110.  
    111. //##### HELPER #####
    112. private static boolean hasEnoughArgs(Command ann, String[] args)
    113. {
    114. int numargs = args.length-1; //don't count command itself
    115.  
    116. if(numargs < ann.minArgs())
    117. {
    118. //System.out.print("Too less args!");
    119. return false;
    120. }
    121.  
    122. if(ann.maxArgs() != -1 && numargs > ann.maxArgs())
    123. {
    124. //System.out.print("Too much args!");
    125. return false;
    126. }
    127. return true;
    128. }
    129. }
    130.  
    131. @Retention(RetentionPolicy.RUNTIME)
    132. @interface Command
    133. {
    134. String cmd();
    135. String[] permissions() default {}; //made it so that it can require more than one permission node
    136.  
    137. String usage() default "No usage found!";
    138.  
    139. int minArgs() default 0;
    140. int maxArgs() default -1;
    141. }
    142.  


    I went this way with command processing. You will have to find the way you like and want to work with because it's never good to use something you can't really understand which will end with a complete mess^^
     
    nicholasntp and Malikk like this.
  15. Offline

    Malikk

    Tempelchat

    Alright, thanks for the example : ) Appreciate it.

    How exactly do you do that?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 26, 2016
  16. Offline

    nicholasntp

    Woah. Thanks. Ive always wondered how to do this. Almost impossibru. XD
     
Thread Status:
Not open for further replies.

Share This Page