OptionInstance.java

net.minecraft.client.OptionInstance

信息

  • 全限定名:net.minecraft.client.OptionInstance
  • 类型:public final class
  • 包:net.minecraft.client
  • 源码路径:src/main/java/net/minecraft/client/OptionInstance.java
  • 起始行号:L38
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L39
    • 说明:

      TODO

  • BOOLEAN_VALUES

    • 类型: OptionInstance.Enum<Boolean>
    • 修饰符: public static final
    • 源码定位: L40
    • 说明:

      TODO

  • BOOLEAN_TO_STRING

    • 类型: OptionInstance.CaptionBasedToString<Boolean>
    • 修饰符: public static final
    • 源码定位: L41
    • 说明:

      TODO

  • tooltip

    • 类型: OptionInstance.TooltipSupplier<T>
    • 修饰符: private final
    • 源码定位: L44
    • 说明:

      TODO

  • toString

    • 类型: Function<T,Component>
    • 修饰符: private final
    • 源码定位: L45
    • 说明:

      TODO

  • values

    • 类型: OptionInstance.ValueSet<T>
    • 修饰符: private final
    • 源码定位: L46
    • 说明:

      TODO

  • codec

    • 类型: Codec<T>
    • 修饰符: private final
    • 源码定位: L47
    • 说明:

      TODO

  • initialValue

    • 类型: T
    • 修饰符: private final
    • 源码定位: L48
    • 说明:

      TODO

  • onValueUpdate

    • 类型: Consumer<T>
    • 修饰符: private final
    • 源码定位: L49
    • 说明:

      TODO

  • caption

    • 类型: Component
    • 修饰符: private final
    • 源码定位: L50
    • 说明:

      TODO

  • value

    • 类型: T
    • 修饰符: private
    • 源码定位: L51
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.OptionInstance.AltEnum

    • 类型: record
    • 修饰符: public
    • 源码定位: L164
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.CaptionBasedToString

    • 类型: interface
    • 修饰符: public
    • 源码定位: L179
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.ClampingLazyMaxIntRange

    • 类型: record
    • 修饰符: public
    • 源码定位: L184
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.CycleableValueSet

    • 类型: interface
    • 修饰符: package-private
    • 源码定位: L221
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.CycleableValueSet.ValueSetter

    • 类型: interface
    • 修饰符: public
    • 源码定位: L243
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.Enum

    • 类型: record
    • 修饰符: public
    • 源码定位: L249
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.IntRange

    • 类型: record
    • 修饰符: public
    • 源码定位: L262
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.IntRangeBase

    • 类型: interface
    • 修饰符: package-private
    • 源码定位: L278
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.LazyEnum

    • 类型: record
    • 修饰符: public
    • 源码定位: L357
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.OptionInstanceSliderButton

    • 类型: class
    • 修饰符: public static final
    • 源码定位: L370
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.SliderableEnum

    • 类型: record
    • 修饰符: public
    • 源码定位: L487
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.SliderableOrCyclableValueSet

    • 类型: interface
    • 修饰符: package-private
    • 源码定位: L529
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.SliderableValueSet

    • 类型: interface
    • 修饰符: package-private
    • 源码定位: L543
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.TooltipSupplier

    • 类型: interface
    • 修饰符: public
    • 源码定位: L572
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.UnitDouble

    • 类型: enum
    • 修饰符: public static
    • 源码定位: L577
    • 说明:

      TODO

  • net.minecraft.client.OptionInstance.ValueSet

    • 类型: interface
    • 修饰符: package-private
    • 源码定位: L627
    • 说明:

      TODO

构造器

public OptionInstance(String captionId, OptionInstance.TooltipSupplier<T> tooltip, OptionInstance.CaptionBasedToString<T> toString, OptionInstance.ValueSet<T> values, T initialValue, Consumer<T> onValueUpdate) @ L81

  • 构造器名:OptionInstance
  • 源码定位:L81
  • 修饰符:public

