From 393ac4610cdfa0b04d4bbdbf20a07fce8a87b25e Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 18:46:28 +0200 Subject: [PATCH 01/11] Improved worldgen seed expansion --- world/src/sim/mod.rs | 72 ++++++++++------------------------ world/src/util/mod.rs | 1 + world/src/util/seed_expan.rs | 76 ++++++++++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 52 deletions(-) create mode 100644 world/src/util/seed_expan.rs diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index c02a1385b9..0b1b573249 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -7,7 +7,7 @@ pub use self::settlement::Settlement; use crate::{ all::ForestKind, - util::{Sampler, StructureGen2d}, + util::{seed_expan, Sampler, StructureGen2d}, CONFIG, }; use common::{ @@ -55,31 +55,32 @@ pub struct WorldSim { impl WorldSim { pub fn generate(seed: u32) -> Self { + let seeds = seed_expan::diffused_field(seed, 17); let mut gen_ctx = GenCtx { - turb_x_nz: SuperSimplex::new().set_seed(seed + 0), - turb_y_nz: SuperSimplex::new().set_seed(seed + 1), - chaos_nz: RidgedMulti::new().set_octaves(7).set_seed(seed + 2), - hill_nz: SuperSimplex::new().set_seed(seed + 3), + turb_x_nz: SuperSimplex::new().set_seed(seeds[0]), + turb_y_nz: SuperSimplex::new().set_seed(seeds[1]), + chaos_nz: RidgedMulti::new().set_octaves(7).set_seed(seeds[2]), + hill_nz: SuperSimplex::new().set_seed(seeds[3]), alt_nz: HybridMulti::new() .set_octaves(8) .set_persistence(0.1) - .set_seed(seed + 4), - temp_nz: SuperSimplex::new().set_seed(seed + 5), - dry_nz: BasicMulti::new().set_seed(seed + 6), - small_nz: BasicMulti::new().set_octaves(2).set_seed(seed + 7), - rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(seed + 8), - cliff_nz: HybridMulti::new().set_persistence(0.3).set_seed(seed + 9), - warp_nz: BasicMulti::new().set_octaves(3).set_seed(seed + 10), + .set_seed(seeds[4]), + temp_nz: SuperSimplex::new().set_seed(seeds[5]), + dry_nz: BasicMulti::new().set_seed(seeds[6]), + small_nz: BasicMulti::new().set_octaves(2).set_seed(seeds[7]), + rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(seeds[8]), + cliff_nz: HybridMulti::new().set_persistence(0.3).set_seed(seeds[9]), + warp_nz: BasicMulti::new().set_octaves(3).set_seed(seeds[10]), tree_nz: BasicMulti::new() .set_octaves(12) .set_persistence(0.75) - .set_seed(seed + 12), - cave_0_nz: SuperSimplex::new().set_seed(seed + 13), - cave_1_nz: SuperSimplex::new().set_seed(seed + 14), + .set_seed(seeds[11]), + cave_0_nz: SuperSimplex::new().set_seed(seeds[12]), + cave_1_nz: SuperSimplex::new().set_seed(seeds[13]), - structure_gen: StructureGen2d::new(seed, 32, 24), - region_gen: StructureGen2d::new(seed + 1, 400, 96), - cliff_gen: StructureGen2d::new(seed + 2, 80, 56), + structure_gen: StructureGen2d::new(seeds[14], 32, 24), + region_gen: StructureGen2d::new(seeds[15], 400, 96), + cliff_gen: StructureGen2d::new(seeds[17], 80, 56), }; let mut chunks = Vec::new(); @@ -94,40 +95,7 @@ impl WorldSim { chunks, locations: Vec::new(), gen_ctx, - rng: ChaChaRng::from_seed([ - (seed >> 0) as u8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - (seed >> 8) as u8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - (seed >> 16) as u8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - (seed >> 24) as u8, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ]), + rng: ChaChaRng::from_seed(seed_expan::expand_seed_to_rng(seed)), }; this.seed_elements(); diff --git a/world/src/util/mod.rs b/world/src/util/mod.rs index a8a71d0c03..f0a44c87c8 100644 --- a/world/src/util/mod.rs +++ b/world/src/util/mod.rs @@ -1,6 +1,7 @@ pub mod hash_cache; pub mod random; pub mod sampler; +pub mod seed_expan; pub mod structure; pub mod unit_chooser; diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs new file mode 100644 index 0000000000..d9070d6930 --- /dev/null +++ b/world/src/util/seed_expan.rs @@ -0,0 +1,76 @@ +static SBOX: [u8; 256] = [ + 206, 21, 212, 69, 54, 234, 13, 42, 184, 48, 92, 64, 196, 55, 225, 235, 229, 120, 135, 72, 32, + 147, 74, 142, 197, 79, 139, 164, 110, 57, 176, 47, 192, 174, 178, 49, 193, 71, 78, 18, 237, 81, + 255, 187, 5, 246, 247, 109, 26, 44, 93, 230, 96, 102, 204, 31, 100, 175, 182, 245, 9, 0, 127, + 161, 125, 52, 129, 179, 209, 130, 219, 77, 218, 252, 61, 75, 62, 248, 124, 220, 98, 87, 63, + 163, 101, 40, 29, 4, 36, 123, 23, 238, 134, 35, 17, 169, 226, 19, 2, 253, 158, 172, 37, 104, + 183, 194, 43, 167, 59, 215, 162, 88, 140, 25, 133, 221, 132, 159, 232, 250, 154, 10, 211, 112, + 146, 189, 141, 95, 1, 111, 28, 160, 73, 181, 67, 30, 190, 157, 148, 149, 11, 8, 41, 217, 106, + 39, 214, 152, 180, 168, 14, 56, 70, 34, 137, 243, 45, 195, 94, 38, 7, 116, 16, 136, 82, 114, + 186, 105, 15, 223, 200, 131, 85, 20, 128, 210, 97, 233, 151, 241, 138, 6, 60, 24, 249, 12, 207, + 239, 171, 65, 113, 115, 22, 107, 68, 143, 90, 119, 185, 153, 166, 46, 155, 191, 254, 58, 150, + 251, 99, 213, 118, 240, 122, 108, 231, 126, 177, 80, 227, 91, 145, 203, 228, 198, 236, 53, 50, + 51, 76, 242, 103, 117, 170, 173, 121, 188, 27, 244, 205, 224, 144, 3, 89, 84, 66, 202, 83, 156, + 216, 33, 165, 86, 222, 199, 208, 201, +]; + +fn sbox(x: u64) -> u64 { + let mut bytes = x.to_ne_bytes(); + for byte in &mut bytes { + *byte = SBOX[*byte as usize]; + } + u64::from_ne_bytes(bytes) +} + +// chaotic bijective function +fn diffuse_rnd(mut x: u64) -> u64 { + x = x.wrapping_mul(0x6eed0e9da4d94a4f); + let a = x >> 32; + let b = x >> 60; + x ^= a >> b; + x = x.wrapping_mul(0x6eed0e9da4d94a4f); + sbox(x) +} + +fn diffuse(mut x: u64) -> u64 { + for _ in 0..4 { + x = diffuse_rnd(x); + } + x +} + +fn initial_expand(x: u32) -> u64 { + (x as u64).wrapping_mul(0x2f72b4215a3d8caf).pow(2) +} + +fn truncate(x: u64) -> u32 { + let xb = x.to_ne_bytes(); + let nb = [ + xb[0].wrapping_mul(xb[1]), + xb[2].wrapping_mul(xb[3]), + xb[4].wrapping_mul(xb[5]), + xb[6].wrapping_mul(xb[7]), + ]; + u32::from_ne_bytes(nb) +} + +pub fn diffused_field(seed: u32, amount: u32) -> Vec { + let mut field = Vec::new(); + for i in 0..amount { + let n = truncate(diffuse(initial_expand(seed + i))); + field.push(n); + } + field +} + +pub fn expand_seed_to_rng(seed: u32) -> [u8; 32] { + let mut r: [u64; 4] = [0; 4]; + let mut state: u64 = initial_expand(seed); + + for i in 0..4 { + state = diffuse(state); + r[i] = state; + } + + unsafe { std::mem::transmute(r) } +} From 8cb48804c2421d92b84e7d1662af270368314a9b Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 18:49:02 +0200 Subject: [PATCH 02/11] Fixed diffuse_field --- world/src/util/seed_expan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index d9070d6930..5a6e47f489 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -56,7 +56,7 @@ fn truncate(x: u64) -> u32 { pub fn diffused_field(seed: u32, amount: u32) -> Vec { let mut field = Vec::new(); - for i in 0..amount { + for i in 0..=amount { let n = truncate(diffuse(initial_expand(seed + i))); field.push(n); } From fea6b2e776ad87c0372ee881daa172b186d4e60d Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 19:41:31 +0200 Subject: [PATCH 03/11] Fixed overflow in seed_expan --- world/src/util/seed_expan.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index 5a6e47f489..ced0437137 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -40,7 +40,8 @@ fn diffuse(mut x: u64) -> u64 { } fn initial_expand(x: u32) -> u64 { - (x as u64).wrapping_mul(0x2f72b4215a3d8caf).pow(2) + let f = (x as u64).wrapping_mul(0x2f72b4215a3d8caf); + f.wrapping_mul(f) } fn truncate(x: u64) -> u32 { From 1c22f380b014d1c70dfa535fd1dbdbcb9930eef6 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 20:32:22 +0200 Subject: [PATCH 04/11] Adjusted default spawn height for now --- server/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/lib.rs b/server/src/lib.rs index 5b16e6d0ec..f5006897c3 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -89,7 +89,7 @@ impl Server { let mut state = State::default(); state .ecs_mut() - .add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 380.0))); + .add_resource(SpawnPoint(Vec3::new(16_384.0, 16_384.0, 512.0))); state.ecs_mut().add_resource(EventBus::default()); // Set starting time for the server. From dcc19e2d04c15229c7543256ffd6673d26eddc80 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 21:04:03 +0200 Subject: [PATCH 05/11] Added a lot of comments. --- world/src/util/seed_expan.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index ced0437137..4a82c962f1 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -1,3 +1,7 @@ +// This module contains a few functions and utilities for expanding a seed into more data for use in worldgen. + +// Very standard substitution box. Takes one number and gives back another. This one works per byte. +// Standard component in diffusion functions. static SBOX: [u8; 256] = [ 206, 21, 212, 69, 54, 234, 13, 42, 184, 48, 92, 64, 196, 55, 225, 235, 229, 120, 135, 72, 32, 147, 74, 142, 197, 79, 139, 164, 110, 57, 176, 47, 192, 174, 178, 49, 193, 71, 78, 18, 237, 81, @@ -14,6 +18,7 @@ static SBOX: [u8; 256] = [ 216, 33, 165, 86, 222, 199, 208, 201, ]; +// Helper function to work with the box above. Takes a u64 and runs each byte through the box. fn sbox(x: u64) -> u64 { let mut bytes = x.to_ne_bytes(); for byte in &mut bytes { @@ -22,7 +27,8 @@ fn sbox(x: u64) -> u64 { u64::from_ne_bytes(bytes) } -// chaotic bijective function +// A bijective diffusion function with chaotic behaviour. It essentially mixes numbers. +// A 1 bit change somewhere will affect a large portion of the other bits after running through this function. fn diffuse_rnd(mut x: u64) -> u64 { x = x.wrapping_mul(0x6eed0e9da4d94a4f); let a = x >> 32; @@ -32,6 +38,7 @@ fn diffuse_rnd(mut x: u64) -> u64 { sbox(x) } +// Helper for running diffuse_rnd 4 times, enough to mix the bits around properly. fn diffuse(mut x: u64) -> u64 { for _ in 0..4 { x = diffuse_rnd(x); @@ -39,11 +46,13 @@ fn diffuse(mut x: u64) -> u64 { x } +// Expands a 32 bit state into at 64 bit state. fn initial_expand(x: u32) -> u64 { let f = (x as u64).wrapping_mul(0x2f72b4215a3d8caf); f.wrapping_mul(f) } +// Truncate a 64 bit state to a 32 bit seed. fn truncate(x: u64) -> u32 { let xb = x.to_ne_bytes(); let nb = [ @@ -55,6 +64,8 @@ fn truncate(x: u64) -> u32 { u32::from_ne_bytes(nb) } +// Generates a sequence of diffused (mixed) numbers from one seed. +// Used for generating a lot of initial seeds for the noise algorithms in worldgen. pub fn diffused_field(seed: u32, amount: u32) -> Vec { let mut field = Vec::new(); for i in 0..=amount { @@ -64,14 +75,20 @@ pub fn diffused_field(seed: u32, amount: u32) -> Vec { field } +// Expand a 32 bit seed into a 32 byte state for the RNG used in worldgen. pub fn expand_seed_to_rng(seed: u32) -> [u8; 32] { + // Create a new empty ChaChaRng state. let mut r: [u64; 4] = [0; 4]; + + // Create a new empty internal state. let mut state: u64 = initial_expand(seed); + // Fill the ChaChaRng state with random bits from repeatedly running mixing the state. for i in 0..4 { state = diffuse(state); r[i] = state; } + // Convert the ChaChaRng state to bytes. Uses unsafe here because the safe code for it would be much longer. unsafe { std::mem::transmute(r) } } From 5eee2622cb9492d45513834cef987f3e6b9c96cd Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 21:06:32 +0200 Subject: [PATCH 06/11] Fixed comment typo. --- world/src/util/seed_expan.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index 4a82c962f1..07e57d9343 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -46,7 +46,7 @@ fn diffuse(mut x: u64) -> u64 { x } -// Expands a 32 bit state into at 64 bit state. +// Expands a 32 bit state into a 64 bit state. fn initial_expand(x: u32) -> u64 { let f = (x as u64).wrapping_mul(0x2f72b4215a3d8caf); f.wrapping_mul(f) From d840ca72e35bbac6270742d85ce81bc5e16636ee Mon Sep 17 00:00:00 2001 From: Acrimon Date: Mon, 5 Aug 2019 21:18:00 +0200 Subject: [PATCH 07/11] Improved some comments. --- world/src/util/seed_expan.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index 07e57d9343..21905c8dff 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -1,7 +1,8 @@ // This module contains a few functions and utilities for expanding a seed into more data for use in worldgen. // Very standard substitution box. Takes one number and gives back another. This one works per byte. -// Standard component in diffusion functions. +// Standard component in diffusion functions. The numbers here are totally random and could be whatever. +// Onlu rule is each index has to match an unique number. static SBOX: [u8; 256] = [ 206, 21, 212, 69, 54, 234, 13, 42, 184, 48, 92, 64, 196, 55, 225, 235, 229, 120, 135, 72, 32, 147, 74, 142, 197, 79, 139, 164, 110, 57, 176, 47, 192, 174, 178, 49, 193, 71, 78, 18, 237, 81, @@ -83,7 +84,7 @@ pub fn expand_seed_to_rng(seed: u32) -> [u8; 32] { // Create a new empty internal state. let mut state: u64 = initial_expand(seed); - // Fill the ChaChaRng state with random bits from repeatedly running mixing the state. + // Fill the ChaChaRng state with random bits from repeatedly mixing the state. for i in 0..4 { state = diffuse(state); r[i] = state; From 00b5a4a58edc55241f0e883cd4625493261cd264 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Tue, 6 Aug 2019 02:03:51 +0200 Subject: [PATCH 08/11] Greatly simplified seed expansion. --- world/src/sim/mod.rs | 47 +++++++++------- world/src/util/seed_expan.rs | 103 ++++------------------------------- 2 files changed, 40 insertions(+), 110 deletions(-) diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 0b1b573249..098c3faaf3 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -55,32 +55,41 @@ pub struct WorldSim { impl WorldSim { pub fn generate(seed: u32) -> Self { - let seeds = seed_expan::diffused_field(seed, 17); let mut gen_ctx = GenCtx { - turb_x_nz: SuperSimplex::new().set_seed(seeds[0]), - turb_y_nz: SuperSimplex::new().set_seed(seeds[1]), - chaos_nz: RidgedMulti::new().set_octaves(7).set_seed(seeds[2]), - hill_nz: SuperSimplex::new().set_seed(seeds[3]), + turb_x_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed)), + turb_y_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 1)), + chaos_nz: RidgedMulti::new() + .set_octaves(7) + .set_seed(seed_expan::diffuse(seed + 2)), + hill_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 3)), alt_nz: HybridMulti::new() .set_octaves(8) .set_persistence(0.1) - .set_seed(seeds[4]), - temp_nz: SuperSimplex::new().set_seed(seeds[5]), - dry_nz: BasicMulti::new().set_seed(seeds[6]), - small_nz: BasicMulti::new().set_octaves(2).set_seed(seeds[7]), - rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(seeds[8]), - cliff_nz: HybridMulti::new().set_persistence(0.3).set_seed(seeds[9]), - warp_nz: BasicMulti::new().set_octaves(3).set_seed(seeds[10]), + .set_seed(seed_expan::diffuse(seed + 4)), + temp_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 5)), + dry_nz: BasicMulti::new().set_seed(seed_expan::diffuse(seed + 6)), + small_nz: BasicMulti::new() + .set_octaves(2) + .set_seed(seed_expan::diffuse(seed + 7)), + rock_nz: HybridMulti::new() + .set_persistence(0.3) + .set_seed(seed_expan::diffuse(seed + 8)), + cliff_nz: HybridMulti::new() + .set_persistence(0.3) + .set_seed(seed_expan::diffuse(seed + 9)), + warp_nz: BasicMulti::new() + .set_octaves(3) + .set_seed(seed_expan::diffuse(seed + 10)), tree_nz: BasicMulti::new() .set_octaves(12) .set_persistence(0.75) - .set_seed(seeds[11]), - cave_0_nz: SuperSimplex::new().set_seed(seeds[12]), - cave_1_nz: SuperSimplex::new().set_seed(seeds[13]), + .set_seed(seed_expan::diffuse(seed + 11)), + cave_0_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 12)), + cave_1_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 13)), - structure_gen: StructureGen2d::new(seeds[14], 32, 24), - region_gen: StructureGen2d::new(seeds[15], 400, 96), - cliff_gen: StructureGen2d::new(seeds[17], 80, 56), + structure_gen: StructureGen2d::new(seed_expan::diffuse(seed + 14), 32, 24), + region_gen: StructureGen2d::new(seed_expan::diffuse(seed + 15), 400, 96), + cliff_gen: StructureGen2d::new(seed_expan::diffuse(seed + 16), 80, 56), }; let mut chunks = Vec::new(); @@ -95,7 +104,7 @@ impl WorldSim { chunks, locations: Vec::new(), gen_ctx, - rng: ChaChaRng::from_seed(seed_expan::expand_seed_to_rng(seed)), + rng: ChaChaRng::from_seed(seed_expan::rng_state(seed)), }; this.seed_elements(); diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index 21905c8dff..ecee48e8d5 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -1,95 +1,16 @@ -// This module contains a few functions and utilities for expanding a seed into more data for use in worldgen. +/// Simple non-cryptographic diffusion function. +pub fn diffuse(mut x: u32) -> u32 { + x ^= 2281701376; + x = x.rotate_left(7); + x.wrapping_mul(0x811c9dc5) +} -// Very standard substitution box. Takes one number and gives back another. This one works per byte. -// Standard component in diffusion functions. The numbers here are totally random and could be whatever. -// Onlu rule is each index has to match an unique number. -static SBOX: [u8; 256] = [ - 206, 21, 212, 69, 54, 234, 13, 42, 184, 48, 92, 64, 196, 55, 225, 235, 229, 120, 135, 72, 32, - 147, 74, 142, 197, 79, 139, 164, 110, 57, 176, 47, 192, 174, 178, 49, 193, 71, 78, 18, 237, 81, - 255, 187, 5, 246, 247, 109, 26, 44, 93, 230, 96, 102, 204, 31, 100, 175, 182, 245, 9, 0, 127, - 161, 125, 52, 129, 179, 209, 130, 219, 77, 218, 252, 61, 75, 62, 248, 124, 220, 98, 87, 63, - 163, 101, 40, 29, 4, 36, 123, 23, 238, 134, 35, 17, 169, 226, 19, 2, 253, 158, 172, 37, 104, - 183, 194, 43, 167, 59, 215, 162, 88, 140, 25, 133, 221, 132, 159, 232, 250, 154, 10, 211, 112, - 146, 189, 141, 95, 1, 111, 28, 160, 73, 181, 67, 30, 190, 157, 148, 149, 11, 8, 41, 217, 106, - 39, 214, 152, 180, 168, 14, 56, 70, 34, 137, 243, 45, 195, 94, 38, 7, 116, 16, 136, 82, 114, - 186, 105, 15, 223, 200, 131, 85, 20, 128, 210, 97, 233, 151, 241, 138, 6, 60, 24, 249, 12, 207, - 239, 171, 65, 113, 115, 22, 107, 68, 143, 90, 119, 185, 153, 166, 46, 155, 191, 254, 58, 150, - 251, 99, 213, 118, 240, 122, 108, 231, 126, 177, 80, 227, 91, 145, 203, 228, 198, 236, 53, 50, - 51, 76, 242, 103, 117, 170, 173, 121, 188, 27, 244, 205, 224, 144, 3, 89, 84, 66, 202, 83, 156, - 216, 33, 165, 86, 222, 199, 208, 201, -]; - -// Helper function to work with the box above. Takes a u64 and runs each byte through the box. -fn sbox(x: u64) -> u64 { - let mut bytes = x.to_ne_bytes(); - for byte in &mut bytes { - *byte = SBOX[*byte as usize]; +/// Expand a 32 bit seed into a 32 byte RNG state. +pub fn rng_state(mut x: u32) -> [u8; 32] { + let mut r: [u32; 8] = [0; 8]; + for s in &mut r { + x = diffuse(x); + *s = x; } - u64::from_ne_bytes(bytes) -} - -// A bijective diffusion function with chaotic behaviour. It essentially mixes numbers. -// A 1 bit change somewhere will affect a large portion of the other bits after running through this function. -fn diffuse_rnd(mut x: u64) -> u64 { - x = x.wrapping_mul(0x6eed0e9da4d94a4f); - let a = x >> 32; - let b = x >> 60; - x ^= a >> b; - x = x.wrapping_mul(0x6eed0e9da4d94a4f); - sbox(x) -} - -// Helper for running diffuse_rnd 4 times, enough to mix the bits around properly. -fn diffuse(mut x: u64) -> u64 { - for _ in 0..4 { - x = diffuse_rnd(x); - } - x -} - -// Expands a 32 bit state into a 64 bit state. -fn initial_expand(x: u32) -> u64 { - let f = (x as u64).wrapping_mul(0x2f72b4215a3d8caf); - f.wrapping_mul(f) -} - -// Truncate a 64 bit state to a 32 bit seed. -fn truncate(x: u64) -> u32 { - let xb = x.to_ne_bytes(); - let nb = [ - xb[0].wrapping_mul(xb[1]), - xb[2].wrapping_mul(xb[3]), - xb[4].wrapping_mul(xb[5]), - xb[6].wrapping_mul(xb[7]), - ]; - u32::from_ne_bytes(nb) -} - -// Generates a sequence of diffused (mixed) numbers from one seed. -// Used for generating a lot of initial seeds for the noise algorithms in worldgen. -pub fn diffused_field(seed: u32, amount: u32) -> Vec { - let mut field = Vec::new(); - for i in 0..=amount { - let n = truncate(diffuse(initial_expand(seed + i))); - field.push(n); - } - field -} - -// Expand a 32 bit seed into a 32 byte state for the RNG used in worldgen. -pub fn expand_seed_to_rng(seed: u32) -> [u8; 32] { - // Create a new empty ChaChaRng state. - let mut r: [u64; 4] = [0; 4]; - - // Create a new empty internal state. - let mut state: u64 = initial_expand(seed); - - // Fill the ChaChaRng state with random bits from repeatedly mixing the state. - for i in 0..4 { - state = diffuse(state); - r[i] = state; - } - - // Convert the ChaChaRng state to bytes. Uses unsafe here because the safe code for it would be much longer. unsafe { std::mem::transmute(r) } } From cdf4c26be7296a22565a36556b508849c850120b Mon Sep 17 00:00:00 2001 From: Acrimon Date: Tue, 6 Aug 2019 09:55:43 +0200 Subject: [PATCH 09/11] Rewrite diffusion function. Now has potential for a full avalanche. --- world/src/util/seed_expan.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/world/src/util/seed_expan.rs b/world/src/util/seed_expan.rs index ecee48e8d5..899c2d435e 100644 --- a/world/src/util/seed_expan.rs +++ b/world/src/util/seed_expan.rs @@ -1,8 +1,12 @@ /// Simple non-cryptographic diffusion function. pub fn diffuse(mut x: u32) -> u32 { - x ^= 2281701376; - x = x.rotate_left(7); - x.wrapping_mul(0x811c9dc5) + x = x.wrapping_add(0x7ed55d16).wrapping_add(x << 12); + x = (x ^ 0xc761c23c) ^ (x >> 19); + x = x.wrapping_add(0x165667b1).wrapping_add(x << 5); + x = x.wrapping_add(0xd3a2646c) ^ (x << 9); + x = x.wrapping_add(0xfd7046c5).wrapping_add(x << 3); + x = (x ^ 0xb55a4f09) ^ (x >> 16); + x } /// Expand a 32 bit seed into a 32 byte RNG state. From 7b8a7a410d19caee620d48ac3e48b7988604422d Mon Sep 17 00:00:00 2001 From: Acrimon Date: Sun, 11 Aug 2019 13:35:04 +0200 Subject: [PATCH 10/11] Cleaned up seed generation in worldsim. --- world/src/sim/mod.rs | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 098c3faaf3..213b6f9ea0 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -54,42 +54,47 @@ pub struct WorldSim { } impl WorldSim { - pub fn generate(seed: u32) -> Self { + pub fn generate(mut seed: u32) -> Self { + let mut gen_seed = || { + seed = seed_expan::diffuse(seed + 1); + seed + }; + let mut gen_ctx = GenCtx { - turb_x_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed)), - turb_y_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 1)), + turb_x_nz: SuperSimplex::new().set_seed(gen_seed()), + turb_y_nz: SuperSimplex::new().set_seed(gen_seed()), chaos_nz: RidgedMulti::new() .set_octaves(7) - .set_seed(seed_expan::diffuse(seed + 2)), - hill_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 3)), + .set_seed(gen_seed()), + hill_nz: SuperSimplex::new().set_seed(gen_seed()), alt_nz: HybridMulti::new() .set_octaves(8) .set_persistence(0.1) - .set_seed(seed_expan::diffuse(seed + 4)), - temp_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 5)), - dry_nz: BasicMulti::new().set_seed(seed_expan::diffuse(seed + 6)), + .set_seed(gen_seed()), + temp_nz: SuperSimplex::new().set_seed(gen_seed()), + dry_nz: BasicMulti::new().set_seed(gen_seed()), small_nz: BasicMulti::new() .set_octaves(2) - .set_seed(seed_expan::diffuse(seed + 7)), + .set_seed(gen_seed()), rock_nz: HybridMulti::new() .set_persistence(0.3) - .set_seed(seed_expan::diffuse(seed + 8)), + .set_seed(gen_seed()), cliff_nz: HybridMulti::new() .set_persistence(0.3) - .set_seed(seed_expan::diffuse(seed + 9)), + .set_seed(gen_seed()), warp_nz: BasicMulti::new() .set_octaves(3) - .set_seed(seed_expan::diffuse(seed + 10)), + .set_seed(gen_seed()), tree_nz: BasicMulti::new() .set_octaves(12) .set_persistence(0.75) - .set_seed(seed_expan::diffuse(seed + 11)), - cave_0_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 12)), - cave_1_nz: SuperSimplex::new().set_seed(seed_expan::diffuse(seed + 13)), + .set_seed(gen_seed()), + cave_0_nz: SuperSimplex::new().set_seed(gen_seed()), + cave_1_nz: SuperSimplex::new().set_seed(gen_seed()), - structure_gen: StructureGen2d::new(seed_expan::diffuse(seed + 14), 32, 24), - region_gen: StructureGen2d::new(seed_expan::diffuse(seed + 15), 400, 96), - cliff_gen: StructureGen2d::new(seed_expan::diffuse(seed + 16), 80, 56), + structure_gen: StructureGen2d::new(gen_seed(), 32, 24), + region_gen: StructureGen2d::new(gen_seed(), 400, 96), + cliff_gen: StructureGen2d::new(gen_seed(), 80, 56), }; let mut chunks = Vec::new(); From 51a4e358ddad0d5b7276942bc3b276e7c15b27f3 Mon Sep 17 00:00:00 2001 From: Acrimon Date: Sun, 11 Aug 2019 13:35:22 +0200 Subject: [PATCH 11/11] Formatted code. --- world/src/sim/mod.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index 213b6f9ea0..0585e3528c 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -63,9 +63,7 @@ impl WorldSim { let mut gen_ctx = GenCtx { turb_x_nz: SuperSimplex::new().set_seed(gen_seed()), turb_y_nz: SuperSimplex::new().set_seed(gen_seed()), - chaos_nz: RidgedMulti::new() - .set_octaves(7) - .set_seed(gen_seed()), + chaos_nz: RidgedMulti::new().set_octaves(7).set_seed(gen_seed()), hill_nz: SuperSimplex::new().set_seed(gen_seed()), alt_nz: HybridMulti::new() .set_octaves(8) @@ -73,18 +71,10 @@ impl WorldSim { .set_seed(gen_seed()), temp_nz: SuperSimplex::new().set_seed(gen_seed()), dry_nz: BasicMulti::new().set_seed(gen_seed()), - small_nz: BasicMulti::new() - .set_octaves(2) - .set_seed(gen_seed()), - rock_nz: HybridMulti::new() - .set_persistence(0.3) - .set_seed(gen_seed()), - cliff_nz: HybridMulti::new() - .set_persistence(0.3) - .set_seed(gen_seed()), - warp_nz: BasicMulti::new() - .set_octaves(3) - .set_seed(gen_seed()), + small_nz: BasicMulti::new().set_octaves(2).set_seed(gen_seed()), + rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(gen_seed()), + cliff_nz: HybridMulti::new().set_persistence(0.3).set_seed(gen_seed()), + warp_nz: BasicMulti::new().set_octaves(3).set_seed(gen_seed()), tree_nz: BasicMulti::new() .set_octaves(12) .set_persistence(0.75)