/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.collect.ImmutableList * com.mojang.logging.LogUtils * com.mojang.serialization.Codec * com.mojang.serialization.DataResult * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.client; import com.google.common.collect.ImmutableList; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.DoubleFunction; import java.util.function.Function; import java.util.function.IntFunction; import java.util.function.IntSupplier; import java.util.function.Supplier; import java.util.function.ToDoubleFunction; import java.util.function.ToIntFunction; import java.util.stream.IntStream; import net.minecraft.client.Minecraft; import net.minecraft.client.Options; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractOptionSliderButton; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.CycleButton; import net.minecraft.client.gui.components.ResettableOptionWidget; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.input.KeyEvent; import net.minecraft.client.input.MouseButtonEvent; import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.util.Util; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public final class OptionInstance { private static final Logger LOGGER = LogUtils.getLogger(); public static final Enum BOOLEAN_VALUES = new Enum(ImmutableList.of((Object)Boolean.TRUE, (Object)Boolean.FALSE), Codec.BOOL); public static final CaptionBasedToString BOOLEAN_TO_STRING = (caption, b) -> b != false ? CommonComponents.OPTION_ON : CommonComponents.OPTION_OFF; private final TooltipSupplier tooltip; private final Function toString; private final ValueSet values; private final Codec codec; private final T initialValue; private final Consumer onValueUpdate; private final Component caption; private T value; public static OptionInstance createBoolean(String captionId, boolean initialValue, Consumer onValueUpdate) { return OptionInstance.createBoolean(captionId, OptionInstance.noTooltip(), initialValue, onValueUpdate); } public static OptionInstance createBoolean(String captionId, boolean initialValue) { return OptionInstance.createBoolean(captionId, OptionInstance.noTooltip(), initialValue, value -> {}); } public static OptionInstance createBoolean(String captionId, TooltipSupplier tooltip, boolean initialValue) { return OptionInstance.createBoolean(captionId, tooltip, initialValue, value -> {}); } public static OptionInstance createBoolean(String captionId, TooltipSupplier tooltip, boolean initialValue, Consumer onValueUpdate) { return OptionInstance.createBoolean(captionId, tooltip, BOOLEAN_TO_STRING, initialValue, onValueUpdate); } public static OptionInstance createBoolean(String captionId, TooltipSupplier tooltip, CaptionBasedToString toString, boolean initialValue, Consumer onValueUpdate) { return new OptionInstance(captionId, tooltip, toString, BOOLEAN_VALUES, initialValue, onValueUpdate); } public OptionInstance(String captionId, TooltipSupplier tooltip, CaptionBasedToString toString, ValueSet values, T initialValue, Consumer onValueUpdate) { this(captionId, tooltip, toString, values, values.codec(), initialValue, onValueUpdate); } public OptionInstance(String captionId, TooltipSupplier tooltip, CaptionBasedToString toString, ValueSet values, Codec codec, T initialValue, Consumer onValueUpdate) { this.caption = Component.translatable(captionId); this.tooltip = tooltip; this.toString = value -> toString.toString(this.caption, value); this.values = values; this.codec = codec; this.initialValue = initialValue; this.onValueUpdate = onValueUpdate; this.value = this.initialValue; } public static TooltipSupplier noTooltip() { return value -> null; } public static TooltipSupplier cachedConstantTooltip(Component tooltipComponent) { return value -> Tooltip.create(tooltipComponent); } public AbstractWidget createButton(Options options) { return this.createButton(options, 0, 0, 150); } public AbstractWidget createButton(Options options, int x, int y, int width) { return this.createButton(options, x, y, width, value -> {}); } public AbstractWidget createButton(Options options, int x, int y, int width, Consumer onValueChanged) { return this.values.createButton(this.tooltip, options, x, y, width, onValueChanged).apply(this); } public T get() { return this.value; } public Codec codec() { return this.codec; } public String toString() { return this.caption.getString(); } public void set(T value) { Object newValue = this.values.validateValue(value).orElseGet(() -> { LOGGER.error("Illegal option value {} for {}", value, (Object)this.caption.getString()); return this.initialValue; }); if (!Minecraft.getInstance().isRunning()) { this.value = newValue; return; } if (!Objects.equals(this.value, newValue)) { this.value = newValue; this.onValueUpdate.accept(this.value); } } public ValueSet values() { return this.values; } @FunctionalInterface public static interface TooltipSupplier { public @Nullable Tooltip apply(T var1); } public static interface CaptionBasedToString { public Component toString(Component var1, T var2); } public record Enum(List values, Codec codec) implements CycleableValueSet { @Override public Optional validateValue(T value) { return this.values.contains(value) ? Optional.of(value) : Optional.empty(); } @Override public CycleButton.ValueListSupplier valueListSupplier() { return CycleButton.ValueListSupplier.create(this.values); } } static interface ValueSet { public Function, AbstractWidget> createButton(TooltipSupplier var1, Options var2, int var3, int var4, int var5, Consumer var6); public Optional validateValue(T var1); public Codec codec(); } public static enum UnitDouble implements SliderableValueSet { INSTANCE; @Override public Optional validateValue(Double value) { return value >= 0.0 && value <= 1.0 ? Optional.of(value) : Optional.empty(); } @Override public double toSliderValue(Double value) { return value; } @Override public Double fromSliderValue(double slider) { return slider; } public SliderableValueSet xmap(final DoubleFunction to, final ToDoubleFunction from) { return new SliderableValueSet(){ @Override public Optional validateValue(R value) { return this.validateValue(from.applyAsDouble(value)).map(to::apply); } @Override public double toSliderValue(R value) { return this.toSliderValue(from.applyAsDouble(value)); } @Override public R fromSliderValue(double slider) { return to.apply(this.fromSliderValue(slider)); } @Override public Codec codec() { return this.codec().xmap(to::apply, from::applyAsDouble); } }; } @Override public Codec codec() { return Codec.withAlternative((Codec)Codec.doubleRange((double)0.0, (double)1.0), (Codec)Codec.BOOL, b -> b != false ? 1.0 : 0.0); } } public record SliderableEnum(List values, Codec codec) implements SliderableValueSet { @Override public double toSliderValue(T value) { if (value == this.values.getFirst()) { return 0.0; } if (value == this.values.getLast()) { return 1.0; } return Mth.map((double)this.values.indexOf(value), 0.0, (double)(this.values.size() - 1), 0.0, 1.0); } @Override public Optional next(T current) { int currentIntex = this.values.indexOf(current); int nextIndex = Mth.clamp(currentIntex + 1, 0, this.values.size() - 1); return Optional.of(this.values.get(nextIndex)); } @Override public Optional previous(T current) { int currentIntex = this.values.indexOf(current); int previousIndex = Mth.clamp(currentIntex - 1, 0, this.values.size() - 1); return Optional.of(this.values.get(previousIndex)); } @Override public T fromSliderValue(double slider) { if (slider >= 1.0) { slider = 0.99999f; } int index = Mth.floor(Mth.map(slider, 0.0, 1.0, 0.0, (double)this.values.size())); return this.values.get(Mth.clamp(index, 0, this.values.size() - 1)); } @Override public Optional validateValue(T value) { int index = this.values.indexOf(value); return index > -1 ? Optional.of(value) : Optional.empty(); } } public record ClampingLazyMaxIntRange(int minInclusive, IntSupplier maxSupplier, int encodableMaxInclusive) implements IntRangeBase, SliderableOrCyclableValueSet { @Override public Optional validateValue(Integer value) { return Optional.of(Mth.clamp(value, this.minInclusive(), this.maxInclusive())); } @Override public int maxInclusive() { return this.maxSupplier.getAsInt(); } @Override public Codec codec() { return Codec.INT.validate(value -> { int maxExclusive = this.encodableMaxInclusive + 1; if (value.compareTo(this.minInclusive) >= 0 && value.compareTo(maxExclusive) <= 0) { return DataResult.success((Object)value); } return DataResult.error(() -> "Value " + value + " outside of range [" + this.minInclusive + ":" + maxExclusive + "]", (Object)value); }); } @Override public boolean createCycleButton() { return true; } @Override public CycleButton.ValueListSupplier valueListSupplier() { return CycleButton.ValueListSupplier.create(IntStream.range(this.minInclusive, this.maxInclusive() + 1).boxed().toList()); } } public record IntRange(int minInclusive, int maxInclusive, boolean applyValueImmediately) implements IntRangeBase { public IntRange(int minInclusive, int maxInclusive) { this(minInclusive, maxInclusive, true); } @Override public Optional validateValue(Integer value) { return value.compareTo(this.minInclusive()) >= 0 && value.compareTo(this.maxInclusive()) <= 0 ? Optional.of(value) : Optional.empty(); } @Override public Codec codec() { return Codec.intRange((int)this.minInclusive, (int)(this.maxInclusive + 1)); } } static interface IntRangeBase extends SliderableValueSet { public int minInclusive(); public int maxInclusive(); @Override default public Optional next(Integer current) { return Optional.of(current + 1); } @Override default public Optional previous(Integer current) { return Optional.of(current - 1); } @Override default public double toSliderValue(Integer value) { if (value.intValue() == this.minInclusive()) { return 0.0; } if (value.intValue() == this.maxInclusive()) { return 1.0; } return Mth.map((double)value.intValue() + 0.5, (double)this.minInclusive(), (double)this.maxInclusive() + 1.0, 0.0, 1.0); } @Override default public Integer fromSliderValue(double slider) { if (slider >= 1.0) { slider = 0.99999f; } return Mth.floor(Mth.map(slider, 0.0, 1.0, (double)this.minInclusive(), (double)this.maxInclusive() + 1.0)); } default public SliderableValueSet xmap(final IntFunction to, final ToIntFunction from, final boolean discrete) { return new SliderableValueSet(){ @Override public Optional validateValue(R value) { return this.validateValue(from.applyAsInt(value)).map(to::apply); } @Override public double toSliderValue(R value) { return this.toSliderValue(from.applyAsInt(value)); } @Override public Optional next(R current) { if (!discrete) { return Optional.empty(); } int currentIndex = from.applyAsInt(current); return Optional.of(to.apply(this.validateValue(currentIndex + 1).orElse(currentIndex))); } @Override public Optional previous(R current) { if (!discrete) { return Optional.empty(); } int currentIndex = from.applyAsInt(current); return Optional.of(to.apply(this.validateValue(currentIndex - 1).orElse(currentIndex))); } @Override public R fromSliderValue(double slider) { return to.apply(this.fromSliderValue(slider)); } @Override public Codec codec() { return this.codec().xmap(to::apply, from::applyAsInt); } }; } } public static final class OptionInstanceSliderButton extends AbstractOptionSliderButton implements ResettableOptionWidget { private final OptionInstance instance; private final SliderableValueSet values; private final TooltipSupplier tooltipSupplier; private final Consumer onValueChanged; private @Nullable Long delayedApplyAt; private final boolean applyValueImmediately; private OptionInstanceSliderButton(Options options, int x, int y, int width, int height, OptionInstance instance, SliderableValueSet values, TooltipSupplier tooltipSupplier, Consumer onValueChanged, boolean applyValueImmediately) { super(options, x, y, width, height, values.toSliderValue(instance.get())); this.instance = instance; this.values = values; this.tooltipSupplier = tooltipSupplier; this.onValueChanged = onValueChanged; this.applyValueImmediately = applyValueImmediately; this.updateMessage(); } @Override protected void updateMessage() { this.setMessage(this.instance.toString.apply(this.values.fromSliderValue(this.value))); this.setTooltip(this.tooltipSupplier.apply(this.values.fromSliderValue(this.value))); } @Override protected void applyValue() { if (this.applyValueImmediately) { this.applyUnsavedValue(); } else { this.delayedApplyAt = Util.getMillis() + 600L; } } public void applyUnsavedValue() { N sliderValue = this.values.fromSliderValue(this.value); if (!Objects.equals(sliderValue, this.instance.get())) { this.instance.set(sliderValue); this.onValueChanged.accept(this.instance.get()); } } @Override public void resetValue() { if (this.value != this.values.toSliderValue(this.instance.get())) { this.value = this.values.toSliderValue(this.instance.get()); this.delayedApplyAt = null; this.updateMessage(); } } @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float a) { super.renderWidget(graphics, mouseX, mouseY, a); if (this.delayedApplyAt != null && Util.getMillis() >= this.delayedApplyAt) { this.delayedApplyAt = null; this.applyUnsavedValue(); this.resetValue(); } } @Override public void onRelease(MouseButtonEvent event) { super.onRelease(event); if (this.applyValueImmediately) { this.resetValue(); } } @Override public boolean keyPressed(KeyEvent event) { if (event.isSelection()) { this.canChangeValue = !this.canChangeValue; return true; } if (this.canChangeValue) { Optional next; Optional previous; boolean left = event.isLeft(); boolean right = event.isRight(); if (left && (previous = this.values.previous(this.values.fromSliderValue(this.value))).isPresent()) { this.setValue(this.values.toSliderValue(previous.get())); return true; } if (right && (next = this.values.next(this.values.fromSliderValue(this.value))).isPresent()) { this.setValue(this.values.toSliderValue(next.get())); return true; } if (left || right) { float direction = left ? -1.0f : 1.0f; this.setValue(this.value + (double)(direction / (float)(this.width - 8))); return true; } } return false; } } public record LazyEnum(Supplier> values, Function> validateValue, Codec codec) implements CycleableValueSet { @Override public Optional validateValue(T value) { return this.validateValue.apply(value); } @Override public CycleButton.ValueListSupplier valueListSupplier() { return CycleButton.ValueListSupplier.create((Collection)this.values.get()); } } public record AltEnum(List values, List altValues, BooleanSupplier altCondition, CycleableValueSet.ValueSetter valueSetter, Codec codec) implements CycleableValueSet { @Override public CycleButton.ValueListSupplier valueListSupplier() { return CycleButton.ValueListSupplier.create(this.altCondition, this.values, this.altValues); } @Override public Optional validateValue(T value) { return (this.altCondition.getAsBoolean() ? this.altValues : this.values).contains(value) ? Optional.of(value) : Optional.empty(); } } static interface SliderableOrCyclableValueSet extends SliderableValueSet, CycleableValueSet { public boolean createCycleButton(); @Override default public Function, AbstractWidget> createButton(TooltipSupplier tooltip, Options options, int x, int y, int width, Consumer onValueChanged) { if (this.createCycleButton()) { return CycleableValueSet.super.createButton(tooltip, options, x, y, width, onValueChanged); } return SliderableValueSet.super.createButton(tooltip, options, x, y, width, onValueChanged); } } static interface CycleableValueSet extends ValueSet { public CycleButton.ValueListSupplier valueListSupplier(); default public ValueSetter valueSetter() { return OptionInstance::set; } @Override default public Function, AbstractWidget> createButton(TooltipSupplier tooltip, Options options, int x, int y, int width, Consumer onValueChanged) { return instance -> CycleButton.builder(instance.toString, instance::get).withValues(this.valueListSupplier()).withTooltip(tooltip).create(x, y, width, 20, instance.caption, (button, value) -> { this.valueSetter().set((OptionInstance)instance, value); options.save(); onValueChanged.accept(value); }); } public static interface ValueSetter { public void set(OptionInstance var1, T var2); } } static interface SliderableValueSet extends ValueSet { public double toSliderValue(T var1); default public Optional next(T current) { return Optional.empty(); } default public Optional previous(T current) { return Optional.empty(); } public T fromSliderValue(double var1); default public boolean applyValueImmediately() { return true; } @Override default public Function, AbstractWidget> createButton(TooltipSupplier tooltip, Options options, int x, int y, int width, Consumer onValueChanged) { return instance -> new OptionInstanceSliderButton(options, x, y, width, 20, instance, this, tooltip, onValueChanged, this.applyValueImmediately()); } } }