mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added caverns, fixed chunk load performance issue
This commit is contained in:
parent
0f2afbec8f
commit
1cfad833c7
@ -644,6 +644,11 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_
|
||||
g: 206,
|
||||
b: 64,
|
||||
},
|
||||
GlowingMushroom => Rgb {
|
||||
r: 50,
|
||||
g: 250,
|
||||
b: 250,
|
||||
},
|
||||
Misc => Rgb {
|
||||
r: 255,
|
||||
g: 0,
|
||||
|
@ -48,7 +48,8 @@ make_case_elim!(
|
||||
// 0x32 <= x < 0x40 is reserved for future earths/muds/gravels/sands/etc.
|
||||
Wood = 0x40,
|
||||
Leaves = 0x41,
|
||||
// 0x42 <= x < 0x50 is reserved for future tree parts
|
||||
GlowingMushroom = 0x42,
|
||||
// 0x43 <= x < 0x50 is reserved for future tree parts
|
||||
// Covers all other cases (we sometimes have bizarrely coloured misc blocks, and also we
|
||||
// often want to experiment with new kinds of block without allocating them a
|
||||
// dedicated block kind.
|
||||
|
@ -106,6 +106,7 @@ native-dialog = { version = "0.5.2", optional = true }
|
||||
num = "0.4"
|
||||
ordered-float = { version = "2.0.1", default-features = false }
|
||||
rand = "0.8"
|
||||
rand_chacha = "0.3"
|
||||
rayon = "1.5"
|
||||
rodio = {version = "0.14", default-features = false, features = ["vorbis"]}
|
||||
ron = {version = "0.6", default-features = false}
|
||||
|
@ -5,6 +5,7 @@ use common::{
|
||||
};
|
||||
use common_base::span;
|
||||
use rand::prelude::*;
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -60,6 +61,8 @@ impl BlocksOfInterest {
|
||||
let mut cricket3 = Vec::new();
|
||||
let mut frogs = Vec::new();
|
||||
|
||||
let mut rng = ChaCha8Rng::from_seed(thread_rng().gen());
|
||||
|
||||
chunk
|
||||
.vol_iter(
|
||||
Vec3::new(0, 0, chunk.get_min_z()),
|
||||
@ -71,13 +74,13 @@ impl BlocksOfInterest {
|
||||
)
|
||||
.for_each(|(pos, block)| {
|
||||
match block.kind() {
|
||||
BlockKind::Leaves if thread_rng().gen_range(0..16) == 0 => leaves.push(pos),
|
||||
BlockKind::WeakRock if thread_rng().gen_range(0..6) == 0 => drip.push(pos),
|
||||
BlockKind::Leaves if rng.gen_range(0..16) == 0 => leaves.push(pos),
|
||||
BlockKind::WeakRock if rng.gen_range(0..6) == 0 => drip.push(pos),
|
||||
BlockKind::Grass => {
|
||||
if thread_rng().gen_range(0..16) == 0 {
|
||||
if rng.gen_range(0..16) == 0 {
|
||||
grass.push(pos);
|
||||
}
|
||||
match thread_rng().gen_range(0..8192) {
|
||||
match rng.gen_range(0..8192) {
|
||||
1 => cricket1.push(pos),
|
||||
2 => cricket2.push(pos),
|
||||
3 => cricket3.push(pos),
|
||||
@ -85,14 +88,12 @@ impl BlocksOfInterest {
|
||||
}
|
||||
},
|
||||
BlockKind::Water
|
||||
if chunk.meta().contains_river() && thread_rng().gen_range(0..16) == 0 =>
|
||||
if chunk.meta().contains_river() && rng.gen_range(0..16) == 0 =>
|
||||
{
|
||||
river.push(pos)
|
||||
},
|
||||
BlockKind::Lava if thread_rng().gen_range(0..5) == 0 => {
|
||||
fires.push(pos + Vec3::unit_z())
|
||||
},
|
||||
BlockKind::Snow if thread_rng().gen_range(0..16) == 0 => snow.push(pos),
|
||||
BlockKind::Lava if rng.gen_range(0..5) == 0 => fires.push(pos + Vec3::unit_z()),
|
||||
BlockKind::Snow if rng.gen_range(0..16) == 0 => snow.push(pos),
|
||||
_ => match block.get_sprite() {
|
||||
Some(SpriteKind::Ember) => {
|
||||
fires.push(pos);
|
||||
@ -114,7 +115,7 @@ impl BlocksOfInterest {
|
||||
Some(SpriteKind::Reed) => {
|
||||
reeds.push(pos);
|
||||
fireflies.push(pos);
|
||||
if thread_rng().gen_range(0..12) == 0 {
|
||||
if rng.gen_range(0..12) == 0 {
|
||||
frogs.push(pos);
|
||||
}
|
||||
},
|
||||
|
@ -10,7 +10,7 @@ pub use self::{
|
||||
|
||||
use crate::{
|
||||
column::ColumnSample,
|
||||
util::{FastNoise, RandomField, Sampler},
|
||||
util::{FastNoise, RandomField, Sampler, RandomPerm},
|
||||
Canvas, IndexRef,
|
||||
};
|
||||
use common::{
|
||||
@ -27,6 +27,7 @@ use std::{
|
||||
f32,
|
||||
ops::{Mul, Range, Sub},
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
@ -570,3 +571,173 @@ pub fn apply_coral_to(canvas: &mut Canvas) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn apply_caverns_to<R: Rng>(canvas: &mut Canvas, dynamic_rng: &mut R) {
|
||||
let info = canvas.info();
|
||||
|
||||
// Get cavern attributes at a position
|
||||
let cavern_at = |wpos2d| {
|
||||
let alt = info.land().get_alt_approx(wpos2d);
|
||||
|
||||
// Horizontal average scale of caverns
|
||||
let scale = 2048.0;
|
||||
// How common should they be? (0.0 - 1.0)
|
||||
let common = 0.15;
|
||||
// Range of heights for the caverns
|
||||
let height_range = 48.0..300.0;
|
||||
// Minimum distance below the surface
|
||||
let surface_clearance = 64.0;
|
||||
|
||||
let cavern_avg_height = Lerp::lerp(
|
||||
height_range.start,
|
||||
height_range.end,
|
||||
info.index().noise.cave_nz.get((wpos2d.map(|e| e as f64) / 128.0).into_array()) as f32 * 0.5 + 0.5,
|
||||
);
|
||||
|
||||
let cavern_avg_alt = alt * 0.25 - height_range.end - surface_clearance;
|
||||
|
||||
let cavern_nz = info.index().noise.cave_nz.get((wpos2d.map(|e| e as f64) / scale).into_array()) as f32;
|
||||
let cavern_height = ((cavern_nz * 0.5 + 0.5 - (1.0 - common)).max(0.0) / common).powf(common * 2.0) * cavern_avg_height;
|
||||
|
||||
// Stalagtites
|
||||
let stalagtite = info.index().noise.cave_nz
|
||||
.get(wpos2d.map(|e| e as f64 * 0.015).into_array())
|
||||
.sub(0.5)
|
||||
.max(0.0)
|
||||
.mul((cavern_height as f64 - 5.0).mul(0.15).clamped(0.0, 1.0))
|
||||
.mul(32.0 + cavern_avg_height as f64 * 0.85);
|
||||
|
||||
let lake = info.index().noise.cave_nz
|
||||
.get(wpos2d.map(|e| e as f64 * 0.01).into_array())
|
||||
.sub(0.5)
|
||||
.max(0.0)
|
||||
.mul(2.0)
|
||||
.mul(80.0);
|
||||
let lake = 0.0;
|
||||
|
||||
let rugged = 0.25; // How bumpy should the floor be relative to the ceiling?
|
||||
let cavern_bottom = (cavern_avg_alt - cavern_height * rugged) as i32;
|
||||
let cavern_avg_bottom = (cavern_avg_alt - ((height_range.start + height_range.end) * 0.5) * rugged) as i32;
|
||||
let cavern_top = (cavern_avg_alt + cavern_height) as i32;
|
||||
let cavern_avg_top = (cavern_avg_alt + cavern_avg_height) as i32;
|
||||
|
||||
// Stalagmites rise up to meet stalagtites
|
||||
let stalagmite = stalagtite * 0.3;
|
||||
|
||||
let floor = stalagmite as i32;
|
||||
|
||||
(cavern_bottom, cavern_top, cavern_avg_bottom, cavern_avg_top, floor, lake, stalagtite)
|
||||
};
|
||||
|
||||
let mut mushroom_cache = HashMap::new();
|
||||
|
||||
struct Mushroom {
|
||||
pos: Vec3<i32>,
|
||||
stalk: f32,
|
||||
head_color: Rgb<u8>,
|
||||
}
|
||||
|
||||
// Get mushroom block, if any, at a position
|
||||
let mut get_mushroom = |wpos: Vec3<i32>, dynamic_rng: &mut R| {
|
||||
for (wpos2d, seed) in info.chunks().gen_ctx.structure_gen.get(wpos.xy()) {
|
||||
let mushroom = if let Some(mushroom) = mushroom_cache
|
||||
.entry(wpos2d)
|
||||
.or_insert_with(|| {
|
||||
let mut rng = RandomPerm::new(seed);
|
||||
let (cavern_bottom, _, _, _, floor, _, _) = cavern_at(wpos2d);
|
||||
if rng.gen_bool(0.1) {
|
||||
Some(Mushroom {
|
||||
pos: wpos2d.with_z(cavern_bottom + floor),
|
||||
stalk: rng.gen_range(8.0..26.0),
|
||||
head_color: Rgb::new(50, rng.gen_range(70..110), rng.gen_range(100..200)),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
{
|
||||
mushroom
|
||||
} else {
|
||||
continue
|
||||
};
|
||||
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
let warp_freq = 1.0 / 32.0;
|
||||
let warp_amp = Vec3::new(8.0, 8.0, 12.0);
|
||||
let wposf_warped = wposf.map(|e| e as f32) + Vec3::new(
|
||||
FastNoise::new(seed + 0).get(wposf * warp_freq) as f32,
|
||||
FastNoise::new(seed + 1).get(wposf * warp_freq) as f32,
|
||||
FastNoise::new(seed + 2).get(wposf * warp_freq) as f32,
|
||||
) * warp_amp;
|
||||
|
||||
let rpos = wposf_warped - mushroom.pos.map(|e| e as f32).map(|e| e as f32);
|
||||
|
||||
let stalk_radius = 2.0f32;
|
||||
let head_radius = 12.0f32;
|
||||
let head_height = 10.0;
|
||||
|
||||
let dist_sq = rpos.xy().magnitude_squared();
|
||||
if dist_sq < head_radius.powi(2) {
|
||||
let dist = dist_sq.sqrt();
|
||||
// Head
|
||||
if rpos.z > mushroom.stalk && rpos.z < mushroom.stalk + head_height && dist < head_radius * (1.0 - (rpos.z - mushroom.stalk) / head_height).powf(0.125) {
|
||||
return Some(Block::new(BlockKind::GlowingMushroom, mushroom.head_color));
|
||||
} else if rpos.z <= mushroom.stalk && rpos.xy().magnitude_squared() < stalk_radius.powi(2) { // Stalk
|
||||
return Some(Block::new(BlockKind::Wood, Rgb::new(50, 120, 180)));
|
||||
} else if ((mushroom.stalk - 1.0)..mushroom.stalk).contains(&rpos.z) // Hanging orbs
|
||||
&& ((head_radius * 0.5)..(head_radius * 0.8)).contains(&dist)
|
||||
&& dynamic_rng.gen_bool(0.025)
|
||||
{
|
||||
return Some(Block::air(SpriteKind::Orb));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
};
|
||||
|
||||
canvas.foreach_col(|canvas, wpos2d, _col| {
|
||||
let (cavern_bottom, cavern_top, cavern_avg_bottom, cavern_avg_top, floor, lake, stalagtite) = cavern_at(wpos2d);
|
||||
|
||||
let mini_stalagtite = info.index().noise.cave_nz
|
||||
.get(wpos2d.map(|e| e as f64 * 0.08).into_array())
|
||||
.sub(0.5)
|
||||
.max(0.0)
|
||||
.mul(((cavern_top - cavern_bottom) as f64 - 5.0).mul(0.15).clamped(0.0, 1.0))
|
||||
.mul(24.0 + (cavern_avg_top - cavern_avg_bottom) as f64 * 0.2);
|
||||
let stalagtite_height = (stalagtite + mini_stalagtite) as i32;
|
||||
|
||||
let cavern_top = cavern_top as i32;
|
||||
let lower_bound = cavern_bottom - lake as i32;
|
||||
let mut on_ground = true;
|
||||
for z in lower_bound..cavern_top {
|
||||
use SpriteKind::*;
|
||||
|
||||
let wpos = wpos2d.with_z(z);
|
||||
|
||||
let block = if z < lower_bound + floor {
|
||||
Block::new(BlockKind::WeakRock, Rgb::new(110, 120, 150))
|
||||
} else if z > cavern_top - stalagtite_height {
|
||||
if dynamic_rng.gen_bool(0.0035) { // Glowing rock in stalagtites
|
||||
Block::new(BlockKind::GlowingRock, Rgb::new(30, 150, 120))
|
||||
} else {
|
||||
Block::new(BlockKind::WeakRock, Rgb::new(110, 120, 150))
|
||||
}
|
||||
} else if let Some(mushroom_block) = get_mushroom(wpos, dynamic_rng) {
|
||||
mushroom_block
|
||||
} else if z < cavern_avg_bottom as i32 + 16 {
|
||||
Block::water(SpriteKind::Empty)
|
||||
} else if z == cavern_bottom + floor && dynamic_rng.gen_bool(0.005) && on_ground {
|
||||
Block::air(*[CrystalLow, CaveMushroom].choose(dynamic_rng).unwrap())
|
||||
} else if z == cavern_top - 1 && dynamic_rng.gen_bool(0.01) {
|
||||
Block::air(*[CrystalHigh, CeilingMushroom, Orb].choose(dynamic_rng).unwrap())
|
||||
} else {
|
||||
Block::empty()
|
||||
};
|
||||
|
||||
on_ground |= block.is_solid();
|
||||
|
||||
let _ = canvas.set(wpos, block);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -346,6 +346,7 @@ impl World {
|
||||
entities: Vec::new(),
|
||||
};
|
||||
|
||||
layer::apply_caverns_to(&mut canvas, &mut dynamic_rng);
|
||||
layer::apply_caves_to(&mut canvas, &mut dynamic_rng);
|
||||
layer::apply_shrubs_to(&mut canvas, &mut dynamic_rng);
|
||||
layer::apply_trees_to(&mut canvas, &mut dynamic_rng);
|
||||
|
Loading…
Reference in New Issue
Block a user