mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'synis/cave-performance' into 'master'
Addressing cave feedback and performance improvements See merge request veloren/veloren!4360
This commit is contained in:
commit
9079a0e3c4
@ -69,6 +69,10 @@ svg_fmt = "0.4"
|
|||||||
harness = false
|
harness = false
|
||||||
name = "tree"
|
name = "tree"
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
harness = false
|
||||||
|
name = "cave"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "chunk_compression_benchmarks"
|
name = "chunk_compression_benchmarks"
|
||||||
required-features = ["bin_compression"]
|
required-features = ["bin_compression"]
|
||||||
|
76
world/benches/cave.rs
Normal file
76
world/benches/cave.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use common::{spiral::Spiral2d, terrain::CoordinateConversions};
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
use rayon::ThreadPoolBuilder;
|
||||||
|
use veloren_world::{
|
||||||
|
layer,
|
||||||
|
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
|
||||||
|
CanvasInfo, Land, World,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn cave(c: &mut Criterion) {
|
||||||
|
let pool = ThreadPoolBuilder::new().build().unwrap();
|
||||||
|
let (world, index) = World::generate(
|
||||||
|
230,
|
||||||
|
WorldOpts {
|
||||||
|
seed_elements: true,
|
||||||
|
world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
|
||||||
|
..WorldOpts::default()
|
||||||
|
},
|
||||||
|
&pool,
|
||||||
|
&|_| {},
|
||||||
|
);
|
||||||
|
let land = Land::from_sim(world.sim());
|
||||||
|
let mut group = c.benchmark_group("cave");
|
||||||
|
group.sample_size(10);
|
||||||
|
group.bench_function("generate_entrances", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let entrances =
|
||||||
|
black_box(layer::cave::surface_entrances(&land)).map(|e| e.wpos_to_cpos());
|
||||||
|
for entrance in entrances {
|
||||||
|
_ = black_box(world.generate_chunk(
|
||||||
|
index.as_index_ref(),
|
||||||
|
entrance,
|
||||||
|
None,
|
||||||
|
|| false,
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group.bench_function("generate_multiple_tunnels", |b| {
|
||||||
|
b.iter(|| {
|
||||||
|
let entrances = layer::cave::surface_entrances(&land)
|
||||||
|
.map(|e| e.wpos_to_cpos())
|
||||||
|
.step_by(6);
|
||||||
|
for entrance in entrances {
|
||||||
|
let chunk = Spiral2d::new()
|
||||||
|
.step_by(16)
|
||||||
|
.find(|p| {
|
||||||
|
CanvasInfo::with_mock_canvas_info(
|
||||||
|
index.as_index_ref(),
|
||||||
|
world.sim(),
|
||||||
|
|&info| {
|
||||||
|
let land = &info.land();
|
||||||
|
let tunnels =
|
||||||
|
layer::cave::tunnel_bounds_at(entrance + p, &info, land);
|
||||||
|
tunnels.count() > 1
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.map_or(entrance, |p| entrance + p);
|
||||||
|
|
||||||
|
_ = black_box(world.generate_chunk(
|
||||||
|
index.as_index_ref(),
|
||||||
|
chunk,
|
||||||
|
None,
|
||||||
|
|| false,
|
||||||
|
None,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, cave);
|
||||||
|
criterion_main!(benches);
|
67
world/examples/cave_biomes.rs
Normal file
67
world/examples/cave_biomes.rs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
use common::terrain::CoordinateConversions;
|
||||||
|
use rayon::ThreadPoolBuilder;
|
||||||
|
use vek::Vec2;
|
||||||
|
use veloren_world::{
|
||||||
|
layer::{
|
||||||
|
self,
|
||||||
|
cave::{Biome, LAYERS},
|
||||||
|
},
|
||||||
|
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
|
||||||
|
CanvasInfo, Land, World,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let pool = ThreadPoolBuilder::new().build().unwrap();
|
||||||
|
let (world, index) = World::generate(
|
||||||
|
230,
|
||||||
|
WorldOpts {
|
||||||
|
seed_elements: true,
|
||||||
|
world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
|
||||||
|
..WorldOpts::default()
|
||||||
|
},
|
||||||
|
&pool,
|
||||||
|
&|_| {},
|
||||||
|
);
|
||||||
|
let land = Land::from_sim(world.sim());
|
||||||
|
|
||||||
|
let mut biomes: Vec<(Biome, u32)> = vec![(Biome::default(), 0); LAYERS as usize];
|
||||||
|
for x in 0..land.size().x {
|
||||||
|
for y in 0..land.size().y {
|
||||||
|
let wpos = Vec2::new(x as i32, y as i32).cpos_to_wpos();
|
||||||
|
CanvasInfo::with_mock_canvas_info(index.as_index_ref(), world.sim(), |&info| {
|
||||||
|
let land = &info.land();
|
||||||
|
let tunnels = layer::cave::tunnel_bounds_at(wpos, &info, land);
|
||||||
|
for (level, z_range, _, _, _, tunnel) in tunnels {
|
||||||
|
let biome = tunnel.biome_at(wpos.with_z(z_range.start), &info);
|
||||||
|
let (ref mut current, ref mut total) = &mut biomes[level as usize - 1];
|
||||||
|
current.barren += biome.barren;
|
||||||
|
current.mushroom += biome.mushroom;
|
||||||
|
current.fire += biome.fire;
|
||||||
|
current.leafy += biome.leafy;
|
||||||
|
current.dusty += biome.dusty;
|
||||||
|
current.icy += biome.icy;
|
||||||
|
current.snowy += biome.snowy;
|
||||||
|
current.crystal += biome.crystal;
|
||||||
|
current.sandy += biome.sandy;
|
||||||
|
*total += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (level, (biome, total)) in biomes.iter().enumerate() {
|
||||||
|
let total = *total as f32;
|
||||||
|
println!("--- LEVEL {} ---", level);
|
||||||
|
println!("TOTAL {}", total);
|
||||||
|
println!("BARREN {:.3}", biome.barren / total);
|
||||||
|
println!("MUSHROOM {:.3}", biome.mushroom / total);
|
||||||
|
println!("FIRE {:.3}", biome.fire / total);
|
||||||
|
println!("LEAFY {:.3}", biome.leafy / total);
|
||||||
|
println!("DUSTY {:.3}", biome.dusty / total);
|
||||||
|
println!("ICY {:.3}", biome.icy / total);
|
||||||
|
println!("SNOWY {:.3}", biome.snowy / total);
|
||||||
|
println!("CRYSTAL {:.3}", biome.crystal / total);
|
||||||
|
println!("SANDY {:.3}", biome.sandy / total);
|
||||||
|
println!("\n");
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,7 @@ fn to_wpos(cell: Vec2<i32>, level: u32) -> Vec2<i32> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const AVG_LEVEL_DEPTH: i32 = 120;
|
const AVG_LEVEL_DEPTH: i32 = 120;
|
||||||
const LAYERS: u32 = 4;
|
pub const LAYERS: u32 = 5;
|
||||||
const MIN_RADIUS: f32 = 8.0;
|
const MIN_RADIUS: f32 = 8.0;
|
||||||
const MAX_RADIUS: f32 = 64.0;
|
const MAX_RADIUS: f32 = 64.0;
|
||||||
|
|
||||||
@ -174,7 +174,8 @@ impl Tunnel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn biome_at(&self, wpos: Vec3<i32>, info: &CanvasInfo) -> Biome {
|
// #[inline_tweak::tweak_fn]
|
||||||
|
pub fn biome_at(&self, wpos: Vec3<i32>, info: &CanvasInfo) -> Biome {
|
||||||
let Some(col) = info.col_or_gen(wpos.xy()) else {
|
let Some(col) = info.col_or_gen(wpos.xy()) else {
|
||||||
return Biome::default();
|
return Biome::default();
|
||||||
};
|
};
|
||||||
@ -195,15 +196,15 @@ impl Tunnel {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let temp = Lerp::lerp_unclamped(
|
let temp = Lerp::lerp_unclamped(
|
||||||
col.temp,
|
col.temp * 2.0,
|
||||||
FastNoise2d::new(42)
|
FastNoise2d::new(42)
|
||||||
.get(wpos.xy().map(|e| e as f64 / 1536.0))
|
.get(wpos.xy().map(|e| e as f64 / 2048.0))
|
||||||
.mul(1.15)
|
.mul(1.15)
|
||||||
.mul(2.0)
|
.mul(2.0)
|
||||||
.sub(1.0)
|
.sub(0.5)
|
||||||
.add(
|
.add(
|
||||||
((col.alt - wpos.z as f32) / (AVG_LEVEL_DEPTH as f32 * LAYERS as f32 * 0.75))
|
((col.alt - wpos.z as f32) / (AVG_LEVEL_DEPTH as f32 * LAYERS as f32))
|
||||||
.clamped(0.0, 2.5),
|
.clamped(0.0, 1.0),
|
||||||
),
|
),
|
||||||
below,
|
below,
|
||||||
);
|
);
|
||||||
@ -214,7 +215,7 @@ impl Tunnel {
|
|||||||
.mul(0.5)
|
.mul(0.5)
|
||||||
.add(
|
.add(
|
||||||
((col.alt - wpos.z as f32) / (AVG_LEVEL_DEPTH as f32 * LAYERS as f32))
|
((col.alt - wpos.z as f32) / (AVG_LEVEL_DEPTH as f32 * LAYERS as f32))
|
||||||
.clamped(0.0, 1.5),
|
.clamped(0.0, 1.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
let [
|
let [
|
||||||
@ -233,38 +234,41 @@ impl Tunnel {
|
|||||||
// Mushrooms grow underground and thrive in a humid environment with moderate
|
// Mushrooms grow underground and thrive in a humid environment with moderate
|
||||||
// temperatures
|
// temperatures
|
||||||
let mushroom = underground
|
let mushroom = underground
|
||||||
* close(humidity, 1.0, 0.7, 3)
|
* close(humidity, 1.0, 0.7, 4)
|
||||||
* close(temp, 1.5, 0.9, 3)
|
* close(temp, 2.0, 1.8, 4)
|
||||||
* close(depth, 1.0, 0.6, 3);
|
* close(depth, 0.9, 0.7, 4);
|
||||||
// Extremely hot and dry areas deep underground
|
// Extremely hot and dry areas deep underground
|
||||||
let fire = underground
|
let fire = underground
|
||||||
* close(humidity, 0.0, 0.6, 3)
|
* close(humidity, 0.0, 0.6, 4)
|
||||||
* close(temp, 2.0, 1.3, 3)
|
* close(temp, 2.5, 2.2, 4)
|
||||||
* close(depth, 1.0, 0.55, 3);
|
* close(depth, 1.0, 0.4, 4);
|
||||||
// Overgrown with plants that need a moderate climate to survive
|
// Overgrown with plants that need a moderate climate to survive
|
||||||
let leafy = underground
|
let leafy = underground
|
||||||
* close(humidity, 0.8, 0.8, 3)
|
* close(humidity, 0.8, 0.8, 4)
|
||||||
* close(temp, 0.95, 0.85, 3)
|
* close(temp, 1.2 + depth, 1.5, 4)
|
||||||
* close(depth, 0.0, 0.6, 3);
|
* close(depth, 0.1, 0.7, 4);
|
||||||
// Cool temperature, dry and devoid of value
|
// Cool temperature, dry and devoid of value
|
||||||
let dusty = close(humidity, 0.0, 0.5, 3) * close(temp, -0.1, 0.6, 3);
|
let dusty = close(humidity, 0.0, 0.5, 4)
|
||||||
|
* close(temp, -0.3, 0.6, 4)
|
||||||
|
* close(depth, 0.5, 0.5, 4);
|
||||||
// Deep underground and freezing cold
|
// Deep underground and freezing cold
|
||||||
let icy = underground
|
let icy = underground
|
||||||
* close(temp, -1.5, 1.3, 3)
|
* close(temp, -2.3 + (depth - 0.5) * 0.5, 2.0, 4)
|
||||||
* close(depth, 1.0, 0.65, 3)
|
* close(depth, 0.8, 0.6, 4)
|
||||||
* close(humidity, 1.0, 0.7, 3);
|
* close(humidity, 1.0, 0.85, 4);
|
||||||
// Rocky cold cave that appear near the surface
|
// Rocky cold cave that appear near the surface
|
||||||
let snowy = close(temp, -0.6, 0.5, 3) * close(depth, 0.0, 0.45, 3);
|
let snowy = close(temp, -1.8, 1.3, 4) * close(depth, 0.0, 0.6, 4);
|
||||||
// Crystals grow deep underground in areas rich with minerals. They are present
|
// Crystals grow deep underground in areas rich with minerals. They are present
|
||||||
// in areas with colder temperatures and low humidity
|
// in areas with colder temperatures and low humidity
|
||||||
let crystal = underground
|
let crystal = underground
|
||||||
* close(humidity, 0.0, 0.5, 3)
|
* close(humidity, 0.0, 0.6, 4)
|
||||||
* close(temp, -0.6, 0.75, 3)
|
* close(temp, -1.6, 1.3, 4)
|
||||||
* close(depth, 1.0, 0.55, 3)
|
* close(depth, 1.0, 0.5, 4)
|
||||||
* close(mineral, 2.0, 1.25, 3);
|
* close(mineral, 1.5, 1.0, 4);
|
||||||
// Hot, dry and shallow
|
// Hot, dry and shallow
|
||||||
let sandy =
|
let sandy = close(humidity, 0.0, 0.4, 4)
|
||||||
close(humidity, 0.0, 0.3, 3) * close(temp, 0.7, 0.9, 3) * close(depth, 0.0, 0.6, 3);
|
* close(temp, 0.7, 0.8, 4)
|
||||||
|
* close(depth, 0.0, 0.65, 4);
|
||||||
|
|
||||||
let biomes = [
|
let biomes = [
|
||||||
barren, mushroom, fire, leafy, dusty, icy, snowy, crystal, sandy,
|
barren, mushroom, fire, leafy, dusty, icy, snowy, crystal, sandy,
|
||||||
@ -434,6 +438,7 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
if !tunnels.is_empty() {
|
if !tunnels.is_empty() {
|
||||||
let giant_tree_dist = info
|
let giant_tree_dist = info
|
||||||
.chunk
|
.chunk
|
||||||
@ -462,6 +467,15 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let z_ranges = &tunnel_bounds
|
||||||
|
.iter()
|
||||||
|
.map(|(_, z_range, _, _, _, _)| z_range.clone())
|
||||||
|
.collect_vec();
|
||||||
|
|
||||||
|
// Compute structure samples only once for each column.
|
||||||
|
// TODO Use iter function in StructureGen2d to compute samples for the whole
|
||||||
|
// chunk once
|
||||||
|
let structure_seeds = StructureGen2d::new(34537, 24, 8).get(wpos2d);
|
||||||
for (level, z_range, horizontal, vertical, dist, tunnel) in tunnel_bounds {
|
for (level, z_range, horizontal, vertical, dist, tunnel) in tunnel_bounds {
|
||||||
write_column(
|
write_column(
|
||||||
canvas,
|
canvas,
|
||||||
@ -469,10 +483,12 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
level,
|
level,
|
||||||
wpos2d,
|
wpos2d,
|
||||||
z_range.clone(),
|
z_range.clone(),
|
||||||
|
z_ranges,
|
||||||
tunnel,
|
tunnel,
|
||||||
(horizontal, vertical, dist),
|
(horizontal, vertical, dist),
|
||||||
giant_tree_dist,
|
giant_tree_dist,
|
||||||
&mut structure_cache,
|
&mut structure_cache,
|
||||||
|
&structure_seeds,
|
||||||
rng,
|
rng,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -480,23 +496,23 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[derive(Default, Clone)]
|
||||||
#[derive(Default)]
|
pub struct Biome {
|
||||||
struct Biome {
|
|
||||||
humidity: f32,
|
humidity: f32,
|
||||||
barren: f32,
|
pub barren: f32,
|
||||||
mineral: f32,
|
mineral: f32,
|
||||||
mushroom: f32,
|
pub mushroom: f32,
|
||||||
fire: f32,
|
pub fire: f32,
|
||||||
leafy: f32,
|
pub leafy: f32,
|
||||||
dusty: f32,
|
pub dusty: f32,
|
||||||
icy: f32,
|
pub icy: f32,
|
||||||
snowy: f32,
|
pub snowy: f32,
|
||||||
crystal: f32,
|
pub crystal: f32,
|
||||||
sandy: f32,
|
pub sandy: f32,
|
||||||
depth: f32,
|
depth: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
enum CaveStructure {
|
enum CaveStructure {
|
||||||
Mushroom(Mushroom),
|
Mushroom(Mushroom),
|
||||||
Crystal(CrystalCluster),
|
Crystal(CrystalCluster),
|
||||||
@ -508,24 +524,28 @@ enum CaveStructure {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct Mushroom {
|
struct Mushroom {
|
||||||
pos: Vec3<i32>,
|
pos: Vec3<i32>,
|
||||||
stalk: f32,
|
stalk: f32,
|
||||||
head_color: Rgb<u8>,
|
head_color: Rgb<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct Crystal {
|
struct Crystal {
|
||||||
dir: Vec3<f32>,
|
dir: Vec3<f32>,
|
||||||
length: f32,
|
length: f32,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct CrystalCluster {
|
struct CrystalCluster {
|
||||||
pos: Vec3<i32>,
|
pos: Vec3<i32>,
|
||||||
crystals: Vec<Crystal>,
|
crystals: [Crystal; 5],
|
||||||
color: Rgb<u8>,
|
color: Rgb<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct Flower {
|
struct Flower {
|
||||||
pos: Vec3<i32>,
|
pos: Vec3<i32>,
|
||||||
stalk: f32,
|
stalk: f32,
|
||||||
@ -535,16 +555,19 @@ struct Flower {
|
|||||||
// rotation: Mat3<f32>,
|
// rotation: Mat3<f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[inline_tweak::tweak_fn]
|
||||||
fn write_column<R: Rng>(
|
fn write_column<R: Rng>(
|
||||||
canvas: &mut Canvas,
|
canvas: &mut Canvas,
|
||||||
col: &ColumnSample,
|
col: &ColumnSample,
|
||||||
level: u32,
|
level: u32,
|
||||||
wpos2d: Vec2<i32>,
|
wpos2d: Vec2<i32>,
|
||||||
z_range: Range<i32>,
|
z_range: Range<i32>,
|
||||||
|
z_ranges: &[Range<i32>],
|
||||||
tunnel: Tunnel,
|
tunnel: Tunnel,
|
||||||
dimensions: (f32, f32, f32),
|
dimensions: (f32, f32, f32),
|
||||||
giant_tree_factor: f32,
|
giant_tree_dist: f32,
|
||||||
structure_cache: &mut SmallCache<Vec3<i32>, Option<CaveStructure>>,
|
structure_cache: &mut SmallCache<Vec3<i32>, Option<CaveStructure>>,
|
||||||
|
structure_seeds: &[(Vec2<i32>, u32); 9],
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) {
|
) {
|
||||||
let info = canvas.info();
|
let info = canvas.info();
|
||||||
@ -558,6 +581,19 @@ fn write_column<R: Rng>(
|
|||||||
let (cave_width, max_height, dist_cave_center) = dimensions;
|
let (cave_width, max_height, dist_cave_center) = dimensions;
|
||||||
let biome = tunnel.biome_at(wpos2d.with_z(z_range.start), &info);
|
let biome = tunnel.biome_at(wpos2d.with_z(z_range.start), &info);
|
||||||
|
|
||||||
|
// Get the range, if there is any, where the current cave overlaps with other
|
||||||
|
// caves. Right now this is only used to prevent ceiling cover from being
|
||||||
|
// place
|
||||||
|
let overlap = z_ranges.iter().find_map(|other_z_range| {
|
||||||
|
if *other_z_range == z_range {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let start = z_range.start.max(other_z_range.start);
|
||||||
|
let end = z_range.end.min(other_z_range.end);
|
||||||
|
let min = z_range.start.min(other_z_range.start);
|
||||||
|
if start < end { Some(min..end) } else { None }
|
||||||
|
});
|
||||||
|
|
||||||
let stalactite = {
|
let stalactite = {
|
||||||
FastNoise2d::new(35)
|
FastNoise2d::new(35)
|
||||||
.get(wpos2d.map(|e| e as f64 / 8.0))
|
.get(wpos2d.map(|e| e as f64 / 8.0))
|
||||||
@ -604,20 +640,20 @@ fn write_column<R: Rng>(
|
|||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let basalt = if biome.fire > 0.0 {
|
let basalt = if biome.fire > 0.5 {
|
||||||
FastNoise2d::new(36)
|
FastNoise2d::new(36)
|
||||||
.get(wpos2d.map(|e| e as f64 / 32.0))
|
.get(wpos2d.map(|e| e as f64 / 16.0))
|
||||||
.mul(1.25)
|
.mul(1.25)
|
||||||
.sub(0.5)
|
.sub(0.75)
|
||||||
.max(0.0)
|
.max(0.0)
|
||||||
.mul(((cave_width + max_height) / 32.0).clamped(0.0, 1.0))
|
.mul(((cave_width + max_height) / 64.0).clamped(0.0, 1.0))
|
||||||
.mul(6.0 + cavern_height * 0.5)
|
.mul(6.0 + cavern_height * 0.5)
|
||||||
.mul(biome.fire)
|
.mul((biome.fire - 0.5).powi(3) * 8.0)
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let lava = if biome.fire > 0.0 {
|
let lava = if biome.fire > 0.5 {
|
||||||
FastNoise2d::new(37)
|
FastNoise2d::new(37)
|
||||||
.get(wpos2d.map(|e| e as f64 / 32.0))
|
.get(wpos2d.map(|e| e as f64 / 32.0))
|
||||||
.mul(0.5)
|
.mul(0.5)
|
||||||
@ -625,6 +661,7 @@ fn write_column<R: Rng>(
|
|||||||
.sub(0.2)
|
.sub(0.2)
|
||||||
.min(0.0)
|
.min(0.0)
|
||||||
// .mul((biome.temp as f64 - 1.5).mul(30.0).clamped(0.0, 1.0))
|
// .mul((biome.temp as f64 - 1.5).mul(30.0).clamped(0.0, 1.0))
|
||||||
|
.mul((cave_width / 16.0).clamped(0.5, 1.0))
|
||||||
.mul((biome.fire - 0.5).mul(30.0).clamped(0.0, 1.0))
|
.mul((biome.fire - 0.5).mul(30.0).clamped(0.0, 1.0))
|
||||||
.mul(64.0)
|
.mul(64.0)
|
||||||
.max(-32.0)
|
.max(-32.0)
|
||||||
@ -632,40 +669,35 @@ fn write_column<R: Rng>(
|
|||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let height_factor = (max_height / MAX_RADIUS * 0.5).clamped(0.0, 1.0).powf(2.0);
|
let bump = if biome
|
||||||
let width_factor = (cave_width / MAX_RADIUS * 0.5).clamped(0.0, 1.0).powf(2.0);
|
.sandy
|
||||||
let ridge = FastNoise2d::new(38)
|
.max(biome.dusty)
|
||||||
.get(wpos2d.map(|e| e as f64 / 512.0))
|
.max(biome.leafy)
|
||||||
.sub(0.25)
|
.max(biome.barren)
|
||||||
.max(0.0)
|
> 0.0
|
||||||
.mul(1.3)
|
{
|
||||||
.mul(height_factor)
|
FastNoise2d::new(38)
|
||||||
.mul(width_factor)
|
.get(wpos2d.map(|e| e as f64 / 4.0))
|
||||||
.mul(
|
.mul(1.15)
|
||||||
(0.75 * dist_cave_center)
|
.add(1.0)
|
||||||
+ max_height * (close(dist_cave_center, cave_width, cave_width * 0.7, 3)),
|
.mul(0.5)
|
||||||
)
|
.mul(((col.alt - z_range.end as f32) / 16.0).clamped(0.0, 1.0))
|
||||||
.mul(((col.alt - z_range.end as f32) / 64.0).clamped(0.0, 1.0));
|
.mul({
|
||||||
|
let (val, total) = [
|
||||||
let bump = FastNoise2d::new(39)
|
(biome.sandy, 0.9),
|
||||||
.get(wpos2d.map(|e| e as f64 / 4.0))
|
(biome.dusty, 0.5),
|
||||||
.mul(1.15)
|
(biome.leafy, 0.6),
|
||||||
.add(1.0)
|
(biome.barren, 0.6),
|
||||||
.mul(0.5)
|
]
|
||||||
.mul(((col.alt - z_range.end as f32) / 16.0).clamped(0.0, 1.0))
|
.into_iter()
|
||||||
.mul({
|
.fold((0.0, 0.0), |a, x| (a.0 + x.0.max(0.0) * x.1, a.1 + x.1));
|
||||||
let (val, total) = [
|
val / total
|
||||||
(biome.sandy, 0.9),
|
})
|
||||||
(biome.dusty, 0.5),
|
.mul(cavern_height * 0.2)
|
||||||
(biome.leafy, 0.6),
|
.clamped(0.0, 4.0)
|
||||||
(biome.barren, 0.6),
|
} else {
|
||||||
]
|
0.0
|
||||||
.into_iter()
|
};
|
||||||
.fold((0.0, 0.0), |a, x| (a.0 + x.0.max(0.0) * x.1, a.1 + x.1));
|
|
||||||
val / total
|
|
||||||
})
|
|
||||||
.mul(cavern_height * 0.2)
|
|
||||||
.clamped(0.0, 4.0);
|
|
||||||
|
|
||||||
let rand = RandomField::new(37 + level);
|
let rand = RandomField::new(37 + level);
|
||||||
|
|
||||||
@ -691,9 +723,8 @@ fn write_column<R: Rng>(
|
|||||||
1 + (!is_ice) as i32 + is_snow as i32
|
1 + (!is_ice) as i32 + is_snow as i32
|
||||||
};
|
};
|
||||||
let bedrock = z_range.start + lava as i32;
|
let bedrock = z_range.start + lava as i32;
|
||||||
let ridge_bedrock = bedrock + (ridge * 0.7) as i32;
|
let base = bedrock + (stalactite * (0.4 + stalagmite_only)) as i32;
|
||||||
let base = ridge_bedrock + (stalactite * (0.4 + stalagmite_only)) as i32;
|
let floor = base + dirt + bump as i32;
|
||||||
let floor = base + dirt + (ridge * 0.3) as i32 + bump as i32;
|
|
||||||
let ceiling =
|
let ceiling =
|
||||||
z_range.end - (stalactite * has_stalactite as i32 as f32).max(ceiling_cover) as i32;
|
z_range.end - (stalactite * has_stalactite as i32 as f32).max(ceiling_cover) as i32;
|
||||||
|
|
||||||
@ -720,7 +751,7 @@ fn write_column<R: Rng>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let ceiling_drip = ceiling
|
let ceiling_drip = ceiling
|
||||||
- if !void_above && !sky_above {
|
- if !void_above && !sky_above && overlap.is_none() {
|
||||||
let c = if biome.mushroom > 0.9 && ceiling_cover > 0.0 {
|
let c = if biome.mushroom > 0.9 && ceiling_cover > 0.0 {
|
||||||
Some((0.07, 7.0))
|
Some((0.07, 7.0))
|
||||||
} else if biome.icy > 0.9 {
|
} else if biome.icy > 0.9 {
|
||||||
@ -741,154 +772,173 @@ fn write_column<R: Rng>(
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut get_structure = |wpos: Vec3<i32>, dynamic_rng: &mut R| {
|
let structures = structure_seeds
|
||||||
for (wpos2d, seed) in StructureGen2d::new(34537, 24, 8).get(wpos.xy()) {
|
.iter()
|
||||||
let structure = if let Some(structure) =
|
.filter_map(|(wpos2d, seed)| {
|
||||||
structure_cache.get(wpos2d.with_z(tunnel.a.depth), |_| {
|
let structure = structure_cache.get(wpos2d.with_z(tunnel.a.depth), |_| {
|
||||||
let mut rng = RandomPerm::new(seed);
|
let mut rng = RandomPerm::new(*seed);
|
||||||
let (z_range, horizontal, vertical, _) =
|
let (z_range, horizontal, vertical, _) =
|
||||||
tunnel.z_range_at(wpos2d.map(|e| e as f64 + 0.5), info)?;
|
tunnel.z_range_at(wpos2d.map(|e| e as f64 + 0.5), info)?;
|
||||||
let pos = wpos2d.with_z(z_range.start);
|
let pos = wpos2d.with_z(z_range.start);
|
||||||
|
let biome = tunnel.biome_at(pos, &info);
|
||||||
|
let tunnel_intersection = || {
|
||||||
|
tunnel_bounds_at(pos.xy(), &info, &info.land())
|
||||||
|
.any(|(_, z_range, _, _, _, _)| z_range.contains(&(z_range.start - 1)))
|
||||||
|
};
|
||||||
|
|
||||||
let biome = tunnel.biome_at(pos, &info);
|
if biome.mushroom > 0.7
|
||||||
let ground_below = !tunnel_bounds_at(pos.xy(), &info, &info.land())
|
&& vertical > 16.0
|
||||||
.any(|(_, z_range, _, _, _, _)| z_range.contains(&(z_range.start - 1)));
|
&& rng.gen_bool(
|
||||||
if !ground_below {
|
0.5 * close(vertical, MAX_RADIUS, MAX_RADIUS - 16.0, 2) as f64
|
||||||
|
* close(biome.mushroom, 1.0, 0.7, 1) as f64,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if tunnel_intersection() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
let purp = rng.gen_range(0..50);
|
||||||
|
Some(CaveStructure::Mushroom(Mushroom {
|
||||||
|
pos,
|
||||||
|
stalk: 8.0
|
||||||
|
+ rng.gen::<f32>().powf(2.0)
|
||||||
|
* (z_range.end - z_range.start - 8) as f32
|
||||||
|
* 0.75,
|
||||||
|
head_color: Rgb::new(
|
||||||
|
40 + purp,
|
||||||
|
rng.gen_range(60..120),
|
||||||
|
rng.gen_range(80..200) + purp,
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
} else if biome.crystal > 0.5
|
||||||
|
&& rng.gen_bool(0.4 * close(biome.crystal, 1.0, 0.7, 2) as f64)
|
||||||
|
{
|
||||||
|
if tunnel_intersection() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let on_ground = rng.gen_bool(0.6);
|
||||||
|
let pos = wpos2d.with_z(if on_ground {
|
||||||
|
z_range.start
|
||||||
|
} else {
|
||||||
|
z_range.end
|
||||||
|
});
|
||||||
|
|
||||||
if biome.mushroom > 0.7
|
let max_length = (48.0 * close(vertical, MAX_RADIUS, MAX_RADIUS, 1)).max(12.0);
|
||||||
&& vertical > 16.0
|
let length = rng.gen_range(8.0..max_length);
|
||||||
&& rng.gen_bool(
|
let radius =
|
||||||
0.5 * close(vertical, MAX_RADIUS, MAX_RADIUS - 16.0, 2) as f64
|
Lerp::lerp(2.0, 4.5, length / max_length + rng.gen_range(-0.1..0.1));
|
||||||
* close(biome.mushroom, 1.0, 0.7, 1) as f64,
|
let dir = Vec3::new(
|
||||||
)
|
rng.gen_range(-3.0..3.0),
|
||||||
{
|
rng.gen_range(-3.0..3.0),
|
||||||
let purp = rng.gen_range(0..50);
|
rng.gen_range(0.5..10.0) * if on_ground { 1.0 } else { -1.0 },
|
||||||
Some(CaveStructure::Mushroom(Mushroom {
|
)
|
||||||
pos,
|
.normalized();
|
||||||
stalk: 8.0
|
|
||||||
+ rng.gen::<f32>().powf(2.0)
|
|
||||||
* (z_range.end - z_range.start - 8) as f32
|
|
||||||
* 0.75,
|
|
||||||
head_color: Rgb::new(
|
|
||||||
40 + purp,
|
|
||||||
rng.gen_range(60..120),
|
|
||||||
rng.gen_range(80..200) + purp,
|
|
||||||
),
|
|
||||||
}))
|
|
||||||
} else if biome.crystal > 0.5
|
|
||||||
&& rng.gen_bool(0.4 * close(biome.crystal, 1.0, 0.7, 2) as f64)
|
|
||||||
{
|
|
||||||
let on_ground = rng.gen_bool(0.6);
|
|
||||||
let pos = wpos2d.with_z(if on_ground {
|
|
||||||
z_range.start
|
|
||||||
} else {
|
|
||||||
z_range.end
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut crystals: Vec<Crystal> = Vec::new();
|
let mut gen_crystal = || Crystal {
|
||||||
let max_length =
|
dir: Vec3::new(
|
||||||
(48.0 * close(vertical, MAX_RADIUS, MAX_RADIUS, 1)).max(12.0);
|
rng.gen_range(-1.0..1.0),
|
||||||
let length = rng.gen_range(8.0..max_length);
|
rng.gen_range(-1.0..1.0),
|
||||||
let radius =
|
(dir.z + rng.gen_range(-0.2..0.2)).clamped(0.0, 1.0),
|
||||||
Lerp::lerp(2.0, 4.5, length / max_length + rng.gen_range(-0.1..0.1));
|
),
|
||||||
let dir = Vec3::new(
|
length: length * rng.gen_range(0.3..0.8),
|
||||||
rng.gen_range(-3.0..3.0),
|
radius: (radius * rng.gen_range(0.5..0.8)).max(1.0),
|
||||||
rng.gen_range(-3.0..3.0),
|
};
|
||||||
rng.gen_range(0.5..10.0) * if on_ground { 1.0 } else { -1.0 },
|
|
||||||
)
|
|
||||||
.normalized();
|
|
||||||
|
|
||||||
crystals.push(Crystal {
|
let crystals = [
|
||||||
|
Crystal {
|
||||||
dir,
|
dir,
|
||||||
length,
|
length,
|
||||||
radius,
|
radius,
|
||||||
});
|
},
|
||||||
|
gen_crystal(),
|
||||||
|
gen_crystal(),
|
||||||
|
gen_crystal(),
|
||||||
|
gen_crystal(),
|
||||||
|
];
|
||||||
|
|
||||||
(0..4).for_each(|_| {
|
let purple = rng.gen_range(25..75);
|
||||||
crystals.push(Crystal {
|
let blue = (rng.gen_range(45.0..75.0) * biome.icy) as u8;
|
||||||
dir: Vec3::new(
|
Some(CaveStructure::Crystal(CrystalCluster {
|
||||||
rng.gen_range(-1.0..1.0),
|
pos,
|
||||||
rng.gen_range(-1.0..1.0),
|
crystals,
|
||||||
(dir.z + rng.gen_range(-0.2..0.2)).clamped(0.0, 1.0),
|
color: Rgb::new(
|
||||||
),
|
255 - blue * 2,
|
||||||
length: length * rng.gen_range(0.3..0.8),
|
255 - blue - purple,
|
||||||
radius: (radius * rng.gen_range(0.5..0.8)).max(1.0),
|
200 + rng.gen_range(25..55),
|
||||||
});
|
),
|
||||||
});
|
}))
|
||||||
|
} else if biome.leafy > 0.8
|
||||||
let purple = rng.gen_range(25..75);
|
&& vertical > 16.0
|
||||||
let blue = (rng.gen_range(45.0..75.0) * biome.icy) as u8;
|
&& horizontal > 16.0
|
||||||
|
&& rng.gen_bool(
|
||||||
Some(CaveStructure::Crystal(CrystalCluster {
|
0.25 * (close(vertical, MAX_RADIUS, MAX_RADIUS - 16.0, 2)
|
||||||
pos,
|
* close(horizontal, MAX_RADIUS, MAX_RADIUS - 16.0, 2)
|
||||||
crystals,
|
* biome.leafy) as f64,
|
||||||
color: Rgb::new(
|
)
|
||||||
255 - blue * 2,
|
{
|
||||||
255 - blue - purple,
|
if tunnel_intersection() {
|
||||||
200 + rng.gen_range(25..55),
|
return None;
|
||||||
),
|
|
||||||
}))
|
|
||||||
} else if biome.leafy > 0.8
|
|
||||||
&& vertical > 16.0
|
|
||||||
&& horizontal > 8.0
|
|
||||||
&& rng.gen_bool(
|
|
||||||
0.25 * (close(vertical, MAX_RADIUS, MAX_RADIUS - 16.0, 2)
|
|
||||||
* close(horizontal, MAX_RADIUS, MAX_RADIUS - 8.0, 2)
|
|
||||||
* biome.leafy) as f64,
|
|
||||||
)
|
|
||||||
{
|
|
||||||
let petal_radius = rng.gen_range(8.0..16.0);
|
|
||||||
Some(CaveStructure::Flower(Flower {
|
|
||||||
pos,
|
|
||||||
stalk: 6.0
|
|
||||||
+ rng.gen::<f32>().powf(2.0)
|
|
||||||
* (z_range.end - z_range.start - 8) as f32
|
|
||||||
* 0.75,
|
|
||||||
petals: rng.gen_range(1..5) * 2 + 1,
|
|
||||||
petal_height: 0.4 * petal_radius * (1.0 + rng.gen::<f32>().powf(2.0)),
|
|
||||||
petal_radius,
|
|
||||||
}))
|
|
||||||
} else if (biome.leafy > 0.7 || giant_tree_factor > 0.0)
|
|
||||||
&& rng.gen_bool(
|
|
||||||
(0.5 * close(biome.leafy, 1.0, 0.5, 1).max(1.0 + giant_tree_factor)
|
|
||||||
as f64)
|
|
||||||
.clamped(0.0, 1.0),
|
|
||||||
)
|
|
||||||
{
|
|
||||||
Some(CaveStructure::GiantRoot {
|
|
||||||
pos,
|
|
||||||
radius: rng.gen_range(
|
|
||||||
1.5..(3.5
|
|
||||||
+ close(vertical, MAX_RADIUS, MAX_RADIUS / 2.0, 2) * 3.0
|
|
||||||
+ close(horizontal, MAX_RADIUS, MAX_RADIUS / 2.0, 2) * 3.0),
|
|
||||||
),
|
|
||||||
height: (z_range.end - z_range.start) as f32,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}) {
|
let petal_radius = rng.gen_range(8.0..16.0);
|
||||||
structure
|
Some(CaveStructure::Flower(Flower {
|
||||||
} else {
|
pos,
|
||||||
continue;
|
stalk: 6.0
|
||||||
};
|
+ rng.gen::<f32>().powf(2.0)
|
||||||
|
* (z_range.end - z_range.start - 8) as f32
|
||||||
|
* 0.75,
|
||||||
|
petals: rng.gen_range(1..5) * 2 + 1,
|
||||||
|
petal_height: 0.4 * petal_radius * (1.0 + rng.gen::<f32>().powf(2.0)),
|
||||||
|
petal_radius,
|
||||||
|
}))
|
||||||
|
} else if (biome.leafy > 0.7 || giant_tree_dist > 0.0)
|
||||||
|
&& rng.gen_bool(
|
||||||
|
(0.5 * close(biome.leafy, 1.0, 0.5, 1).max(1.0 + giant_tree_dist) as f64)
|
||||||
|
.clamped(0.0, 1.0),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if tunnel_intersection() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(CaveStructure::GiantRoot {
|
||||||
|
pos,
|
||||||
|
radius: rng.gen_range(
|
||||||
|
2.5..(3.5
|
||||||
|
+ close(vertical, MAX_RADIUS, MAX_RADIUS / 2.0, 2) * 3.0
|
||||||
|
+ close(horizontal, MAX_RADIUS, MAX_RADIUS / 2.0, 2) * 3.0),
|
||||||
|
),
|
||||||
|
height: (z_range.end - z_range.start) as f32,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO Some way to not clone here?
|
||||||
|
structure
|
||||||
|
.as_ref()
|
||||||
|
.map(|structure| (*seed, structure.clone()))
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
let get_structure = |wpos: Vec3<i32>, dynamic_rng: &mut R| {
|
||||||
|
let warp = |wposf: Vec3<f64>, freq: f64, amp: Vec3<f32>, seed: u32| -> Vec3<f32> {
|
||||||
|
let xy = wposf.xy();
|
||||||
|
let xz = Vec2::new(wposf.x, wposf.z);
|
||||||
|
let yz = Vec2::new(wposf.y, wposf.z);
|
||||||
|
Vec3::new(
|
||||||
|
FastNoise2d::new(seed).get(yz * freq),
|
||||||
|
FastNoise2d::new(seed).get(xz * freq),
|
||||||
|
FastNoise2d::new(seed).get(xy * freq),
|
||||||
|
) * amp
|
||||||
|
};
|
||||||
|
for (seed, structure) in structures.iter() {
|
||||||
|
let seed = *seed;
|
||||||
match structure {
|
match structure {
|
||||||
CaveStructure::Mushroom(mushroom) => {
|
CaveStructure::Mushroom(mushroom) => {
|
||||||
let wposf = wpos.map(|e| e as f64);
|
let wposf = wpos.map(|e| e as f64);
|
||||||
let warp_freq = 1.0 / 32.0;
|
let warp_freq = 1.0 / 32.0;
|
||||||
let warp_amp = Vec3::new(12.0, 12.0, 12.0);
|
let warp_amp = Vec3::new(12.0, 12.0, 12.0);
|
||||||
let xy = wposf.xy();
|
let warp_offset = warp(wposf, warp_freq, warp_amp, seed);
|
||||||
let xz = Vec2::new(wposf.x, wposf.z);
|
|
||||||
let yz = Vec2::new(wposf.y, wposf.z);
|
|
||||||
let wposf_warped = wposf.map(|e| e as f32)
|
let wposf_warped = wposf.map(|e| e as f32)
|
||||||
+ Vec3::new(
|
+ warp_offset
|
||||||
FastNoise2d::new(seed).get(yz * warp_freq),
|
|
||||||
FastNoise2d::new(seed).get(xz * warp_freq),
|
|
||||||
FastNoise2d::new(seed).get(xy * warp_freq),
|
|
||||||
) * warp_amp
|
|
||||||
* (wposf.z as f32 - mushroom.pos.z as f32)
|
* (wposf.z as f32 - mushroom.pos.z as f32)
|
||||||
.mul(0.1)
|
.mul(0.1)
|
||||||
.clamped(0.0, 1.0);
|
.clamped(0.0, 1.0);
|
||||||
@ -1011,15 +1061,9 @@ fn write_column<R: Rng>(
|
|||||||
let wposf = wpos.map(|e| e as f64);
|
let wposf = wpos.map(|e| e as f64);
|
||||||
let warp_freq = 1.0 / 16.0;
|
let warp_freq = 1.0 / 16.0;
|
||||||
let warp_amp = Vec3::new(8.0, 8.0, 8.0);
|
let warp_amp = Vec3::new(8.0, 8.0, 8.0);
|
||||||
let xy = wposf.xy();
|
let warp_offset = warp(wposf, warp_freq, warp_amp, seed);
|
||||||
let xz = Vec2::new(wposf.x, wposf.z);
|
|
||||||
let yz = Vec2::new(wposf.y, wposf.z);
|
|
||||||
let wposf_warped = wposf.map(|e| e as f32)
|
let wposf_warped = wposf.map(|e| e as f32)
|
||||||
+ Vec3::new(
|
+ warp_offset
|
||||||
FastNoise2d::new(seed).get(yz * warp_freq),
|
|
||||||
FastNoise2d::new(seed).get(xz * warp_freq),
|
|
||||||
FastNoise2d::new(seed).get(xy * warp_freq),
|
|
||||||
) * warp_amp
|
|
||||||
* (wposf.z as f32 - flower.pos.z as f32)
|
* (wposf.z as f32 - flower.pos.z as f32)
|
||||||
.mul(1.0 / flower.stalk)
|
.mul(1.0 / flower.stalk)
|
||||||
.sub(1.0)
|
.sub(1.0)
|
||||||
@ -1044,8 +1088,7 @@ fn write_column<R: Rng>(
|
|||||||
let dist_sq = rpos.xy().magnitude_squared();
|
let dist_sq = rpos.xy().magnitude_squared();
|
||||||
let petal_radius_sq = flower.petal_radius.powi(2);
|
let petal_radius_sq = flower.petal_radius.powi(2);
|
||||||
if dist_sq < petal_radius_sq {
|
if dist_sq < petal_radius_sq {
|
||||||
let petal_height_at =
|
let petal_height_at = (dist_sq / petal_radius_sq) * flower.petal_height;
|
||||||
(dist_sq / petal_radius_sq).powf(1.0) * flower.petal_height;
|
|
||||||
if rpos.z > petal_height_at - 1.0
|
if rpos.z > petal_height_at - 1.0
|
||||||
&& rpos.z <= petal_height_at + petal_thickness
|
&& rpos.z <= petal_height_at + petal_thickness
|
||||||
{
|
{
|
||||||
@ -1095,7 +1138,7 @@ fn write_column<R: Rng>(
|
|||||||
.powi(2)
|
.powi(2)
|
||||||
{
|
{
|
||||||
return Some(Block::new(
|
return Some(Block::new(
|
||||||
BlockKind::GlowingMushroom,
|
BlockKind::GlowingWeakRock,
|
||||||
Rgb::new(239, 192, 0),
|
Rgb::new(239, 192, 0),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -1107,17 +1150,10 @@ fn write_column<R: Rng>(
|
|||||||
height,
|
height,
|
||||||
} => {
|
} => {
|
||||||
let wposf = wpos.map(|e| e as f64);
|
let wposf = wpos.map(|e| e as f64);
|
||||||
let warp_freq = 1.0 / 32.0;
|
let warp_freq = 1.0 / 16.0;
|
||||||
let warp_amp = Vec3::new(20.0, 20.0, 20.0);
|
let warp_amp = Vec3::new(8.0, 8.0, 8.0);
|
||||||
let xy = wposf.xy();
|
let warp_offset = warp(wposf, warp_freq, warp_amp, seed);
|
||||||
let xz = Vec2::new(wposf.x, wposf.z);
|
let wposf_warped = wposf.map(|e| e as f32) + warp_offset;
|
||||||
let yz = Vec2::new(wposf.y, wposf.z);
|
|
||||||
let wposf_warped = wposf.map(|e| e as f32)
|
|
||||||
+ Vec3::new(
|
|
||||||
FastNoise2d::new(seed).get(yz * warp_freq),
|
|
||||||
FastNoise2d::new(seed).get(xz * warp_freq),
|
|
||||||
FastNoise2d::new(seed).get(xy * warp_freq),
|
|
||||||
) * warp_amp;
|
|
||||||
let rpos = wposf_warped - pos.map(|e| e as f32);
|
let rpos = wposf_warped - pos.map(|e| e as f32);
|
||||||
let dist_sq = rpos.xy().magnitude_squared();
|
let dist_sq = rpos.xy().magnitude_squared();
|
||||||
if dist_sq < radius.powi(2) {
|
if dist_sq < radius.powi(2) {
|
||||||
@ -1142,7 +1178,7 @@ fn write_column<R: Rng>(
|
|||||||
for z in bedrock..z_range.end {
|
for z in bedrock..z_range.end {
|
||||||
let wpos = wpos2d.with_z(z);
|
let wpos = wpos2d.with_z(z);
|
||||||
let mut try_spawn_entity = false;
|
let mut try_spawn_entity = false;
|
||||||
canvas.map_resource(wpos, |_block| {
|
canvas.set(wpos, {
|
||||||
if z < z_range.start - 4 && !void_below {
|
if z < z_range.start - 4 && !void_below {
|
||||||
Block::new(BlockKind::Lava, Rgb::new(255, 65, 0))
|
Block::new(BlockKind::Lava, Rgb::new(255, 65, 0))
|
||||||
} else if basalt > 0.0
|
} else if basalt > 0.0
|
||||||
@ -1156,9 +1192,10 @@ fn write_column<R: Rng>(
|
|||||||
&& !void_below
|
&& !void_below
|
||||||
{
|
{
|
||||||
Block::new(BlockKind::Rock, Rgb::new(50, 35, 75))
|
Block::new(BlockKind::Rock, Rgb::new(50, 35, 75))
|
||||||
} else if z < ridge_bedrock && !void_below {
|
} else if (z < base && !void_below)
|
||||||
Block::new(BlockKind::Rock, col.stone_col)
|
|| ((z >= ceiling && !void_above)
|
||||||
} else if (z < base && !void_below) || (z >= ceiling && !void_above) {
|
&& !(ceiling_cover > 0.0 && overlap.as_ref().map_or(false, |o| o.contains(&z))))
|
||||||
|
{
|
||||||
let stalactite: Rgb<i16> = Lerp::lerp_unclamped(
|
let stalactite: Rgb<i16> = Lerp::lerp_unclamped(
|
||||||
Lerp::lerp_unclamped(
|
Lerp::lerp_unclamped(
|
||||||
Lerp::lerp_unclamped(
|
Lerp::lerp_unclamped(
|
||||||
@ -1347,7 +1384,6 @@ fn write_column<R: Rng>(
|
|||||||
[
|
[
|
||||||
(SpriteKind::GlowMushroom, 0.5),
|
(SpriteKind::GlowMushroom, 0.5),
|
||||||
(SpriteKind::Mushroom, 0.25),
|
(SpriteKind::Mushroom, 0.25),
|
||||||
(SpriteKind::GrassBlue, 0.0),
|
|
||||||
(SpriteKind::GrassBlueMedium, 1.5),
|
(SpriteKind::GrassBlueMedium, 1.5),
|
||||||
(SpriteKind::GrassBlueLong, 2.0),
|
(SpriteKind::GrassBlueLong, 2.0),
|
||||||
(SpriteKind::Moonbell, 0.01),
|
(SpriteKind::Moonbell, 0.01),
|
||||||
@ -1360,7 +1396,7 @@ fn write_column<R: Rng>(
|
|||||||
&& biome.leafy > 0.4
|
&& biome.leafy > 0.4
|
||||||
&& rand.chance(
|
&& rand.chance(
|
||||||
wpos2d.with_z(15),
|
wpos2d.with_z(15),
|
||||||
biome.leafy.powi(2) * 0.25 * col.marble_mid,
|
biome.leafy.powi(2) * col.marble_mid * (biome.humidity * 1.3) * 0.25,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let mixed = col.marble.add(col.marble_small.sub(0.5).mul(0.25));
|
let mixed = col.marble.add(col.marble_small.sub(0.5).mul(0.25));
|
||||||
@ -1368,7 +1404,6 @@ fn write_column<R: Rng>(
|
|||||||
return [
|
return [
|
||||||
(SpriteKind::LongGrass, 1.0),
|
(SpriteKind::LongGrass, 1.0),
|
||||||
(SpriteKind::MediumGrass, 2.0),
|
(SpriteKind::MediumGrass, 2.0),
|
||||||
(SpriteKind::ShortGrass, 0.0),
|
|
||||||
(SpriteKind::JungleFern, 0.5),
|
(SpriteKind::JungleFern, 0.5),
|
||||||
(SpriteKind::JungleRedGrass, 0.35),
|
(SpriteKind::JungleRedGrass, 0.35),
|
||||||
(SpriteKind::Fern, 0.75),
|
(SpriteKind::Fern, 0.75),
|
||||||
@ -1395,7 +1430,6 @@ fn write_column<R: Rng>(
|
|||||||
return [
|
return [
|
||||||
(SpriteKind::LongGrass, 1.0),
|
(SpriteKind::LongGrass, 1.0),
|
||||||
(SpriteKind::MediumGrass, 2.0),
|
(SpriteKind::MediumGrass, 2.0),
|
||||||
(SpriteKind::ShortGrass, 0.0),
|
|
||||||
(SpriteKind::JungleFern, 0.5),
|
(SpriteKind::JungleFern, 0.5),
|
||||||
(SpriteKind::JungleLeafyPlant, 0.5),
|
(SpriteKind::JungleLeafyPlant, 0.5),
|
||||||
(SpriteKind::JungleRedGrass, 0.35),
|
(SpriteKind::JungleRedGrass, 0.35),
|
||||||
@ -1517,14 +1551,18 @@ fn write_column<R: Rng>(
|
|||||||
Block::air(sprite)
|
Block::air(sprite)
|
||||||
} else if let Some(sprite) = (z == ceiling - 1 && !void_above)
|
} else if let Some(sprite) = (z == ceiling - 1 && !void_above)
|
||||||
.then(|| {
|
.then(|| {
|
||||||
if biome.mushroom > 0.5 && rand.chance(wpos2d.with_z(3), biome.mushroom * 0.01)
|
if biome.mushroom > 0.5
|
||||||
|
&& rand.chance(wpos2d.with_z(3), biome.mushroom.powi(2) * 0.01)
|
||||||
{
|
{
|
||||||
[(SpriteKind::MycelBlue, 0.75), (SpriteKind::Mold, 1.0)]
|
[(SpriteKind::MycelBlue, 0.75), (SpriteKind::Mold, 1.0)]
|
||||||
.choose_weighted(rng, |(_, w)| *w)
|
.choose_weighted(rng, |(_, w)| *w)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|s| s.0)
|
.map(|s| s.0)
|
||||||
} else if biome.leafy > 0.4
|
} else if biome.leafy > 0.4
|
||||||
&& rand.chance(wpos2d.with_z(4), biome.leafy * 0.015)
|
&& rand.chance(
|
||||||
|
wpos2d.with_z(4),
|
||||||
|
biome.leafy * (biome.humidity * 1.3) * 0.015,
|
||||||
|
)
|
||||||
{
|
{
|
||||||
[
|
[
|
||||||
(SpriteKind::Liana, 1.5),
|
(SpriteKind::Liana, 1.5),
|
||||||
@ -1559,6 +1597,7 @@ fn write_column<R: Rng>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #[inline_tweak::tweak_fn]
|
||||||
fn apply_entity_spawns<R: Rng>(canvas: &mut Canvas, wpos: Vec3<i32>, biome: &Biome, rng: &mut R) {
|
fn apply_entity_spawns<R: Rng>(canvas: &mut Canvas, wpos: Vec3<i32>, biome: &Biome, rng: &mut R) {
|
||||||
if RandomField::new(canvas.info().index().seed).chance(wpos, 0.035) {
|
if RandomField::new(canvas.info().index().seed).chance(wpos, 0.035) {
|
||||||
if let Some(entity_asset) = [
|
if let Some(entity_asset) = [
|
||||||
@ -1656,7 +1695,7 @@ fn apply_entity_spawns<R: Rng>(canvas: &mut Canvas, wpos: Vec3<i32>, biome: &Bio
|
|||||||
(
|
(
|
||||||
Some("common.entity.wild.aggressive.cave_spider"),
|
Some("common.entity.wild.aggressive.cave_spider"),
|
||||||
biome.dusty + 0.0,
|
biome.dusty + 0.0,
|
||||||
0.4,
|
0.05,
|
||||||
0.5,
|
0.5,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -1706,19 +1745,19 @@ fn apply_entity_spawns<R: Rng>(canvas: &mut Canvas, wpos: Vec3<i32>, biome: &Bio
|
|||||||
(
|
(
|
||||||
Some("common.entity.wild.aggressive.lavadrake"),
|
Some("common.entity.wild.aggressive.lavadrake"),
|
||||||
biome.fire + 0.0,
|
biome.fire + 0.0,
|
||||||
0.5,
|
0.15,
|
||||||
0.5,
|
0.5,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Some("common.entity.wild.peaceful.crawler_molten"),
|
Some("common.entity.wild.peaceful.crawler_molten"),
|
||||||
biome.fire + 0.0,
|
biome.fire + 0.0,
|
||||||
0.5,
|
0.2,
|
||||||
0.5,
|
0.5,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
Some("common.entity.wild.aggressive.cave_salamander"),
|
Some("common.entity.wild.aggressive.cave_salamander"),
|
||||||
biome.fire + 0.0,
|
biome.fire + 0.0,
|
||||||
0.5,
|
0.4,
|
||||||
0.5,
|
0.5,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
@ -1763,7 +1802,7 @@ fn apply_entity_spawns<R: Rng>(canvas: &mut Canvas, wpos: Vec3<i32>, biome: &Bio
|
|||||||
(
|
(
|
||||||
Some("common.entity.wild.aggressive.akhlut"),
|
Some("common.entity.wild.aggressive.akhlut"),
|
||||||
(biome.snowy.max(biome.icy) + 0.1),
|
(biome.snowy.max(biome.icy) + 0.1),
|
||||||
0.05,
|
0.01,
|
||||||
0.5,
|
0.5,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
Loading…
Reference in New Issue
Block a user