参数:

  • captionId: String
  • tooltip: OptionInstance.TooltipSupplier
  • toString: OptionInstance.CaptionBasedToString
  • values: OptionInstance.ValueSet
  • initialValue: T
  • onValueUpdate: Consumer

说明:

TODO

public OptionInstance(String captionId, OptionInstance.TooltipSupplier<T> tooltip, OptionInstance.CaptionBasedToString<T> toString, OptionInstance.ValueSet<T> values, Codec<T> codec, T initialValue, Consumer<T> onValueUpdate) @ L92

  • 构造器名:OptionInstance
  • 源码定位:L92
  • 修饰符:public

参数:

  • captionId: String
  • tooltip: OptionInstance.TooltipSupplier
  • toString: OptionInstance.CaptionBasedToString
  • values: OptionInstance.ValueSet
  • codec: Codec
  • initialValue: T
  • onValueUpdate: Consumer

说明:

TODO

方法

下面的方法块按源码顺序生成。

public static OptionInstance<Boolean> createBoolean(String captionId, boolean initialValue, Consumer<Boolean> onValueUpdate) @ L53

  • 方法名:createBoolean
  • 源码定位:L53
  • 返回类型:OptionInstance
  • 修饰符:public static

参数:

  • captionId: String
  • initialValue: boolean
  • onValueUpdate: Consumer

说明:

TODO

public static OptionInstance<Boolean> createBoolean(String captionId, boolean initialValue) @ L57

  • 方法名:createBoolean
  • 源码定位:L57
  • 返回类型:OptionInstance
  • 修饰符:public static

参数:

  • captionId: String
  • initialValue: boolean

说明:

TODO

public static OptionInstance<Boolean> createBoolean(String captionId, OptionInstance.TooltipSupplier<Boolean> tooltip, boolean initialValue) @ L61

  • 方法名:createBoolean
  • 源码定位:L61
  • 返回类型:OptionInstance
  • 修饰符:public static

参数:

  • captionId: String
  • tooltip: OptionInstance.TooltipSupplier
  • initialValue: boolean

说明:

TODO

public static OptionInstance<Boolean> createBoolean(String captionId, OptionInstance.TooltipSupplier<Boolean> tooltip, boolean initialValue, Consumer<Boolean> onValueUpdate) @ L65

  • 方法名:createBoolean
  • 源码定位:L65
  • 返回类型:OptionInstance
  • 修饰符:public static

参数:

  • captionId: String
  • tooltip: OptionInstance.TooltipSupplier
  • initialValue: boolean
  • onValueUpdate: Consumer

说明:

TODO

public static OptionInstance<Boolean> createBoolean(String captionId, OptionInstance.TooltipSupplier<Boolean> tooltip, OptionInstance.CaptionBasedToString<Boolean> toString, boolean initialValue, Consumer<Boolean> onValueUpdate) @ L71

  • 方法名:createBoolean
  • 源码定位:L71
  • 返回类型:OptionInstance
  • 修饰符:public static

参数:

  • captionId: String
  • tooltip: OptionInstance.TooltipSupplier
  • toString: OptionInstance.CaptionBasedToString
  • initialValue: boolean
  • onValueUpdate: Consumer

说明:

TODO

public static <T> OptionInstance.TooltipSupplier<T> noTooltip() @ L111

  • 方法名:noTooltip
  • 源码定位:L111
  • 返回类型: OptionInstance.TooltipSupplier
  • 修饰符:public static

参数:

说明:

TODO

public static <T> OptionInstance.TooltipSupplier<T> cachedConstantTooltip(Component tooltipComponent) @ L115

  • 方法名:cachedConstantTooltip
  • 源码定位:L115
  • 返回类型: OptionInstance.TooltipSupplier
  • 修饰符:public static

参数:

  • tooltipComponent: Component

说明:

