Skip to content

Command Arguments

Gabriel Souza edited this page Apr 12, 2021 · 18 revisions

What is Arguments

Arguments is an extension function for Executor that parsers the arguments in the command.

It's important you read Command Fail first because the Arguments Extensions works with it.

val MISSING_STRING_PARAMETER = "Missing a word argument.".color(ChatColor.RED)

fun Executor<*>.string(
        index: Int,
        argMissing: BaseComponent = MISSING_STRING_PARAMETER
): String = args.getOrNull(index) ?: throw CommandFailException(argMissing, true)
  • index is argument position that the player should inform (start in zero, like args array)
  • argMissing is the message to send the Player/Console if the argument was not informed in the command.

Usage

// /createClan CLAN_NAME CLAN_TAG
myPlugin.simpleCommand("createClan") { 
  val clanName = string(0)
  val clanTag = string(1)

  MyClanManager.createClan(sender as Player, clanName, clanTag)
}

More useful Arguments

Player

val PLAYER_MISSING_PARAMETER = "Missing a player argument!".color(ChatColor.RED)
val PLAYER_NOT_ONLINE = "The player specified is not online.".color(ChatColor.RED)

// returns a [Player] or null if the player is not online.
fun Executor<*>.playerOrNull(
        index: Int,
        argMissing: BaseComponent = PLAYER_MISSING_PARAMETER
): Player?

fun Executor<*>.player(
        index: Int,
        argMissing: BaseComponent = PLAYER_MISSING_PARAMETER,
        notOnline: BaseComponent = PLAYER_NOT_ONLINE
): Player

Example

// /isOnline PLAYER_NAME
myPlugin.simpleCommand("isOnline") {
  val target: Player? = playerOrNull(index = 0)

  if(target != null) {
    sender.msg("This player is online")
  } else {
    sender.msg("This player is offline")
  }
}

Int

val MISSING_NUMBER_PARAMETER = "Missing a number argument.".color(ChatColor.RED)
val NUMBER_FORMAT = "The parameter needs only numbers.".color(ChatColor.RED)

// Returns [Int] or null if was not able to parse to Int.
fun Executor<*>.intOrNull(
        index: Int,
        argMissing: BaseComponent = MISSING_NUMBER_PARAMETER
): Int? = string(index, argMissing).toIntOrNull()

fun Executor<*>.int(
        index: Int,
        argMissing: BaseComponent = MISSING_NUMBER_PARAMETER,
        numberFormat: BaseComponent = NUMBER_FORMAT
): Int = intOrNull(index, argMissing) ?: fail(numberFormat)

Example

// /giveDiamond PLAYER_NAME AMOUNT
myPlugin.simpleCommand("giveDiamond") {
  val target: Player = player(0, notOnline = "ERROR: This player is not online now :S".color(ChatColor.RED))
  val amount: Int = int(1, numberFormat = "ERROR: The amount argument can be just numbers.".color(ChatColor.RED))

  target.inventory.addItem(item(Material.DIAMOND, amount = amount))
}

Documentation for item(Material.DIAMOND, amount = amount) can be found here.

List of arguments

All arguments can be found on command/arguments folder.

But here is a list of all extension provided by KotlinBukkitAPI:

IMPORTANT: All arguments parser have a default message.

  • string(index: Int,argMissing: BaseComponent): String
  • text(startIndex: Int, endIndex: Int = args.size, separator: String = " ", argMissing: BaseComponent): String
  • booleanOrNull(index: Int, argMissing: BaseComponent, trueCases: Array<String>, falseCases: Array<String>): Boolean?
  • boolean(index: Int, argMissing: BaseComponent, booleanFormat: BaseComponent, trueCases: Array<String>, falseCases: Array<String>): Boolean
  • intOrNull(index: Int, argMissing: BaseComponent): Int?
  • int(index: Int, argMissing: BaseComponent, numberFormat: BaseComponent): Int
  • doubleOrNull(index: Int, argMissing: BaseComponent): Double?
  • double(index: Int, argMissing: BaseComponent, numberFormat: BaseComponent): Double
  • playerOrNull(index: Int, argMissing: BaseComponent): Player?
  • player(index: Int, argMissing: BaseComponent, notOnline: BaseComponent): Player
  • offlinePlayer(index: Int, argMissing: BaseComponent): OfflinePlayer
  • gameModeOrNull(index: Int, argMissing: BaseComponent): GameMode?
  • gameMode(index: Int, argMissing: BaseComponent, notFound: BaseComponent): GameMode
  • materialOrNull(index: Int, argMissing: BaseComponent): Material?
  • material(index: Int, argMissing: BaseComponent, notFound: BaseComponent): Material
  • materialDataOrNull(index: Int, argMissing: BaseComponent, dataFormat: BaseComponent): MaterialData?
  • materialData(index: Int, argMissing: BaseComponent, notFound: BaseComponent, dataFormat: BaseComponent): MaterialData
  • worldOrNull(index: Int, argMissing: BaseComponent): World?
  • world(index: Int, argMissing: BaseComponent, notFound: BaseComponent): World
  • coordinate(xIndex: Int, yIndex: Int, zIndex: Int, world: World, argMissing: BaseComponent, numberFormat: BaseComponent): Location
  • <T : Enum<T>> enumOrNull(index: Int, argMissing: BaseComponent, additionalNames: Map<String, T>): T?
  • <T : Enum<T>> enum(index: Int, argMissing: BaseComponent, notFound: BaseComponent, additionalNames: Map<String, T>): T

