minecraft-src/net/minecraft/server/dialog/input/NumberRangeInput.java
2025-09-18 12:27:44 +00:00

94 lines
3.4 KiB
Java

package net.minecraft.server.dialog.input;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Optional;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentSerialization;
import net.minecraft.server.dialog.Dialog;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.util.Mth;
public record NumberRangeInput(int width, Component label, String labelFormat, NumberRangeInput.RangeInfo rangeInfo) implements InputControl {
public static final MapCodec<NumberRangeInput> MAP_CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
Dialog.WIDTH_CODEC.optionalFieldOf("width", 200).forGetter(NumberRangeInput::width),
ComponentSerialization.CODEC.fieldOf("label").forGetter(NumberRangeInput::label),
Codec.STRING.optionalFieldOf("label_format", "options.generic_value").forGetter(NumberRangeInput::labelFormat),
NumberRangeInput.RangeInfo.MAP_CODEC.forGetter(NumberRangeInput::rangeInfo)
)
.apply(instance, NumberRangeInput::new)
);
@Override
public MapCodec<NumberRangeInput> mapCodec() {
return MAP_CODEC;
}
public Component computeLabel(String string) {
return Component.translatable(this.labelFormat, this.label, string);
}
public record RangeInfo(float start, float end, Optional<Float> initial, Optional<Float> step) {
public static final MapCodec<NumberRangeInput.RangeInfo> MAP_CODEC = RecordCodecBuilder.<NumberRangeInput.RangeInfo>mapCodec(
instance -> instance.group(
Codec.FLOAT.fieldOf("start").forGetter(NumberRangeInput.RangeInfo::start),
Codec.FLOAT.fieldOf("end").forGetter(NumberRangeInput.RangeInfo::end),
Codec.FLOAT.optionalFieldOf("initial").forGetter(NumberRangeInput.RangeInfo::initial),
ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("step").forGetter(NumberRangeInput.RangeInfo::step)
)
.apply(instance, NumberRangeInput.RangeInfo::new)
)
.validate(rangeInfo -> {
if (rangeInfo.initial.isPresent()) {
double d = ((Float)rangeInfo.initial.get()).floatValue();
double e = Math.min(rangeInfo.start, rangeInfo.end);
double f = Math.max(rangeInfo.start, rangeInfo.end);
if (d < e || d > f) {
return DataResult.error(() -> "Initial value " + d + " is outside of range [" + e + ", " + f + "]");
}
}
return DataResult.success(rangeInfo);
});
public float computeScaledValue(float f) {
float g = Mth.lerp(f, this.start, this.end);
if (this.step.isEmpty()) {
return g;
} else {
float h = (Float)this.step.get();
float i = this.initialScaledValue();
float j = g - i;
int k = Math.round(j / h);
float l = i + k * h;
if (!this.isOutOfRange(l)) {
return l;
} else {
int m = k - Mth.sign(k);
return i + m * h;
}
}
}
private boolean isOutOfRange(float f) {
float g = this.scaledValueToSlider(f);
return g < 0.0 || g > 1.0;
}
private float initialScaledValue() {
return this.initial.isPresent() ? (Float)this.initial.get() : (this.start + this.end) / 2.0F;
}
public float initialSliderValue() {
float f = this.initialScaledValue();
return this.scaledValueToSlider(f);
}
private float scaledValueToSlider(float f) {
return this.start == this.end ? 0.5F : Mth.inverseLerp(f, this.start, this.end);
}
}
}