BedrioxDOCUMENTATION
PLUGIN DEVELOPMENT

Configuration and packaged resources

Put default configuration and other server-side files in your project’s resources/ directory. Bedriox exposes them through the plugin-bound data capability and keeps editable copies under plugin_data/<PluginName>/.

These resources are files for the server and plugin. They are not Minecraft client resource packs.

Start with a packaged default

For a project named TownTools, a basic layout looks like this:

TEXT
TownTools/
├── plugin.json
├── resources/
│   ├── config.yml
│   └── messages.yml
└── src/
    └── Main.php

The simplest way to open the conventional config.yml is:

PHP
$config = $this->context()->data()->config();

If plugin_data/TownTools/config.yml does not exist and the plugin packages resources/config.yml, config() copies that default first. If neither file exists, Bedriox creates an empty configuration map.

Use saveResource() when you want to install a particular packaged file explicitly:

PHP
$data = $this->context()->data();
$installed = $data->saveResource('messages.yml');

$this->logger()->debug(
    $installed ? 'Installed the default messages file.' : 'Kept the existing messages file.',
);

The first call returns true when it copies the resource. Later calls return false because the administrator’s existing file is preserved. Do not pass replace: true on every startup; that would deliberately replace their edits.

Read typed settings

Configuration keys use dots to walk through nested maps. Given:

YAML
join:
  enabled: true
  message: "{player} joined the server"
rewards:
  amount: 3
  multiplier: 1.5
  items:
    - minecraft:bread
    - minecraft:torch

read each setting with the type the file is expected to contain:

PHP
$config = $this->context()->data()->config();

$enabled = $config->getBool('join.enabled', true);
$message = $config->getString('join.message', '{player} joined the server');
$amount = $config->getInt('rewards.amount', 1);
$multiplier = $config->getFloat('rewards.multiplier', 1.0);
$items = $config->getList('rewards.items', []);

Defaults apply when a key is missing. Typed getters do not silently coerce a wrong value: the string "true" is not a boolean, and asking for it with getBool() throws PluginDataException. This makes an invalid administrator edit visible instead of quietly changing plugin behavior.

The complete reading surface is:

  • has($key) checks whether a key exists, even when its value is null.
  • get($key, $default) returns a value without asserting its type.
  • getString(), getInt(), getFloat(), and getBool() enforce scalar types.
  • getList() requires an indexed list.
  • getMap() requires a string-keyed map.
  • all() returns the complete in-memory configuration map.

Prefer a typed getter whenever the expected shape is known. Treat configuration as untrusted input and still validate application-specific rules such as ranges, identifier formats, list length, and allowed choices.

Save changes

set() and remove() change the in-memory map. Call save() to write the complete updated configuration atomically:

PHP
$config = $this->context()->data()->config();
$config->set('join.enabled', false);
$config->set('rewards.items', ['minecraft:apple', 'minecraft:bread']);
$config->remove('legacy-setting');
$config->save();

Use dot-separated keys with set() too. A key cannot cross through a scalar; for example, setting join.message.text fails when join.message is already a string.

Reload administrator edits

A Configuration object keeps an in-memory snapshot. If an administrator edits the file while the server is running, reload it before reading the new values:

PHP
$config = $this->context()->data()->config();
$config->reload();

$enabled = $config->getBool('join.enabled', true);

Reload before a read-modify-save operation when an external edit may have happened, otherwise save() writes the plugin’s current in-memory map.

Use more than one configuration file

Bedriox accepts YAML, YML, and JSON configuration files:

PHP
$data = $this->context()->data();

$main = $data->config();
$messages = $data->config('messages.yml');
$storage = $data->config('storage.json');

Each file must decode to a string-keyed root map. Configuration sizes and structures are bounded, invalid UTF-8 and unsupported PHP values are rejected, and malformed YAML or JSON throws PluginDataException.

Read or copy other resources

Resources may be nested below resources/:

PHP
$data = $this->context()->data();

if ($data->hasResource('language/en_US.yml')) {
    $contents = $data->readResource('language/en_US.yml');
    $this->logger()->debug('Loaded the packaged English message catalog.');
}

$copiedFiles = $data->saveResources();
$this->logger()->debug("Installed {$copiedFiles} missing resource file(s).");

readResource() reads the packaged, read-only copy as a string; it does not read the administrator’s data-directory copy. saveResources() attempts every packaged resource and returns the number newly copied. By default it preserves every existing file.

path() returns this plugin’s data-directory root for a custom bounded format that config() does not support. Build paths only from names controlled by the plugin, never directly from player input, and keep all data inside that root.

Handle invalid configuration clearly

Configuration and resource failures use PluginDataException. Required configuration can fail plugin enablement rather than leaving partially registered behavior running:

PHP
use Bedriox\Api\Plugin\Data\PluginDataException;

try {
    $config = $this->context()->data()->config();
    $maximumHomes = $config->getInt('homes.maximum', 3);

    if ($maximumHomes < 0 || $maximumHomes > 100) {
        throw new PluginDataException('homes.maximum must be between 0 and 100.');
    }
} catch (PluginDataException $failure) {
    $this->logger()->error('TownTools configuration is invalid: ' . $failure->getMessage());
    throw $failure;
}

Never log an entire configuration file: it may contain credentials or other private administrator values. Packaged defaults committed to a plugin repository must not contain secrets.

The source-derived section below shows the exact configuration currently used by ExamplePlugin.

FROM THE SCANNED EXAMPLE

ExamplePlugin’s real configuration

The generator reads these examples from the exact ExamplePlugin revision used for this documentation. They are not hand-copied snippets.

Open resources/config.yml · Open src/Main.php

YAML
join:
  enabled: true
  message: "{player} joined this Bedriox server"

Install the packaged default

PHP
$this->context()->data()->saveResource('config.yml');

Read it in a listener

PHP
#[\Bedriox\Api\Event\EventHandler]
public function onJoin(\Bedriox\Api\Event\Player\PlayerJoinEvent $event): void
{
    $config = $this->context()->data()->config();
    if (!$config->getBool('join.enabled', true)) {
        $event->setJoinMessage(null);
        return;
    }
    $event->setJoinMessage(\Bedriox\Api\TextFormat::YELLOW . str_replace('{player}', $event->player->name, $config->getString('join.message', '{player} joined the server')) . \Bedriox\Api\TextFormat::RESET);
}
Continue into the exact API. See PluginData, Configuration, and PluginDataException for every method and signature.