Added poi for all biomes

This commit is contained in:
IsseW 2022-01-16 16:54:49 +01:00
parent d5f0ee2fc5
commit 5bd7507f31
2 changed files with 52 additions and 108 deletions

View File

@ -4,10 +4,10 @@ mod econ;
use crate::{ use crate::{
config::CONFIG, config::CONFIG,
sim::{RiverKind, WorldSim}, sim::WorldSim,
site::{namegen::NameGen, Castle, Settlement, Site as WorldSite, Tree}, site::{namegen::NameGen, Castle, Settlement, Site as WorldSite, Tree},
site2, site2,
util::{attempt, seed_expan, CARDINALS, NEIGHBORS}, util::{attempt, seed_expan, NEIGHBORS},
Index, Land, Index, Land,
}; };
use common::{ use common::{
@ -15,7 +15,7 @@ use common::{
path::Path, path::Path,
spiral::Spiral2d, spiral::Spiral2d,
store::{Id, Store}, store::{Id, Store},
terrain::{uniform_idx_as_vec2, vec2_as_uniform_idx, MapSizeLg, TerrainChunkSize}, terrain::{uniform_idx_as_vec2, MapSizeLg, TerrainChunkSize},
vol::RectVolSize, vol::RectVolSize,
}; };
use core::{fmt, hash::BuildHasherDefault, ops::Range}; use core::{fmt, hash::BuildHasherDefault, ops::Range};
@ -89,8 +89,8 @@ impl Civs {
let mut ctx = GenCtx { sim, rng }; let mut ctx = GenCtx { sim, rng };
info!("starting peak naming"); info!("starting peak naming");
this.name_peaks(&mut ctx); this.name_peaks(&mut ctx);
info!("starting lake naming"); info!("starting biome naming");
this.name_lakes(&mut ctx); this.name_biomes(&mut ctx);
for _ in 0..ctx.sim.get_size().product() / 10_000 { for _ in 0..ctx.sim.get_size().product() / 10_000 {
this.generate_cave(&mut ctx); this.generate_cave(&mut ctx);
@ -468,113 +468,57 @@ impl Civs {
} }
/// Adds lake POIs and names them /// Adds lake POIs and names them
fn name_lakes(&mut self, ctx: &mut GenCtx<impl Rng>) { fn name_biomes(&mut self, ctx: &mut GenCtx<impl Rng>) {
let map_size_lg = ctx.sim.map_size_lg(); let map_size_lg = ctx.sim.map_size_lg();
let rng = &mut ctx.rng; let mut biomes: Vec<(common::terrain::BiomeKind, Vec<usize>)> = Vec::new();
let sim_chunks = &ctx.sim.chunks; let mut explored = HashSet::new();
let lakes = sim_chunks let mut to_explore = HashSet::new();
.iter() let mut to_floodfill = HashSet::new();
.enumerate() // TODO: have start point in center and ignore ocean?
.filter(|(posi, chunk)| { let start_point = 0;
let neighbor_alts_min = common::terrain::neighbors(map_size_lg, *posi) to_explore.insert(start_point);
.map(|i| sim_chunks[i].alt as u32) explored.insert(start_point);
.min();
chunk while to_explore.len() > 0 {
.river let exploring = *to_explore.iter().next().unwrap();
.river_kind to_explore.remove(&exploring);
.map_or(false, |r_kind| matches!(r_kind, RiverKind::Lake { .. })) to_floodfill.insert(exploring);
&& neighbor_alts_min.map_or(false, |n_alt| (chunk.alt as u32) < n_alt) // Should always be a chunk on the map
}) let biome = ctx.sim.chunks[exploring].get_biome();
.map(|(posi, chunk)| { biomes.push((biome, Vec::new()));
( while to_floodfill.len() > 0 {
uniform_idx_as_vec2(map_size_lg, posi), let filling = *to_floodfill.iter().next().unwrap();
chunk.alt as u32, to_explore.remove(&filling);
chunk.water_alt as u32, to_floodfill.remove(&filling);
) explored.insert(filling);
}) biomes.last_mut().unwrap().1.push(filling);
.collect::<Vec<(Vec2<i32>, u32, u32)>>(); for neighbour in common::terrain::neighbors(map_size_lg, filling) {
let mut removals = vec![false; lakes.len()]; if explored.contains(&neighbour) {
let mut lake_alts = HashSet::new(); continue;
for (i, (loc, alt, water_alt)) in lakes.iter().enumerate() {
for (k, (n_loc, n_alt, n_water_alt)) in lakes.iter().enumerate() {
// If the difference in position of this low point and another is
// below a threshold and this chunk's altitude is higher, remove the
// lake from the list. Also remove shallow ponds.
// If this lake water altitude is already accounted for and the lake bed
// altitude is lower than the neighboring lake bed altitude, remove this
// lake from the list. Otherwise, add this lake water altitude to the list
// of counted lake water altitudes.
if i != k
&& (*water_alt <= CONFIG.sea_level as u32
|| (!lake_alts.insert(water_alt)
&& water_alt == n_water_alt
&& alt > n_alt)
|| ((loc).distance_squared(*n_loc) < POI_THINNING_DIST_SQRD
&& alt >= n_alt))
{
// This cannot panic as `removals` is the same length as `lakes`
// i is the index in `lakes`
removals[i] = true;
} }
} let n_biome = ctx.sim.chunks[neighbour].get_biome();
} if n_biome == biome {
let mut num_lakes = 0; to_floodfill.insert(neighbour);
for (_j, (loc, alt, water_alt)) in lakes.iter().enumerate().filter(|&(i, _)| !removals[i]) {
// Recenter the location of the lake POI
// Sample every few units to speed this up
let sample_step = 3;
let mut chords: [i32; 4] = [0, 0, 0, 0];
// only search up to 100 chunks in any direction
for (j, chord) in chords.iter_mut().enumerate() {
for i in 0..100 {
let posi = vec2_as_uniform_idx(
map_size_lg,
Vec2::new(loc.x, loc.y) + CARDINALS[j] * sample_step * i,
);
if let Some(r_kind) = sim_chunks[posi].river.river_kind {
if matches!(r_kind, RiverKind::Lake { .. }) {
*chord += sample_step;
} else { } else {
break; to_explore.insert(neighbour);
}
} else {
break;
} }
} }
} }
let center_y = ((chords[0] + chords[1]) / 2) - chords[1] + loc.y;
let center_x = ((chords[2] + chords[3]) / 2) - chords[3] + loc.x;
let new_loc = Vec2::new(center_x, center_y);
let size_parameter = ((chords[2] + chords[3]) + (chords[0] + chords[1]) / 4) as u32;
let lake = PointOfInterest {
name: {
let name = NameGen::location(rng).generate_biome();
if size_parameter > 30 {
format!("{} Sea", name)
} else if (water_alt - alt) < 30 {
match rng.gen_range(0..5) {
0 => format!("{} Shallows", name),
1 => format!("{} Pool", name),
2 => format!("{} Well", name),
_ => format!("{} Pond", name),
} }
} else { let num_biomes = biomes.len();
match rng.gen_range(0..6) {
0 => format!("{} Lake", name), for biome in biomes {
1 => format!("Loch {}", name), // Select point
_ => format!("Lake {}", name), let idx = biome.1[ctx.rng.gen_range(0..biome.1.len())];
let name = format!("{:?}", biome.0);
self.pois.insert(PointOfInterest {
name,
loc: uniform_idx_as_vec2(map_size_lg, idx),
kind: PoiKind::Biome(biome.1.len() as u32),
});
} }
}
}, info!(?num_biomes, "all biomes named");
// Size parameter is based on the east west chord length with a smaller factor from
// the north south chord length. This is used for text scaling on the map
kind: PoiKind::Lake(size_parameter),
loc: new_loc,
};
num_lakes += 1;
self.pois.insert(lake);
}
info!(?num_lakes, "all lakes named");
} }
/// Adds mountain POIs and name them /// Adds mountain POIs and name them
@ -934,5 +878,5 @@ pub enum PoiKind {
/// Peak stores the altitude /// Peak stores the altitude
Peak(u32), Peak(u32),
/// Lake stores a metric relating to size /// Lake stores a metric relating to size
Lake(u32), Biome(u32),
} }

View File

@ -131,7 +131,7 @@ impl World {
name: poi.name.clone(), name: poi.name.clone(),
kind: match &poi.kind { kind: match &poi.kind {
civ::PoiKind::Peak(alt) => world_msg::PoiKind::Peak(*alt), civ::PoiKind::Peak(alt) => world_msg::PoiKind::Peak(*alt),
civ::PoiKind::Lake(size) => world_msg::PoiKind::Lake(*size), civ::PoiKind::Biome(size) => world_msg::PoiKind::Lake(*size),
}, },
wpos: poi.loc * TerrainChunkSize::RECT_SIZE.map(|e| e as i32), wpos: poi.loc * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
} }