diff --git a/Cargo.toml b/Cargo.toml index 0fe1c17..756bdae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ unicase = "2.0.0" rayon = "1.0.0" [target.'cfg(windows)'.dependencies] -app_dirs2 = "2.3" +dirs = "5.0" [dev-dependencies] criterion = "0.5.1" diff --git a/src/enums.rs b/src/enums.rs index 12e4193..ab91cbb 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -92,16 +92,6 @@ pub enum Error { InstalledPlugin(String), } -#[cfg(windows)] -impl From for Error { - fn from(error: app_dirs2::AppDirsError) -> Self { - match error { - app_dirs2::AppDirsError::Io(x) => Error::IoError(x), - _ => Error::NoLocalAppData, - } - } -} - impl From for Error { fn from(error: io::Error) -> Self { Error::IoError(error) diff --git a/src/game_settings.rs b/src/game_settings.rs index efca641..bd97c6b 100644 --- a/src/game_settings.rs +++ b/src/game_settings.rs @@ -86,7 +86,10 @@ const MS_FO4_VAULT_TEC_PATH: &str = "../../Fallout 4- Vault-Tec Workshop (PC)/Co impl GameSettings { #[cfg(windows)] pub fn new(game_id: GameId, game_path: &Path) -> Result { - let local_app_data_path = app_dirs2::get_data_root(app_dirs2::AppDataType::UserCache)?; + let local_app_data_path = match dirs::data_local_dir() { + Some(x) => x, + None => return Err(Error::NoLocalAppData), + }; let local_path = match appdata_folder_name(game_id, game_path) { Some(x) => local_app_data_path.join(x), None => local_app_data_path, @@ -282,6 +285,35 @@ fn is_microsoft_store_install(game_id: GameId, game_path: &Path) -> bool { } } +#[cfg(windows)] +fn documents_path(_local_path: &Path) -> Option { + dirs::document_dir() +} + +#[cfg(not(windows))] +fn documents_path_without_fallback(local_path: &Path) -> Option { + local_path + .parent() + .and_then(Path::parent) + .and_then(Path::parent) + .map(|p| p.join("Documents")) +} + +#[cfg(not(windows))] +fn documents_path(local_path: &Path) -> Option { + // Get the documents path relative to the game's local path, which should end in + // AppData/Local/. + // If the given path doesn't have enough components, try to canonicalise it, and then try again + // using the canonicalised path. Canonicalisation may fail in valid situations like if the given + // path does not exist, so don't try it first. + documents_path_without_fallback(local_path).or_else(|| { + local_path + .canonicalize() + .ok() + .and_then(|p| documents_path_without_fallback(&p)) + }) +} + fn additional_plugins_directories(game_id: GameId, game_path: &Path) -> Vec { if game_id == GameId::Fallout4 && is_microsoft_store_install(game_id, game_path) { vec![ @@ -695,7 +727,8 @@ mod tests { } #[test] - fn appdata_folder_name_for_skyrim_se_should_have_ms_suffix_if_appxmanifest_xml_is_in_game_path() { + fn appdata_folder_name_for_skyrim_se_should_have_ms_suffix_if_appxmanifest_xml_is_in_game_path() + { let tmp_dir = tempdir().unwrap(); let game_path = tmp_dir.path(); @@ -740,7 +773,8 @@ mod tests { } #[test] - fn appdata_folder_name_for_fallout4_should_have_ms_suffix_if_appxmanifest_xml_is_in_game_path() { + fn appdata_folder_name_for_fallout4_should_have_ms_suffix_if_appxmanifest_xml_is_in_game_path() + { let tmp_dir = tempdir().unwrap(); let game_path = tmp_dir.path(); @@ -1215,14 +1249,27 @@ mod tests { File::create(game_path.join("appxmanifest.xml")).unwrap(); - let settings = - GameSettings::with_local_path(GameId::SkyrimSE, game_path, Path::new("local")).unwrap(); + let game_ids = [ + GameId::Morrowind, + GameId::Oblivion, + GameId::Skyrim, + GameId::SkyrimSE, + GameId::SkyrimVR, + GameId::Fallout3, + GameId::FalloutNV, + ]; - assert!(settings.additional_plugins_directories().is_empty()); + for game_id in game_ids { + let settings = + GameSettings::with_local_path(game_id, game_path, Path::new("local")).unwrap(); + + assert!(settings.additional_plugins_directories().is_empty()); + } } #[test] - fn additional_plugins_directories_should_be_empty_if_game_is_not_from_the_microsoft_store() { + fn additional_plugins_directories_should_be_empty_if_fallout4_is_not_from_the_microsoft_store() + { let settings = GameSettings::with_local_path(GameId::Fallout4, Path::new("game"), Path::new("local")) .unwrap();