chunkgen 0.2.0

Minecraft world generation library
Documentation
use serde::Deserialize;

use crate::util::rng::RandomSource;
use crate::util::shuffle;
use crate::util::value_providers::int::IntProvider;
use crate::world::worldgen::feature::features::tree::TreeConfig;
use crate::world::worldgen::feature::foliageplacers::FoliageAttachment;
use crate::world::worldgen::region::WorldGenRegion;
use shulkr::util::BlockPosition;
use shulkr::util::Direction;
use shulkr::world::block::BlockState;

#[derive(Debug, Deserialize)]
pub struct PoplarTrunkPlacer {
    pub base_height: i32,
    pub height_rand_a: i32,
    pub height_rand_b: i32,
    pub trunk_height_above_branches: IntProvider,
    pub branch_amount: IntProvider,
}

impl PoplarTrunkPlacer {
    #[expect(
        clippy::too_many_arguments,
        reason = "mirrors vanilla PoplarTrunkPlacer.placeTrunk"
    )]
    pub fn place_trunk(
        &self,
        placer: &super::TrunkPlacer,
        region: &WorldGenRegion<'_>,
        trunk_setter: &mut dyn FnMut(BlockPosition, BlockState),
        random: &mut RandomSource,
        tree_height: i32,
        origin: BlockPosition,
        config: &TreeConfig,
    ) -> Vec<FoliageAttachment> {
        super::place_below_trunk_block(region, trunk_setter, random, origin.below(), config);
        let trunk_height_up_to_foliage_branches =
            tree_height - self.trunk_height_above_branches.sample(random);

        for y in 0..tree_height {
            placer.place_log(region, trunk_setter, random, origin.above_n(y), config);
            let directions = shuffled_branch_directions(random);
            if trunk_height_up_to_foliage_branches - 1 == y {
                let branches = self.branch_amount.sample(random);
                for &branch_direction in directions.iter().take(branches as usize) {
                    let axis = branch_direction.get_axis();
                    placer.place_log_with(
                        region,
                        trunk_setter,
                        random,
                        origin.above_n(y).relative(branch_direction),
                        config,
                        |state| super::set_axis(state, axis),
                    );
                }
            }
        }

        vec![FoliageAttachment {
            pos: origin.above_n(trunk_height_up_to_foliage_branches),
            radius_offset: 0,
            double_trunk: false,
        }]
    }
}

fn shuffled_branch_directions(random: &mut RandomSource) -> Vec<Direction> {
    let mut directions = Direction::ALL;
    shuffle(&mut directions, random);
    directions
        .into_iter()
        .filter(|direction| !direction.get_axis().is_vertical())
        .collect()
}