Command
The command module provides a Kotlin DSL over Mojang Brigadier for building type-safe command trees. The Paper integration adds typed argument builders, context accessors, and registration utilities.
Modules
| Module | Description |
|---|---|
kraftlin-command-core |
Platform-agnostic Brigadier DSL (no Minecraft dependencies) |
kraftlin-command-paper |
Paper integration: typed arguments and registration |
kraftlin-command-velocity |
Velocity integration: registration and choice arguments |
Getting Started
val command = kraftlinCommand("demo") {
requiresPermission("demo.use")
player("target") {
executes { sender, context ->
val target = context.player("target")
sender.sendMessage("Sent hello to ${target.name}")
target.sendMessage("Hello!")
}
}
}
Register in your plugin:
override fun onEnable() {
registerKraftlinCommands(command)
}
Core Concepts
Command Structure
Commands are built using nested DSL blocks:
kraftlinCommand("mycommand") {
// Literal sub-commands
literal("info") {
executes { sender, ctx -> /* ... */ }
}
// Typed arguments
integer("amount") {
executes { sender, ctx ->
val amount = ctx.integer("amount")
sender.sendMessage("Amount: $amount")
}
}
}
Dual-Function Pattern
Every argument type has two functions: 1. Builder function: Adds the argument to the command tree 2. Accessor function: Retrieves the typed value from context
// Builder - adds argument node
player("target") {
executes { sender, ctx ->
// Accessor - retrieves typed Player
val target = ctx.player("target")
}
}
Execution
// Standard execution (automatic SINGLE_SUCCESS)
executes { sender, context -> /* ... */ }
// Custom result code
executesResult { sender, context ->
if (condition) Command.SINGLE_SUCCESS else 0
}
// Player-only execution
executesPlayer { player, context -> /* ... */ }
Requirements
Requirements can be chained and are AND-ed together:
kraftlinCommand("admin") {
requiresPermission("admin.use")
requiresPlayer()
requires { /* custom check */ }
// All must pass
}
Argument Types
Core Types
Available in kraftlin-command-core:
string(name),word(name),greedyString(name)- String argumentsinteger(name, min?, max?),long(name, min?, max?)- Integers with optional boundsfloat(name, min?, max?),double(name, min?, max?)- Floats with optional boundsboolean(name)- Boolean values
Paper Types
Available in kraftlin-command-paper:
Players & Entities:
- player(name) → Player - Single player selector
- players(name) → List<Player> - Multiple players
- entity(name) → Entity - Single entity
- entities(name) → List<Entity> - Multiple entities
Positions:
- blockPosition(name) → BlockPosition
- finePosition(name, centerIntegers?) → FinePosition
- columnBlockPosition(name), columnFinePosition(name) - 2D positions
Gameplay:
- world(name) → World
- blockState(name) → BlockState
- itemStack(name) → ItemStack
- gameMode(name) → GameMode
- time(name, minTime?) → Int - Game time
Messages & Components:
- component(name) → Component - Adventure component
- signedMessage(name) → CompletableFuture<SignedMessage> - Preserves signatures
- style(name) → Style
- namedColor(name) → NamedTextColor
- hexColor(name) → TextColor
Resources & Keys:
- key(name) → Key
- namespacedKey(name) → NamespacedKey
- resource(name, registryKey) → T
- resourceKey(name, registryKey) → TypedKey<T>
Other:
- choice(name, values) → String - Custom string choice with validation
- enum<E>(name, values?) → E - Enum-backed choice
- integerRange(name), doubleRange(name) - Numeric ranges
- rotation(name), angle(name) - Rotation/angles
- playerProfiles(name), uuid(name) - Player profiles and UUIDs
See KDoc for the complete list.
Advanced Features
Suggestions
word("option") {
suggestsStatic("foo", "bar", "baz")
executes { sender, ctx -> /* ... */ }
}
// Custom suggestions
word("dynamic") {
suggests { context, builder ->
listOf("option1", "option2").forEach { builder.suggest(it) }
builder.buildFuture()
}
}
Aliases
literal("info", "i", "information") {
executes { sender, ctx -> /* ... */ }
}
// Override existing commands (use carefully)
kraftlinCommand("help", overrideAliases = true) {
// ...
}
Custom Argument Types
Use choice() for custom validated strings:
choice("difficulty", listOf("easy", "normal", "hard")) {
executes { sender, ctx ->
val difficulty = ctx.choice("difficulty")
}
}
Use enum() for enum-backed arguments:
enum<GameMode>("mode") {
executes { sender, ctx ->
val mode = ctx.enum<GameMode>("mode")
}
}
Velocity
The Velocity module provides the same DSL structure with Velocity's CommandSource:
val command = kraftlinCommand("demo", description = "Demo command") {
requiresPermission("demo.use")
string("name") {
executes { sender, context ->
sender.sendMessage(Component.text("Hello, ${context.string("name")}!"))
}
}
}
Register in your plugin's proxyInitialize:
@Subscribe
fun onInit(event: ProxyInitializeEvent) {
server.commandManager.registerKraftlinCommands(command)
}
Velocity commands have access to core argument types (string, integer, boolean, etc.) plus
choice() and enum(). Paper-specific arguments (entity selectors, positions, etc.) are not available.
Why Kraftlin Commands?
Kraftlin removes boilerplate and type-unsafe patterns from Brigadier:
Without Kraftlin:
Commands.argument("target", ArgumentTypes.player())
.executes { context ->
val source = context.source
val resolver = context.getArgument("target", PlayerSelectorArgumentResolver::class.java)
val target = resolver.resolve(source).first()
// ...
}
With Kraftlin:
player("target") {
executes { sender, context ->
val target = context.player("target")
// ...
}
}
Benefits:
- No manual resolver extraction or resolution
- Typed context accessors instead of raw getArgument()
- Cleaner syntax with Kotlin DSL
- Type safety at compile time
- No resolver types leaking into command logic