1206 lines
44 KiB
Java
1206 lines
44 KiB
Java
package net.minecraft.world.level.levelgen;
|
|
|
|
import com.mojang.datafixers.util.Either;
|
|
import com.mojang.logging.LogUtils;
|
|
import com.mojang.serialization.Codec;
|
|
import com.mojang.serialization.MapCodec;
|
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|
import java.util.Arrays;
|
|
import java.util.function.BiFunction;
|
|
import java.util.function.Function;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.Registry;
|
|
import net.minecraft.core.Holder.Direct;
|
|
import net.minecraft.core.registries.BuiltInRegistries;
|
|
import net.minecraft.util.CubicSpline;
|
|
import net.minecraft.util.KeyDispatchDataCodec;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.util.VisibleForDebug;
|
|
import net.minecraft.world.level.dimension.DimensionType;
|
|
import net.minecraft.world.level.levelgen.DensityFunctions.Marker.Type;
|
|
import net.minecraft.world.level.levelgen.DensityFunctions.Spline.Coordinate;
|
|
import net.minecraft.world.level.levelgen.DensityFunctions.Spline.Point;
|
|
import net.minecraft.world.level.levelgen.DensityFunctions.WeirdScaledSampler.RarityValueMapper;
|
|
import net.minecraft.world.level.levelgen.synth.BlendedNoise;
|
|
import net.minecraft.world.level.levelgen.synth.SimplexNoise;
|
|
import net.minecraft.world.level.levelgen.synth.NormalNoise.NoiseParameters;
|
|
import org.slf4j.Logger;
|
|
|
|
public final class DensityFunctions {
|
|
private static final Codec<DensityFunction> CODEC = BuiltInRegistries.DENSITY_FUNCTION_TYPE
|
|
.byNameCodec()
|
|
.dispatch(densityFunction -> densityFunction.codec().codec(), Function.identity());
|
|
protected static final double MAX_REASONABLE_NOISE_VALUE = 1000000.0;
|
|
static final Codec<Double> NOISE_VALUE_CODEC = Codec.doubleRange(-1000000.0, 1000000.0);
|
|
public static final Codec<DensityFunction> DIRECT_CODEC = Codec.either(NOISE_VALUE_CODEC, CODEC)
|
|
.xmap(
|
|
either -> either.map(DensityFunctions::constant, Function.identity()),
|
|
densityFunction -> densityFunction instanceof DensityFunctions.Constant constant ? Either.left(constant.value()) : Either.right(densityFunction)
|
|
);
|
|
|
|
public static MapCodec<? extends DensityFunction> bootstrap(Registry<MapCodec<? extends DensityFunction>> registry) {
|
|
register(registry, "blend_alpha", DensityFunctions.BlendAlpha.CODEC);
|
|
register(registry, "blend_offset", DensityFunctions.BlendOffset.CODEC);
|
|
register(registry, "beardifier", DensityFunctions.BeardifierMarker.CODEC);
|
|
register(registry, "old_blended_noise", BlendedNoise.CODEC);
|
|
|
|
for (Type type : Type.values()) {
|
|
register(registry, type.getSerializedName(), type.codec);
|
|
}
|
|
|
|
register(registry, "noise", DensityFunctions.Noise.CODEC);
|
|
register(registry, "end_islands", DensityFunctions.EndIslandDensityFunction.CODEC);
|
|
register(registry, "weird_scaled_sampler", DensityFunctions.WeirdScaledSampler.CODEC);
|
|
register(registry, "shifted_noise", DensityFunctions.ShiftedNoise.CODEC);
|
|
register(registry, "range_choice", DensityFunctions.RangeChoice.CODEC);
|
|
register(registry, "shift_a", DensityFunctions.ShiftA.CODEC);
|
|
register(registry, "shift_b", DensityFunctions.ShiftB.CODEC);
|
|
register(registry, "shift", DensityFunctions.Shift.CODEC);
|
|
register(registry, "blend_density", DensityFunctions.BlendDensity.CODEC);
|
|
register(registry, "clamp", DensityFunctions.Clamp.CODEC);
|
|
|
|
for (net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type type2 : net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type.values()) {
|
|
register(registry, type2.getSerializedName(), type2.codec);
|
|
}
|
|
|
|
for (net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type type3 : net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.values()) {
|
|
register(registry, type3.getSerializedName(), type3.codec);
|
|
}
|
|
|
|
register(registry, "spline", DensityFunctions.Spline.CODEC);
|
|
register(registry, "constant", DensityFunctions.Constant.CODEC);
|
|
return register(registry, "y_clamped_gradient", DensityFunctions.YClampedGradient.CODEC);
|
|
}
|
|
|
|
private static MapCodec<? extends DensityFunction> register(
|
|
Registry<MapCodec<? extends DensityFunction>> registry, String name, KeyDispatchDataCodec<? extends DensityFunction> codec
|
|
) {
|
|
return Registry.register(registry, name, codec.codec());
|
|
}
|
|
|
|
static <A, O> KeyDispatchDataCodec<O> singleArgumentCodec(Codec<A> codec, Function<A, O> fromFunction, Function<O, A> toFunction) {
|
|
return KeyDispatchDataCodec.of(codec.fieldOf("argument").xmap(fromFunction, toFunction));
|
|
}
|
|
|
|
static <O> KeyDispatchDataCodec<O> singleFunctionArgumentCodec(Function<DensityFunction, O> fromFunction, Function<O, DensityFunction> toFunction) {
|
|
return singleArgumentCodec(DensityFunction.HOLDER_HELPER_CODEC, fromFunction, toFunction);
|
|
}
|
|
|
|
static <O> KeyDispatchDataCodec<O> doubleFunctionArgumentCodec(
|
|
BiFunction<DensityFunction, DensityFunction, O> fromFunction, Function<O, DensityFunction> primary, Function<O, DensityFunction> secondary
|
|
) {
|
|
return KeyDispatchDataCodec.of(
|
|
RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("argument1").forGetter(primary),
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("argument2").forGetter(secondary)
|
|
)
|
|
.apply(instance, fromFunction)
|
|
)
|
|
);
|
|
}
|
|
|
|
static <O> KeyDispatchDataCodec<O> makeCodec(MapCodec<O> mapCodec) {
|
|
return KeyDispatchDataCodec.of(mapCodec);
|
|
}
|
|
|
|
private DensityFunctions() {
|
|
}
|
|
|
|
public static DensityFunction interpolated(DensityFunction wrapped) {
|
|
return new DensityFunctions.Marker(Type.Interpolated, wrapped);
|
|
}
|
|
|
|
public static DensityFunction flatCache(DensityFunction wrapped) {
|
|
return new DensityFunctions.Marker(Type.FlatCache, wrapped);
|
|
}
|
|
|
|
public static DensityFunction cache2d(DensityFunction wrapped) {
|
|
return new DensityFunctions.Marker(Type.Cache2D, wrapped);
|
|
}
|
|
|
|
public static DensityFunction cacheOnce(DensityFunction wrapped) {
|
|
return new DensityFunctions.Marker(Type.CacheOnce, wrapped);
|
|
}
|
|
|
|
public static DensityFunction cacheAllInCell(DensityFunction wrapped) {
|
|
return new DensityFunctions.Marker(Type.CacheAllInCell, wrapped);
|
|
}
|
|
|
|
public static DensityFunction mappedNoise(Holder<NoiseParameters> noiseData, @Deprecated double xzScale, double yScale, double fromY, double toY) {
|
|
return mapFromUnitTo(new DensityFunctions.Noise(new DensityFunction.NoiseHolder(noiseData), xzScale, yScale), fromY, toY);
|
|
}
|
|
|
|
public static DensityFunction mappedNoise(Holder<NoiseParameters> noiseData, double yScale, double fromY, double toY) {
|
|
return mappedNoise(noiseData, 1.0, yScale, fromY, toY);
|
|
}
|
|
|
|
public static DensityFunction mappedNoise(Holder<NoiseParameters> noiseData, double fromY, double toY) {
|
|
return mappedNoise(noiseData, 1.0, 1.0, fromY, toY);
|
|
}
|
|
|
|
public static DensityFunction shiftedNoise2d(DensityFunction shiftX, DensityFunction shiftZ, double xzScale, Holder<NoiseParameters> noiseData) {
|
|
return new DensityFunctions.ShiftedNoise(shiftX, zero(), shiftZ, xzScale, 0.0, new DensityFunction.NoiseHolder(noiseData));
|
|
}
|
|
|
|
public static DensityFunction noise(Holder<NoiseParameters> noiseData) {
|
|
return noise(noiseData, 1.0, 1.0);
|
|
}
|
|
|
|
public static DensityFunction noise(Holder<NoiseParameters> noiseData, double xzScale, double yScale) {
|
|
return new DensityFunctions.Noise(new DensityFunction.NoiseHolder(noiseData), xzScale, yScale);
|
|
}
|
|
|
|
public static DensityFunction noise(Holder<NoiseParameters> noiseData, double yScale) {
|
|
return noise(noiseData, 1.0, yScale);
|
|
}
|
|
|
|
public static DensityFunction rangeChoice(
|
|
DensityFunction input, double minInclusive, double maxExclusive, DensityFunction whenInRange, DensityFunction whenOutOfRange
|
|
) {
|
|
return new DensityFunctions.RangeChoice(input, minInclusive, maxExclusive, whenInRange, whenOutOfRange);
|
|
}
|
|
|
|
public static DensityFunction shiftA(Holder<NoiseParameters> noiseData) {
|
|
return new DensityFunctions.ShiftA(new DensityFunction.NoiseHolder(noiseData));
|
|
}
|
|
|
|
public static DensityFunction shiftB(Holder<NoiseParameters> noiseData) {
|
|
return new DensityFunctions.ShiftB(new DensityFunction.NoiseHolder(noiseData));
|
|
}
|
|
|
|
public static DensityFunction shift(Holder<NoiseParameters> noiseData) {
|
|
return new DensityFunctions.Shift(new DensityFunction.NoiseHolder(noiseData));
|
|
}
|
|
|
|
public static DensityFunction blendDensity(DensityFunction input) {
|
|
return new DensityFunctions.BlendDensity(input);
|
|
}
|
|
|
|
public static DensityFunction endIslands(long seed) {
|
|
return new DensityFunctions.EndIslandDensityFunction(seed);
|
|
}
|
|
|
|
public static DensityFunction weirdScaledSampler(DensityFunction input, Holder<NoiseParameters> noiseData, RarityValueMapper rarityValueMapper) {
|
|
return new DensityFunctions.WeirdScaledSampler(input, new DensityFunction.NoiseHolder(noiseData), rarityValueMapper);
|
|
}
|
|
|
|
public static DensityFunction add(DensityFunction argument1, DensityFunction argument2) {
|
|
return DensityFunctions.TwoArgumentSimpleFunction.create(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.ADD, argument1, argument2
|
|
);
|
|
}
|
|
|
|
public static DensityFunction mul(DensityFunction argument1, DensityFunction argument2) {
|
|
return DensityFunctions.TwoArgumentSimpleFunction.create(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MUL, argument1, argument2
|
|
);
|
|
}
|
|
|
|
public static DensityFunction min(DensityFunction argument1, DensityFunction argument2) {
|
|
return DensityFunctions.TwoArgumentSimpleFunction.create(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MIN, argument1, argument2
|
|
);
|
|
}
|
|
|
|
public static DensityFunction max(DensityFunction argument1, DensityFunction argument2) {
|
|
return DensityFunctions.TwoArgumentSimpleFunction.create(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MAX, argument1, argument2
|
|
);
|
|
}
|
|
|
|
public static DensityFunction spline(CubicSpline<Point, Coordinate> spline) {
|
|
return new DensityFunctions.Spline(spline);
|
|
}
|
|
|
|
public static DensityFunction zero() {
|
|
return DensityFunctions.Constant.ZERO;
|
|
}
|
|
|
|
public static DensityFunction constant(double value) {
|
|
return new DensityFunctions.Constant(value);
|
|
}
|
|
|
|
public static DensityFunction yClampedGradient(int fromY, int toY, double fromValue, double toValue) {
|
|
return new DensityFunctions.YClampedGradient(fromY, toY, fromValue, toValue);
|
|
}
|
|
|
|
public static DensityFunction map(DensityFunction input, net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type type) {
|
|
return DensityFunctions.Mapped.create(type, input);
|
|
}
|
|
|
|
private static DensityFunction mapFromUnitTo(DensityFunction densityFunction, double fromY, double toY) {
|
|
double d = (fromY + toY) * 0.5;
|
|
double e = (toY - fromY) * 0.5;
|
|
return add(constant(d), mul(constant(e), densityFunction));
|
|
}
|
|
|
|
public static DensityFunction blendAlpha() {
|
|
return DensityFunctions.BlendAlpha.INSTANCE;
|
|
}
|
|
|
|
public static DensityFunction blendOffset() {
|
|
return DensityFunctions.BlendOffset.INSTANCE;
|
|
}
|
|
|
|
public static DensityFunction lerp(DensityFunction deltaFunction, DensityFunction minFunction, DensityFunction maxFunction) {
|
|
if (minFunction instanceof DensityFunctions.Constant constant) {
|
|
return lerp(deltaFunction, constant.value, maxFunction);
|
|
} else {
|
|
DensityFunction densityFunction = cacheOnce(deltaFunction);
|
|
DensityFunction densityFunction2 = add(mul(densityFunction, constant(-1.0)), constant(1.0));
|
|
return add(mul(minFunction, densityFunction2), mul(maxFunction, densityFunction));
|
|
}
|
|
}
|
|
|
|
public static DensityFunction lerp(DensityFunction deltaFunction, double min, DensityFunction maxFunction) {
|
|
return add(mul(deltaFunction, add(maxFunction, constant(-min))), constant(min));
|
|
}
|
|
|
|
record Ap2(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type type,
|
|
DensityFunction argument1,
|
|
DensityFunction argument2,
|
|
double minValue,
|
|
double maxValue
|
|
) implements DensityFunctions.TwoArgumentSimpleFunction {
|
|
// $VF: Unable to simplify switch-on-enum, as the enum class was not able to be found.
|
|
// Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!)
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
double d = this.argument1.compute(context);
|
|
|
|
return switch (this.type.ordinal()) {
|
|
case 0 -> d + this.argument2.compute(context);
|
|
case 1 -> d == 0.0 ? 0.0 : d * this.argument2.compute(context);
|
|
case 2 -> d < this.argument2.minValue() ? d : Math.min(d, this.argument2.compute(context));
|
|
case 3 -> d > this.argument2.maxValue() ? d : Math.max(d, this.argument2.compute(context));
|
|
default -> throw new MatchException(null, null);
|
|
};
|
|
}
|
|
|
|
// $VF: Unable to simplify switch-on-enum, as the enum class was not able to be found.
|
|
// Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!)
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
this.argument1.fillArray(array, contextProvider);
|
|
switch (this.type.ordinal()) {
|
|
case 0:
|
|
double[] ds = new double[array.length];
|
|
this.argument2.fillArray(ds, contextProvider);
|
|
|
|
for (int i = 0; i < array.length; i++) {
|
|
array[i] += ds[i];
|
|
}
|
|
break;
|
|
case 1:
|
|
for (int j = 0; j < array.length; j++) {
|
|
double d = array[j];
|
|
array[j] = d == 0.0 ? 0.0 : d * this.argument2.compute(contextProvider.forIndex(j));
|
|
}
|
|
break;
|
|
case 2:
|
|
double e = this.argument2.minValue();
|
|
|
|
for (int k = 0; k < array.length; k++) {
|
|
double f = array[k];
|
|
array[k] = f < e ? f : Math.min(f, this.argument2.compute(contextProvider.forIndex(k)));
|
|
}
|
|
break;
|
|
case 3:
|
|
double e = this.argument2.maxValue();
|
|
|
|
for (int k = 0; k < array.length; k++) {
|
|
double f = array[k];
|
|
array[k] = f > e ? f : Math.max(f, this.argument2.compute(contextProvider.forIndex(k)));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(DensityFunctions.TwoArgumentSimpleFunction.create(this.type, this.argument1.mapAll(visitor), this.argument2.mapAll(visitor)));
|
|
}
|
|
}
|
|
|
|
protected static enum BeardifierMarker implements DensityFunctions.BeardifierOrMarker {
|
|
INSTANCE;
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
Arrays.fill(array, 0.0);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
public interface BeardifierOrMarker extends DensityFunction.SimpleFunction {
|
|
KeyDispatchDataCodec<DensityFunction> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(DensityFunctions.BeardifierMarker.INSTANCE));
|
|
|
|
@Override
|
|
default KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected static enum BlendAlpha implements DensityFunction.SimpleFunction {
|
|
INSTANCE;
|
|
|
|
public static final KeyDispatchDataCodec<DensityFunction> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return 1.0;
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
Arrays.fill(array, 1.0);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return 1.0;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return 1.0;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
record BlendDensity(DensityFunction input) implements DensityFunctions.TransformerWithContext {
|
|
static final KeyDispatchDataCodec<DensityFunctions.BlendDensity> CODEC = DensityFunctions.singleFunctionArgumentCodec(
|
|
DensityFunctions.BlendDensity::new, DensityFunctions.BlendDensity::input
|
|
);
|
|
|
|
@Override
|
|
public double transform(DensityFunction.FunctionContext context, double value) {
|
|
return context.getBlender().blendDensity(context, value);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.BlendDensity(this.input.mapAll(visitor)));
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return Double.NEGATIVE_INFINITY;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return Double.POSITIVE_INFINITY;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected static enum BlendOffset implements DensityFunction.SimpleFunction {
|
|
INSTANCE;
|
|
|
|
public static final KeyDispatchDataCodec<DensityFunction> CODEC = KeyDispatchDataCodec.of(MapCodec.unit(INSTANCE));
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
Arrays.fill(array, 0.0);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected record Clamp(DensityFunction input, double minValue, double maxValue) implements DensityFunctions.PureTransformer {
|
|
private static final MapCodec<DensityFunctions.Clamp> DATA_CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
DensityFunction.DIRECT_CODEC.fieldOf("input").forGetter(DensityFunctions.Clamp::input),
|
|
DensityFunctions.NOISE_VALUE_CODEC.fieldOf("min").forGetter(DensityFunctions.Clamp::minValue),
|
|
DensityFunctions.NOISE_VALUE_CODEC.fieldOf("max").forGetter(DensityFunctions.Clamp::maxValue)
|
|
)
|
|
.apply(instance, DensityFunctions.Clamp::new)
|
|
);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.Clamp> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double transform(double value) {
|
|
return Mth.clamp(value, this.minValue, this.maxValue);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return new DensityFunctions.Clamp(this.input.mapAll(visitor), this.minValue, this.maxValue);
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
record Constant(double value) implements DensityFunction.SimpleFunction {
|
|
static final KeyDispatchDataCodec<DensityFunctions.Constant> CODEC = DensityFunctions.singleArgumentCodec(
|
|
DensityFunctions.NOISE_VALUE_CODEC, DensityFunctions.Constant::new, DensityFunctions.Constant::value
|
|
);
|
|
static final DensityFunctions.Constant ZERO = new DensityFunctions.Constant(0.0);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.value;
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
Arrays.fill(array, this.value);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return this.value;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.value;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected static final class EndIslandDensityFunction implements DensityFunction.SimpleFunction {
|
|
public static final KeyDispatchDataCodec<DensityFunctions.EndIslandDensityFunction> CODEC = KeyDispatchDataCodec.of(
|
|
MapCodec.unit(new DensityFunctions.EndIslandDensityFunction(0L))
|
|
);
|
|
private static final float ISLAND_THRESHOLD = -0.9F;
|
|
private final SimplexNoise islandNoise;
|
|
|
|
public EndIslandDensityFunction(long seed) {
|
|
RandomSource randomSource = new LegacyRandomSource(seed);
|
|
randomSource.consumeCount(17292);
|
|
this.islandNoise = new SimplexNoise(randomSource);
|
|
}
|
|
|
|
private static float getHeightValue(SimplexNoise noise, int x, int z) {
|
|
int i = x / 2;
|
|
int j = z / 2;
|
|
int k = x % 2;
|
|
int l = z % 2;
|
|
float f = 100.0F - Mth.sqrt(x * x + z * z) * 8.0F;
|
|
f = Mth.clamp(f, -100.0F, 80.0F);
|
|
|
|
for (int m = -12; m <= 12; m++) {
|
|
for (int n = -12; n <= 12; n++) {
|
|
long o = i + m;
|
|
long p = j + n;
|
|
if (o * o + p * p > 4096L && noise.getValue(o, p) < -0.9F) {
|
|
float g = (Mth.abs((float)o) * 3439.0F + Mth.abs((float)p) * 147.0F) % 13.0F + 9.0F;
|
|
float h = k - m * 2;
|
|
float q = l - n * 2;
|
|
float r = 100.0F - Mth.sqrt(h * h + q * q) * g;
|
|
r = Mth.clamp(r, -100.0F, 80.0F);
|
|
f = Math.max(f, r);
|
|
}
|
|
}
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return (getHeightValue(this.islandNoise, context.blockX() / 8, context.blockZ() / 8) - 8.0) / 128.0;
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return -0.84375;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return 0.5625;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
@VisibleForDebug
|
|
public record HolderHolder(Holder<DensityFunction> function) implements DensityFunction {
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.function.value().compute(context);
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
this.function.value().fillArray(array, contextProvider);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.HolderHolder(new Direct<>(this.function.value().mapAll(visitor))));
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return this.function.isBound() ? this.function.value().minValue() : Double.NEGATIVE_INFINITY;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.function.isBound() ? this.function.value().maxValue() : Double.POSITIVE_INFINITY;
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
throw new UnsupportedOperationException("Calling .codec() on HolderHolder");
|
|
}
|
|
}
|
|
|
|
protected record Mapped(net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type type, DensityFunction input, double minValue, double maxValue)
|
|
implements DensityFunctions.PureTransformer {
|
|
public static DensityFunctions.Mapped create(net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type type, DensityFunction input) {
|
|
double d = input.minValue();
|
|
double e = transform(type, d);
|
|
double f = transform(type, input.maxValue());
|
|
return type != net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type.ABS
|
|
&& type != net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type.SQUARE
|
|
? new DensityFunctions.Mapped(type, input, e, f)
|
|
: new DensityFunctions.Mapped(type, input, Math.max(0.0, d), Math.max(e, f));
|
|
}
|
|
|
|
// $VF: Unable to simplify switch-on-enum, as the enum class was not able to be found.
|
|
// Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!)
|
|
private static double transform(net.minecraft.world.level.levelgen.DensityFunctions.Mapped.Type type, double value) {
|
|
return switch (type.ordinal()) {
|
|
case 0 -> Math.abs(value);
|
|
case 1 -> value * value;
|
|
case 2 -> value * value * value;
|
|
case 3 -> value > 0.0 ? value : value * 0.5;
|
|
case 4 -> value > 0.0 ? value : value * 0.25;
|
|
case 5 -> {
|
|
double d = Mth.clamp(value, -1.0, 1.0);
|
|
yield d / 2.0 - d * d * d / 24.0;
|
|
}
|
|
default -> throw new MatchException(null, null);
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public double transform(double value) {
|
|
return transform(this.type, value);
|
|
}
|
|
|
|
public DensityFunctions.Mapped mapAll(DensityFunction.Visitor visitor) {
|
|
return create(this.type, this.input.mapAll(visitor));
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return this.type.codec;
|
|
}
|
|
}
|
|
|
|
protected record Marker(Type type, DensityFunction wrapped) implements DensityFunctions.MarkerOrMarked {
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.wrapped.compute(context);
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
this.wrapped.fillArray(array, contextProvider);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return this.wrapped.minValue();
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.wrapped.maxValue();
|
|
}
|
|
}
|
|
|
|
public interface MarkerOrMarked extends DensityFunction {
|
|
Type type();
|
|
|
|
DensityFunction wrapped();
|
|
|
|
@Override
|
|
default KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return this.type().codec;
|
|
}
|
|
|
|
@Override
|
|
default DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.Marker(this.type(), this.wrapped().mapAll(visitor)));
|
|
}
|
|
}
|
|
|
|
record MulOrAdd(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type specificType, DensityFunction input, double minValue, double maxValue, double argument
|
|
) implements DensityFunctions.PureTransformer, DensityFunctions.TwoArgumentSimpleFunction {
|
|
@Override
|
|
public net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type type() {
|
|
return this.specificType == net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type.MUL
|
|
? net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MUL
|
|
: net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.ADD;
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction argument1() {
|
|
return DensityFunctions.constant(this.argument);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction argument2() {
|
|
return this.input;
|
|
}
|
|
|
|
// $VF: Unable to simplify switch-on-enum, as the enum class was not able to be found.
|
|
// Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!)
|
|
@Override
|
|
public double transform(double value) {
|
|
return switch (this.specificType.ordinal()) {
|
|
case 0 -> value * this.argument;
|
|
case 1 -> value + this.argument;
|
|
default -> throw new MatchException(null, null);
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
DensityFunction densityFunction = this.input.mapAll(visitor);
|
|
double d = densityFunction.minValue();
|
|
double e = densityFunction.maxValue();
|
|
double f;
|
|
double g;
|
|
if (this.specificType == net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type.ADD) {
|
|
f = d + this.argument;
|
|
g = e + this.argument;
|
|
} else if (this.argument >= 0.0) {
|
|
f = d * this.argument;
|
|
g = e * this.argument;
|
|
} else {
|
|
f = e * this.argument;
|
|
g = d * this.argument;
|
|
}
|
|
|
|
return new DensityFunctions.MulOrAdd(this.specificType, densityFunction, f, g, this.argument);
|
|
}
|
|
}
|
|
|
|
protected record Noise(DensityFunction.NoiseHolder noise, @Deprecated double xzScale, double yScale) implements DensityFunction {
|
|
public static final MapCodec<DensityFunctions.Noise> DATA_CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
DensityFunction.NoiseHolder.CODEC.fieldOf("noise").forGetter(DensityFunctions.Noise::noise),
|
|
Codec.DOUBLE.fieldOf("xz_scale").forGetter(DensityFunctions.Noise::xzScale),
|
|
Codec.DOUBLE.fieldOf("y_scale").forGetter(DensityFunctions.Noise::yScale)
|
|
)
|
|
.apply(instance, DensityFunctions.Noise::new)
|
|
);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.Noise> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.noise.getValue(context.blockX() * this.xzScale, context.blockY() * this.yScale, context.blockZ() * this.xzScale);
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
contextProvider.fillAllDirectly(array, this);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.Noise(visitor.visitNoise(this.noise), this.xzScale, this.yScale));
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return -this.maxValue();
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.noise.maxValue();
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
interface PureTransformer extends DensityFunction {
|
|
DensityFunction input();
|
|
|
|
@Override
|
|
default double compute(DensityFunction.FunctionContext context) {
|
|
return this.transform(this.input().compute(context));
|
|
}
|
|
|
|
@Override
|
|
default void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
this.input().fillArray(array, contextProvider);
|
|
|
|
for (int i = 0; i < array.length; i++) {
|
|
array[i] = this.transform(array[i]);
|
|
}
|
|
}
|
|
|
|
double transform(double value);
|
|
}
|
|
|
|
record RangeChoice(DensityFunction input, double minInclusive, double maxExclusive, DensityFunction whenInRange, DensityFunction whenOutOfRange)
|
|
implements DensityFunction {
|
|
public static final MapCodec<DensityFunctions.RangeChoice> DATA_CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("input").forGetter(DensityFunctions.RangeChoice::input),
|
|
DensityFunctions.NOISE_VALUE_CODEC.fieldOf("min_inclusive").forGetter(DensityFunctions.RangeChoice::minInclusive),
|
|
DensityFunctions.NOISE_VALUE_CODEC.fieldOf("max_exclusive").forGetter(DensityFunctions.RangeChoice::maxExclusive),
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("when_in_range").forGetter(DensityFunctions.RangeChoice::whenInRange),
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("when_out_of_range").forGetter(DensityFunctions.RangeChoice::whenOutOfRange)
|
|
)
|
|
.apply(instance, DensityFunctions.RangeChoice::new)
|
|
);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.RangeChoice> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
double d = this.input.compute(context);
|
|
return d >= this.minInclusive && d < this.maxExclusive ? this.whenInRange.compute(context) : this.whenOutOfRange.compute(context);
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
this.input.fillArray(array, contextProvider);
|
|
|
|
for (int i = 0; i < array.length; i++) {
|
|
double d = array[i];
|
|
if (d >= this.minInclusive && d < this.maxExclusive) {
|
|
array[i] = this.whenInRange.compute(contextProvider.forIndex(i));
|
|
} else {
|
|
array[i] = this.whenOutOfRange.compute(contextProvider.forIndex(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(
|
|
new DensityFunctions.RangeChoice(
|
|
this.input.mapAll(visitor), this.minInclusive, this.maxExclusive, this.whenInRange.mapAll(visitor), this.whenOutOfRange.mapAll(visitor)
|
|
)
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return Math.min(this.whenInRange.minValue(), this.whenOutOfRange.minValue());
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return Math.max(this.whenInRange.maxValue(), this.whenOutOfRange.maxValue());
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected record Shift(DensityFunction.NoiseHolder offsetNoise) implements DensityFunctions.ShiftNoise {
|
|
static final KeyDispatchDataCodec<DensityFunctions.Shift> CODEC = DensityFunctions.singleArgumentCodec(
|
|
DensityFunction.NoiseHolder.CODEC, DensityFunctions.Shift::new, DensityFunctions.Shift::offsetNoise
|
|
);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.compute(context.blockX(), context.blockY(), context.blockZ());
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.Shift(visitor.visitNoise(this.offsetNoise)));
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected record ShiftA(DensityFunction.NoiseHolder offsetNoise) implements DensityFunctions.ShiftNoise {
|
|
static final KeyDispatchDataCodec<DensityFunctions.ShiftA> CODEC = DensityFunctions.singleArgumentCodec(
|
|
DensityFunction.NoiseHolder.CODEC, DensityFunctions.ShiftA::new, DensityFunctions.ShiftA::offsetNoise
|
|
);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.compute(context.blockX(), 0.0, context.blockZ());
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.ShiftA(visitor.visitNoise(this.offsetNoise)));
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
protected record ShiftB(DensityFunction.NoiseHolder offsetNoise) implements DensityFunctions.ShiftNoise {
|
|
static final KeyDispatchDataCodec<DensityFunctions.ShiftB> CODEC = DensityFunctions.singleArgumentCodec(
|
|
DensityFunction.NoiseHolder.CODEC, DensityFunctions.ShiftB::new, DensityFunctions.ShiftB::offsetNoise
|
|
);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.compute(context.blockZ(), context.blockX(), 0.0);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.ShiftB(visitor.visitNoise(this.offsetNoise)));
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
interface ShiftNoise extends DensityFunction {
|
|
DensityFunction.NoiseHolder offsetNoise();
|
|
|
|
@Override
|
|
default double minValue() {
|
|
return -this.maxValue();
|
|
}
|
|
|
|
@Override
|
|
default double maxValue() {
|
|
return this.offsetNoise().maxValue() * 4.0;
|
|
}
|
|
|
|
default double compute(double x, double y, double z) {
|
|
return this.offsetNoise().getValue(x * 0.25, y * 0.25, z * 0.25) * 4.0;
|
|
}
|
|
|
|
@Override
|
|
default void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
contextProvider.fillAllDirectly(array, this);
|
|
}
|
|
}
|
|
|
|
protected record ShiftedNoise(
|
|
DensityFunction shiftX, DensityFunction shiftY, DensityFunction shiftZ, double xzScale, double yScale, DensityFunction.NoiseHolder noise
|
|
) implements DensityFunction {
|
|
private static final MapCodec<DensityFunctions.ShiftedNoise> DATA_CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("shift_x").forGetter(DensityFunctions.ShiftedNoise::shiftX),
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("shift_y").forGetter(DensityFunctions.ShiftedNoise::shiftY),
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("shift_z").forGetter(DensityFunctions.ShiftedNoise::shiftZ),
|
|
Codec.DOUBLE.fieldOf("xz_scale").forGetter(DensityFunctions.ShiftedNoise::xzScale),
|
|
Codec.DOUBLE.fieldOf("y_scale").forGetter(DensityFunctions.ShiftedNoise::yScale),
|
|
DensityFunction.NoiseHolder.CODEC.fieldOf("noise").forGetter(DensityFunctions.ShiftedNoise::noise)
|
|
)
|
|
.apply(instance, DensityFunctions.ShiftedNoise::new)
|
|
);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.ShiftedNoise> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
double d = context.blockX() * this.xzScale + this.shiftX.compute(context);
|
|
double e = context.blockY() * this.yScale + this.shiftY.compute(context);
|
|
double f = context.blockZ() * this.xzScale + this.shiftZ.compute(context);
|
|
return this.noise.getValue(d, e, f);
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
contextProvider.fillAllDirectly(array, this);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(
|
|
new DensityFunctions.ShiftedNoise(
|
|
this.shiftX.mapAll(visitor), this.shiftY.mapAll(visitor), this.shiftZ.mapAll(visitor), this.xzScale, this.yScale, visitor.visitNoise(this.noise)
|
|
)
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return -this.maxValue();
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.noise.maxValue();
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
public record Spline(CubicSpline<Point, Coordinate> spline) implements DensityFunction {
|
|
private static final Codec<CubicSpline<Point, Coordinate>> SPLINE_CODEC = CubicSpline.codec(Coordinate.CODEC);
|
|
private static final MapCodec<DensityFunctions.Spline> DATA_CODEC = SPLINE_CODEC.fieldOf("spline")
|
|
.xmap(DensityFunctions.Spline::new, DensityFunctions.Spline::spline);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.Spline> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return this.spline.apply(new Point(context));
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return this.spline.minValue();
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.spline.maxValue();
|
|
}
|
|
|
|
@Override
|
|
public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
contextProvider.fillAllDirectly(array, this);
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.Spline(this.spline.mapAll(coordinate -> coordinate.mapAll(visitor))));
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
interface TransformerWithContext extends DensityFunction {
|
|
DensityFunction input();
|
|
|
|
@Override
|
|
default double compute(DensityFunction.FunctionContext context) {
|
|
return this.transform(context, this.input().compute(context));
|
|
}
|
|
|
|
@Override
|
|
default void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
|
|
this.input().fillArray(array, contextProvider);
|
|
|
|
for (int i = 0; i < array.length; i++) {
|
|
array[i] = this.transform(contextProvider.forIndex(i), array[i]);
|
|
}
|
|
}
|
|
|
|
double transform(DensityFunction.FunctionContext context, double value);
|
|
}
|
|
|
|
interface TwoArgumentSimpleFunction extends DensityFunction {
|
|
Logger LOGGER = LogUtils.getLogger();
|
|
|
|
// $VF: Unable to simplify switch-on-enum, as the enum class was not able to be found.
|
|
// Please report this to the Vineflower issue tracker, at https://github.com/Vineflower/vineflower/issues with a copy of the class file (if you have the rights to distribute it!)
|
|
static DensityFunctions.TwoArgumentSimpleFunction create(
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type type, DensityFunction argument1, DensityFunction argument2
|
|
) {
|
|
double d = argument1.minValue();
|
|
double e = argument2.minValue();
|
|
double f = argument1.maxValue();
|
|
double g = argument2.maxValue();
|
|
if (type == net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MIN
|
|
|| type == net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MAX) {
|
|
boolean bl = d >= g;
|
|
boolean bl2 = e >= f;
|
|
if (bl || bl2) {
|
|
LOGGER.warn("Creating a " + type + " function between two non-overlapping inputs: " + argument1 + " and " + argument2);
|
|
}
|
|
}
|
|
double h = switch (type.ordinal()) {
|
|
case 0 -> d + e;
|
|
case 1 -> d > 0.0 && e > 0.0 ? d * e : (f < 0.0 && g < 0.0 ? f * g : Math.min(d * g, f * e));
|
|
case 2 -> Math.min(d, e);
|
|
case 3 -> Math.max(d, e);
|
|
default -> throw new MatchException(null, null);
|
|
};
|
|
|
|
double i = switch (type.ordinal()) {
|
|
case 0 -> f + g;
|
|
case 1 -> d > 0.0 && e > 0.0 ? f * g : (f < 0.0 && g < 0.0 ? d * e : Math.max(d * e, f * g));
|
|
case 2 -> Math.min(f, g);
|
|
case 3 -> Math.max(f, g);
|
|
default -> throw new MatchException(null, null);
|
|
};
|
|
if (type == net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.MUL
|
|
|| type == net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.ADD) {
|
|
if (argument1 instanceof DensityFunctions.Constant constant) {
|
|
return new DensityFunctions.MulOrAdd(
|
|
type == net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.ADD
|
|
? net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type.ADD
|
|
: net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type.MUL,
|
|
argument2,
|
|
h,
|
|
i,
|
|
constant.value
|
|
);
|
|
}
|
|
|
|
if (argument2 instanceof DensityFunctions.Constant constant) {
|
|
return new DensityFunctions.MulOrAdd(
|
|
type == net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type.ADD
|
|
? net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type.ADD
|
|
: net.minecraft.world.level.levelgen.DensityFunctions.MulOrAdd.Type.MUL,
|
|
argument1,
|
|
h,
|
|
i,
|
|
constant.value
|
|
);
|
|
}
|
|
}
|
|
|
|
return new DensityFunctions.Ap2(type, argument1, argument2, h, i);
|
|
}
|
|
|
|
net.minecraft.world.level.levelgen.DensityFunctions.TwoArgumentSimpleFunction.Type type();
|
|
|
|
DensityFunction argument1();
|
|
|
|
DensityFunction argument2();
|
|
|
|
@Override
|
|
default KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return this.type().codec;
|
|
}
|
|
}
|
|
|
|
protected record WeirdScaledSampler(DensityFunction input, DensityFunction.NoiseHolder noise, RarityValueMapper rarityValueMapper)
|
|
implements DensityFunctions.TransformerWithContext {
|
|
private static final MapCodec<DensityFunctions.WeirdScaledSampler> DATA_CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
DensityFunction.HOLDER_HELPER_CODEC.fieldOf("input").forGetter(DensityFunctions.WeirdScaledSampler::input),
|
|
DensityFunction.NoiseHolder.CODEC.fieldOf("noise").forGetter(DensityFunctions.WeirdScaledSampler::noise),
|
|
RarityValueMapper.CODEC.fieldOf("rarity_value_mapper").forGetter(DensityFunctions.WeirdScaledSampler::rarityValueMapper)
|
|
)
|
|
.apply(instance, DensityFunctions.WeirdScaledSampler::new)
|
|
);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.WeirdScaledSampler> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double transform(DensityFunction.FunctionContext context, double value) {
|
|
double d = this.rarityValueMapper.mapper.get(value);
|
|
return d * Math.abs(this.noise.getValue(context.blockX() / d, context.blockY() / d, context.blockZ() / d));
|
|
}
|
|
|
|
@Override
|
|
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
|
|
return visitor.apply(new DensityFunctions.WeirdScaledSampler(this.input.mapAll(visitor), visitor.visitNoise(this.noise), this.rarityValueMapper));
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return 0.0;
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return this.rarityValueMapper.maxRarity * this.noise.maxValue();
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
|
|
record YClampedGradient(int fromY, int toY, double fromValue, double toValue) implements DensityFunction.SimpleFunction {
|
|
private static final MapCodec<DensityFunctions.YClampedGradient> DATA_CODEC = RecordCodecBuilder.mapCodec(
|
|
instance -> instance.group(
|
|
Codec.intRange(DimensionType.MIN_Y * 2, DimensionType.MAX_Y * 2).fieldOf("from_y").forGetter(DensityFunctions.YClampedGradient::fromY),
|
|
Codec.intRange(DimensionType.MIN_Y * 2, DimensionType.MAX_Y * 2).fieldOf("to_y").forGetter(DensityFunctions.YClampedGradient::toY),
|
|
DensityFunctions.NOISE_VALUE_CODEC.fieldOf("from_value").forGetter(DensityFunctions.YClampedGradient::fromValue),
|
|
DensityFunctions.NOISE_VALUE_CODEC.fieldOf("to_value").forGetter(DensityFunctions.YClampedGradient::toValue)
|
|
)
|
|
.apply(instance, DensityFunctions.YClampedGradient::new)
|
|
);
|
|
public static final KeyDispatchDataCodec<DensityFunctions.YClampedGradient> CODEC = DensityFunctions.makeCodec(DATA_CODEC);
|
|
|
|
@Override
|
|
public double compute(DensityFunction.FunctionContext context) {
|
|
return Mth.clampedMap((double)context.blockY(), (double)this.fromY, (double)this.toY, this.fromValue, this.toValue);
|
|
}
|
|
|
|
@Override
|
|
public double minValue() {
|
|
return Math.min(this.fromValue, this.toValue);
|
|
}
|
|
|
|
@Override
|
|
public double maxValue() {
|
|
return Math.max(this.fromValue, this.toValue);
|
|
}
|
|
|
|
@Override
|
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
|
return CODEC;
|
|
}
|
|
}
|
|
}
|