chunkgen 0.2.0

Minecraft world generation library
Documentation
use serde::Deserialize;

use crate::util::rng::RandomSource;
use crate::util::value_providers::int::IntProvider;
use crate::world::worldgen::feature::features::HORIZONTAL_DIRECTIONS;
use crate::world::worldgen::feature::features::tree::{TreeConfig, valid_tree_pos};
use crate::world::worldgen::feature::foliageplacers::FoliageAttachment;
use crate::world::worldgen::region::WorldGenRegion;
use shulkr::util::BlockPosition;
use shulkr::world::block::BlockState;

#[derive(Debug, Deserialize)]
pub struct BendingTrunkPlacer {
    pub base_height: i32,
    pub height_rand_a: i32,
    pub height_rand_b: i32,
    #[serde(default = "default_min_height_for_leaves")]
    pub min_height_for_leaves: i32,
    pub bend_length: IntProvider,
}

const fn default_min_height_for_leaves() -> i32 {
    1
}

impl BendingTrunkPlacer {
    #[expect(
        clippy::too_many_arguments,
        reason = "mirrors vanilla BendingTrunkPlacer.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> {
        let direction = HORIZONTAL_DIRECTIONS[random.next_i32_bounded(4) as usize];
        let log_height = tree_height - 1;
        let mut pos = origin;
        super::place_below_trunk_block(region, trunk_setter, random, origin.below(), config);
        let mut foliage_points = Vec::new();

        for i in 0..=log_height {
            if i + 1 >= log_height + random.next_i32_bounded(2) {
                pos = pos.offset(direction.offset().0, 0, direction.offset().2);
            }

            if valid_tree_pos(region, pos) {
                placer.place_log(region, trunk_setter, random, pos, config);
            }

            if i >= self.min_height_for_leaves {
                foliage_points.push(FoliageAttachment {
                    pos,
                    radius_offset: 0,
                    double_trunk: false,
                });
            }

            pos = pos.above();
        }

        let dir_length = self.bend_length.sample(random);
        for _ in 0..=dir_length {
            if valid_tree_pos(region, pos) {
                placer.place_log(region, trunk_setter, random, pos, config);
            }

            foliage_points.push(FoliageAttachment {
                pos,
                radius_offset: 0,
                double_trunk: false,
            });
            pos = pos.offset(direction.offset().0, 0, direction.offset().2);
        }

        foliage_points
    }
}