-
Notifications
You must be signed in to change notification settings - Fork 515
Command Handling
This page is a technical description of how the commands of AuthMe are registered and handled.
The following overview shows the most important players in the command handling process.
We use CommandDescription
objects to define the commands available in AuthMe. These objects do not contain any logic of the command but contain all of the necessary information to invoke the command it describes: the labels to access the command (e.g. must use /authme register
or /authme reg
), the necessary number of arguments and a link to the actual command implementation.
When a command is invoked, Bukkit (or Spigot) passes the information to the plugin with the arguments String commandLabel, String[] args
. The Bukkit command label simply contains the first "word" of a command (e.g. authme
in /authme reload
) and the Bukkit arguments are the rest.
In AuthMe, we call labels any tokens at the beginning that lead to a command, so e.g. in /authme register billy pass123
the labels are authme, register
as they lead to the admin register command. In the beginning, we don't know what is a label and what is an argument yet, so we collectively refer to them as command parts.
The first job is to determine which of the parts are labels and arguments. If the parts could be mapped to a command description and the number of arguments is valid according to the CommandDescription, we speak of a successful mapping. For example, /authme register billy pass123
leads to the command description for the admin registration command and leaves us with the arguments billy, pass123
. The command description defines two mandatory arguments, so the argument count matched and we have a successful mapping.
Safe assumption: It is safe to assume while programming that there will be at most 2 labels to access a command (such as /authme register
, whereas /authme user register
– with three labels – cannot occur). Any more would unnecessarily complicate our command structure and our code. There is a test verifying that no command description is initialized with more than two labels. Nevertheless, you are still encouraged to write logic related to labels generically if it is not a lot more complicated.
Permission-related logic is handled in the permission
package. The CommandHandler class passes the command sender and the command description to the PermissionsManager to query whether the user may invoke the command.
If the permissions check is successful, the command can be invoked. Each command description has a subclass of ExecutableCommand
linked to it which is the class for actually executing the command logic. The arguments are passed to it.
An ExecutableCommand
instance may call further objects, typically for asynchronous processing when database calls are involved. In such cases, the ExecutableCommand
typically does as much validation as necessary which doesn't require I/O operations (e.g. does the password confirmation match?, is the player online?) and then passes the data on to an async task which handles interactions with the database.
Safe assumption: Within an ExecutableCommand
, it is safe to assume that all mandatory arguments defined in the corresponding command description(s) are present. The command handler will not execute a command if the argument count does not match.
The following graph shows the dependencies of the command classes and in which order they are instantiated.