2020-10-05 07:41:58 +00:00
|
|
|
use directories_next::UserDirs;
|
2020-10-05 08:35:24 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-04-13 13:24:47 +00:00
|
|
|
use std::{fs, path::PathBuf};
|
2020-06-21 10:22:26 +00:00
|
|
|
use tracing::warn;
|
2020-03-10 21:00:13 +00:00
|
|
|
|
2021-05-14 12:27:15 +00:00
|
|
|
pub mod audio;
|
|
|
|
pub mod chat;
|
|
|
|
pub mod control;
|
|
|
|
pub mod gamepad;
|
|
|
|
pub mod gameplay;
|
|
|
|
pub mod graphics;
|
|
|
|
pub mod interface;
|
|
|
|
pub mod language;
|
|
|
|
pub mod networking;
|
2021-04-13 13:24:47 +00:00
|
|
|
|
|
|
|
pub use audio::{AudioOutput, AudioSettings};
|
2021-05-14 12:27:15 +00:00
|
|
|
pub use chat::ChatSettings;
|
2021-04-13 13:24:47 +00:00
|
|
|
pub use control::ControlSettings;
|
|
|
|
pub use gamepad::GamepadSettings;
|
|
|
|
pub use gameplay::GameplaySettings;
|
|
|
|
pub use graphics::{get_fps, Fps, GraphicsSettings};
|
|
|
|
pub use interface::InterfaceSettings;
|
|
|
|
pub use language::LanguageSettings;
|
|
|
|
pub use networking::NetworkingSettings;
|
2019-06-08 23:35:23 +00:00
|
|
|
|
2019-12-18 19:35:17 +00:00
|
|
|
/// `Log` stores whether we should create a log file
|
2019-04-25 11:49:36 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2019-06-08 23:35:23 +00:00
|
|
|
#[serde(default)]
|
2019-04-25 11:49:36 +00:00
|
|
|
pub struct Log {
|
2019-12-18 19:35:17 +00:00
|
|
|
// Whether to create a log file or not.
|
|
|
|
// Default is to create one.
|
|
|
|
pub log_to_file: bool,
|
2020-03-05 19:26:07 +00:00
|
|
|
// The path on which the logs will be stored
|
|
|
|
pub logs_path: PathBuf,
|
2019-04-25 11:49:36 +00:00
|
|
|
}
|
|
|
|
|
2019-06-08 23:35:23 +00:00
|
|
|
impl Default for Log {
|
2020-03-05 19:26:07 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
// Chooses a path to store the logs by the following order:
|
|
|
|
// - The VOXYGEN_LOGS environment variable
|
|
|
|
// - The ProjectsDirs data local directory
|
2020-11-25 19:36:41 +00:00
|
|
|
// This function is only called if there isn't already an entry in the settings
|
|
|
|
// file. However, the VOXYGEN_LOGS environment variable always overrides
|
|
|
|
// the log file path if set.
|
2020-03-05 19:26:07 +00:00
|
|
|
let logs_path = std::env::var_os("VOXYGEN_LOGS")
|
|
|
|
.map(PathBuf::from)
|
2020-10-05 07:41:58 +00:00
|
|
|
.unwrap_or_else(|| {
|
|
|
|
let mut path = voxygen_data_dir();
|
|
|
|
path.push("logs");
|
|
|
|
path
|
|
|
|
});
|
2020-03-05 19:26:07 +00:00
|
|
|
|
|
|
|
Self {
|
|
|
|
log_to_file: true,
|
|
|
|
logs_path,
|
|
|
|
}
|
|
|
|
}
|
2019-06-08 23:35:23 +00:00
|
|
|
}
|
|
|
|
|
2020-02-01 20:39:39 +00:00
|
|
|
/// `Settings` contains everything that can be configured in the settings.ron
|
|
|
|
/// file.
|
2019-06-08 23:35:23 +00:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
|
|
#[serde(default)]
|
|
|
|
pub struct Settings {
|
2021-05-14 12:27:15 +00:00
|
|
|
pub chat: ChatSettings,
|
2019-06-08 23:35:23 +00:00
|
|
|
pub controls: ControlSettings,
|
2021-03-12 19:09:25 +00:00
|
|
|
pub interface: InterfaceSettings,
|
2019-06-08 23:35:23 +00:00
|
|
|
pub gameplay: GameplaySettings,
|
|
|
|
pub networking: NetworkingSettings,
|
|
|
|
pub log: Log,
|
|
|
|
pub graphics: GraphicsSettings,
|
|
|
|
pub audio: AudioSettings,
|
|
|
|
pub show_disclaimer: bool,
|
2019-07-18 22:50:46 +00:00
|
|
|
pub send_logon_commands: bool,
|
|
|
|
// TODO: Remove at a later date, for dev testing
|
|
|
|
pub logon_commands: Vec<String>,
|
2020-01-17 23:43:18 +00:00
|
|
|
pub language: LanguageSettings,
|
2020-03-05 19:26:07 +00:00
|
|
|
pub screenshots_path: PathBuf,
|
2020-03-10 21:00:13 +00:00
|
|
|
pub controller: GamepadSettings,
|
2019-06-08 23:35:23 +00:00
|
|
|
}
|
|
|
|
|
2019-04-16 17:41:39 +00:00
|
|
|
impl Default for Settings {
|
|
|
|
fn default() -> Self {
|
2020-03-05 19:26:07 +00:00
|
|
|
let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
|
|
|
|
|
|
|
|
// Chooses a path to store the screenshots by the following order:
|
|
|
|
// - The VOXYGEN_SCREENSHOT environment variable
|
|
|
|
// - The user's picture directory
|
|
|
|
// - The executable's directory
|
|
|
|
// This only selects if there isn't already an entry in the settings file
|
|
|
|
let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
|
|
|
|
.map(PathBuf::from)
|
2020-10-05 07:41:58 +00:00
|
|
|
.or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
|
|
|
|
.or_else(|| {
|
|
|
|
std::env::current_exe()
|
|
|
|
.ok()
|
|
|
|
.and_then(|dir| dir.parent().map(PathBuf::from))
|
|
|
|
})
|
2020-03-05 19:26:07 +00:00
|
|
|
.expect("Couldn't choose a place to store the screenshots");
|
|
|
|
|
2019-04-16 08:56:47 +00:00
|
|
|
Settings {
|
2021-05-14 12:27:15 +00:00
|
|
|
chat: ChatSettings::default(),
|
2019-06-08 23:35:23 +00:00
|
|
|
controls: ControlSettings::default(),
|
2021-03-12 19:09:25 +00:00
|
|
|
interface: InterfaceSettings::default(),
|
2019-06-08 23:35:23 +00:00
|
|
|
gameplay: GameplaySettings::default(),
|
|
|
|
networking: NetworkingSettings::default(),
|
|
|
|
log: Log::default(),
|
|
|
|
graphics: GraphicsSettings::default(),
|
|
|
|
audio: AudioSettings::default(),
|
2019-05-26 20:42:45 +00:00
|
|
|
show_disclaimer: true,
|
2019-07-18 22:50:46 +00:00
|
|
|
send_logon_commands: false,
|
|
|
|
logon_commands: Vec::new(),
|
2020-01-17 23:43:18 +00:00
|
|
|
language: LanguageSettings::default(),
|
2020-03-05 19:26:07 +00:00
|
|
|
screenshots_path,
|
2020-03-10 21:00:13 +00:00
|
|
|
controller: GamepadSettings::default(),
|
2019-04-16 08:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-16 17:41:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Settings {
|
2019-05-17 07:55:51 +00:00
|
|
|
pub fn load() -> Self {
|
2020-10-05 08:35:24 +00:00
|
|
|
let path = Self::get_settings_path();
|
2019-08-11 19:18:18 +00:00
|
|
|
|
2019-08-11 04:02:49 +00:00
|
|
|
if let Ok(file) = fs::File::open(&path) {
|
2020-11-25 19:36:41 +00:00
|
|
|
match ron::de::from_reader::<_, Self>(file) {
|
|
|
|
Ok(mut s) => {
|
|
|
|
// Override the logs path if it is explicitly set using the VOXYGEN_LOGS
|
|
|
|
// environment variable. This is needed to support package managers that enforce
|
|
|
|
// strict application confinement (e.g. snap). In fact, the veloren snap package
|
|
|
|
// relies on this environment variable to be respected in
|
|
|
|
// order to communicate a path where the snap package is
|
|
|
|
// allowed to write to.
|
|
|
|
if let Some(logs_path_override) =
|
|
|
|
std::env::var_os("VOXYGEN_LOGS").map(PathBuf::from)
|
|
|
|
{
|
|
|
|
s.log.logs_path = logs_path_override;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
},
|
2019-08-11 04:02:49 +00:00
|
|
|
Err(e) => {
|
2020-06-21 21:47:49 +00:00
|
|
|
warn!(?e, "Failed to parse setting file! Fallback to default.");
|
2019-08-11 04:02:49 +00:00
|
|
|
// Rename the corrupted settings file
|
|
|
|
let mut new_path = path.to_owned();
|
|
|
|
new_path.pop();
|
|
|
|
new_path.push("settings.invalid.ron");
|
2020-10-05 07:41:58 +00:00
|
|
|
if let Err(e) = std::fs::rename(&path, &new_path) {
|
2020-06-21 21:47:49 +00:00
|
|
|
warn!(?e, ?path, ?new_path, "Failed to rename settings file.");
|
2019-08-11 04:02:49 +00:00
|
|
|
}
|
2020-02-01 20:39:39 +00:00
|
|
|
},
|
2019-08-11 04:02:49 +00:00
|
|
|
}
|
2019-05-17 07:55:51 +00:00
|
|
|
}
|
2019-09-13 03:37:28 +00:00
|
|
|
// This is reached if either:
|
|
|
|
// - The file can't be opened (presumably it doesn't exist)
|
|
|
|
// - Or there was an error parsing the file
|
2019-08-11 04:02:49 +00:00
|
|
|
let default_settings = Self::default();
|
|
|
|
default_settings.save_to_file_warn();
|
|
|
|
default_settings
|
2019-04-15 17:51:26 +00:00
|
|
|
}
|
2019-04-16 16:06:23 +00:00
|
|
|
|
2019-07-26 02:28:53 +00:00
|
|
|
pub fn save_to_file_warn(&self) {
|
2020-06-21 21:47:49 +00:00
|
|
|
if let Err(e) = self.save_to_file() {
|
|
|
|
warn!(?e, "Failed to save settings");
|
2019-07-26 02:28:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-16 16:06:23 +00:00
|
|
|
pub fn save_to_file(&self) -> std::io::Result<()> {
|
2020-10-05 08:35:24 +00:00
|
|
|
let path = Self::get_settings_path();
|
2019-05-20 21:32:16 +00:00
|
|
|
if let Some(dir) = path.parent() {
|
|
|
|
fs::create_dir_all(dir)?;
|
|
|
|
}
|
2019-06-08 23:35:23 +00:00
|
|
|
|
2020-10-05 08:35:24 +00:00
|
|
|
let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
|
|
|
|
fs::write(path, ron.as_bytes())
|
2019-04-16 16:06:23 +00:00
|
|
|
}
|
2019-04-25 16:24:00 +00:00
|
|
|
|
2019-12-18 19:35:17 +00:00
|
|
|
pub fn get_settings_path() -> PathBuf {
|
2020-06-21 21:47:49 +00:00
|
|
|
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
|
2020-10-05 07:41:58 +00:00
|
|
|
let settings = PathBuf::from(&path).join("settings.ron");
|
2019-10-22 13:53:05 +00:00
|
|
|
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {
|
|
|
|
return settings;
|
|
|
|
}
|
2020-06-21 21:47:49 +00:00
|
|
|
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
|
2019-10-22 13:53:05 +00:00
|
|
|
}
|
|
|
|
|
2020-10-05 07:41:58 +00:00
|
|
|
let mut path = voxygen_data_dir();
|
|
|
|
path.push("settings.ron");
|
|
|
|
path
|
2019-04-25 16:24:00 +00:00
|
|
|
}
|
2019-04-15 17:51:26 +00:00
|
|
|
}
|
2020-10-05 07:41:58 +00:00
|
|
|
|
|
|
|
pub fn voxygen_data_dir() -> PathBuf {
|
|
|
|
// Note: since voxygen is technically a lib we made need to lift this up to
|
|
|
|
// run.rs
|
2021-03-08 22:40:02 +00:00
|
|
|
let mut path = common_base::userdata_dir_workspace!();
|
2020-10-05 07:41:58 +00:00
|
|
|
path.push("voxygen");
|
|
|
|
path
|
|
|
|
}
|