aboutsummaryrefslogtreecommitdiff
path: root/common/src
diff options
context:
space:
mode:
authorisXander <xandersmith2008@gmail.com>2023-08-12 15:04:45 +0100
committerisXander <xandersmith2008@gmail.com>2023-08-12 15:05:01 +0100
commit3083aebe47f63661238ee2b521b0451af2d95e9f (patch)
tree2e6ac26f024e045394bbc7b02c325641291c35d7 /common/src
parentf0482b7e6cab80ea770aeccc07820c675c93def8 (diff)
downloadYetAnotherConfigLib-3083aebe47f63661238ee2b521b0451af2d95e9f.tar.gz
YetAnotherConfigLib-3083aebe47f63661238ee2b521b0451af2d95e9f.tar.bz2
YetAnotherConfigLib-3083aebe47f63661238ee2b521b0451af2d95e9f.zip
Fix `Option#setAvailable` not updating the reset button when used outside of a listener (@enjarai).
Made listener system more robust.
Diffstat (limited to 'common/src')
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java2
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java44
-rw-r--r--common/src/main/java/dev/isxander/yacl3/impl/OptionImpl.java29
3 files changed, 67 insertions, 8 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java
index bdb8de8..72254cf 100644
--- a/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java
+++ b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionEntryImpl.java
@@ -138,7 +138,7 @@ public final class ListOptionEntryImpl<T> implements ListOptionEntry<T> {
@Override
public void setValue(T newValue) {
value = newValue;
- group.callListeners();
+ group.callListeners(true);
}
@Override
diff --git a/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java
index 12842c1..f45e368 100644
--- a/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java
+++ b/common/src/main/java/dev/isxander/yacl3/impl/ListOptionImpl.java
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import dev.isxander.yacl3.api.*;
import dev.isxander.yacl3.api.controller.ControllerBuilder;
+import dev.isxander.yacl3.impl.utils.YACLConstants;
import net.minecraft.network.chat.Component;
import org.apache.commons.lang3.Validate;
import org.jetbrains.annotations.ApiStatus;
@@ -30,8 +31,10 @@ public final class ListOptionImpl<T> implements ListOption<T> {
private final boolean insertEntriesAtEnd;
private final ImmutableSet<OptionFlag> flags;
private final EntryFactory entryFactory;
+
private final List<BiConsumer<Option<List<T>>, List<T>>> listeners;
private final List<Runnable> refreshListeners;
+ private int listenerTriggerDepth = 0;
public ListOptionImpl(@NotNull Component name, @NotNull OptionDescription description, @NotNull Binding<List<T>> binding, @NotNull Supplier<T> initialValue, @NotNull Function<ListOptionEntry<T>, Controller<T>> controllerFunction, ImmutableSet<OptionFlag> flags, boolean collapsed, boolean available, int minimumNumberOfEntries, int maximumNumberOfEntries, boolean insertEntriesAtEnd, Collection<BiConsumer<Option<List<T>>, List<T>>> listeners) {
this.name = name;
@@ -49,7 +52,7 @@ public final class ListOptionImpl<T> implements ListOption<T> {
this.listeners = new ArrayList<>();
this.listeners.addAll(listeners);
this.refreshListeners = new ArrayList<>();
- callListeners();
+ callListeners(true);
}
@Override
@@ -170,7 +173,12 @@ public final class ListOptionImpl<T> implements ListOption<T> {
@Override
public void setAvailable(boolean available) {
+ boolean changed = this.available != available;
+
this.available = available;
+
+ if (changed)
+ callListeners(false);
}
@Override
@@ -205,14 +213,30 @@ public final class ListOptionImpl<T> implements ListOption<T> {
return values.stream().map(entryFactory::create).collect(Collectors.toList());
}
- void callListeners() {
+ void callListeners(boolean bypass) {
List<T> pendingValue = pendingValue();
- this.listeners.forEach(listener -> listener.accept(this, pendingValue));
+ if (bypass || listenerTriggerDepth == 0) {
+ if (listenerTriggerDepth > 10) {
+ throw new IllegalStateException("Listener trigger depth exceeded 10! This means a listener triggered a listener etc etc 10 times deep. This is likely a bug in the mod using YACL!");
+ }
+
+ this.listenerTriggerDepth++;
+
+ for (BiConsumer<Option<List<T>>, List<T>> listener : listeners) {
+ try {
+ listener.accept(this, pendingValue);
+ } catch (Exception e) {
+ YACLConstants.LOGGER.error("Exception whilst triggering listener for option '%s'".formatted(name.getString()), e);
+ }
+ }
+
+ this.listenerTriggerDepth--;
+ }
}
private void onRefresh() {
refreshListeners.forEach(Runnable::run);
- callListeners();
+ callListeners(true);
}
private class EntryFactory {
@@ -234,7 +258,7 @@ public final class ListOptionImpl<T> implements ListOption<T> {
private Function<ListOptionEntry<T>, Controller<T>> controllerFunction;
private Binding<List<T>> binding = null;
private final Set<OptionFlag> flags = new HashSet<>();
- private T initialValue;
+ private Supplier<T> initialValue;
private boolean collapsed = false;
private boolean available = true;
private int minimumNumberOfEntries = 0;
@@ -259,7 +283,7 @@ public final class ListOptionImpl<T> implements ListOption<T> {
}
@Override
- public Builder<T> initial(@NotNull T initialValue) {
+ public Builder<T> initial(@NotNull Supplier<T> initialValue) {
Validate.notNull(initialValue, "`initialValue` cannot be empty");
this.initialValue = initialValue;
@@ -267,6 +291,14 @@ public final class ListOptionImpl<T> implements ListOption<T> {
}
@Override
+ public Builder<T> initial(@NotNull T initialValue) {
+ Validate.notNull(initialValue, "`initialValue` cannot be empty");
+
+ this.initialValue = () -> initialValue;
+ return this;
+ }
+
+ @Override
public Builder<T> controller(@NotNull Function<Option<T>, ControllerBuilder<T>> controller) {
Validate.notNull(controller, "`controller` cannot be null");
diff --git a/common/src/main/java/dev/isxander/yacl3/impl/OptionImpl.java b/common/src/main/java/dev/isxander/yacl3/impl/OptionImpl.java
index 01a6287..165f38d 100644
--- a/common/src/main/java/dev/isxander/yacl3/impl/OptionImpl.java
+++ b/common/src/main/java/dev/isxander/yacl3/impl/OptionImpl.java
@@ -3,6 +3,7 @@ package dev.isxander.yacl3.impl;
import com.google.common.collect.ImmutableSet;
import dev.isxander.yacl3.api.*;
import dev.isxander.yacl3.api.controller.ControllerBuilder;
+import dev.isxander.yacl3.impl.utils.YACLConstants;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import org.apache.commons.lang3.Validate;
@@ -28,6 +29,7 @@ public final class OptionImpl<T> implements Option<T> {
private T pendingValue;
private final List<BiConsumer<Option<T>, T>> listeners;
+ private int listenerTriggerDepth = 0;
public OptionImpl(
@NotNull Component name,
@@ -82,7 +84,12 @@ public final class OptionImpl<T> implements Option<T> {
@Override
public void setAvailable(boolean available) {
+ boolean changed = this.available != available;
+
this.available = available;
+
+ if (changed)
+ this.triggerListeners(false);
}
@Override
@@ -103,7 +110,7 @@ public final class OptionImpl<T> implements Option<T> {
@Override
public void requestSet(T value) {
pendingValue = value;
- listeners.forEach(listener -> listener.accept(this, pendingValue));
+ this.triggerListeners(true);
}
@Override
@@ -135,6 +142,26 @@ public final class OptionImpl<T> implements Option<T> {
this.listeners.add(changedListener);
}
+ private void triggerListeners(boolean bypass) {
+ if (bypass || listenerTriggerDepth == 0) {
+ if (listenerTriggerDepth > 10) {
+ throw new IllegalStateException("Listener trigger depth exceeded 10! This means a listener triggered a listener etc etc 10 times deep. This is likely a bug in the mod using YACL!");
+ }
+
+ this.listenerTriggerDepth++;
+
+ for (BiConsumer<Option<T>, T> listener : listeners) {
+ try {
+ listener.accept(this, pendingValue);
+ } catch (Exception e) {
+ YACLConstants.LOGGER.error("Exception whilst triggering listener for option '%s'".formatted(name.getString()), e);
+ }
+ }
+
+ this.listenerTriggerDepth--;
+ }
+ }
+
@ApiStatus.Internal
public static class BuilderImpl<T> implements Builder<T> {
private Component name = Component.literal("Name not specified!").withStyle(ChatFormatting.RED);