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) } +}