Advanced

Declarative Configs

Learn how to use Declarative Configs as an alternative to annotation-based configs.

Overview

Balm offers two ways to define configurations:

  1. Annotation-based Configuration - Using annotated Java classes
  2. Declarative Configuration - Using a builder pattern

This page is focused on Declarative Configs. Check out Using Mod Configs for information on how to register configs using the annotation-based approach.

Personally, I recommend using annotation-based configs because they are more readable. Annotation-based configs use the declarative system in the background, so both systems are managed the same in the background. Declarative Configs may be a good alternative for you if you are porting from Neo/Forge and don't want to fully rewrite your configs for Balm.

Getting Started

To use Balm's declarative configuration system, you need to:

  1. Create your configuration schema
  2. Register it with Balm in your mod's initializer or registerConfig() method

Creating a configuration schema

The declarative approach uses a builder pattern to define configuration properties.

public class MyDeclarativeConfig {
    // Create a schema with your mod's namespace and config type
    public static final ConfigSchemaBuilder schema = BalmConfigSchema.create(
        ResourceLocation.fromNamespaceAndPath("yourmodid", "common")
    );

    // Define a boolean property
    public static final ConfiguredBoolean enableFeature = schema
        .property("enableFeature")
        .comment("Enables the special feature")
        .boolOf(true); // default value

    // Define an integer property
    public static final ConfiguredInt maxItems = schema
        .property("maxItems")
        .comment("Maximum number of items")
        .intOf(100); // default value

    // Define a string property
    public static final ConfiguredString welcomeMessage = schema
        .property("welcomeMessage")
        .comment("Message shown to players")
        .stringOf("Welcome to my mod!");

    // Create a category for related settings
    public static final MyCategory advancedSettings = schema
        .category("advanced")
        .comment("Advanced configuration options")
        .via(MyCategory::new);

    // Define a nested category
    public static class MyCategory extends BalmConfigCategoryInitializer {
        public final ConfiguredFloat speedMultiplier = category
            .property("speedMultiplier")
            .comment("Multiplier for movement speed")
            .synced() // This will sync to clients
            .floatOf(1.0f);

        public MyCategory(ConfigCategoryBuilder category) {
            super(category);
        }
    }
}

Registering a configuration schema

Register your configuration in your mod's initialization code:

// in your initializer:
Balm.config().registerConfig(MyDeclarativeConfig.schema);

// or as part of a BalmModule:
@Override
public void registerConfig(BalmConfig config) {
    config.registerConfig(MyDeclarativeConfig.schema);
}

Accessing properties

When accessing properties, Balm will automatically use the current active config. This config may differ from the local config, as it includes values that were synced from the server.

// Access a boolean value
boolean featureEnabled = MyDeclarativeConfig.enableFeature.get();

// Access an integer value
int max = MyDeclarativeConfig.maxItems.get();

// Access a category property
float speed = MyDeclarativeConfig.advancedSettings.speedMultiplier.get();

Updating properties

To update a property, you can use the set() method - but you must remember to call saveLocalConfig() afterwards to apply the changes.

// Update a boolean value
MyDeclarativeConfig.enableFeature.set(true);

// Update an integer value
MyDeclarativeConfig.maxItems.set(200);

// Update a category property
MyDeclarativeConfig.advancedSettings.speedMultiplier.set(1.5f);

// Save the updated config
Balm.config().saveLocalConfig(MyDeclarativeConfig.schema);

Network Synchronization of Properties

Properties marked as .synced() will be synced from server to clients when they join.

These changes are temporary and only apply to the active config, not the local config.

More on Configs

You can learn more about loader-specific differences, supported config screens and supported property types on the annotation-based config guide.