mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-06 18:50:51 +01:00
Reworked command registration so that aliases are secondary to the primary command label requested
Updated docs to reflect what the code really does This adds a few new methods to Command including:- * A full constructor that takes descriptio, usageMassage and aliases for convenience * getLabel() which returns the active label for a command, which is derived from the Command name or subsiquent call to setLabel(..) * A number of registration functions for use in the CommandMap implementer Also of note is Command.getAliases() no returns the "active" aliases By: stevenh <steven.hartland@multiplay.co.uk>
This commit is contained in:
parent
a679c0c906
commit
8eddaae2f2
3 changed files with 189 additions and 51 deletions
|
@ -8,14 +8,26 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public abstract class Command {
|
public abstract class Command {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private String nextLabel;
|
||||||
|
private String label;
|
||||||
private List<String> aliases;
|
private List<String> aliases;
|
||||||
|
private List<String> activeAliases;
|
||||||
|
private CommandMap commandMap = null;
|
||||||
protected String description = "";
|
protected String description = "";
|
||||||
protected String usageMessage;
|
protected String usageMessage;
|
||||||
|
|
||||||
protected Command(String name) {
|
protected Command(String name) {
|
||||||
|
this(name, "", "/" + name, new ArrayList<String>());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Command(String name, String description, String usageMessage, List<String> aliases) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.aliases = new ArrayList<String>();
|
this.nextLabel = name;
|
||||||
this.usageMessage = "/" + name;
|
this.label = name;
|
||||||
|
this.description = description;
|
||||||
|
this.usageMessage = usageMessage;
|
||||||
|
this.aliases = aliases;
|
||||||
|
this.activeAliases = new ArrayList<String>(aliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,12 +50,84 @@ public abstract class Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of aliases registered to this command
|
* Returns the current lable for this command
|
||||||
|
*
|
||||||
|
* @return Label of this command or null if not registered
|
||||||
|
*/
|
||||||
|
public String getLabel() {
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the label of this command
|
||||||
|
* If the command is currently registered the label change will only take effect after
|
||||||
|
* its been reregistered e.g. after a /reload
|
||||||
|
*
|
||||||
|
* @return returns true if the name change happened instantly or false if it was scheduled for reregistration
|
||||||
|
*/
|
||||||
|
public boolean setLabel(String name) {
|
||||||
|
this.nextLabel = name;
|
||||||
|
if (!isRegistered()) {
|
||||||
|
this.label = name;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers this command to a CommandMap
|
||||||
|
* Once called it only allows changes the registered CommandMap
|
||||||
|
*
|
||||||
|
* @param commandMap the CommandMap to register this command to
|
||||||
|
* @return true if the registration was successful (the current registered CommandMap was the passed CommandMap or null) false otherwise
|
||||||
|
*/
|
||||||
|
public boolean register(CommandMap commandMap) {
|
||||||
|
if (allowChangesFrom(commandMap)) {
|
||||||
|
this.commandMap = commandMap;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters this command from the passed CommandMap applying any outstanding changes
|
||||||
|
*
|
||||||
|
* @param commandMap the CommandMap to unregister
|
||||||
|
* @return true if the unregistration was successfull (the current registered CommandMap was the passed CommandMap or null) false otherwise
|
||||||
|
*/
|
||||||
|
public boolean unregister(CommandMap commandMap) {
|
||||||
|
if (allowChangesFrom(commandMap)) {
|
||||||
|
this.commandMap = null;
|
||||||
|
this.activeAliases = new ArrayList<String>(this.aliases);
|
||||||
|
this.label = this.nextLabel;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean allowChangesFrom(CommandMap commandMap) {
|
||||||
|
return (null == this.commandMap || this.commandMap == commandMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current registered state of this command
|
||||||
|
*
|
||||||
|
* @return true if this command is currently registered false otherwise
|
||||||
|
*/
|
||||||
|
public boolean isRegistered() {
|
||||||
|
return (null != this.commandMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of active aliases of this command
|
||||||
*
|
*
|
||||||
* @return List of aliases
|
* @return List of aliases
|
||||||
*/
|
*/
|
||||||
public List<String> getAliases() {
|
public List<String> getAliases() {
|
||||||
return aliases;
|
return activeAliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,13 +149,16 @@ public abstract class Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the list of aliases registered to this command
|
* Sets the list of aliases to request on registration for this command
|
||||||
*
|
*
|
||||||
* @param aliases Aliases to register to this command
|
* @param aliases Aliases to register to this command
|
||||||
* @return This command object, for linking
|
* @return This command object, for linking
|
||||||
*/
|
*/
|
||||||
public Command setAliases(List<String> aliases) {
|
public Command setAliases(List<String> aliases) {
|
||||||
this.aliases = aliases;
|
this.aliases = aliases;
|
||||||
|
if (!isRegistered()) {
|
||||||
|
this.activeAliases = new ArrayList<String>(aliases);
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,40 @@ public interface CommandMap {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers all the commands belonging to a certain plugin.
|
* Registers all the commands belonging to a certain plugin.
|
||||||
* @param plugin
|
* Caller can use:-
|
||||||
* @return
|
* command.getName() to determine the label registered for this command
|
||||||
|
* command.getAliases() to determine the aliases which where registered
|
||||||
|
*
|
||||||
|
* @param fallbackPrefix a prefix which is prepended to each command with a ':' one or more times to make the command unique
|
||||||
|
* @param commands a list of commands to register
|
||||||
*/
|
*/
|
||||||
public void registerAll(String fallbackPrefix, List<Command> commands);
|
public void registerAll(String fallbackPrefix, List<Command> commands);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a command. Returns true on success; false if name is already taken and fallback had to be used.
|
* Registers a command. Returns true on success; false if name is already taken and fallback had to be used.
|
||||||
|
* Caller can use:-
|
||||||
|
* command.getName() to determine the label registered for this command
|
||||||
|
* command.getAliases() to determine the aliases which where registered
|
||||||
*
|
*
|
||||||
* @param a label for this command, without the '/'-prefix.
|
* @param label the label of the command, without the '/'-prefix.
|
||||||
* @return Returns true if command was registered; false if label was already in use.
|
* @param fallbackPrefix a prefix which is prepended to the command with a ':' one or more times to make the command unique
|
||||||
|
* @param command the command to register
|
||||||
|
* @return true if command was registered with the passed in label, false otherwise, which indicates the fallbackPrefix was used one or more times
|
||||||
*/
|
*/
|
||||||
public boolean register(String label, String fallbackPrefix, Command command);
|
public boolean register(String label, String fallbackPrefix, Command command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a command. Returns true on success; false if name is already taken and fallback had to be used.
|
||||||
|
* Caller can use:-
|
||||||
|
* command.getName() to determine the label registered for this command
|
||||||
|
* command.getAliases() to determine the aliases which where registered
|
||||||
|
*
|
||||||
|
* @param fallbackPrefix a prefix which is prepended to the command with a ':' one or more times to make the command unique
|
||||||
|
* @param command the command to register, from which label is determined from the command name
|
||||||
|
* @return true if command was registered with the passed in label, false otherwise, which indicates the fallbackPrefix was used one or more times
|
||||||
|
*/
|
||||||
|
public boolean register(String fallbackPrefix, Command command);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for the requested command and executes it if found.
|
* Looks for the requested command and executes it if found.
|
||||||
*
|
*
|
||||||
|
@ -26,7 +47,7 @@ public interface CommandMap {
|
||||||
* @return targetFound returns false if no target is found.
|
* @return targetFound returns false if no target is found.
|
||||||
* @throws CommandException Thrown when the executor for the given command fails with an unhandled exception
|
* @throws CommandException Thrown when the executor for the given command fails with an unhandled exception
|
||||||
*/
|
*/
|
||||||
public boolean dispatch(CommandSender sender, String cmdLine);
|
public boolean dispatch(CommandSender sender, String cmdLine) throws CommandException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears all registered commands.
|
* Clears all registered commands.
|
||||||
|
@ -37,7 +58,7 @@ public interface CommandMap {
|
||||||
* Gets the command registered to the specified name
|
* Gets the command registered to the specified name
|
||||||
*
|
*
|
||||||
* @param name Name of the command to retrieve
|
* @param name Name of the command to retrieve
|
||||||
* @return Command with the specified name
|
* @return Command with the specified name or null if a command with that label doesn't exist
|
||||||
*/
|
*/
|
||||||
public Command getCommand(String name);
|
public Command getCommand(String name);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
|
@ -32,9 +33,7 @@ public final class SimpleCommandMap implements CommandMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers multiple commands. Returns name of first command for which fallback had to be used if any.
|
* {@inheritDoc}
|
||||||
* @param plugin
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public void registerAll(String fallbackPrefix, List<Command> commands) {
|
public void registerAll(String fallbackPrefix, List<Command> commands) {
|
||||||
if (commands != null) {
|
if (commands != null) {
|
||||||
|
@ -44,41 +43,74 @@ public final class SimpleCommandMap implements CommandMap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void register(String fallbackPrefix, Command command) {
|
/**
|
||||||
register(command.getName(), fallbackPrefix, command);
|
* {@inheritDoc}
|
||||||
aliases.addAll(command.getAliases());
|
*/
|
||||||
aliases.remove(command.getName());
|
public boolean register(String fallbackPrefix, Command command) {
|
||||||
|
return register(command.getName(), fallbackPrefix, command);
|
||||||
for (String name : command.getAliases()) {
|
|
||||||
register(name, fallbackPrefix, command);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public boolean register(String name, String fallbackPrefix, Command command) {
|
public boolean register(String label, String fallbackPrefix, Command command) {
|
||||||
boolean nameInUse = nameInUse(name);
|
boolean registeredPassedLabel = register(label, fallbackPrefix, command, false);
|
||||||
|
|
||||||
if (nameInUse) {
|
Iterator iterator = command.getAliases().iterator();
|
||||||
name = fallbackPrefix + ":" + name;
|
while (iterator.hasNext()) {
|
||||||
|
if (!register((String) iterator.next(), fallbackPrefix, command, true)) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
knownCommands.put(name.toLowerCase(), command);
|
// Register to us so further updates of the commands label and aliases are postponed until its reregistered
|
||||||
return !nameInUse;
|
command.register(this);
|
||||||
|
|
||||||
|
return registeredPassedLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean nameInUse(String name) {
|
/**
|
||||||
if (getCommand(name) != null) {
|
* Registers a command with the given name is possible, otherwise uses fallbackPrefix to create a unique name if its not an alias
|
||||||
return !aliases.contains(name);
|
* @param name the name of the command, without the '/'-prefix.
|
||||||
|
* @param fallbackPrefix a prefix which is prepended to the command with a ':' one or more times to make the command unique
|
||||||
|
* @param command the command to register
|
||||||
|
* @return true if command was registered with the passed in label, false otherwise.
|
||||||
|
* If isAlias was true a return of false indicates no command was registerd
|
||||||
|
* If isAlias was false a return of false indicates the fallbackPrefix was used one or more times to create a unique name for the command
|
||||||
|
*/
|
||||||
|
private synchronized boolean register(String label, String fallbackPrefix, Command command, boolean isAlias) {
|
||||||
|
String lowerLabel = label.trim().toLowerCase();
|
||||||
|
|
||||||
|
if (isAlias && knownCommands.containsKey(lowerLabel)) {
|
||||||
|
// Request is for an alias 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;
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
boolean registerdPassedLabel = true;
|
||||||
|
|
||||||
|
// If the command exists but is an alias we overwrite it, otherwise we rename it based on the fallbackPrefix
|
||||||
|
while (knownCommands.containsKey(lowerLabel) && !aliases.contains(lowerLabel)) {
|
||||||
|
lowerLabel = fallbackPrefix + ":" + lowerLabel;
|
||||||
|
registerdPassedLabel = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAlias) {
|
||||||
|
aliases.add(lowerLabel);
|
||||||
|
} else {
|
||||||
|
// Ensure lowerLabel isn't listed as a alias anymore and update the commands registered name
|
||||||
|
aliases.remove(lowerLabel);
|
||||||
|
command.setLabel(lowerLabel);
|
||||||
|
}
|
||||||
|
knownCommands.put(lowerLabel, command);
|
||||||
|
|
||||||
|
return registerdPassedLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
public boolean dispatch(CommandSender sender, String commandLine) {
|
public boolean dispatch(CommandSender sender, String commandLine) throws CommandException {
|
||||||
String[] args = commandLine.split(" ");
|
String[] args = commandLine.split(" ");
|
||||||
|
|
||||||
if (args.length == 0) {
|
if (args.length == 0) {
|
||||||
|
@ -86,29 +118,27 @@ public final class SimpleCommandMap implements CommandMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
String sentCommandLabel = args[0].toLowerCase();
|
String sentCommandLabel = args[0].toLowerCase();
|
||||||
|
|
||||||
args = Arrays_copyOfRange(args, 1, args.length);
|
|
||||||
|
|
||||||
Command target = getCommand(sentCommandLabel);
|
Command target = getCommand(sentCommandLabel);
|
||||||
boolean isRegisteredCommand = (target != null);
|
if (target == null) {
|
||||||
|
return false;
|
||||||
if (isRegisteredCommand) {
|
}
|
||||||
try {
|
|
||||||
target.execute(sender, sentCommandLabel, args);
|
try {
|
||||||
} catch (CommandException ex) {
|
return target.execute(sender, sentCommandLabel, Arrays_copyOfRange(args, 1, args.length));
|
||||||
throw ex;
|
} catch (CommandException ex) {
|
||||||
} catch (Throwable ex) {
|
throw ex;
|
||||||
throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex);
|
} catch (Throwable ex) {
|
||||||
}
|
throw new CommandException("Unhandled exception executing '" + commandLine + "' in " + target, ex);
|
||||||
}
|
}
|
||||||
return isRegisteredCommand;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearCommands() {
|
public synchronized void clearCommands() {
|
||||||
synchronized (this) {
|
for (Map.Entry<String,Command> entry : knownCommands.entrySet()) {
|
||||||
knownCommands.clear();
|
entry.getValue().unregister(this);
|
||||||
setDefaultCommands(server);
|
|
||||||
}
|
}
|
||||||
|
knownCommands.clear();
|
||||||
|
aliases.clear();
|
||||||
|
setDefaultCommands(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command getCommand(String name) {
|
public Command getCommand(String name) {
|
||||||
|
|
Loading…
Reference in a new issue