minecraft-src/net/minecraft/world/level/levelgen/carver/CanyonWorldCarver.java
2025-07-04 03:15:13 +03:00

144 lines
4.9 KiB
Java

package net.minecraft.world.level.levelgen.carver;
import com.mojang.serialization.Codec;
import java.util.function.Function;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.chunk.CarvingMask;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.levelgen.Aquifer;
/**
* A carver responsible for creating ravines, or canyons.
*/
public class CanyonWorldCarver extends WorldCarver<CanyonCarverConfiguration> {
public CanyonWorldCarver(Codec<CanyonCarverConfiguration> codec) {
super(codec);
}
public boolean isStartChunk(CanyonCarverConfiguration canyonCarverConfiguration, RandomSource randomSource) {
return randomSource.nextFloat() <= canyonCarverConfiguration.probability;
}
public boolean carve(
CarvingContext carvingContext,
CanyonCarverConfiguration canyonCarverConfiguration,
ChunkAccess chunkAccess,
Function<BlockPos, Holder<Biome>> function,
RandomSource randomSource,
Aquifer aquifer,
ChunkPos chunkPos,
CarvingMask carvingMask
) {
int i = (this.getRange() * 2 - 1) * 16;
double d = chunkPos.getBlockX(randomSource.nextInt(16));
int j = canyonCarverConfiguration.y.sample(randomSource, carvingContext);
double e = chunkPos.getBlockZ(randomSource.nextInt(16));
float f = randomSource.nextFloat() * (float) (Math.PI * 2);
float g = canyonCarverConfiguration.verticalRotation.sample(randomSource);
double h = canyonCarverConfiguration.yScale.sample(randomSource);
float k = canyonCarverConfiguration.shape.thickness.sample(randomSource);
int l = (int)(i * canyonCarverConfiguration.shape.distanceFactor.sample(randomSource));
int m = 0;
this.doCarve(carvingContext, canyonCarverConfiguration, chunkAccess, function, randomSource.nextLong(), aquifer, d, j, e, k, f, g, 0, l, h, carvingMask);
return true;
}
private void doCarve(
CarvingContext context,
CanyonCarverConfiguration config,
ChunkAccess chunk,
Function<BlockPos, Holder<Biome>> biomeAccessor,
long seed,
Aquifer aquifer,
double x,
double y,
double z,
float thickness,
float yaw,
float pitch,
int branchIndex,
int branchCount,
double horizontalVerticalRatio,
CarvingMask carvingMask
) {
RandomSource randomSource = RandomSource.create(seed);
float[] fs = this.initWidthFactors(context, config, randomSource);
float f = 0.0F;
float g = 0.0F;
for (int i = branchIndex; i < branchCount; i++) {
double d = 1.5 + Mth.sin(i * (float) Math.PI / branchCount) * thickness;
double e = d * horizontalVerticalRatio;
d *= config.shape.horizontalRadiusFactor.sample(randomSource);
e = this.updateVerticalRadius(config, randomSource, e, branchCount, i);
float h = Mth.cos(pitch);
float j = Mth.sin(pitch);
x += Mth.cos(yaw) * h;
y += j;
z += Mth.sin(yaw) * h;
pitch *= 0.7F;
pitch += g * 0.05F;
yaw += f * 0.05F;
g *= 0.8F;
f *= 0.5F;
g += (randomSource.nextFloat() - randomSource.nextFloat()) * randomSource.nextFloat() * 2.0F;
f += (randomSource.nextFloat() - randomSource.nextFloat()) * randomSource.nextFloat() * 4.0F;
if (randomSource.nextInt(4) != 0) {
if (!canReach(chunk.getPos(), x, z, i, branchCount, thickness)) {
return;
}
this.carveEllipsoid(
context,
config,
chunk,
biomeAccessor,
aquifer,
x,
y,
z,
d,
e,
carvingMask,
(carvingContext, dx, ex, fx, ix) -> this.shouldSkip(carvingContext, fs, dx, ex, fx, ix)
);
}
}
}
/**
* Generates a random array full of width factors which are used to create the uneven walls of a ravine.
* @return An array of length {@code context.getGenDepth()}, populated with values between 1.0 and 2.0 inclusive.
*/
private float[] initWidthFactors(CarvingContext context, CanyonCarverConfiguration config, RandomSource random) {
int i = context.getGenDepth();
float[] fs = new float[i];
float f = 1.0F;
for (int j = 0; j < i; j++) {
if (j == 0 || random.nextInt(config.shape.widthSmoothness) == 0) {
f = 1.0F + random.nextFloat() * random.nextFloat();
}
fs[j] = f * f;
}
return fs;
}
private double updateVerticalRadius(CanyonCarverConfiguration config, RandomSource random, double verticalRadius, float branchCount, float currentBranch) {
float f = 1.0F - Mth.abs(0.5F - currentBranch / branchCount) * 2.0F;
float g = config.shape.verticalRadiusDefaultFactor + config.shape.verticalRadiusCenterFactor * f;
return g * verticalRadius * Mth.randomBetween(random, 0.75F, 1.0F);
}
private boolean shouldSkip(CarvingContext context, float[] widthFactors, double relativeX, double relativeY, double relativeZ, int y) {
int i = y - context.getMinGenY();
return (relativeX * relativeX + relativeZ * relativeZ) * widthFactors[i - 1] + relativeY * relativeY / 6.0 >= 1.0;
}
}