Mods
Resource Packs
Data Packs
Modpacks
Shaders
Plugins
Mods Resource Packs Data Packs Plugins Shaders Modpacks
Get Modrinth App Upgrade to Modrinth+
Sign in
ModsPluginsData PacksShadersResource PacksModpacks
Sign in
Settings
YetAnotherConfigLib (YACL)

YetAnotherConfigLib (YACL)

A builder-based configuration library for Minecraft.

29.19M
5,520
Library
Management
Utility

Compatibility

Minecraft: Java Edition

1.21.x
1.20.x
1.19.x

Platforms

Fabric
Forge
NeoForge
Quilt

Supported environments

Client-side
Server-side
Client and server (optional)

90% of ad revenue goes to creators

Support creators and Modrinth ad-free with Modrinth+

Links

Report issues View source Visit wiki Join Discord server
Donate on Patreon

Creators

isxander
isxander Owner

Details

Licensed LGPL-3.0-or-later
Published 2 years ago
Updated 2 weeks ago
DescriptionGalleryChangelogVersions

Show all versions

1
5
6
7
12

YetAnotherConfigLib 3.6.0 for MC 1.20.1

by isxander on Oct 19, 2024
Download

YetAnotherConfigLib 3.6.0 for MC 1.20.1

by isxander on Oct 19, 2024
Download

YetAnotherConfigLib 3.6.0

This build supports the following versions:

  • Fabric 1.21.2
  • Fabric 1.20.1
  • Fabric 1.20.4
  • Fabric 1.20.6 (also supports 1.20.5)
  • Fabric 1.21
  • NeoForge 1.21
  • NeoForge 1.20.6 (also supports 1.20.5)
  • NeoForge 1.20.4
  • MinecraftForge 1.20.1

State Managers

Options now no longer hold their state themselves. This job is now delegated to the StateManager.

This change serves to allow multiple options to share the same state, but with different controllers, descriptions, names, etc.

Example

Take an example of how this might be useful:

You have a long range of gamepad bindings, utilising a custom YACL controller. They are sorted alphabetically in YACL. You want a specific gamepad binding, let's call it 'Jump', to be featured at the top of the list, but also still appear alphabetically in the list.

You add a second 'Jump' YACL option and place it at the beginning of the category, you assign it an identical binding.

This appears to work, but you discover a problem: you can modify the featured option just fine, but when you hit 'Save Changes', you see an error in your log 'Option value mismatch' and your option defaults to the previous, now unchanged value.

Why is this? Each instance of Option holds its own pending value. Which is then applied to the binding when you click save. When you click save, YACL iterates over each option in-order and applies the pending value to the binding. Which leads to the following series of events:

  1. YACL successfully applies the featured 'Jump' option to the binding, as it's first in the list.
  2. YACL then finds the non-featured 'Jump' option, which retained the original default value because the pending value has not changed. From step 1, the binding's value has now changed to something none-default, so now it sets the binding again to the pending value of THIS option, now the binding is back to its default state.
  3. YACL finishes saving options, and checks over each one again. It checks that the pending value matches the binding. Because the featured 'Jump' option now doesn't match, it creates an error in your log: 'Option value mismatch' and assigns the pending value to the binding value.

Solution

State managers essentially solve this by moving the pending value into a separate object that can then be given to multiple options. They ensure that each option's controller is kept up to date by emitting events upon the state's change that controllers then listen to, to keep themselves up to date.

Code Examples

StateManager<Boolean> stateManager = StateManager.createSimple(getter, setter, def);

category.option(Option.<Boolean>createOption()
        .name(Component.literal("Sharing Tick Box"))
        .stateManager(stateManager)
        .controller(TickBoxControllerBuilder::create)
        .build());
category.option(Option.<Boolean>createOption()
        .name(Component.literal("Sharing Boolean"))
        .stateManager(stateManager)
        .controller(BooleanControllerBuilder::create)
        .build());

Here, instead of using a .binding(), you use a .stateManager(). Now both share and update the same state!

Event Changes

Options that listen to events, .listener((option, newValue) -> {}), the syntax has slightly changed. The aforementioned methods have been deprecated, replaced with .addListener((option, event) -> {}), you can retrieve the new value with option.pendingValue().

Consolidation of .instant() behaviour

Because of this open-ness of how an option's pending value gets applied, users of YACL have a lot more power on what happens with how an option's state is applied.

.stateManager(StateManager.createInstant(getter, setter, def))

Is the new way to get instantly applied options. You can also implement StateManager yourself.

Other Changes

  • Added support for 1.21.2
  • Label Options now allow change of state, so labels can now be changed dynamically.

YetAnotherConfigLib 3.6.0 for MC 1.21.2-rc1

by isxander on Oct 19, 2024
Download

YetAnotherConfigLib 3.6.0

