Newer
Older
ultramine_bukkit / src / main / java / org / bukkit / command / SimpleCommandMap.java
@vlad20012 vlad20012 on 24 Feb 2017 11 KB initial
package org.bukkit.command;

import org.apache.commons.lang.Validate;
import org.bukkit.Server;
import org.bukkit.command.defaults.AchievementCommand;
import org.bukkit.command.defaults.BanCommand;
import org.bukkit.command.defaults.BanIpCommand;
import org.bukkit.command.defaults.BanListCommand;
import org.bukkit.command.defaults.ClearCommand;
import org.bukkit.command.defaults.DefaultGameModeCommand;
import org.bukkit.command.defaults.DeopCommand;
import org.bukkit.command.defaults.DifficultyCommand;
import org.bukkit.command.defaults.EffectCommand;
import org.bukkit.command.defaults.EnchantCommand;
import org.bukkit.command.defaults.ExpCommand;
import org.bukkit.command.defaults.GameModeCommand;
import org.bukkit.command.defaults.GameRuleCommand;
import org.bukkit.command.defaults.GiveCommand;
import org.bukkit.command.defaults.HelpCommand;
import org.bukkit.command.defaults.KickCommand;
import org.bukkit.command.defaults.KillCommand;
import org.bukkit.command.defaults.ListCommand;
import org.bukkit.command.defaults.MeCommand;
import org.bukkit.command.defaults.OpCommand;
import org.bukkit.command.defaults.PardonCommand;
import org.bukkit.command.defaults.PardonIpCommand;
import org.bukkit.command.defaults.PlaySoundCommand;
import org.bukkit.command.defaults.PluginsCommand;
import org.bukkit.command.defaults.ReloadCommand;
import org.bukkit.command.defaults.SaveCommand;
import org.bukkit.command.defaults.SaveOffCommand;
import org.bukkit.command.defaults.SaveOnCommand;
import org.bukkit.command.defaults.SayCommand;
import org.bukkit.command.defaults.ScoreboardCommand;
import org.bukkit.command.defaults.SeedCommand;
import org.bukkit.command.defaults.SetIdleTimeoutCommand;
import org.bukkit.command.defaults.SetWorldSpawnCommand;
import org.bukkit.command.defaults.SpawnpointCommand;
import org.bukkit.command.defaults.SpreadPlayersCommand;
import org.bukkit.command.defaults.StopCommand;
import org.bukkit.command.defaults.TeleportCommand;
import org.bukkit.command.defaults.TellCommand;
import org.bukkit.command.defaults.TestForCommand;
import org.bukkit.command.defaults.TimeCommand;
import org.bukkit.command.defaults.ToggleDownfallCommand;
import org.bukkit.command.defaults.VanillaCommand;
import org.bukkit.command.defaults.VersionCommand;
import org.bukkit.command.defaults.WeatherCommand;
import org.bukkit.command.defaults.WhitelistCommand;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;

import java.util.ArrayList;
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 static org.bukkit.util.Java15Compat.Arrays_copyOfRange;

public class SimpleCommandMap implements CommandMap
{
	private static final Pattern PATTERN_ON_SPACE = Pattern.compile(" ", Pattern.LITERAL);
	protected final Map<String, Command> knownCommands = new HashMap<String, Command>();
	private final Server server;

	public SimpleCommandMap(final Server server)
	{
		this.server = server;
		setDefaultCommands();
	}

