From 9dccdb0b0335f82aa9f2e63642f16ff0f2699528 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 18 Jul 2023 14:26:20 +0200 Subject: feat: Add basic Proton management (#383) Adds logic to install, remove, and check existing install of NorthstarProton. --- src-tauri/Cargo.lock | 3 ++ src-tauri/Cargo.toml | 4 +- src-tauri/src/main.rs | 32 ++++++++++++++ src-tauri/src/platform_specific/linux.rs | 75 ++++++++++++++++++++++++++++++++ src-vue/src/views/DeveloperView.vue | 28 ++++++++++++ 5 files changed, 141 insertions(+), 1 deletion(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 77064841..968d523b 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -83,6 +83,7 @@ dependencies = [ "chrono", "const_format", "dirs", + "glob", "json5", "libthermite", "log", @@ -1987,9 +1988,11 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27cd844bbc25676cd14fa9ad04cc40e0f3c4d5c66107ef3a99896db1f81324c0" dependencies = [ + "flate2", "json5", "serde", "serde_json", + "tar", "thiserror", "tracing", "ureq", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ed523a4b..63ff51f7 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -33,7 +33,7 @@ steamlocate = "1.2" # Error messages anyhow = "1.0" # libthermite for Northstar/mod install handling -libthermite = "0.6.5" +libthermite = { version = "0.6.5", features = ["proton"] } # zip stuff zip = "0.6.2" # Regex @@ -62,6 +62,8 @@ zip-extract = "0.1.2" # open urls open = "3.2.0" semver = "1.0" +# simplified filesystem access +glob = "0.3.1" dirs = "5" [target.'cfg(windows)'.dependencies] diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index a584eea9..a295f322 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -144,6 +144,9 @@ fn main() { mod_management::delete_northstar_mod, util::get_server_player_count, mod_management::delete_thunderstore_mod, + install_northstar_proton_wrapper, + uninstall_northstar_proton_wrapper, + get_local_northstar_proton_wrapper_version, open_repair_window, thunderstore::query_thunderstore_packages_api, github::get_list_of_tags, @@ -525,3 +528,32 @@ pub fn check_is_valid_game_path(game_install_path: &str) -> Result<(), String> { fn get_host_os() -> String { env::consts::OS.to_string() } + +/// On Linux attempts to install NorthstarProton +/// On Windows simply returns an error message +#[tauri::command] +async fn install_northstar_proton_wrapper() -> Result<(), String> { + #[cfg(target_os = "linux")] + return linux::install_ns_proton().map_err(|err| err.to_string()); + + #[cfg(target_os = "windows")] + Err("Not supported on Windows".to_string()) +} + +#[tauri::command] +async fn uninstall_northstar_proton_wrapper() -> Result<(), String> { + #[cfg(target_os = "linux")] + return linux::uninstall_ns_proton(); + + #[cfg(target_os = "windows")] + Err("Not supported on Windows".to_string()) +} + +#[tauri::command] +async fn get_local_northstar_proton_wrapper_version() -> Result { + #[cfg(target_os = "linux")] + return linux::get_local_ns_proton_version(); + + #[cfg(target_os = "windows")] + Err("Not supported on Windows".to_string()) +} diff --git a/src-tauri/src/platform_specific/linux.rs b/src-tauri/src/platform_specific/linux.rs index 4b9964e9..674f384b 100644 --- a/src-tauri/src/platform_specific/linux.rs +++ b/src-tauri/src/platform_specific/linux.rs @@ -3,6 +3,81 @@ use regex::Regex; use std::process::Command; +fn get_proton_dir() -> Option { + let steam_dir = steamlocate::SteamDir::locate()?; + let compat_dir = format!("{}/compatibilitytools.d/", steam_dir.path.display()); + + Some(compat_dir) +} + +/// Downloads and installs NS proton +/// Assumes Steam install +pub fn install_ns_proton() -> Result<(), thermite::prelude::ThermiteError> { + // Get latest NorthstarProton release + let latest = thermite::core::latest_release()?; + + let temp_dir = std::env::temp_dir(); + let path = format!("{}/nsproton-{}.tar.gz", temp_dir.display(), latest); + let archive = std::fs::File::create(path.clone())?; + + // Download the latest Proton release + log::info!("Downloading NorthstarProton to {}", path); + thermite::core::download_ns_proton(latest, archive)?; + log::info!("Finished Download"); + + let compat_dir = get_proton_dir().unwrap(); + std::fs::create_dir_all(compat_dir.clone())?; + + let finished = std::fs::File::open(path.clone())?; + + // Extract to Proton dir + log::info!("Installing NorthstarProton to {}", compat_dir); + thermite::core::install_ns_proton(&finished, compat_dir)?; + log::info!("Finished Installation"); + drop(finished); + + std::fs::remove_file(path)?; + + Ok(()) +} + +/// Remove NS Proton +pub fn uninstall_ns_proton() -> Result<(), String> { + let compat_dir = get_proton_dir().unwrap(); + let pattern = format!("{}/NorthstarProton-*", compat_dir); + for e in glob::glob(&pattern).expect("Failed to read glob pattern") { + std::fs::remove_dir_all(e.unwrap()).unwrap(); + } + + Ok(()) +} + +/// Get the latest installed NS Proton version +pub fn get_local_ns_proton_version() -> Result { + let compat_dir = get_proton_dir().unwrap(); + let ns_prefix = "NorthstarProton-"; + let pattern = format!("{}/{}*/version", compat_dir, ns_prefix); + + let mut version: String = "".to_string(); + + for e in glob::glob(&pattern).expect("Failed to read glob pattern") { + let version_content = std::fs::read_to_string(e.unwrap()).unwrap(); + let version_string = version_content.split(' ').nth(1).unwrap(); + + if version_string.starts_with(ns_prefix) { + version = version_string[ns_prefix.len()..version_string.len() - 1] + .to_string() + .clone(); + } + } + + if version.is_empty() { + return Err("Northstar Proton is not installed".to_string()); + } + + Ok(version) +} + pub fn check_glibc_v() -> f32 { let out = Command::new("/bin/ldd") .arg("--version") diff --git a/src-vue/src/views/DeveloperView.vue b/src-vue/src/views/DeveloperView.vue index 500c9c35..28ab3892 100644 --- a/src-vue/src/views/DeveloperView.vue +++ b/src-vue/src/views/DeveloperView.vue @@ -21,6 +21,18 @@ Check NSProton Compatibility + + Install NSProton + + + + Remove NSProton + + + + Get local NSProton Version + +

Testing:

@@ -308,6 +320,22 @@ export default defineComponent({ notification.close(); }); }, + async installNSProton() { + showNotification(`Started NSProton install`); + await invoke("install_northstar_proton_wrapper") + .then((message) => { showNotification(`Done`); }) + .catch((error) => { showNotification(`Error`, error, "error"); }) + }, + async uninstallNSProton() { + await invoke("uninstall_northstar_proton_wrapper") + .then((message) => { showNotification(`Done`); }) + .catch((error) => { showNotification(`Error`, error, "error"); }) + }, + async getLocalNSProtonVersion() { + await invoke("get_local_northstar_proton_wrapper_version") + .then((message) => { showNotification(`NSProton Version`, message as string); }) + .catch((error) => { showNotification(`Error`, error, "error"); }) + }, } }); -- cgit v1.2.3 From 24090dd1a134b593aa0a77180f2ae16fab3227a0 Mon Sep 17 00:00:00 2001 From: GeckoEidechse Date: Tue, 18 Jul 2023 15:21:35 +0200 Subject: feat: Give wrong version number on legacy TS mods to prompt to "update" mod --- src-tauri/src/mod_management/legacy.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/mod_management/legacy.rs b/src-tauri/src/mod_management/legacy.rs index f24f44b6..568aadfc 100644 --- a/src-tauri/src/mod_management/legacy.rs +++ b/src-tauri/src/mod_management/legacy.rs @@ -88,7 +88,7 @@ pub fn parse_installed_mods( } }; // Get Thunderstore mod string if it exists - let thunderstore_mod_string = match parsed_mod_json.thunderstore_mod_string { + let mut thunderstore_mod_string = match parsed_mod_json.thunderstore_mod_string { // Attempt legacy method for getting Thunderstore string first Some(ts_mod_string) => Some(ts_mod_string), // Legacy method failed @@ -100,6 +100,17 @@ pub fn parse_installed_mods( // Get directory path let mod_directory = directory.to_str().unwrap().to_string(); + // This is a stupid way to show a legacy installed mod as outdated by simply giving back a wrong version number + if thunderstore_mod_string.is_some() { + // Parse the string + let mut parsed_string: ParsedThunderstoreModString = + thunderstore_mod_string.clone().unwrap().parse().unwrap(); + // Set version number to `0.0.0` + parsed_string.version = "0.0.0".to_string(); + // And store new string back in original variable + thunderstore_mod_string = Some(parsed_string.to_string()) + } + let ns_mod = NorthstarMod { name: parsed_mod_json.name, version: parsed_mod_json.version, -- cgit v1.2.3