aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeckoEidechse <40122905+GeckoEidechse@users.noreply.github.com>2023-05-10 22:51:10 +0200
committerGitHub <noreply@github.com>2023-05-10 22:51:10 +0200
commit6632a081a846116e7ca1e4ab96b3592938ee2a20 (patch)
treee473e632237e3273e14c3dcee3f4cf0b8c944c07
parent1635993f130f0f71d9a9bc002b2f74167ad5c974 (diff)
downloadFlightCore-6632a081a846116e7ca1e4ab96b3592938ee2a20.tar.gz
FlightCore-6632a081a846116e7ca1e4ab96b3592938ee2a20.zip
refactor: Move code from `lib.rs` into `main.rs` (#330)
Move remaining logic in one big move
-rw-r--r--src-tauri/src/github/pull_requests.rs4
-rw-r--r--src-tauri/src/lib.rs411
-rw-r--r--src-tauri/src/main.rs413
-rw-r--r--src-tauri/src/mod_management/mod.rs4
-rw-r--r--src-tauri/src/northstar/mod.rs3
-rw-r--r--src-tauri/src/repair_and_verify/mod.rs4
6 files changed, 418 insertions, 421 deletions
diff --git a/src-tauri/src/github/pull_requests.rs b/src-tauri/src/github/pull_requests.rs
index 6c605424..e600e2e4 100644
--- a/src-tauri/src/github/pull_requests.rs
+++ b/src-tauri/src/github/pull_requests.rs
@@ -1,8 +1,8 @@
use crate::github::release_notes::fetch_github_releases_api;
+use crate::check_is_valid_game_path;
+use crate::constants::{APP_USER_AGENT, PULLS_API_ENDPOINT_LAUNCHER, PULLS_API_ENDPOINT_MODS};
use anyhow::anyhow;
-use app::check_is_valid_game_path;
-use app::constants::{APP_USER_AGENT, PULLS_API_ENDPOINT_LAUNCHER, PULLS_API_ENDPOINT_MODS};
use serde::{Deserialize, Serialize};
use std::fs::File;
use std::io;
diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs
deleted file mode 100644
index a7919102..00000000
--- a/src-tauri/src/lib.rs
+++ /dev/null
@@ -1,411 +0,0 @@
-use std::{cell::RefCell, env, fs, path::Path, time::Duration, time::Instant};
-
-use anyhow::{Context, Result};
-
-pub mod constants;
-mod platform_specific;
-#[cfg(target_os = "windows")]
-use platform_specific::windows;
-
-#[cfg(target_os = "linux")]
-use platform_specific::linux;
-
-use serde::{Deserialize, Serialize};
-use sysinfo::SystemExt;
-use tokio::time::sleep;
-use ts_rs::TS;
-use zip::ZipArchive;
-
-use crate::constants::TITANFALL2_STEAM_ID;
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub enum InstallType {
- STEAM,
- ORIGIN,
- EAPLAY,
- UNKNOWN,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct GameInstall {
- pub game_path: String,
- pub install_type: InstallType,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, TS)]
-#[ts(export)]
-pub struct NorthstarMod {
- pub name: String,
- pub version: Option<String>,
- pub thunderstore_mod_string: Option<String>,
- pub enabled: bool,
- pub directory: String,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct NorthstarServer {
- #[serde(rename = "playerCount")]
- pub player_count: i32,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, TS)]
-#[ts(export)]
-pub enum InstallState {
- DOWNLOADING,
- EXTRACTING,
- DONE,
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone, TS)]
-#[ts(export)]
-struct InstallProgress {
- current_downloaded: u64,
- total_size: u64,
- state: InstallState,
-}
-
-// I intend to add more linux related stuff to check here, so making a func
-// for now tho it only checks `ldd --version`
-// - salmon
-#[cfg(target_os = "linux")]
-pub fn linux_checks_librs() -> Result<(), String> {
- // Perform various checks in terms of Linux compatibility
- // Return early with error message if a check fails
-
- // check `ldd --version` to see if glibc is up to date for northstar proton
- let min_required_ldd_version = 2.33;
- let lddv = linux::check_glibc_v();
- if lddv < min_required_ldd_version {
- return Err(format!(
- "GLIBC is not version {} or greater",
- min_required_ldd_version
- ));
- };
-
- // All checks passed
- Ok(())
-}
-
-/// Attempts to find the game install location
-pub fn find_game_install_location() -> Result<GameInstall, String> {
- // Attempt parsing Steam library directly
- match steamlocate::SteamDir::locate() {
- Some(mut steamdir) => {
- let titanfall2_steamid = TITANFALL2_STEAM_ID.parse().unwrap();
- match steamdir.app(&titanfall2_steamid) {
- Some(app) => {
- // println!("{:#?}", app);
- let game_install = GameInstall {
- game_path: app.path.to_str().unwrap().to_string(),
- install_type: InstallType::STEAM,
- };
- return Ok(game_install);
- }
- None => log::info!("Couldn't locate Titanfall2 Steam install"),
- }
- }
- None => log::info!("Couldn't locate Steam on this computer!"),
- }
-
- // (On Windows only) try parsing Windows registry for Origin install path
- #[cfg(target_os = "windows")]
- match windows::origin_install_location_detection() {
- Ok(game_path) => {
- let game_install = GameInstall {
- game_path,
- install_type: InstallType::ORIGIN,
- };
- return Ok(game_install);
- }
- Err(err) => {
- log::info!("{}", err);
- }
- };
-
- Err("Could not auto-detect game install location! Please enter it manually.".to_string())
-}
-
-/// Checks whether the provided path is a valid Titanfall2 gamepath by checking against a certain set of criteria
-pub fn check_is_valid_game_path(game_install_path: &str) -> Result<(), String> {
- let path_to_titanfall2_exe = format!("{game_install_path}/Titanfall2.exe");
- let is_correct_game_path = std::path::Path::new(&path_to_titanfall2_exe).exists();
- log::info!("Titanfall2.exe exists in path? {}", is_correct_game_path);
-
- // Exit early if wrong game path
- if !is_correct_game_path {
- return Err(format!("Incorrect game path \"{game_install_path}\"")); // Return error cause wrong game path
- }
- Ok(())
-}
-
-/// Copied from `papa` source code and modified
-///Extract N* zip file to target game path
-// fn extract(ctx: &Ctx, zip_file: File, target: &Path) -> Result<()> {
-fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> {
- let mut archive = ZipArchive::new(&zip_file).context("Unable to open zip archive")?;
- for i in 0..archive.len() {
- let mut f = archive.by_index(i).unwrap();
-
- //This should work fine for N* because the dir structure *should* always be the same
- if f.enclosed_name().unwrap().starts_with("Northstar") {
- let out = target.join(
- f.enclosed_name()
- .unwrap()
- .strip_prefix("Northstar")
- .unwrap(),
- );
-
- if (*f.name()).ends_with('/') {
- log::info!("Create directory {}", f.name());
- std::fs::create_dir_all(target.join(f.name()))
- .context("Unable to create directory")?;
- continue;
- } else if let Some(p) = out.parent() {
- std::fs::create_dir_all(p).context("Unable to create directory")?;
- }
-
- let mut outfile = std::fs::OpenOptions::new()
- .create(true)
- .write(true)
- .truncate(true)
- .open(&out)?;
-
- log::info!("Write file {}", out.display());
-
- std::io::copy(&mut f, &mut outfile).context("Unable to write to file")?;
- }
- }
-
- Ok(())
-}
-
-/// Copied from `papa` source code and modified
-///Install N* from the provided mod
-///
-///Checks cache, else downloads the latest version
-async fn do_install(
- window: tauri::Window,
- nmod: &thermite::model::ModVersion,
- game_path: &std::path::Path,
-) -> Result<()> {
- let filename = format!("northstar-{}.zip", nmod.version);
- let download_directory = format!("{}/___flightcore-temp-download-dir/", game_path.display());
-
- std::fs::create_dir_all(download_directory.clone())?;
-
- let download_path = format!("{}/{}", download_directory, filename);
- log::info!("Download path: {download_path}");
-
- let last_emit = RefCell::new(Instant::now()); // Keep track of the last time a signal was emitted
- let nfile = thermite::core::manage::download_file_with_progress(
- &nmod.url,
- download_path,
- |delta, current, total| {
- if delta != 0 {
- // Only emit a signal once every 100ms
- // This way we don't bombard the frontend with events on fast download speeds
- let time_since_last_emit = Instant::now().duration_since(*last_emit.borrow());
- if time_since_last_emit >= Duration::from_millis(100) {
- window
- .emit(
- "northstar-install-download-progress",
- InstallProgress {
- current_downloaded: current,
- total_size: total,
- state: InstallState::DOWNLOADING,
- },
- )
- .unwrap();
- *last_emit.borrow_mut() = Instant::now();
- }
- }
- },
- )
- .unwrap();
-
- window
- .emit(
- "northstar-install-download-progress",
- InstallProgress {
- current_downloaded: 0,
- total_size: 0,
- state: InstallState::EXTRACTING,
- },
- )
- .unwrap();
-
- log::info!("Extracting Northstar...");
- extract(nfile, game_path)?;
-
- // Delete old copy
- log::info!("Delete temp folder again");
- std::fs::remove_dir_all(download_directory).unwrap();
-
- log::info!("Done installing Northstar!");
- window
- .emit(
- "northstar-install-download-progress",
- InstallProgress {
- current_downloaded: 0,
- total_size: 0,
- state: InstallState::DONE,
- },
- )
- .unwrap();
-
- Ok(())
-}
-
-pub async fn install_northstar(
- window: tauri::Window,
- game_path: &str,
- northstar_package_name: String,
- version_number: Option<String>,
-) -> Result<String, String> {
- let index = thermite::api::get_package_index().unwrap().to_vec();
- let nmod = index
- .iter()
- .find(|f| f.name.to_lowercase() == northstar_package_name.to_lowercase())
- .ok_or_else(|| panic!("Couldn't find Northstar on thunderstore???"))
- .unwrap();
-
- // Use passed version or latest if no version was passed
- let version = version_number.as_ref().unwrap_or(&nmod.latest);
-
- log::info!("Install path \"{}\"", game_path);
-
- match do_install(
- window,
- nmod.versions.get(version).unwrap(),
- std::path::Path::new(game_path),
- )
- .await
- {
- Ok(_) => (),
- Err(err) => {
- if game_path
- .to_lowercase()
- .contains(&r#"C:\Program Files\"#.to_lowercase())
- // default is `C:\Program Files\EA Games\Titanfall2`
- {
- return Err(
- "Cannot install to default EA App install path, please move Titanfall2 to a different install location.".to_string(),
- );
- } else {
- return Err(err.to_string());
- }
- }
- }
-
- Ok(nmod.latest.clone())
-}
-
-/// Returns identifier of host OS FlightCore is running on
-pub fn get_host_os() -> String {
- env::consts::OS.to_string()
-}
-
-/// Prepare Northstar and Launch through Steam using the Browser Protocol
-pub fn launch_northstar_steam(
- game_install: &GameInstall,
- _bypass_checks: Option<bool>,
-) -> Result<String, String> {
- if !matches!(game_install.install_type, InstallType::STEAM) {
- return Err("Titanfall2 was not installed via Steam".to_string());
- }
-
- match steamlocate::SteamDir::locate() {
- Some(mut steamdir) => {
- if get_host_os() != "windows" {
- let titanfall2_steamid: u32 = TITANFALL2_STEAM_ID.parse().unwrap();
- match steamdir.compat_tool(&titanfall2_steamid) {
- Some(compat) => {
- if !compat
- .name
- .clone()
- .unwrap()
- .to_ascii_lowercase()
- .contains("northstarproton")
- {
- return Err(
- "Titanfall2 was not configured to use NorthstarProton".to_string()
- );
- }
- }
- None => {
- return Err(
- "Titanfall2 was not configured to use a compatibility tool".to_string()
- );
- }
- }
- }
- }
- None => {
- return Err("Couldn't access Titanfall2 directory".to_string());
- }
- }
-
- // Switch to Titanfall2 directory to set everything up
- if std::env::set_current_dir(game_install.game_path.clone()).is_err() {
- // We failed to get to Titanfall2 directory
- return Err("Couldn't access Titanfall2 directory".to_string());
- }
-
- let run_northstar = "run_northstar.txt";
- let run_northstar_bak = "run_northstar.txt.bak";
-
- if Path::new(run_northstar).exists() {
- // rename should ovewrite existing files
- fs::rename(run_northstar, run_northstar_bak).unwrap();
- }
-
- // Passing arguments gives users a prompt, so we use run_northstar.txt
- fs::write(run_northstar, b"1").unwrap();
-
- let retval = match open::that(format!("steam://run/{}/", TITANFALL2_STEAM_ID)) {
- Ok(()) => Ok("Started game".to_string()),
- Err(_err) => Err("Failed to launch Titanfall 2 via Steam".to_string()),
- };
-
- let is_err = retval.is_err();
-
- // Handle the rest in the backround
- tauri::async_runtime::spawn(async move {
- // Starting the EA app and Titanfall might take a good minute or three
- let mut wait_countdown = 60 * 3;
- while wait_countdown > 0 && !check_northstar_running() && !is_err {
- sleep(Duration::from_millis(1000)).await;
- wait_countdown -= 1;
- }
-
- // Northstar may be running, but it may not have loaded the file yet
- sleep(Duration::from_millis(2000)).await;
-
- // intentionally ignore Result
- let _ = fs::remove_file(run_northstar);
-
- if Path::new(run_northstar_bak).exists() {
- fs::rename(run_northstar_bak, run_northstar).unwrap();
- }
- });
-
- retval
-}
-
-pub fn check_origin_running() -> bool {
- let s = sysinfo::System::new_all();
- let x = s.processes_by_name("Origin.exe").next().is_some()
- || s.processes_by_name("EADesktop.exe").next().is_some();
- x
-}
-
-/// Checks if Northstar process is running
-pub fn check_northstar_running() -> bool {
- let s = sysinfo::System::new_all();
- let x = s
- .processes_by_name("NorthstarLauncher.exe")
- .next()
- .is_some()
- || s.processes_by_name("Titanfall2.exe").next().is_some();
- x
-}
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index 9f268956..3b1504bf 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -14,8 +14,6 @@ use std::ptr::null_mut;
#[cfg(target_os = "windows")]
use winapi::um::winuser::{MessageBoxW, MB_ICONERROR, MB_OK, MB_USERICON};
-use app::*;
-
use crate::constants::{APP_USER_AGENT, MASTER_SERVER_URL, REFRESH_DELAY, SERVER_BROWSER_ENDPOINT};
mod github;
@@ -534,3 +532,414 @@ async fn get_available_northstar_versions() -> Result<Vec<NorthstarThunderstoreR
Ok(releases)
}
+
+// The remaining below was originally in `lib.rs`.
+// As this was causing issues it was moved into `main.rs` until being later moved into dedicated modules
+use std::{cell::RefCell, fs, path::Path, time::Instant};
+
+use anyhow::{Context, Result};
+
+pub mod constants;
+mod platform_specific;
+#[cfg(target_os = "windows")]
+use platform_specific::windows;
+
+#[cfg(target_os = "linux")]
+use platform_specific::linux;
+
+use sysinfo::SystemExt;
+use zip::ZipArchive;
+
+use crate::constants::TITANFALL2_STEAM_ID;
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum InstallType {
+ STEAM,
+ ORIGIN,
+ EAPLAY,
+ UNKNOWN,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct GameInstall {
+ pub game_path: String,
+ pub install_type: InstallType,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub struct NorthstarMod {
+ pub name: String,
+ pub version: Option<String>,
+ pub thunderstore_mod_string: Option<String>,
+ pub enabled: bool,
+ pub directory: String,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct NorthstarServer {
+ #[serde(rename = "playerCount")]
+ pub player_count: i32,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+pub enum InstallState {
+ DOWNLOADING,
+ EXTRACTING,
+ DONE,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone, TS)]
+#[ts(export)]
+struct InstallProgress {
+ current_downloaded: u64,
+ total_size: u64,
+ state: InstallState,
+}
+
+// I intend to add more linux related stuff to check here, so making a func
+// for now tho it only checks `ldd --version`
+// - salmon
+#[cfg(target_os = "linux")]
+pub fn linux_checks_librs() -> Result<(), String> {
+ // Perform various checks in terms of Linux compatibility
+ // Return early with error message if a check fails
+
+ // check `ldd --version` to see if glibc is up to date for northstar proton
+ let min_required_ldd_version = 2.33;
+ let lddv = linux::check_glibc_v();
+ if lddv < min_required_ldd_version {
+ return Err(format!(
+ "GLIBC is not version {} or greater",
+ min_required_ldd_version
+ ));
+ };
+
+ // All checks passed
+ Ok(())
+}
+
+/// Attempts to find the game install location
+pub fn find_game_install_location() -> Result<GameInstall, String> {
+ // Attempt parsing Steam library directly
+ match steamlocate::SteamDir::locate() {
+ Some(mut steamdir) => {
+ let titanfall2_steamid = TITANFALL2_STEAM_ID.parse().unwrap();
+ match steamdir.app(&titanfall2_steamid) {
+ Some(app) => {
+ // println!("{:#?}", app);
+ let game_install = GameInstall {
+ game_path: app.path.to_str().unwrap().to_string(),
+ install_type: InstallType::STEAM,
+ };
+ return Ok(game_install);
+ }
+ None => log::info!("Couldn't locate Titanfall2 Steam install"),
+ }
+ }
+ None => log::info!("Couldn't locate Steam on this computer!"),
+ }
+
+ // (On Windows only) try parsing Windows registry for Origin install path
+ #[cfg(target_os = "windows")]
+ match windows::origin_install_location_detection() {
+ Ok(game_path) => {
+ let game_install = GameInstall {
+ game_path,
+ install_type: InstallType::ORIGIN,
+ };
+ return Ok(game_install);
+ }
+ Err(err) => {
+ log::info!("{}", err);
+ }
+ };
+
+ Err("Could not auto-detect game install location! Please enter it manually.".to_string())
+}
+
+/// Checks whether the provided path is a valid Titanfall2 gamepath by checking against a certain set of criteria
+pub fn check_is_valid_game_path(game_install_path: &str) -> Result<(), String> {
+ let path_to_titanfall2_exe = format!("{game_install_path}/Titanfall2.exe");
+ let is_correct_game_path = std::path::Path::new(&path_to_titanfall2_exe).exists();
+ log::info!("Titanfall2.exe exists in path? {}", is_correct_game_path);
+
+ // Exit early if wrong game path
+ if !is_correct_game_path {
+ return Err(format!("Incorrect game path \"{game_install_path}\"")); // Return error cause wrong game path
+ }
+ Ok(())
+}
+
+/// Copied from `papa` source code and modified
+///Extract N* zip file to target game path
+// fn extract(ctx: &Ctx, zip_file: File, target: &Path) -> Result<()> {
+fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> {
+ let mut archive = ZipArchive::new(&zip_file).context("Unable to open zip archive")?;
+ for i in 0..archive.len() {
+ let mut f = archive.by_index(i).unwrap();
+
+ //This should work fine for N* because the dir structure *should* always be the same
+ if f.enclosed_name().unwrap().starts_with("Northstar") {
+ let out = target.join(
+ f.enclosed_name()
+ .unwrap()
+ .strip_prefix("Northstar")
+ .unwrap(),
+ );
+
+ if (*f.name()).ends_with('/') {
+ log::info!("Create directory {}", f.name());
+ std::fs::create_dir_all(target.join(f.name()))
+ .context("Unable to create directory")?;
+ continue;
+ } else if let Some(p) = out.parent() {
+ std::fs::create_dir_all(p).context("Unable to create directory")?;
+ }
+
+ let mut outfile = std::fs::OpenOptions::new()
+ .create(true)
+ .write(true)
+ .truncate(true)
+ .open(&out)?;
+
+ log::info!("Write file {}", out.display());
+
+ std::io::copy(&mut f, &mut outfile).context("Unable to write to file")?;
+ }
+ }
+
+ Ok(())
+}
+
+/// Copied from `papa` source code and modified
+///Install N* from the provided mod
+///
+///Checks cache, else downloads the latest version
+async fn do_install(
+ window: tauri::Window,
+ nmod: &thermite::model::ModVersion,
+ game_path: &std::path::Path,
+) -> Result<()> {
+ let filename = format!("northstar-{}.zip", nmod.version);
+ let download_directory = format!("{}/___flightcore-temp-download-dir/", game_path.display());
+
+ std::fs::create_dir_all(download_directory.clone())?;
+
+ let download_path = format!("{}/{}", download_directory, filename);
+ log::info!("Download path: {download_path}");
+
+ let last_emit = RefCell::new(Instant::now()); // Keep track of the last time a signal was emitted
+ let nfile = thermite::core::manage::download_file_with_progress(
+ &nmod.url,
+ download_path,
+ |delta, current, total| {
+ if delta != 0 {
+ // Only emit a signal once every 100ms
+ // This way we don't bombard the frontend with events on fast download speeds
+ let time_since_last_emit = Instant::now().duration_since(*last_emit.borrow());
+ if time_since_last_emit >= Duration::from_millis(100) {
+ window
+ .emit(
+ "northstar-install-download-progress",
+ InstallProgress {
+ current_downloaded: current,
+ total_size: total,
+ state: InstallState::DOWNLOADING,
+ },
+ )
+ .unwrap();
+ *last_emit.borrow_mut() = Instant::now();
+ }
+ }
+ },
+ )
+ .unwrap();
+
+ window
+ .emit(
+ "northstar-install-download-progress",
+ InstallProgress {
+ current_downloaded: 0,
+ total_size: 0,
+ state: InstallState::EXTRACTING,
+ },
+ )
+ .unwrap();
+
+ log::info!("Extracting Northstar...");
+ extract(nfile, game_path)?;
+
+ // Delete old copy
+ log::info!("Delete temp folder again");
+ std::fs::remove_dir_all(download_directory).unwrap();
+
+ log::info!("Done installing Northstar!");
+ window
+ .emit(
+ "northstar-install-download-progress",
+ InstallProgress {
+ current_downloaded: 0,
+ total_size: 0,
+ state: InstallState::DONE,
+ },
+ )
+ .unwrap();
+
+ Ok(())
+}
+
+pub async fn install_northstar(
+ window: tauri::Window,
+ game_path: &str,
+ northstar_package_name: String,
+ version_number: Option<String>,
+) -> Result<String, String> {
+ let index = thermite::api::get_package_index().unwrap().to_vec();
+ let nmod = index
+ .iter()
+ .find(|f| f.name.to_lowercase() == northstar_package_name.to_lowercase())
+ .ok_or_else(|| panic!("Couldn't find Northstar on thunderstore???"))
+ .unwrap();
+
+ // Use passed version or latest if no version was passed
+ let version = version_number.as_ref().unwrap_or(&nmod.latest);
+
+ log::info!("Install path \"{}\"", game_path);
+
+ match do_install(
+ window,
+ nmod.versions.get(version).unwrap(),
+ std::path::Path::new(game_path),
+ )
+ .await
+ {
+ Ok(_) => (),
+ Err(err) => {
+ if game_path
+ .to_lowercase()
+ .contains(&r#"C:\Program Files\"#.to_lowercase())
+ // default is `C:\Program Files\EA Games\Titanfall2`
+ {
+ return Err(
+ "Cannot install to default EA App install path, please move Titanfall2 to a different install location.".to_string(),
+ );
+ } else {
+ return Err(err.to_string());
+ }
+ }
+ }
+
+ Ok(nmod.latest.clone())
+}
+
+/// Returns identifier of host OS FlightCore is running on
+pub fn get_host_os() -> String {
+ env::consts::OS.to_string()
+}
+
+/// Prepare Northstar and Launch through Steam using the Browser Protocol
+pub fn launch_northstar_steam(
+ game_install: &GameInstall,
+ _bypass_checks: Option<bool>,
+) -> Result<String, String> {
+ if !matches!(game_install.install_type, InstallType::STEAM) {
+ return Err("Titanfall2 was not installed via Steam".to_string());
+ }
+
+ match steamlocate::SteamDir::locate() {
+ Some(mut steamdir) => {
+ if get_host_os() != "windows" {
+ let titanfall2_steamid: u32 = TITANFALL2_STEAM_ID.parse().unwrap();
+ match steamdir.compat_tool(&titanfall2_steamid) {
+ Some(compat) => {
+ if !compat
+ .name
+ .clone()
+ .unwrap()
+ .to_ascii_lowercase()
+ .contains("northstarproton")
+ {
+ return Err(
+ "Titanfall2 was not configured to use NorthstarProton".to_string()
+ );
+ }
+ }
+ None => {
+ return Err(
+ "Titanfall2 was not configured to use a compatibility tool".to_string()
+ );
+ }
+ }
+ }
+ }
+ None => {
+ return Err("Couldn't access Titanfall2 directory".to_string());
+ }
+ }
+
+ // Switch to Titanfall2 directory to set everything up
+ if std::env::set_current_dir(game_install.game_path.clone()).is_err() {
+ // We failed to get to Titanfall2 directory
+ return Err("Couldn't access Titanfall2 directory".to_string());
+ }
+
+ let run_northstar = "run_northstar.txt";
+ let run_northstar_bak = "run_northstar.txt.bak";
+
+ if Path::new(run_northstar).exists() {
+ // rename should ovewrite existing files
+ fs::rename(run_northstar, run_northstar_bak).unwrap();
+ }
+
+ // Passing arguments gives users a prompt, so we use run_northstar.txt
+ fs::write(run_northstar, b"1").unwrap();
+
+ let retval = match open::that(format!("steam://run/{}/", TITANFALL2_STEAM_ID)) {
+ Ok(()) => Ok("Started game".to_string()),
+ Err(_err) => Err("Failed to launch Titanfall 2 via Steam".to_string()),
+ };
+
+ let is_err = retval.is_err();
+
+ // Handle the rest in the backround
+ tauri::async_runtime::spawn(async move {
+ // Starting the EA app and Titanfall might take a good minute or three
+ let mut wait_countdown = 60 * 3;
+ while wait_countdown > 0 && !check_northstar_running() && !is_err {
+ sleep(Duration::from_millis(1000)).await;
+ wait_countdown -= 1;
+ }
+
+ // Northstar may be running, but it may not have loaded the file yet
+ sleep(Duration::from_millis(2000)).await;
+
+ // intentionally ignore Result
+ let _ = fs::remove_file(run_northstar);
+
+ if Path::new(run_northstar_bak).exists() {
+ fs::rename(run_northstar_bak, run_northstar).unwrap();
+ }
+ });
+
+ retval
+}
+
+pub fn check_origin_running() -> bool {
+ let s = sysinfo::System::new_all();
+ let x = s.processes_by_name("Origin.exe").next().is_some()
+ || s.processes_by_name("EADesktop.exe").next().is_some();
+ x
+}
+
+/// Checks if Northstar process is running
+pub fn check_northstar_running() -> bool {
+ let s = sysinfo::System::new_all();
+ let x = s
+ .processes_by_name("NorthstarLauncher.exe")
+ .next()
+ .is_some()
+ || s.processes_by_name("Titanfall2.exe").next().is_some();
+ x
+}
diff --git a/src-tauri/src/mod_management/mod.rs b/src-tauri/src/mod_management/mod.rs
index 1c648ca4..455aa424 100644
--- a/src-tauri/src/mod_management/mod.rs
+++ b/src-tauri/src/mod_management/mod.rs
@@ -3,12 +3,12 @@
use crate::constants::{BLACKLISTED_MODS, CORE_MODS};
use async_recursion::async_recursion;
+use crate::NorthstarMod;
use anyhow::{anyhow, Result};
-use app::NorthstarMod;
use serde::{Deserialize, Serialize};
use std::{fs, io::Read, path::PathBuf};
-use app::GameInstall;
+use crate::GameInstall;
#[derive(Debug, Clone)]
struct ParsedThunderstoreModString {
diff --git a/src-tauri/src/northstar/mod.rs b/src-tauri/src/northstar/mod.rs
index a969d456..0fd4743e 100644
--- a/src-tauri/src/northstar/mod.rs
+++ b/src-tauri/src/northstar/mod.rs
@@ -1,9 +1,8 @@
//! This module deals with handling things around Northstar such as
//! - getting version number
-use crate::constants::CORE_MODS;
+use crate::{check_origin_running, constants::CORE_MODS, get_host_os, GameInstall, InstallType};
use anyhow::anyhow;
-use app::{check_origin_running, get_host_os, GameInstall, InstallType};
/// Check version number of a mod
pub fn check_mod_version_number(path_to_mod_folder: &str) -> Result<String, anyhow::Error> {
diff --git a/src-tauri/src/repair_and_verify/mod.rs b/src-tauri/src/repair_and_verify/mod.rs
index fd6c0e83..92835a4e 100644
--- a/src-tauri/src/repair_and_verify/mod.rs
+++ b/src-tauri/src/repair_and_verify/mod.rs
@@ -1,7 +1,7 @@
use crate::mod_management::{get_enabled_mods, rebuild_enabled_mods_json, set_mod_enabled_status};
-use anyhow::anyhow;
/// Contains various functions to repair common issues and verifying installation
-use app::{constants::CORE_MODS, GameInstall};
+use crate::{constants::CORE_MODS, GameInstall};
+use anyhow::anyhow;
/// Verifies Titanfall2 game files
#[tauri::command]