This build supports the following versions:

  • Fabric 1.21.2
  • Fabric 1.20.1
  • Fabric 1.20.4
  • Fabric 1.20.6 (also supports 1.20.5)
  • Fabric 1.21
  • NeoForge 1.21
  • NeoForge 1.20.6 (also supports 1.20.5)
  • NeoForge 1.20.4
  • MinecraftForge 1.20.1

State Managers

Options now no longer hold their state themselves. This job is now delegated to the StateManager.

This change serves to allow multiple options to share the same state, but with different controllers, descriptions, names, etc.

Example

Take an example of how this might be useful:

You have a long range of gamepad bindings, utilising a custom YACL controller. They are sorted alphabetically in YACL. You want a specific gamepad binding, let's call it 'Jump', to be featured at the top of the list, but also still appear alphabetically in the list.

You add a second 'Jump' YACL option and place it at the beginning of the category, you assign it an identical binding.

This appears to work, but you discover a problem: you can modify the featured option just fine, but when you hit 'Save Changes', you see an error in your log 'Option value mismatch' and your option defaults to the previous, now unchanged value.

Why is this? Each instance of Option holds its own pending value. Which is then applied to the binding when you click save. When you click save, YACL iterates over each option in-order and applies the pending value to the binding. Which leads to the following series of events:

  1. YACL successfully applies the featured 'Jump' option to the binding, as it's first in the list.
  2. YACL then finds the non-featured 'Jump' option, which retained the original default value because the pending value has not changed. From step 1, the binding's value has now changed to something none-default, so now it sets the binding again to the pending value of THIS option, now the binding is back to its default state.
  3. YACL finishes saving options, and checks over each one again. It checks that the pending value matches the binding. Because the featured 'Jump' option now doesn't match, it creates an error in your log: 'Option value mismatch' and assigns the pending value to the binding value.

Solution

State managers essentially solve this by moving the pending value into a separate object that can then be given to multiple options. They ensure that each option's controller is kept up to date by emitting events upon the state's change that controllers then listen to, to keep themselves up to date.

Code Examples

StateManager<Boolean> stateManager = StateManager.createSimple(getter, setter, def);

category.option(Option.<Boolean>createOption()
        .name(Component.literal("Sharing Tick Box"))
        .stateManager(stateManager)
        .controller(TickBoxControllerBuilder::create)
        .build());
category.option(Option.<Boolean>createOption()
        .name(Component.literal("Sharing Boolean"))
        .stateManager(stateManager)
        .controller(BooleanControllerBuilder::create)
        .build());

Here, instead of using a .binding(), you use a .stateManager(). Now both share and update the same state!

Event Changes

Options that listen to events, .listener((option, newValue) -> {}), the syntax has slightly changed. The aforementioned methods have been deprecated, replaced with .addListener((option, event) -> {}), you can retrieve the new value with option.pendingValue().

Consolidation of .instant() behaviour

Because of this open-ness of how an option's pending value gets applied, users of YACL have a lot more power on what happens with how an option's state is applied.

.stateManager(StateManager.createInstant(getter, setter, def))

Is the new way to get instantly applied options. You can also implement StateManager yourself.

Other Changes

  • Added support for 1.21.2
  • Label Options now allow change of state, so labels can now be changed dynamically.

YetAnotherConfigLib 3.5.0 for MC 1.21

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.21

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0

This build supports the following versions:

  • Fabric 1.20.1
  • Fabric 1.20.4
  • Fabric 1.20.6 (also supports 1.20.5)
  • Fabric 1.21
  • NeoForge 1.21
  • NeoForge 1.20.6 (also supports 1.20.5)
  • NeoForge 1.20.4
  • MinecraftForge 1.20.1

Experimental Codec Config

This update brings a new experimental config API that utilises Mojang's Codec for (de)serialization.

public class CodecConfig extends JsonFileCodecConfig/*or*/CodecConfig {
    public static final CodecConfig INSTANCE = new CodecConfig();

    public final ConfigEntry<Integer> myInt =
            register("my_int", 0, Codec.INT);

    public final ReadonlyConfigEntry<InnerCodecConfig> myInnerConfig =
            register("my_inner_config", InnerCodecConfig.INSTANCE);

    public CodecConfig() {
        super(path);
    }
    
    void test() {
        loadFromFile(); // load like this
        saveToFile(); // save like this
        
        // or if you just extend CodecConfig instead of JsonFileConfig:
        JsonElement element = null;
        this.decode(element, JsonOps.INSTANCE); // load
        DataResult<JsonElement> encoded = this.encodeStart(JsonOps.INSTANCE); // save
    }
}

or in Kotlin...

object CodecConfig : JsonFileCodecConfig(path) {
    val myInt by register<Int>(0, Codec.INT)
    
