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