Organizing commands in CommandExecutor

Discussion in 'Plugin Development' started by SuicideBunnyNL, Dec 1, 2011.

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

    SuicideBunnyNL

    Hey all,

    I've just recently started to develop plugins and very early ran into a 'problem' with switch statements and commands. After a little bit of research I found out that Java 1.6 doesn't support the usage of strings in switch statements, so I was thinking about using a HashMap<String, Integer> to register all the available commands, give them a unique number and pass said number to the switch statement and continue from there.

    Is the a 'good' way to go about this or is there a better way? I don't like having to make 20 if statements for the sole purpose that it's ugly (in my opinion).

    Also, I am wondering if I'm handling commands the right way in general. What I do is get the command in onCommand, assign this to a String variable, lowercase it and then check to see if it's in the HashMap and if so, grab it's assigned Integer. Then from there I check it in the switch, check if the sender is a player or console (depending on the command) and check the permissions. If this all passes, I continue to get whatever info I need for said command and pass this to a private function within the CommandExecutor and return true. If the permission isn't set for the player, I return a message and return true as well. Is this too the right way to go about things?

    Finally, how do I override basic commands such as time, kick, ban etc.?

    Sorry for the long post, just want to get things right from the beginning.
     
  2. Offline

    halley

    In your main class, inside your onEnable() method, you probably have some code like this:

    Code:
    private MyPluginCommandExecutor myExecutor;
    @Override
    public void onEnable() {
    	// ....
     	myExecutor = new MyPluginCommandExecutor(this);
    	getCommand("basic").setExecutor(myExecutor);
     	// ...
    }
    
    (I just copied that from the Plugin Tutorial, but every plugin does it roughly the same way.)

    So, think about what must be inside that bukkit line, getCommand("basic").setExecutor(). Do you think maybe it's setting up some kind of hashmap or lookup table to register all of the available commands? You'd be right! So why do that again yourself?

    Create new classes for each command executor. Register each class independently. No hashmap required on your side.

    Code:
    private MyAppleCommandExecutor myAppleExecutor;
    private MyBananaCommandExecutor myBananaExecutor;
    private MyCherryCommandExecutor myCherryExecutor;
    
    @Override
    public void onEnable() {
    	// ....
     	myAppleExecutor = new MyAppleCommandExecutor(this);
    	getCommand("apple").setExecutor(myAppleExecutor);
     	myBananaExecutor = new MyBananaCommandExecutor(this);
    	getCommand("banana").setExecutor(myBananaExecutor);
     	myCherryExecutor = new MyCherryCommandExecutor(this);
    	getCommand("cherry").setExecutor(myCherryExecutor);
     	// ...
    }
    
    Now you have three different commands, three different classes, three different onCommand() methods, and none of them get tripped up with switch statements or hash lookups. Voi la.
     
  3. Offline

    iffa

    ..aaand this gets messy if you have many commands.

    *Hint hint*
    Code:java
    1. /**
    2.   * Initializes all commands and adds them to the Map containing each command.
    3.   * This way no if-elseif-statements are needed in CommandExecutors, as they
    4.   * will simply scan through the Map for a matching command.
    5.   */
    6. public static void initializeCommands() {
    7. // Administration commands
    8. commands.put("debug", new DebugCommand("debug"));
    9. commands.put("trashcan", new AboutCommand("trashcan"));
    10. commands.put("paid", new PaidCommand("paid"));
    11. commands.put("who", new WhoCommand("who"));
    12. commands.put("shutdown", new ShutdownCommand("shutdown"));
    13. commands.put("createworld", new CreateworldCommand("createworld"));
    14. commands.put("unloadworld", new UnloadworldCommand("unloadworld"));
    15. commands.put("weather", new WeatherCommand("weather"));
    16. commands.put("time", new TimeCommand("time"));
    17. commands.put("setspawn", new SetspawnCommand("setspawn"));
    18. commands.put("broadcast", new BroadcastCommand("broadcast"));
    19.  
    20. // General commands
    21. commands.put("motd", new MOTDCommand("motd"));
    22. commands.put("me", new MeCommand("me"));
    23. commands.put("creative", new CreativeCommand("creative"));
    24. commands.put("survival", new SurvivalCommand("survival"));
    25. commands.put("spawnmob", new SpawnmobCommand("spawnmob"));
    26. // TODO: Add command for non-multihome /home
    27. commands.put("home", TrashCan.getConfigHandler().getMultiHomes() ? new HomeCommand("home") : new HomeCommand2("home"));
    28. // TODO: Add command for non-multihome /sethome
    29. commands.put("sethome", TrashCan.getConfigHandler().getMultiHomes() ? new SethomeCommand("sethome") : new SethomeCommand2("sethome"));
    30. commands.put("nick", new NickCommand("nick"));
    31. commands.put("warp", new WarpCommand("warp"));
    32. commands.put("usage", new UsageCommand("usage"));
    33. commands.put("help", new HelpCommand("help"));
    34. commands.put("item", new ItemCommand("item"));
    35. commands.put("more", new MoreCommand("more"));
    36. commands.put("feed", new FeedCommand("feed"));
    37. commands.put("heal", new HealCommand("heal"));
    38. commands.put("setxp", new SetxpCommand("setxp"));
    39. commands.put("mytime", new MytimeCommand("mytime"));
    40. commands.put("up", new UpCommand("up"));
    41. commands.put("unlimited", new UnlimitedCommand("unlimited"));
    42. commands.put("put", new PutCommand("put"));
    43. commands.put("spawn", new SpawnCommand("spawn"));
    44. commands.put("tp", new TeleportCommand("tp"));
    45. commands.put("tpall", new TeleportallCommand("tpall"));
    46. commands.put("tphere", new TeleporthereCommand("tphere"));
    47. commands.put("msg", new MsgCommand("msg"));
    48. commands.put("tpworld", new TeleportworldCommand("tpworld"));
    49. commands.put("clear", new ClearCommand("clear"));
    50. commands.put("armor", new ArmorCommand("armor"));
    51. commands.put("unstuck", new UnstuckCommand("unstuck"));
    52.  
    53. // Fun commands
    54. commands.put("crossbow", new CrossbowCommand("crossbow"));
    55. commands.put("explosionbow", new ExplosionBowCommand("explosionbow"));
    56. commands.put("torchbow", new TorchbowCommand("torchbow"));
    57. commands.put("join", new JoinCommand("join"));
    58. commands.put("leave", new LeaveCommand("leave"));
    59. commands.put("facepalm", new FacepalmCommand("facepalm"));
    60. commands.put("snowman", new SnowmanCommand("snowman"));
    61. commands.put("explode", new ExplodeCommand("explode"));
    62. commands.put("light", new LightCommand("light"));
    63. commands.put("roll", new RollCommand("roll"));
    64. commands.put("lightningstick", new LightningstickCommand("lightningstick"));
    65. commands.put("explosionstick", new ExplosionstickCommand("explosionstick"));
    66. commands.put("smoke", new SmokeCommand("smoke"));
    67. commands.put("strike", new StrikeCommand("strike"));
    68. commands.put("shoot", new ShootCommand("shoot"));
    69. commands.put("slap", new SlapCommand("slap"));
    70.  
    71. // Moderating commands
    72. commands.put("kick", new KickCommand("kick"));
    73. commands.put("ban", new BanCommand("ban"));
    74. commands.put("mute", new MuteCommand("mute"));
    75. commands.put("unban", new UnbanCommand("unban"));
    76. commands.put("unbanip", new UnbanIPCommand("unbanip"));
    77. commands.put("freeze", new FreezeCommand("freeze"));
    78. commands.put("banip", new BanIPCommand("banip"));
    79. commands.put("handicap", new HandicapCommand("handicap"));
    80. commands.put("setwarp", new SetwarpCommand("setwarp"));
    81. commands.put("delwarp", new DelwarpCommand("delwarp"));
    82. commands.put("kill", new KillCommand("kill"));
    83. //
    84. // Adding each command to the List of all commands.
    85. for (String cmd : commands.keySet()) {
    86. commandsList.add(cmd);
    87. }
    88.  
    89. // Adding all commands to the CommandExecutor.
    90. @SuppressWarnings("unchecked")
    91. Map<String, Map<String, Object>> pluginCommands = (Map<String, Map<String, Object>>) TrashCan.getDescriptionFile().getCommands();
    92. for (String command : pluginCommands.keySet()) {
    93. Bukkit.getPluginCommand(command).setExecutor(executor);
    94. }
    95.  
    96.  
    97. }


    Yes, it works. Each command has its own class extending a class. (blaH!)
     
    Konato_K and kg9dh like this.
  4. Offline

    halley

    Well, some plugins are Swiss Army Knives... but most are not.

    [​IMG]
     
  5. Offline

    SuicideBunnyNL

    Each function having it's own class seems just a bit too much tho.. Can I place functions instead of objects within the map?

    Unless you're talking about declaring all those functions in 'grouped' classes for each type of function?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 21, 2016
Thread Status:
Not open for further replies.

Share This Page