Skip to main content

Overview

Parameter annotations control how command arguments are parsed, validated, and injected into your command methods. They are applied to method parameters to customize their behavior.

Sender Annotations

@Sender

Marks a parameter as the command sender. This parameter receives the user executing the command and does not consume arguments from the input. Source: me/vaperion/blade/annotation/parameter/Sender.java:22-23
@Command("heal")
public void healCommand(@Sender Player player) {
    player.setHealth(20.0);
}
Type Support: Blade supports custom sender types through SenderProvider:
Blade.forPlatform(platform)
    .bind(binder -> {
        binder.bindSender(Player.class, (context, sender) -> {
            if (sender.getHandle() instanceof Player) {
                return (Player) sender.getHandle();
            }
            throw BladeParseError.fatal("This command is player-only!");
        });
    })
    .build();
The @Sender parameter must be the first parameter in the method. Only one sender parameter is allowed per command.

Naming and Display

@Name

Sets a custom name for a parameter, used in usage messages and error displays. Source: me/vaperion/blade/annotation/parameter/Name.java:26-34 Without @Name:
@Command("give")
public void giveCommand(@Sender Player player, String arg0, int arg1) {
    // Usage: /give <arg0> <arg1>
}
With @Name:
@Command("give")
public void giveCommand(@Sender Player player, 
                        @Name("item") String item,
                        @Name("amount") int amount) {
    // Usage: /give <item> <amount>
}
If you compile with the -parameters flag, Java preserves parameter names and @Name becomes optional. Most modern IDEs and build tools enable this by default.
Compiler Configuration:
<!-- Maven -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <compilerArgs>
            <arg>-parameters</arg>
        </compilerArgs>
    </configuration>
</plugin>
// Gradle
tasks.withType(JavaCompile) {
    options.compilerArgs << '-parameters'
}

Optional Parameters

@Opt

Marks a parameter as optional with configurable default behavior. Source: me/vaperion/blade/annotation/parameter/Opt.java:19-77
Uses null for objects or default primitive values.
@Command("teleport")
public void tpCommand(@Sender Player player, 
                      @Opt Player target) {
    if (target == null) {
        player.sendMessage("Usage: /tp <player>");
        return;
    }
    player.teleport(target.getLocation());
}
Type Reference:
public enum Type {
    EMPTY_OR_CUSTOM,  // Automatic based on custom value
    EMPTY,            // null or primitive default (0, false, etc.)
    SENDER,           // Use command sender
    CUSTOM            // Parse from custom() string
}

Parsing Modifiers

@Greedy

Captures all remaining arguments as a single string. Source: me/vaperion/blade/annotation/parameter/Greedy.java:15-16
@Command("broadcast")
public void broadcastCommand(@Sender CommandSender sender, 
                             @Greedy String message) {
    // /broadcast Hello everyone! How are you?
    // message = "Hello everyone! How are you?"
    server.broadcastMessage(message);
}
@Greedy parameters must be the last parameter in the command (except for flags). They consume all remaining input.
Common Pattern with @Quoted:
@Command("announce")
@Quoted
public void announceCommand(@Sender Player player,
                            String title,
                            @Greedy String message) {
    // /announce "Event" This is a longer message
    // title = "Event"
    // message = "This is a longer message"
}

@Range

Validates numeric parameters against minimum and maximum bounds. Source: me/vaperion/blade/annotation/parameter/Range.java:15-33
@Command("setlevel")
public void setLevelCommand(@Sender Player sender,
                           Player target,
                           @Range(min = 1, max = 100) int level) {
    target.setLevel(level);
}
Properties:
  • min() - Minimum value (inclusive), defaults to Double.NaN (no minimum)
  • max() - Maximum value (inclusive), defaults to Double.NaN (no maximum)
Examples:
// Only minimum
@Range(min = 0) int amount

// Only maximum
@Range(max = 100) int percentage

// Both bounds
@Range(min = 1.0, max = 10.0) double multiplier

// No bounds (pointless but valid)
@Range int value

Custom Data

@Data

Passes custom string data to argument providers for per-parameter customization. Source: me/vaperion/blade/annotation/parameter/Data.java:21-29
@Command("spawmob")
public void spawnMobCommand(@Sender Player player,
                            @Data({"HOSTILE", "PASSIVE"}) EntityType type) {
    // Data array is passed to EntityType's ArgumentProvider
    // Provider can use this to filter suggestions
}
In ArgumentProvider:
public class EntityTypeProvider implements ArgumentProvider<EntityType> {
    @Override
    public EntityType provide(Context ctx, InputArgument arg) {
        // Access via arg.parameter().data()
        List<String> data = arg.parameter().data();
        return EntityType.valueOf(arg.requireValue().toUpperCase());
    }
    
    @Override
    public void suggest(Context ctx, InputArgument arg, SuggestionsBuilder suggestions) {
        List<String> data = arg.parameter().data();
        if (data.contains("HOSTILE")) {
            suggestions.suggest("ZOMBIE");
            suggestions.suggest("SKELETON");
        }
        if (data.contains("PASSIVE")) {
            suggestions.suggest("COW");
            suggestions.suggest("SHEEP");
        }
    }
}
For type-safe metadata, consider creating custom annotations marked with @Forwarded instead of using @Data.

Flags

@Flag

Defines optional flag parameters with short and long names. Source: me/vaperion/blade/annotation/parameter/Flag.java:15-45
@Command("teleport")
public void teleportCommand(@Sender Player player,
                           Player target,
                           @Flag(value = 's', longName = "silent") boolean silent) {
    player.teleport(target.getLocation());
    if (!silent) {
        player.sendMessage("Teleported!");
    }
}
Usage Examples:
/teleport Steve -s              # Short flag
/teleport Steve --silent        # Long flag
/teleport Steve                 # No flag (silent = false)
Flag Properties:
@Flag(
    value = 'f',                    // Short name: -f
    longName = "force",             // Long name: --force
    description = "Force operation", // Help text
    required = false                 // Whether flag is mandatory
)
boolean force
Value Flags:
@Command("search")
public void searchCommand(@Sender Player player,
                         @Greedy String query,
                         @Flag(value = 'r', longName = "radius") 
                         @Opt(value = Type.CUSTOM, custom = "10") 
                         int radius) {
    // /search -r 50 diamond ore
    // /search --radius 100 diamond ore
    // /search diamond ore (radius = 10)
}

Combining Annotations

Parameter annotations can be combined for complex behaviors:
@Command("give")
public void giveCommand(
    @Sender Player sender,
    @Name("target") @Opt(Type.SENDER) Player target,
    @Name("item") String item,
    @Name("amount") @Range(min = 1, max = 64) @Opt(value = Type.CUSTOM, custom = "1") int amount,
    @Flag(value = 's', longName = "silent", description = "No message") boolean silent
) {
    // /give -s Steve diamond 32
    // /give --silent diamond_sword (gives 1 to sender)
    // /give Bob emerald 10
}

Reference

Parameter Processing:
me/vaperion/blade/command/BladeCommand.java:132-198
Name Resolution:
me/vaperion/blade/command/BladeCommand.java:160-164

Build docs developers (and LLMs) love