BedrioxDOCUMENTATION
PLUGIN DEVELOPMENT

Commands and typed parameters

Extend AbstractCommand, declare the accepted shape with CommandArguments, and register the command through PluginContext::commands(). Bedriox parses, validates, resolves selectors, and converts values before execute() runs.

Register a command

PHP
public function onEnable(): void
{
    $this->context()->commands()->register(new ArenaCommand());
}

Text, numbers, and booleans

PHP
public function defineArguments(): CommandArguments
{
    return CommandArguments::create()
        ->addArgument(CommandParameter::string('arena'))
        ->addArgument(CommandParameter::integer('rounds')->minimum(1)->maximum(20))
        ->addArgument(CommandParameter::float('damage')->minimum(0.0)->maximum(40.0))
        ->addArgument(CommandParameter::boolean('friendlyFire'));
}

public function execute(CommandContext $context): CommandResult
{
    $values = $context->values();
    $arena = $values->string('arena');
    $rounds = $values->integer('rounds');
    $damage = $values->float('damage');
    $friendlyFire = $values->boolean('friendlyFire');

    return $this->success("Configured {$arena} for {$rounds} rounds.");
}

Use minimum() and maximum() on integer or float parameters. Invalid values never reach the command handler.

Choices, enums, and changing choices

Use choice() for a small fixed string list:

PHP
CommandParameter::choice('mode', ['solo', 'teams'])

Use a backed PHP enum when the plugin owns the fixed values. Calling enum() returns the enum case from CommandValues::enum():

PHP
enum ArenaMode: string
{
    case SOLO = 'solo';
    case TEAMS = 'teams';
}

CommandParameter::enum('mode', ArenaMode::class);
$mode = $context->values()->enum('mode', ArenaMode::class);

Use softEnum() when suggestions may change while the server runs, such as loaded arena names or kits. Keep the CommandSoftEnum instance and update its values instead of unregistering the command.

PHP
$arenas = $this->context()->commands()->registerSoftEnum('arenas', ['duel', 'teams']);
$parameter = CommandParameter::softEnum('arena', $arenas);

$arenas->add('capture');
$arenas->remove('duel');

Players and entity selectors

PHP
CommandParameter::onlinePlayer('player'); // one connected player
CommandParameter::players('targets');     // player name or bounded selectors
CommandParameter::entity('target');       // one player or entity
CommandParameter::entities('targets');    // bounded player/entity selection

Read them with the matching typed accessor:

PHP
$player = $context->values()->player('player');
$players = $context->values()->players('targets');
$entity = $context->values()->entity('target');
$entities = $context->values()->entities('targets');

Selectors are resolved by Bedriox. Do not parse @a, @s, or other selector syntax yourself.

Positions and block positions

position() accepts world coordinates, including relative coordinates when the sender has a position. blockPosition() returns integer block coordinates.

PHP
CommandParameter::position('destination');
CommandParameter::blockPosition('block');

$destination = $context->values()->position('destination');
$block = $context->values()->blockPosition('block');

Messages, raw text, and JSON

These parameters consume structured or remaining input and therefore belong at the end of an overload:

PHP
CommandParameter::message('message');
CommandParameter::rawText('text');
CommandParameter::json('payload');

Read them with message(), rawText(), or json(). Validate the shape of a decoded JSON value before using it.

Optional values and defaults

PHP
CommandParameter::integer('rounds')->optional(3);
CommandParameter::onlinePlayer('player')->optional();

An explicit default is returned by the typed accessor. For an optional value without a default, check CommandValues::has() before reading it.

Literal routes and overloads

PHP
public function defineArguments(): CommandArguments
{
    return CommandArguments::create()
        ->addOverload(CommandOverload::create()
            ->addArgument(CommandParameter::literal('join'))
            ->addArgument(CommandParameter::string('arena')))
        ->addOverload(CommandOverload::create()
            ->addArgument(CommandParameter::literal('teleport'))
            ->addArgument(CommandParameter::position('destination')));
}

Literals cannot be optional. Use another overload when a route is optional.

Sender and result policy

Use AllowedCommandSenders::PLAYER_ONLY when the command fundamentally needs a player. Otherwise inspect CommandContext::sender() and deliberately support both player and console senders. Return $this->success() for accepted work and $this->failure() for a readable command error.