TODO

public AbstractWidget createButton(Options options) @ L119

  • 方法名:createButton
  • 源码定位:L119
  • 返回类型:AbstractWidget
  • 修饰符:public

参数:

  • options: Options

说明:

TODO

public AbstractWidget createButton(Options options, int x, int y, int width) @ L123

  • 方法名:createButton
  • 源码定位:L123
  • 返回类型:AbstractWidget
  • 修饰符:public

参数:

  • options: Options
  • x: int
  • y: int
  • width: int

说明:

TODO

public AbstractWidget createButton(Options options, int x, int y, int width, Consumer<T> onValueChanged) @ L127

  • 方法名:createButton
  • 源码定位:L127
  • 返回类型:AbstractWidget
  • 修饰符:public

参数:

  • options: Options
  • x: int
  • y: int
  • width: int
  • onValueChanged: Consumer

说明:

TODO

public T get() @ L131

  • 方法名:get
  • 源码定位:L131
  • 返回类型:T
  • 修饰符:public

参数:

说明:

TODO

public Codec<T> codec() @ L135

  • 方法名:codec
  • 源码定位:L135
  • 返回类型:Codec
  • 修饰符:public

参数:

说明:

TODO

public String toString() @ L139

  • 方法名:toString
  • 源码定位:L139
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public void set(T value) @ L144

  • 方法名:set
  • 源码定位:L144
  • 返回类型:void
  • 修饰符:public

参数:

  • value: T

说明:

TODO

