001    package org.bukkit.command.defaults;
002    
003    import java.util.ArrayList;
004    import java.util.Collection;
005    import java.util.Collections;
006    import java.util.HashSet;
007    import java.util.List;
008    import java.util.Map;
009    import java.util.Set;
010    
011    import org.apache.commons.lang.ArrayUtils;
012    import org.apache.commons.lang.StringUtils;
013    import org.apache.commons.lang.Validate;
014    import org.bukkit.Bukkit;
015    import org.bukkit.ChatColor;
016    import org.bukkit.OfflinePlayer;
017    import org.bukkit.command.CommandSender;
018    import org.bukkit.entity.Player;
019    import org.bukkit.scoreboard.DisplaySlot;
020    import org.bukkit.scoreboard.Objective;
021    import org.bukkit.scoreboard.Score;
022    import org.bukkit.scoreboard.Scoreboard;
023    import org.bukkit.scoreboard.Team;
024    import org.bukkit.util.StringUtil;
025    
026    import com.google.common.collect.ImmutableList;
027    import com.google.common.collect.ImmutableMap;
028    
029    public class ScoreboardCommand extends VanillaCommand {
030    
031        private static final List<String> MAIN_CHOICES = ImmutableList.of("objectives", "players", "teams");
032        private static final List<String> OBJECTIVES_CHOICES = ImmutableList.of("list", "add", "remove", "setdisplay");
033        private static final List<String> OBJECTIVES_CRITERIA = ImmutableList.of("health", "playerKillCount", "totalKillCount", "deathCount", "dummy");
034        private static final List<String> PLAYERS_CHOICES = ImmutableList.of("set", "add", "remove", "reset", "list");
035        private static final List<String> TEAMS_CHOICES = ImmutableList.of("add", "remove", "join", "leave", "empty", "list", "option");
036        private static final List<String> TEAMS_OPTION_CHOICES = ImmutableList.of("color", "friendlyfire", "seeFriendlyInvisibles");
037        private static final Map<String, DisplaySlot> OBJECTIVES_DISPLAYSLOT = ImmutableMap.of("belowName", DisplaySlot.BELOW_NAME, "list", DisplaySlot.PLAYER_LIST, "sidebar", DisplaySlot.SIDEBAR);
038        private static final Map<String, ChatColor> TEAMS_OPTION_COLOR = ImmutableMap.<String, ChatColor>builder()
039                .put("aqua", ChatColor.AQUA)
040                .put("black", ChatColor.BLACK)
041                .put("blue", ChatColor.BLUE)
042                .put("bold", ChatColor.BOLD)
043                .put("dark_aqua", ChatColor.DARK_AQUA)
044                .put("dark_blue", ChatColor.DARK_BLUE)
045                .put("dark_gray",  ChatColor.DARK_GRAY)
046                .put("dark_green", ChatColor.DARK_GREEN)
047                .put("dark_purple", ChatColor.DARK_PURPLE)
048                .put("dark_red", ChatColor.DARK_RED)
049                .put("gold", ChatColor.GOLD)
050                .put("gray", ChatColor.GRAY)
051                .put("green", ChatColor.GREEN)
052                .put("italic", ChatColor.ITALIC)
053                .put("light_purple", ChatColor.LIGHT_PURPLE)
054                .put("obfuscated", ChatColor.MAGIC) // This is the important line
055                .put("red", ChatColor.RED)
056                .put("reset", ChatColor.RESET)
057                .put("strikethrough", ChatColor.STRIKETHROUGH)
058                .put("underline", ChatColor.UNDERLINE)
059                .put("white", ChatColor.WHITE)
060                .put("yellow", ChatColor.YELLOW)
061                .build();
062        private static final List<String> BOOLEAN = ImmutableList.of("true", "false");
063    
064        public ScoreboardCommand() {
065            super("scoreboard");
066            this.description = "Scoreboard control";
067            this.usageMessage = "/scoreboard";
068            this.setPermission("bukkit.command.scoreboard");
069        }
070    
071        @Override
072        public boolean execute(CommandSender sender, String currentAlias, String[] args) {
073            if (!testPermission(sender))
074                return true;
075            if (args.length < 1 || args[0].length() == 0) {
076                sender.sendMessage(ChatColor.RED + "Usage: /scoreboard <objectives|players|teams>");
077                return false;
078            }
079    
080            final Scoreboard mainScoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
081    
082            if (args[0].equalsIgnoreCase("objectives")) {
083                if (args.length == 1) {
084                    sender.sendMessage(ChatColor.RED + "Usage: /scoreboard objectives <list|add|remove|setdisplay>");
085                    return false;
086                }
087                if (args[1].equalsIgnoreCase("list")) {
088                    Set<Objective> objectives = mainScoreboard.getObjectives();
089                    if (objectives.isEmpty()) {
090                        sender.sendMessage(ChatColor.RED + "There are no objectives on the scoreboard");
091                        return false;
092                    }
093                    sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + objectives.size() + " objective(s) on scoreboard");
094                    for (Objective objective : objectives) {
095                        sender.sendMessage("- " + objective.getName() + ": displays as '" + objective.getDisplayName() + "' and is type '" + objective.getCriteria() + "'");
096                    }
097                } else if (args[1].equalsIgnoreCase("add")) {
098                    if (args.length < 4) {
099                        sender.sendMessage(ChatColor.RED + "/scoreboard objectives add <name> <criteriaType> [display name ...]");
100                        return false;
101                    }
102                    String name = args[2];
103                    String criteria = args[3];
104    
105                    if (criteria == null) {
106                        sender.sendMessage(ChatColor.RED + "Invalid objective criteria type. Valid types are: " + stringCollectionToString(OBJECTIVES_CRITERIA));
107                    } else if (name.length() > 16) {
108                        sender.sendMessage(ChatColor.RED + "The name '" + name + "' is too long for an objective, it can be at most 16 characters long");
109                    } else if (mainScoreboard.getObjective(name) != null) {
110                        sender.sendMessage(ChatColor.RED + "An objective with the name '" + name + "' already exists");
111                    } else {
112                        String displayName = null;
113                        if (args.length > 4) {
114                            displayName = StringUtils.join(ArrayUtils.subarray(args, 4, args.length), ' ');
115                            if (displayName.length() > 32) {
116                                sender.sendMessage(ChatColor.RED + "The name '" + displayName + "' is too long for an objective, it can be at most 32 characters long");
117                                return false;
118                            }
119                        }
120                        Objective objective = mainScoreboard.registerNewObjective(name, criteria);
121                        if (displayName != null && displayName.length() > 0) {
122                            objective.setDisplayName(displayName);
123                        }
124                        sender.sendMessage("Added new objective '" + name + "' successfully");
125                    }
126                } else if (args[1].equalsIgnoreCase("remove")) {
127                    if (args.length != 3) {
128                        sender.sendMessage(ChatColor.RED + "/scoreboard objectives remove <name>");
129                        return false;
130                    }
131                    String name = args[2];
132                    Objective objective = mainScoreboard.getObjective(name);
133                    if (objective == null) {
134                        sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + name + "'");
135                    } else {
136                        objective.unregister();
137                        sender.sendMessage("Removed objective '" + name + "' successfully");
138                    }
139                } else if (args[1].equalsIgnoreCase("setdisplay")) {
140                    if (args.length != 3 && args.length != 4) {
141                        sender.sendMessage(ChatColor.RED + "/scoreboard objectives setdisplay <slot> [objective]");
142                        return false;
143                    }
144                    String slotName = args[2];
145                    DisplaySlot slot = OBJECTIVES_DISPLAYSLOT.get(slotName);
146                    if (slot == null) {
147                        sender.sendMessage(ChatColor.RED + "No such display slot '" + slotName + "'");
148                    } else {
149                        if (args.length == 4) {
150                            String objectiveName = args[3];
151                            Objective objective = mainScoreboard.getObjective(objectiveName);
152                            if (objective == null) {
153                                sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + objectiveName + "'");
154                                return false;
155                            }
156    
157                            objective.setDisplaySlot(slot);
158                            sender.sendMessage("Set the display objective in slot '" + slotName + "' to '" + objective.getName() + "'");
159                        } else {
160                            Objective objective = mainScoreboard.getObjective(slot);
161                            if (objective != null) {
162                                objective.setDisplaySlot(null);
163                            }
164                            sender.sendMessage("Cleared objective display slot '" + slotName + "'");
165                        }
166                    }
167                }
168            } else if (args[0].equalsIgnoreCase("players")) {
169                if (args.length == 1) {
170                    sender.sendMessage(ChatColor.RED + "/scoreboard players <set|add|remove|reset|list>");
171                    return false;
172                }
173                if (args[1].equalsIgnoreCase("set") || args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) {
174                    if (args.length != 5) {
175                        if (args[1].equalsIgnoreCase("set")) {
176                            sender.sendMessage(ChatColor.RED + "/scoreboard players set <player> <objective> <score>");
177                        } else if (args[1].equalsIgnoreCase("add")) {
178                            sender.sendMessage(ChatColor.RED + "/scoreboard players add <player> <objective> <count>");
179                        } else {
180                            sender.sendMessage(ChatColor.RED + "/scoreboard players remove <player> <objective> <count>");
181                        }
182                        return false;
183                    }
184                    String objectiveName = args[3];
185                    Objective objective = mainScoreboard.getObjective(objectiveName);
186                    if (objective == null) {
187                        sender.sendMessage(ChatColor.RED + "No objective was found by the name '" + objectiveName + "'");
188                        return false;
189                    } else if (!objective.isModifiable()) {
190                        sender.sendMessage(ChatColor.RED + "The objective '" + objectiveName + "' is read-only and cannot be set");
191                        return false;
192                    }
193    
194                    String valueString = args[4];
195                    int value;
196                    try {
197                        value = Integer.parseInt(valueString);
198                    } catch (NumberFormatException e) {
199                        sender.sendMessage(ChatColor.RED + "'" + valueString + "' is not a valid number");
200                        return false;
201                    }
202                    if (value < 1 && !args[1].equalsIgnoreCase("set")) {
203                        sender.sendMessage(ChatColor.RED + "The number you have entered (" + value + ") is too small, it must be at least 1");
204                        return false;
205                    }
206    
207                    String playerName = args[2];
208                    if (playerName.length() > 16) {
209                        sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name");
210                        return false;
211                    }
212                    Score score = objective.getScore(playerName);
213                    int newScore;
214                    if (args[1].equalsIgnoreCase("set")) {
215                        newScore = value;
216                    } else if (args[1].equalsIgnoreCase("add")) {
217                        newScore = score.getScore() + value;
218                    } else {
219                        newScore = score.getScore() - value;
220                    }
221                    score.setScore(newScore);
222                    sender.sendMessage("Set score of " + objectiveName + " for player " + playerName + " to " + newScore);
223                } else if (args[1].equalsIgnoreCase("reset")) {
224                    if (args.length != 3) {
225                        sender.sendMessage(ChatColor.RED + "/scoreboard players reset <player>");
226                        return false;
227                    }
228                    String playerName = args[2];
229                    if (playerName.length() > 16) {
230                        sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name");
231                        return false;
232                    }
233                    mainScoreboard.resetScores(playerName);
234                    sender.sendMessage("Reset all scores of player " + playerName);
235                } else if (args[1].equalsIgnoreCase("list")) {
236                    if (args.length > 3) {
237                        sender.sendMessage(ChatColor.RED + "/scoreboard players list <player>");
238                        return false;
239                    }
240                    if (args.length == 2) {
241                        Set<String> entries = mainScoreboard.getEntries();
242                        if (entries.isEmpty()) {
243                            sender.sendMessage(ChatColor.RED + "There are no tracked players on the scoreboard");
244                        } else {
245                            sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + entries.size() + " tracked players on the scoreboard");
246                            sender.sendMessage(stringCollectionToString(entries));
247                        }
248                    } else {
249                        String playerName = args[2];
250                        if (playerName.length() > 16) {
251                            sender.sendMessage(ChatColor.RED + "'" + playerName + "' is too long for a player name");
252                            return false;
253                        }
254                        Set<Score> scores = mainScoreboard.getScores(playerName);
255                        if (scores.isEmpty()) {
256                            sender.sendMessage(ChatColor.RED + "Player " + playerName + " has no scores recorded");
257                        } else {
258                            sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + scores.size() + " tracked objective(s) for " + playerName);
259                            for (Score score : scores) {
260                                sender.sendMessage("- " + score.getObjective().getDisplayName() + ": " + score.getScore() + " (" + score.getObjective().getName() + ")");
261                            }
262                        }
263                    }
264                }
265            } else if (args[0].equalsIgnoreCase("teams")) {
266                if (args.length == 1) {
267                    sender.sendMessage(ChatColor.RED + "/scoreboard teams <list|add|remove|empty|join|leave|option>");
268                    return false;
269                }
270                if (args[1].equalsIgnoreCase("list")) {
271                    if (args.length == 2) {
272                        Set<Team> teams = mainScoreboard.getTeams();
273                        if (teams.isEmpty()) {
274                            sender.sendMessage(ChatColor.RED + "There are no teams registered on the scoreboard");
275                        } else {
276                            sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + teams.size() + " teams on the scoreboard");
277                            for (Team team : teams) {
278                                sender.sendMessage("- " + team.getName() + ": '" + team.getDisplayName() + "' has " + team.getSize() + " players");
279                            }
280                        }
281                    } else if (args.length == 3) {
282                        String teamName = args[2];
283                        Team team = mainScoreboard.getTeam(teamName);
284                        if (team == null) {
285                            sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'");
286                        } else {
287                            Set<OfflinePlayer> players = team.getPlayers();
288                            if (players.isEmpty()) {
289                                sender.sendMessage(ChatColor.RED + "Team " + team.getName() + " has no players");
290                            } else {
291                                sender.sendMessage(ChatColor.DARK_GREEN + "Showing " + players.size() + " player(s) in team " + team.getName());
292                                sender.sendMessage(offlinePlayerSetToString(players));
293                            }
294                        }
295                    } else {
296                        sender.sendMessage(ChatColor.RED + "/scoreboard teams list [name]");
297                        return false;
298                    }
299                } else if (args[1].equalsIgnoreCase("add")) {
300                    if (args.length < 3) {
301                        sender.sendMessage(ChatColor.RED + "/scoreboard teams add <name> [display name ...]");
302                        return false;
303                    }
304                    String name = args[2];
305                    if (name.length() > 16) {
306                        sender.sendMessage(ChatColor.RED + "The name '" + name + "' is too long for a team, it can be at most 16 characters long");
307                    } else if (mainScoreboard.getTeam(name) != null) {
308                        sender.sendMessage(ChatColor.RED + "A team with the name '" + name + "' already exists");
309                    } else {
310                        String displayName = null;
311                        if (args.length > 3) {
312                            displayName = StringUtils.join(ArrayUtils.subarray(args, 3, args.length), ' ');
313                            if (displayName.length() > 32) {
314                                sender.sendMessage(ChatColor.RED + "The display name '" + displayName + "' is too long for a team, it can be at most 32 characters long");
315                                return false;
316                            }
317                        }
318                        Team team = mainScoreboard.registerNewTeam(name);
319                        if (displayName != null && displayName.length() > 0) {
320                            team.setDisplayName(displayName);
321                        }
322                        sender.sendMessage("Added new team '" + team.getName() + "' successfully");
323                    }
324                } else if (args[1].equalsIgnoreCase("remove")) {
325                    if (args.length != 3) {
326                        sender.sendMessage(ChatColor.RED + "/scoreboard teams remove <name>");
327                        return false;
328                    }
329                    String name = args[2];
330                    Team team = mainScoreboard.getTeam(name);
331                    if (team == null) {
332                        sender.sendMessage(ChatColor.RED + "No team was found by the name '" + name + "'");
333                    } else {
334                        team.unregister();
335                        sender.sendMessage("Removed team " + name);
336                    }
337                } else if (args[1].equalsIgnoreCase("empty")) {
338                    if (args.length != 3) {
339                        sender.sendMessage(ChatColor.RED + "/scoreboard teams clear <name>");
340                        return false;
341                    }
342                    String name = args[2];
343                    Team team = mainScoreboard.getTeam(name);
344                    if (team == null) {
345                        sender.sendMessage(ChatColor.RED + "No team was found by the name '" + name + "'");
346                    } else {
347                        Set<OfflinePlayer> players = team.getPlayers();
348                        if (players.isEmpty()) {
349                            sender.sendMessage(ChatColor.RED + "Team " + team.getName() + " is already empty, cannot remove nonexistant players");
350                        } else {
351                            for (OfflinePlayer player : players) {
352                                team.removePlayer(player);
353                            }
354                            sender.sendMessage("Removed all " + players.size() + " player(s) from team " + team.getName());
355                        }
356                    }
357                } else if (args[1].equalsIgnoreCase("join")) {
358                    if ((sender instanceof Player) ? args.length < 3 : args.length < 4) {
359                        sender.sendMessage(ChatColor.RED + "/scoreboard teams join <team> [player...]");
360                        return false;
361                    }
362                    String teamName = args[2];
363                    Team team = mainScoreboard.getTeam(teamName);
364                    if (team == null) {
365                        sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'");
366                    } else {
367                        Set<String> addedPlayers = new HashSet<String>();
368                        if ((sender instanceof Player) && args.length == 3) {
369                            team.addPlayer((Player) sender);
370                            addedPlayers.add(sender.getName());
371                        } else {
372                            for (int i = 3; i < args.length; i++) {
373                                String playerName = args[i];
374                                OfflinePlayer offlinePlayer;
375                                Player player = Bukkit.getPlayerExact(playerName);
376                                if (player != null) {
377                                    offlinePlayer = player;
378                                } else {
379                                    offlinePlayer = Bukkit.getOfflinePlayer(playerName);
380                                }
381                                team.addPlayer(offlinePlayer);
382                                addedPlayers.add(offlinePlayer.getName());
383                            }
384                        }
385                        sender.sendMessage("Added " + addedPlayers.size() + " player(s) to team " + team.getName() + ": " + stringCollectionToString(addedPlayers));
386                    }
387                } else if (args[1].equalsIgnoreCase("leave")) {
388                    if (!(sender instanceof Player) && args.length < 3) {
389                        sender.sendMessage(ChatColor.RED + "/scoreboard teams leave [player...]");
390                        return false;
391                    }
392                    Set<String> left = new HashSet<String>();
393                    Set<String> noTeam = new HashSet<String>();
394                    if ((sender instanceof Player) && args.length == 2) {
395                        Team team = mainScoreboard.getPlayerTeam((Player) sender);
396                        if (team != null) {
397                            team.removePlayer((Player) sender);
398                            left.add(sender.getName());
399                        } else {
400                            noTeam.add(sender.getName());
401                        }
402                    } else {
403                        for (int i = 2; i < args.length; i++) {
404                            String playerName = args[i];
405                            OfflinePlayer offlinePlayer;
406                            Player player = Bukkit.getPlayerExact(playerName);
407                            if (player != null) {
408                                offlinePlayer = player;
409                            } else {
410                                offlinePlayer = Bukkit.getOfflinePlayer(playerName);
411                            }
412                            Team team = mainScoreboard.getPlayerTeam(offlinePlayer);
413                            if (team != null) {
414                                team.removePlayer(offlinePlayer);
415                                left.add(offlinePlayer.getName());
416                            } else {
417                                noTeam.add(offlinePlayer.getName());
418                            }
419                        }
420                    }
421                    if (!left.isEmpty()) {
422                        sender.sendMessage("Removed " + left.size() + " player(s) from their teams: " + stringCollectionToString(left));
423                    }
424                    if (!noTeam.isEmpty()) {
425                        sender.sendMessage("Could not remove " + noTeam.size() + " player(s) from their teams: " + stringCollectionToString(noTeam));
426                    }
427                } else if (args[1].equalsIgnoreCase("option")) {
428                    if (args.length != 4 && args.length != 5) {
429                        sender.sendMessage(ChatColor.RED + "/scoreboard teams option <team> <friendlyfire|color|seefriendlyinvisibles> <value>");
430                        return false;
431                    }
432                    String teamName = args[2];
433                    Team team = mainScoreboard.getTeam(teamName);
434                    if (team == null) {
435                        sender.sendMessage(ChatColor.RED + "No team was found by the name '" + teamName + "'");
436                        return false;
437                    }
438                    String option = args[3].toLowerCase();
439                    if (!option.equals("friendlyfire") && !option.equals("color") && !option.equals("seefriendlyinvisibles")) {
440                        sender.sendMessage(ChatColor.RED + "/scoreboard teams option <team> <friendlyfire|color|seefriendlyinvisibles> <value>");
441                        return false;
442                    }
443                    if (args.length == 4) {
444                        if (option.equals("color")) {
445                            sender.sendMessage(ChatColor.RED + "Valid values for option color are: " + stringCollectionToString(TEAMS_OPTION_COLOR.keySet()));
446                        } else {
447                            sender.sendMessage(ChatColor.RED + "Valid values for option " + option + " are: true and false");
448                        }
449                    } else {
450                        String value = args[4].toLowerCase();
451                        if (option.equals("color")) {
452                            ChatColor color = TEAMS_OPTION_COLOR.get(value);
453                            if (color == null) {
454                                sender.sendMessage(ChatColor.RED + "Valid values for option color are: " + stringCollectionToString(TEAMS_OPTION_COLOR.keySet()));
455                                return false;
456                            }
457                            team.setPrefix(color.toString());
458                            team.setSuffix(ChatColor.RESET.toString());
459                        } else {
460                            if (!value.equals("true") && !value.equals("false")) {
461                                sender.sendMessage(ChatColor.RED + "Valid values for option " + option + " are: true and false");
462                                return false;
463                            }
464                            if (option.equals("friendlyfire")) {
465                                team.setAllowFriendlyFire(value.equals("true"));
466                            } else {
467                                team.setCanSeeFriendlyInvisibles(value.equals("true"));
468                            }
469                        }
470                        sender.sendMessage("Set option " + option + " for team " + team.getName() + " to " + value);
471                    }
472                }
473            } else {
474                sender.sendMessage(ChatColor.RED + "Usage: /scoreboard <objectives|players|teams>");
475                return false;
476            }
477            return true;
478        }
479    
480        @Override
481        public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
482            Validate.notNull(sender, "Sender cannot be null");
483            Validate.notNull(args, "Arguments cannot be null");
484            Validate.notNull(alias, "Alias cannot be null");
485    
486            if (args.length == 1) {
487                return StringUtil.copyPartialMatches(args[0], MAIN_CHOICES, new ArrayList<String>());
488            }
489            if (args.length > 1) {
490                if (args[0].equalsIgnoreCase("objectives")) {
491                    if (args.length == 2) {
492                        return StringUtil.copyPartialMatches(args[1], OBJECTIVES_CHOICES, new ArrayList<String>());
493                    }
494                    if (args[1].equalsIgnoreCase("add")) {
495                        if (args.length == 4) {
496                            return StringUtil.copyPartialMatches(args[3], OBJECTIVES_CRITERIA, new ArrayList<String>());
497                        }
498                    } else if (args[1].equalsIgnoreCase("remove")) {
499                        if (args.length == 3) {
500                            return StringUtil.copyPartialMatches(args[2], this.getCurrentObjectives(), new ArrayList<String>());
501                        }
502                    } else if (args[1].equalsIgnoreCase("setdisplay")) {
503                        if (args.length == 3) {
504                            return StringUtil.copyPartialMatches(args[2], OBJECTIVES_DISPLAYSLOT.keySet(), new ArrayList<String>());
505                        }
506                        if (args.length == 4) {
507                            return StringUtil.copyPartialMatches(args[3], this.getCurrentObjectives(), new ArrayList<String>());
508                        }
509                    }
510                } else if (args[0].equalsIgnoreCase("players")) {
511                    if (args.length == 2) {
512                        return StringUtil.copyPartialMatches(args[1], PLAYERS_CHOICES, new ArrayList<String>());
513                    }
514                    if (args[1].equalsIgnoreCase("set") || args[1].equalsIgnoreCase("add") || args[1].equalsIgnoreCase("remove")) {
515                        if (args.length == 3) {
516                            return super.tabComplete(sender, alias, args);
517                        }
518                        if (args.length == 4) {
519                            return StringUtil.copyPartialMatches(args[3], this.getCurrentObjectives(), new ArrayList<String>());
520                        }
521                    } else {
522                        if (args.length == 3) {
523                            return StringUtil.copyPartialMatches(args[2], this.getCurrentEntries(), new ArrayList<String>());
524                        }
525                    }
526                } else if (args[0].equalsIgnoreCase("teams")) {
527                    if (args.length == 2) {
528                        return StringUtil.copyPartialMatches(args[1], TEAMS_CHOICES, new ArrayList<String>());
529                    }
530                    if (args[1].equalsIgnoreCase("join")) {
531                        if (args.length == 3) {
532                            return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList<String>());
533                        }
534                        if (args.length >= 4) {
535                            return super.tabComplete(sender, alias, args);
536                        }
537                    } else if (args[1].equalsIgnoreCase("leave")) {
538                        return super.tabComplete(sender, alias, args);
539                    } else if (args[1].equalsIgnoreCase("option")) {
540                        if (args.length == 3) {
541                            return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList<String>());
542                        }
543                        if (args.length == 4) {
544                            return StringUtil.copyPartialMatches(args[3], TEAMS_OPTION_CHOICES, new ArrayList<String>());
545                        }
546                        if (args.length == 5) {
547                            if (args[3].equalsIgnoreCase("color")) {
548                                return StringUtil.copyPartialMatches(args[4], TEAMS_OPTION_COLOR.keySet(), new ArrayList<String>());
549                            } else {
550                                return StringUtil.copyPartialMatches(args[4], BOOLEAN, new ArrayList<String>());
551                            }
552                        }
553                    } else {
554                        if (args.length == 3) {
555                            return StringUtil.copyPartialMatches(args[2], this.getCurrentTeams(), new ArrayList<String>());
556                        }
557                    }
558                }
559            }
560    
561            return ImmutableList.of();
562        }
563    
564        private static String offlinePlayerSetToString(Set<OfflinePlayer> set) {
565            StringBuilder string = new StringBuilder();
566            String lastValue = null;
567            for (OfflinePlayer value : set) {
568                string.append(lastValue = value.getName()).append(", ");
569            }
570            string.delete(string.length() - 2, Integer.MAX_VALUE);
571            if (string.length() != lastValue.length()) {
572                string.insert(string.length() - lastValue.length(), "and ");
573            }
574            return string.toString();
575    
576        }
577    
578        private static String stringCollectionToString(Collection<String> set) {
579            StringBuilder string = new StringBuilder();
580            String lastValue = null;
581            for (String value : set) {
582                string.append(lastValue = value).append(", ");
583            }
584            string.delete(string.length() - 2, Integer.MAX_VALUE);
585            if (string.length() != lastValue.length()) {
586                string.insert(string.length() - lastValue.length(), "and ");
587            }
588            return string.toString();
589        }
590    
591        private List<String> getCurrentObjectives() {
592            List<String> list = new ArrayList<String>();
593            for (Objective objective : Bukkit.getScoreboardManager().getMainScoreboard().getObjectives()) {
594                list.add(objective.getName());
595            }
596            Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
597            return list;
598        }
599    
600        private List<String> getCurrentEntries() {
601            List<String> list = new ArrayList<String>();
602            for (String entry : Bukkit.getScoreboardManager().getMainScoreboard().getEntries()) {
603                list.add(entry);
604            }
605            Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
606            return list;
607        }
608    
609        private List<String> getCurrentTeams() {
610            List<String> list = new ArrayList<String>();
611            for (Team team : Bukkit.getScoreboardManager().getMainScoreboard().getTeams()) {
612                list.add(team.getName());
613            }
614            Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
615            return list;
616        }
617    }