Merge branch 'ProfessionalHobbyist/configurable_day_night_length' into 'master'

Add setting to control length of day/night cycle for servers. ("Fix" for https://gitlab.com/veloren/veloren/-/issues/1798)

See merge request veloren/veloren!3836
This commit is contained in:
Isse 2023-03-23 16:33:39 +00:00
commit 1298fc792b
12 changed files with 90 additions and 7 deletions

View File

@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
with a keybind to enable/disable the setting, and an Auto/Toggle behavior setting. Auto behavior
will only lock the camera zoom while movement and combat inputs are also being pressed.
- Custom spots can be added without recompilation (only ron and vox files)
- Setting in userdata/server/server_config/settings.ron that controls the length of each day/night cycle.
### Changed
- Bats move slower and use a simple proportional controller to maintain altitude

View File

@ -40,6 +40,7 @@ use common::{
outcome::Outcome,
recipe::{ComponentRecipeBook, RecipeBook},
resources::{GameMode, PlayerEntity, Time, TimeOfDay},
shared_server_config::ServerConstants,
spiral::Spiral2d,
terrain::{
block::Block, map::MapConfig, neighbors, site::DungeonKindMeta, BiomeKind,
@ -264,6 +265,8 @@ pub struct Client {
pending_chunks: HashMap<Vec2<i32>, Instant>,
target_time_of_day: Option<TimeOfDay>,
connected_server_constants: ServerConstants,
}
/// Holds data related to the current players characters, as well as some
@ -355,6 +358,7 @@ impl Client {
component_recipe_book,
material_stats,
ability_map,
server_constants,
} = loop {
tokio::select! {
// Spawn in a blocking thread (leaving the network thread free). This is mostly
@ -744,6 +748,8 @@ impl Client {
pending_chunks: HashMap::new(),
target_time_of_day: None,
connected_server_constants: server_constants,
})
}
@ -1802,6 +1808,7 @@ impl Client {
},
true,
None,
&self.connected_server_constants,
);
// TODO: avoid emitting these in the first place
let _ = self

View File

@ -12,6 +12,7 @@ use common::{
outcome::Outcome,
recipe::{ComponentRecipeBook, RecipeBook},
resources::{Time, TimeOfDay},
shared_server_config::ServerConstants,
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
uid::Uid,
@ -66,6 +67,7 @@ pub enum ServerInit {
component_recipe_book: ComponentRecipeBook,
material_stats: MaterialStatManifest,
ability_map: comp::item::tool::AbilityMap,
server_constants: ServerConstants,
},
}

View File

@ -31,6 +31,7 @@ pub mod combat;
pub mod comp;
pub mod consts;
pub mod resources;
pub mod shared_server_config;
pub mod uid;
// NOTE: Comment out macro to get rustfmt to re-order these as needed.

View File

@ -0,0 +1,16 @@
use serde::{Deserialize, Serialize};
/// Per-server constant data (configs) that stays the same for the server's
/// life.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ServerConstants {
pub day_cycle_coefficient: f64,
}
impl Default for ServerConstants {
fn default() -> Self {
ServerConstants {
// == 30.0 via server settings (the default)
day_cycle_coefficient: 24.0 * 2.0,
}
}
}

View File

@ -16,6 +16,7 @@ use common::{
DeltaTime, EntitiesDiedLastTick, GameMode, PlayerEntity, PlayerPhysicsSettings, Time,
TimeOfDay,
},
shared_server_config::ServerConstants,
slowjob::SlowJobPool,
terrain::{Block, MapSizeLg, TerrainChunk, TerrainGrid},
time::DayPeriod,
@ -39,9 +40,6 @@ use std::{sync::Arc, time::Instant};
use timer_queue::TimerQueue;
use vek::*;
/// How much faster should an in-game day be compared to a real day?
// TODO: Don't hard-code this.
const DAY_CYCLE_FACTOR: f64 = 24.0 * 2.0;
/// At what point should we stop speeding up physics to compensate for lag? If
/// we speed physics up too fast, we'd skip important physics events like
/// collisions. This constant determines the upper limit. If delta time exceeds
@ -598,6 +596,7 @@ impl State {
add_systems: impl Fn(&mut DispatcherBuilder),
update_terrain_and_regions: bool,
mut metrics: Option<&mut StateTickMetrics>,
server_constants: &ServerConstants,
) {
span!(_guard, "tick", "State::tick");
@ -611,7 +610,8 @@ impl State {
}
// Change the time accordingly.
self.ecs.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
self.ecs.write_resource::<TimeOfDay>().0 +=
dt.as_secs_f64() * server_constants.day_cycle_coefficient;
self.ecs.write_resource::<Time>().0 += dt.as_secs_f64();
// Update delta time.

View File

@ -6,6 +6,7 @@ mod tests {
Controller, Energy, Ori, PhysicsState, Poise, Pos, Skill, Stats, Vel,
},
resources::{DeltaTime, GameMode, Time},
shared_server_config::ServerConstants,
terrain::{MapSizeLg, TerrainChunk},
uid::Uid,
util::Dir,
@ -81,6 +82,8 @@ mod tests {
},
false,
None,
// Dummy ServerConstants
&ServerConstants::default(),
);
}

View File

