Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
pub mod admin;
|
|
|
|
pub mod banlist;
|
2020-10-05 07:41:58 +00:00
|
|
|
mod editable;
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
pub mod server_description;
|
|
|
|
pub mod whitelist;
|
2020-10-05 07:41:58 +00:00
|
|
|
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
pub use editable::{EditableSetting, Error as SettingError};
|
2020-10-05 07:41:58 +00:00
|
|
|
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
pub use admin::{AdminRecord, Admins};
|
|
|
|
pub use banlist::{
|
|
|
|
Ban, BanAction, BanEntry, BanError, BanErrorKind, BanInfo, BanKind, BanRecord, Banlist,
|
|
|
|
};
|
|
|
|
pub use server_description::ServerDescription;
|
|
|
|
pub use whitelist::{Whitelist, WhitelistInfo, WhitelistRecord};
|
|
|
|
|
|
|
|
use chrono::Utc;
|
2021-12-07 22:00:43 +00:00
|
|
|
use common::{
|
|
|
|
calendar::{Calendar, CalendarEvent},
|
|
|
|
resources::BattleMode,
|
|
|
|
};
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
use core::time::Duration;
|
2019-10-11 12:19:55 +00:00
|
|
|
use portpicker::pick_unused_port;
|
2020-07-06 14:23:08 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-10-05 07:41:58 +00:00
|
|
|
use std::{
|
|
|
|
fs,
|
2021-10-15 10:46:20 +00:00
|
|
|
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
|
2020-10-05 07:41:58 +00:00
|
|
|
path::{Path, PathBuf},
|
|
|
|
};
|
2020-06-21 14:26:06 +00:00
|
|
|
use tracing::{error, warn};
|
2020-01-18 18:41:37 +00:00
|
|
|
use world::sim::FileOpts;
|
|
|
|
|
2021-07-24 10:56:08 +00:00
|
|
|
const DEFAULT_WORLD_SEED: u32 = 230;
|
2020-10-06 02:59:47 +00:00
|
|
|
const CONFIG_DIR: &str = "server_config";
|
2020-10-05 08:56:28 +00:00
|
|
|
const SETTINGS_FILENAME: &str = "settings.ron";
|
|
|
|
const WHITELIST_FILENAME: &str = "whitelist.ron";
|
|
|
|
const BANLIST_FILENAME: &str = "banlist.ron";
|
|
|
|
const SERVER_DESCRIPTION_FILENAME: &str = "description.ron";
|
2020-10-10 06:10:04 +00:00
|
|
|
const ADMINS_FILENAME: &str = "admins.ron";
|
2019-06-29 16:41:26 +00:00
|
|
|
|
2021-08-27 14:08:18 +00:00
|
|
|
#[derive(Copy, Clone, Debug, Deserialize, Serialize)]
|
|
|
|
pub enum ServerBattleMode {
|
|
|
|
Global(BattleMode),
|
|
|
|
PerPlayer { default: BattleMode },
|
|
|
|
}
|
|
|
|
|
2021-08-27 22:42:42 +00:00
|
|
|
impl ServerBattleMode {
|
|
|
|
pub fn allow_choosing(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
ServerBattleMode::Global { .. } => false,
|
|
|
|
ServerBattleMode::PerPlayer { .. } => true,
|
|
|
|
}
|
|
|
|
}
|
2021-09-03 22:40:02 +00:00
|
|
|
|
|
|
|
pub fn default_mode(&self) -> BattleMode {
|
|
|
|
match self {
|
|
|
|
ServerBattleMode::Global(mode) => *mode,
|
|
|
|
ServerBattleMode::PerPlayer { default: mode } => *mode,
|
|
|
|
}
|
|
|
|
}
|
2021-08-27 22:42:42 +00:00
|
|
|
}
|
|
|
|
|
2021-10-15 11:45:55 +00:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
2021-10-15 10:46:20 +00:00
|
|
|
pub enum Protocol {
|
2021-10-15 11:45:55 +00:00
|
|
|
Quic {
|
|
|
|
address: SocketAddr,
|
|
|
|
cert_file_path: PathBuf,
|
|
|
|
key_file_path: PathBuf,
|
|
|
|
},
|
|
|
|
Tcp {
|
|
|
|
address: SocketAddr,
|
|
|
|
},
|
2021-10-15 10:46:20 +00:00
|
|
|
}
|
|
|
|
|
2021-12-06 22:17:20 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
pub enum CalendarMode {
|
|
|
|
None,
|
|
|
|
Auto,
|
|
|
|
Timezone(chrono_tz::Tz),
|
|
|
|
Events(Vec<CalendarEvent>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for CalendarMode {
|
|
|
|
fn default() -> Self { Self::Auto }
|
|
|
|
}
|
|
|
|
|
2021-12-06 23:06:48 +00:00
|
|
|
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()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-29 16:41:26 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
#[serde(default)]
|
2020-10-06 02:59:47 +00:00
|
|
|
pub struct Settings {
|
2021-10-15 11:45:55 +00:00
|
|
|
pub gameserver_protocols: Vec<Protocol>,
|
2019-10-11 12:19:55 +00:00
|
|
|
pub metrics_address: SocketAddr,
|
2019-12-21 17:02:39 +00:00
|
|
|
pub auth_server_address: Option<String>,
|
2019-07-01 11:19:26 +00:00
|
|
|
pub max_players: usize,
|
2019-06-29 16:41:26 +00:00
|
|
|
pub world_seed: u32,
|
2021-08-27 14:08:18 +00:00
|
|
|
pub battle_mode: ServerBattleMode,
|
2019-07-01 09:37:17 +00:00
|
|
|
pub server_name: String,
|
2019-07-12 13:03:35 +00:00
|
|
|
pub start_time: f64,
|
2020-02-01 20:39:39 +00:00
|
|
|
/// When set to None, loads the default map file (if available); otherwise,
|
|
|
|
/// uses the value of the file options to decide how to proceed.
|
2020-01-18 18:41:37 +00:00
|
|
|
pub map_file: Option<FileOpts>,
|
2020-06-25 11:20:09 +00:00
|
|
|
pub max_view_distance: Option<u32>,
|
2020-07-16 14:05:35 +00:00
|
|
|
pub banned_words_files: Vec<PathBuf>,
|
2020-08-07 01:59:28 +00:00
|
|
|
pub max_player_group_size: u32,
|
2020-09-06 19:24:52 +00:00
|
|
|
pub client_timeout: Duration,
|
2021-03-25 22:09:27 +00:00
|
|
|
pub spawn_town: Option<String>,
|
2021-04-17 21:54:11 +00:00
|
|
|
pub safe_spawn: bool,
|
2021-04-18 20:46:16 +00:00
|
|
|
pub max_player_for_kill_broadcast: Option<usize>,
|
2021-12-06 22:17:20 +00:00
|
|
|
pub calendar_mode: CalendarMode,
|
2021-07-23 12:04:16 +00:00
|
|
|
|
|
|
|
/// Experimental feature. No guaranteed forwards-compatibility, may be
|
|
|
|
/// removed at *any time* with no migration.
|
|
|
|
#[serde(default, skip_serializing)]
|
|
|
|
pub experimental_terrain_persistence: bool,
|
2019-06-29 16:41:26 +00:00
|
|
|
}
|
|
|
|
|
2020-10-06 02:59:47 +00:00
|
|
|
impl Default for Settings {
|
2019-06-29 16:41:26 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
2021-10-15 11:45:55 +00:00
|
|
|
gameserver_protocols: vec![
|
|
|
|
Protocol::Tcp {
|
|
|
|
address: SocketAddr::from((Ipv6Addr::UNSPECIFIED, 14004)),
|
|
|
|
},
|
|
|
|
Protocol::Tcp {
|
|
|
|
address: SocketAddr::from((Ipv4Addr::UNSPECIFIED, 14004)),
|
|
|
|
},
|
2021-10-15 10:46:20 +00:00
|
|
|
],
|
|
|
|
metrics_address: SocketAddr::from((Ipv4Addr::LOCALHOST, 14005)),
|
2021-03-11 15:57:50 +00:00
|
|
|
auth_server_address: Some("https://auth.veloren.net".into()),
|
2020-01-18 18:41:37 +00:00
|
|
|
world_seed: DEFAULT_WORLD_SEED,
|
2020-10-05 07:41:58 +00:00
|
|
|
server_name: "Veloren Alpha".into(),
|
2019-07-28 09:21:17 +00:00
|
|
|
max_players: 100,
|
2021-08-27 14:08:18 +00:00
|
|
|
battle_mode: ServerBattleMode::Global(BattleMode::PvP),
|
2019-07-28 10:46:03 +00:00
|
|
|
start_time: 9.0 * 3600.0,
|
2019-12-11 09:14:50 +00:00
|
|
|
map_file: None,
|
2021-03-20 15:21:41 +00:00
|
|
|
max_view_distance: Some(65),
|
2020-07-16 14:05:35 +00:00
|
|
|
banned_words_files: Vec::new(),
|
2020-08-07 01:59:28 +00:00
|
|
|
max_player_group_size: 6,
|
2021-12-06 22:17:20 +00:00
|
|
|
calendar_mode: CalendarMode::Auto,
|
2020-09-06 19:24:52 +00:00
|
|
|
client_timeout: Duration::from_secs(40),
|
2021-03-25 22:09:27 +00:00
|
|
|
spawn_town: None,
|
2021-04-17 21:54:11 +00:00
|
|
|
safe_spawn: true,
|
2021-04-18 20:46:16 +00:00
|
|
|
max_player_for_kill_broadcast: None,
|
2021-07-23 12:04:16 +00:00
|
|
|
experimental_terrain_persistence: false,
|
2019-06-29 16:41:26 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-01 09:37:17 +00:00
|
|
|
}
|
2019-06-29 16:41:26 +00:00
|
|
|
|
2020-10-06 02:59:47 +00:00
|
|
|
impl Settings {
|
2020-10-05 07:41:58 +00:00
|
|
|
/// path: Directory that contains the server config directory
|
|
|
|
pub fn load(path: &Path) -> Self {
|
|
|
|
let path = Self::get_settings_path(path);
|
2019-06-29 16:41:26 +00:00
|
|
|
|
2020-10-05 07:41:58 +00:00
|
|
|
if let Ok(file) = fs::File::open(&path) {
|
2019-07-04 17:37:56 +00:00
|
|
|
match ron::de::from_reader(file) {
|
|
|
|
Ok(x) => x,
|
|
|
|
Err(e) => {
|
2020-10-25 20:19:39 +00:00
|
|
|
let default_settings = Self::default();
|
|
|
|
let template_path = path.with_extension("template.ron");
|
2020-10-05 07:41:58 +00:00
|
|
|
warn!(
|
|
|
|
?e,
|
|
|
|
"Failed to parse setting file! Falling back to default settings and \
|
2020-10-25 20:19:39 +00:00
|
|
|
creating a template file for you to migrate your current settings file: \
|
|
|
|
{}",
|
|
|
|
template_path.display()
|
2020-10-05 07:41:58 +00:00
|
|
|
);
|
|
|
|
if let Err(e) = default_settings.save_to_file(&template_path) {
|
|
|
|
error!(?e, "Failed to create template settings file")
|
|
|
|
}
|
|
|
|
default_settings
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-07-04 17:37:56 +00:00
|
|
|
}
|
2019-06-29 16:41:26 +00:00
|
|
|
} else {
|
2019-07-04 17:37:56 +00:00
|
|
|
let default_settings = Self::default();
|
|
|
|
|
2020-10-05 07:41:58 +00:00
|
|
|
if let Err(e) = default_settings.save_to_file(&path) {
|
|
|
|
error!(?e, "Failed to create default settings file!");
|
2019-07-04 17:37:56 +00:00
|
|
|
}
|
|
|
|
default_settings
|
2019-06-29 16:41:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-05 07:41:58 +00:00
|
|
|
fn save_to_file(&self, path: &Path) -> std::io::Result<()> {
|
|
|
|
// Create dir if it doesn't exist
|
|
|
|
if let Some(dir) = path.parent() {
|
|
|
|
fs::create_dir_all(dir)?;
|
|
|
|
}
|
|
|
|
let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default())
|
2019-10-23 18:23:31 +00:00
|
|
|
.expect("Failed serialize settings.");
|
2020-10-05 07:41:58 +00:00
|
|
|
|
|
|
|
fs::write(path, ron.as_bytes())?;
|
|
|
|
|
2019-06-29 16:41:26 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-10-05 07:41:58 +00:00
|
|
|
/// path: Directory that contains the server config directory
|
|
|
|
pub fn singleplayer(path: &Path) -> Self {
|
2021-07-11 18:41:52 +00:00
|
|
|
let load = Self::load(path);
|
2019-08-14 15:51:59 +00:00
|
|
|
Self {
|
2021-10-15 10:46:20 +00:00
|
|
|
// BUG: theoretically another process can grab the port between here and server
|
|
|
|
// creation, however the time window is quite small.
|
2021-10-15 11:45:55 +00:00
|
|
|
gameserver_protocols: vec![Protocol::Tcp {
|
|
|
|
address: SocketAddr::from((
|
2021-10-15 10:46:20 +00:00
|
|
|
Ipv4Addr::LOCALHOST,
|
|
|
|
pick_unused_port().expect("Failed to find unused port!"),
|
|
|
|
)),
|
2021-10-15 11:45:55 +00:00
|
|
|
}],
|
2019-10-11 12:19:55 +00:00
|
|
|
metrics_address: SocketAddr::from((
|
2021-10-15 10:46:20 +00:00
|
|
|
Ipv4Addr::LOCALHOST,
|
2019-10-11 12:19:55 +00:00
|
|
|
pick_unused_port().expect("Failed to find unused port!"),
|
|
|
|
)),
|
2019-12-21 17:02:39 +00:00
|
|
|
auth_server_address: None,
|
2020-01-24 02:45:29 +00:00
|
|
|
// If loading the default map file, make sure the seed is also default.
|
|
|
|
world_seed: if load.map_file.is_some() {
|
|
|
|
load.world_seed
|
|
|
|
} else {
|
|
|
|
DEFAULT_WORLD_SEED
|
|
|
|
},
|
2019-08-14 15:51:59 +00:00
|
|
|
server_name: "Singleplayer".to_owned(),
|
|
|
|
max_players: 100,
|
|
|
|
start_time: 9.0 * 3600.0,
|
2020-07-06 08:37:44 +00:00
|
|
|
max_view_distance: None,
|
2021-07-31 19:33:28 +00:00
|
|
|
safe_spawn: false,
|
2020-09-06 19:24:52 +00:00
|
|
|
client_timeout: Duration::from_secs(180),
|
2020-04-15 11:31:16 +00:00
|
|
|
..load // Fill in remaining fields from server_settings.ron.
|
2019-08-14 15:51:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-05 07:41:58 +00:00
|
|
|
fn get_settings_path(path: &Path) -> PathBuf {
|
|
|
|
let mut path = with_config_dir(path);
|
|
|
|
path.push(SETTINGS_FILENAME);
|
|
|
|
path
|
2020-06-25 13:56:21 +00:00
|
|
|
}
|
2019-07-01 09:37:17 +00:00
|
|
|
}
|
2020-10-05 07:41:58 +00:00
|
|
|
|
|
|
|
fn with_config_dir(path: &Path) -> PathBuf {
|
|
|
|
let mut path = PathBuf::from(path);
|
2020-10-06 02:59:47 +00:00
|
|
|
path.push(CONFIG_DIR);
|
2020-10-05 07:41:58 +00:00
|
|
|
path
|
|
|
|
}
|
|
|
|
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
/// Our upgrade guarantee is that if validation succeeds
|
|
|
|
/// for an old version, then migration to the next version must always succeed
|
|
|
|
/// and produce a valid settings file for that version (if we need to change
|
|
|
|
/// this in the future, it should require careful discussion). Therefore, we
|
|
|
|
/// would normally panic if the upgrade produced an invalid settings file, which
|
|
|
|
/// we would perform by doing the following post-validation (example
|
|
|
|
/// is given for a hypothetical upgrade from Whitelist_V1 to Whitelist_V2):
|
|
|
|
///
|
|
|
|
/// Ok(Whitelist_V2::try_into().expect())
|
|
|
|
const MIGRATION_UPGRADE_GUARANTEE: &str = "Any valid file of an old verison should be able to \
|
|
|
|
successfully migrate to the latest version.";
|
2020-10-05 07:41:58 +00:00
|
|
|
|
2020-10-06 02:59:47 +00:00
|
|
|
/// Combines all the editable settings into one struct that is stored in the ecs
|
|
|
|
pub struct EditableSettings {
|
|
|
|
pub whitelist: Whitelist,
|
|
|
|
pub banlist: Banlist,
|
|
|
|
pub server_description: ServerDescription,
|
2020-10-10 06:10:04 +00:00
|
|
|
pub admins: Admins,
|
2020-10-06 02:59:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl EditableSettings {
|
|
|
|
pub fn load(data_dir: &Path) -> Self {
|
|
|
|
Self {
|
|
|
|
whitelist: Whitelist::load(data_dir),
|
|
|
|
banlist: Banlist::load(data_dir),
|
|
|
|
server_description: ServerDescription::load(data_dir),
|
2020-10-10 06:10:04 +00:00
|
|
|
admins: Admins::load(data_dir),
|
2020-10-06 02:59:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn singleplayer(data_dir: &Path) -> Self {
|
|
|
|
let load = Self::load(data_dir);
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
|
|
|
|
let mut server_description = ServerDescription::default();
|
|
|
|
*server_description = "Who needs friends anyway?".into();
|
|
|
|
|
|
|
|
let mut admins = Admins::default();
|
|
|
|
// TODO: Let the player choose if they want to use admin commands or not
|
|
|
|
admins.insert(
|
|
|
|
crate::login_provider::derive_singleplayer_uuid(),
|
|
|
|
AdminRecord {
|
|
|
|
username_when_admined: Some("singleplayer".into()),
|
|
|
|
date: Utc::now(),
|
|
|
|
role: admin::Role::Admin,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2020-10-06 02:59:47 +00:00
|
|
|
Self {
|
Added non-admin moderators and timed bans.
The security model has been updated to reflect this change (for example,
moderators cannot revert a ban by an administrator). Ban history is
also now recorded in the ban file, and much more information about the
ban is stored (whitelists and administrators also have extra
information).
To support the new information without losing important information,
this commit also introduces a new migration path for editable settings
(both from legacy to the new format, and between versions). Examples
of how to do this correctly, and migrate to new versions of a settings
file, are in the settings/ subdirectory.
As part of this effort, editable settings have been revamped to
guarantee atomic saves (due to the increased amount of information in
each file), some latent bugs in networking were fixed, and server-cli
has been updated to go through StructOpt for both calls through TUI
and argv, greatly simplifying parsing logic.
2021-05-08 18:22:21 +00:00
|
|
|
server_description,
|
|
|
|
admins,
|
2020-10-06 02:59:47 +00:00
|
|
|
..load
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|