diff --git a/client/src/lib.rs b/client/src/lib.rs index 00f64c5025..bb1bbf2873 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -172,7 +172,8 @@ impl Client { pub fn set_view_distance(&mut self, view_distance: u32) { self.view_distance = Some(view_distance.max(1).min(25)); self.postbox - .send_message(ClientMsg::SetViewDistance(self.view_distance.unwrap())); // Can't fail + .send_message(ClientMsg::SetViewDistance(self.view_distance.unwrap())); + // Can't fail } pub fn swap_inventory_slots(&mut self, a: usize, b: usize) { diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 5305b8f223..cbd5b2b99f 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -10,6 +10,8 @@ use common::{ msg::ServerMsg, npc::{get_npc_name, NpcKind}, state::TimeOfDay, + terrain::TerrainChunkSize, + vol::VolSize, }; use rand::Rng; use specs::{Builder, Entity as EcsEntity, Join}; @@ -198,7 +200,14 @@ lazy_static! { "/adminify : Temporarily gives a player admin permissions or removes them", true, handle_adminify, - ) + ), + ChatCommand::new( + "debug_column", + "{} {}", + "/debug_column : Prints some debug information about a column", + false, + handle_debug_column, + ), ]; } @@ -828,3 +837,50 @@ fn handle_tell(server: &mut Server, entity: EcsEntity, args: String, action: &Ch .notify(entity, ServerMsg::private(String::from(action.help_string))); } } + +fn handle_debug_column(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { + let sim = server.world.sim(); + if let Ok((x, y)) = scan_fmt!(&args, action.arg_fmt, i32, i32) { + let wpos = Vec2::new(x, y); + /* let chunk_pos = wpos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| { + e / sz as i32 + }); */ + + let foo = || { + // let sim_chunk = sim.get(chunk_pos)?; + let alt_base = sim.get_interpolated(wpos, |chunk| chunk.alt_base)?; + let alt = sim.get_interpolated(wpos, |chunk| chunk.alt)?; + let chaos = sim.get_interpolated(wpos, |chunk| chunk.chaos)?; + let temp = sim.get_interpolated(wpos, |chunk| chunk.temp)?; + let humidity = sim.get_interpolated(wpos, |chunk| chunk.humidity)?; + let rockiness = sim.get_interpolated(wpos, |chunk| chunk.rockiness)?; + let tree_density = sim.get_interpolated(wpos, |chunk| chunk.tree_density)?; + let spawn_rate = sim.get_interpolated(wpos, |chunk| chunk.spawn_rate)?; + + Some(format!( + r#"wpos: {:?} +alt_base {:?} +alt {:?} +chaos {:?} +temp {:?} +humidity {:?} +rockiness {:?} +tree_density {:?} +spawn_rate {:?} "#, + wpos, alt_base, alt, chaos, temp, humidity, rockiness, tree_density, spawn_rate + )) + }; + if let Some(s) = foo() { + server.clients.notify(entity, ServerMsg::private(s)); + } else { + server.clients.notify( + entity, + ServerMsg::private(String::from("Not a pregenerated chunk.")), + ); + } + } else { + server + .clients + .notify(entity, ServerMsg::private(String::from(action.help_string))); + } +} diff --git a/world/src/block/natural.rs b/world/src/block/natural.rs index 1d12a72cc5..79fde45685 100644 --- a/world/src/block/natural.rs +++ b/world/src/block/natural.rs @@ -8,6 +8,7 @@ use crate::{ use common::{assets, terrain::Structure}; use lazy_static::lazy_static; use std::sync::Arc; +use std::u32; use vek::*; static VOLUME_RAND: RandomPerm = RandomPerm::new(0xDB21C052); @@ -25,7 +26,8 @@ pub fn structure_gen<'a>( let st_sample = &structure_samples[idx].as_ref()?; // Assuming it's a tree... figure out when it SHOULDN'T spawn - if st_sample.tree_density < 0.5 + (st_seed as f32 / 1000.0).fract() * 0.5 + let random_seed = (st_seed as f64) / (u32::MAX as f64); + if (st_sample.tree_density as f64) < random_seed || st_sample.alt < st_sample.water_level || st_sample.spawn_rate < 0.5 { diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs index e8d58b7c47..c89575e1e4 100644 --- a/world/src/column/mod.rs +++ b/world/src/column/mod.rs @@ -78,8 +78,8 @@ impl<'a> ColumnGen<'a> { if seed % 5 == 2 && chunk.temp > CONFIG.desert_temp - && chunk.humidity < CONFIG.desert_hum && chunk.alt > CONFIG.sea_level + 5.0 + && chunk.chaos <= 0.35 { Some(StructureData { pos, diff --git a/world/src/sim/mod.rs b/world/src/sim/mod.rs index a259a98309..5be3ae1e69 100644 --- a/world/src/sim/mod.rs +++ b/world/src/sim/mod.rs @@ -55,6 +55,7 @@ struct GenCdf { alt_base: InverseCdf, chaos: InverseCdf, alt: InverseCdf, + alt_no_seawater: InverseCdf, } pub(crate) struct GenCtx { @@ -223,8 +224,8 @@ impl WorldSim { // are included). let pure_water = |posi| { let pos = uniform_idx_as_vec2(posi); - for x in (pos.x - 1..=pos.x + 1) { - for y in (pos.y - 1..=pos.y + 1) { + for x in pos.x - 1..=pos.x + 1 { + for y in pos.y - 1..=pos.y + 1 { if x >= 0 && y >= 0 && x < WORLD_SIZE.x as i32 && y < WORLD_SIZE.y as i32 { let posi = vec2_as_uniform_idx(Vec2::new(x, y)); if alt[posi].1.mul(CONFIG.mountain_scale) > 0.0 { @@ -236,12 +237,21 @@ impl WorldSim { true }; + // A version of alt that is uniform over *non-seawater* (or land-adjacent seawater) chunks. + let alt_no_seawater = uniform_noise(|posi, wposf| { + if pure_water(posi) { + None + } else { + Some(alt[posi].1) + } + }); + // -1 to 1. let temp_base = uniform_noise(|posi, wposf| { if pure_water(posi) { None } else { - Some((gen_ctx.temp_nz.get((wposf.div(12000.0)).into_array()) as f32)) + Some(gen_ctx.temp_nz.get((wposf.div(12000.0)).into_array()) as f32) } }); @@ -265,6 +275,7 @@ impl WorldSim { alt_base, chaos, alt, + alt_no_seawater, }; let mut chunks = Vec::new(); @@ -530,7 +541,8 @@ impl SimChunk { let map_edge_factor = map_edge_factor(posi); let (_, chaos) = gen_cdf.chaos[posi]; let (humid_uniform, _) = gen_cdf.humid_base[posi]; - let (alt_uniform, alt_pre) = gen_cdf.alt[posi]; + let (_, alt_pre) = gen_cdf.alt[posi]; + let (alt_uniform, _) = gen_cdf.alt_no_seawater[posi]; let (temp_uniform, _) = gen_cdf.temp_base[posi]; // Take the weighted average of our randomly generated base humidity, the scaled