mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Initial spot implementation
This commit is contained in:
parent
a2e0426d45
commit
3025f043d3
@ -1,13 +1,14 @@
|
||||
use crate::{
|
||||
block::ZCache,
|
||||
block::{block_from_structure, ZCache},
|
||||
column::ColumnSample,
|
||||
index::IndexRef,
|
||||
land::Land,
|
||||
layer::spot::Spot,
|
||||
sim::{SimChunk, WorldSim},
|
||||
util::Grid,
|
||||
};
|
||||
use common::{
|
||||
terrain::{Block, TerrainChunk, TerrainChunkSize},
|
||||
terrain::{Block, Structure, TerrainChunk, TerrainChunkSize},
|
||||
vol::{ReadVol, RectVolSize, WriteVol},
|
||||
};
|
||||
use std::ops::Deref;
|
||||
@ -15,6 +16,7 @@ use vek::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct CanvasInfo<'a> {
|
||||
pub(crate) chunk_pos: Vec2<i32>,
|
||||
pub(crate) wpos: Vec2<i32>,
|
||||
pub(crate) column_grid: &'a Grid<Option<ZCache<'a>>>,
|
||||
pub(crate) column_grid_border: i32,
|
||||
@ -42,6 +44,24 @@ impl<'a> CanvasInfo<'a> {
|
||||
.map(|zc| &zc.sample)
|
||||
}
|
||||
|
||||
pub fn nearby_spots(&self) -> impl Iterator<Item = (Vec2<i32>, Spot, u32)> + '_ {
|
||||
(-1..2)
|
||||
.map(|x| (-1..2).map(move |y| Vec2::new(x, y)))
|
||||
.flatten()
|
||||
.filter_map(move |pos| {
|
||||
let pos = self.chunk_pos + pos;
|
||||
self.chunks.get(pos).and_then(|c| c.spot).map(|spot| {
|
||||
let wpos = pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz| {
|
||||
e * sz as i32 + sz as i32 / 2
|
||||
});
|
||||
// TODO: Very dumb, not this.
|
||||
let seed = pos.x as u32 | (pos.y as u32).wrapping_shl(16);
|
||||
|
||||
(wpos, spot, seed)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn index(&self) -> IndexRef<'a> { self.index }
|
||||
|
||||
pub fn chunk(&self) -> &'a SimChunk { self.chunk }
|
||||
@ -117,11 +137,19 @@ impl<'a> Canvas<'a> {
|
||||
let _ = self.chunk.map(pos - self.wpos(), f);
|
||||
}
|
||||
|
||||
/// Execute an operation upon each column in this canvas.
|
||||
pub fn foreach_col(&mut self, mut f: impl FnMut(&mut Self, Vec2<i32>, &ColumnSample)) {
|
||||
for y in 0..self.area().size().h as i32 {
|
||||
for x in 0..self.area().size().w as i32 {
|
||||
let wpos2d = self.wpos() + Vec2::new(x, y);
|
||||
pub fn foreach_col_area(
|
||||
&mut self,
|
||||
aabr: Aabr<i32>,
|
||||
mut f: impl FnMut(&mut Self, Vec2<i32>, &ColumnSample),
|
||||
) {
|
||||
let chunk_aabr = Aabr {
|
||||
min: self.wpos(),
|
||||
max: self.wpos() + Vec2::from(self.area().size().map(|e| e as i32)),
|
||||
};
|
||||
|
||||
for y in chunk_aabr.min.y.max(aabr.min.y)..chunk_aabr.max.y.min(aabr.max.y) {
|
||||
for x in chunk_aabr.min.x.max(aabr.min.x)..chunk_aabr.max.x.min(aabr.max.x) {
|
||||
let wpos2d = Vec2::new(x, y);
|
||||
let info = self.info;
|
||||
let col = if let Some(col) = info.col(wpos2d) {
|
||||
col
|
||||
@ -132,6 +160,51 @@ impl<'a> Canvas<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute an operation upon each column in this canvas.
|
||||
pub fn foreach_col(&mut self, f: impl FnMut(&mut Self, Vec2<i32>, &ColumnSample)) {
|
||||
self.foreach_col_area(
|
||||
Aabr {
|
||||
min: Vec2::broadcast(i32::MIN),
|
||||
max: Vec2::broadcast(i32::MAX),
|
||||
},
|
||||
f,
|
||||
);
|
||||
}
|
||||
|
||||
/// Blit a structure on to the canvas at the given position.
|
||||
///
|
||||
/// Note that this function should be called with identitical parameters by
|
||||
/// all chunks within the bounds of the structure to avoid cut-offs
|
||||
/// occurring at chunk borders. Deterministic RNG is advised!
|
||||
pub fn blit_structure(&mut self, origin: Vec3<i32>, structure: &Structure, seed: u32) {
|
||||
let aabr = Aabr {
|
||||
min: origin.xy() + structure.get_bounds().min.xy(),
|
||||
max: origin.xy() + structure.get_bounds().max.xy(),
|
||||
};
|
||||
let info = self.info();
|
||||
self.foreach_col_area(aabr, |canvas, wpos2d, col| {
|
||||
for z in structure.get_bounds().min.z..structure.get_bounds().max.z {
|
||||
if let Ok(sblock) = structure.get((wpos2d - origin.xy()).with_z(z)) {
|
||||
let _ = canvas.map(wpos2d.with_z(origin.z + z), |block| {
|
||||
if let Some(block) = block_from_structure(
|
||||
info.index,
|
||||
*sblock,
|
||||
wpos2d.with_z(origin.z + z),
|
||||
wpos2d - origin.xy(),
|
||||
seed,
|
||||
col,
|
||||
|sprite| block.with_sprite(sprite),
|
||||
) {
|
||||
block
|
||||
} else {
|
||||
block
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Deref for Canvas<'a> {
|
||||
|
@ -1,8 +1,9 @@
|
||||
pub mod scatter;
|
||||
pub mod spot;
|
||||
pub mod tree;
|
||||
pub mod wildlife;
|
||||
|
||||
pub use self::{scatter::apply_scatter_to, tree::apply_trees_to};
|
||||
pub use self::{scatter::apply_scatter_to, spot::apply_spots_to, tree::apply_trees_to};
|
||||
|
||||
use crate::{
|
||||
column::ColumnSample,
|
||||
|
94
world/src/layer/spot.rs
Normal file
94
world/src/layer/spot.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use crate::{
|
||||
sim::{SimChunk, WorldSim},
|
||||
util::seed_expan,
|
||||
Canvas,
|
||||
};
|
||||
use common::terrain::{Block, BlockKind, Structure};
|
||||
use rand::prelude::*;
|
||||
use rand_chacha::ChaChaRng;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Spot {
|
||||
Camp,
|
||||
Hideout,
|
||||
}
|
||||
|
||||
impl Spot {
|
||||
pub fn generate(world: &mut WorldSim) {
|
||||
Self::generate_spots(
|
||||
Spot::Camp,
|
||||
world,
|
||||
10.0,
|
||||
|g, c| g < 0.25 && !c.near_cliffs() && !c.river.near_water(),
|
||||
false,
|
||||
);
|
||||
Self::generate_spots(
|
||||
Spot::Hideout,
|
||||
world,
|
||||
10.0,
|
||||
|g, c| g < 0.25 && !c.near_cliffs() && !c.river.near_water(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
fn generate_spots(
|
||||
spot: Spot,
|
||||
world: &mut WorldSim,
|
||||
freq: f32, // Per sq km
|
||||
mut valid: impl FnMut(f32, &SimChunk) -> bool,
|
||||
trees: bool,
|
||||
) {
|
||||
let world_size = world.get_size();
|
||||
for _ in 0..(world_size.product() as f32 / 32.0f32.powi(2) * freq).ceil() as u64 {
|
||||
let pos = world_size.map(|e| world.rng.gen_range(0..e as i32));
|
||||
if let Some((_, chunk)) = world
|
||||
.get_gradient_approx(pos)
|
||||
.zip(world.get_mut(pos))
|
||||
.filter(|(grad, chunk)| valid(*grad, chunk))
|
||||
{
|
||||
chunk.spot = Some(spot);
|
||||
if !trees {
|
||||
chunk.tree_density = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_spots_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
||||
let nearby_spots = canvas.nearby_spots().collect::<Vec<_>>();
|
||||
|
||||
for (spot_wpos, spot, seed) in nearby_spots.iter().copied() {
|
||||
let mut rng = ChaChaRng::from_seed(seed_expan::rng_state(seed));
|
||||
match spot {
|
||||
Spot::Camp => {
|
||||
canvas.foreach_col_area(
|
||||
Aabr {
|
||||
min: spot_wpos - 8,
|
||||
max: spot_wpos + 8,
|
||||
},
|
||||
|canvas, wpos2d, col| {
|
||||
if nearby_spots
|
||||
.iter()
|
||||
.any(|(wpos, _, _)| wpos.distance_squared(wpos2d) < 64)
|
||||
{
|
||||
for z in -8..32 {
|
||||
canvas.set(
|
||||
wpos2d.with_z(col.alt as i32 + z),
|
||||
Block::new(BlockKind::Misc, Rgb::broadcast(255)),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
Spot::Hideout => {
|
||||
let structures = Structure::load_group("dungeon_entrances").read();
|
||||
let structure = structures.choose(&mut rng).unwrap();
|
||||
let origin = spot_wpos.with_z(canvas.land().get_alt_approx(spot_wpos) as i32);
|
||||
canvas.blit_structure(origin, &structure, seed);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
@ -338,6 +338,7 @@ impl World {
|
||||
// Apply layers (paths, caves, etc.)
|
||||
let mut canvas = Canvas {
|
||||
info: CanvasInfo {
|
||||
chunk_pos,
|
||||
wpos: chunk_pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
||||
column_grid: &zcache_grid,
|
||||
column_grid_border: grid_border,
|
||||
@ -352,6 +353,7 @@ impl World {
|
||||
layer::apply_trees_to(&mut canvas, &mut dynamic_rng);
|
||||
layer::apply_scatter_to(&mut canvas, &mut dynamic_rng);
|
||||
layer::apply_paths_to(&mut canvas);
|
||||
layer::apply_spots_to(&mut canvas, &mut dynamic_rng);
|
||||
// layer::apply_coral_to(&mut canvas);
|
||||
|
||||
// Apply site generation
|
||||
|
@ -30,6 +30,7 @@ use crate::{
|
||||
block::BlockGen,
|
||||
civ::Place,
|
||||
column::ColumnGen,
|
||||
layer::spot::Spot,
|
||||
site::Site,
|
||||
util::{
|
||||
seed_expan, DHashSet, FastNoise, FastNoise2d, RandomField, Sampler, StructureGen2d,
|
||||
@ -1413,6 +1414,8 @@ impl WorldSim {
|
||||
|
||||
this.generate_cliffs();
|
||||
|
||||
Spot::generate(&mut this);
|
||||
|
||||
if opts.seed_elements {
|
||||
this.seed_elements();
|
||||
}
|
||||
@ -2134,6 +2137,7 @@ pub struct SimChunk {
|
||||
pub path: (Way, Path),
|
||||
pub cave: (Way, Cave),
|
||||
pub cliff_height: f32,
|
||||
pub spot: Option<Spot>,
|
||||
|
||||
pub contains_waypoint: bool,
|
||||
}
|
||||
@ -2363,6 +2367,7 @@ impl SimChunk {
|
||||
path: Default::default(),
|
||||
cave: Default::default(),
|
||||
cliff_height: 0.0,
|
||||
spot: None,
|
||||
|
||||
contains_waypoint: false,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user