veloren_voxygen/settings/
mod.rs

1use 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 controller;
13pub mod gameplay;
14pub mod graphics;
15pub mod hud_position;
16pub mod interface;
17pub mod inventory;
18pub mod language;
19pub mod networking;
20
21pub use audio::{AudioOutput, AudioSettings};
22pub use chat::ChatSettings;
23pub use control::ControlSettings;
24pub use controller::{Button, ControllerSettings};
25pub use gameplay::GameplaySettings;
26pub use graphics::{Fps, GraphicsSettings, get_fps};
27pub use hud_position::HudPositionSettings;
28pub use interface::InterfaceSettings;
29pub use inventory::InventorySettings;
30pub use language::LanguageSettings;
31pub use networking::NetworkingSettings;
32
33/// `Settings` contains everything that can be configured in the settings.ron
34/// file.
35#[derive(Clone, Debug, Serialize, Deserialize)]
36#[serde(default)]
37pub struct Settings {
38    pub chat: ChatSettings,
39    pub controls: ControlSettings,
40    pub controller: ControllerSettings,
41    pub interface: InterfaceSettings,
42    pub hud_position: HudPositionSettings,
43    pub gameplay: GameplaySettings,
44    pub networking: NetworkingSettings,
45    pub graphics: GraphicsSettings,
46    pub audio: AudioSettings,
47    pub show_disclaimer: bool,
48    pub send_logon_commands: bool,
49    // TODO: Remove at a later date, for dev testing
50    pub logon_commands: Vec<String>,
51    pub language: LanguageSettings,
52    pub screenshots_path: PathBuf,
53    pub inventory: InventorySettings,
54}
55
56impl Default for Settings {
57    fn default() -> Self {
58        let user_dirs = UserDirs::new().expect("System's $HOME directory path not found!");
59
60        // Chooses a path to store the screenshots by the following order:
61        //  - The VOXYGEN_SCREENSHOT environment variable
62        //  - The user's picture directory
63        //  - The executable's directory
64        // This only selects if there isn't already an entry in the settings file
65        let screenshots_path = std::env::var_os("VOXYGEN_SCREENSHOT")
66            .map(PathBuf::from)
67            .or_else(|| user_dirs.picture_dir().map(|dir| dir.join("veloren")))
68            .or_else(|| {
69                std::env::current_exe()
70                    .ok()
71                    .and_then(|dir| dir.parent().map(PathBuf::from))
72            })
73            .expect("Couldn't choose a place to store the screenshots");
74
75        Settings {
76            chat: ChatSettings::default(),
77            controls: ControlSettings::default(),
78            controller: ControllerSettings::default(),
79            interface: InterfaceSettings::default(),
80            hud_position: HudPositionSettings::default(),
81            gameplay: GameplaySettings::default(),
82            networking: NetworkingSettings::default(),
83            graphics: GraphicsSettings::default(),
84            audio: AudioSettings::default(),
85            show_disclaimer: true,
86            send_logon_commands: false,
87            logon_commands: Vec::new(),
88            language: LanguageSettings::default(),
89            screenshots_path,
90            inventory: InventorySettings::default(),
91        }
92    }
93}
94
95impl Settings {
96    pub fn load(config_dir: &Path) -> Self {
97        let path = Self::get_path(config_dir);
98
99        let settings = common::util::ron_from_path_recoverable::<Self>(&path);
100        // Save settings to add new fields or create the file if it is not already there
101        settings.save_to_file_warn(config_dir);
102        settings
103    }
104
105    pub fn save_to_file_warn(&self, config_dir: &Path) {
106        if let Err(e) = self.save_to_file(config_dir) {
107            warn!(?e, "Failed to save settings");
108        }
109    }
110
111    pub fn save_to_file(&self, config_dir: &Path) -> std::io::Result<()> {
112        let path = Self::get_path(config_dir);
113        if let Some(dir) = path.parent() {
114            fs::create_dir_all(dir)?;
115        }
116
117        let ron = ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
118        fs::write(path, ron.as_bytes())
119    }
120
121    fn get_path(config_dir: &Path) -> PathBuf { config_dir.join("settings.ron") }
122
123    pub fn display_warnings(&self) {
124        if !self.graphics.render_mode.experimental_shaders.is_empty() {
125            warn!(
126                "One or more experimental shaders are enabled, all rendering guarantees are off. \
127                 Experimental shaders may be unmaintained, mutually-incompatible, entirely \
128                 broken, or may cause your GPU to explode. You have been warned!"
129            );
130        }
131    }
132}