Overview
Blade provides a rich set of annotations to control command behavior, permissions, visibility, and execution. These annotations are applied to command methods to customize their functionality.
Core Annotations
@Description
@Permission
@Hidden
@Async
Sets the description displayed in help messages.@Command("heal")
@Description("Restore your health to full")
public void healCommand(@Sender Player player) {
player.setHealth(20.0);
}
Source: me/vaperion/blade/annotation/command/Description.java:15-23Properties:
value() - The description string
Target: ElementType.METHOD Restricts command execution based on permissions.@Command("ban")
@Permission("server.admin.ban")
public void banCommand(@Sender Player sender, Player target) {
target.ban();
}
Source: me/vaperion/blade/annotation/command/Permission.java:15-46Properties:
value() - The required permission
message() - Custom permission denial message
Special Values:
"op" - Requires sender to be an operator
"console" - Requires sender to be console
"@predicateName" - Uses a registered permission predicate
Custom Message Example:@Command("admin")
@Permission(value = "server.admin", message = "You must be an admin!")
public void adminCommand(@Sender Player player) {
// Admin only
}
Permission Predicates:Blade.forPlatform(platform)
.permission(p -> {
p.predicate("vip", (context, sender) -> {
return hasVipStatus(sender);
});
})
.build();
@Command("viproom")
@Permission("@vip")
public void vipCommand(@Sender Player player) {
// VIP only
}
Hides the command from help messages and tab completion.@Command("debug")
@Hidden
@Permission("op")
public void debugCommand(@Sender CommandSender sender) {
// Hidden debug command
}
Source: me/vaperion/blade/annotation/command/Hidden.java:15-16Behavior:
- Does not appear in help messages
- Cannot be tab-completed
- Shows “unknown command” message if executed without permission
Hidden commands are useful for debug commands or administrative tools that shouldn’t be advertised to regular users.
Executes the command asynchronously off the main thread.@Command("lookup")
@Async
public void lookupCommand(@Sender Player player, String username) {
// Performs database lookup without blocking main thread
User user = database.findUser(username);
player.sendMessage("Found: " + user.getName());
}
Source: me/vaperion/blade/annotation/command/Async.java:13-14Be careful when modifying game state from async commands. Most platform APIs are not thread-safe and require synchronization back to the main thread.
Thread-Safe Pattern:@Command("heavywork")
@Async
public void heavyWorkCommand(@Sender Player player) {
// Heavy computation off main thread
Result result = performHeavyCalculation();
// Sync back to main thread for game interaction
Bukkit.getScheduler().runTask(plugin, () -> {
player.sendMessage("Result: " + result);
});
}
Usage Annotations
Provides a custom usage message instead of the auto-generated one.@Command("tp")
@Usage("/tp <player> or /tp <x> <y> <z>")
public void teleportCommand(@Sender Player player, @Greedy String args) {
// Custom parsing logic
}
Source: me/vaperion/blade/annotation/command/Usage.java:17-20If not specified, Blade automatically generates a usage message based on the command’s parameters.
Marks a method as a help command that displays available subcommands.@Command("game")
@Help
public void gameHelp(@Sender Player player) {
// Method body is ignored - Blade generates help automatically
}
Source: me/vaperion/blade/annotation/command/Help.java:15-16Behavior:
- Method body is completely ignored
- Blade automatically generates and displays help for subcommands
- Adds a greedy string parameter for help queries
Implementation:me/vaperion/blade/command/BladeCommand.java:95-120
@Quoted
Enables quote parsing for command arguments.
Source: me/vaperion/blade/annotation/command/Quoted.java:20-21
Method-Level:
@Command("announce")
@Quoted
public void announceCommand(@Sender Player player, String title, String message) {
// /announce "Server Event" "Join us for a special event!"
// title = "Server Event"
// message = "Join us for a special event!"
}
Parameter-Level:
@Command("setname")
public void setNameCommand(@Sender Player player, Player target, @Quoted String name) {
// /setname Steve "The Builder"
// Only the 'name' parameter supports quotes
}
Without @Quoted, arguments are split by spaces. With quotes, text within quotes is treated as a single argument.
Annotation Combinations
Annotations can be combined for sophisticated command behavior:
@Command({"sudo", "runas"})
@Description("Execute a command as another player")
@Permission(value = "server.admin.sudo", message = "Only admins can use sudo!")
@Async
@Quoted
public void sudoCommand(@Sender Player admin, Player target, @Greedy String command) {
// Executes 'command' as if 'target' typed it
performAsyncSudoExecution(target, command);
}
Best Practices
- Always provide
@Description for user-facing commands
- Use
@Hidden for debug/admin commands that shouldn’t be advertised
- Apply
@Async for database queries, file I/O, or network requests
- Combine
@Permission with @Hidden for secret admin commands
- Use
@Quoted sparingly - most users don’t know about quote syntax
Configuration in Builder
Some annotation behaviors can be configured when building Blade:
Blade blade = Blade.forPlatform(platform)
.config(cfg -> {
// Default permission denial message
cfg.defaultPermissionMessage("You don't have permission!");
})
.build();
Reference: me/vaperion/blade/command/BladeCommand.java:91