Files
Documentation/content/core-concepts/commands/command-context.en.md
2026-01-20 20:33:59 +01:00

6.9 KiB

title, type, weight
title type weight
Command Context docs 4

The CommandContext provides access to command execution information, including the sender, parsed arguments, and the original input string.

Accessing the Context

The context is passed to your execute() method:

@Override
protected CompletableFuture<Void> execute(CommandContext context) {
    // Use context here
    return null;
}

Command Sender

Get the entity or console that executed the command:

CommandSender sender = context.sender();

// Send messages (must use Message class)
sender.sendMessage(Message.raw("Hello!"));
sender.sendMessage(Message.translation("my.translation.key"));

// Check permissions
if (sender.hasPermission("myplugin.admin")) {
    // ...
}

Checking Sender Type

if (context.sender() instanceof Player) {
    Player player = (Player) context.sender();
    // Player-specific logic
} else {
    // Console or other sender
    context.sender().sendMessage("This command requires a player!");
}

Getting Arguments

Required Arguments

private final RequiredArg<PlayerRef> playerArg;
private final RequiredArg<Integer> countArg;

// In execute():
PlayerRef player = context.get(playerArg);  // Never null for required args
int count = context.get(countArg);          // Never null for required args

Optional Arguments

private final OptionalArg<String> reasonArg;

// Get value (may be null if not provided)
String reason = context.get(reasonArg);

// Check if provided before using
if (context.provided(reasonArg)) {
    String reason = context.get(reasonArg);
}

Default Arguments

private final DefaultArg<Integer> countArg;  // Default: 1

// Always returns a value (never null)
int count = context.get(countArg);  // Returns default if not specified

Flag Arguments

private final FlagArg silentFlag;

// Check if flag was provided
boolean isSilent = context.provided(silentFlag);

Input String

Access the original command input:

String input = context.getInputString();
// For "/give player123 sword 5" -> "give player123 sword 5"

The Command

Access the command being executed:

AbstractCommand command = context.getCalledCommand();
String commandName = command.getName();
String fullName = command.getFullyQualifiedName();  // e.g., "admin kick"

Argument Type Fallback Behavior

Some argument types have special processing with fallback behavior. This is handled by the argument type's processedGet() method:

PLAYER_REF Fallback

When using PLAYER_REF with optional arguments:

  • If argument is not provided and sender is a player, the argument type can return the sender's PlayerRef
// Note: This fallback behavior is in the argument type, not CommandContext
private final OptionalArg<PlayerRef> targetArg;

@Override
protected CompletableFuture<Void> execute(CommandContext context) {
    PlayerRef target = context.get(targetArg);

    // Manual fallback if null
    if (target == null && context.sender() instanceof Player player) {
        target = player.getPlayerRef();
    }
    // ...
}

World Argument Fallback

When using WORLD with optional arguments:

  • If not specified and sender is player, returns player's world
  • If only one world exists, returns that world
private final OptionalArg<World> worldArg;

@Override
protected CompletableFuture<Void> execute(CommandContext context) {
    World world = context.get(worldArg);

    // Manual fallback if null
    if (world == null && context.sender() instanceof Player player) {
        world = player.getWorld();
    }
    // ...
}

Error Handling

Commands can throw exceptions for error cases:

@Override
protected CompletableFuture<Void> execute(CommandContext context) {
    PlayerRef playerRef = context.get(playerArg);

    // Check if player is online via ECS reference
    Ref<EntityStore> ref = playerRef.getReference();
    if (ref == null || !ref.isValid()) {
        throw new GeneralCommandException(
            Message.translation("error.player.offline")
                .param("player", playerRef.getUsername())
        );
    }

    // Continue execution with valid reference
    return null;
}

Asynchronous Commands

Return a CompletableFuture for async operations:

@Override
protected CompletableFuture<Void> execute(CommandContext context) {
    if (!(context.sender() instanceof Player player)) {
        return null;
    }

    PlayerRef playerRef = player.getPlayerRef();  // Note: deprecated
    World world = player.getWorld();

    return CompletableFuture.runAsync(() -> {
        // Async operation (e.g., database query)
        // PlayerData data = database.loadData(playerRef.getUuid());

        // Return to world thread for game logic
        world.execute(() -> {
            Ref<EntityStore> ref = playerRef.getReference();
            if (ref != null && ref.isValid()) {
                // applyData(ref, data);
                playerRef.sendMessage(Message.raw("Data loaded!"));
            }
        });
    });
}

Complete Example

public class GiveCommand extends AbstractCommand {

    private final RequiredArg<Item> itemArg;
    private final OptionalArg<PlayerRef> targetArg;
    private final DefaultArg<Integer> countArg;
    private final FlagArg silentFlag;

    public GiveCommand() {
        super("give", "Give items to a player");

        itemArg = withRequiredArg("item", "Item to give", ArgTypes.ITEM_ASSET);
        targetArg = withOptionalArg("target", "Target player", ArgTypes.PLAYER_REF);
        countArg = withDefaultArg("count", "Amount", ArgTypes.INTEGER, 1, "1");
        silentFlag = withFlagArg("silent", "Don't broadcast");
    }

    @Override
    protected CompletableFuture<Void> execute(CommandContext context) {
        // Get arguments
        Item item = context.get(itemArg);
        int count = context.get(countArg);  // Uses default if not specified
        boolean silent = context.provided(silentFlag);

        // Get target with fallback to sender
        PlayerRef targetRef = context.get(targetArg);
        if (targetRef == null && context.sender() instanceof Player senderPlayer) {
            targetRef = senderPlayer.getPlayerRef();  // Note: deprecated
        }

        if (targetRef == null) {
            throw new GeneralCommandException(
                Message.raw("Must specify a target player!")
            );
        }

        // Validate target is online via ECS reference
        Ref<EntityStore> ref = targetRef.getReference();
        if (ref == null || !ref.isValid()) {
            throw new GeneralCommandException(
                Message.raw("Player is not online!")
            );
        }

        // Execute - give item to player via ECS
        // ...

        // Feedback
        if (!silent) {
            context.sendMessage(Message.raw(
                "Gave " + count + "x " + item.getId() + " to " + targetRef.getUsername()
            ));
        }

        return null;
    }
}