mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added poi for all biomes
This commit is contained in:
parent
d5f0ee2fc5
commit
5bd7507f31
@ -4,10 +4,10 @@ mod econ;
|
||||
|
||||
use crate::{
|
||||
config::CONFIG,
|
||||
sim::{RiverKind, WorldSim},
|
||||
sim::WorldSim,
|
||||
site::{namegen::NameGen, Castle, Settlement, Site as WorldSite, Tree},
|
||||
site2,
|
||||
util::{attempt, seed_expan, CARDINALS, NEIGHBORS},
|
||||
util::{attempt, seed_expan, NEIGHBORS},
|
||||
Index, Land,
|
||||
};
|
||||
use common::{
|
||||
@ -15,7 +15,7 @@ use common::{
|
||||
path::Path,
|
||||
spiral::Spiral2d,
|
||||
store::{Id, Store},
|
||||
terrain::{uniform_idx_as_vec2, vec2_as_uniform_idx, MapSizeLg, TerrainChunkSize},
|
||||
terrain::{uniform_idx_as_vec2, MapSizeLg, TerrainChunkSize},
|
||||
vol::RectVolSize,
|
||||
};
|
||||
use core::{fmt, hash::BuildHasherDefault, ops::Range};
|
||||
@ -89,8 +89,8 @@ impl Civs {
|
||||
let mut ctx = GenCtx { sim, rng };
|
||||
info!("starting peak naming");
|
||||
this.name_peaks(&mut ctx);
|
||||
info!("starting lake naming");
|
||||
this.name_lakes(&mut ctx);
|
||||
info!("starting biome naming");
|
||||
this.name_biomes(&mut ctx);
|
||||
|
||||
for _ in 0..ctx.sim.get_size().product() / 10_000 {
|
||||
this.generate_cave(&mut ctx);
|
||||
@ -468,113 +468,57 @@ impl Civs {
|
||||
}
|
||||
|
||||
/// 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 rng = &mut ctx.rng;
|
||||
let sim_chunks = &ctx.sim.chunks;
|
||||
let lakes = sim_chunks
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(posi, chunk)| {
|
||||
let neighbor_alts_min = common::terrain::neighbors(map_size_lg, *posi)
|
||||
.map(|i| sim_chunks[i].alt as u32)
|
||||
.min();
|
||||
chunk
|
||||
.river
|
||||
.river_kind
|
||||
.map_or(false, |r_kind| matches!(r_kind, RiverKind::Lake { .. }))
|
||||
&& neighbor_alts_min.map_or(false, |n_alt| (chunk.alt as u32) < n_alt)
|
||||
})
|
||||
.map(|(posi, chunk)| {
|
||||
(
|
||||
uniform_idx_as_vec2(map_size_lg, posi),
|
||||
chunk.alt as u32,
|
||||
chunk.water_alt as u32,
|
||||
)
|
||||
})
|
||||
.collect::<Vec<(Vec2<i32>, u32, u32)>>();
|
||||
let mut removals = vec![false; lakes.len()];
|
||||
let mut lake_alts = HashSet::new();
|
||||
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 mut num_lakes = 0;
|
||||
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 {
|
||||
break;
|
||||
}
|
||||
let mut biomes: Vec<(common::terrain::BiomeKind, Vec<usize>)> = Vec::new();
|
||||
let mut explored = HashSet::new();
|
||||
let mut to_explore = HashSet::new();
|
||||
let mut to_floodfill = HashSet::new();
|
||||
// TODO: have start point in center and ignore ocean?
|
||||
let start_point = 0;
|
||||
to_explore.insert(start_point);
|
||||
explored.insert(start_point);
|
||||
|
||||
while to_explore.len() > 0 {
|
||||
let exploring = *to_explore.iter().next().unwrap();
|
||||
to_explore.remove(&exploring);
|
||||
to_floodfill.insert(exploring);
|
||||
// Should always be a chunk on the map
|
||||
let biome = ctx.sim.chunks[exploring].get_biome();
|
||||
biomes.push((biome, Vec::new()));
|
||||
while to_floodfill.len() > 0 {
|
||||
let filling = *to_floodfill.iter().next().unwrap();
|
||||
to_explore.remove(&filling);
|
||||
to_floodfill.remove(&filling);
|
||||
explored.insert(filling);
|
||||
biomes.last_mut().unwrap().1.push(filling);
|
||||
for neighbour in common::terrain::neighbors(map_size_lg, filling) {
|
||||
if explored.contains(&neighbour) {
|
||||
continue;
|
||||
}
|
||||
let n_biome = ctx.sim.chunks[neighbour].get_biome();
|
||||
if n_biome == biome {
|
||||
to_floodfill.insert(neighbour);
|
||||
} else {
|
||||
break;
|
||||
to_explore.insert(neighbour);
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
match rng.gen_range(0..6) {
|
||||
0 => format!("{} Lake", name),
|
||||
1 => format!("Loch {}", name),
|
||||
_ => format!("Lake {}", name),
|
||||
}
|
||||
}
|
||||
},
|
||||
// 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");
|
||||
let num_biomes = biomes.len();
|
||||
|
||||
for biome in biomes {
|
||||
// Select point
|
||||
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");
|
||||
}
|
||||
|
||||
/// Adds mountain POIs and name them
|
||||
@ -934,5 +878,5 @@ pub enum PoiKind {
|
||||
/// Peak stores the altitude
|
||||
Peak(u32),
|
||||
/// Lake stores a metric relating to size
|
||||
Lake(u32),
|
||||
Biome(u32),
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ impl World {
|
||||
name: poi.name.clone(),
|
||||
kind: match &poi.kind {
|
||||
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),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user