diff --git a/assets/cubyz/biomes/peak.zig.zon b/assets/cubyz/biomes/peak.zig.zon index 362949fb..5d3c19d1 100644 --- a/assets/cubyz/biomes/peak.zig.zon +++ b/assets/cubyz/biomes/peak.zig.zon @@ -12,6 +12,8 @@ .music = "cubyz:DarkTimes", + .soilCreep = 1.0, + .ground_structure = .{ "3 to 6 cubyz:snow", "1 to 3 cubyz:permafrost", diff --git a/assets/cubyz/biomes/tall_mountain/peak.zig.zon b/assets/cubyz/biomes/tall_mountain/peak.zig.zon index d197b0ce..169772ac 100644 --- a/assets/cubyz/biomes/tall_mountain/peak.zig.zon +++ b/assets/cubyz/biomes/tall_mountain/peak.zig.zon @@ -8,6 +8,8 @@ .mountains = 30, .chance = 0, + .soilCreep = 1.5, + .music = "cubyz:out_of_breath", .parentBiomes = .{ diff --git a/src/server/terrain/biomes.zig b/src/server/terrain/biomes.zig index 7fb6fa5d..abace6ed 100644 --- a/src/server/terrain/biomes.zig +++ b/src/server/terrain/biomes.zig @@ -289,6 +289,8 @@ pub const Biome = struct { // MARK: Biome caves: f32, caveRadiusFactor: f32, crystals: u32, + /// How much of the surface structure should be eroded depending on the slope. + soilCreep: f32, stoneBlock: main.blocks.Block, fogLower: f32, fogHigher: f32, @@ -334,6 +336,7 @@ pub const Biome = struct { // MARK: Biome .caves = zon.get(f32, "caves", -0.375), .caveRadiusFactor = @max(-2, @min(2, zon.get(f32, "caveRadiusFactor", 1))), .crystals = zon.get(u32, "crystals", 0), + .soilCreep = zon.get(f32, "soilCreep", 0.5), .minHeight = zon.get(i32, "minHeight", std.math.minInt(i32)), .maxHeight = zon.get(i32, "maxHeight", std.math.maxInt(i32)), .supportsRivers = zon.get(bool, "rivers", false), @@ -462,11 +465,16 @@ pub const BlockStructure = struct { // MARK: BlockStructure 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 remainingSkippedBlocks = @as(i32, @intFromFloat(@as(f32, @floatFromInt(slope))*soilCreep)) - 1; for(self.structure) |blockStack| { const total = blockStack.min + main.random.nextIntBounded(u32, seed, @as(u32, 1) + blockStack.max - blockStack.min); for(0..total) |_| { + if(remainingSkippedBlocks > 0) { + remainingSkippedBlocks -= 1; + continue; + } if(chunk.liesInChunk(x, y, depth)) { chunk.updateBlockInGeneration(x, y, depth, blockStack.block); } diff --git a/src/server/terrain/chunkgen/TerrainGenerator.zig b/src/server/terrain/chunkgen/TerrainGenerator.zig index 14432a86..a32366cc 100644 --- a/src/server/terrain/chunkgen/TerrainGenerator.zig +++ b/src/server/terrain/chunkgen/TerrainGenerator.zig @@ -73,11 +73,32 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap while(z >= zBiome) : (z -= chunk.super.pos.voxelSize) { const mask = @as(u64, 1) << @intCast(z >> voxelSizeShift); 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; + 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}); const airBlockBelow = caveMap.findTerrainChangeBelow(x, y, z); // 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; if(z < zBiome) break; if(z > airBlockBelow) {