@ -1,6 +1,6 @@
use crate::utils;
use approx::assert_relative_eq;
use common::{comp::Controller, resources::Time};
use common::{comp::Controller, resources::Time, shared_server_config::ServerConstants};
use specs::WorldExt;
use std::error::Error;
use utils::{DT, DT_F64, EPSILON};
@ -18,6 +18,7 @@ fn simple_run() {
},
false,
None,
&ServerConstants::default(),
);
}

View File

@ -7,6 +7,7 @@ use common::{
Vel,
},
resources::{DeltaTime, GameMode, Time},
shared_server_config::ServerConstants,
skillset_builder::SkillSetBuilder,
terrain::{
Block, BlockKind, MapSizeLg, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainGrid,
@ -64,6 +65,7 @@ pub fn tick(state: &mut State, dt: Duration) {
},
false,
None,
&ServerConstants::default(),
);
}

View File

@ -79,6 +79,7 @@ use common::{
event::{EventBus, ServerEvent},
resources::{BattleMode, GameMode, Time, TimeOfDay},
rtsim::RtSimEntity,
shared_server_config::ServerConstants,
slowjob::SlowJobPool,
terrain::{TerrainChunk, TerrainChunkSize},
vol::RectRasterableVol,
@ -205,6 +206,8 @@ pub struct Server {
metrics_shutdown: Arc<Notify>,
database_settings: Arc<RwLock<DatabaseSettings>>,
disconnect_all_clients_requested: bool,
server_constants: ServerConstants,
}
impl Server {
@ -561,6 +564,10 @@ impl Server {
#[cfg(not(feature = "worldgen"))]
rtsim::init(&mut state);
let server_constants = ServerConstants {
day_cycle_coefficient: 1440.0 / settings.day_length,
};
let this = Self {
state,
world,
@ -571,6 +578,8 @@ impl Server {
metrics_shutdown,
database_settings,
disconnect_all_clients_requested: false,
server_constants,
};
debug!(?settings, "created veloren server with");
@ -701,6 +710,7 @@ impl Server {
},
false,
Some(&mut state_tick_metrics),
&self.server_constants,
);
let before_handle_events = Instant::now();

View File

@ -22,6 +22,7 @@ use core::time::Duration;
use portpicker::pick_unused_port;
use serde::{Deserialize, Serialize};
use std::{
fmt::Display,
fs,
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
path::{Path, PathBuf},
@ -166,6 +167,8 @@ pub struct Settings {
pub world_seed: u32,
pub server_name: String,
pub start_time: f64,
/// Length of a day in minutes.
pub day_length: f64,
/// When set to None, loads the default map file (if available); otherwise,
/// uses the value of the file options to decide how to proceed.
pub map_file: Option<FileOpts>,
@ -203,6 +206,7 @@ impl Default for Settings {
world_seed: DEFAULT_WORLD_SEED,
server_name: "Veloren Server".into(),
max_players: 100,
day_length: 30.0,
start_time: 9.0 * 3600.0,
map_file: None,
max_view_distance: Some(65),
@ -223,7 +227,7 @@ impl Settings {
pub fn load(path: &Path) -> Self {
let path = Self::get_settings_path(path);
if let Ok(file) = fs::File::open(&path) {
let mut settings = if let Ok(file) = fs::File::open(&path) {
match ron::de::from_reader(file) {
Ok(x) => x,
Err(e) => {
@ -249,7 +253,10 @@ impl Settings {
error!(?e, "Failed to create default settings file!");
}
default_settings
}
};
settings.validate();
settings
}
fn save_to_file(&self, path: &Path) -> std::io::Result<()> {
@ -302,6 +309,35 @@ impl Settings {
path.push(SETTINGS_FILENAME);
path
}
fn validate(&mut self) {
const INVALID_SETTING_MSG: &str =
"Invalid value for setting in userdata/server/server_config/settings.ron.";
let default_values = Settings::default();
if self.day_length <= 0.0 {
warn!(
"{} Setting: day_length, Value: {}. Set day_length to it's default value of {}. \
Help: day_length must be a positive floating point value above 0.",
INVALID_SETTING_MSG, self.day_length, default_values.day_length
);
self.day_length = default_values.day_length;
}
}
}
pub enum InvalidSettingsError {
InvalidDayDuration,
}
impl Display for InvalidSettingsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
InvalidSettingsError::InvalidDayDuration => {
f.write_str("Invalid settings error: Day length was invalid (zero or negative).")
},
}
}
}
pub fn with_config_dir(path: &Path) -> PathBuf {

View File

@ -10,6 +10,7 @@ use common::{
event::{EventBus, ServerEvent},
recipe::{default_component_recipe_book, default_recipe_book},
resources::TimeOfDay,
shared_server_config::ServerConstants,
uid::{Uid, UidAllocator},
};
use common_base::prof_span;
@ -349,6 +350,9 @@ impl<'a> System<'a> for Sys {
component_recipe_book: default_component_recipe_book().cloned(),
material_stats: (*read_data.material_stats).clone(),
ability_map: (*read_data.ability_map).clone(),
server_constants: ServerConstants {
day_cycle_coefficient: 1440.0 / read_data.settings.day_length
},
})?;
debug!("Done initial sync with client.");