//! Theseus settings file use serde::{Deserialize, Serialize}; // Types /// Global Theseus settings #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Settings { pub max_concurrent_downloads: usize, pub max_concurrent_writes: usize, pub theme: Theme, pub default_page: DefaultPage, pub collapsed_navigation: bool, pub advanced_rendering: bool, pub native_decorations: bool, pub telemetry: bool, pub discord_rpc: bool, pub developer_mode: bool, pub personalized_ads: bool, pub onboarded: bool, pub extra_launch_args: Vec, pub custom_env_vars: Vec<(String, String)>, pub memory: MemorySettings, pub force_fullscreen: bool, pub game_resolution: WindowSize, pub hide_on_process_start: bool, pub hooks: Hooks, pub custom_dir: Option, pub prev_custom_dir: Option, pub migrated: bool, } impl Settings { pub async fn get( exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>, ) -> crate::Result { let res = sqlx::query!( " SELECT max_concurrent_writes, max_concurrent_downloads, theme, default_page, collapsed_navigation, advanced_rendering, native_decorations, discord_rpc, developer_mode, telemetry, personalized_ads, onboarded, json(extra_launch_args) extra_launch_args, json(custom_env_vars) custom_env_vars, mc_memory_max, mc_force_fullscreen, mc_game_resolution_x, mc_game_resolution_y, hide_on_process_start, hook_pre_launch, hook_wrapper, hook_post_exit, custom_dir, prev_custom_dir, migrated FROM settings " ) .fetch_one(exec) .await?; Ok(Self { max_concurrent_downloads: res.max_concurrent_downloads as usize, max_concurrent_writes: res.max_concurrent_writes as usize, theme: Theme::from_string(&res.theme), default_page: DefaultPage::from_string(&res.default_page), collapsed_navigation: res.collapsed_navigation == 1, advanced_rendering: res.advanced_rendering == 1, native_decorations: res.native_decorations == 1, telemetry: res.telemetry == 1, discord_rpc: res.discord_rpc == 1, developer_mode: res.developer_mode == 1, personalized_ads: res.personalized_ads == 1, onboarded: res.onboarded == 1, extra_launch_args: res .extra_launch_args .as_ref() .and_then(|x| serde_json::from_str(x).ok()) .unwrap_or_default(), custom_env_vars: res .custom_env_vars .as_ref() .and_then(|x| serde_json::from_str(x).ok()) .unwrap_or_default(), memory: MemorySettings { maximum: res.mc_memory_max as u32, }, force_fullscreen: res.mc_force_fullscreen == 1, game_resolution: WindowSize( res.mc_game_resolution_x as u16, res.mc_game_resolution_y as u16, ), hide_on_process_start: res.hide_on_process_start == 1, hooks: Hooks { pre_launch: res.hook_pre_launch, wrapper: res.hook_wrapper, post_exit: res.hook_post_exit, }, custom_dir: res.custom_dir, prev_custom_dir: res.prev_custom_dir, migrated: res.migrated == 1, }) } pub async fn update( &self, exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite>, ) -> crate::Result<()> { let max_concurrent_writes = self.max_concurrent_writes as i32; let max_concurrent_downloads = self.max_concurrent_downloads as i32; let theme = self.theme.as_str(); let default_page = self.default_page.as_str(); let extra_launch_args = serde_json::to_string(&self.extra_launch_args)?; let custom_env_vars = serde_json::to_string(&self.custom_env_vars)?; sqlx::query!( " UPDATE settings SET max_concurrent_writes = $1, max_concurrent_downloads = $2, theme = $3, default_page = $4, collapsed_navigation = $5, advanced_rendering = $6, native_decorations = $7, discord_rpc = $8, developer_mode = $9, telemetry = $10, personalized_ads = $11, onboarded = $12, extra_launch_args = jsonb($13), custom_env_vars = jsonb($14), mc_memory_max = $15, mc_force_fullscreen = $16, mc_game_resolution_x = $17, mc_game_resolution_y = $18, hide_on_process_start = $19, hook_pre_launch = $20, hook_wrapper = $21, hook_post_exit = $22, custom_dir = $23, prev_custom_dir = $24, migrated = $25 ", max_concurrent_writes, max_concurrent_downloads, theme, default_page, self.collapsed_navigation, self.advanced_rendering, self.native_decorations, self.discord_rpc, self.developer_mode, self.telemetry, self.personalized_ads, self.onboarded, extra_launch_args, custom_env_vars, self.memory.maximum, self.force_fullscreen, self.game_resolution.0, self.game_resolution.1, self.hide_on_process_start, self.hooks.pre_launch, self.hooks.wrapper, self.hooks.post_exit, self.custom_dir, self.prev_custom_dir, self.migrated ) .execute(exec) .await?; Ok(()) } } /// Theseus theme #[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub enum Theme { Dark, Light, Oled, } impl Theme { pub fn as_str(&self) -> &'static str { match self { Theme::Dark => "dark", Theme::Light => "light", Theme::Oled => "oled", } } pub fn from_string(string: &str) -> Theme { match string { "dark" => Theme::Dark, "light" => Theme::Light, "oled" => Theme::Oled, _ => Theme::Dark, } } } /// Minecraft memory settings #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct MemorySettings { pub maximum: u32, } /// Game window size #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub struct WindowSize(pub u16, pub u16); /// Game initialization hooks #[derive(Serialize, Deserialize, Debug, Clone)] pub struct Hooks { pub pre_launch: Option, pub wrapper: Option, pub post_exit: Option, } /// Opening window to start with #[derive(Serialize, Deserialize, Debug, Clone, Copy)] pub enum DefaultPage { Home, Library, } impl DefaultPage { pub fn as_str(&self) -> &'static str { match self { DefaultPage::Home => "home", DefaultPage::Library => "library", } } pub fn from_string(string: &str) -> Self { match string { "home" => Self::Home, "library" => Self::Library, _ => Self::Home, } } }