conflict backend stuff #89

This commit is contained in:
Novattz
2025-12-26 22:10:34 +01:00
parent 7fd3147f44
commit d4ae5d74e9
2 changed files with 169 additions and 11 deletions

View File

@@ -10,6 +10,7 @@ mod searcher;
mod unlockers;
mod smokeapi_config;
use crate::unlockers::{CreamLinux, SmokeAPI, Unlocker};
use dlc_manager::DlcInfoWithState;
use installer::{Game, InstallerAction, InstallerType};
use log::{debug, error, info, warn};
@@ -456,6 +457,146 @@ fn delete_smokeapi_config(game_path: String) -> Result<(), String> {
smokeapi_config::delete_config(&game_path)
}
#[tauri::command]
async fn resolve_platform_conflict(
game_id: String,
conflict_type: String, // "cream-to-proton" or "smoke-to-native"
state: State<'_, AppState>,
app_handle: tauri::AppHandle,
) -> Result<Game, String> {
info!(
"Resolving platform conflict for game {}: {}",
game_id, conflict_type
);
let game = {
let games = state.games.lock();
games
.get(&game_id)
.cloned()
.ok_or_else(|| format!("Game with ID {} not found", game_id))?
};
let game_title = game.title.clone();
// Emit progress
installer::emit_progress(
&app_handle,
&format!("Resolving Conflict: {}", game_title),
"Removing conflicting files...",
50.0,
false,
false,
None,
);
// Perform the appropriate removal based on conflict type
match conflict_type.as_str() {
"cream-to-proton" => {
// Remove CreamLinux files (bypassing native check)
info!("Removing CreamLinux files from Proton game: {}", game_title);
CreamLinux::uninstall_from_game(&game.path, &game.id)
.await
.map_err(|e| format!("Failed to remove CreamLinux files: {}", e))?;
// Remove version from manifest
crate::cache::remove_creamlinux_version(&game.path)?;
}
"smoke-to-native" => {
// Remove SmokeAPI files (bypassing proton check)
info!("Removing SmokeAPI files from native game: {}", game_title);
// For native games, we need to manually remove backup files since
// the main DLL might already be gone
// Look for and remove *_o.dll backup files
use walkdir::WalkDir;
let mut removed_files = false;
for entry in WalkDir::new(&game.path)
.max_depth(5)
.into_iter()
.filter_map(Result::ok)
{
let path = entry.path();
if !path.is_file() {
continue;
}
let filename = path.file_name().unwrap_or_default().to_string_lossy();
// Remove steam_api*_o.dll backup files
if filename.starts_with("steam_api") && filename.ends_with("_o.dll") {
match std::fs::remove_file(path) {
Ok(_) => {
info!("Removed SmokeAPI backup file: {}", path.display());
removed_files = true;
}
Err(e) => {
warn!("Failed to remove backup file {}: {}", path.display(), e);
}
}
}
}
// Also try the normal uninstall if api_files are present
if !game.api_files.is_empty() {
let api_files_str = game.api_files.join(",");
if let Err(e) = SmokeAPI::uninstall_from_game(&game.path, &api_files_str).await {
// Don't fail if this errors - we might have already cleaned up manually above
warn!("SmokeAPI uninstall warning: {}", e);
}
}
if !removed_files {
warn!("No SmokeAPI files found to remove for: {}", game_title);
}
// Remove version from manifest
crate::cache::remove_smokeapi_version(&game.path)?;
}
_ => return Err(format!("Invalid conflict type: {}", conflict_type)),
}
installer::emit_progress(
&app_handle,
&format!("Conflict Resolved: {}", game_title),
"Conflicting files have been removed successfully!",
100.0,
true,
false,
None,
);
// Update game state
let updated_game = {
let mut games_map = state.games.lock();
let game = games_map
.get_mut(&game_id)
.ok_or_else(|| format!("Game with ID {} not found after conflict resolution", game_id))?;
match conflict_type.as_str() {
"cream-to-proton" => {
game.cream_installed = false;
}
"smoke-to-native" => {
game.smoke_installed = false;
}
_ => {}
}
game.installing = false;
game.clone()
};
if let Err(e) = app_handle.emit("game-updated", &updated_game) {
warn!("Failed to emit game-updated event: {}", e);
}
info!("Platform conflict resolved successfully for: {}", game_title);
Ok(updated_game)
}
fn setup_logging() -> Result<(), Box<dyn std::error::Error>> {
use log::LevelFilter;
use log4rs::append::file::FileAppender;
@@ -516,6 +657,7 @@ fn main() {
read_smokeapi_config,
write_smokeapi_config,
delete_smokeapi_config,
resolve_platform_conflict,
])
.setup(|app| {
info!("Tauri application setup");

View File

@@ -256,11 +256,7 @@ fn check_creamlinux_installed(game_path: &Path) -> bool {
// Check if a game has SmokeAPI installed
fn check_smokeapi_installed(game_path: &Path, api_files: &[String]) -> bool {
if api_files.is_empty() {
return false;
}
// SmokeAPI creates backups with _o.dll suffix
// First check the provided api_files for backup files
for api_file in api_files {
let api_path = game_path.join(api_file);
let api_dir = api_path.parent().unwrap_or(game_path);
@@ -275,6 +271,28 @@ fn check_smokeapi_installed(game_path: &Path, api_files: &[String]) -> bool {
return true;
}
}
// Also scan for orphaned backup files (in case the main DLL was removed)
// This handles the Proton->Native switch case where steam_api*.dll is gone
// but steam_api*_o.dll backup remains
for entry in WalkDir::new(game_path)
.max_depth(5)
.into_iter()
.filter_map(Result::ok)
{
let path = entry.path();
if !path.is_file() {
continue;
}
let filename = path.file_name().unwrap_or_default().to_string_lossy();
// Look for steam_api*_o.dll backup files (SmokeAPI pattern)
if filename.starts_with("steam_api") && filename.ends_with("_o.dll") {
debug!("Found orphaned SmokeAPI backup file: {}", path.display());
return true;
}
}
false
}
@@ -631,12 +649,10 @@ pub async fn find_installed_games(steamapps_paths: &[PathBuf]) -> Vec<GameInfo>
// Check for CreamLinux installation
let cream_installed = check_creamlinux_installed(&game_path);
// Check for SmokeAPI installation (only for non-native games with Steam API DLLs)
let smoke_installed = if !is_native && !api_files.is_empty() {
check_smokeapi_installed(&game_path, &api_files)
} else {
false
};
// Check for SmokeAPI installation
// For Proton games: check if api_files exist
// For Native games: ALSO check for orphaned backup files (proton->native switch)
let smoke_installed = check_smokeapi_installed(&game_path, &api_files);
// Create the game info
let game_info = GameInfo {