chunkgen 0.2.0

Minecraft world generation library
Documentation
use serde::Deserialize;
use shulkr::world::block::BlockState;

use crate::util::rng::RandomSource;
use crate::world::worldgen::block_predicate::BlockPredicate;
use crate::world::worldgen::region::WorldGenRegion;
use shulkr::util::BlockPosition;

#[derive(Debug, Deserialize)]
pub struct BlockBlobConfig {
    pub state: BlockState,
    pub can_place_on: BlockPredicate,
}

pub fn place(
    region: &WorldGenRegion<'_>,
    random: &mut RandomSource,
    origin: BlockPosition,
    config: &BlockBlobConfig,
) -> bool {
    let mut origin = origin;
    while origin.y() > region.min_y() + 3 && !config.can_place_on.test(region, origin.below()) {
        origin = origin.below();
    }

    if origin.y() <= region.min_y() + 3 {
        return false;
    }

    for _ in 0..3 {
        let xr = random.next_i32_bounded(2);
        let yr = random.next_i32_bounded(2);
        let zr = random.next_i32_bounded(2);
        let tr = (xr + yr + zr) as f32 * 0.333 + 0.5;

        for y in origin.y() - yr..=origin.y() + yr {
            for z in origin.z() - zr..=origin.z() + zr {
                for x in origin.x() - xr..=origin.x() + xr {
                    let (dx, dy, dz) = (x - origin.x(), y - origin.y(), z - origin.z());
                    let dist_sqr = (dx * dx + dy * dy + dz * dz) as f32;
                    if dist_sqr <= tr * tr {
                        region.set_block(BlockPosition::new(x, y, z), config.state);
                    }
                }
            }
        }

        origin = BlockPosition::new(
            origin.x() - 1 + random.next_i32_bounded(2),
            origin.y() - random.next_i32_bounded(2),
            origin.z() - 1 + random.next_i32_bounded(2),
        );
    }

    true
}