This commit is contained in:
Joshua Barretto 2019-06-23 20:43:02 +01:00
parent 397c909bd4
commit f781aca8e9
6 changed files with 184 additions and 133 deletions

View File

@ -152,11 +152,8 @@ fn handle_kill(server: &mut Server, entity: EcsEntity, _args: String, _action: &
fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
let time = scan_fmt!(&args, action.arg_fmt, String); let time = scan_fmt!(&args, action.arg_fmt, String);
server server.state.ecs_mut().write_resource::<TimeOfDay>().0 = match time.as_ref().map(|s| s.as_str())
.state {
.ecs_mut()
.write_resource::<TimeOfDay>()
.0 = match time.as_ref().map(|s| s.as_str()) {
Some("day") => 12.0 * 3600.0, Some("day") => 12.0 * 3600.0,
Some("night") => 24.0 * 3600.0, Some("night") => 24.0 * 3600.0,
Some("dawn") => 5.0 * 3600.0, Some("dawn") => 5.0 * 3600.0,
@ -164,14 +161,19 @@ fn handle_time(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
Some(n) => match n.parse() { Some(n) => match n.parse() {
Ok(n) => n, Ok(n) => n,
Err(_) => { Err(_) => {
server.clients.notify(entity, ServerMsg::Chat(format!("'{}' is not a time!", n))); server
.clients
.notify(entity, ServerMsg::Chat(format!("'{}' is not a time!", n)));
return; return;
}, }
}, },
None => { None => {
server.clients.notify(entity, ServerMsg::Chat("You must specify a time!".to_string())); server.clients.notify(
entity,
ServerMsg::Chat("You must specify a time!".to_string()),
);
return; return;
}, }
}; };
} }

View File

