Tweak some more, idk what else to say, not like I understand this.
Population is next 7d5d16bde5fd3e50bb6e5faf934db32415ef6626 149fbe66d2903c9ad4005977973ee53583b97430 a979a07249a0b0eed797ab365bc88cd7c74672e1 8a81ec053123cc2e6fd69b4b7bae6d7b39c75e63
This commit is contained in:
parent
cb935618b0
commit
af05c1b761
9 changed files with 236 additions and 74 deletions
7
planet/src/human_group.rs
Normal file
7
planet/src/human_group.rs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct HumanGroup {
|
||||||
|
pub id: u32,
|
||||||
|
pub population: u32,
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod human_group;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
pub use world::{TerrainCell, World, WorldGenError};
|
pub use world::{TerrainCell, World, WorldGenError};
|
||||||
pub mod biome;
|
pub mod biome;
|
||||||
|
|
|
@ -1,4 +1,17 @@
|
||||||
const PERMUTATION: [u8; 256] = [
|
const PERMUTATION: [u8; 512] = [
|
||||||
|
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69,
|
||||||
|
142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219,
|
||||||
|
203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
|
||||||
|
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230,
|
||||||
|
220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76,
|
||||||
|
132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173,
|
||||||
|
186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206,
|
||||||
|
59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163,
|
||||||
|
70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232,
|
||||||
|
178, 185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162,
|
||||||
|
241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204,
|
||||||
|
176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141,
|
||||||
|
128, 195, 78, 66, 215, 61, 156, 180, // Duplicated
|
||||||
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69,
|
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69,
|
||||||
142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219,
|
142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219,
|
||||||
203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
|
203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
|
||||||
|
@ -15,9 +28,28 @@ const PERMUTATION: [u8; 256] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn perlin_value(x: f32, y: f32, z: f32) -> f32 {
|
pub fn permutation_value(x: f32, y: f32, z: f32) -> u32 {
|
||||||
let p = [PERMUTATION, PERMUTATION].concat();
|
let x = (f32::floor(x) as i32 & 255) as usize;
|
||||||
|
let y = (f32::floor(y) as i32 & 255) as usize;
|
||||||
|
let z = (f32::floor(z) as i32 & 255) as usize;
|
||||||
|
|
||||||
|
let a = PERMUTATION[x] as usize + y;
|
||||||
|
let aa = PERMUTATION[a] as usize + z;
|
||||||
|
let ab = PERMUTATION[aa] as u32;
|
||||||
|
|
||||||
|
let b = PERMUTATION[x + 1] as usize + y;
|
||||||
|
let ba = PERMUTATION[b] as usize + z;
|
||||||
|
let bb = PERMUTATION[ba] as u32;
|
||||||
|
|
||||||
|
let c = PERMUTATION[x + 2] as usize + y;
|
||||||
|
let ca = PERMUTATION[c] as usize + z;
|
||||||
|
let cb = PERMUTATION[ca] as u32;
|
||||||
|
|
||||||
|
ab + (bb * 256) + (cb * 256 * 256)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn perlin_value(x: f32, y: f32, z: f32) -> f32 {
|
||||||
let fx: i32 = f32::floor(x) as i32;
|
let fx: i32 = f32::floor(x) as i32;
|
||||||
let fy: i32 = f32::floor(y) as i32;
|
let fy: i32 = f32::floor(y) as i32;
|
||||||
let fz: i32 = f32::floor(z) as i32;
|
let fz: i32 = f32::floor(z) as i32;
|
||||||
|
@ -34,36 +66,40 @@ pub fn perlin_value(x: f32, y: f32, z: f32) -> f32 {
|
||||||
let v = fade(y);
|
let v = fade(y);
|
||||||
let w = fade(z);
|
let w = fade(z);
|
||||||
|
|
||||||
let a = p[xb] as usize + yb;
|
let a = PERMUTATION[xb] as usize + yb;
|
||||||
let aa = p[a] as usize + zb;
|
let aa = PERMUTATION[a] as usize + zb;
|
||||||
let ab = p[a + 1] as usize + zb;
|
let ab = PERMUTATION[a + 1] as usize + zb;
|
||||||
|
|
||||||
let b = p[xb + 1] as usize + yb;
|
let b = PERMUTATION[xb + 1] as usize + yb;
|
||||||
let ba = p[b] as usize + zb;
|
let ba = PERMUTATION[b] as usize + zb;
|
||||||
let bb = p[b + 1] as usize + zb;
|
let bb = PERMUTATION[b + 1] as usize + zb;
|
||||||
|
|
||||||
scale(lerp(
|
scale(lerp(
|
||||||
w,
|
w,
|
||||||
lerp(
|
lerp(
|
||||||
v,
|
v,
|
||||||
lerp(u, grad(p[aa], x, y, z), grad(p[ba], x - 1.0, y, z)),
|
|
||||||
lerp(
|
lerp(
|
||||||
u,
|
u,
|
||||||
grad(p[ab], x, y - 1.0, z),
|
grad(PERMUTATION[aa], x, y, z),
|
||||||
grad(p[bb], x - 1.0, y - 1.0, z),
|
grad(PERMUTATION[ba], x - 1.0, y, z),
|
||||||
|
),
|
||||||
|
lerp(
|
||||||
|
u,
|
||||||
|
grad(PERMUTATION[ab], x, y - 1.0, z),
|
||||||
|
grad(PERMUTATION[bb], x - 1.0, y - 1.0, z),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
lerp(
|
lerp(
|
||||||
v,
|
v,
|
||||||
lerp(
|
lerp(
|
||||||
u,
|
u,
|
||||||
grad(p[aa + 1], x, y, z - 1.0),
|
grad(PERMUTATION[aa + 1], x, y, z - 1.0),
|
||||||
grad(p[ba + 1], x - 1.0, y, z - 1.0),
|
grad(PERMUTATION[ba + 1], x - 1.0, y, z - 1.0),
|
||||||
),
|
),
|
||||||
lerp(
|
lerp(
|
||||||
u,
|
u,
|
||||||
grad(p[ab + 1], x, y - 1.0, z - 1.0),
|
grad(PERMUTATION[ab + 1], x, y - 1.0, z - 1.0),
|
||||||
grad(p[bb + 1], x - 1.0, y - 1.0, z - 1.0),
|
grad(PERMUTATION[bb + 1], x - 1.0, y - 1.0, z - 1.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
|
|
2
planet/src/saving/mod.rs
Normal file
2
planet/src/saving/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// pub mod terrain_cell;
|
||||||
|
pub mod world;
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{TerrainCell, World},
|
crate::{TerrainCell, World},
|
||||||
|
bevy::prelude::debug,
|
||||||
rand::{rngs::StdRng, SeedableRng},
|
rand::{rngs::StdRng, SeedableRng},
|
||||||
serde::{
|
serde::{
|
||||||
de::{Error, MapAccess, SeqAccess, Visitor},
|
de::{Error, MapAccess, SeqAccess, Visitor},
|
||||||
|
@ -43,6 +44,7 @@ impl<'de> Deserialize<'de> for World {
|
||||||
Terrain,
|
Terrain,
|
||||||
ContinentOffsets,
|
ContinentOffsets,
|
||||||
ContinentSizes,
|
ContinentSizes,
|
||||||
|
Iteration,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WorldVisitor;
|
struct WorldVisitor;
|
||||||
|
@ -64,23 +66,29 @@ impl<'de> Deserialize<'de> for World {
|
||||||
|
|
||||||
let height = seq
|
let height = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| Error::invalid_length(0, &self))?;
|
.ok_or_else(|| Error::invalid_length(1, &self))?;
|
||||||
|
|
||||||
let seed = seq
|
let seed = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| Error::invalid_length(0, &self))?;
|
.ok_or_else(|| Error::invalid_length(2, &self))?;
|
||||||
|
|
||||||
let terrain: Vec<Vec<TerrainCell>> = seq
|
let terrain: Vec<Vec<TerrainCell>> = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| Error::invalid_length(0, &self))?;
|
.ok_or_else(|| Error::invalid_length(3, &self))?;
|
||||||
|
|
||||||
let continent_offsets = seq
|
let continent_offsets = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| Error::invalid_length(0, &self))?;
|
.ok_or_else(|| Error::invalid_length(4, &self))?;
|
||||||
|
|
||||||
let continent_widths = seq
|
let continent_sizes = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| Error::invalid_length(0, &self))?;
|
.ok_or_else(|| Error::invalid_length(5, &self))?;
|
||||||
|
|
||||||
|
debug!("Iteration aaaaa");
|
||||||
|
let iteration = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| Error::invalid_length(6, &self))?;
|
||||||
|
debug!("Iteration bbbbb");
|
||||||
|
|
||||||
let world_attributes = &mut WorldTerrainAttributes::default();
|
let world_attributes = &mut WorldTerrainAttributes::default();
|
||||||
let world_attributes =
|
let world_attributes =
|
||||||
|
@ -111,13 +119,14 @@ impl<'de> Deserialize<'de> for World {
|
||||||
attributes
|
attributes
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(World {
|
debug!("Constructing world");
|
||||||
|
let mut world = World {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
seed,
|
seed,
|
||||||
terrain,
|
terrain,
|
||||||
continent_offsets,
|
continent_offsets,
|
||||||
continent_sizes: continent_widths,
|
continent_sizes,
|
||||||
|
|
||||||
max_altitude: world_attributes.max_altitude,
|
max_altitude: world_attributes.max_altitude,
|
||||||
min_altitude: world_attributes.min_altitude,
|
min_altitude: world_attributes.min_altitude,
|
||||||
|
@ -127,7 +136,22 @@ impl<'de> Deserialize<'de> for World {
|
||||||
min_temperature: world_attributes.min_temperature,
|
min_temperature: world_attributes.min_temperature,
|
||||||
|
|
||||||
rng: StdRng::seed_from_u64(seed as u64),
|
rng: StdRng::seed_from_u64(seed as u64),
|
||||||
})
|
iteration,
|
||||||
|
};
|
||||||
|
{
|
||||||
|
let mut y = 0;
|
||||||
|
debug!("Completing terrain");
|
||||||
|
for terrain_row in world.terrain.iter_mut() {
|
||||||
|
let mut x = 0;
|
||||||
|
for terrain_cell in terrain_row.iter_mut() {
|
||||||
|
terrain_cell.x = x;
|
||||||
|
terrain_cell.y = y;
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(world)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
||||||
|
@ -140,6 +164,7 @@ impl<'de> Deserialize<'de> for World {
|
||||||
let mut terrain = None;
|
let mut terrain = None;
|
||||||
let mut continent_offsets = None;
|
let mut continent_offsets = None;
|
||||||
let mut continent_widths = None;
|
let mut continent_widths = None;
|
||||||
|
let mut iteration = None;
|
||||||
|
|
||||||
while let Some(key) = map.next_key()? {
|
while let Some(key) = map.next_key()? {
|
||||||
match key {
|
match key {
|
||||||
|
@ -179,6 +204,12 @@ impl<'de> Deserialize<'de> for World {
|
||||||
}
|
}
|
||||||
continent_widths = Some(map.next_value()?);
|
continent_widths = Some(map.next_value()?);
|
||||||
},
|
},
|
||||||
|
Field::Iteration => {
|
||||||
|
if iteration.is_some() {
|
||||||
|
return Err(Error::duplicate_field("iteration"));
|
||||||
|
}
|
||||||
|
iteration = Some(map.next_value()?);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +260,9 @@ impl<'de> Deserialize<'de> for World {
|
||||||
attributes
|
attributes
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(World {
|
let iteration = iteration.ok_or_else(|| Error::missing_field("iteration"))?;
|
||||||
|
|
||||||
|
let mut world = World {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
seed,
|
seed,
|
||||||
|
@ -245,7 +278,21 @@ impl<'de> Deserialize<'de> for World {
|
||||||
min_temperature: world_attributes.min_temperature,
|
min_temperature: world_attributes.min_temperature,
|
||||||
|
|
||||||
rng: StdRng::seed_from_u64(seed as u64),
|
rng: StdRng::seed_from_u64(seed as u64),
|
||||||
})
|
iteration,
|
||||||
|
};
|
||||||
|
{
|
||||||
|
let mut y = 0;
|
||||||
|
for terrain_row in world.terrain.iter_mut() {
|
||||||
|
let mut x = 0;
|
||||||
|
for terrain_cell in terrain_row.iter_mut() {
|
||||||
|
terrain_cell.x = x;
|
||||||
|
terrain_cell.y = y;
|
||||||
|
x += 1;
|
||||||
|
}
|
||||||
|
y += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(world)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,7 @@ pub struct World {
|
||||||
pub min_temperature: f32,
|
pub min_temperature: f32,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub rng: StdRng,
|
pub rng: StdRng,
|
||||||
|
pub iteration: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||||
|
@ -98,24 +99,40 @@ pub struct TerrainCell {
|
||||||
pub temperature: f32,
|
pub temperature: f32,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub x: usize,
|
pub x: usize,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub y: usize,
|
pub y: usize,
|
||||||
|
pub local_iteration: usize,
|
||||||
|
|
||||||
pub biome_presences: Vec<(BiomeType, f32)>,
|
pub biome_presences: Vec<(BiomeType, f32)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TerrainCell {
|
||||||
|
pub fn get_next_local_random_int(&mut self, world: &World) -> f32 {
|
||||||
|
let seed = world.seed;
|
||||||
|
|
||||||
|
let x = seed as f32 + self.x as f32;
|
||||||
|
let y = seed as f32 + self.y as f32;
|
||||||
|
let z = seed as f32 + world.iteration as f32 + (self.local_iteration - 1) as f32;
|
||||||
|
|
||||||
|
drop(world);
|
||||||
|
self.local_iteration += 1;
|
||||||
|
|
||||||
|
perlin::perlin_value(x, y, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
pub const ALTITUDE_SPAN: f32 = World::MAX_ALTITUDE - World::MIN_ALTITUDE;
|
pub const ALTITUDE_SPAN: f32 = World::MAX_ALTITUDE - World::MIN_ALTITUDE;
|
||||||
pub const CONTINENT_MAX_SIZE_FACTOR: f32 = 8.0;
|
pub const CONTINENT_MAX_SIZE_FACTOR: f32 = 8.7;
|
||||||
pub const CONTINENT_MIN_SIZE_FACTOR: f32 = 6.0;
|
pub const CONTINENT_MIN_SIZE_FACTOR: f32 = 5.7;
|
||||||
pub const MAX_ALTITUDE: f32 = 15000.0;
|
pub const MAX_ALTITUDE: f32 = 15000.0;
|
||||||
pub const MAX_RAINFALL: f32 = 13000.0;
|
pub const MAX_RAINFALL: f32 = 13000.0;
|
||||||
pub const MAX_TEMPERATURE: f32 = 30.0;
|
pub const MAX_TEMPERATURE: f32 = 30.0;
|
||||||
pub const MIN_ALTITUDE: f32 = -15000.0;
|
pub const MIN_ALTITUDE: f32 = -15000.0;
|
||||||
pub const MIN_RAINFALL: f32 = 0.0;
|
pub const MIN_RAINFALL: f32 = 0.0;
|
||||||
pub const MIN_TEMPERATURE: f32 = -35.0;
|
pub const MIN_TEMPERATURE: f32 = -35.0;
|
||||||
pub const NUM_CONTINENTS: u8 = 6;
|
pub const NUM_CONTINENTS: u8 = 12;
|
||||||
pub const RAINFALL_DRYNESS_FACTOR: f32 = 0.005;
|
pub const RAINFALL_DRYNESS_FACTOR: f32 = 0.005;
|
||||||
pub const RAINFALL_DRYNESS_OFFSET: f32 = World::RAINFALL_DRYNESS_FACTOR * World::MAX_RAINFALL;
|
pub const RAINFALL_DRYNESS_OFFSET: f32 = World::RAINFALL_DRYNESS_FACTOR * World::MAX_RAINFALL;
|
||||||
pub const RAINFALL_SPAN: f32 = World::MAX_RAINFALL - World::MIN_RAINFALL;
|
pub const RAINFALL_SPAN: f32 = World::MAX_RAINFALL - World::MIN_RAINFALL;
|
||||||
|
@ -127,10 +144,7 @@ impl World {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
seed,
|
seed,
|
||||||
terrain: vec![
|
terrain: vec![vec![default(); width.try_into().unwrap()]; height.try_into().unwrap()],
|
||||||
vec![TerrainCell::default(); width.try_into().unwrap()];
|
|
||||||
height.try_into().unwrap()
|
|
||||||
],
|
|
||||||
continent_offsets: [default(); World::NUM_CONTINENTS as usize],
|
continent_offsets: [default(); World::NUM_CONTINENTS as usize],
|
||||||
continent_sizes: [default(); World::NUM_CONTINENTS as usize],
|
continent_sizes: [default(); World::NUM_CONTINENTS as usize],
|
||||||
max_altitude: World::MIN_ALTITUDE,
|
max_altitude: World::MIN_ALTITUDE,
|
||||||
|
@ -140,6 +154,7 @@ impl World {
|
||||||
max_temperature: World::MIN_TEMPERATURE,
|
max_temperature: World::MIN_TEMPERATURE,
|
||||||
min_temperature: World::MAX_TEMPERATURE,
|
min_temperature: World::MAX_TEMPERATURE,
|
||||||
rng: StdRng::seed_from_u64(seed as u64),
|
rng: StdRng::seed_from_u64(seed as u64),
|
||||||
|
iteration: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,10 +163,7 @@ impl World {
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
seed,
|
seed,
|
||||||
terrain: vec![
|
terrain: vec![vec![default(); width.try_into().unwrap()]; height.try_into().unwrap()],
|
||||||
vec![TerrainCell::default(); width.try_into().unwrap()];
|
|
||||||
height.try_into().unwrap()
|
|
||||||
],
|
|
||||||
continent_offsets: [default(); World::NUM_CONTINENTS as usize],
|
continent_offsets: [default(); World::NUM_CONTINENTS as usize],
|
||||||
continent_sizes: [default(); World::NUM_CONTINENTS as usize],
|
continent_sizes: [default(); World::NUM_CONTINENTS as usize],
|
||||||
max_altitude: World::MIN_ALTITUDE,
|
max_altitude: World::MIN_ALTITUDE,
|
||||||
|
@ -161,6 +173,7 @@ impl World {
|
||||||
max_temperature: World::MIN_TEMPERATURE,
|
max_temperature: World::MIN_TEMPERATURE,
|
||||||
min_temperature: World::MAX_TEMPERATURE,
|
min_temperature: World::MAX_TEMPERATURE,
|
||||||
rng: StdRng::seed_from_u64(seed as u64),
|
rng: StdRng::seed_from_u64(seed as u64),
|
||||||
|
iteration: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,35 +200,76 @@ impl World {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_continents(&mut self) {
|
fn generate_continents(&mut self, progress_sender: &Sender<(f32, String)>) {
|
||||||
#[cfg(feature = "logging")]
|
|
||||||
info!("Generating continents");
|
info!("Generating continents");
|
||||||
|
|
||||||
|
send_progress(progress_sender, 0.0, format!("Generating continents"));
|
||||||
let width = self.width as f32;
|
let width = self.width as f32;
|
||||||
let height = self.height as f32;
|
let height = self.height as f32;
|
||||||
|
|
||||||
|
const LONGTITUDE_FACTOR: f32 = 15.0;
|
||||||
const LATITUDE_FACTOR: f32 = 6.0;
|
const LATITUDE_FACTOR: f32 = 6.0;
|
||||||
|
|
||||||
for i in 0..World::NUM_CONTINENTS {
|
let mut previous_position = Vec2 {
|
||||||
// #[cfg(feature = "logging")]
|
x: self
|
||||||
// info!("Continents: {}/{}", i, World::NUM_CONTINENTS);
|
|
||||||
|
|
||||||
self.continent_offsets[i as usize].x = self
|
|
||||||
.rng
|
.rng
|
||||||
.gen_range(width * i as f32 * 2.0 / 5.0..(width * (i as f32 + 2.0) * 2.0 / 5.0))
|
.gen_range(0.0..width * (LONGTITUDE_FACTOR - 1.0) / LONGTITUDE_FACTOR),
|
||||||
.repeat(width);
|
y: self.rng.gen_range(
|
||||||
self.continent_offsets[i as usize].y = self.rng.gen_range(
|
height / LATITUDE_FACTOR..height * (LATITUDE_FACTOR - 1.0) / LATITUDE_FACTOR,
|
||||||
height * 1.0 / LATITUDE_FACTOR..height * (LATITUDE_FACTOR - 1.0) / LATITUDE_FACTOR,
|
),
|
||||||
|
};
|
||||||
|
for i in 0..World::NUM_CONTINENTS {
|
||||||
|
send_progress(
|
||||||
|
progress_sender,
|
||||||
|
i as f32 / World::NUM_CONTINENTS as f32,
|
||||||
|
format!("Generating continents: {i}/{{World::NUM_CONTINENTS}}"),
|
||||||
|
);
|
||||||
|
let idx = i as usize;
|
||||||
|
|
||||||
|
let width_offset = self.rng.gen_range(0.0..6.0);
|
||||||
|
|
||||||
|
self.continent_offsets[idx] = previous_position;
|
||||||
|
|
||||||
|
self.continent_sizes[idx] = Vec2 {
|
||||||
|
x: self.rng.gen_range(
|
||||||
|
World::CONTINENT_MIN_SIZE_FACTOR + width_offset
|
||||||
|
..World::CONTINENT_MAX_SIZE_FACTOR + width_offset,
|
||||||
|
),
|
||||||
|
y: self.rng.gen_range(
|
||||||
|
World::CONTINENT_MIN_SIZE_FACTOR + width_offset
|
||||||
|
..World::CONTINENT_MAX_SIZE_FACTOR + width_offset,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
let y_position = self.rng.gen_range(
|
||||||
|
height / LATITUDE_FACTOR..height * (LATITUDE_FACTOR - 1.0) / LATITUDE_FACTOR,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.continent_sizes[i as usize] = Vec2 {
|
let new_vector = if i % 3 == 2 {
|
||||||
x: self
|
Vec2 {
|
||||||
.rng
|
x: f32::repeat(
|
||||||
.gen_range(World::CONTINENT_MIN_SIZE_FACTOR..World::CONTINENT_MAX_SIZE_FACTOR),
|
previous_position.x
|
||||||
y: self
|
+ self.rng.gen_range(
|
||||||
.rng
|
width * 4.0 / LONGTITUDE_FACTOR..width * 6.0 / LONGTITUDE_FACTOR,
|
||||||
.gen_range(World::CONTINENT_MIN_SIZE_FACTOR..World::CONTINENT_MAX_SIZE_FACTOR)
|
),
|
||||||
/ 2.0,
|
width,
|
||||||
|
),
|
||||||
|
y: y_position,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Vec2 {
|
||||||
|
x: f32::repeat(
|
||||||
|
previous_position.x
|
||||||
|
+ self.rng.gen_range(
|
||||||
|
width / LONGTITUDE_FACTOR..width * 2.0 / LONGTITUDE_FACTOR,
|
||||||
|
),
|
||||||
|
width,
|
||||||
|
),
|
||||||
|
y: y_position,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
previous_position = new_vector;
|
||||||
}
|
}
|
||||||
info!("Done generating continents");
|
info!("Done generating continents");
|
||||||
}
|
}
|
||||||
|
@ -278,16 +332,16 @@ impl World {
|
||||||
progress_sender: &Sender<(f32, String)>,
|
progress_sender: &Sender<(f32, String)>,
|
||||||
) -> Result<(), CartesianError> {
|
) -> Result<(), CartesianError> {
|
||||||
info!("Generating altitude");
|
info!("Generating altitude");
|
||||||
self.generate_continents();
|
self.generate_continents(progress_sender);
|
||||||
|
|
||||||
const RADIUS_1: f32 = 0.5;
|
const RADIUS_1: f32 = 0.75;
|
||||||
const RADIUS_2: f32 = 8.0;
|
const RADIUS_2: f32 = 8.0;
|
||||||
const RADIUS_3: f32 = 4.0;
|
const RADIUS_3: f32 = 4.0;
|
||||||
const RADIUS_4: f32 = 8.0;
|
const RADIUS_4: f32 = 8.0;
|
||||||
const RADIUS_5: f32 = 16.0;
|
const RADIUS_5: f32 = 16.0;
|
||||||
const RADIUS_6: f32 = 64.0;
|
const RADIUS_6: f32 = 64.0;
|
||||||
const RADIUS_7: f32 = 128.0;
|
const RADIUS_7: f32 = 128.0;
|
||||||
const RADIUS_8: f32 = 1.0;
|
const RADIUS_8: f32 = 1.5;
|
||||||
const RADIUS_9: f32 = 1.0;
|
const RADIUS_9: f32 = 1.0;
|
||||||
|
|
||||||
let offset_1 = World::random_offset_vector(&mut self.rng);
|
let offset_1 = World::random_offset_vector(&mut self.rng);
|
||||||
|
@ -433,8 +487,10 @@ impl World {
|
||||||
info!("Generating rainfall");
|
info!("Generating rainfall");
|
||||||
const RADIUS_1: f32 = 2.0;
|
const RADIUS_1: f32 = 2.0;
|
||||||
const RADIUS_2: f32 = 1.0;
|
const RADIUS_2: f32 = 1.0;
|
||||||
|
const RADIUS_3: f32 = 16.0;
|
||||||
let offset_1 = World::random_offset_vector(&mut self.rng);
|
let offset_1 = World::random_offset_vector(&mut self.rng);
|
||||||
let offset_2 = World::random_offset_vector(&mut self.rng);
|
let offset_2 = World::random_offset_vector(&mut self.rng);
|
||||||
|
let offset_3 = World::random_offset_vector(&mut self.rng);
|
||||||
|
|
||||||
let height = self.terrain.len();
|
let height = self.terrain.len();
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
|
@ -457,8 +513,12 @@ impl World {
|
||||||
.random_noise_from_polar_coordinates(alpha, beta, RADIUS_2, offset_2)?
|
.random_noise_from_polar_coordinates(alpha, beta, RADIUS_2, offset_2)?
|
||||||
* 1.5
|
* 1.5
|
||||||
+ 0.25;
|
+ 0.25;
|
||||||
|
let random_noise_3 =
|
||||||
|
self.random_noise_from_polar_coordinates(alpha, beta, RADIUS_3, offset_3)?;
|
||||||
|
|
||||||
let latitude_factor = alpha + (random_noise_1 * 2.0 - 1.0) * PI * 0.2;
|
let value_a = mix_values(random_noise_1, random_noise_3, 0.15);
|
||||||
|
|
||||||
|
let latitude_factor = alpha + (value_a * 2.0 - 1.0) * PI * 0.2;
|
||||||
let latitude_modifier_1 = (1.5 * f32::sin(latitude_factor)) - 0.5;
|
let latitude_modifier_1 = (1.5 * f32::sin(latitude_factor)) - 0.5;
|
||||||
let latitude_modifier_2 = f32::cos(latitude_factor);
|
let latitude_modifier_2 = f32::cos(latitude_factor);
|
||||||
|
|
||||||
|
@ -545,8 +605,10 @@ impl World {
|
||||||
progress_sender: &Sender<(f32, String)>,
|
progress_sender: &Sender<(f32, String)>,
|
||||||
) -> Result<(), CartesianError> {
|
) -> Result<(), CartesianError> {
|
||||||
info!("Generating temperature");
|
info!("Generating temperature");
|
||||||
let offset = World::random_offset_vector(&mut self.rng);
|
let offset_1 = World::random_offset_vector(&mut self.rng);
|
||||||
const RADIUS: f32 = 2.0;
|
let offset_2 = World::random_offset_vector(&mut self.rng);
|
||||||
|
const RADIUS_1: f32 = 2.0;
|
||||||
|
const RADIUS_2: f32 = 16.0;
|
||||||
|
|
||||||
let height = self.terrain.len();
|
let height = self.terrain.len();
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
|
@ -564,12 +626,14 @@ impl World {
|
||||||
|
|
||||||
let beta = (x as f32 / self.width as f32) * TAU;
|
let beta = (x as f32 / self.width as f32) * TAU;
|
||||||
|
|
||||||
let random_noise =
|
let random_noise_1 =
|
||||||
self.random_noise_from_polar_coordinates(alpha, beta, RADIUS, offset)?;
|
self.random_noise_from_polar_coordinates(alpha, beta, RADIUS_1, offset_1)?;
|
||||||
|
let random_noise_2 =
|
||||||
|
self.random_noise_from_polar_coordinates(alpha, beta, RADIUS_2, offset_2)?;
|
||||||
|
|
||||||
let cell = &mut self.terrain[y][x];
|
let cell = &mut self.terrain[y][x];
|
||||||
|
|
||||||
let latitude_modifer = mix_values(alpha, random_noise * PI, 0.1);
|
let latitude_modifer = alpha * 0.9 + (random_noise_1 + random_noise_2) * 0.05 * PI;
|
||||||
let altitude_factor = f32::max(
|
let altitude_factor = f32::max(
|
||||||
0.0,
|
0.0,
|
||||||
(cell.altitude / World::MAX_ALTITUDE) * World::TEMPERATURE_ALTITUDE_FACTOR,
|
(cell.altitude / World::MAX_ALTITUDE) * World::TEMPERATURE_ALTITUDE_FACTOR,
|
||||||
|
|
|
@ -42,7 +42,10 @@ impl Display for LoadError {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
LoadError::MissingSave(_) => f.write_str("No save found at given path"),
|
LoadError::MissingSave(_) => f.write_str("No save found at given path"),
|
||||||
LoadError::InvalidSave(_) => f.write_str("Loaded file is not a valid save"),
|
LoadError::InvalidSave(err) => f.write_fmt(format_args!(
|
||||||
|
"Loaded file is not a valid save - {}",
|
||||||
|
err.to_string()
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,12 @@ impl WindowSystem for SaveLoad<'_, '_> {
|
||||||
if let Some(path) = tinyfiledialogs::save_file_dialog_with_filter(
|
if let Some(path) = tinyfiledialogs::save_file_dialog_with_filter(
|
||||||
"Save world",
|
"Save world",
|
||||||
state.file_name.as_str(),
|
state.file_name.as_str(),
|
||||||
&["*.rsplnt", "*.ron"],
|
&["*.rsplnt", "*.rsplnt"],
|
||||||
"World file",
|
"World file",
|
||||||
) {
|
) {
|
||||||
if let Err(err) = world_manager.save_world(&path) {
|
if let Err(err) = world_manager.save_world(&path) {
|
||||||
// TODO: Error popup
|
// TODO: Error popup
|
||||||
error!("Failed to save: {err:#?}");
|
error!("Failed to save: {err}");
|
||||||
}
|
}
|
||||||
*state.file_name = path;
|
*state.file_name = path;
|
||||||
}
|
}
|
||||||
|
@ -45,14 +45,15 @@ impl WindowSystem for SaveLoad<'_, '_> {
|
||||||
if let Some(path) = tinyfiledialogs::open_file_dialog(
|
if let Some(path) = tinyfiledialogs::open_file_dialog(
|
||||||
"World file",
|
"World file",
|
||||||
state.file_name.as_str(),
|
state.file_name.as_str(),
|
||||||
Some((&["*.ron", "*.rsplnt"], "*.ron,*.rsplnt")),
|
Some((&["*.rsplnt"], "*.rspnt")),
|
||||||
) {
|
) {
|
||||||
if let Err(err) = world_manager.load_world(&path) {
|
if let Err(err) = world_manager.load_world(&path) {
|
||||||
// TODO: Error popup
|
// TODO: Error popup
|
||||||
error!("Failed to load: {err:#?}");
|
error!("Failed to load: {err}");
|
||||||
|
} else {
|
||||||
|
should_redraw.0 = true;
|
||||||
}
|
}
|
||||||
*state.file_name = path;
|
*state.file_name = path;
|
||||||
should_redraw.0 = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -41,6 +41,7 @@ impl WindowSystem for TileInfo<'_, '_> {
|
||||||
biome_presences,
|
biome_presences,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
..
|
||||||
} = &world.terrain[cursor_y as usize][cursor_x as usize];
|
} = &world.terrain[cursor_y as usize][cursor_x as usize];
|
||||||
|
|
||||||
_ = ui.label("Coordinates");
|
_ = ui.label("Coordinates");
|
||||||
|
|
Loading…
Reference in a new issue