From 5e9850881d35d3af9ae8a2f99402e02300f77835 Mon Sep 17 00:00:00 2001 From: HsiangNianian Date: Sun, 18 Jan 2026 12:58:22 +0800 Subject: fix: complete Instance/Profile System isolation and state management ## Overview Fixed critical multi-instance isolation bugs where versions, mod loaders, and instance state were not properly isolated between instances. These changes ensure full data isolation and consistent instance metadata. ## Bug Fixes - P0 (Critical Isolation Issues) ### 1. Backend: get_versions() command isolation - Problem: Used global app_data_dir instead of instance-specific game_dir - Fix: Added instance_id parameter, now queries instance.game_dir - Impact: Versions are now properly isolated per instance ### 2. Frontend: delete_version missing instanceId - Problem: Frontend passed only versionId, not instanceId - Fix: Updated VersionsView.svelte to pass instanceId parameter - Impact: Version deletion now targets correct instance ### 3. Frontend: get_version_metadata missing instanceId - Problem: Metadata queries didn't specify which instance to check - Fix: Updated VersionsView.svelte to pass instanceId parameter - Impact: Version info displayed per-instance correctly ### 4. Frontend: Instance switching doesn't refresh versions - Problem: Switching instances didn't reload version list - Fix: Added $effect hook in GameState to watch activeInstanceId changes - Impact: Version list auto-refreshes on instance switch ## Bug Fixes - P1 (State Synchronization) ### 5. Backend: install_fabric doesn't update Instance.mod_loader - Problem: Instance.mod_loader field wasn't updated after installation - Fix: Added instance_state.update_instance() call - Impact: Instance metadata stays in sync ### 6. Backend: install_forge doesn't update Instance.mod_loader - Problem: Instance.mod_loader field wasn't updated after installation - Fix: Added instance_state.update_instance() call - Impact: Instance metadata stays in sync ### 7. Backend: delete_version doesn't clean up Instance state - Problem: Deleting version didn't clear Instance.version_id or .mod_loader - Fix: Added cleanup logic to clear stale references - Impact: Instance state remains valid after deletion ## Testing - Added comprehensive integration tests in instance_isolation_tests.rs - Tests document 10 key scenarios for multi-instance isolation - All code compiles cleanly with no errors --- src-tauri/src/main.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'src-tauri/src') diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 853c93e..4f9071f 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -879,12 +879,14 @@ fn parse_jvm_arguments( } #[tauri::command] -async fn get_versions(window: Window) -> Result, String> { - let app_handle = window.app_handle(); - let game_dir = app_handle - .path() - .app_data_dir() - .map_err(|e| format!("Failed to get app data dir: {}", e))?; +async fn get_versions( + _window: Window, + instance_state: State<'_, core::instance::InstanceState>, + instance_id: String, +) -> Result, String> { + let game_dir = instance_state + .get_instance_game_dir(&instance_id) + .ok_or_else(|| format!("Instance {} not found", instance_id))?; match core::manifest::fetch_version_manifest().await { Ok(manifest) => { @@ -1595,6 +1597,13 @@ async fn install_fabric( format!("Fabric installed successfully: {}", result.id) ); + // Update Instance's mod_loader metadata + if let Some(mut instance) = instance_state.get_instance(&instance_id) { + instance.mod_loader = Some("fabric".to_string()); + instance.mod_loader_version = Some(loader_version); + instance_state.update_instance(instance)?; + } + // Emit event to notify frontend let _ = window.emit("fabric-installed", &result.id); @@ -1669,6 +1678,31 @@ async fn delete_version( .await .map_err(|e| format!("Failed to delete version: {}", e))?; + // Clean up Instance state if necessary + if let Some(mut instance) = instance_state.get_instance(&instance_id) { + let mut updated = false; + + // If deleted version is the current selected version + if instance.version_id.as_ref() == Some(&version_id) { + instance.version_id = None; + updated = true; + } + + // If deleted version is a modded version, clear mod_loader + if (version_id.starts_with("fabric-loader-") + && instance.mod_loader == Some("fabric".to_string())) + || (version_id.contains("-forge-") && instance.mod_loader == Some("forge".to_string())) + { + instance.mod_loader = None; + instance.mod_loader_version = None; + updated = true; + } + + if updated { + instance_state.update_instance(instance)?; + } + } + // Emit event to notify frontend let _ = window.emit("version-deleted", &version_id); @@ -1948,7 +1982,10 @@ async fn install_forge( // Check if the version JSON already exists let version_id = core::forge::generate_version_id(&game_version, &forge_version); - let json_path = game_dir.join("versions").join(&version_id).join(format!("{}.json", version_id)); + let json_path = game_dir + .join("versions") + .join(&version_id) + .join(format!("{}.json", version_id)); let result = if json_path.exists() { // Version JSON was created by the installer, load it @@ -1974,6 +2011,13 @@ async fn install_forge( format!("Forge installed successfully: {}", result.id) ); + // Update Instance's mod_loader metadata + if let Some(mut instance) = instance_state.get_instance(&instance_id) { + instance.mod_loader = Some("forge".to_string()); + instance.mod_loader_version = Some(forge_version); + instance_state.update_instance(instance)?; + } + // Emit event to notify frontend let _ = window.emit("forge-installed", &result.id); -- cgit v1.2.3-70-g09d2