Skip to content

Commit

Permalink
Merge pull request #90 from kralverde/surface_generation
Browse files Browse the repository at this point in the history
start work on noise for chunk generation
  • Loading branch information
Snowiiii authored Sep 14, 2024
2 parents e9b43fc + 56b5d85 commit 0da078a
Show file tree
Hide file tree
Showing 8 changed files with 2,094 additions and 68 deletions.
21 changes: 8 additions & 13 deletions pumpkin-core/src/random/gaussian.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
use super::Random;
use super::RandomImpl;

pub trait GaussianGenerator: Random {
fn has_next_gaussian(&self) -> bool;
pub trait GaussianGenerator: RandomImpl {
fn stored_next_gaussian(&self) -> Option<f64>;

fn set_has_next_gaussian(&mut self, value: bool);

fn stored_next_gaussian(&self) -> f64;

fn set_stored_next_gaussian(&mut self, value: f64);
fn set_stored_next_gaussian(&mut self, value: Option<f64>);

fn calculate_gaussian(&mut self) -> f64 {
if self.has_next_gaussian() {
self.set_has_next_gaussian(false);
self.stored_next_gaussian()
if let Some(gaussian) = self.stored_next_gaussian() {
self.set_stored_next_gaussian(None);
gaussian
} else {
loop {
let d = 2f64 * self.next_f64() - 1f64;
Expand All @@ -21,8 +17,7 @@ pub trait GaussianGenerator: Random {

if f < 1f64 && f != 0f64 {
let g = (-2f64 * f.ln() / f).sqrt();
self.set_stored_next_gaussian(e * g);
self.set_has_next_gaussian(true);
self.set_stored_next_gaussian(Some(e * g));
return d * g;
}
}
Expand Down
57 changes: 30 additions & 27 deletions pumpkin-core/src/random/legacy_rand.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use super::{
gaussian::GaussianGenerator, hash_block_pos, java_string_hash, Random, RandomSplitter,
gaussian::GaussianGenerator, hash_block_pos, java_string_hash, RandomDeriverImpl, RandomImpl,
};

struct LegacyRand {
pub struct LegacyRand {
seed: u64,
internal_next_gaussian: f64,
internal_has_next_gaussian: bool,
internal_next_gaussian: Option<f64>,
}

impl LegacyRand {
Expand All @@ -18,29 +17,20 @@ impl LegacyRand {
}

impl GaussianGenerator for LegacyRand {
fn has_next_gaussian(&self) -> bool {
self.internal_has_next_gaussian
}

fn stored_next_gaussian(&self) -> f64 {
fn stored_next_gaussian(&self) -> Option<f64> {
self.internal_next_gaussian
}

fn set_has_next_gaussian(&mut self, value: bool) {
self.internal_has_next_gaussian = value;
}

fn set_stored_next_gaussian(&mut self, value: f64) {
fn set_stored_next_gaussian(&mut self, value: Option<f64>) {
self.internal_next_gaussian = value;
}
}

impl Random for LegacyRand {
impl RandomImpl for LegacyRand {
fn from_seed(seed: u64) -> Self {
LegacyRand {
seed: (seed ^ 0x5DEECE66D) & 0xFFFFFFFFFFFF,
internal_has_next_gaussian: false,
internal_next_gaussian: 0f64,
internal_next_gaussian: None,
}
}

Expand Down Expand Up @@ -77,7 +67,8 @@ impl Random for LegacyRand {
self.next(1) != 0
}

fn next_splitter(&mut self) -> impl RandomSplitter {
#[allow(refining_impl_trait)]
fn next_splitter(&mut self) -> LegacySplitter {
LegacySplitter::new(self.next_i64() as u64)
}

Expand All @@ -86,21 +77,21 @@ impl Random for LegacyRand {
}

fn next_bounded_i32(&mut self, bound: i32) -> i32 {
if bound & (bound - 1) == 0 {
(bound as u64).wrapping_mul(self.next(31) >> 31) as i32
if (bound & bound.wrapping_sub(1)) == 0 {
((bound as u64).wrapping_mul(self.next(31)) >> 31) as i32
} else {
loop {
let i = self.next(31) as i32;
let j = i % bound;
if (i - j + (bound - 1)) > 0 {
if (i.wrapping_sub(j).wrapping_add(bound.wrapping_sub(1))) >= 0 {
return j;
}
}
}
}
}

struct LegacySplitter {
pub struct LegacySplitter {
seed: u64,
}

Expand All @@ -110,25 +101,26 @@ impl LegacySplitter {
}
}

impl RandomSplitter for LegacySplitter {
fn split_u64(&self, seed: u64) -> impl Random {
#[allow(refining_impl_trait)]
impl RandomDeriverImpl for LegacySplitter {
fn split_u64(&self, seed: u64) -> LegacyRand {
LegacyRand::from_seed(seed)
}

fn split_string(&self, seed: &str) -> impl Random {
fn split_string(&self, seed: &str) -> LegacyRand {
let string_hash = java_string_hash(seed);
LegacyRand::from_seed((string_hash as u64) ^ self.seed)
}

fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random {
fn split_pos(&self, x: i32, y: i32, z: i32) -> LegacyRand {
let pos_hash = hash_block_pos(x, y, z);
LegacyRand::from_seed((pos_hash as u64) ^ self.seed)
}
}

#[cfg(test)]
mod test {
use crate::random::{Random, RandomSplitter};
use crate::random::{RandomDeriverImpl, RandomImpl};

use super::LegacyRand;

Expand Down Expand Up @@ -163,6 +155,17 @@ mod test {
for value in values {
assert_eq!(rand.next_bounded_i32(0xf), value);
}

let mut rand = LegacyRand::from_seed(0);
for _ in 0..10 {
assert_eq!(rand.next_bounded_i32(1), 0);
}

let mut rand = LegacyRand::from_seed(0);
let values = [1, 1, 0, 1, 1, 0, 1, 0, 1, 1];
for value in values {
assert_eq!(rand.next_bounded_i32(2), value);
}
}

#[test]
Expand Down
155 changes: 149 additions & 6 deletions pumpkin-core/src/random/mod.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,156 @@
use legacy_rand::{LegacyRand, LegacySplitter};
use xoroshiro128::{Xoroshiro, XoroshiroSplitter};

mod gaussian;
pub mod legacy_rand;
pub mod xoroshiro128;

pub trait Random {
pub enum RandomGenerator {
Xoroshiro(Xoroshiro),
Legacy(LegacyRand),
}

impl RandomGenerator {
#[inline]
pub fn split(&mut self) -> Self {
match self {
Self::Xoroshiro(rand) => Self::Xoroshiro(rand.split()),
Self::Legacy(rand) => Self::Legacy(rand.split()),
}
}

#[inline]
pub fn next_splitter(&mut self) -> RandomDeriver {
match self {
Self::Xoroshiro(rand) => RandomDeriver::Xoroshiro(rand.next_splitter()),
Self::Legacy(rand) => RandomDeriver::Legacy(rand.next_splitter()),
}
}

#[inline]
pub fn next(&mut self, bits: u64) -> u64 {
match self {
Self::Xoroshiro(rand) => rand.next(bits),
Self::Legacy(rand) => rand.next(bits),
}
}

#[inline]
pub fn next_i32(&mut self) -> i32 {
match self {
Self::Xoroshiro(rand) => rand.next_i32(),
Self::Legacy(rand) => rand.next_i32(),
}
}

#[inline]
pub fn next_bounded_i32(&mut self, bound: i32) -> i32 {
match self {
Self::Xoroshiro(rand) => rand.next_bounded_i32(bound),
Self::Legacy(rand) => rand.next_bounded_i32(bound),
}
}

#[inline]
pub fn next_inbetween_i32(&mut self, min: i32, max: i32) -> i32 {
self.next_bounded_i32(max - min + 1) + min
}

#[inline]
pub fn next_i64(&mut self) -> i64 {
match self {
Self::Xoroshiro(rand) => rand.next_i64(),
Self::Legacy(rand) => rand.next_i64(),
}
}

#[inline]
pub fn next_bool(&mut self) -> bool {
match self {
Self::Xoroshiro(rand) => rand.next_bool(),
Self::Legacy(rand) => rand.next_bool(),
}
}

#[inline]
pub fn next_f32(&mut self) -> f32 {
match self {
Self::Xoroshiro(rand) => rand.next_f32(),
Self::Legacy(rand) => rand.next_f32(),
}
}

#[inline]
pub fn next_f64(&mut self) -> f64 {
match self {
Self::Xoroshiro(rand) => rand.next_f64(),
Self::Legacy(rand) => rand.next_f64(),
}
}

#[inline]
pub fn next_gaussian(&mut self) -> f64 {
match self {
Self::Xoroshiro(rand) => rand.next_gaussian(),
Self::Legacy(rand) => rand.next_gaussian(),
}
}

#[inline]
pub fn next_triangular(&mut self, mode: f64, deviation: f64) -> f64 {
mode + deviation * (self.next_f64() - self.next_f64())
}

#[inline]
pub fn skip(&mut self, count: i32) {
for _ in 0..count {
self.next_i64();
}
}

#[inline]
pub fn next_inbetween_i32_exclusive(&mut self, min: i32, max: i32) -> i32 {
min + self.next_bounded_i32(max - min)
}
}

pub enum RandomDeriver {
Xoroshiro(XoroshiroSplitter),
Legacy(LegacySplitter),
}

impl RandomDeriver {
#[inline]
pub fn split_string(&self, seed: &str) -> RandomGenerator {
match self {
Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_string(seed)),
Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_string(seed)),
}
}

#[inline]
pub fn split_u64(&self, seed: u64) -> RandomGenerator {
match self {
Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_u64(seed)),
Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_u64(seed)),
}
}

#[inline]
pub fn split_pos(&self, x: i32, y: i32, z: i32) -> RandomGenerator {
match self {
Self::Xoroshiro(deriver) => RandomGenerator::Xoroshiro(deriver.split_pos(x, y, z)),
Self::Legacy(deriver) => RandomGenerator::Legacy(deriver.split_pos(x, y, z)),
}
}
}

pub trait RandomImpl {
fn from_seed(seed: u64) -> Self;

fn split(&mut self) -> Self;

fn next_splitter(&mut self) -> impl RandomSplitter;
fn next_splitter(&mut self) -> impl RandomDeriverImpl;

fn next(&mut self, bits: u64) -> u64;

Expand Down Expand Up @@ -44,12 +187,12 @@ pub trait Random {
}
}

pub trait RandomSplitter {
fn split_string(&self, seed: &str) -> impl Random;
pub trait RandomDeriverImpl {
fn split_string(&self, seed: &str) -> impl RandomImpl;

fn split_u64(&self, seed: u64) -> impl Random;
fn split_u64(&self, seed: u64) -> impl RandomImpl;

fn split_pos(&self, x: i32, y: i32, z: i32) -> impl Random;
fn split_pos(&self, x: i32, y: i32, z: i32) -> impl RandomImpl;
}

fn hash_block_pos(x: i32, y: i32, z: i32) -> i64 {
Expand Down
Loading

0 comments on commit 0da078a

Please sign in to comment.