/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.google.common.annotations.VisibleForTesting * com.google.common.collect.ImmutableList * com.google.common.collect.ImmutableList$Builder * com.google.common.collect.Lists * com.mojang.datafixers.kinds.App * com.mojang.datafixers.kinds.Applicative * com.mojang.datafixers.util.Either * com.mojang.serialization.Codec * com.mojang.serialization.codecs.RecordCodecBuilder * it.unimi.dsi.fastutil.floats.FloatArrayList * it.unimi.dsi.fastutil.floats.FloatList * org.apache.commons.lang3.mutable.MutableObject */ package net.minecraft.util; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.mojang.datafixers.kinds.App; import com.mojang.datafixers.kinds.Applicative; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.floats.FloatList; import java.util.List; import java.util.Locale; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; import net.minecraft.util.BoundedFloatFunction; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.Mth; import net.minecraft.util.VisibleForDebug; import org.apache.commons.lang3.mutable.MutableObject; public interface CubicSpline> extends BoundedFloatFunction { @VisibleForDebug public String parityString(); public CubicSpline mapAll(CoordinateVisitor var1); public static > Codec> codec(Codec coordinateCodec) { record Point>(float location, CubicSpline value, float derivative) { } MutableObject result = new MutableObject(); Codec pointCodec = RecordCodecBuilder.create(i -> i.group((App)Codec.FLOAT.fieldOf("location").forGetter(Point::location), (App)Codec.lazyInitialized((Supplier)result).fieldOf("value").forGetter(Point::value), (App)Codec.FLOAT.fieldOf("derivative").forGetter(Point::derivative)).apply((Applicative)i, (x$0, x$1, x$2) -> new Point((float)x$0, x$1, (float)x$2))); Codec multipointCodec = RecordCodecBuilder.create(i -> i.group((App)coordinateCodec.fieldOf("coordinate").forGetter(Multipoint::coordinate), (App)ExtraCodecs.nonEmptyList(pointCodec.listOf()).fieldOf("points").forGetter(m -> IntStream.range(0, m.locations.length).mapToObj(p -> new Point(m.locations()[p], m.values().get(p), m.derivatives()[p])).toList())).apply((Applicative)i, (coordinate, points) -> { float[] locations = new float[points.size()]; ImmutableList.Builder values = ImmutableList.builder(); float[] derivatives = new float[points.size()]; for (int p = 0; p < points.size(); ++p) { Point point = (Point)points.get(p); locations[p] = point.location(); values.add(point.value()); derivatives[p] = point.derivative(); } return Multipoint.create(coordinate, locations, values.build(), derivatives); })); result.setValue((Object)Codec.either((Codec)Codec.FLOAT, (Codec)multipointCodec).xmap(e -> (CubicSpline)e.map(Constant::new, m -> m), s -> { Either either; if (s instanceof Constant) { Constant c = (Constant)s; either = Either.left((Object)Float.valueOf(c.value())); } else { either = Either.right((Object)((Multipoint)s)); } return either; })); return (Codec)result.get(); } public static > CubicSpline constant(float value) { return new Constant(value); } public static > Builder builder(I coordinate) { return new Builder(coordinate); } public static > Builder builder(I coordinate, BoundedFloatFunction valueTransformer) { return new Builder(coordinate, valueTransformer); } @VisibleForDebug public record Constant>(float value) implements CubicSpline { @Override public float apply(C c) { return this.value; } @Override public String parityString() { return String.format(Locale.ROOT, "k=%.3f", Float.valueOf(this.value)); } @Override public float minValue() { return this.value; } @Override public float maxValue() { return this.value; } @Override public CubicSpline mapAll(CoordinateVisitor visitor) { return this; } } public static final class Builder> { private final I coordinate; private final BoundedFloatFunction valueTransformer; private final FloatList locations = new FloatArrayList(); private final List> values = Lists.newArrayList(); private final FloatList derivatives = new FloatArrayList(); protected Builder(I coordinate) { this(coordinate, BoundedFloatFunction.IDENTITY); } protected Builder(I coordinate, BoundedFloatFunction valueTransformer) { this.coordinate = coordinate; this.valueTransformer = valueTransformer; } public Builder addPoint(float location, float value) { return this.addPoint(location, new Constant(this.valueTransformer.apply(Float.valueOf(value))), 0.0f); } public Builder addPoint(float location, float value, float derivative) { return this.addPoint(location, new Constant(this.valueTransformer.apply(Float.valueOf(value))), derivative); } public Builder addPoint(float location, CubicSpline sampler) { return this.addPoint(location, sampler, 0.0f); } private Builder addPoint(float location, CubicSpline sampler, float derivative) { if (!this.locations.isEmpty() && location <= this.locations.getFloat(this.locations.size() - 1)) { throw new IllegalArgumentException("Please register points in ascending order"); } this.locations.add(location); this.values.add(sampler); this.derivatives.add(derivative); return this; } public CubicSpline build() { if (this.locations.isEmpty()) { throw new IllegalStateException("No elements added"); } return Multipoint.create(this.coordinate, this.locations.toFloatArray(), ImmutableList.copyOf(this.values), this.derivatives.toFloatArray()); } } @VisibleForDebug public record Multipoint>(I coordinate, float[] locations, List> values, float[] derivatives, float minValue, float maxValue) implements CubicSpline { public Multipoint { Multipoint.validateSizes(locations, values, derivatives); } private static > Multipoint create(I coordinate, float[] locations, List> values, float[] derivatives) { float edge2; float edge1; Multipoint.validateSizes(locations, values, derivatives); int lastIndex = locations.length - 1; float minValue = Float.POSITIVE_INFINITY; float maxValue = Float.NEGATIVE_INFINITY; float minInput = coordinate.minValue(); float maxInput = coordinate.maxValue(); if (minInput < locations[0]) { edge1 = Multipoint.linearExtend(minInput, locations, values.get(0).minValue(), derivatives, 0); edge2 = Multipoint.linearExtend(minInput, locations, values.get(0).maxValue(), derivatives, 0); minValue = Math.min(minValue, Math.min(edge1, edge2)); maxValue = Math.max(maxValue, Math.max(edge1, edge2)); } if (maxInput > locations[lastIndex]) { edge1 = Multipoint.linearExtend(maxInput, locations, values.get(lastIndex).minValue(), derivatives, lastIndex); edge2 = Multipoint.linearExtend(maxInput, locations, values.get(lastIndex).maxValue(), derivatives, lastIndex); minValue = Math.min(minValue, Math.min(edge1, edge2)); maxValue = Math.max(maxValue, Math.max(edge1, edge2)); } for (CubicSpline value : values) { minValue = Math.min(minValue, value.minValue()); maxValue = Math.max(maxValue, value.maxValue()); } for (int i = 0; i < lastIndex; ++i) { float x1 = locations[i]; float x2 = locations[i + 1]; float xDiff = x2 - x1; CubicSpline v1 = values.get(i); CubicSpline v2 = values.get(i + 1); float min1 = v1.minValue(); float max1 = v1.maxValue(); float min2 = v2.minValue(); float max2 = v2.maxValue(); float d1 = derivatives[i]; float d2 = derivatives[i + 1]; if (d1 == 0.0f && d2 == 0.0f) continue; float p1 = d1 * xDiff; float p2 = d2 * xDiff; float minLerp1 = Math.min(min1, min2); float maxLerp1 = Math.max(max1, max2); float minA = p1 - max2 + min1; float maxA = p1 - min2 + max1; float minB = -p2 + min2 - max1; float maxB = -p2 + max2 - min1; float minLerp2 = Math.min(minA, minB); float maxLerp2 = Math.max(maxA, maxB); minValue = Math.min(minValue, minLerp1 + 0.25f * minLerp2); maxValue = Math.max(maxValue, maxLerp1 + 0.25f * maxLerp2); } return new Multipoint(coordinate, locations, values, derivatives, minValue, maxValue); } private static float linearExtend(float input, float[] locations, float value, float[] derivatives, int index) { float derivative = derivatives[index]; if (derivative == 0.0f) { return value; } return value + derivative * (input - locations[index]); } private static > void validateSizes(float[] locations, List> values, float[] derivatives) { if (locations.length != values.size() || locations.length != derivatives.length) { throw new IllegalArgumentException("All lengths must be equal, got: " + locations.length + " " + values.size() + " " + derivatives.length); } if (locations.length == 0) { throw new IllegalArgumentException("Cannot create a multipoint spline with no points"); } } @Override public float apply(C c) { float input = this.coordinate.apply(c); int start = Multipoint.findIntervalStart(this.locations, input); int lastIndex = this.locations.length - 1; if (start < 0) { return Multipoint.linearExtend(input, this.locations, this.values.get(0).apply(c), this.derivatives, 0); } if (start == lastIndex) { return Multipoint.linearExtend(input, this.locations, this.values.get(lastIndex).apply(c), this.derivatives, lastIndex); } float x1 = this.locations[start]; float x2 = this.locations[start + 1]; float t = (input - x1) / (x2 - x1); BoundedFloatFunction f1 = this.values.get(start); BoundedFloatFunction f2 = this.values.get(start + 1); float d1 = this.derivatives[start]; float d2 = this.derivatives[start + 1]; float y1 = f1.apply(c); float y2 = f2.apply(c); float a = d1 * (x2 - x1) - (y2 - y1); float b = -d2 * (x2 - x1) + (y2 - y1); float offset = Mth.lerp(t, y1, y2) + t * (1.0f - t) * Mth.lerp(t, a, b); return offset; } private static int findIntervalStart(float[] locations, float input) { return Mth.binarySearch(0, locations.length, i -> input < locations[i]) - 1; } @Override @VisibleForTesting public String parityString() { return "Spline{coordinate=" + String.valueOf(this.coordinate) + ", locations=" + this.toString(this.locations) + ", derivatives=" + this.toString(this.derivatives) + ", values=" + this.values.stream().map(CubicSpline::parityString).collect(Collectors.joining(", ", "[", "]")) + "}"; } private String toString(float[] arr) { return "[" + IntStream.range(0, arr.length).mapToDouble(i -> arr[i]).mapToObj(f -> String.format(Locale.ROOT, "%.3f", f)).collect(Collectors.joining(", ")) + "]"; } @Override public CubicSpline mapAll(CoordinateVisitor visitor) { return Multipoint.create((BoundedFloatFunction)visitor.visit(this.coordinate), this.locations, this.values().stream().map(v -> v.mapAll(visitor)).toList(), this.derivatives); } } public static interface CoordinateVisitor { public I visit(I var1); } }