public OptionInstance.ValueSet<T> values() @ L159

  • 方法名:values
  • 源码定位:L159
  • 返回类型:OptionInstance.ValueSet
  • 修饰符:public

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public final class OptionInstance<T> {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final OptionInstance.Enum<Boolean> BOOLEAN_VALUES = new OptionInstance.Enum<>(ImmutableList.of(Boolean.TRUE, Boolean.FALSE), Codec.BOOL);
    public static final OptionInstance.CaptionBasedToString<Boolean> BOOLEAN_TO_STRING = (caption, b) -> b
        ? CommonComponents.OPTION_ON
        : CommonComponents.OPTION_OFF;
    private final OptionInstance.TooltipSupplier<T> tooltip;
    private final Function<T, Component> toString;
    private final OptionInstance.ValueSet<T> values;
    private final Codec<T> codec;
    private final T initialValue;
    private final Consumer<T> onValueUpdate;
    private final Component caption;
    private T value;
 
    public static OptionInstance<Boolean> createBoolean(String captionId, boolean initialValue, Consumer<Boolean> onValueUpdate) {
        return createBoolean(captionId, noTooltip(), initialValue, onValueUpdate);
    }
 
    public static OptionInstance<Boolean> createBoolean(String captionId, boolean initialValue) {
        return createBoolean(captionId, noTooltip(), initialValue, value -> {});
    }
 
    public static OptionInstance<Boolean> createBoolean(String captionId, OptionInstance.TooltipSupplier<Boolean> tooltip, boolean initialValue) {
        return createBoolean(captionId, tooltip, initialValue, value -> {});
    }
 
    public static OptionInstance<Boolean> createBoolean(
        String captionId, OptionInstance.TooltipSupplier<Boolean> tooltip, boolean initialValue, Consumer<Boolean> onValueUpdate
    ) {
        return createBoolean(captionId, tooltip, BOOLEAN_TO_STRING, initialValue, onValueUpdate);
    }
 
    public static OptionInstance<Boolean> createBoolean(
        String captionId,
        OptionInstance.TooltipSupplier<Boolean> tooltip,
        OptionInstance.CaptionBasedToString<Boolean> toString,
        boolean initialValue,
        Consumer<Boolean> onValueUpdate
    ) {
        return new OptionInstance<>(captionId, tooltip, toString, BOOLEAN_VALUES, initialValue, onValueUpdate);
    }
 
    public OptionInstance(
        String captionId,
        OptionInstance.TooltipSupplier<T> tooltip,
        OptionInstance.CaptionBasedToString<T> toString,
        OptionInstance.ValueSet<T> values,
        T initialValue,
        Consumer<T> onValueUpdate
    ) {
        this(captionId, tooltip, toString, values, values.codec(), initialValue, onValueUpdate);
    }
 
    public OptionInstance(
        String captionId,
        OptionInstance.TooltipSupplier<T> tooltip,
        OptionInstance.CaptionBasedToString<T> toString,
        OptionInstance.ValueSet<T> values,
        Codec<T> codec,
        T initialValue,
        Consumer<T> 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 <T> OptionInstance.TooltipSupplier<T> noTooltip() {
        return value -> null;
    }
 
    public static <T> OptionInstance.TooltipSupplier<T> 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<T> onValueChanged) {
        return this.values.createButton(this.tooltip, options, x, y, width, onValueChanged).apply(this);
    }
 
    public T get() {
        return this.value;
    }
 
    public Codec<T> codec() {
        return this.codec;
    }
 
    @Override
    public String toString() {
        return this.caption.getString();
    }
 
    public void set(T value) {
        T newValue = this.values.validateValue(value).orElseGet(() -> {
            LOGGER.error("Illegal option value {} for {}", value, this.caption.getString());
            return this.initialValue;
        });
        if (!Minecraft.getInstance().isRunning()) {
            this.value = newValue;
        } else {
            if (!Objects.equals(this.value, newValue)) {
                this.value = newValue;
                this.onValueUpdate.accept(this.value);
            }
        }
    }
 
    public OptionInstance.ValueSet<T> values() {
        return this.values;
    }
 
    @OnlyIn(Dist.CLIENT)
    public record AltEnum<T>(
        List<T> values, List<T> altValues, BooleanSupplier altCondition, OptionInstance.CycleableValueSet.ValueSetter<T> valueSetter, Codec<T> codec
    ) implements OptionInstance.CycleableValueSet<T> {
        @Override
        public CycleButton.ValueListSupplier<T> valueListSupplier() {
            return CycleButton.ValueListSupplier.create(this.altCondition, this.values, this.altValues);
        }
 
        @Override
        public Optional<T> validateValue(T value) {
            return (this.altCondition.getAsBoolean() ? this.altValues : this.values).contains(value) ? Optional.of(value) : Optional.empty();
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public interface CaptionBasedToString<T> {
        Component toString(final Component caption, final T value);
    }
 
    @OnlyIn(Dist.CLIENT)
    public record ClampingLazyMaxIntRange(int minInclusive, IntSupplier maxSupplier, int encodableMaxInclusive)
        implements OptionInstance.IntRangeBase,
        OptionInstance.SliderableOrCyclableValueSet<Integer> {
        public Optional<Integer> validateValue(Integer value) {
            return Optional.of(Mth.clamp(value, this.minInclusive(), this.maxInclusive()));
        }
 
        @Override
        public int maxInclusive() {
            return this.maxSupplier.getAsInt();
        }
 
        @Override
        public Codec<Integer> codec() {
            return Codec.INT
                .validate(
                    value -> {
                        int maxExclusive = this.encodableMaxInclusive + 1;
                        return value.compareTo(this.minInclusive) >= 0 && value.compareTo(maxExclusive) <= 0
                            ? DataResult.success(value)
                            : DataResult.error(() -> "Value " + value + " outside of range [" + this.minInclusive + ":" + maxExclusive + "]", value);
                    }
                );
        }
 
        @Override
        public boolean createCycleButton() {
            return true;
        }
 
        @Override
        public CycleButton.ValueListSupplier<Integer> valueListSupplier() {
            return CycleButton.ValueListSupplier.create(IntStream.range(this.minInclusive, this.maxInclusive() + 1).boxed().toList());
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    interface CycleableValueSet<T> extends OptionInstance.ValueSet<T> {
        CycleButton.ValueListSupplier<T> valueListSupplier();
 
        default OptionInstance.CycleableValueSet.ValueSetter<T> valueSetter() {
            return OptionInstance::set;
        }
 
        @Override
        default Function<OptionInstance<T>, AbstractWidget> createButton(
            OptionInstance.TooltipSupplier<T> tooltip, Options options, int x, int y, int width, Consumer<T> onValueChanged
        ) {
            return instance -> CycleButton.<T>builder(instance.toString, instance::get)
                .withValues(this.valueListSupplier())
                .withTooltip(tooltip)
                .create(x, y, width, 20, instance.caption, (button, value) -> {
                    this.valueSetter().set(instance, value);
                    options.save();
                    onValueChanged.accept(value);
                });
        }
 
        @OnlyIn(Dist.CLIENT)
        public interface ValueSetter<T> {
            void set(final OptionInstance<T> instance, final T value);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Enum<T>(List<T> values, Codec<T> codec) implements OptionInstance.CycleableValueSet<T> {
        @Override
        public Optional<T> validateValue(T value) {
            return this.values.contains(value) ? Optional.of(value) : Optional.empty();
        }
 
        @Override
        public CycleButton.ValueListSupplier<T> valueListSupplier() {
            return CycleButton.ValueListSupplier.create(this.values);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record IntRange(int minInclusive, int maxInclusive, boolean applyValueImmediately) implements OptionInstance.IntRangeBase {
        public IntRange(int minInclusive, int maxInclusive) {
            this(minInclusive, maxInclusive, true);
        }
 
        public Optional<Integer> validateValue(Integer value) {
            return value.compareTo(this.minInclusive()) >= 0 && value.compareTo(this.maxInclusive()) <= 0 ? Optional.of(value) : Optional.empty();
        }
 
        @Override
        public Codec<Integer> codec() {
            return Codec.intRange(this.minInclusive, this.maxInclusive + 1);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    interface IntRangeBase extends OptionInstance.SliderableValueSet<Integer> {
        int minInclusive();
 
        int maxInclusive();
 
        default Optional<Integer> next(Integer current) {
            return Optional.of(current + 1);
        }
 
        default Optional<Integer> previous(Integer current) {
            return Optional.of(current - 1);
        }
 
        default double toSliderValue(Integer value) {
            if (value == this.minInclusive()) {
                return 0.0;
            } else {
                return value == this.maxInclusive() ? 1.0 : Mth.map(value.intValue() + 0.5, (double)this.minInclusive(), this.maxInclusive() + 1.0, 0.0, 1.0);
            }
        }
 
        default Integer fromSliderValue(double slider) {
            if (slider >= 1.0) {
                slider = 0.99999F;
            }
 
            return Mth.floor(Mth.map(slider, 0.0, 1.0, (double)this.minInclusive(), this.maxInclusive() + 1.0));
        }
 
        default <R> OptionInstance.SliderableValueSet<R> xmap(IntFunction<? extends R> to, ToIntFunction<? super R> from, boolean discrete) {
            return new OptionInstance.SliderableValueSet<R>() {
                {
                    Objects.requireNonNull(IntRangeBase.this);
                }
 
                @Override
                public Optional<R> validateValue(R value) {
                    return IntRangeBase.this.validateValue(from.applyAsInt(value)).map(to::apply);
                }
 
                @Override
                public double toSliderValue(R value) {
                    return IntRangeBase.this.toSliderValue(from.applyAsInt(value));
                }
 
                @Override
                public Optional<R> next(R current) {
                    if (!discrete) {
                        return Optional.empty();
                    } else {
                        int currentIndex = from.applyAsInt(current);
                        return (Optional<R>)Optional.of(to.apply(IntRangeBase.this.validateValue(currentIndex + 1).orElse(currentIndex)));
                    }
                }
 
                @Override
                public Optional<R> previous(R current) {
                    if (!discrete) {
                        return Optional.empty();
                    } else {
                        int currentIndex = from.applyAsInt(current);
                        return (Optional<R>)Optional.of(to.apply(IntRangeBase.this.validateValue(currentIndex - 1).orElse(currentIndex)));
                    }
                }
 
                @Override
                public R fromSliderValue(double slider) {
                    return (R)to.apply(IntRangeBase.this.fromSliderValue(slider));
                }
 
                @Override
                public Codec<R> codec() {
                    return IntRangeBase.this.codec().xmap(to::apply, from::applyAsInt);
                }
            };
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record LazyEnum<T>(Supplier<List<T>> values, Function<T, Optional<T>> validateValue, Codec<T> codec) implements OptionInstance.CycleableValueSet<T> {
        @Override
        public Optional<T> validateValue(T value) {
            return this.validateValue.apply(value);
        }
 
        @Override
        public CycleButton.ValueListSupplier<T> valueListSupplier() {
            return CycleButton.ValueListSupplier.create(this.values.get());
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public static final class OptionInstanceSliderButton<N> extends AbstractOptionSliderButton implements ResettableOptionWidget {
        private final OptionInstance<N> instance;
        private final OptionInstance.SliderableValueSet<N> values;
        private final OptionInstance.TooltipSupplier<N> tooltipSupplier;
        private final Consumer<N> onValueChanged;
        private @Nullable Long delayedApplyAt;
        private final boolean applyValueImmediately;
 
        private OptionInstanceSliderButton(
            Options options,
            int x,
            int y,
            int width,
            int height,
            OptionInstance<N> instance,
            OptionInstance.SliderableValueSet<N> values,
            OptionInstance.TooltipSupplier<N> tooltipSupplier,
            Consumer<N> 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 extractWidgetRenderState(GuiGraphicsExtractor graphics, int mouseX, int mouseY, float a) {
            super.extractWidgetRenderState(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;
            } else {
                if (this.canChangeValue) {
                    boolean left = event.isLeft();
                    boolean right = event.isRight();
                    if (left) {
                        Optional<N> previous = this.values.previous(this.values.fromSliderValue(this.value));
                        if (previous.isPresent()) {
                            this.setValue(this.values.toSliderValue(previous.get()));
                            return true;
                        }
                    }
 
                    if (right) {
                        Optional<N> next = this.values.next(this.values.fromSliderValue(this.value));
                        if (next.isPresent()) {
                            this.setValue(this.values.toSliderValue(next.get()));
                            return true;
                        }
                    }
 
                    if (left || right) {
                        float direction = left ? -1.0F : 1.0F;
                        this.setValue(this.value + direction / (this.width - 8));
                        return true;
                    }
                }
 
                return false;
            }
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    public record SliderableEnum<T>(List<T> values, Codec<T> codec) implements OptionInstance.SliderableValueSet<T> {
        @Override
        public double toSliderValue(T value) {
            if (value == this.values.getFirst()) {
                return 0.0;
            } else {
                return value == this.values.getLast() ? 1.0 : Mth.map((double)this.values.indexOf(value), 0.0, (double)(this.values.size() - 1), 0.0, 1.0);
            }
        }
 
        @Override
        public Optional<T> 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<T> 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<T> validateValue(T value) {
            int index = this.values.indexOf(value);
            return index > -1 ? Optional.of(value) : Optional.empty();
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    interface SliderableOrCyclableValueSet<T> extends OptionInstance.SliderableValueSet<T>, OptionInstance.CycleableValueSet<T> {
        boolean createCycleButton();
 
        @Override
        default Function<OptionInstance<T>, AbstractWidget> createButton(
            OptionInstance.TooltipSupplier<T> tooltip, Options options, int x, int y, int width, Consumer<T> onValueChanged
        ) {
            return this.createCycleButton()
                ? OptionInstance.CycleableValueSet.super.createButton(tooltip, options, x, y, width, onValueChanged)
                : OptionInstance.SliderableValueSet.super.createButton(tooltip, options, x, y, width, onValueChanged);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    interface SliderableValueSet<T> extends OptionInstance.ValueSet<T> {
        double toSliderValue(final T value);
 
        default Optional<T> next(T current) {
            return Optional.empty();
        }
 
        default Optional<T> previous(T current) {
            return Optional.empty();
        }
 
        T fromSliderValue(final double slider);
 
        default boolean applyValueImmediately() {
            return true;
        }
 
        @Override
        default Function<OptionInstance<T>, AbstractWidget> createButton(
            OptionInstance.TooltipSupplier<T> tooltip, Options options, int x, int y, int width, Consumer<T> onValueChanged
        ) {
            return instance -> new OptionInstance.OptionInstanceSliderButton<>(
                options, x, y, width, 20, instance, this, tooltip, onValueChanged, this.applyValueImmediately()
            );
        }
    }
 
    @FunctionalInterface
    @OnlyIn(Dist.CLIENT)
    public interface TooltipSupplier<T> {
        @Nullable Tooltip apply(T value);
    }
 
    @OnlyIn(Dist.CLIENT)
    public static enum UnitDouble implements OptionInstance.SliderableValueSet<Double> {
        INSTANCE;
 
        public Optional<Double> validateValue(Double value) {
            return value >= 0.0 && value <= 1.0 ? Optional.of(value) : Optional.empty();
        }
 
        public double toSliderValue(Double value) {
            return value;
        }
 
        public Double fromSliderValue(double slider) {
            return slider;
        }
 
        public <R> OptionInstance.SliderableValueSet<R> xmap(DoubleFunction<? extends R> to, ToDoubleFunction<? super R> from) {
            return new OptionInstance.SliderableValueSet<R>() {
                {
                    Objects.requireNonNull(UnitDouble.this);
                }
 
                @Override
                public Optional<R> validateValue(R value) {
                    return UnitDouble.this.validateValue(from.applyAsDouble(value)).map(to::apply);
                }
 
                @Override
                public double toSliderValue(R value) {
                    return UnitDouble.this.toSliderValue(from.applyAsDouble(value));
                }
 
                @Override
                public R fromSliderValue(double slider) {
                    return (R)to.apply(UnitDouble.this.fromSliderValue(slider));
                }
 
                @Override
                public Codec<R> codec() {
                    return UnitDouble.this.codec().xmap(to::apply, from::applyAsDouble);
                }
            };
        }
 
        @Override
        public Codec<Double> codec() {
            return Codec.withAlternative(Codec.doubleRange(0.0, 1.0), Codec.BOOL, b -> b ? 1.0 : 0.0);
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    interface ValueSet<T> {
        Function<OptionInstance<T>, AbstractWidget> createButton(
            final OptionInstance.TooltipSupplier<T> tooltip, Options options, final int x, final int y, final int width, final Consumer<T> onValueChanged
        );
 
        Optional<T> validateValue(final T value);
 
        Codec<T> codec();
    }
}

引用的其他类

  • Minecraft

    • 引用位置: 方法调用
    • 关联成员: Minecraft.getInstance()
  • Options

    • 引用位置: 参数
  • AbstractWidget

    • 引用位置: 返回值
  • CycleButton

    • 引用位置: 方法调用
    • 关联成员: CycleButton.ValueListSupplier.create()
  • Tooltip

    • 引用位置: 方法调用
    • 关联成员: Tooltip.create()
  • Component

    • 引用位置: 参数/字段/方法调用
    • 关联成员: Component.translatable()
  • Mth

    • 引用位置: 方法调用
    • 关联成员: Mth.clamp(), Mth.floor(), Mth.map()
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.getMillis()