mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
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:
commit
1298fc792b
@ -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
|
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.
|
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)
|
- 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
|
### Changed
|
||||||
- Bats move slower and use a simple proportional controller to maintain altitude
|
- Bats move slower and use a simple proportional controller to maintain altitude
|
||||||
|
@ -40,6 +40,7 @@ use common::{
|
|||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
recipe::{ComponentRecipeBook, RecipeBook},
|
recipe::{ComponentRecipeBook, RecipeBook},
|
||||||
resources::{GameMode, PlayerEntity, Time, TimeOfDay},
|
resources::{GameMode, PlayerEntity, Time, TimeOfDay},
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
spiral::Spiral2d,
|
spiral::Spiral2d,
|
||||||
terrain::{
|
terrain::{
|
||||||
block::Block, map::MapConfig, neighbors, site::DungeonKindMeta, BiomeKind,
|
block::Block, map::MapConfig, neighbors, site::DungeonKindMeta, BiomeKind,
|
||||||
@ -264,6 +265,8 @@ pub struct Client {
|
|||||||
|
|
||||||
pending_chunks: HashMap<Vec2<i32>, Instant>,
|
pending_chunks: HashMap<Vec2<i32>, Instant>,
|
||||||
target_time_of_day: Option<TimeOfDay>,
|
target_time_of_day: Option<TimeOfDay>,
|
||||||
|
|
||||||
|
connected_server_constants: ServerConstants,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds data related to the current players characters, as well as some
|
/// Holds data related to the current players characters, as well as some
|
||||||
@ -355,6 +358,7 @@ impl Client {
|
|||||||
component_recipe_book,
|
component_recipe_book,
|
||||||
material_stats,
|
material_stats,
|
||||||
ability_map,
|
ability_map,
|
||||||
|
server_constants,
|
||||||
} = loop {
|
} = loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
// Spawn in a blocking thread (leaving the network thread free). This is mostly
|
// Spawn in a blocking thread (leaving the network thread free). This is mostly
|
||||||
@ -744,6 +748,8 @@ impl Client {
|
|||||||
|
|
||||||
pending_chunks: HashMap::new(),
|
pending_chunks: HashMap::new(),
|
||||||
target_time_of_day: None,
|
target_time_of_day: None,
|
||||||
|
|
||||||
|
connected_server_constants: server_constants,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1802,6 +1808,7 @@ impl Client {
|
|||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
|
&self.connected_server_constants,
|
||||||
);
|
);
|
||||||
// TODO: avoid emitting these in the first place
|
// TODO: avoid emitting these in the first place
|
||||||
let _ = self
|
let _ = self
|
||||||
|
@ -12,6 +12,7 @@ use common::{
|
|||||||
outcome::Outcome,
|
outcome::Outcome,
|
||||||
recipe::{ComponentRecipeBook, RecipeBook},
|
recipe::{ComponentRecipeBook, RecipeBook},
|
||||||
resources::{Time, TimeOfDay},
|
resources::{Time, TimeOfDay},
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
terrain::{Block, TerrainChunk, TerrainChunkMeta, TerrainChunkSize},
|
||||||
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
@ -66,6 +67,7 @@ pub enum ServerInit {
|
|||||||
component_recipe_book: ComponentRecipeBook,
|
component_recipe_book: ComponentRecipeBook,
|
||||||
material_stats: MaterialStatManifest,
|
material_stats: MaterialStatManifest,
|
||||||
ability_map: comp::item::tool::AbilityMap,
|
ability_map: comp::item::tool::AbilityMap,
|
||||||
|
server_constants: ServerConstants,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ pub mod combat;
|
|||||||
pub mod comp;
|
pub mod comp;
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod resources;
|
pub mod resources;
|
||||||
|
pub mod shared_server_config;
|
||||||
pub mod uid;
|
pub mod uid;
|
||||||
|
|
||||||
// NOTE: Comment out macro to get rustfmt to re-order these as needed.
|
// NOTE: Comment out macro to get rustfmt to re-order these as needed.
|
||||||
|
16
common/src/shared_server_config.rs
Normal file
16
common/src/shared_server_config.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ use common::{
|
|||||||
DeltaTime, EntitiesDiedLastTick, GameMode, PlayerEntity, PlayerPhysicsSettings, Time,
|
DeltaTime, EntitiesDiedLastTick, GameMode, PlayerEntity, PlayerPhysicsSettings, Time,
|
||||||
TimeOfDay,
|
TimeOfDay,
|
||||||
},
|
},
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
slowjob::SlowJobPool,
|
slowjob::SlowJobPool,
|
||||||
terrain::{Block, MapSizeLg, TerrainChunk, TerrainGrid},
|
terrain::{Block, MapSizeLg, TerrainChunk, TerrainGrid},
|
||||||
time::DayPeriod,
|
time::DayPeriod,
|
||||||
@ -39,9 +40,6 @@ use std::{sync::Arc, time::Instant};
|
|||||||
use timer_queue::TimerQueue;
|
use timer_queue::TimerQueue;
|
||||||
use vek::*;
|
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
|
/// 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
|
/// we speed physics up too fast, we'd skip important physics events like
|
||||||
/// collisions. This constant determines the upper limit. If delta time exceeds
|
/// collisions. This constant determines the upper limit. If delta time exceeds
|
||||||
@ -598,6 +596,7 @@ impl State {
|
|||||||
add_systems: impl Fn(&mut DispatcherBuilder),
|
add_systems: impl Fn(&mut DispatcherBuilder),
|
||||||
update_terrain_and_regions: bool,
|
update_terrain_and_regions: bool,
|
||||||
mut metrics: Option<&mut StateTickMetrics>,
|
mut metrics: Option<&mut StateTickMetrics>,
|
||||||
|
server_constants: &ServerConstants,
|
||||||
) {
|
) {
|
||||||
span!(_guard, "tick", "State::tick");
|
span!(_guard, "tick", "State::tick");
|
||||||
|
|
||||||
@ -611,7 +610,8 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change the time accordingly.
|
// 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();
|
self.ecs.write_resource::<Time>().0 += dt.as_secs_f64();
|
||||||
|
|
||||||
// Update delta time.
|
// Update delta time.
|
||||||
|
@ -6,6 +6,7 @@ mod tests {
|
|||||||
Controller, Energy, Ori, PhysicsState, Poise, Pos, Skill, Stats, Vel,
|
Controller, Energy, Ori, PhysicsState, Poise, Pos, Skill, Stats, Vel,
|
||||||
},
|
},
|
||||||
resources::{DeltaTime, GameMode, Time},
|
resources::{DeltaTime, GameMode, Time},
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
terrain::{MapSizeLg, TerrainChunk},
|
terrain::{MapSizeLg, TerrainChunk},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
util::Dir,
|
util::Dir,
|
||||||
@ -81,6 +82,8 @@ mod tests {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
// Dummy ServerConstants
|
||||||
|
&ServerConstants::default(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::utils;
|
use crate::utils;
|
||||||
use approx::assert_relative_eq;
|
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 specs::WorldExt;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use utils::{DT, DT_F64, EPSILON};
|
use utils::{DT, DT_F64, EPSILON};
|
||||||
@ -18,6 +18,7 @@ fn simple_run() {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
&ServerConstants::default(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use common::{
|
|||||||
Vel,
|
Vel,
|
||||||
},
|
},
|
||||||
resources::{DeltaTime, GameMode, Time},
|
resources::{DeltaTime, GameMode, Time},
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
skillset_builder::SkillSetBuilder,
|
skillset_builder::SkillSetBuilder,
|
||||||
terrain::{
|
terrain::{
|
||||||
Block, BlockKind, MapSizeLg, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainGrid,
|
Block, BlockKind, MapSizeLg, SpriteKind, TerrainChunk, TerrainChunkMeta, TerrainGrid,
|
||||||
@ -64,6 +65,7 @@ pub fn tick(state: &mut State, dt: Duration) {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
&ServerConstants::default(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ use common::{
|
|||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
resources::{BattleMode, GameMode, Time, TimeOfDay},
|
resources::{BattleMode, GameMode, Time, TimeOfDay},
|
||||||
rtsim::RtSimEntity,
|
rtsim::RtSimEntity,
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
slowjob::SlowJobPool,
|
slowjob::SlowJobPool,
|
||||||
terrain::{TerrainChunk, TerrainChunkSize},
|
terrain::{TerrainChunk, TerrainChunkSize},
|
||||||
vol::RectRasterableVol,
|
vol::RectRasterableVol,
|
||||||
@ -205,6 +206,8 @@ pub struct Server {
|
|||||||
metrics_shutdown: Arc<Notify>,
|
metrics_shutdown: Arc<Notify>,
|
||||||
database_settings: Arc<RwLock<DatabaseSettings>>,
|
database_settings: Arc<RwLock<DatabaseSettings>>,
|
||||||
disconnect_all_clients_requested: bool,
|
disconnect_all_clients_requested: bool,
|
||||||
|
|
||||||
|
server_constants: ServerConstants,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
@ -561,6 +564,10 @@ impl Server {
|
|||||||
#[cfg(not(feature = "worldgen"))]
|
#[cfg(not(feature = "worldgen"))]
|
||||||
rtsim::init(&mut state);
|
rtsim::init(&mut state);
|
||||||
|
|
||||||
|
let server_constants = ServerConstants {
|
||||||
|
day_cycle_coefficient: 1440.0 / settings.day_length,
|
||||||
|
};
|
||||||
|
|
||||||
let this = Self {
|
let this = Self {
|
||||||
state,
|
state,
|
||||||
world,
|
world,
|
||||||
@ -571,6 +578,8 @@ impl Server {
|
|||||||
metrics_shutdown,
|
metrics_shutdown,
|
||||||
database_settings,
|
database_settings,
|
||||||
disconnect_all_clients_requested: false,
|
disconnect_all_clients_requested: false,
|
||||||
|
|
||||||
|
server_constants,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!(?settings, "created veloren server with");
|
debug!(?settings, "created veloren server with");
|
||||||
@ -701,6 +710,7 @@ impl Server {
|
|||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
Some(&mut state_tick_metrics),
|
Some(&mut state_tick_metrics),
|
||||||
|
&self.server_constants,
|
||||||
);
|
);
|
||||||
|
|
||||||
let before_handle_events = Instant::now();
|
let before_handle_events = Instant::now();
|
||||||
|
@ -22,6 +22,7 @@ use core::time::Duration;
|
|||||||
use portpicker::pick_unused_port;
|
use portpicker::pick_unused_port;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
|
fmt::Display,
|
||||||
fs,
|
fs,
|
||||||
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
|
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
@ -166,6 +167,8 @@ pub struct Settings {
|
|||||||
pub world_seed: u32,
|
pub world_seed: u32,
|
||||||
pub server_name: String,
|
pub server_name: String,
|
||||||
pub start_time: f64,
|
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,
|
/// When set to None, loads the default map file (if available); otherwise,
|
||||||
/// uses the value of the file options to decide how to proceed.
|
/// uses the value of the file options to decide how to proceed.
|
||||||
pub map_file: Option<FileOpts>,
|
pub map_file: Option<FileOpts>,
|
||||||
@ -203,6 +206,7 @@ impl Default for Settings {
|
|||||||
world_seed: DEFAULT_WORLD_SEED,
|
world_seed: DEFAULT_WORLD_SEED,
|
||||||
server_name: "Veloren Server".into(),
|
server_name: "Veloren Server".into(),
|
||||||
max_players: 100,
|
max_players: 100,
|
||||||
|
day_length: 30.0,
|
||||||
start_time: 9.0 * 3600.0,
|
start_time: 9.0 * 3600.0,
|
||||||
map_file: None,
|
map_file: None,
|
||||||
max_view_distance: Some(65),
|
max_view_distance: Some(65),
|
||||||
@ -223,7 +227,7 @@ impl Settings {
|
|||||||
pub fn load(path: &Path) -> Self {
|
pub fn load(path: &Path) -> Self {
|
||||||
let path = Self::get_settings_path(path);
|
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) {
|
match ron::de::from_reader(file) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -249,7 +253,10 @@ impl Settings {
|
|||||||
error!(?e, "Failed to create default settings file!");
|
error!(?e, "Failed to create default settings file!");
|
||||||
}
|
}
|
||||||
default_settings
|
default_settings
|
||||||
}
|
};
|
||||||
|
|
||||||
|
settings.validate();
|
||||||
|
settings
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_to_file(&self, path: &Path) -> std::io::Result<()> {
|
fn save_to_file(&self, path: &Path) -> std::io::Result<()> {
|
||||||
@ -302,6 +309,35 @@ impl Settings {
|
|||||||
path.push(SETTINGS_FILENAME);
|
path.push(SETTINGS_FILENAME);
|
||||||
path
|
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 {
|
pub fn with_config_dir(path: &Path) -> PathBuf {
|
||||||
|
@ -10,6 +10,7 @@ use common::{
|
|||||||
event::{EventBus, ServerEvent},
|
event::{EventBus, ServerEvent},
|
||||||
recipe::{default_component_recipe_book, default_recipe_book},
|
recipe::{default_component_recipe_book, default_recipe_book},
|
||||||
resources::TimeOfDay,
|
resources::TimeOfDay,
|
||||||
|
shared_server_config::ServerConstants,
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
};
|
};
|
||||||
use common_base::prof_span;
|
use common_base::prof_span;
|
||||||
@ -349,6 +350,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
component_recipe_book: default_component_recipe_book().cloned(),
|
component_recipe_book: default_component_recipe_book().cloned(),
|
||||||
material_stats: (*read_data.material_stats).clone(),
|
material_stats: (*read_data.material_stats).clone(),
|
||||||
ability_map: (*read_data.ability_map).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.");
|
debug!("Done initial sync with client.");
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user