chunkgen 0.2.0

Minecraft world generation library
Documentation
use crate::registry::biome::BiomeRef;
use crate::world::worldgen::biome::climate::{Sampler, TargetPoint};
use crate::world::worldgen::densityfunction::context::SamplerContext;
use crate::world::worldgen::densityfunction::volume::DensityVolume;
use crate::world::worldgen::random_state::RandomState;

use super::{BiomeSource, distinct_biome_refs};

struct ChunkClimate {
    volume: DensityVolume,
    min_quart: [i32; 3],
    temperature: Vec<f32>,
    vegetation: Vec<f32>,
    continents: Vec<f32>,
    erosion: Vec<f32>,
    depth: Vec<f32>,
    ridges: Vec<f32>,
}

pub struct BiomeResolver<'a> {
    source: &'a BiomeSource,
    sampler: Sampler,
    chunk: Option<ChunkClimate>,
    last_result: Option<usize>,
}

impl BiomeSource {
    pub const fn create_resolver(&self, sampler: Sampler) -> BiomeResolver<'_> {
        BiomeResolver {
            source: self,
            sampler,
            chunk: None,
            last_result: None,
        }
    }

    pub fn create_uncached_resolver(&self, random_state: &RandomState) -> BiomeResolver<'_> {
        self.create_resolver(random_state.create_climate_sampler(SamplerContext::uncached()))
    }

    pub fn create_caching_resolver(&self, random_state: &RandomState) -> BiomeResolver<'_> {
        self.create_resolver(random_state.create_climate_sampler(SamplerContext::cached()))
    }

    pub fn create_resolver_for_chunk(
        &self,
        sampler: Sampler,
        min_quart: [i32; 3],
        quart_size: [i32; 3],
    ) -> BiomeResolver<'_> {
        if !self.is_multi_noise() {
            return self.create_resolver(sampler);
        }
        let volume = DensityVolume::stepped(quart_size, min_quart.map(|q| q << 2), [4, 4, 4]);
        let temperature = sampler.sample_volume(&sampler.temperature, &volume);
        let vegetation = sampler.sample_volume(&sampler.humidity, &volume);
        let continents = sampler.sample_volume(&sampler.continentalness, &volume);
        let erosion = sampler.sample_volume(&sampler.erosion, &volume);
        let depth = sampler.sample_volume(&sampler.depth, &volume);
        let ridges = sampler.sample_volume(&sampler.weirdness, &volume);
        BiomeResolver {
            source: self,
            sampler,
            chunk: Some(ChunkClimate {
                volume,
                min_quart,
                temperature,
                vegetation,
                continents,
                erosion,
                depth,
                ridges,
            }),
            last_result: None,
        }
    }
}

impl BiomeResolver<'_> {
    pub fn get_noise_biome(&mut self, quart_x: i32, quart_y: i32, quart_z: i32) -> BiomeRef {
        if let Some(chunk) = &self.chunk {
            let index = chunk.volume.index_unchecked(
                quart_x - chunk.min_quart[0],
                quart_y - chunk.min_quart[1],
                quart_z - chunk.min_quart[2],
            );
            let target = TargetPoint::from_floats(
                f64::from(chunk.temperature[index]),
                f64::from(chunk.vegetation[index]),
                f64::from(chunk.continents[index]),
                f64::from(chunk.erosion[index]),
                f64::from(chunk.depth[index]),
                f64::from(chunk.ridges[index]),
            );
            return self
                .source
                .multi_noise_biome(&target, &mut self.last_result);
        }
        self.source.get_noise_biome(
            &self.sampler,
            &mut self.last_result,
            quart_x,
            quart_y,
            quart_z,
        )
    }

    pub fn get_biomes_within(&mut self, x: i32, y: i32, z: i32, radius: i32) -> Vec<BiomeRef> {
        let x0 = (x - radius) >> 2;
        let y0 = (y - radius) >> 2;
        let z0 = (z - radius) >> 2;
        let x1 = (x + radius) >> 2;
        let y1 = (y + radius) >> 2;
        let z1 = (z + radius) >> 2;
        let mut biomes = Vec::new();
        for noise_z in z0..=z1 {
            for noise_x in x0..=x1 {
                for noise_y in y0..=y1 {
                    biomes.push(self.get_noise_biome(noise_x, noise_y, noise_z));
                }
            }
        }
        distinct_biome_refs(biomes)
    }
}