From 7ff639bf6208635da5c4cb01cbace1c5b229eaf3 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Tue, 18 Mar 2025 21:16:20 +0100 Subject: [PATCH] Allow structures on the water surface with `.generationMode = .water_surface` fixes #841 --- src/server/terrain/StructureMap.zig | 10 +++--- src/server/terrain/biomes.zig | 9 ++--- .../terrain/chunkgen/StructureGenerator.zig | 4 +-- .../terrain/simple_structures/Boulder.zig | 6 ++-- .../terrain/simple_structures/FallenTree.zig | 8 +++-- .../terrain/simple_structures/FlowerPatch.zig | 28 +++++++++++----- .../terrain/simple_structures/GroundPatch.zig | 33 +++++++++++++------ .../simple_structures/SimpleTreeModel.zig | 6 ++-- .../simple_structures/SimpleVegetation.zig | 6 ++-- .../terrain/simple_structures/Stalagmite.zig | 6 ++-- .../structuremapgen/SimpleStructureGen.zig | 16 ++++++--- 11 files changed, 87 insertions(+), 45 deletions(-) diff --git a/src/server/terrain/StructureMap.zig b/src/server/terrain/StructureMap.zig index c4e980ef..c6c30307 100644 --- a/src/server/terrain/StructureMap.zig +++ b/src/server/terrain/StructureMap.zig @@ -14,11 +14,11 @@ const terrain = @import("terrain.zig"); const TerrainGenerationProfile = terrain.TerrainGenerationProfile; const StructureInternal = struct { - generateFn: *const fn(self: *const anyopaque, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView) void, + generateFn: *const fn(self: *const anyopaque, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView) void, data: *const anyopaque, - pub fn generate(self: StructureInternal, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView) void { - self.generateFn(self.data, chunk, caveMap); + pub fn generate(self: StructureInternal, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView) void { + self.generateFn(self.data, chunk, caveMap, biomeMap); } }; @@ -106,10 +106,10 @@ pub const StructureMapFragment = struct { } } - pub fn generateStructuresInChunk(self: *const StructureMapFragment, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView) void { + pub fn generateStructuresInChunk(self: *const StructureMapFragment, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView) void { const index = self.getIndex(chunk.super.pos.wx - self.pos.wx, chunk.super.pos.wy - self.pos.wy, chunk.super.pos.wz - self.pos.wz); for(self.data[index]) |structure| { - structure.generate(chunk, caveMap); + structure.generate(chunk, caveMap, biomeMap); } } diff --git a/src/server/terrain/biomes.zig b/src/server/terrain/biomes.zig index f39af9ff..d477d503 100644 --- a/src/server/terrain/biomes.zig +++ b/src/server/terrain/biomes.zig @@ -11,16 +11,17 @@ const Vec3f = main.vec.Vec3f; const Vec3d = main.vec.Vec3d; pub const SimpleStructureModel = struct { // MARK: SimpleStructureModel - const GenerationMode = enum { + pub const GenerationMode = enum { floor, ceiling, floor_and_ceiling, air, underground, + water_surface, }; const VTable = struct { loadModel: *const fn(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) *anyopaque, - generate: *const fn(self: *anyopaque, x: i32, y: i32, z: i32, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, isCeiling: bool) void, + generate: *const fn(self: *anyopaque, generationMode: GenerationMode, x: i32, y: i32, z: i32, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView, seed: *u64, isCeiling: bool) void, hashFunction: *const fn(self: *anyopaque) u64, generationMode: GenerationMode, }; @@ -46,8 +47,8 @@ pub const SimpleStructureModel = struct { // MARK: SimpleStructureModel }; } - pub fn generate(self: SimpleStructureModel, x: i32, y: i32, z: i32, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, isCeiling: bool) void { - self.vtable.generate(self.data, x, y, z, chunk, caveMap, seed, isCeiling); + pub fn generate(self: SimpleStructureModel, x: i32, y: i32, z: i32, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView, seed: *u64, isCeiling: bool) void { + self.vtable.generate(self.data, self.generationMode, x, y, z, chunk, caveMap, biomeMap, seed, isCeiling); } var modelRegistry: std.StringHashMapUnmanaged(VTable) = .{}; diff --git a/src/server/terrain/chunkgen/StructureGenerator.zig b/src/server/terrain/chunkgen/StructureGenerator.zig index f6391dd2..31ca4fbd 100644 --- a/src/server/terrain/chunkgen/StructureGenerator.zig +++ b/src/server/terrain/chunkgen/StructureGenerator.zig @@ -25,8 +25,8 @@ pub fn init(parameters: ZonElement) void { pub fn deinit() void {} -pub fn generate(_: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, _: CaveBiomeMap.CaveBiomeMapView) void { +pub fn generate(_: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void { const structureMap = terrain.StructureMap.getOrGenerateFragmentAndIncreaseRefCount(chunk.super.pos.wx, chunk.super.pos.wy, chunk.super.pos.wz, chunk.super.pos.voxelSize); defer structureMap.decreaseRefCount(); - structureMap.generateStructuresInChunk(chunk, caveMap); + structureMap.generateStructuresInChunk(chunk, caveMap, biomeMap); } diff --git a/src/server/terrain/simple_structures/Boulder.zig b/src/server/terrain/simple_structures/Boulder.zig index 3973e1bf..9eec11ec 100644 --- a/src/server/terrain/simple_structures/Boulder.zig +++ b/src/server/terrain/simple_structures/Boulder.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -31,7 +33,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) return self; } -pub fn generate(self: *Boulder, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, _: bool) void { +pub fn generate(self: *Boulder, _: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, _: CaveBiomeMapView, seed: *u64, _: bool) void { _ = caveMap; const radius = self.size + self.sizeVariation*(random.nextFloat(seed)*2 - 1); // My basic idea is to use a point cloud and a potential function to achieve somewhat smooth boulders without being a sphere. diff --git a/src/server/terrain/simple_structures/FallenTree.zig b/src/server/terrain/simple_structures/FallenTree.zig index 22c206b5..056f07d7 100644 --- a/src/server/terrain/simple_structures/FallenTree.zig +++ b/src/server/terrain/simple_structures/FallenTree.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -38,7 +40,7 @@ pub fn generateStump(self: *FallenTree, x: i32, y: i32, z: i32, chunk: *main.chu chunk.updateBlockIfDegradable(x, y, z, .{.typ = self.woodBlock, .data = 0}); } -pub fn generateFallen(self: *FallenTree, x: i32, y: i32, z: i32, length: u32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64) void { +pub fn generateFallen(self: *FallenTree, x: i32, y: i32, z: i32, length: u32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, seed: *u64) void { var d: ?u32 = null; const sh = caveMap.getHeightData(x, y); @@ -99,7 +101,7 @@ pub fn generateFallen(self: *FallenTree, x: i32, y: i32, z: i32, length: u32, ch } } -pub fn generate(self: *FallenTree, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, _: bool) void { +pub fn generate(self: *FallenTree, _: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, _: CaveBiomeMapView, seed: *u64, _: bool) void { const height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight); generateStump(self, x, y, z, chunk); diff --git a/src/server/terrain/simple_structures/FlowerPatch.zig b/src/server/terrain/simple_structures/FlowerPatch.zig index 7c28a4a5..f32f1696 100644 --- a/src/server/terrain/simple_structures/FlowerPatch.zig +++ b/src/server/terrain/simple_structures/FlowerPatch.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -33,7 +35,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) return self; } -pub fn generate(self: *FlowerPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, _: bool) void { +pub fn generate(self: *FlowerPatch, mode: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, caveBiomeMap: CaveBiomeMapView, seed: *u64, _: bool) void { const width = self.width + (random.nextFloat(seed) - 0.5)*self.variation; const orientation = 2*std.math.pi*random.nextFloat(seed); const ellipseParam = 1 + random.nextFloat(seed); @@ -51,10 +53,12 @@ pub fn generate(self: *FlowerPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.S const yMax = @min(chunk.super.width, y + @as(i32, @intFromFloat(@ceil(width)))); var baseHeight = z; - if(caveMap.isSolid(x, y, baseHeight)) { - baseHeight = caveMap.findTerrainChangeAbove(x, y, baseHeight) - 1; - } else { - baseHeight = caveMap.findTerrainChangeBelow(x, y, baseHeight); + if(mode != .water_surface) { + if(caveMap.isSolid(x, y, baseHeight)) { + baseHeight = caveMap.findTerrainChangeAbove(x, y, baseHeight) - 1; + } else { + baseHeight = caveMap.findTerrainChangeBelow(x, y, baseHeight); + } } var px = chunk.startIndex(xMin); @@ -68,11 +72,17 @@ pub fn generate(self: *FlowerPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.S if((1 - distSqr)*self.density < random.nextFloat(seed)) continue; var startHeight = z; - if(caveMap.isSolid(px, py, startHeight)) { - startHeight = caveMap.findTerrainChangeAbove(px, py, startHeight) - 1; + if(mode == .water_surface) { + if(caveBiomeMap.getSurfaceHeight(chunk.super.pos.wx + px, chunk.super.pos.wy + py) >= 0) continue; + startHeight = z -% 1; } else { - startHeight = caveMap.findTerrainChangeBelow(px, py, startHeight); + if(caveMap.isSolid(px, py, startHeight)) { + startHeight = caveMap.findTerrainChangeAbove(px, py, startHeight) -% 1; + } else { + startHeight = caveMap.findTerrainChangeBelow(px, py, startHeight); + } } + startHeight = chunk.startIndex(startHeight + chunk.super.pos.voxelSize); if(@abs(startHeight -% baseHeight) > 5) continue; if(chunk.liesInChunk(px, py, startHeight)) { diff --git a/src/server/terrain/simple_structures/GroundPatch.zig b/src/server/terrain/simple_structures/GroundPatch.zig index 552c5a34..66037be8 100644 --- a/src/server/terrain/simple_structures/GroundPatch.zig +++ b/src/server/terrain/simple_structures/GroundPatch.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -35,7 +37,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) return self; } -pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, _: bool) void { +pub fn generate(self: *GroundPatch, mode: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, caveBiomeMap: CaveBiomeMapView, seed: *u64, _: bool) void { const width = self.width + (random.nextFloat(seed) - 0.5)*self.variation; const orientation = 2*std.math.pi*random.nextFloat(seed); const ellipseParam = 1 + random.nextFloat(seed); @@ -53,10 +55,12 @@ pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.S const yMax = @min(chunk.super.width, y + @as(i32, @intFromFloat(@ceil(width)))); var baseHeight = z; - if(caveMap.isSolid(x, y, baseHeight)) { - baseHeight = caveMap.findTerrainChangeAbove(x, y, baseHeight) - 1; - } else { - baseHeight = caveMap.findTerrainChangeBelow(x, y, baseHeight); + if(mode != .water_surface) { + if(caveMap.isSolid(x, y, baseHeight)) { + baseHeight = caveMap.findTerrainChangeAbove(x, y, baseHeight) - 1; + } else { + baseHeight = caveMap.findTerrainChangeBelow(x, y, baseHeight); + } } var px = chunk.startIndex(xMin); @@ -69,13 +73,22 @@ pub fn generate(self: *GroundPatch, x: i32, y: i32, z: i32, chunk: *main.chunk.S if(dist <= 1) { var startHeight = z; - if(caveMap.isSolid(px, py, startHeight)) { - startHeight = caveMap.findTerrainChangeAbove(px, py, startHeight) - 1; + if(mode == .water_surface) { + startHeight -%= 1; + startHeight &= ~chunk.super.voxelSizeMask; } else { - startHeight = caveMap.findTerrainChangeBelow(px, py, startHeight); + if(caveMap.isSolid(px, py, startHeight)) { + startHeight = caveMap.findTerrainChangeAbove(px, py, startHeight) -% 1; + } else { + startHeight = caveMap.findTerrainChangeBelow(px, py, startHeight); + } + } + var pz = chunk.startIndex(startHeight - self.depth + 1); + if(mode == .water_surface) { + const surfaceHeight = caveBiomeMap.getSurfaceHeight(chunk.super.pos.wx + px, chunk.super.pos.wy + py); + pz = @max(pz, surfaceHeight -% chunk.super.pos.wz); } if(@abs(startHeight -% baseHeight) > 5) continue; - var pz = chunk.startIndex(startHeight - self.depth + 1); while(pz <= startHeight) : (pz += chunk.super.pos.voxelSize) { if(dist <= self.smoothness or (dist - self.smoothness)/(1 - self.smoothness) < random.nextFloat(seed)) { if(chunk.liesInChunk(px, py, pz)) { diff --git a/src/server/terrain/simple_structures/SimpleTreeModel.zig b/src/server/terrain/simple_structures/SimpleTreeModel.zig index 7803e9fc..3cdbf799 100644 --- a/src/server/terrain/simple_structures/SimpleTreeModel.zig +++ b/src/server/terrain/simple_structures/SimpleTreeModel.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -88,7 +90,7 @@ pub fn generateBranch(self: *SimpleTreeModel, x: i32, y: i32, z: i32, d: u32, ch } } -pub fn generate(self: *SimpleTreeModel, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, _: bool) void { +pub fn generate(self: *SimpleTreeModel, _: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, _: CaveBiomeMapView, seed: *u64, _: bool) void { const factor = random.nextFloat(seed); var height = self.height0 + @as(i32, @intFromFloat(factor*@as(f32, @floatFromInt(self.deltaHeight)))); const leafRadius = self.leafRadius + factor*self.deltaLeafRadius; diff --git a/src/server/terrain/simple_structures/SimpleVegetation.zig b/src/server/terrain/simple_structures/SimpleVegetation.zig index 5657c735..2ef4ffda 100644 --- a/src/server/terrain/simple_structures/SimpleVegetation.zig +++ b/src/server/terrain/simple_structures/SimpleVegetation.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -31,7 +33,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) return self; } -pub fn generate(self: *SimpleVegetation, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: terrain.CaveMap.CaveMapView, seed: *u64, isCeiling: bool) void { +pub fn generate(self: *SimpleVegetation, _: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, caveMap: CaveMapView, _: CaveBiomeMapView, seed: *u64, isCeiling: bool) void { if(chunk.super.pos.voxelSize > 2 and (x & chunk.super.pos.voxelSize - 1 != 0 or y & chunk.super.pos.voxelSize - 1 != 0)) return; const height = self.height0 + random.nextIntBounded(u31, seed, self.deltaHeight + 1); if(z + height >= caveMap.findTerrainChangeAbove(x, y, z)) return; // Space is too small. diff --git a/src/server/terrain/simple_structures/Stalagmite.zig b/src/server/terrain/simple_structures/Stalagmite.zig index 238396f6..8d1a0222 100644 --- a/src/server/terrain/simple_structures/Stalagmite.zig +++ b/src/server/terrain/simple_structures/Stalagmite.zig @@ -4,7 +4,9 @@ const main = @import("root"); const random = main.random; const ZonElement = main.ZonElement; const terrain = main.server.terrain; -const CaveMap = terrain.CaveMap; +const CaveBiomeMapView = terrain.CaveBiomeMap.CaveBiomeMapView; +const CaveMapView = terrain.CaveMap.CaveMapView; +const GenerationMode = terrain.biomes.SimpleStructureModel.GenerationMode; const vec = main.vec; const Vec3d = vec.Vec3d; const Vec3f = vec.Vec3f; @@ -31,7 +33,7 @@ pub fn loadModel(arenaAllocator: NeverFailingAllocator, parameters: ZonElement) return self; } -pub fn generate(self: *Stalagmite, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, _: terrain.CaveMap.CaveMapView, seed: *u64, isCeiling: bool) void { +pub fn generate(self: *Stalagmite, _: GenerationMode, x: i32, y: i32, z: i32, chunk: *main.chunk.ServerChunk, _: CaveMapView, _: CaveBiomeMapView, seed: *u64, isCeiling: bool) void { const relX: f32 = @as(f32, @floatFromInt(x)) + main.random.nextFloat(seed); const relY: f32 = @as(f32, @floatFromInt(y)) + main.random.nextFloat(seed); var relZ: f32 = @as(f32, @floatFromInt(z)) + main.random.nextFloat(seed); diff --git a/src/server/terrain/structuremapgen/SimpleStructureGen.zig b/src/server/terrain/structuremapgen/SimpleStructureGen.zig index 49239cff..dacba2ea 100644 --- a/src/server/terrain/structuremapgen/SimpleStructureGen.zig +++ b/src/server/terrain/structuremapgen/SimpleStructureGen.zig @@ -59,13 +59,17 @@ pub fn generate(map: *StructureMapFragment, worldSeed: u64) void { .seed = seed, .model = model, }; + if(model.generationMode == .water_surface) { + if(wpz != 0) break; + data.wz = 0; + } map.addStructure(.{ .internal = .{ .data = @ptrCast(data), .generateFn = &SimpleStructure.generate, }, .priority = model.priority, - }, .{px -% margin, py -% margin, relZ -% margin -% 15}, .{px +% margin, py +% margin, relZ +% margin +% 15}); + }, .{px -% margin, py -% margin, data.wz -% map.pos.wz -% margin -% 15}, .{px +% margin, py +% margin, data.wz -% map.pos.wz +% margin +% 15}); break; } else { randomValue -= model.chance; @@ -100,13 +104,14 @@ pub fn generate(map: *StructureMapFragment, worldSeed: u64) void { .seed = seed, .model = model, }; + if(model.generationMode == .water_surface) data.wz = 0; map.addStructure(.{ .internal = .{ .data = @ptrCast(data), .generateFn = &SimpleStructure.generate, }, .priority = model.priority, - }, .{px -% margin, py -% margin, relZ -% margin -% 15}, .{px +% margin, py +% margin, relZ +% margin +% 15}); + }, .{px -% margin, py -% margin, data.wz -% map.pos.wz -% margin -% 15}, .{px +% margin, py +% margin, data.wz -% map.pos.wz +% margin +% 15}); break; } else { randomValue -= adaptedChance; @@ -124,7 +129,7 @@ const SimpleStructure = struct { wy: i32, wz: i32, - pub fn generate(_self: *const anyopaque, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView) void { + pub fn generate(_self: *const anyopaque, chunk: *ServerChunk, caveMap: terrain.CaveMap.CaveMapView, biomeMap: terrain.CaveBiomeMap.CaveBiomeMapView) void { const self: *const SimpleStructure = @ptrCast(@alignCast(_self)); var seed = self.seed; const px = self.wx - chunk.super.pos.wx; @@ -174,7 +179,10 @@ const SimpleStructure = struct { relZ += -16 + random.nextIntBounded(i32, &seed, 32); if(!caveMap.isSolid(px, py, relZ)) return; }, + .water_surface => { + if(biomeMap.getSurfaceHeight(self.wx, self.wy) >= 0) return; + } } - self.model.generate(px, py, relZ, chunk, caveMap, &seed, isCeiling); + self.model.generate(px, py, relZ, chunk, caveMap, biomeMap, &seed, isCeiling); } };