Permissions

Permissions let you control which players are allowed to execute which commands. This is handled using the CommandPermission class, which has the following uses:

PermissionWhat it does
CommandPermission.OPRequires OP to execute the command
CommandPermission.NONEAnyone can execute the command
CommandPermission.fromString("my.permission")Requires a specific permission node to execute the command

In addition to the CommandPermission class, there are two different ways to assign permissions (compared to the simple CommandSender.hasPermission() method that is provided by Bukkit), by using the withPermission method for arguments or for commands.

The withPermission method can take two values:

  • A CommandPermission, which represents a permission such as OP or NONE
  • A String, which will be converted automatically to a CommandPermission using CommandPermission.fromString()

Adding permissions to commands

To add a permission to a command, you can use the withPermission(CommandPermission) or withPermission(String) method when declaring a command.

Example - /god command with permissions

Say we created a command /god that sets a player as being invulnerable. Since this is a pretty non-survival command, we want to restrict who can run this command. As such, we want our player to have the permission command.god in order to run this command. To do this, we simply use the withPermission(CommandPermission) method from our command builder:

// Register the /god command with the permission node "command.god"
new CommandAPICommand("god")
    .withPermission(CommandPermission.fromString("command.god"))
    .executesPlayer((player, args) -> {
        player.setInvulnerable(true);
        player.sendMessage("God mode enabled");
    })
    .register();
// Register the /god command with the permission node "command.god"
CommandAPICommand("god")
    .withPermission(CommandPermission.fromString("command.god"))
    .executesPlayer(PlayerCommandExecutor { player, _ ->
        player.isInvulnerable = true
    })
    .register()

As stated above, it is possible to assign a permission using a String instead of using CommandPermission.fromString():

// Register the /god command with the permission node "command.god", without creating a CommandPermission
new CommandAPICommand("god")
    .withPermission("command.god")
    .executesPlayer((player, args) -> {
        player.setInvulnerable(true);
        player.sendMessage("God mode enabled");
    })
    .register();
// Register the /god command with the permission node "command.god", without creating a CommandPermission
CommandAPICommand("god")
    .withPermission("command.god")
    .executesPlayer(PlayerCommandExecutor { player, _ ->
        player.isInvulnerable = true
    })
    .register()

Adding permissions to arguments

For further fine-tuning of permission management, the CommandAPI allows you to add permissions to individual arguments. This prevents the user from executing a command with a specific argument if they do not have a specific permission.

This is done by using the withPermission(CommandPermission) method at the end of an argument.

If a player does not have the required permission:

  • The argument hover text which suggests what the command is will not be shown
  • The player will receive an error if they try to type something in for that argument
  • Suggestions, such as a list of materials or players, will not be shown

Example - /kill command with argument permissions

For example, say we're registering a command /kill:

/kill          - Kills yourself
/kill <target> - Kills a target player

We first declare the command as normal. Nothing fancy is going on here:

// Register /kill command normally. Since no permissions are applied, anyone can run this command
new CommandAPICommand("kill")
    .executesPlayer((player, args) -> {
        player.setHealth(0);
    })
    .register();
// Register /kill command normally. Since no permissions are applied, anyone can run this command
CommandAPICommand("kill")
    .executesPlayer(PlayerCommandExecutor { player, _ ->
        player.health = 0.0
    })
    .register()

Now we declare our command with arguments. We use a PlayerArgument and apply the permission to the argument. After that, we register our command as normal:

// Adds the OP permission to the "target" argument. The sender requires OP to execute /kill <target>
new CommandAPICommand("kill")
    .withArguments(new PlayerArgument("target").withPermission(CommandPermission.OP))
    .executesPlayer((player, args) -> {
        ((Player) args.get(0)).setHealth(0);
    })
    .register();
// Adds the OP permission to the "target" argument. The sender requires OP to execute /kill <target>
CommandAPICommand("kill")
    .withArguments(PlayerArgument("target").withPermission(CommandPermission.OP))
    .executesPlayer(PlayerCommandExecutor { _, args ->
        (args[0] as Player).health = 0.0
    })
    .register()

Developer's Note:

As you can see, there are multiple ways of applying permissions to commands with arguments. In the /god command shown above, the permission was applied to the whole command. In the /kill command shown above, the permission was applied to the argument.

There's not really much difference between the two methods, but I personally would use argument permissions as it has greater control over arguments.


Child-based permissions

