Added christmas snow

This commit is contained in:
Joshua Barretto 2021-12-06 23:06:48 +00:00
parent e3203080ed
commit 3ddacb96ab
10 changed files with 69 additions and 37 deletions

View File

@ -2713,6 +2713,7 @@ fn handle_debug_column(
_action: &ChatCommand,
) -> CmdResult<()> {
let sim = server.world.sim();
let calendar = (*server.state.ecs().read_resource::<Calendar>()).clone();
let sampler = server.world.sample_columns();
let wpos = if let (Some(x), Some(y)) = parse_args!(args, i32, i32) {
Vec2::new(x, y)
@ -2721,7 +2722,7 @@ fn handle_debug_column(
// FIXME: Deal with overflow, if needed.
pos.0.xy().map(|x| x as i32)
};
let msg_generator = || {
let msg_generator = |calendar| {
let alt = sim.get_interpolated(wpos, |chunk| chunk.alt)?;
let basement = sim.get_interpolated(wpos, |chunk| chunk.basement)?;
let water_alt = sim.get_interpolated(wpos, |chunk| chunk.water_alt)?;
@ -2733,7 +2734,7 @@ fn handle_debug_column(
let spawn_rate = sim.get_interpolated(wpos, |chunk| chunk.spawn_rate)?;
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
let chunk = sim.get(chunk_pos)?;
let col = sampler.get((wpos, server.index.as_index_ref()))?;
let col = sampler.get((wpos, server.index.as_index_ref(), Some(calendar)))?;
let gradient = sim.get_gradient_approx(chunk_pos)?;
let downhill = chunk.downhill;
let river = &chunk.river;
@ -2772,7 +2773,7 @@ spawn_rate {:?} "#,
spawn_rate
))
};
if let Some(s) = msg_generator() {
if let Some(s) = msg_generator(&calendar) {
server.notify_client(client, ServerGeneral::server_msg(ChatType::CommandInfo, s));
Ok(())
} else {

View File

@ -361,7 +361,7 @@ impl Server {
);
#[cfg(feature = "worldgen")]
let map = world.get_map_data(index.as_index_ref(), state.thread_pool());
let map = world.get_map_data(index.as_index_ref(), Some(&settings.calendar_mode.calendar_now()), state.thread_pool());
#[cfg(not(feature = "worldgen"))]
let (world, index) = World::generate(settings.world_seed);
@ -597,12 +597,7 @@ impl Server {
// Update calendar events as time changes
// TODO: If a lot of calendar events get added, this might become expensive.
// Maybe don't do this every tick?
let new_calendar = match &self.state.ecs().read_resource::<Settings>().calendar_mode {
CalendarMode::None => Calendar::default(),
CalendarMode::Auto => Calendar::from_tz(None),
CalendarMode::Timezone(tz) => Calendar::from_tz(Some(*tz)),
CalendarMode::Events(events) => Calendar::from_events(events.clone()),
};
let new_calendar = self.state.ecs().read_resource::<Settings>().calendar_mode.calendar_now();
*self.state.ecs_mut().write_resource::<Calendar>() = new_calendar;
// This tick function is the centre of the Veloren universe. Most server-side

View File

@ -14,7 +14,7 @@ pub use server_description::ServerDescription;
pub use whitelist::{Whitelist, WhitelistInfo, WhitelistRecord};
use chrono::Utc;
use common::{calendar::CalendarEvent, resources::BattleMode};
use common::{calendar::{Calendar, CalendarEvent}, resources::BattleMode};
use core::time::Duration;
use portpicker::pick_unused_port;
use serde::{Deserialize, Serialize};
@ -74,6 +74,17 @@ impl Default for CalendarMode {
fn default() -> Self { Self::Auto }
}
impl CalendarMode {
pub fn calendar_now(&self) -> Calendar {
match self {
CalendarMode::None => Calendar::default(),
CalendarMode::Auto => Calendar::from_tz(None),
CalendarMode::Timezone(tz) => Calendar::from_tz(Some(*tz)),
CalendarMode::Events(events) => Calendar::from_events(events.clone()),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct Settings {

View File

@ -3,9 +3,12 @@ use crate::{
util::{FastNoise, RandomField, RandomPerm, Sampler, SmallCache},
IndexRef,
};
use common::terrain::{
use common::{
calendar::Calendar,
terrain::{
structure::{self, StructureBlock},
Block, BlockKind, SpriteKind,
},
};
use core::ops::{Div, Mul, Range};
use serde::Deserialize;
@ -33,17 +36,18 @@ impl<'a> BlockGen<'a> {
cache: &'b mut SmallCache<Option<ColumnSample<'a>>>,
wpos: Vec2<i32>,
index: IndexRef<'a>,
calendar: Option<&'a Calendar>,
) -> Option<&'b ColumnSample<'a>> {
cache
.get(wpos, |wpos| column_gen.get((wpos, index)))
.get(wpos, |wpos| column_gen.get((wpos, index, calendar)))
.as_ref()
}
pub fn get_z_cache(&mut self, wpos: Vec2<i32>, index: IndexRef<'a>) -> Option<ZCache<'a>> {
pub fn get_z_cache(&mut self, wpos: Vec2<i32>, index: IndexRef<'a>, calendar: Option<&'a Calendar>) -> Option<ZCache<'a>> {
let BlockGen { column_gen } = self;
// Main sample
let sample = column_gen.get((wpos, index))?;
let sample = column_gen.get((wpos, index, calendar))?;
Some(ZCache { sample })
}

View File

@ -8,6 +8,7 @@ use crate::{
util::{Grid, Sampler},
};
use common::{
calendar::Calendar,
generation::EntityInfo,
terrain::{Block, BlockKind, Structure, TerrainChunk, TerrainChunkSize},
vol::{ReadVol, RectVolSize, WriteVol},
@ -24,6 +25,7 @@ pub struct CanvasInfo<'a> {
pub(crate) chunks: &'a WorldSim,
pub(crate) index: IndexRef<'a>,
pub(crate) chunk: &'a SimChunk,
pub(crate) calendar: Option<&'a Calendar>,
}
impl<'a> CanvasInfo<'a> {
@ -52,7 +54,7 @@ impl<'a> CanvasInfo<'a> {
pub fn col_or_gen(&self, wpos: Vec2<i32>) -> Option<Cow<'a, ColumnSample>> {
self.col(wpos).map(Cow::Borrowed).or_else(|| {
Some(Cow::Owned(
ColumnGen::new(self.chunks()).get((wpos, self.index()))?,
ColumnGen::new(self.chunks()).get((wpos, self.index(), self.calendar))?,
))
})
}
@ -122,6 +124,7 @@ impl<'a> CanvasInfo<'a> {
chunks: sim,
index,
chunk: &sim_chunk,
calendar: None,
})
}
}

View File

@ -5,6 +5,7 @@ use crate::{
IndexRef, CONFIG,
};
use common::{
calendar::{Calendar, CalendarEvent},
terrain::{
quadratic_nearest_point, river_spline_coeffs, uniform_idx_as_vec2, vec2_as_uniform_idx,
TerrainChunkSize,
@ -64,10 +65,10 @@ impl<'a> ColumnGen<'a> {
}
impl<'a> Sampler<'a> for ColumnGen<'a> {
type Index = (Vec2<i32>, IndexRef<'a>);
type Index = (Vec2<i32>, IndexRef<'a>, Option<&'a Calendar>);
type Sample = Option<ColumnSample<'a>>;
fn get(&self, (wpos, index): Self::Index) -> Option<ColumnSample<'a>> {
fn get(&self, (wpos, index, calendar): Self::Index) -> Option<ColumnSample<'a>> {
let wposf = wpos.map(|e| e as f64);
let chunk_pos = wpos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
@ -1079,8 +1080,13 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
);
// Snow covering
let thematic_snow = calendar.map_or(false, |c| c.is_event(CalendarEvent::Christmas));
let snow_cover = temp
.sub(CONFIG.snow_temp)
.sub(if thematic_snow {
CONFIG.tropical_temp
} else {
CONFIG.snow_temp
})
.max(-humidity.sub(CONFIG.desert_hum))
.mul(4.0)
.add(((marble - 0.5) / 0.5) * 0.5)

View File

@ -7,6 +7,7 @@ use crate::{
};
use common::{
assets::AssetHandle,
calendar::{Calendar, CalendarEvent},
terrain::{
structure::{Structure, StructureBlock, StructuresGroup},
Block, BlockKind, SpriteKind,
@ -33,7 +34,7 @@ static MODEL_RAND: RandomPerm = RandomPerm::new(0xDB21C052);
static UNIT_CHOOSER: UnitChooser = UnitChooser::new(0x700F4EC7);
static QUIRKY_RAND: RandomPerm = RandomPerm::new(0xA634460F);
pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng, calendar: Option<&Calendar>) {
// TODO: Get rid of this
#[allow(clippy::large_enum_variant)]
enum TreeModel {
@ -63,7 +64,7 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
} in trees
{
let tree = if let Some(tree) = tree_cache.entry(pos).or_insert_with(|| {
let col = ColumnGen::new(info.chunks()).get((pos, info.index()))?;
let col = ColumnGen::new(info.chunks()).get((pos, info.index(), calendar))?;
// Ensure that it's valid to place a *thing* here
if col.alt < col.water_level
@ -135,7 +136,7 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
ForestKind::Pine => {
break 'model TreeModel::Procedural(
ProceduralTree::generate(
TreeConfig::pine(&mut RandomPerm::new(seed), scale),
TreeConfig::pine(&mut RandomPerm::new(seed), scale, calendar),
&mut RandomPerm::new(seed),
),
StructureBlock::PineLeaves,
@ -547,7 +548,7 @@ impl TreeConfig {
}
}
pub fn pine(rng: &mut impl Rng, scale: f32) -> Self {
pub fn pine(rng: &mut impl Rng, scale: f32, calendar: Option<&Calendar>) -> Self {
let scale = scale * (1.0 + rng.gen::<f32>().powi(4) * 0.5);
let log_scale = 1.0 + scale.log2().max(0.0);
@ -567,7 +568,11 @@ impl TreeConfig {
leaf_vertical_scale: 0.3,
proportionality: 1.0,
inhabited: false,
hanging_sprites: &[(0.0001, SpriteKind::Beehive)],
hanging_sprites: if calendar.map_or(false, |c| c.is_event(CalendarEvent::Christmas)) {
&[(0.0001, SpriteKind::Beehive), (0.01, SpriteKind::Orb)]
} else {
&[(0.0001, SpriteKind::Beehive)]
},
trunk_block: StructureBlock::Filled(BlockKind::Wood, Rgb::new(90, 35, 15)),
}
}

View File

@ -287,7 +287,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
index: IndexRef,
chunk: &SimChunk,
supplement: &mut ChunkSupplement,
time: Option<(TimeOfDay, Calendar)>,
time: Option<&(TimeOfDay, Calendar)>,
) {
let scatter = &index.wildlife_spawns;
@ -305,7 +305,7 @@ pub fn apply_wildlife_supplement<'a, R: Rng>(
};
let underwater = col_sample.water_level > col_sample.alt;
let (current_day_period, calendar) = if let Some((time, calendar)) = &time {
let (current_day_period, calendar) = if let Some((time, calendar)) = time {
(DayPeriod::from(time.0), Some(calendar))
} else {
(DayPeriod::Noon, None)

View File

@ -120,7 +120,7 @@ impl World {
// TODO
}
pub fn get_map_data(&self, index: IndexRef, threadpool: &rayon::ThreadPool) -> WorldMapMsg {
pub fn get_map_data(&self, index: IndexRef, calendar: Option<&Calendar>, threadpool: &rayon::ThreadPool) -> WorldMapMsg {
threadpool.install(|| {
// we need these numbers to create unique ids for cave ends
let num_sites = self.civs().sites().count() as u64;
@ -179,14 +179,14 @@ impl World {
}),
)
.collect(),
..self.sim.get_map(index)
..self.sim.get_map(index, calendar)
}
})
}
pub fn sample_columns(
&self,
) -> impl Sampler<Index = (Vec2<i32>, IndexRef), Sample = Option<ColumnSample>> + '_ {
) -> impl Sampler<Index = (Vec2<i32>, IndexRef, Option<&'_ Calendar>), Sample = Option<ColumnSample>> + '_ {
ColumnGen::new(&self.sim)
}
@ -218,6 +218,8 @@ impl World {
mut should_continue: impl FnMut() -> bool,
time: Option<(TimeOfDay, Calendar)>,
) -> Result<(TerrainChunk, ChunkSupplement), ()> {
let calendar = time.as_ref().map(|(_, cal)| cal);
let mut sampler = self.sample_blocks();
let chunk_wpos2d = chunk_pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
@ -225,7 +227,7 @@ impl World {
let grid_border = 4;
let zcache_grid = Grid::populate_from(
TerrainChunkSize::RECT_SIZE.map(|e| e as i32) + grid_border * 2,
|offs| sampler.get_z_cache(chunk_wpos2d - grid_border + offs, index),
|offs| sampler.get_z_cache(chunk_wpos2d - grid_border + offs, index, calendar),
);
let air = Block::air(SpriteKind::Empty);
@ -348,6 +350,7 @@ impl World {
chunks: &self.sim,
index,
chunk: sim_chunk,
calendar,
},
chunk: &mut chunk,
entities: Vec::new(),
@ -363,7 +366,7 @@ impl World {
layer::apply_shrubs_to(&mut canvas, &mut dynamic_rng);
}
if index.features.trees {
layer::apply_trees_to(&mut canvas, &mut dynamic_rng);
layer::apply_trees_to(&mut canvas, &mut dynamic_rng, calendar);
}
if index.features.scatter {
layer::apply_scatter_to(&mut canvas, &mut dynamic_rng);
@ -425,7 +428,7 @@ impl World {
index,
sim_chunk,
&mut supplement,
time,
time.as_ref(),
);
// Apply site supplementary information

View File

@ -39,6 +39,7 @@ use crate::{
IndexRef, CONFIG,
};
use common::{
calendar::Calendar,
assets::{self, AssetExt},
grid::Grid,
lottery::Lottery,
@ -1460,7 +1461,7 @@ impl WorldSim {
/// Draw a map of the world based on chunk information. Returns a buffer of
/// u32s.
pub fn get_map(&self, index: IndexRef) -> WorldMapMsg {
pub fn get_map(&self, index: IndexRef, calendar: Option<&Calendar>) -> WorldMapMsg {
let mut map_config = MapConfig::orthographic(
self.map_size_lg(),
core::ops::RangeInclusive::new(CONFIG.sea_level, CONFIG.sea_level + self.max_height),
@ -1485,8 +1486,11 @@ impl WorldSim {
|| Box::new(BlockGen::new(ColumnGen::new(self))),
|_block_gen, posi| {
let sample = column_sample.get(
(uniform_idx_as_vec2(self.map_size_lg(), posi) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
index)
(
uniform_idx_as_vec2(self.map_size_lg(), posi) * TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
index,
calendar,
)
)?;
// sample.water_level = CONFIG.sea_level.max(sample.water_level);