chunkgen 0.2.0

Minecraft world generation library
Documentation
pub mod gaussian;
pub mod legacy_random;
pub mod name_hash;
pub mod worldgen_random;
pub mod xoroshiro;

use legacy_random::{LegacyRandomFactory, LegacyRandomSource};
use name_hash::NameHash;
use shulkr::util::Direction;
use worldgen_random::WorldgenRandom;
use xoroshiro::{XoroshiroRandomFactory, XoroshiroRandomSource};

pub enum RandomSource {
    Xoroshiro(XoroshiroRandomSource),
    Legacy(LegacyRandomSource),
    Worldgen(WorldgenRandom),
}

impl RandomSource {
    pub fn fork(&mut self) -> Self {
        match self {
            Self::Xoroshiro(r) => Self::Xoroshiro(r.fork()),
            Self::Legacy(r) => Self::Legacy(r.fork()),
            Self::Worldgen(r) => Self::Xoroshiro(r.fork()),
        }
    }

    pub const fn set_seed(&mut self, seed: i64) {
        match self {
            Self::Xoroshiro(r) => r.set_seed(seed),
            Self::Legacy(r) => r.set_seed(seed),
            Self::Worldgen(r) => r.set_seed(seed),
        }
    }

    pub fn set_decoration_seed(&mut self, seed: i64, block_x: i32, block_z: i32) -> i64 {
        match self {
            Self::Worldgen(r) => r.set_decoration_seed(seed, block_x, block_z),
            _ => panic!("decoration seeds require a WorldgenRandom source"),
        }
    }

    pub const fn draw_count(&self) -> i32 {
        match self {
            Self::Worldgen(r) => r.count(),
            _ => -1,
        }
    }

    pub fn set_large_feature_seed(&mut self, seed: i64, chunk_x: i32, chunk_z: i32) {
        match self {
            Self::Legacy(r) => r.set_large_feature_seed(seed, chunk_x, chunk_z),
            Self::Worldgen(_) | Self::Xoroshiro(_) => {
                panic!("large feature seeds require a legacy random source")
            }
        }
    }

    pub fn set_feature_seed(&mut self, decoration_seed: i64, feature_index: i32, step: i32) {
        match self {
            Self::Worldgen(r) => r.set_feature_seed(decoration_seed, feature_index, step),
            _ => panic!("feature seeds require a WorldgenRandom source"),
        }
    }

    pub const fn next_i32(&mut self) -> i32 {
        match self {
            Self::Xoroshiro(r) => r.next_i32(),
            Self::Legacy(r) => r.next_i32(),
            Self::Worldgen(r) => r.next_i32(),
        }
    }

    pub fn next_horizontal_direction(&mut self) -> Direction {
        Direction::HORIZONTAL[self.next_i32_bounded(4) as usize]
    }

    pub fn next_i32_bounded(&mut self, bound: i32) -> i32 {
        match self {
            Self::Xoroshiro(r) => r.next_i32_bounded(bound),
            Self::Legacy(r) => r.next_i32_bounded(bound),
            Self::Worldgen(r) => r.next_i32_bounded(bound),
        }
    }

    pub fn next_i32_between(&mut self, min: i32, max: i32) -> i32 {
        self.next_i32_bounded(max - min + 1) + min
    }

    pub fn next_i32_between_exclusive(&mut self, min: i32, max: i32) -> i32 {
        min + self.next_i32_bounded(max - min)
    }

    pub fn next_i64(&mut self) -> i64 {
        match self {
            Self::Xoroshiro(r) => r.next_i64(),
            Self::Legacy(r) => r.next_i64(),
            Self::Worldgen(r) => r.next_i64(),
        }
    }

    pub fn next_f32(&mut self) -> f32 {
        match self {
            Self::Xoroshiro(r) => r.next_f32(),
            Self::Legacy(r) => r.next_f32(),
            Self::Worldgen(r) => r.next_f32(),
        }
    }

    pub fn next_f64(&mut self) -> f64 {
        match self {
            Self::Xoroshiro(r) => r.next_f64(),
            Self::Legacy(r) => r.next_f64(),
            Self::Worldgen(r) => r.next_f64(),
        }
    }

    pub const fn next_bool(&mut self) -> bool {
        match self {
            Self::Xoroshiro(r) => r.next_bool(),
            Self::Legacy(r) => r.next_bool(),
            Self::Worldgen(r) => r.next_bool(),
        }
    }

    pub fn next_gaussian(&mut self) -> f64 {
        match self {
            Self::Xoroshiro(r) => r.next_gaussian(),
            Self::Legacy(r) => r.next_gaussian(),
            Self::Worldgen(r) => r.next_gaussian(),
        }
    }

    pub fn triangle(&mut self, min: f64, max: f64) -> f64 {
        min + max * (self.next_f64() - self.next_f64())
    }

    pub fn triangle_f32(&mut self, min: f32, max: f32) -> f32 {
        min + max * (self.next_f32() - self.next_f32())
    }

    pub fn next_positional(&mut self) -> RandomFactory {
        match self {
            Self::Xoroshiro(r) => r.next_positional(),
            Self::Legacy(r) => r.next_positional(),
            Self::Worldgen(r) => r.next_positional(),
        }
    }

    pub fn consume_count(&mut self, count: i32) {
        match self {
            Self::Xoroshiro(r) => r.consume_count(count),
            Self::Legacy(r) => r.consume_count(count),
            Self::Worldgen(r) => r.consume_count(count),
        }
    }
}

#[derive(Clone)]
pub enum RandomFactory {
    Xoroshiro(XoroshiroRandomFactory),
    Legacy(LegacyRandomFactory),
}

impl RandomFactory {
    pub fn at(&self, x: i32, y: i32, z: i32) -> RandomSource {
        match self {
            Self::Xoroshiro(f) => f.at(x, y, z),
            Self::Legacy(f) => f.at(x, y, z),
        }
    }

    pub const fn with_hash_of(&self, hash: &NameHash) -> RandomSource {
        match self {
            Self::Xoroshiro(f) => f.with_hash_of(hash),
            Self::Legacy(f) => f.with_hash_of(hash),
        }
    }

    pub const fn with_seed(&self, seed: u64) -> RandomSource {
        match self {
            Self::Xoroshiro(f) => f.with_seed(seed),
            Self::Legacy(f) => f.with_seed(seed),
        }
    }
}

pub fn get_seed(x: i32, y: i32, z: i32) -> i64 {
    let l = i64::from(x.wrapping_mul(3_129_871))
        ^ (i64::from(z).wrapping_mul(116_129_781_i64))
        ^ i64::from(y);
    let l = l
        .wrapping_mul(l)
        .wrapping_mul(42_317_861_i64)
        .wrapping_add(l.wrapping_mul(11));
    l >> 16
}