From 871426ca6e6aa6744f3eb347684553c358708b44 Mon Sep 17 00:00:00 2001 From: "Calum H. (IMB11)" Date: Thu, 26 Mar 2026 19:52:01 +0000 Subject: [PATCH 1/4] fix: wrong lock field --- .../shared/content-tab/composables/content-filtering.ts | 1 - packages/ui/src/layouts/shared/content-tab/layout.vue | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts b/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts index 7f448e1e18..66ce92f33f 100644 --- a/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts +++ b/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts @@ -53,7 +53,6 @@ export function useContentFilters(items: Ref, config?: ContentFil if ( config?.showUpdateFilter && - !config?.isPackLocked?.value && items.value.some((m) => m.has_update) ) { options.push({ id: 'updates', label: 'Updates' }) diff --git a/packages/ui/src/layouts/shared/content-tab/layout.vue b/packages/ui/src/layouts/shared/content-tab/layout.vue index e1334224aa..8a47bc4575 100644 --- a/packages/ui/src/layouts/shared/content-tab/layout.vue +++ b/packages/ui/src/layouts/shared/content-tab/layout.vue @@ -278,7 +278,7 @@ const tableItems = computed(() => { isBulkOperating.value || item.installing === true, installing: item.installing === true, - hasUpdate: !ctx.isPackLocked.value && item.has_update, + hasUpdate: item.has_update, isClientOnly: isClientOnlyEnvironment(item.environment), overflowOptions: ctx.getOverflowOptions?.(item), } @@ -711,7 +711,7 @@ const confirmUnlinkModal = ref>() >() Date: Thu, 26 Mar 2026 20:09:34 +0000 Subject: [PATCH 2/4] fix: install_stage locking up due to previous failure stored as stale snapshot --- packages/app-lib/src/api/profile/mod.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/app-lib/src/api/profile/mod.rs b/packages/app-lib/src/api/profile/mod.rs index 0384d3c652..87df25c24b 100644 --- a/packages/app-lib/src/api/profile/mod.rs +++ b/packages/app-lib/src/api/profile/mod.rs @@ -352,14 +352,22 @@ pub async fn install(path: &str, force: bool) -> crate::Result<()> { if let Some(profile) = get(path).await? { let result = crate::launcher::install_minecraft(&profile, None, force).await; - if result.is_err() - && profile.install_stage != ProfileInstallStage::Installed - { - edit(path, |prof| { - prof.install_stage = ProfileInstallStage::NotInstalled; - async { Ok(()) } - }) - .await?; + if result.is_err() { + // Re-read the profile to get the current install_stage, as + // install_minecraft may have changed it (e.g. to MinecraftInstalling) + let current_stage = get(path) + .await + .ok() + .flatten() + .map(|p| p.install_stage) + .unwrap_or(ProfileInstallStage::NotInstalled); + if current_stage != ProfileInstallStage::Installed { + edit(path, |prof| { + prof.install_stage = ProfileInstallStage::NotInstalled; + async { Ok(()) } + }) + .await?; + } } result?; } else { From c50db58d8104f589012c756cf44635544c8d59b8 Mon Sep 17 00:00:00 2001 From: "Calum H. (IMB11)" Date: Thu, 26 Mar 2026 20:16:29 +0000 Subject: [PATCH 3/4] fix: Error when updating instance Fixes #5671 --- packages/app-lib/src/api/profile/mod.rs | 20 +++----- packages/app-lib/src/api/worlds.rs | 16 +++---- packages/app-lib/src/launcher/mod.rs | 63 +++++++++++++++++-------- 3 files changed, 58 insertions(+), 41 deletions(-) diff --git a/packages/app-lib/src/api/profile/mod.rs b/packages/app-lib/src/api/profile/mod.rs index 87df25c24b..313fe59ae8 100644 --- a/packages/app-lib/src/api/profile/mod.rs +++ b/packages/app-lib/src/api/profile/mod.rs @@ -294,19 +294,13 @@ pub async fn get_optimal_jre_key( let state = State::get().await?; if let Some(profile) = get(path).await? { - let minecraft = crate::api::metadata::get_minecraft_versions().await?; - - // Fetch version info from stored profile game_version - let version = minecraft - .versions - .iter() - .find(|it| it.id == profile.game_version) - .ok_or_else(|| { - crate::ErrorKind::LauncherError(format!( - "Invalid or unknown Minecraft version: {}", - profile.game_version - )) - })?; + let (minecraft, version_index) = + crate::launcher::resolve_minecraft_manifest( + &profile.game_version, + &state, + ) + .await?; + let version = &minecraft.versions[version_index]; let loader_version = crate::launcher::get_loader_version_from_profile( &profile.game_version, diff --git a/packages/app-lib/src/api/worlds.rs b/packages/app-lib/src/api/worlds.rs index 4cde476e12..4edfd5aecb 100644 --- a/packages/app-lib/src/api/worlds.rs +++ b/packages/app-lib/src/api/worlds.rs @@ -901,15 +901,13 @@ pub async fn get_profile_protocol_version( return Ok(Some(*protocol_version)); } - let minecraft = crate::api::metadata::get_minecraft_versions().await?; - let version_index = minecraft - .versions - .iter() - .position(|it| it.id == profile.game_version) - .ok_or(ErrorKind::LauncherError(format!( - "Invalid game version: {}", - profile.game_version - )))?; + let state = State::get().await?; + let (minecraft, version_index) = + crate::launcher::resolve_minecraft_manifest( + &profile.game_version, + &state, + ) + .await?; let version = &minecraft.versions[version_index]; let loader_version = get_loader_version_from_profile( diff --git a/packages/app-lib/src/launcher/mod.rs b/packages/app-lib/src/launcher/mod.rs index db29817fb8..51b8a91240 100644 --- a/packages/app-lib/src/launcher/mod.rs +++ b/packages/app-lib/src/launcher/mod.rs @@ -189,6 +189,46 @@ pub async fn get_loader_version_from_profile( } } +/// Resolves the Minecraft version manifest and finds the index for the given +/// game version. If the version isn't found in the cache, forces a manifest +/// refresh to pick up newly-released versions. +pub async fn resolve_minecraft_manifest( + game_version: &str, + state: &State, +) -> crate::Result<(d::minecraft::VersionManifest, usize)> { + let minecraft = crate::api::metadata::get_minecraft_versions().await?; + + if let Some(idx) = minecraft + .versions + .iter() + .position(|it| it.id == game_version) + { + return Ok((minecraft, idx)); + } + + // Version not found in cache — force a manifest refresh in case it was + // released after the cache was populated. + let refreshed = crate::state::CachedEntry::get_minecraft_manifest( + Some(crate::state::CacheBehaviour::MustRevalidate), + &state.pool, + &state.api_semaphore, + ) + .await? + .ok_or_else(|| { + crate::ErrorKind::NoValueFor("minecraft versions".to_string()) + })?; + + let idx = refreshed + .versions + .iter() + .position(|it| it.id == game_version) + .ok_or(crate::ErrorKind::LauncherError(format!( + "Invalid game version: {game_version}" + )))?; + + Ok((refreshed, idx)) +} + #[tracing::instrument(skip(profile))] pub async fn install_minecraft( @@ -219,16 +259,8 @@ pub async fn install_minecraft( let instance_path = crate::api::profile::get_full_path(&profile.path).await?; - let minecraft = crate::api::metadata::get_minecraft_versions().await?; - - let version_index = minecraft - .versions - .iter() - .position(|it| it.id == profile.game_version) - .ok_or(crate::ErrorKind::LauncherError(format!( - "Invalid game version: {}", - profile.game_version - )))?; + let (minecraft, version_index) = + resolve_minecraft_manifest(&profile.game_version, &state).await?; let version = &minecraft.versions[version_index]; let minecraft_updated = version_index <= minecraft @@ -481,15 +513,8 @@ pub async fn launch_minecraft( let instance_path = crate::api::profile::get_full_path(&profile.path).await?; - let minecraft = crate::api::metadata::get_minecraft_versions().await?; - let version_index = minecraft - .versions - .iter() - .position(|it| it.id == profile.game_version) - .ok_or(crate::ErrorKind::LauncherError(format!( - "Invalid game version: {}", - profile.game_version - )))?; + let (minecraft, version_index) = + resolve_minecraft_manifest(&profile.game_version, &state).await?; let version = &minecraft.versions[version_index]; let minecraft_updated = version_index <= minecraft From 71dd7391cb515eacbca3e1a786223568c7a12b01 Mon Sep 17 00:00:00 2001 From: "Calum H. (IMB11)" Date: Thu, 26 Mar 2026 20:27:47 +0000 Subject: [PATCH 4/4] fix: prepr --- .../shared/content-tab/composables/content-filtering.ts | 5 +---- packages/ui/src/layouts/shared/content-tab/layout.vue | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts b/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts index 66ce92f33f..cc0c569543 100644 --- a/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts +++ b/packages/ui/src/layouts/shared/content-tab/composables/content-filtering.ts @@ -51,10 +51,7 @@ export function useContentFilters(items: Ref, config?: ContentFil } } - if ( - config?.showUpdateFilter && - items.value.some((m) => m.has_update) - ) { + if (config?.showUpdateFilter && items.value.some((m) => m.has_update)) { options.push({ id: 'updates', label: 'Updates' }) } diff --git a/packages/ui/src/layouts/shared/content-tab/layout.vue b/packages/ui/src/layouts/shared/content-tab/layout.vue index 8a47bc4575..fd9b45158a 100644 --- a/packages/ui/src/layouts/shared/content-tab/layout.vue +++ b/packages/ui/src/layouts/shared/content-tab/layout.vue @@ -814,10 +814,7 @@ const confirmUnlinkModal = ref>() >