diff options
Diffstat (limited to 'src/launcher/settings.rs')
| -rw-r--r-- | src/launcher/settings.rs | 232 |
1 files changed, 0 insertions, 232 deletions
diff --git a/src/launcher/settings.rs b/src/launcher/settings.rs deleted file mode 100644 index 8453653..0000000 --- a/src/launcher/settings.rs +++ /dev/null @@ -1,232 +0,0 @@ -use std::collections::HashMap; -use std::error::Error; -use std::fmt::{Display, Formatter}; -use std::io::ErrorKind; -use std::path::{Path, PathBuf}; -use log::warn; -use serde::{Deserialize, Serialize}; -use tokio::{fs, io}; -use tokio::fs::File; -use tokio::io::AsyncWriteExt; -use super::constants; - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct SettingsInner { - profiles: HashMap<String, Profile>, - instances: HashMap<String, Instance> -} - -pub struct Settings { - path: Option<PathBuf>, - inner: SettingsInner -} - -#[derive(Debug)] -pub enum SettingsError { - IO { what: &'static str, error: io::Error }, - Format(serde_json::Error), - Inconsistent(String) -} - -impl Display for SettingsError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - SettingsError::IO { what, error } => write!(f, "settings i/o error ({}): {}", what, error), - SettingsError::Format(err) => write!(f, "settings format error: {}", err), - SettingsError::Inconsistent(err) => write!(f, "inconsistent settings: {}", err), - } - } -} - -impl Error for SettingsError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - SettingsError::IO { error: err, .. } => Some(err), - SettingsError::Format(err) => Some(err), - _ => None - } - } -} - -impl Default for SettingsInner { - fn default() -> Self { - SettingsInner { - instances: [(String::from(constants::DEF_INSTANCE_NAME), PathBuf::from(constants::DEF_INSTANCE_NAME).into())].into_iter().collect(), - profiles: [(String::from(constants::DEF_PROFILE_NAME), Profile::new(constants::DEF_INSTANCE_NAME))].into_iter().collect() - } - } -} - -impl Settings { - async fn load_inner(path: impl AsRef<Path>) -> Result<SettingsInner, SettingsError> { - match fs::read_to_string(&path).await { - Ok(data) => serde_json::from_str(data.as_str()).map_err(SettingsError::Format), - Err(e) if e.kind() == ErrorKind::NotFound => Ok(SettingsInner::default()), - Err(e) => Err(SettingsError::IO { what: "loading settings", error: e }) - } - } - - fn check_consistent(mut inner: SettingsInner, path: Option<impl AsRef<Path>>) -> Result<Settings, SettingsError> { - inner.profiles.retain(|name, profile| { - if !inner.instances.contains_key(&profile.instance) { - warn!("Settings inconsistency: profile {} refers to instance {}, which does not exist. Ignoring this profile.", name, profile.instance); - false - } else { - true - } - }); - - // there will be more checks later maybe - - Ok(Settings { - path: path.map(|p| p.as_ref().to_owned()), - inner - }) - } - - pub async fn load(path: impl AsRef<Path>) -> Result<Settings, SettingsError> { - Self::check_consistent(Self::load_inner(&path).await?, Some(path)) - } - - pub fn get_path(&self) -> Option<&Path> { - self.path.as_deref() - } - - pub async fn save_to(&self, path: impl AsRef<Path>) -> Result<(), SettingsError> { - let path = path.as_ref(); - - if let Some(parent) = path.parent() { - fs::create_dir_all(parent).await - .map_err(|e| SettingsError::IO { what: "saving settings (creating directory)", error: e })?; - } - - let mut file = File::create(path).await - .map_err(|e| SettingsError::IO { what: "saving settings (open)", error: e })?; - - file.write_all(serde_json::to_string_pretty(&self.inner).map_err(SettingsError::Format)?.as_bytes()).await - .map_err(|e| SettingsError::IO { what: "saving settings (write)", error: e })?; - - Ok(()) - } - - pub async fn save(&self) -> Result<(), SettingsError> { - self.save_to(self.path.as_ref().expect("save() called on Settings instance not loaded from file")).await - } - - pub fn get_instance(&self, name: &str) -> Option<&Instance> { - self.inner.instances.get(name) - } - - pub fn get_profile(&self, name: &str) -> Option<&Profile> { - self.inner.profiles.get(name) - } - - pub fn get_instance_for(&self, profile: &Profile) -> &Instance { - self.inner.instances.get(&profile.instance).unwrap() - } -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -pub struct Instance { - path: PathBuf // relative to launcher home (or absolute) -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -#[serde(rename_all = "snake_case")] -pub enum ProfileVersion { - LatestSnapshot, - LatestRelease, - #[serde(untagged)] - Specific(String) -} - -#[derive(Deserialize, Serialize, Debug, Clone, Copy)] -pub struct Resolution { - width: u32, - height: u32 -} - -impl Default for Resolution { - fn default() -> Self { - Resolution { width: 864, height: 480 } - } -} - -#[derive(Deserialize, Serialize, Debug, Clone)] -pub struct Profile { - game_version: ProfileVersion, - java_runtime: Option<String>, - instance: String, - - #[serde(default)] - jvm_arguments: Vec<String>, - #[serde(default)] - legacy_launch: bool, - - resolution: Option<Resolution> -} - -impl<P: AsRef<Path>> From<P> for Instance { - fn from(path: P) -> Self { - Self { path: path.as_ref().into() } - } -} - -impl Instance { - pub async fn get_path(&self, home: impl AsRef<Path>) -> Result<PathBuf, io::Error> { - let path = self.path.as_path(); - - if path.is_relative() { - Ok([home.as_ref(), Path::new("instances"), path].iter().collect::<PathBuf>()) - } else { - fs::canonicalize(path).await - } - } -} - -const DEF_JVM_ARGUMENTS: [&str; 7] = [ - "-Xmx2G", - "-XX:+UnlockExperimentalVMOptions", - "-XX:+UseG1GC", - "-XX:G1NewSizePercent=20", - "-XX:G1ReservePercent=20", - "-XX:MaxGCPauseMillis=50", - "-XX:G1HeapRegionSize=32M" -]; - -impl Profile { - fn new(instance_name: &str) -> Self { - Self { - game_version: ProfileVersion::LatestRelease, - java_runtime: None, - instance: instance_name.into(), - jvm_arguments: DEF_JVM_ARGUMENTS.iter().map(|s| String::from(*s)).collect(), - legacy_launch: false, - resolution: None - } - } - - pub fn get_version(&self) -> &ProfileVersion { - &self.game_version - } - - pub fn get_instance_name(&self) -> &str { - &self.instance - } - - pub fn iter_arguments(&self) -> impl Iterator<Item = &String> { - self.jvm_arguments.iter() - } - - pub fn get_resolution(&self) -> Option<Resolution> { - self.resolution - } - - pub fn get_java_runtime(&self) -> Option<&String> { - self.java_runtime.as_ref() - } - - pub fn is_legacy_launch(&self) -> bool { - self.legacy_launch - } -} |
