Cubyz/src/server/terrain/chunkgen/StructureGenerator.zig
IntegratedQuantum 001416dde6 Refactor the Chunk, sperating the Server-specific functionality into a new struct.
Also fixes some data races and changes the default compression so it no longer includes the (redundant) chunk position.
2024-05-17 17:28:53 +02:00

95 lines
3.7 KiB
Zig

const std = @import("std");
const main = @import("root");
const random = main.random;
const JsonElement = main.JsonElement;
const terrain = main.server.terrain;
const CaveMap = terrain.CaveMap;
const CaveBiomeMap = terrain.CaveBiomeMap;
const noise = terrain.noise;
const Biome = terrain.biomes.Biome;
const vec = main.vec;
const Vec3d = vec.Vec3d;
const Vec3f = vec.Vec3f;
const Vec3i = vec.Vec3i;
pub const id = "cubyz:vegetation";
pub const priority = 131072;
pub const generatorSeed = 0x2026b65487da9226;
pub fn init(parameters: JsonElement) void {
_ = parameters;
}
pub fn deinit() void {
}
pub fn generate(worldSeed: u64, chunk: *main.chunk.ServerChunk, caveMap: CaveMap.CaveMapView, biomeMap: CaveBiomeMap.CaveBiomeMapView) void {
if(chunk.super.pos.voxelSize < 4) {
// Uses a blue noise pattern for all structure that shouldn't touch.
const blueNoise = noise.BlueNoise.getRegionData(main.stackAllocator, chunk.super.pos.wx -% 8, chunk.super.pos.wy -% 8, chunk.super.width + 16, chunk.super.width + 16);
defer main.stackAllocator.free(blueNoise);
for(blueNoise) |coordinatePair| {
const px = @as(i32, @intCast(coordinatePair >> 16)) - 8; // TODO: Maybe add a blue-noise iterator or something like that?
const py = @as(i32, @intCast(coordinatePair & 0xffff)) - 8;
const wpx = chunk.super.pos.wx +% px;
const wpy = chunk.super.pos.wy +% py;
var pz : i32 = -32;
while(pz < chunk.super.width) : (pz += 32) {
const wpz = chunk.super.pos.wz +% pz;
var seed = random.initSeed3D(worldSeed, .{wpx, wpy, wpz});
var relZ = pz + 16;
if(caveMap.isSolid(px, py, relZ)) {
relZ = caveMap.findTerrainChangeAbove(px, py, relZ);
} else {
relZ = caveMap.findTerrainChangeBelow(px, py, relZ) + chunk.super.pos.voxelSize;
}
if(relZ < pz or relZ >= pz + 32) continue;
const biome = biomeMap.getBiome(px, py, relZ);
var randomValue = random.nextFloat(&seed);
for(biome.vegetationModels) |model| { // TODO: Could probably use an alias table here.
const adaptedChance = model.chance*16;
if(randomValue < adaptedChance) {
model.generate(px, py, relZ, chunk, caveMap, &seed);
break;
} else {
// Make sure that after the first one was considered all others get the correct chances.
randomValue = (randomValue - adaptedChance)/(1 - adaptedChance);
}
}
}
}
} else { // TODO: Make this case work with cave-structures. Low priority because caves aren't even generated this far out.
var px: i32 = 0;
while(px < chunk.super.width + 16) : (px += chunk.super.pos.voxelSize) {
var py: i32 = 0;
while(py < chunk.super.width + 16) : (py += chunk.super.pos.voxelSize) {
const wpx = px -% 8 +% chunk.super.pos.wx;
const wpy = py -% 8 +% chunk.super.pos.wy;
const relZ = @as(i32, @intFromFloat(biomeMap.getSurfaceHeight(wpx, wpy))) -% chunk.super.pos.wz;
if(relZ < -32 or relZ >= chunk.super.width + 32) continue;
var seed = random.initSeed3D(worldSeed, .{wpx, wpy, relZ});
var randomValue = random.nextFloat(&seed);
const biome = biomeMap.getBiome(px, py, relZ);
for(biome.vegetationModels) |model| { // TODO: Could probably use an alias table here.
var adaptedChance = model.chance;
// Increase chance if there are less spawn points considered. Messes up positions, but at that distance density matters more.
adaptedChance = 1 - std.math.pow(f32, 1 - adaptedChance, @as(f32, @floatFromInt(chunk.super.pos.voxelSize*chunk.super.pos.voxelSize)));
if(randomValue < adaptedChance) {
model.generate(px - 8, py - 8, relZ, chunk, caveMap, &seed);
break;
} else {
// Make sure that after the first one was considered all others get the correct chances.
randomValue = (randomValue - adaptedChance)/(1 - adaptedChance);
}
}
}
}
}
}