minecraft-src/net/minecraft/world/level/levelgen/synth/BlendedNoise.java
2025-07-04 01:41:11 +03:00

179 lines
5.8 KiB
Java

package net.minecraft.world.level.levelgen.synth;
import com.google.common.annotations.VisibleForTesting;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.Locale;
import java.util.stream.IntStream;
import net.minecraft.util.KeyDispatchDataCodec;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.XoroshiroRandomSource;
/**
* This class wraps three individual perlin noise octaves samplers.
* It computes the octaves of the main noise, and then uses that as a linear interpolation value between the minimum and maximum limit noises.
*/
public class BlendedNoise implements DensityFunction.SimpleFunction {
private static final Codec<Double> SCALE_RANGE = Codec.doubleRange(0.001, 1000.0);
private static final MapCodec<BlendedNoise> DATA_CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
SCALE_RANGE.fieldOf("xz_scale").forGetter(blendedNoise -> blendedNoise.xzScale),
SCALE_RANGE.fieldOf("y_scale").forGetter(blendedNoise -> blendedNoise.yScale),
SCALE_RANGE.fieldOf("xz_factor").forGetter(blendedNoise -> blendedNoise.xzFactor),
SCALE_RANGE.fieldOf("y_factor").forGetter(blendedNoise -> blendedNoise.yFactor),
Codec.doubleRange(1.0, 8.0).fieldOf("smear_scale_multiplier").forGetter(blendedNoise -> blendedNoise.smearScaleMultiplier)
)
.apply(instance, BlendedNoise::createUnseeded)
);
public static final KeyDispatchDataCodec<BlendedNoise> CODEC = KeyDispatchDataCodec.of(DATA_CODEC);
private final PerlinNoise minLimitNoise;
private final PerlinNoise maxLimitNoise;
private final PerlinNoise mainNoise;
private final double xzMultiplier;
private final double yMultiplier;
private final double xzFactor;
private final double yFactor;
private final double smearScaleMultiplier;
private final double maxValue;
private final double xzScale;
private final double yScale;
public static BlendedNoise createUnseeded(double xzScale, double yScale, double xzFactor, double yFactor, double smearScaleMultiplier) {
return new BlendedNoise(new XoroshiroRandomSource(0L), xzScale, yScale, xzFactor, yFactor, smearScaleMultiplier);
}
private BlendedNoise(
PerlinNoise minLimitNoise,
PerlinNoise maxLimitNoise,
PerlinNoise mainNoise,
double xzScale,
double yScale,
double xzFactor,
double yFactor,
double smearScaleMultiplier
) {
this.minLimitNoise = minLimitNoise;
this.maxLimitNoise = maxLimitNoise;
this.mainNoise = mainNoise;
this.xzScale = xzScale;
this.yScale = yScale;
this.xzFactor = xzFactor;
this.yFactor = yFactor;
this.smearScaleMultiplier = smearScaleMultiplier;
this.xzMultiplier = 684.412 * this.xzScale;
this.yMultiplier = 684.412 * this.yScale;
this.maxValue = minLimitNoise.maxBrokenValue(this.yMultiplier);
}
@VisibleForTesting
public BlendedNoise(RandomSource random, double xzScale, double yScale, double xzFactor, double yFactor, double smearScaleMultiplier) {
this(
PerlinNoise.createLegacyForBlendedNoise(random, IntStream.rangeClosed(-15, 0)),
PerlinNoise.createLegacyForBlendedNoise(random, IntStream.rangeClosed(-15, 0)),
PerlinNoise.createLegacyForBlendedNoise(random, IntStream.rangeClosed(-7, 0)),
xzScale,
yScale,
xzFactor,
yFactor,
smearScaleMultiplier
);
}
public BlendedNoise withNewRandom(RandomSource random) {
return new BlendedNoise(random, this.xzScale, this.yScale, this.xzFactor, this.yFactor, this.smearScaleMultiplier);
}
@Override
public double compute(DensityFunction.FunctionContext context) {
double d = context.blockX() * this.xzMultiplier;
double e = context.blockY() * this.yMultiplier;
double f = context.blockZ() * this.xzMultiplier;
double g = d / this.xzFactor;
double h = e / this.yFactor;
double i = f / this.xzFactor;
double j = this.yMultiplier * this.smearScaleMultiplier;
double k = j / this.yFactor;
double l = 0.0;
double m = 0.0;
double n = 0.0;
boolean bl = true;
double o = 1.0;
for (int p = 0; p < 8; p++) {
ImprovedNoise improvedNoise = this.mainNoise.getOctaveNoise(p);
if (improvedNoise != null) {
n += improvedNoise.noise(PerlinNoise.wrap(g * o), PerlinNoise.wrap(h * o), PerlinNoise.wrap(i * o), k * o, h * o) / o;
}
o /= 2.0;
}
double q = (n / 10.0 + 1.0) / 2.0;
boolean bl2 = q >= 1.0;
boolean bl3 = q <= 0.0;
o = 1.0;
for (int r = 0; r < 16; r++) {
double s = PerlinNoise.wrap(d * o);
double t = PerlinNoise.wrap(e * o);
double u = PerlinNoise.wrap(f * o);
double v = j * o;
if (!bl2) {
ImprovedNoise improvedNoise2 = this.minLimitNoise.getOctaveNoise(r);
if (improvedNoise2 != null) {
l += improvedNoise2.noise(s, t, u, v, e * o) / o;
}
}
if (!bl3) {
ImprovedNoise improvedNoise2 = this.maxLimitNoise.getOctaveNoise(r);
if (improvedNoise2 != null) {
m += improvedNoise2.noise(s, t, u, v, e * o) / o;
}
}
o /= 2.0;
}
return Mth.clampedLerp(l / 512.0, m / 512.0, q) / 128.0;
}
@Override
public double minValue() {
return -this.maxValue();
}
@Override
public double maxValue() {
return this.maxValue;
}
@VisibleForTesting
public void parityConfigString(StringBuilder builder) {
builder.append("BlendedNoise{minLimitNoise=");
this.minLimitNoise.parityConfigString(builder);
builder.append(", maxLimitNoise=");
this.maxLimitNoise.parityConfigString(builder);
builder.append(", mainNoise=");
this.mainNoise.parityConfigString(builder);
builder.append(
String.format(
Locale.ROOT,
", xzScale=%.3f, yScale=%.3f, xzMainScale=%.3f, yMainScale=%.3f, cellWidth=4, cellHeight=8",
684.412,
684.412,
8.555150000000001,
4.277575000000001
)
)
.append('}');
}
@Override
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
return CODEC;
}
}