Use an approximation of the heightmap derivative to "erode" some layers of ground_structure (#1699)

Fixes #188
This commit is contained in:
codemob 2025-07-25 16:04:45 -04:00 committed by GitHub
parent a47c8d14a1
commit 55dc104c37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 35 additions and 2 deletions

View File

@ -12,6 +12,8 @@
.music = "cubyz:DarkTimes", .music = "cubyz:DarkTimes",
.soilCreep = 1.0,
.ground_structure = .{ .ground_structure = .{
"3 to 6 cubyz:snow", "3 to 6 cubyz:snow",
"1 to 3 cubyz:permafrost", "1 to 3 cubyz:permafrost",

View File

@ -8,6 +8,8 @@
.mountains = 30, .mountains = 30,
.chance = 0, .chance = 0,
.soilCreep = 1.5,
.music = "cubyz:out_of_breath", .music = "cubyz:out_of_breath",
.parentBiomes = .{ .parentBiomes = .{

View File

@ -289,6 +289,8 @@ pub const Biome = struct { // MARK: Biome
caves: f32, caves: f32,
caveRadiusFactor: f32, caveRadiusFactor: f32,
crystals: u32, crystals: u32,
/// How much of the surface structure should be eroded depending on the slope.
soilCreep: f32,
stoneBlock: main.blocks.Block, stoneBlock: main.blocks.Block,
fogLower: f32, fogLower: f32,
fogHigher: f32, fogHigher: f32,
@ -334,6 +336,7 @@ pub const Biome = struct { // MARK: Biome
.caves = zon.get(f32, "caves", -0.375), .caves = zon.get(f32, "caves", -0.375),
.caveRadiusFactor = @max(-2, @min(2, zon.get(f32, "caveRadiusFactor", 1))), .caveRadiusFactor = @max(-2, @min(2, zon.get(f32, "caveRadiusFactor", 1))),
.crystals = zon.get(u32, "crystals", 0), .crystals = zon.get(u32, "crystals", 0),
.soilCreep = zon.get(f32, "soilCreep", 0.5),
.minHeight = zon.get(i32, "minHeight", std.math.minInt(i32)), .minHeight = zon.get(i32, "minHeight", std.math.minInt(i32)),
.maxHeight = zon.get(i32, "maxHeight", std.math.maxInt(i32)), .maxHeight = zon.get(i32, "maxHeight", std.math.maxInt(i32)),
.supportsRivers = zon.get(bool, "rivers", false), .supportsRivers = zon.get(bool, "rivers", false),
@ -462,11 +465,16 @@ pub const BlockStructure = struct { // MARK: BlockStructure
allocator.free(self.structure); allocator.free(self.structure);
} }
pub fn addSubTerranian(self: BlockStructure, chunk: *ServerChunk, startingDepth: i32, minDepth: i32, x: i32, y: i32, seed: *u64) i32 { pub fn addSubTerranian(self: BlockStructure, chunk: *ServerChunk, startingDepth: i32, minDepth: i32, slope: i32, soilCreep: f32, x: i32, y: i32, seed: *u64) i32 {
var depth = startingDepth; var depth = startingDepth;
var remainingSkippedBlocks = @as(i32, @intFromFloat(@as(f32, @floatFromInt(slope))*soilCreep)) - 1;
for(self.structure) |blockStack| { for(self.structure) |blockStack| {
const total = blockStack.min + main.random.nextIntBounded(u32, seed, @as(u32, 1) + blockStack.max - blockStack.min); const total = blockStack.min + main.random.nextIntBounded(u32, seed, @as(u32, 1) + blockStack.max - blockStack.min);
for(0..total) |_| { for(0..total) |_| {
if(remainingSkippedBlocks > 0) {
remainingSkippedBlocks -= 1;
continue;
}
if(chunk.liesInChunk(x, y, depth)) { if(chunk.liesInChunk(x, y, depth)) {
chunk.updateBlockInGeneration(x, y, depth, blockStack.block); chunk.updateBlockInGeneration(x, y, depth, blockStack.block);
} }

View File

@ -73,11 +73,32 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap
while(z >= zBiome) : (z -= chunk.super.pos.voxelSize) { while(z >= zBiome) : (z -= chunk.super.pos.voxelSize) {
const mask = @as(u64, 1) << @intCast(z >> voxelSizeShift); const mask = @as(u64, 1) << @intCast(z >> voxelSizeShift);
if(heightData & mask != 0) { if(heightData & mask != 0) {
const cardinalDirections = [_]Vec3i{
Vec3i{1, 0, 0},
Vec3i{-1, 0, 0},
Vec3i{0, 1, 0},
Vec3i{0, -1, 0},
};
const surfaceBlock = caveMap.findTerrainChangeAbove(x, y, z) - chunk.super.pos.voxelSize; const surfaceBlock = caveMap.findTerrainChangeAbove(x, y, z) - chunk.super.pos.voxelSize;
var maxUp: i32 = 0;
var maxDown: i32 = 0;
for(cardinalDirections) |direction| {
if(caveMap.isSolid(x + direction[0], y + direction[1], z + direction[2])) {
const diff = caveMap.findTerrainChangeAbove(x + direction[0], y + direction[1], z + direction[2]) - chunk.super.pos.voxelSize - surfaceBlock;
maxUp = @max(maxUp, diff);
} else {
const diff = caveMap.findTerrainChangeBelow(x + direction[0], y + direction[1], z + direction[2]) - surfaceBlock;
maxDown = @max(maxDown, -diff);
}
}
const slope = @min(maxUp, maxDown);
const soilCreep: f32 = biome.soilCreep;
var bseed: u64 = random.initSeed3D(worldSeed, .{chunk.super.pos.wx + x, chunk.super.pos.wy + y, chunk.super.pos.wz + z}); var bseed: u64 = random.initSeed3D(worldSeed, .{chunk.super.pos.wx + x, chunk.super.pos.wy + y, chunk.super.pos.wz + z});
const airBlockBelow = caveMap.findTerrainChangeBelow(x, y, z); const airBlockBelow = caveMap.findTerrainChangeBelow(x, y, z);
// Add the biomes surface structure: // Add the biomes surface structure:
z = @min(z + chunk.super.pos.voxelSize, biome.structure.addSubTerranian(chunk, surfaceBlock, @max(airBlockBelow, zBiome - 1), x, y, &bseed)); z = @min(z + chunk.super.pos.voxelSize, biome.structure.addSubTerranian(chunk, surfaceBlock, @max(airBlockBelow, zBiome - 1), slope, soilCreep, x, y, &bseed));
z -= chunk.super.pos.voxelSize; z -= chunk.super.pos.voxelSize;
if(z < zBiome) break; if(z < zBiome) break;
if(z > airBlockBelow) { if(z > airBlockBelow) {