mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Greatly simplified seed expansion.
This commit is contained in:
parent
d840ca72e3
commit
00b5a4a58e
@ -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();
|
||||
|
@ -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<u32> {
|
||||
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) }
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user