Skip to content

Command DSL

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

In this section we will learn how to make commands much IZI using KotlinBukkitAPI. You can see all the code here

Simple Command DSL

fun Plugin.simpleCommand(
        name: String,
        vararg aliases: String = arrayOf(),
        description: String = "",
        block: ExecutorBlock
)

Simple, but, what is ExecutorBlock? is simples too, is a lambda with a Receiver.

typealias ExecutorBlock = suspend Executor<CommandSender>.() -> Unit

class Executor<E : CommandSender>(
        val sender: E,
        val label: String,
        val args: Array<out String>,
        val command: CommandDSL
)

Example

myPlugin.simpleCommand("hello") {
  sender.msg("world")
}

Note: ExecutorBlock is a suspend block, this that you can use Coroutines inside of it, by default, it use the Bukkit Main Thread, this means, do not do block operation or heavy tasks without change the your context, like using: withContext(Dispatchers.IO) {}.

IMPORTANT: The commands are auto registered by KotlinBukkitAPI.


myPlugin.simpleCommand("warp") {
  val player = sender as? Player ?: fail("Please, use this command just in game")
  val arg0 = args.getOrNull(0) ?: fail("Please add the warp name")
  val warp = warpManager.findWarp(arg0) ?: fail("This warp was not found")

  warp.teleport(player)
}

myPlugin.simpleCommand("tp") {
  val player = sender as? Player ?: fail("Please, use this command just in game")

  val target = player(
      0,
      "Is missing the Player argument".color(ChatColor.RED),
      "This player is not online".color(ChatColor.RED)
  )

  player.teleport(target)
}

Command DSL

Simple Commmand DSL vs Command DSL: Command DSL has sub commands, support for permission, permission message, tab complete and much more.

typealias CommandBuilderBlock = CommandDSL.() -> Unit

fun command(
        name: String,
        vararg aliases: String = arrayOf(),
        plugin: Plugin,
        block: CommandBuilderBlock
): CommandDSL

First I will show how to use it, before we jump into the structure from CommandDSL class.

fun executor(block: ExecutorBlock) is the same lambda from simpleCommand, with this in mind, you can use fail and arguments.

Example

myPlugin.command("playersonline") {
  aliases = listOf("online")

  permission = "myplugin.cmd.playersonline"
  permissionMessage = "You don't have permission to use this command"

  executor {
    val onlinePlayerNames = onlinePlayers().map { it.name }.joinToString()

    sender.msg("&aPlayers online: &e$onlinePlayerNames".translateColor())
  }
}

Commands just for Player

typealias ExecutorPlayerBlock = Executor<Player>.() -> Unit

fun executorPlayer(block: ExecutorPlayerBlock)

Example

myPlugin.command("spawn") {
  permission = "myplugin.cmd.spawn"
  permissionMessage = "You don't have permission to use this command"
  onlyInGameMessage = "This command can be run just in game"

  executorPlayer {
    sender.teleport(spawnLocation)
    sender.msg("Teleported to the server spawn")
  }
}

onlyInGameMessage: When a command just have executorPlayer this message will be sent to the console when try to use the command.

If the command has executorPlayer and executor, the executorPlayer will be usage to Player and executor when is not a Player (console)

Important: executorPlayer like the normal executor, it is suspend, but, the main difference is that the Coroutine of the executor player in canceled on the player disconnection, preventing Coroutines Job Leaks. If you don't use with attention, you could find some bugs when using it. Because by default it runs in the Main Thread, if you are not using any Coroutines calls, like delay() or others, your task will ALWAYS complete, don't be afraid.


Sub commands

myPlugin.command("myplugin") {
  permission = "myplugin.cmd"
  permissionMessage = "You don't have permission to use this command"
  onlyInGameMessage = "This command can be run just in game"

  executor {
    sender.msg("use: /myplugin help")
  }
  
  command("help") {
    executor {
      sender.msg("""
        /myplugin help
        /myplugin version
        /myplugin reload config
        /myplugin reload messages
      """)
    }
  }
  command("version") {
    executor {
      sender.msg("Version 1.0.0")
    }
  }
  command("reload") {
    command("config") {
      executor {
        MyConfig.reloadConfig()
        sender.msg("Config reloaded")
      }
    }
    command("messages") {
      executor {
        MyConfig.reloadMessages()
        sender.msg("Messages reloaded")
      }
    }
  }
}
  • The KotlinBukkitAPI auto generate Tab complete for you based on sub commands
  • All sub command has the same Permission message and Only in game message from the root command.

More about commands: