diff options
Diffstat (limited to 'changelog.md')
-rw-r--r-- | changelog.md | 144 |
1 files changed, 74 insertions, 70 deletions
diff --git a/changelog.md b/changelog.md index ff542b8..45b034a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ -# YetAnotherConfigLib 3.5.0 +# 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) @@ -10,80 +11,83 @@ This build supports the following versions: - NeoForge 1.20.4 - MinecraftForge 1.20.1 -## *Experimental* Codec Config +## State Managers -This update brings a new experimental config API that utilises Mojang's Codec for (de)serialization. +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 ```java -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... -```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 - } -} +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()); ``` -## Rewritten Kotlin DSL - -Completely rewrote the Kotlin DSL! - -```kotlin -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() - } - } - } -} +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. + +```java +.stateManager(StateManager.createInstant(getter, setter, def)) ``` -## Changes +Is the new way to get instantly applied options. You can also implement `StateManager` yourself. + +## Other Changes -- Fix dropdown controllers erroneously showing their dropdown - Crendgrim -- Make cancel/reset and undo buttons public for accessing -- Add compatibility for 1.21 +- Added support for 1.21.2 +- Label Options now allow change of state, so labels can now be changed dynamically. |