Skip to content

Command Handling

ljacqu edited this page Dec 20, 2015 · 5 revisions

This page is a technical description of how the commands of AuthMe are registered and handled.

Overview

The following overview shows the most important players in the command handling process.

Command handling overview

Command registration

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.

Mapping of incoming commands

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.

Permissions check

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.

Invocation of 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.