Child-based permissions allow you to group permissions together. We achieve this by laying out our permission groups in the plugin.yml file which Bukkit registers as valid permissions. When the CommandAPI checks if our player has a permission, Bukkit considers if they have the child of a permission as well. This not only keeps permissions easier to manage, it also makes your code cleaner and gives you a nice place to lay out all of your permissions, detailing what they do and what other permissions inherit them.

Example - /economy command with argument permissions

For example, say we're registering a command /economy:

/economy                         - shows your own balance                 | economy.self
/economy <target>                - shows you another players balance      | economy.other
/economy give  <target> <amount> - gives the target a set amount of money | economy.admin.give
/economy reset <target> <amount> - resets the targets balance             | economy.admin.reset

We first declare the command as normal. Nothing fancy is going on here:

// /economy - requires the permission "economy.self" to execute
new CommandAPICommand("economy")
    .withPermission("economy.self") // The important part of this example
    .executesPlayer((player, args) -> {
        // send the executor their own balance here.
    })
    .register();

// /economy <target> - requires the permission "economy.other" to execute
new CommandAPICommand("economy")
    .withPermission("economy.other") // The important part of this example
    .withArguments(new PlayerArgument("target"))
    .executesPlayer((player, args) -> {
        Player target = (Player) args.get(0);

        // Send a message to the executor with the the target's balance
        player.sendMessage(target.getName() + "'s balance: " + Economy.getBalance(target));
    })
    .register();

// /economy give <target> <amount> - requires the permission "economy.admin.give" to execute
new CommandAPICommand("economy")
    .withPermission("economy.admin.give") // The important part of this example
    .withArguments(new PlayerArgument("target"))
    .withArguments(new DoubleArgument("amount"))
    .executesPlayer((player, args) -> {
        Player target = (Player) args.get(0);
        double amount = (Double) args.get(1);

        // Update the target player's balance
        Economy.updateBalance(target, amount);
    })
    .register();

// /economy reset <target> - requires the permission "economy.admin.reset" to execute
new CommandAPICommand("economy")
    .withPermission("economy.admin.reset") // The important part of this example
    .withArguments(new PlayerArgument("target"))
    .executesPlayer((player, args) -> {
        Player target = (Player) args.get(0);

        // Reset target balance here
        Economy.resetBalance(target);
    })
    .register();
// /economy - requires the permission "economy.self" to exectue
CommandAPICommand("economy")
    .withPermission("economy.self")
    .executesPlayer(PlayerCommandExecutor { player, _ ->
        // send the executor their own balance here.
    })
    .register()

// /economy <target> - requires the permission "economy.other" to execute
CommandAPICommand("economy")
    .withPermission("economy.other") // The important part of this example
    .withArguments(PlayerArgument("target"))
    .executesPlayer(PlayerCommandExecutor { player, args ->
        val target = args[0] as Player
        // send the executor the targets balance here.
    })
    .register()

// /economy give <target> <amount> - requires the permission "economy.admin.give" to execute
CommandAPICommand("economy")
    .withPermission("economy.admin.give") // The important part of this example
    .withArguments(PlayerArgument("target"))
    .withArguments(DoubleArgument("amount"))
    .executesPlayer(PlayerCommandExecutor { player, args ->
        val target = args[0] as Player
        val amount = args[1] as Double
        // update the targets balance here
    })
    .register()

// /economy reset <target> - requires the permission "economy.admin.reset" to execute
CommandAPICommand("economy")
    .withPermission("economy.admin.reset") // The important part of this example
    .withArguments(PlayerArgument("target"))
    .executesPlayer(PlayerCommandExecutor { player, args ->
        val target = args[0] as Player
        // reset the targets balance here
    })
    .register()

In our plugin.yml we can also set up our permissions for example...

permissions:
  economy.*:
    description: Gives the user full access to the economy commands
    children:
      economy.other: true
      economy.admin.*: true

  economy.self:
    description: Allows the user to view their own balance
  economy.other:
    description: Allows the user to another players balance
    children:
      economy.self: true

  economy.admin.*:
    description: Gives the user access to all of the admin commands
    children:
      economy.admin.give: true
      economy.admin.reset: true
  economy.admin.give:
    description: Gives the user access to /economy give <target> <amount>
  economy.admin.reset:
    description: Gives the user access to /economy reset <target>

This setup of children allows us to give a player less permissions, but have them access more features. Since economy.* inherits economy.admin.* which inherits economy.admin.give, a player with the permission economy.* will be able to execute /economy give <target> <amount> without them directly having the economy.admin.give permission node. This also works with economy.other, if a player has economy.other they will inherit economy.