Creating Your First Command

Prerequisites#

This guide assumes that you have a plugin environment setup. If you have not already, follow that guide first.

Writing a Command type#

Each command for GoMint plugins must extend the Command type to be recognized by the plugin manager. This guide will walk you through setting up a velocity command.

public class CommandVelocity extends Command {}

Using Annotations#

Commands in GoMint are based on annotations and injection. There are two required annotations that each command must have, but the full list of annotations for commands are below. GoMint will detect all classes in your plugin which extend Command and have at least the required annotations and will automatically create an instance and register it. For custom conditions on command registration you need to use methods for describing your command instead.

AnnotationTypeValueRequired?Repeatable?
NameStringThe command's nameYesNo
DescriptionStringA description of the commandYesNo
AliasStringAn alias for the command that will also execute itNoYes
PermissionStringThe permission required for the command to executeNoNo
Overload...See overload annotation informationNoYes

The next step to writing your command is to add the necessary annotations to the class:

@Name("velocity")
@Description("Give custom velocity to the player who runs it")
public class CommandVelocity extends Command {}

Required Methods#

The only required method for a Command type is the execute method, which must be overridden from io.gomint.command.Command type. Our CommandVelocity type then becomes:

@Name("velocity")
@Description("Give custom velocity to the player who runs it")
public class CommandVelocity extends Command {
@Override
public CommandOutput execute(CommandSender commandSender, String alias, Map<String, Object> arguments) {
CommandOutput output = new CommandOutput();
return output;
}
}

Casting the CommandSender#

The CommandSender type that is passed to execute by the server's command handler can be cast in two ways: a PlayerCommandSender or a ConsoleCommandSender. It is important to verify that the sender was the correct type before performing any kind of operations on them. Player methods are unavailable to ConsoleCommandSenders and vice-versa. A simple instanceof check will suffice:

@Name("velocity")
@Description("Give custom velocity to the player who runs it")
public class CommandVelocity extends Command {
@Override
public CommandOutput execute(CommandSender commandSender, String alias, Map<String, Object> arguments) {
CommandOutput output = new CommandOutput();
if (commandSender instanceof PlayerCommandSender) {
EntityPlayer player = (EntityPlayer) commandSender;
// Now that we have casted the CommandSender to an EntityPlayer, we can use those methods on the object.
player.setVelocity(new Vector(0, 2, 0));
} else if (commandSender instanceof ConsoleCommandSender) {
// TODO: Let's add arguments in a moment!
}
return output;
}
}

Adding Permissions#

Adding permissions to a command is as simple as adding the permission annotation. Supposing that we want to only allow players to use the velocity command if they have the velocityplugin.command.velocity, we can append the annotation to the class declaration:

@Name("velocity")
@Description("Give custom velocity to the player who runs it")
@Permission("velocityplugin.command.velocity")
public class CommandVelocity extends Command {...}

Using Parameters (Arguments)#

For more complicated commands that require parameters to be passed, you can both check and validate the types of arguments passed. First, we will address how to use the arguments passed to a command. Second, we will address how to use annotations to validate the types of these arguments.

Overload Annotation#

When using arguments, we can validate their type as well as assign them names. This allows us to anticipate not only the way the arguments of the command are organized, but their types, and, to a degree, validate their content.

For arguments, the Overload annotation is used. Within this annotation, Parameter annotations can be used to define a name for the arguments passed, a validator to use, and specify whether or not the parameter is optional.

Note: For each Overload annotation, your command will have a different way to organize parameters. Multiple Overload annotations can be summarized by using the Overloads annotation.

The parameter annotation accepts the following fields:

  • name - String: The name of the parameter (stored as a key in the arguments map)
  • validator - Class that extends ParamValidator: The validator to use for this parameter. Can be implemented, or you can use any of the API's built-in validators
  • optional - Boolean: Whether or not the parameter is optional (note: defaults to false)
// Our velocity command should be able to accept a parameter for a player name and the specified velocity they should receive.
@Overload({
@Parameter(name = "player", validator = TargetValidator.class, optional = true)
@Parameter(name = "velocity_x", validator = FloatValidator.class, optional = true)
@Parameter(name = "velocity_y", validator = FloatValidator.class, optional = true)
@Parameter(name = "velocity_z", validator = FloatValidator.class, optional = true)
})

Arguments Passed#

The arguments passed when a command is executed by the player/console are passed to execute in the Map object arguments. For our velocity command example, we will allow a ConsoleCommandSender to specify a player's name to apply the velocity to.

// Continued from above
else if (commandSender instanceof ConsoleCommandSender) {
EntityPlayer player = (EntityPlayer) arguments.get("player");
Float velocity_x = (Float) arguments.getOrDefault("velocity_x", 0f);
Float velocity_y = (Float) arguments.getOrDefault("velocity_y", 2f);
Float velocity_z = (Float) arguments.getOrDefault("velocity_z", 0f);
// If all the parameters were passed, the player will receive the specified velocity.
// Otherwise, they will receive a velocity of (x: 0, y: 2, z: 0).
player.setVelocity(new Vector(velocity_x, velocity_y, velocity_z));
// When the velocity was successfully applied to the given player, a messagae will be sent to the ConsoleCommandSender.
output.success("Applied velocity to " + player.getNameTag());
}

Additional Information#

Adding Commands Using Methods#

If you want to have commands registered based on custom conditions, you need to use method calls to describe your command instead of annotations.

You register your method-based described commands with the registerCommand(/* your command instance*/); method present in the Plugin object (your main class).

The name of the command has to be delivered as parameter of the Command class constructor and the description has to be set with the description(String) method:

public class CommandVelocity extends Command {
public CommandVelocity() {
super("velocity");
description("Give custom velocity to the player who runs it");
}
@Override
public CommandOutput execute(CommandSender commandSender, String alias, Map<String, Object> arguments) {
CommandOutput output = new CommandOutput();
return output;
}
}

The other method names are named similar to the annotation as well:

AnnotationMethodTypeValueRequired?Repeatable?
Namesuper("...")StringThe command's nameYesNo
Descriptiondescription("...")StringA description of the commandYesNo
Aliasalias("...")StringAn alias for the command that will also execute itNoYes
Permissionpermission("...")StringThe permission required for the command to executeNoNo
Overloadoverload().param(...)...See belowNoYes

Calling not repeatable methods again will overwrite the existing value.

Overload Method#

Each call to overload() will add a new overload to your method. By default the overload is empty. To add a parameter you have to call the param(...) functions on the return ComandOverload object.

The param function takes the name of parameter first, next up is the ParamValidator. The third argument is the optional boolean, which is itself optional and defaults to false as well. The ParamValidator needs to be instantiated here instead of it's class.

public CommandVelocity() {
super("velocity");
description("Give custom velocity to the player who runs it");
permission("velocityplugin.command.velocity");
overload().param("player", new TargetValidator(), true)
.param("velocity_x", new FloatValidator(), true)
.param("velocity_y", new FloatValidator(), true)
.param("velocity_z", new FloatValidator(), true);
}