Skip to main content

steel_utils/random/
mod.rs

1//! This module contains utilities for random number generation.
2use enum_dispatch::enum_dispatch;
3
4use crate::random::{
5    legacy_random::{LegacyRandom, LegacyRandomSplitter},
6    name_hash::NameHash,
7    xoroshiro::{Xoroshiro, XoroshiroSplitter},
8};
9
10/// This module contains the gaussian random number generator.
11pub mod gaussian;
12/// This module contains the legacy random number generator implementation.
13pub mod legacy_random;
14/// Precomputed name hashes for positional random seeding.
15pub mod name_hash;
16/// This module contains vanilla's feature-decoration `WorldgenRandom` wrapper.
17pub mod worldgen_random;
18/// This module contains the xoroshiro random number generator.
19pub mod xoroshiro;
20
21/// A trait for random number generators.
22#[enum_dispatch]
23#[expect(missing_docs, reason = "method names are self-explanatory")]
24pub trait Random {
25    #[must_use]
26    fn fork(&mut self) -> Self;
27
28    fn next_i32(&mut self) -> i32;
29
30    fn next_i32_bounded(&mut self, bound: i32) -> i32;
31
32    fn next_i32_between(&mut self, min: i32, max: i32) -> i32 {
33        self.next_i32_bounded(max - min + 1) + min
34    }
35
36    fn next_i32_between_exclusive(&mut self, min: i32, max: i32) -> i32 {
37        min + self.next_i32_bounded(max - min)
38    }
39
40    fn next_i64(&mut self) -> i64;
41
42    fn next_f32(&mut self) -> f32;
43
44    fn next_f64(&mut self) -> f64;
45
46    fn next_bool(&mut self) -> bool;
47
48    fn next_gaussian(&mut self) -> f64;
49
50    fn triangle(&mut self, min: f64, max: f64) -> f64 {
51        min + max * (self.next_f64() - self.next_f64())
52    }
53
54    fn triangle_f32(&mut self, min: f32, max: f32) -> f32 {
55        min + max * (self.next_f32() - self.next_f32())
56    }
57
58    fn next_positional(&mut self) -> RandomSplitter;
59
60    fn consume_count(&mut self, count: i32) {
61        for _ in 0..count {
62            self.next_i32();
63        }
64    }
65}
66
67/// A trait for positional random number generators.
68#[enum_dispatch]
69#[expect(missing_docs, reason = "method names are self-explanatory")]
70pub trait PositionalRandom {
71    fn at(&self, x: i32, y: i32, z: i32) -> RandomSource;
72
73    fn with_hash_of(&self, hash: &NameHash) -> RandomSource;
74
75    fn with_seed(&self, seed: u64) -> RandomSource;
76}
77
78/// A source of random numbers.
79#[enum_dispatch(Random)]
80pub enum RandomSource {
81    /// A xoroshiro random number generator.
82    Xoroshiro(Xoroshiro),
83    /// A legacy Minecraft random number generator.
84    Legacy(LegacyRandom),
85}
86
87/// A random number generator that can be split.
88#[derive(Clone)]
89#[enum_dispatch(PositionalRandom)]
90pub enum RandomSplitter {
91    /// A xoroshiro random number generator.
92    Xoroshiro(XoroshiroSplitter),
93    /// A legacy Minecraft random number generator splitter.
94    Legacy(LegacyRandomSplitter),
95}
96
97/// Gets a seed from a position.
98#[must_use]
99pub fn get_seed(x: i32, y: i32, z: i32) -> i64 {
100    let l = i64::from(x.wrapping_mul(3_129_871))
101        ^ (i64::from(z).wrapping_mul(116_129_781_i64))
102        ^ i64::from(y);
103    let l = l
104        .wrapping_mul(l)
105        .wrapping_mul(42_317_861_i64)
106        .wrapping_add(l.wrapping_mul(11));
107    l >> 16
108}