@ -30,7 +30,8 @@ impl<'a> BlockGen<'a> {
fn sample_column( fn sample_column(
column_gen: &ColumnGen<'a>, column_gen: &ColumnGen<'a>,
cache: &mut HashCache<Vec2<i32>, Option<ColumnSample<'a>>>, wpos: Vec2<i32>, cache: &mut HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
wpos: Vec2<i32>,
) -> Option<ColumnSample<'a>> { ) -> Option<ColumnSample<'a>> {
cache cache
.get(Vec2::from(wpos), |wpos| column_gen.get(wpos)) .get(Vec2::from(wpos), |wpos| column_gen.get(wpos))
@ -44,25 +45,34 @@ impl<'a> BlockGen<'a> {
close_cliffs: &[(Vec2<i32>, u32); 9], close_cliffs: &[(Vec2<i32>, u32); 9],
cliff_hill: f32, cliff_hill: f32,
) -> f32 { ) -> f32 {
close_cliffs close_cliffs.iter().fold(
.iter() 0.0f32,
.fold(0.0f32, |max_height, (cliff_pos, seed)| { |max_height, (cliff_pos, seed)| match Self::sample_column(
match Self::sample_column(column_gen, cache, Vec2::from(*cliff_pos)) { column_gen,
cache,
Vec2::from(*cliff_pos),
) {
Some(cliff_sample) if cliff_sample.cliffs => { Some(cliff_sample) if cliff_sample.cliffs => {
let cliff_pos3d = Vec3::from(*cliff_pos); let cliff_pos3d = Vec3::from(*cliff_pos);
let height = RandomField::new(seed + 1).get(cliff_pos3d) % 48; let height = RandomField::new(seed + 1).get(cliff_pos3d) % 48;
let radius = RandomField::new(seed + 2).get(cliff_pos3d) % 48 + 8; let radius = RandomField::new(seed + 2).get(cliff_pos3d) % 48 + 8;
max_height.max(if cliff_pos.map(|e| e as f32).distance_squared(wpos) < (radius * radius) as f32 { max_height.max(
cliff_sample.alt + height as f32 * (1.0 - cliff_sample.chaos) + cliff_hill if cliff_pos.map(|e| e as f32).distance_squared(wpos)
< (radius * radius) as f32
{
cliff_sample.alt
+ height as f32 * (1.0 - cliff_sample.chaos)
+ cliff_hill
} else { } else {
0.0 0.0
})
}, },
_ => max_height, )
} }
}) _ => max_height,
},
)
} }
} }
@ -99,7 +109,8 @@ impl<'a> SamplerMut for BlockGen<'a> {
let wposf = wpos.map(|e| e as f64); let wposf = wpos.map(|e| e as f64);
let (definitely_underground, height, water_height) = if (wposf.z as f32) < alt - 64.0 * chaos { let (definitely_underground, height, water_height) =
if (wposf.z as f32) < alt - 64.0 * chaos {
// Shortcut warping // Shortcut warping
(true, alt, water_level) (true, alt, water_level)
} else { } else {
@ -118,12 +129,26 @@ impl<'a> SamplerMut for BlockGen<'a> {
alt + warp alt + warp
} else { } else {
let turb = Vec2::new( let turb = Vec2::new(
world.sim().gen_ctx.turb_x_nz.get((wposf.div(48.0)).into_array()) as f32, world
world.sim().gen_ctx.turb_y_nz.get((wposf.div(48.0)).into_array()) as f32, .sim()
.gen_ctx
.turb_x_nz
.get((wposf.div(48.0)).into_array()) as f32,
world
.sim()
.gen_ctx
.turb_y_nz
.get((wposf.div(48.0)).into_array()) as f32,
) * 12.0; ) * 12.0;
let wpos_turb = Vec2::from(wpos).map(|e: i32| e as f32) + turb; let wpos_turb = Vec2::from(wpos).map(|e: i32| e as f32) + turb;
let cliff_height = Self::get_cliff_height(column_gen, column_cache, wpos_turb, &close_cliffs, cliff_hill); let cliff_height = Self::get_cliff_height(
column_gen,
column_cache,
wpos_turb,
&close_cliffs,
cliff_hill,
);
(alt + warp).max(cliff_height) (alt + warp).max(cliff_height)
}; };
@ -162,7 +187,9 @@ impl<'a> SamplerMut for BlockGen<'a> {
let col = Lerp::lerp( let col = Lerp::lerp(
sub_surface_color, sub_surface_color,
surface_color, surface_color,
(wposf.z as f32 - (height - grass_depth)).div(grass_depth).powf(0.5), (wposf.z as f32 - (height - grass_depth))
.div(grass_depth)
.powf(0.5),
); );
// Surface // Surface
Some(Block::new(1, col.map(|e| (e * 255.0) as u8))) Some(Block::new(1, col.map(|e| (e * 255.0) as u8)))
@ -260,18 +287,30 @@ impl<'a> SamplerMut for BlockGen<'a> {
Some(block) => block, Some(block) => block,
None => (&close_trees) None => (&close_trees)
.iter() .iter()
.fold(air, |block, (tree_pos, tree_seed)| if !block.is_empty() { .fold(air, |block, (tree_pos, tree_seed)| {
if !block.is_empty() {
block block
} else { } else {
match Self::sample_column(column_gen, column_cache, Vec2::from(*tree_pos)) { match Self::sample_column(
column_gen,
column_cache,
Vec2::from(*tree_pos),
) {
Some(tree_sample) Some(tree_sample)
if tree_sample.tree_density if tree_sample.tree_density
> 0.5 + (*tree_seed as f32 / 1000.0).fract() * 0.2 > 0.5 + (*tree_seed as f32 / 1000.0).fract() * 0.2
&& tree_sample.alt > tree_sample.water_level => && tree_sample.alt > tree_sample.water_level =>
{ {
let cliff_height = Self::get_cliff_height(column_gen, column_cache, tree_pos.map(|e| e as f32), &tree_sample.close_cliffs, cliff_hill); let cliff_height = Self::get_cliff_height(
column_gen,
column_cache,
tree_pos.map(|e| e as f32),
&tree_sample.close_cliffs,
cliff_hill,
);
let height = tree_sample.alt.max(cliff_height); let height = tree_sample.alt.max(cliff_height);
let tree_pos3d = Vec3::new(tree_pos.x, tree_pos.y, height as i32); let tree_pos3d =
Vec3::new(tree_pos.x, tree_pos.y, height as i32);
let rpos = wpos - tree_pos3d; let rpos = wpos - tree_pos3d;
let trees = tree::kinds(tree_sample.forest_kind); // Choose tree kind let trees = tree::kinds(tree_sample.forest_kind); // Choose tree kind
@ -291,6 +330,7 @@ impl<'a> SamplerMut for BlockGen<'a> {
} }
_ => block, _ => block,
} }
}
}), }),
} }
}; };

View File

@ -2,8 +2,7 @@ use crate::{
all::ForestKind, all::ForestKind,
sim::{Location, LocationInfo}, sim::{Location, LocationInfo},
util::Sampler, util::Sampler,
World, World, CONFIG,
CONFIG,
}; };
use common::{ use common::{
terrain::{Block, TerrainChunkSize}, terrain::{Block, TerrainChunkSize},
@ -64,8 +63,8 @@ impl<'a> Sampler for ColumnGen<'a> {
.max(0.0) .max(0.0)
.mul((1.0 - (chaos - 0.15) * 20.0).max(0.0).min(1.0)); .mul((1.0 - (chaos - 0.15) * 20.0).max(0.0).min(1.0));
let cliff_hill = (sim.gen_ctx.small_nz.get((wposf.div(128.0)).into_array()) as f32) let cliff_hill =
.mul(16.0); (sim.gen_ctx.small_nz.get((wposf.div(128.0)).into_array()) as f32).mul(16.0);
let riverless_alt = sim.get_interpolated(wpos, |chunk| chunk.alt)? let riverless_alt = sim.get_interpolated(wpos, |chunk| chunk.alt)?
+ (sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32) + (sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32)
@ -100,7 +99,8 @@ impl<'a> Sampler for ColumnGen<'a> {
let marble_small = (sim.gen_ctx.hill_nz.get((wposf3d.div(3.0)).into_array()) as f32) let marble_small = (sim.gen_ctx.hill_nz.get((wposf3d.div(3.0)).into_array()) as f32)
.add(1.0) .add(1.0)
.mul(0.5); .mul(0.5);
let marble = (sim.gen_ctx.hill_nz.get((wposf3d.div(48.0)).into_array()) as f32).mul(0.75) let marble = (sim.gen_ctx.hill_nz.get((wposf3d.div(48.0)).into_array()) as f32)
.mul(0.75)
.add(1.0) .add(1.0)
.mul(0.5) .mul(0.5)
.add(marble_small.mul(0.25)); .add(marble_small.mul(0.25));
@ -118,11 +118,7 @@ impl<'a> Sampler for ColumnGen<'a> {
let sand = Rgb::lerp(beach_sand, desert_sand, marble); let sand = Rgb::lerp(beach_sand, desert_sand, marble);
let cliff = Rgb::lerp(cold_stone, warm_stone, marble); let cliff = Rgb::lerp(cold_stone, warm_stone, marble);
let dirt = Lerp::lerp( let dirt = Lerp::lerp(Rgb::new(0.2, 0.1, 0.05), Rgb::new(0.4, 0.25, 0.0), marble);
Rgb::new(0.2, 0.1, 0.05),
Rgb::new(0.4, 0.25, 0.0),
marble,
);
let turf = grass; let turf = grass;
@ -139,11 +135,20 @@ impl<'a> Sampler for ColumnGen<'a> {
); );
// Work out if we're on a path or near a town // Work out if we're on a path or near a town
let near_0 = sim_chunk.location.as_ref().map(|l| l.near[0].block_pos).unwrap_or(Vec2::zero()).map(|e| e as f32); let near_0 = sim_chunk
let near_1 = sim_chunk.location.as_ref().map(|l| l.near[1].block_pos).unwrap_or(Vec2::zero()).map(|e| e as f32); .location
.as_ref()
.map(|l| l.near[0].block_pos)
.unwrap_or(Vec2::zero())
.map(|e| e as f32);
let near_1 = sim_chunk
.location
.as_ref()
.map(|l| l.near[1].block_pos)
.unwrap_or(Vec2::zero())
.map(|e| e as f32);
let dist_to_path = (0.0 let dist_to_path = (0.0 + (near_1.y - near_0.y) * wposf_turb.x as f32
+ (near_1.y - near_0.y) * wposf_turb.x as f32
- (near_1.x - near_0.x) * wposf_turb.y as f32 - (near_1.x - near_0.x) * wposf_turb.y as f32
+ near_1.x * near_0.y + near_1.x * near_0.y
- near_0.x * near_1.y) - near_0.x * near_1.y)

View File

@ -48,12 +48,12 @@ fn generate_name<R: Rng>(rng: &mut R) -> String {
]; ];
let mid = ["ka", "se", "au", "da", "di"]; let mid = ["ka", "se", "au", "da", "di"];
let tails = [ let tails = [
/*"mill",*/ "ben", "sel", "dori", "theas", "dar", "bur", "to", "vis", "ten", "stone", "tiva", /*"mill",*/ "ben", "sel", "dori", "theas", "dar", "bur", "to", "vis", "ten", "stone",
"id", "and", "or", "el", "ond", "ia", "eld", "ald", "aft", "ift", "ity", "well", "oll", "tiva", "id", "and", "or", "el", "ond", "ia", "eld", "ald", "aft", "ift", "ity", "well",
"ill", "all", "wyn", "light", " Hill", "lin", "mont", "mor", "cliff", "rok", "den", "mi", "oll", "ill", "all", "wyn", "light", " Hill", "lin", "mont", "mor", "cliff", "rok", "den",
"rock", "glenn", "rovi", "lea", "gate", "view", "ley", "wood", "ovia", "cliff", "marsh", "mi", "rock", "glenn", "rovi", "lea", "gate", "view", "ley", "wood", "ovia", "cliff",
"kor", "ice", /*"river",*/ "acre", "venn", "crest", "field", "vale", "spring", " Vale", "marsh", "kor", "ice", /*"river",*/ "acre", "venn", "crest", "field", "vale",
"grasp", "fel", "fall", "grove", "wyn", "edge", "spring", " Vale", "grasp", "fel", "fall", "grove", "wyn", "edge",
]; ];
let mut name = String::new(); let mut name = String::new();

View File

@ -5,14 +5,17 @@ pub use self::location::Location;
use crate::{ use crate::{
all::ForestKind, all::ForestKind,
util::{StructureGen2d, Sampler}, util::{Sampler, StructureGen2d},
CONFIG, CONFIG,
}; };
use common::{ use common::{
terrain::{BiomeKind, TerrainChunkSize}, terrain::{BiomeKind, TerrainChunkSize},
vol::VolSize, vol::VolSize,
}; };
use noise::{BasicMulti, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, OpenSimplex, SuperSimplex}; use noise::{
BasicMulti, HybridMulti, MultiFractal, NoiseFn, OpenSimplex, RidgedMulti, Seedable,
SuperSimplex,
};
use rand::{prng::XorShiftRng, Rng, SeedableRng}; use rand::{prng::XorShiftRng, Rng, SeedableRng};
use std::{ use std::{
ops::{Add, Div, Mul, Neg, Sub}, ops::{Add, Div, Mul, Neg, Sub},
@ -132,12 +135,12 @@ impl WorldSim {
self.rng.gen::<usize>() % grid_size.y, self.rng.gen::<usize>() % grid_size.y,
); );
let wpos = (cell_pos * cell_size) let wpos = (cell_pos * cell_size)
.map2( .map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
Vec2::from(TerrainChunkSize::SIZE), e as i32 * sz as i32
|e, sz: u32| e as i32 * sz as i32, });
);
locations[cell_pos.y * grid_size.x + cell_pos.x] = Some(Arc::new(Location::generate(wpos, &mut rng))); locations[cell_pos.y * grid_size.x + cell_pos.x] =
Some(Arc::new(Location::generate(wpos, &mut rng)));
} }
// Simulate invasion! // Simulate invasion!
@ -148,10 +151,8 @@ impl WorldSim {
if locations[j * grid_size.x + i].is_none() { if locations[j * grid_size.x + i].is_none() {
const R_COORDS: [i32; 5] = [-1, 0, 1, 0, -1]; const R_COORDS: [i32; 5] = [-1, 0, 1, 0, -1];
let idx = self.rng.gen::<usize>() % 4; let idx = self.rng.gen::<usize>() % 4;
let loc = Vec2::new( let loc = Vec2::new(i as i32 + R_COORDS[idx], j as i32 + R_COORDS[idx + 1])
i as i32 + R_COORDS[idx], .map(|e| e as usize);
j as i32 + R_COORDS[idx + 1],
).map(|e| e as usize);
locations[j * grid_size.x + i] = locations locations[j * grid_size.x + i] = locations
.get(loc.y * grid_size.x + loc.x) .get(loc.y * grid_size.x + loc.x)
@ -175,7 +176,9 @@ impl WorldSim {
.iter() .iter()
.map(|(pos, seed)| RegionInfo { .map(|(pos, seed)| RegionInfo {
chunk_pos: *pos, chunk_pos: *pos,
block_pos: pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| e * sz as i32), block_pos: pos.map2(Vec2::from(TerrainChunkSize::SIZE), |e, sz: u32| {
e * sz as i32
}),
dist: (pos - chunk_pos).map(|e| e as f32).magnitude(), dist: (pos - chunk_pos).map(|e| e as f32).magnitude(),
seed: *seed, seed: *seed,
}) })
@ -189,10 +192,7 @@ impl WorldSim {
.get(nearest_cell_pos.y * grid_size.x + nearest_cell_pos.x) .get(nearest_cell_pos.y * grid_size.x + nearest_cell_pos.x)
.cloned() .cloned()
.unwrap_or(None) .unwrap_or(None)
.map(|loc| LocationInfo { .map(|loc| LocationInfo { loc, near });
loc,
near,
});
} }
} }
@ -409,7 +409,10 @@ impl SimChunk {
.sub(0.1) .sub(0.1)
.mul(1.3) .mul(1.3)
.max(0.0), .max(0.0),
cliffs: cliff > 0.5 && dryness > 0.05 && alt > CONFIG.sea_level + 5.0 && dryness.abs() > 0.075, cliffs: cliff > 0.5
&& dryness > 0.05
&& alt > CONFIG.sea_level + 5.0
&& dryness.abs() > 0.075,
near_cliffs: cliff > 0.4, near_cliffs: cliff > 0.4,
tree_density: (gen_ctx.tree_nz.get((wposf.div(1024.0)).into_array()) as f32) tree_density: (gen_ctx.tree_nz.get((wposf.div(1024.0)).into_array()) as f32)
.add(1.0) .add(1.0)
@ -447,7 +450,8 @@ impl SimChunk {
} }
pub fn get_max_z(&self) -> f32 { pub fn get_max_z(&self) -> f32 {
(self.alt + Z_TOLERANCE.1 * if self.near_cliffs { 1.0 } else { 0.5 }).max(CONFIG.sea_level + 2.0) (self.alt + Z_TOLERANCE.1 * if self.near_cliffs { 1.0 } else { 0.5 })
.max(CONFIG.sea_level + 2.0)
} }
pub fn get_name(&self) -> Option<String> { pub fn get_name(&self) -> Option<String> {