    val myInnerConfig by register(InnerCodecConfig)
    
    fun test() {
        loadFromFile()
        saveToFile()
        
        // blah blah blah
    }
}

Rewritten Kotlin DSL

Completely rewrote the Kotlin DSL!

YetAnotherConfigLib("namespace") {
    val category by categories.registering {
        val option by rootOptions.registering<Int> {
            controller = slider(range = 5..10)
            binding(::thisProp, default)
            
            val otherOption by categories["category"]["group"].futureRef<Boolean>()
            otherOption.onReady { it.setAvailable(false) }
        }
        
        // translation key is generated automagically
        val label by rootOptions.registeringLabel
        
        val group by groups.registering {
            val otherOption = options.register<Boolean>("otherOption") {
                controller = tickBox()
            }
        }
    }
}

Changes

  • Fix dropdown controllers erroneously showing their dropdown - Crendgrim
  • Make cancel/reset and undo buttons public for accessing
  • Add compatibility for 1.21

YetAnotherConfigLib 3.5.0 for MC 1.21

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.20.6

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.20.6

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.20.4

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.20.4

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.20.1

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0 for MC 1.20.1

by isxander on Jun 13, 2024
Download

YetAnotherConfigLib 3.5.0

This build supports the following versions:

  • Fabric 1.20.1
  • Fabric 1.20.4
  • Fabric 1.20.6 (also supports 1.20.5)
  • Fabric 1.21
  • NeoForge 1.20.6 (also supports 1.20.5)
  • NeoForge 1.20.4
  • MinecraftForge 1.20.1

Experimental Codec Config

This update brings a new experimental config API that utilises Mojang's Codec for (de)serialization.

public class CodecConfig extends JsonFileCodecConfig/*or*/CodecConfig {
    public static final CodecConfig INSTANCE = new CodecConfig();

    public final ConfigEntry<Integer> myInt =
            register("my_int", 0, Codec.INT);

    public final ReadonlyConfigEntry<InnerCodecConfig> myInnerConfig =
            register("my_inner_config", InnerCodecConfig.INSTANCE);

    public CodecConfig() {
        super(path);
    }
    
    void test() {
        loadFromFile(); // load like this
        saveToFile(); // save like this
        
        // or if you just extend CodecConfig instead of JsonFileConfig:
        JsonElement element = null;
        this.decode(element, JsonOps.INSTANCE); // load
        DataResult<JsonElement> encoded = this.encodeStart(JsonOps.INSTANCE); // save
    }
}

or in Kotlin...

object CodecConfig : JsonFileCodecConfig(path) {
    val myInt by register<Int>(0, Codec.INT)
    
    val myInnerConfig by register(InnerCodecConfig)
    
    fun test() {
        loadFromFile()
        saveToFile()
        
        // blah blah blah
    }
}

Rewritten Kotlin DSL

Completely rewrote the Kotlin DSL!

YetAnotherConfigLib("namespace") {
    val category by categories.registering {
        val option by rootOptions.registering<Int> {
            controller = slider(range = 5..10)
            binding(::thisProp, default)
            
            val otherOption by categories["category"]["group"].futureRef<Boolean>()
            otherOption.onReady { it.setAvailable(false) }
        }
        
        // translation key is generated automagically
        val label by rootOptions.registeringLabel
        
        val group by groups.registering {
            val otherOption = options.register<Boolean>("otherOption") {
                controller = tickBox()
            }
        }
    }
}

Changes

  • Fix dropdown controllers erroneously showing their dropdown - Crendgrim
  • Make cancel/reset and undo buttons public for accessing
  • Add compatibility for 1.21

YetAnotherConfigLib 3.4.4 for MC 1.20.1

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.4 for MC 1.20.1

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.4 for MC 1.20.4

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.4 for MC 1.20.6

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.4 for MC 1.20.4

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.4 for MC 1.20.6

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.4

This build supports the following versions:

  • Fabric 1.20.1
  • Fabric 1.20.4
  • Fabric 1.20.6 (also supports 1.20.5)
  • NeoForge 1.20.6 (also supports 1.20.5)
  • NeoForge 1.20.4
  • MinecraftForge 1.20.1

Bug Fixes

  • Fix Kotlin DSL not being included

YetAnotherConfigLib 3.4.3 for MC 1.20.4

by isxander on May 27, 2024
Download

YetAnotherConfigLib 3.4.3 for MC 1.20.4

by isxander on May 27, 2024
Download
1
5
6
7
12

Modrinth is open source.

main@396f737

© Rinth, Inc.

Company

TermsPrivacyRulesCareers

Resources

SupportBlogDocsStatus

Interact

Discord X (Twitter) Mastodon Crowdin
Get Modrinth App Settings
NOT AN OFFICIAL MINECRAFT SERVICE. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.