Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions src/server/terrain/biomes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,11 @@ pub const Biome = struct { // MARK: Biome
isValidPlayerSpawn: bool,
chance: f32,
tags: []const Tag,
oceanHeight: i32,
liquidBlock: main.blocks.Block,
isOceanRelative: bool,
relativeOceanGap: u32,
relativeOceanOffset: i32,

pub fn init(self: *Biome, id: []const u8, paletteId: u32, zon: ZonElement) void {
const minRadius = zon.get(f32, "radius") orelse zon.get(f32, "minRadius") orelse 256;
Expand Down Expand Up @@ -298,6 +303,11 @@ pub const Biome = struct { // MARK: Biome
.chance = zon.get(f32, "chance") orelse if (zon == .null) 0 else 1,
.maxSubBiomeCount = zon.get(f32, "maxSubBiomeCount") orelse std.math.floatMax(f32),
.tags = Tag.loadTagsFromZon(main.worldArena, zon.getChild("tags")),
.oceanHeight = zon.get(i32, "oceanHeight") orelse 0,
.liquidBlock = blocks.parseBlock(zon.get([]const u8, "liquidBlock") orelse "cubyz:water"),
.isOceanRelative = zon.get(bool, "isOceanRelative") orelse false,
.relativeOceanGap = zon.get(u32, "relativeOceanGap") orelse 8,
.relativeOceanOffset = zon.get(i32, "relativeOceanOffset") orelse 0,
};
if (self.isCave) {
for (self.tags) |tag| {
Expand Down Expand Up @@ -390,6 +400,14 @@ pub const Biome = struct { // MARK: Biome
for (stripes.toSlice(), 0..) |elem, i| {
self.stripes[i] = Stripe.init(elem);
}
if (self.isOceanRelative and self.oceanHeight <= 0) {
std.log.err("Biome {s} has a relative ocean and an ocean height of {d}. Ocean height should be greater than 0.", .{self.id, self.oceanHeight});
}
if (self.relativeOceanGap == 0) {
std.log.err("Biome {s} cannot have relative ocean gap of 0. Setting to 1 instead.", .{self.id});
self.relativeOceanGap = 1;
}
self.relativeOceanOffset = @mod(self.relativeOceanOffset, @as(i32, @intCast(self.relativeOceanGap)));
}

fn getCheckSum(self: *Biome) u64 {
Expand Down
62 changes: 51 additions & 11 deletions src/server/terrain/chunkgen/TerrainGenerator.zig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,29 @@ pub fn init(parameters: ZonElement) void {
water = main.blocks.parseBlock("cubyz:water");
}

fn getOceanHeight(biome: *const Biome, chunk: *main.chunk.ServerChunk, airBlockBelow: i32) i32 {
if (!biome.isOceanRelative) {
return biome.oceanHeight -% chunk.super.pos.wz;
}
const snapped: i32 = @divFloor(airBlockBelow +% chunk.super.pos.wz, @as(i32, @intCast(biome.relativeOceanGap)))*@as(i32, @intCast(biome.relativeOceanGap)) -% chunk.super.pos.wz;
if (snapped + biome.relativeOceanOffset > airBlockBelow) {
return snapped -% @as(i32, @intCast(biome.relativeOceanGap)) +% @as(i32, @intCast(biome.relativeOceanOffset)) +% biome.oceanHeight;
}
return snapped + biome.relativeOceanOffset +% biome.oceanHeight;
}

fn isOceanEdge(chunk: *main.chunk.ServerChunk, relPos: Vec3i, biome: *const Biome, biomeOceanHeight: i32, biomeMap: CaveBiomeMap.CaveBiomeMapView, caveMap: CaveMap.CaveMapView) bool {
const neighborAirBlockBelow = caveMap.findTerrainChangeBelow(relPos[0], relPos[1], relPos[2]) + chunk.super.pos.voxelSize;
const neighborBiome = if (neighborAirBlockBelow -% 1 >= -32) biomeMap.getBiome(relPos[0], relPos[1], neighborAirBlockBelow -% 1) else biomeMap.getBiome(relPos[0], relPos[1], relPos[2]);
const liquidMatches = biome.liquidBlock == neighborBiome.liquidBlock;
const neighborOceanHeight = getOceanHeight(neighborBiome, chunk, neighborAirBlockBelow);
const neighborValidDepth = neighborOceanHeight -% neighborAirBlockBelow <= neighborBiome.oceanHeight;
if (!liquidMatches or neighborOceanHeight != biomeOceanHeight or (biome.isOceanRelative and neighborBiome.isOceanRelative and !neighborValidDepth)) {
return true;
}
return false;
}

pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
if (chunk.super.pos.voxelSize >= 8) {
var maxHeight: i32 = 0;
Expand Down Expand Up @@ -67,15 +90,14 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap
defer zBiome = chunk.startIndex(zBiome + biomeHeight - 1 + chunk.super.pos.voxelSize);
var z: i32 = @min(chunk.super.width - chunk.super.pos.voxelSize, chunk.startIndex(zBiome + biomeHeight - 1));
while (z >= zBiome) : (z -= chunk.super.pos.voxelSize) {
const cardinalDirections = [_]Vec3i{
Vec3i{1, 0, 0},
Vec3i{-1, 0, 0},
Vec3i{0, 1, 0},
Vec3i{0, -1, 0},
};
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;
Expand Down Expand Up @@ -142,17 +164,35 @@ pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap
}
} else {
const surface = biomeMap.getSurfaceHeight(x + chunk.super.pos.wx, y + chunk.super.pos.wy) - (chunk.super.pos.voxelSize - 1) -% chunk.super.pos.wz;
const oceanHeight = 0 -% chunk.super.pos.wz;
const airVolumeStart = caveMap.findTerrainChangeBelow(x, y, z) + chunk.super.pos.voxelSize;
const zStart = @max(airVolumeStart, zBiome);
if (z < surface or zStart >= oceanHeight) {
var airBlockBelow = surface;
if (biome.isOceanRelative) {
airBlockBelow = airVolumeStart;
}
const oceanHeight = getOceanHeight(biome, chunk, airBlockBelow);
const oceanSurfaceDifference = oceanHeight -% airBlockBelow;
if (z < airBlockBelow or zStart >= oceanHeight or (biome.isOceanRelative and oceanSurfaceDifference > biome.oceanHeight)) {
chunk.updateBlockColumnInGeneration(x, y, zStart, z, .{.typ = 0, .data = 0});
} else {
if (z >= oceanHeight) {
chunk.updateBlockColumnInGeneration(x, y, oceanHeight, z, .{.typ = 0, .data = 0});
z = oceanHeight - chunk.super.pos.voxelSize;
z = oceanHeight -% chunk.super.pos.voxelSize;
}
var blockToPlace = biome.liquidBlock;
for (cardinalDirections) |cardinalDirection| {
const neighborCoords = Vec3i{x, y, z} + cardinalDirection;
if (isOceanEdge(chunk, neighborCoords, biome, oceanHeight, biomeMap, caveMap)) {
blockToPlace = biome.stoneBlock;
var bseed: u64 = random.initSeed3D(worldSeed, .{chunk.super.pos.wx + x, chunk.super.pos.wy + y, chunk.super.pos.wz + z});
z = @min(z + chunk.super.pos.voxelSize, biome.structure.addSubTerranian(chunk, oceanHeight -% 1, @max(airBlockBelow, zBiome - 1), 0, 1, x, y, &bseed));
z -= chunk.super.pos.voxelSize;
break;
}
}
if (zStart <= z) {
chunk.updateBlockColumnInGeneration(x, y, zStart, z, blockToPlace);
}
chunk.updateBlockColumnInGeneration(x, y, zStart, z, water);
}
z = zStart;
}
Expand Down
6 changes: 3 additions & 3 deletions src/server/terrain/structuremapgen/SimpleStructureGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,8 @@ pub fn generate(map: *StructureMapFragment, worldSeed: u64) void {
.isCeiling = heightFinalized.isCeiling,
};
if (model.generationMode == .water_surface) {
if (wpz != 0) break;
data.wz = 0;
if (wpz != 0 or biome.isOceanRelative) break;
data.wz = biome.oceanHeight;
}
map.addStructure(.{
.internal = .{
Expand Down Expand Up @@ -170,7 +170,7 @@ pub fn generate(map: *StructureMapFragment, worldSeed: u64) void {
.model = model,
.isCeiling = heightFinalized.isCeiling,
};
if (model.generationMode == .water_surface) data.wz = 0;
if (model.generationMode == .water_surface and biome.isOceanRelative) data.wz = biome.oceanHeight;
map.addStructure(.{
.internal = .{
.data = data,
Expand Down
Loading