From e97d58011e7ab2ad70a1d7b3cc3ef261bc116a0d Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sat, 2 Jul 2022 17:41:44 +0100 Subject: [PATCH] Made trees and cave entrances play better --- world/src/index.rs | 4 +++- world/src/layer/cave.rs | 36 ++++++++++++++++++------------------ world/src/layer/shrub.rs | 3 +++ world/src/layer/tree.rs | 16 +++++++++++++--- world/src/lib.rs | 4 ++-- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/world/src/index.rs b/world/src/index.rs index 35ea35d1be..5fdaa6bff9 100644 --- a/world/src/index.rs +++ b/world/src/index.rs @@ -9,7 +9,7 @@ use common::{ trade::{SiteId, SitePrices}, }; use core::ops::Deref; -use noise::{Seedable, SuperSimplex}; +use noise::{Fbm, Seedable, SuperSimplex}; use std::sync::Arc; const WORLD_COLORS_MANIFEST: &str = "world.style.colors"; @@ -136,6 +136,7 @@ impl IndexOwned { pub struct Noise { pub cave_nz: SuperSimplex, pub scatter_nz: SuperSimplex, + pub cave_fbm_nz: Fbm, } impl Noise { @@ -143,6 +144,7 @@ impl Noise { Self { cave_nz: SuperSimplex::new().set_seed(seed + 0), scatter_nz: SuperSimplex::new().set_seed(seed + 1), + cave_fbm_nz: Fbm::new().set_seed(seed + 2), } } } diff --git a/world/src/layer/cave.rs b/world/src/layer/cave.rs index 5777a0c829..4e103b3850 100644 --- a/world/src/layer/cave.rs +++ b/world/src/layer/cave.rs @@ -2,7 +2,7 @@ use super::scatter::close; use crate::{ util::{sampler::Sampler, FastNoise, RandomField, RandomPerm, StructureGen2d, LOCALITY}, - Canvas, CanvasInfo, ColumnSample, Land, + Canvas, CanvasInfo, ColumnSample, IndexRef, Land, }; use common::{ terrain::{ @@ -11,7 +11,7 @@ use common::{ }, vol::RectVolSize, }; -use noise::{Fbm, NoiseFn}; +use noise::NoiseFn; use rand::prelude::*; use std::{ cmp::Ordering, @@ -105,7 +105,7 @@ pub fn surface_entrances<'a>(land: &'a Land) -> impl Iterator> }) } -struct Tunnel { +pub struct Tunnel { a: Node, b: Node, curve: f32, @@ -120,7 +120,7 @@ impl Tunnel { .map(|e| e as f32) } - fn z_range_at(&self, wposf: Vec2, nz: &Fbm) -> Option<(Range, f64)> { + fn z_range_at(&self, wposf: Vec2, index: IndexRef) -> Option<(Range, f64)> { let start = self.a.wpos.xy().map(|e| e as f64 + 0.5); let end = self.b.wpos.xy().map(|e| e as f64 + 0.5); @@ -140,14 +140,19 @@ impl Tunnel { let radius = Lerp::lerp( radius.start, radius.end, - (nz.get((wposf.with_z(self.a.wpos.z as f64) / 200.0).into_array()) * 2.0 * 0.5 + (index + .noise + .cave_fbm_nz + .get((wposf.with_z(self.a.wpos.z as f64) / 200.0).into_array()) + * 2.0 + * 0.5 + 0.5) .clamped(0.0, 1.0) .powf(3.0), ); // Lerp::lerp(8.0, 24.0, (t * 0.075 * tunnel_len).sin() * 0.5 + 0.5); let height_here = (1.0 - dist / radius).max(0.0).powf(0.3) * radius; if height_here > 0.0 { - let z_offs = nz.get((wposf / 512.0).into_array()) + let z_offs = index.noise.cave_fbm_nz.get((wposf / 512.0).into_array()) * 48.0 * ((1.0 - (t - 0.5).abs() * 2.0) * 8.0).min(1.0); let depth = Lerp::lerp(self.a.wpos.z as f64, self.b.wpos.z as f64, t) + z_offs; @@ -306,13 +311,11 @@ fn tunnels_down_from<'a>( .filter_map(move |rpos| tunnel_below_from_cell(col_cell + rpos, level, land)) } -fn tunnel_bounds_at<'a>( +pub fn tunnel_bounds_at<'a>( wpos2d: Vec2, info: &'a CanvasInfo, land: &'a Land, - nz: &'a Fbm, ) -> impl Iterator, f64, Tunnel)> + 'a { - let col = info.col_or_gen(wpos2d); let wposf = wpos2d.map(|e| e as f64 + 0.5); info.col_or_gen(wpos2d).into_iter().flat_map(move |col| { let col_alt = col.alt; @@ -323,7 +326,7 @@ fn tunnel_bounds_at<'a>( tunnels_at(wpos2d, level, land) .chain(tunnels_down_from(wpos2d, level - 1, land)) .filter_map(move |tunnel| { - let (z_range, radius) = tunnel.z_range_at(wposf, nz)?; + let (z_range, radius) = tunnel.z_range_at(wposf, info.index())?; // Avoid cave entrances intersecting water let z_range = Lerp::lerp( z_range.end, @@ -341,18 +344,17 @@ fn tunnel_bounds_at<'a>( } pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) { - let nz = Fbm::new(); let info = canvas.info(); let mut mushroom_cache = HashMap::new(); canvas.foreach_col(|canvas, wpos2d, col| { let wposf = wpos2d.map(|e| e as f64 + 0.5); let land = info.land(); - let tunnel_bounds = tunnel_bounds_at(wpos2d, &info, &land, &nz).collect::>(); + let tunnel_bounds = tunnel_bounds_at(wpos2d, &info, &land).collect::>(); // First, clear out tunnels for (_, z_range, _, tunnel) in &tunnel_bounds { - for z in z_range.clone() { + for z in z_range.start..z_range.end.min(col.alt as i32 + 1) { canvas.set(wpos2d.with_z(z), Block::air(SpriteKind::Empty)); } } @@ -366,7 +368,6 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) { z_range.clone(), tunnel, radius, - &nz, &mut mushroom_cache, rng, ); @@ -399,7 +400,6 @@ fn write_column( z_range: Range, tunnel: Tunnel, radius: f64, - nz: &Fbm, mushroom_cache: &mut HashMap<(Vec3, Vec2), Option>, rng: &mut R, ) { @@ -489,7 +489,7 @@ fn write_column( .or_insert_with(|| { let mut rng = RandomPerm::new(seed); let (z_range, radius) = - tunnel.z_range_at(wpos2d.map(|e| e as f64 + 0.5), nz)?; + tunnel.z_range_at(wpos2d.map(|e| e as f64 + 0.5), info.index())?; let (cavern_bottom, cavern_top, floor, water_level) = ( z_range.start, z_range.end, @@ -500,7 +500,7 @@ fn write_column( if rng.gen_bool(0.5 * close(radius as f32, 64.0, 48.0) as f64) && tunnel.biome_at(pos, &info).mushroom > 0.5 // Ensure that we're not placing the mushroom over a void - && !tunnel_bounds_at(pos.xy(), &info, &info.land(), nz) + && !tunnel_bounds_at(pos.xy(), &info, &info.land()) .any(|(_, z_range, _, _)| z_range.contains(&(cavern_bottom - 1))) // && pos.z as i32 > water_level - 2 { @@ -783,7 +783,7 @@ fn write_column( } { Block::new(BlockKind::Rock, col.stone_col) } else { - get_mushroom(wpos, rng).unwrap_or(Block::air(SpriteKind::Empty)) + get_mushroom(wpos, rng).unwrap_or(block) } }); } diff --git a/world/src/layer/shrub.rs b/world/src/layer/shrub.rs index 2c975e002a..d37ba37e49 100644 --- a/world/src/layer/shrub.rs +++ b/world/src/layer/shrub.rs @@ -1,5 +1,6 @@ use crate::{ all::ForestKind, + layer::cave::tunnel_bounds_at, util::{gen_cache::StructureGenCache, seed_expan, Sampler, StructureGen2d, UnitChooser}, Canvas, }; @@ -44,6 +45,8 @@ pub fn apply_shrubs_to(canvas: &mut Canvas, _dynamic_rng: &mut impl Rng) { && col.alt > col.water_level && col.spawn_rate > 0.9 && col.path.map_or(true, |(d, _, _, _)| d > 6.0) + && !tunnel_bounds_at(wpos, &info, &info.land()) + .any(|(_, z_range, _, _)| z_range.contains(&(col.alt as i32 - 1))) { let kind = *info .chunks() diff --git a/world/src/layer/tree.rs b/world/src/layer/tree.rs index 73fca950d4..05ce3162e8 100644 --- a/world/src/layer/tree.rs +++ b/world/src/layer/tree.rs @@ -2,8 +2,9 @@ use crate::{ all::*, block::block_from_structure, column::ColumnGen, + layer::cave::tunnel_bounds_at, util::{gen_cache::StructureGenCache, RandomPerm, Sampler, UnitChooser}, - Canvas, ColumnSample, + Canvas, CanvasInfo, ColumnSample, }; use common::{ assets::AssetHandle, @@ -34,11 +35,20 @@ static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7); static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F); // Ensure that it's valid to place a tree here -pub fn tree_valid_at(col: &ColumnSample, seed: u32) -> bool { +pub fn tree_valid_at( + wpos: Vec2, + col: &ColumnSample, + info: Option>, + seed: u32, +) -> bool { if col.alt < col.water_level || col.spawn_rate < 0.9 || col.water_dist.map(|d| d < 8.0).unwrap_or(false) || col.path.map(|(d, _, _, _)| d < 12.0).unwrap_or(false) + || info.map_or(false, |info| { + tunnel_bounds_at(wpos, &info, &info.land()) + .any(|(_, z_range, _, _)| z_range.contains(&(col.alt as i32 - 1))) + }) { return false; } @@ -85,7 +95,7 @@ pub fn apply_trees_to( let col = ColumnGen::new(info.chunks()).get((wpos, info.index(), calendar))?; - if !tree_valid_at(&col, seed) { + if !tree_valid_at(wpos, &col, Some(info), seed) { return None; } diff --git a/world/src/lib.rs b/world/src/lib.rs index 7e7ea96e98..d850e6c0c9 100644 --- a/world/src/lib.rs +++ b/world/src/lib.rs @@ -378,6 +378,7 @@ impl World { if index.features.caves { layer::apply_caves_to(&mut canvas, &mut dynamic_rng); } + layer::apply_caves2_to(&mut canvas, &mut dynamic_rng); if index.features.rocks { layer::apply_rocks_to(&mut canvas, &mut dynamic_rng); } @@ -396,7 +397,6 @@ impl World { if index.features.spots { layer::apply_spots_to(&mut canvas, &mut dynamic_rng); } - layer::apply_caves2_to(&mut canvas, &mut dynamic_rng); // layer::apply_coral_to(&mut canvas); // Apply site generation @@ -492,7 +492,7 @@ impl World { .filter_map(|attr| { ColumnGen::new(self.sim()) .get((attr.pos, index, self.sim().calendar.as_ref())) - .filter(|col| layer::tree::tree_valid_at(col, attr.seed)) + .filter(|col| layer::tree::tree_valid_at(attr.pos, col, None, attr.seed)) .zip(Some(attr)) }) .filter_map(|(col, tree)| {