package org.bukkit.command; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.apache.commons.lang.Validate; import org.bukkit.Location; import org.bukkit.Server; import org.bukkit.command.defaults.*; import org.bukkit.entity.Player; import org.bukkit.util.StringUtil; public class SimpleCommandMap implements CommandMap { protected final Map knownCommands = new HashMap(); private final Server server; public SimpleCommandMap(final Server server) { this.server = server; setDefaultCommands(); } private void setDefaultCommands() { register("bukkit", new VersionCommand("version")); register("bukkit", new ReloadCommand("reload")); register("bukkit", new PluginsCommand("plugins")); register("bukkit", new TimingsCommand("timings")); } public void setFallbackCommands() { register("bukkit", new HelpCommand()); } /** * {@inheritDoc} */ public void registerAll(String fallbackPrefix, List commands) { if (commands != null) { for (Command c : commands) { register(fallbackPrefix, c); } } } /** * {@inheritDoc} */ public boolean register(String fallbackPrefix, Command command) { return register(command.getName(), fallbackPrefix, command); } /** * {@inheritDoc} */ public boolean register(String label, String fallbackPrefix, Command command) { label = label.toLowerCase(java.util.Locale.ENGLISH).trim(); fallbackPrefix = fallbackPrefix.toLowerCase(java.util.Locale.ENGLISH).trim(); boolean registered = register(label, command, false, fallbackPrefix); Iterator iterator = command.getAliases().iterator(); while (iterator.hasNext()) { if (!register(iterator.next(), command, true, fallbackPrefix)) { iterator.remove(); } } // If we failed to register under the real name, we need to set the command label to the direct address if (!registered) { command.setLabel(fallbackPrefix + ":" + label); } // Register to us so further updates of the commands label and aliases are postponed until its reregistered command.register(this); return registered; } /** * Registers a command with the given name is possible. Also uses * fallbackPrefix to create a unique name. * * @param label the name of the command, without the '/'-prefix. * @param command the command to register * @param isAlias whether the command is an alias * @param fallbackPrefix a prefix which is prepended to the command for a * unique address * @return true if command was registered, false otherwise. */ private synchronized boolean register(String label, Command command, boolean isAlias, String fallbackPrefix) { knownCommands.put(fallbackPrefix + ":" + label, command); if ((command instanceof BukkitCommand || isAlias) && knownCommands.containsKey(label)) { // Request is for an alias/fallback command and it conflicts with // a existing command or previous alias ignore it // Note: This will mean it gets removed from the commands list of active aliases return false; } boolean registered = true; // If the command exists but is an alias we overwrite it, otherwise we return Command conflict = knownCommands.get(label); if (conflict != null && conflict.getLabel().equals(label)) { return false; } if (!isAlias) { command.setLabel(label); } knownCommands.put(label, command); return registered; } /** * {@inheritDoc} */ public boolean dispatch(CommandSender sender, String commandLine) throws CommandException { String[] args = commandLine.split(" "); if (args.length == 0) { return false; } String sentCommandLabel = args[0].toLowerCase(java.util.Locale.ENGLISH); Command target = getCommand(sentCommandLabel); if (target == null) { return false; } try { // Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false) target.execute(sender, sentCommandLabel, Arrays.copyOfRange(args, 1, args.length)); } catch (CommandException ex) { throw ex; } catch (Throwable ex) { throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex); } // return true as command was handled return true; } public synchronized void clearCommands() { for (Map.Entry entry : knownCommands.entrySet()) { entry.getValue().unregister(this); } knownCommands.clear(); setDefaultCommands(); } public Command getCommand(String name) { Command target = knownCommands.get(name.toLowerCase(java.util.Locale.ENGLISH)); return target; } public List tabComplete(CommandSender sender, String cmdLine) { return tabComplete(sender, cmdLine, null); } public List tabComplete(CommandSender sender, String cmdLine, Location location) { Validate.notNull(sender, "Sender cannot be null"); Validate.notNull(cmdLine, "Command line cannot null"); int spaceIndex = cmdLine.indexOf(' '); if (spaceIndex == -1) { ArrayList completions = new ArrayList(); Map knownCommands = this.knownCommands; final String prefix = (sender instanceof Player ? "/" : ""); for (Map.Entry commandEntry : knownCommands.entrySet()) { Command command = commandEntry.getValue(); if (!command.testPermissionSilent(sender)) { continue; } String name = commandEntry.getKey(); // Use the alias, not command name if (StringUtil.startsWithIgnoreCase(name, cmdLine)) { completions.add(prefix + name); } } Collections.sort(completions, String.CASE_INSENSITIVE_ORDER); return completions; } String commandName = cmdLine.substring(0, spaceIndex); Command target = getCommand(commandName); if (target == null) { return null; } if (!target.testPermissionSilent(sender)) { return null; } String[] args = cmdLine.substring(spaceIndex + 1, cmdLine.length()).split(" ", -1); try { return target.tabComplete(sender, commandName, args, location); } catch (CommandException ex) { throw ex; } catch (Throwable ex) { throw new CommandException("Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target, ex); } } public Collection getCommands() { return Collections.unmodifiableCollection(knownCommands.values()); } public void registerServerAliases() { Map values = server.getCommandAliases(); for (Map.Entry entry : values.entrySet()) { String alias = entry.getKey(); if (alias.contains(" ")) { server.getLogger().warning("Could not register alias " + alias + " because it contains illegal characters"); continue; } String[] commandStrings = entry.getValue(); List targets = new ArrayList(); StringBuilder bad = new StringBuilder(); for (String commandString : commandStrings) { String[] commandArgs = commandString.split(" "); Command command = getCommand(commandArgs[0]); if (command == null) { if (bad.length() > 0) { bad.append(", "); } bad.append(commandString); } else { targets.add(commandString); } } if (bad.length() > 0) { server.getLogger().warning("Could not register alias " + alias + " because it contains commands that do not exist: " + bad); continue; } // We register these as commands so they have absolute priority. if (targets.size() > 0) { knownCommands.put(alias.toLowerCase(java.util.Locale.ENGLISH), new FormattedCommandAlias(alias.toLowerCase(java.util.Locale.ENGLISH), targets.toArray(new String[targets.size()]))); } else { knownCommands.remove(alias.toLowerCase(java.util.Locale.ENGLISH)); } } } }