veloren_voxygen/settings/
mod.rs1use directories_next::UserDirs;
2use serde::{Deserialize, Serialize};
3use std::{
4 fs,
5 path::{Path, PathBuf},
6};
7use tracing::warn;
8
9pub mod audio;
10pub mod chat;
11pub mod control;
12pub mod gamepad;
13pub mod gameplay;
14pub mod graphics;
15pub mod interface;
16pub mod inventory;
17pub mod language;
18pub mod networking;
19
20pub use audio::{AudioOutput, AudioSettings};
21pub use chat::ChatSettings;
22pub use control::ControlSettings;
23pub use gamepad::GamepadSettings;
24pub use gameplay::GameplaySettings;
25pub use graphics::{Fps, GraphicsSettings, get_fps};
26pub use interface::InterfaceSettings;
27pub use inventory::InventorySettings;
28pub use language::LanguageSettings;
29pub use networking::NetworkingSettings;
30
31#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(default)]
35pub struct Settings {
36 pub chat: ChatSettings,
37 pub controls: ControlSettings,
38 pub interface: InterfaceSettings,
39 pub gameplay: GameplaySettings,
40 pub networking: NetworkingSettings,
41 pub graphics: GraphicsSettings,
42 pub audio: AudioSettings,
43 pub show_disclaimer: bool,
44 pub send_logon_commands: bool,
45 pub logon_commands: Vec<String>,
47 pub language: LanguageSettings,
48 pub screenshots_path: PathBuf,
49 pub controller: GamepadSettings,
50 pub inventory: InventorySettings,
51}
52
53impl Default for Settings {
54 fn default() -> Self {
55 let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
56
57 let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
63 .map(PathBuf::from)
64 .or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
65 .or_else(|| {
66 std::env::current_exe()
67 .ok()
68 .and_then(|dir| dir.parent().map(PathBuf::from))
69 })
70 .expect("Couldn't choose a place to store the screenshots");
71
72 Settings {
73 chat: ChatSettings::default(),
74 controls: ControlSettings::default(),
75 interface: InterfaceSettings::default(),
76 gameplay: GameplaySettings::default(),
77 networking: NetworkingSettings::default(),
78 graphics: GraphicsSettings::default(),
79 audio: AudioSettings::default(),
80 show_disclaimer: true,
81 send_logon_commands: false,
82 logon_commands: Vec::new(),
83 language: LanguageSettings::default(),
84 screenshots_path,
85 controller: GamepadSettings::default(),
86 inventory: InventorySettings::default(),
87 }
88 }
89}
90
91impl Settings {
92 pub fn load(config_dir: &Path) -> Self {
93 let path = Self::get_path(config_dir);
94
95 if let Ok(file) = fs::File::open(&path) {
96 match ron::de::from_reader::<_, Self>(file) {
97 Ok(s) => return s,
98 Err(e) => {
99 warn!(?e, "Failed to parse setting file! Fallback to default.");
100 let mut new_path = path.to_owned();
102 new_path.pop();
103 new_path.push("settings.invalid.ron");
104 if let Err(e) = fs::rename(&path, &new_path) {
105 warn!(?e, ?path, ?new_path, "Failed to rename settings file.");
106 }
107 },
108 }
109 }
110 let default_settings = Self::default();
114 default_settings.save_to_file_warn(config_dir);
115 default_settings
116 }
117
118 pub fn save_to_file_warn(&self, config_dir: &Path) {
119 if let Err(e) = self.save_to_file(config_dir) {
120 warn!(?e, "Failed to save settings");
121 }
122 }
123
124 pub fn save_to_file(&self, config_dir: &Path) -> std::io::Result<()> {
125 let path = Self::get_path(config_dir);
126 if let Some(dir) = path.parent() {
127 fs::create_dir_all(dir)?;
128 }
129
130 let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
131 fs::write(path, ron.as_bytes())
132 }
133
134 fn get_path(config_dir: &Path) -> PathBuf { config_dir.join("settings.ron") }
135
136 pub fn display_warnings(&self) {
137 if !self.graphics.render_mode.experimental_shaders.is_empty() {
138 warn!(
139 "One or more experimental shaders are enabled, all rendering guarantees are off. \
140 Experimental shaders may be unmaintained, mutually-incompatible, entirely \
141 broken, or may cause your GPU to explode. You have been warned!"
142 );
143 }
144 }
145}