Solved TabComplete need to understand a few things

Discussion in 'Plugin Development' started by xize, Feb 25, 2014.

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

    xize

    Hello,

    so I'm trying to make a /give command with a auto tab complete based on the Material enum I know how to do this in theory.
    but now I'm sort of confused because how would I add these keywords inside the List<String> since I only have the return function and not the actually tab complete list ?

    for now i've did this in OnEnable:
    Code:
    getCommand("give").setTabCompleter(new CmdGive());
    
    and this is just my empty command:
    Code:
    public class CmdGive implements TabCompleter {
    @Override
    public List<String> onTabComplete(CommandSender sender, Command cmd, String CommandLabel, String[] args) {
      // TODO Auto-generated method stub
      return null;
    }
    }
    
    so 2 questions 1. does the command just work like any normal command?, 2. how can I modify the tab complete list?

    thanks:)

    -edit-
    I think ive found it, I probably need to use both setExecutor and setTabCompleter where setTabCompleter is the one which only handles the auto completion.
     
  2. Offline

    desht

    Material.values() will give you an array of all Material objects in the Material enum. From there, it's very easy to get the String for the Material...

    PHP:
    for (Material m Material.values()) {
      
    String s m.toString();
      
    // do what you need to do with s
    }
    As for TabCompleter, your onTabComplete() method is called whenever someone presses Tab while entering a command. The arguments are basically the same as you would expect to receive in onCommand(), although you'll obviously only get a partial command.

    It's up to you to work out which argument needs to be completed, based on the number of arguments in the args[] array and the syntax of your command. Your onTabComplete() just needs to return a list of the possible completions, and CraftBukkit will do the rest for you (displaying them to the user, cycling through them on subsequent presses of Tab).

    Note that if someone tries to tab-complete, say, "/mycommand arg1 arg2 " (note the trailing space there), then args[] will contain {"arg1", "arg2", ""} - three elements with the final one being the empty string.

    The most common operation in onTabComplete() will be filtering out a list of strings from a known list (in your case, a list of all known Material names), where the strings you want start with the final argument (and when the final argument is the empty string or there are no arguments at all, that means all of the strings from your known list). For example:
    • I type /giveme <TAB> - your onTabComplete() should return the complete list of Material names
    • I type /giveme dia<TAB> - your onTabComplete() should return those Material names which start with "dia" (you probably want ignore case here)
     
    xize likes this.
  3. Offline

    xize

    desht
    thanks thats very usefull, so the method onTabComplete is not the same as onCommand but you need to use them both correct?

    i've did it this way:

    Code:
    private List<String> getAllMaterials() {
      List<String> list = new ArrayList<String>();
      for(Material mat : Material.values()) {
       list.add(mat.name());
      }
      
      return list;
     }
     
     private List<String> getContainedMaterials(String material) {
      List<String> list = new ArrayList<String>();
      for(String mat : getAllMaterials()) {
       if(mat.contains(material.toUpperCase())) {
        list.add(mat);
       }
      }
      return list;
     }
     
     public List<String> onTabComplete(CommandSender sender, Command cmd, String[] args) {
      if(cmd.getName().equalsIgnoreCase("give")) {
       if(args.length == 1) {
        List<String> list = getContainedMaterials(args[0]);
        return list;
       }
      }
      return null;
     }
     public boolean execute(CommandSender sender, Command cmd, String[] args) {
      if(cmd.getName().equalsIgnoreCase("give")) {
       if(args.length == 0) {
        sender.sendMessage("command works");
       } else if(args.length == 1) {
        sender.sendMessage("testing material! " + args[0]);
       }
      }
      return false;
     }
     
     
    }
    
     
  4. Offline

    desht

    xize looks pretty good, couple of comments:
    1. Your onTabComplete() should also handle the case where args.length == 0, and just return all known material names.
    2. If there are no completions, you should probably return an empty list rather than null (I believe CraftBukkit interprets null as "show a list of online players")
    3. Since the Material enum won't change, it would be much more efficient to build a List<String> of all known material names once, either statically or in your class's constructor.
    4. In getContainedMaterials(), using contains() might produce slightly unexpected results for your users - generally with Tab completion, you type the start of the string and press Tab for any completions, so using startsWith() might be more suitable. If I type "/giveme s<TAB>", I would expect to see materials starting with S, not e.g. IRON_SWORD. Your choice, though :)
     
Thread Status:
Not open for further replies.

Share This Page