	protected void setDefaultCommands()
	{
		register("bukkit", new SaveCommand());
		register("bukkit", new SaveOnCommand());
		register("bukkit", new SaveOffCommand());
		register("bukkit", new StopCommand());
		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 ListCommand());
		register("bukkit", new OpCommand());
		register("bukkit", new DeopCommand());
		register("bukkit", new BanIpCommand());
		register("bukkit", new PardonIpCommand());
		register("bukkit", new BanCommand());
		register("bukkit", new PardonCommand());
		register("bukkit", new KickCommand());
		register("bukkit", new TeleportCommand());
		register("bukkit", new GiveCommand());
		register("bukkit", new TimeCommand());
		register("bukkit", new SayCommand());
		register("bukkit", new WhitelistCommand());
		register("bukkit", new TellCommand());
		register("bukkit", new MeCommand());
		register("bukkit", new KillCommand());
		register("bukkit", new GameModeCommand());
		register("bukkit", new HelpCommand());
		register("bukkit", new ExpCommand());
		register("bukkit", new ToggleDownfallCommand());
		register("bukkit", new BanListCommand());
		register("bukkit", new DefaultGameModeCommand());
		register("bukkit", new SeedCommand());
		register("bukkit", new DifficultyCommand());
		register("bukkit", new WeatherCommand());
		register("bukkit", new SpawnpointCommand());
		register("bukkit", new ClearCommand());
		register("bukkit", new GameRuleCommand());
		register("bukkit", new EnchantCommand());
		register("bukkit", new TestForCommand());
		register("bukkit", new EffectCommand());
		register("bukkit", new ScoreboardCommand());
		register("bukkit", new PlaySoundCommand());
		register("bukkit", new SpreadPlayersCommand());
		register("bukkit", new SetWorldSpawnCommand());
		register("bukkit", new SetIdleTimeoutCommand());
		register("bukkit", new AchievementCommand());
	}

	/**
	 * {@inheritDoc}
	 */
	public void registerAll(String fallbackPrefix, List<Command> 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().trim();
		fallbackPrefix = fallbackPrefix.toLowerCase().trim();
		boolean registered = register(label, command, false, fallbackPrefix);

		Iterator<String> 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 VanillaCommand || 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;
		}

		// 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 true;
	}

	/**
	 * {@inheritDoc}
	 */
	public boolean dispatch(CommandSender sender, String commandLine) throws CommandException
	{
		String[] args = PATTERN_ON_SPACE.split(commandLine);

		if(args.length == 0)
		{
			return false;
		}

		String sentCommandLabel = args[0].toLowerCase();
		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(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<String, Command> entry : knownCommands.entrySet())
		{
			entry.getValue().unregister(this);
		}
		knownCommands.clear();
		setDefaultCommands();
	}

	public Command getCommand(String name)
	{
		Command target = knownCommands.get(name.toLowerCase());
		return target;
	}

	public List<String> tabComplete(CommandSender sender, String cmdLine)
	{
		Validate.notNull(sender, "Sender cannot be null");
		Validate.notNull(cmdLine, "Command line cannot null");

		int spaceIndex = cmdLine.indexOf(' ');

		if(spaceIndex == -1)
		{
			ArrayList<String> completions = new ArrayList<String>();
			Map<String, Command> knownCommands = this.knownCommands;

			final String prefix = (sender instanceof Player ? "/" : "");

			for(Map.Entry<String, Command> 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 argLine = cmdLine.substring(spaceIndex + 1, cmdLine.length());
		String[] args = PATTERN_ON_SPACE.split(argLine, -1);

		try
		{
			return target.tabComplete(sender, commandName, args);
		} catch(CommandException ex)
		{
			throw ex;
		} catch(Throwable ex)
		{
			throw new CommandException("Unhandled exception executing tab-completer for '" + cmdLine + "' in " + target, ex);
		}
	}

	public Collection<Command> getCommands()
	{
		return Collections.unmodifiableCollection(knownCommands.values());
	}

	public void registerServerAliases()
	{
		Map<String, String[]> values = server.getCommandAliases();

		for(String alias : values.keySet())
		{
			if(alias.contains(":") || alias.contains(" "))
			{
				server.getLogger().warning("Could not register alias " + alias + " because it contains illegal characters");
				continue;
			}

			String[] commandStrings = values.get(alias);
			List<String> targets = new ArrayList<String>();
			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(), new FormattedCommandAlias(alias.toLowerCase(), targets.toArray(new String[targets.size()])));
			}
			else
			{
				knownCommands.remove(alias.toLowerCase());
			}
		}
	}
}