Optional Arguments

All arguments are required to player add in the command, if the Player/Sender does not add the argument, the command will fail sending the argMissing message to the Player/Sender.

Because of that, we have the optional extension for handle when we want an optional argument.

inline fun <T> Executor<*>.optional(block: () -> T): T?

Example

This command will send the message Welcome to my server!! to the Sender or to a Player if he is provided.

// welcome [optional:PLAYER_NAME]
myPlugin.simpleCommand("welcome") {
  val target: Player? = optional {
    player(index = 0, notOnline = "This player is not online".color(ChatColor.RED))
  }

  val message = "Welcome to my server!!"

  if(target != null) {
    target.msg(message)
  } else {
    sender.msg(message)
  }
}

Arguments Array

And if you want a list of Players or any other type of argument in the command, you can use the array extension for that. The extension returns an Array of the type of the argument that you use in the lambda block.

fun <T> Executor<*>.array(
        startIndex: Int,
        endIndex: Int,
        usageIndexPerArgument: Int = 1,
        block: (index: Int) -> T
): Array<T>

Example

// /moneyGive MONEY_AMOUNT PLAYER_1 PLAYER_2 PLAYER_3 ... PLAYER_N
myPlugin.simpleCommand("moneyGive") {
    val moneyAmount: Double = double(0)
    val players: Array<OfflinePlayer> = array(1, args.size) {
        offlinePlayer(0)
    }

    // filter only players that has account (for saffety)
    val playersWithAccount = players.filter { vaultEconomy.hasAccount(it) }

    // add the money to the players that has account using Vault API
    for(player in playersWithAccount) {
        vaultEconomy.depositPlayer(player, moneyAmount)
    }

    // Generating a String with the Players that receive the money using Kotlin joinToString extension
    val playersName = playersWithAccount.map { it.name }.joinToString()
    sender.msg("You deposit $moneyAmount in the players account: $playersName")
}

Build your own

Creating your own argument parser extension is pretty easy too, you can look at the implantation of KotlinBukkitAPI for understanding how its works (if this example not be enough).

First will start with the signature from your extension function. We will build an argument parser for a Warp plugin that provide a Warp.

data class Warp(val name: String, val location: Location)

Just for continuing the design pattern of KotlinBukkitAPI command argument, we need the default message for argMissing.

ERROR: Please inform the warp argument

val MISSING_WARP_ARGUMENT = "ERROR: Please inform the warp argument".color(ChatColor.RED)

// return null if warp was not found
fun Executor<*>.warpOrNull(
    index: Int,
    argMissing: TextComponent = MISSING_WARP_ARGUMENT
): Warp?

This is the first step, we need an Index to get in the Args Array and a argMissing if the player does not inform the warp argument.

val MISSING_WARP_ARGUMENT = "ERROR: Please inform the warp argument".color(ChatColor.RED)

// return null if warp was not found
fun Executor<*>.warpOrNull(
    index: Int,
    argMissing: TextComponent = MISSING_WARP_ARGUMENT
): Warp? {
  val warpName = string(index, argMissing)
  return WarpManager.findWarp(warpName)
}

You can use others Arguments Parsers like string that I use in your own arguments.

Why I use string(): Be because they already have the argument missing validation.

To complete, we need the Non-null Warp argument.

val MISSING_WARP_ARGUMENT = "ERROR: Please inform the warp argument".color(ChatColor.RED)

// return null if warp was not found
fun Executor<*>.warpOrNull(
    index: Int,
    argMissing: TextComponent = MISSING_WARP_ARGUMENT
): Warp? {
  val warpName = string(index, argMissing)
  return WarpManager.findWarp(warpName)
}

val WARP_NOT_FOUND = "ERROR: Warp informed was not found".color(ChatColor.RED)

fun Executor<*>.warp(
    index: Int,
    argMissing: TextComponent = MISSING_WARP_ARGUMENT,
    notFound: TextComponent = WARP_NOT_FOUND
): Warp = warpOrNull(index, argMissing) ?: fail(notFound)

We are done!

TabComplete