Async downloader, better Proton support (#183)

* feat: async downloader + other fixes

* feat: windows command parsing + use library path for install path

* feat: better proton support

* feat: style fixes and store button now uses in-app

* feat: emulator rename + umu emulator fix

* feat: bring process creation inline with docs

* fix: clippy
This commit is contained in:
DecDuck
2026-02-06 23:24:14 +11:00
committed by GitHub
parent 1f74d35bdc
commit 16ef83228b
45 changed files with 1453 additions and 381 deletions
@@ -1,4 +1,4 @@
use std::fs::create_dir_all;
use std::{fs::create_dir_all, path::PathBuf};
use client::compat::{COMPAT_INFO, UMU_LAUNCHER_EXECUTABLE};
use database::{
@@ -15,6 +15,7 @@ impl ProcessHandler for NativeGameLauncher {
launch_command: String,
_game_version: &GameVersion,
_current_dir: &str,
_database: &Database,
) -> Result<String, ProcessError> {
Ok(format!("\"{}\"", launch_command))
}
@@ -32,33 +33,55 @@ impl ProcessHandler for UMULauncher {
launch_command: String,
game_version: &GameVersion,
_current_dir: &str,
database: &Database,
) -> Result<String, ProcessError> {
let launch_config = game_version
let umu_id_override = game_version
.launches
.iter()
.find(|v| v.platform == meta.target_platform)
.ok_or(ProcessError::NotInstalled)?;
.and_then(|v| v.umu_id_override.as_ref())
.map_or("", |v| v);
let game_id = match &launch_config.umu_id_override {
Some(game_override) => {
if game_override.is_empty() {
game_version.version_id.clone()
} else {
game_override.clone()
}
}
None => game_version.version_id.clone(),
let game_id = if umu_id_override.is_empty() {
&game_version.version_id
} else {
umu_id_override
};
let pfx_dir = DATA_ROOT_DIR.join("pfx");
let pfx_dir = pfx_dir.join(meta.id.clone());
create_dir_all(&pfx_dir)?;
let no_proton = match meta.target_platform {
Platform::Linux => Some("UMU_NO_PROTON=1"),
_ => None,
};
let proton_env = if no_proton.is_none() {
let proton_path = game_version
.user_configuration
.override_proton_path
.as_ref()
.or(database.applications.default_proton_path.as_ref())
.ok_or(ProcessError::NoCompat)?;
let proton_valid = crate::compat::read_proton_path(PathBuf::from(proton_path))
.ok()
.flatten()
.is_some();
if !proton_valid {
return Err(ProcessError::NoCompat);
}
Some(format!("PROTONPATH={}", proton_path))
} else {
None
};
Ok(format!(
"GAMEID={game_id} WINEPREFIX={} {} {umu:?} {launch}",
"GAMEID={game_id} {} WINEPREFIX={} {} {umu:?} {launch}",
proton_env.unwrap_or(String::new()),
pfx_dir.to_string_lossy(),
match meta.target_platform {
Platform::Linux => "UMU_NO_PROTON=1",
_ => "",
},
no_proton.unwrap_or(""),
umu = UMU_LAUNCHER_EXECUTABLE
.as_ref()
.expect("Failed to get UMU_LAUNCHER_EXECUTABLE as ref"),
@@ -82,6 +105,7 @@ impl ProcessHandler for AsahiMuvmLauncher {
launch_command: String,
game_version: &GameVersion,
current_dir: &str,
database: &Database,
) -> Result<String, ProcessError> {
let umu_launcher = UMULauncher {};
let umu_string = umu_launcher.create_launch_process(
@@ -89,6 +113,7 @@ impl ProcessHandler for AsahiMuvmLauncher {
launch_command,
game_version,
current_dir,
database,
)?;
let mut args_cmd = umu_string
.split("umu-run")