From e745c75cc81c064f8c7b96a0f554e8a30899709e Mon Sep 17 00:00:00 2001 From: Wyvest Date: Mon, 23 Feb 2026 05:56:01 -0500 Subject: [PATCH] Fix overrides not being downloaded --- apps/oneclient/desktop/src/api/commands.rs | 31 +++++++ apps/oneclient/frontend/src/bindings.gen.ts | 41 ++++----- .../frontend/src/components/DownloadMods.tsx | 83 ++++++++++++++----- .../preferences/versionCategory.tsx | 9 +- packages/core/src/api/packages/modpack/mod.rs | 2 +- .../core/src/api/packages/modpack/mrpack.rs | 2 +- 6 files changed, 122 insertions(+), 46 deletions(-) diff --git a/apps/oneclient/desktop/src/api/commands.rs b/apps/oneclient/desktop/src/api/commands.rs index c34b4217..7ed07b76 100644 --- a/apps/oneclient/desktop/src/api/commands.rs +++ b/apps/oneclient/desktop/src/api/commands.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::path::PathBuf; use onelauncher_core::api::cluster::dao::ClusterId; use onelauncher_core::api::packages::modpack::data::ModpackArchive; @@ -21,6 +22,12 @@ pub trait OneClientApi { #[taurpc(alias = "getVersions")] async fn get_versions() -> LauncherResult; + #[taurpc(alias = "extractBundleOverrides")] + async fn extract_bundle_overrides( + bundle_path: PathBuf, + cluster_id: ClusterId, + ) -> LauncherResult<()>; + #[taurpc(alias = "checkForUpdate")] async fn check_for_update( app_handle: AppHandle, @@ -82,6 +89,30 @@ impl OneClientApi for OneClientApiImpl { get_data_storage_versions().await } + async fn extract_bundle_overrides( + self, + bundle_path: PathBuf, + cluster_id: ClusterId, + ) -> LauncherResult<()> { + let cluster = onelauncher_core::api::cluster::dao::get_cluster_by_id(cluster_id) + .await? + .ok_or_else(|| { + onelauncher_core::error::LauncherError::from(anyhow::anyhow!( + "cluster with id {} not found", + cluster_id + )) + })?; + + onelauncher_core::api::packages::modpack::mrpack::copy_overrides_folder( + &cluster, + &bundle_path, + &None, + ) + .await?; + + Ok(()) + } + async fn check_for_update( self, app_handle: AppHandle, diff --git a/apps/oneclient/frontend/src/bindings.gen.ts b/apps/oneclient/frontend/src/bindings.gen.ts index cd5340aa..13cf1b8f 100644 --- a/apps/oneclient/frontend/src/bindings.gen.ts +++ b/apps/oneclient/frontend/src/bindings.gen.ts @@ -303,25 +303,12 @@ export type VersionType = */ "old_beta" -const ARGS_MAP = { 'events':'{"message":["event"],"process":["event"],"ingress":["event"]}', 'oneclient':'{"getBundlesFor":["cluster_id"],"checkForUpdate":[],"installUpdate":[],"getVersions":[],"getClustersGroupedByMajor":[]}', 'debug':'{"getLocale":[],"getType":[],"getArch":[],"getFamily":[],"getOsVersion":[],"getPackageVersion":[],"getPlatform":[],"getBuildTimestamp":[],"isInDev":[],"getGitCommitHash":[],"openDevTools":[]}', 'core':'{"getWorlds":["id"],"setClusterStage":["id","stage"],"getDefaultUser":["fallback"],"setDefaultUser":["uuid"],"getClusterById":["id"],"getLogByName":["id","name"],"removePackage":["cluster_id","package_hash"],"getRunningProcessesByClusterId":["cluster_id"],"getPackage":["provider","slug"],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"isClusterRunning":["cluster_id"],"getUser":["uuid"],"setDiscordRPCMessage":["message"],"getRunningProcesses":[],"killProcess":["pid"],"getLoadersForVersion":["mc_version"],"searchPackages":["provider","query"],"updateClusterById":["id","request"],"getClusters":[],"getGameVersions":[],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"launchCluster":["id","uuid","search_for_java"],"installModpack":["modpack","cluster_id"],"changeSkin":["access_token","skin_url","skin_variant"],"readSettings":[],"refreshAccount":["uuid"],"getMultiplePackages":["provider","slugs"],"openMsaLogin":[],"updateClusterProfile":["name","profile"],"open":["input"],"getUsers":[],"getScreenshots":["id"],"getProfileOrDefault":["name"],"removeUser":["uuid"],"getGlobalProfile":[],"createCluster":["options"],"getUsersFromAuthor":["provider","author"],"fetchMinecraftProfile":["uuid"],"removeCape":["access_token"],"convertUsernameUUID":["username_uuid"],"createSettingsProfile":["name"],"getLogs":["id"],"getPackageBody":["provider","body"],"refreshAccounts":[],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"getLinkedPackages":["cluster_id"],"changeCape":["access_token","cape_uuid"],"writeSettings":["setting"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"fetchLoggedInProfile":["access_token"],"removeCluster":["id"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}' } -export type Router = { 'debug': { openDevTools: () => Promise, -isInDev: () => Promise, -getArch: () => Promise, -getFamily: () => Promise, -getLocale: () => Promise, -getType: () => Promise, -getPlatform: () => Promise, -getOsVersion: () => Promise, -getGitCommitHash: () => Promise, -getBuildTimestamp: () => Promise, -getPackageVersion: () => Promise }, +const ARGS_MAP = { 'core':'{"removeUser":["uuid"],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"changeCape":["access_token","cape_uuid"],"getScreenshots":["id"],"setClusterStage":["id","stage"],"getRunningProcesses":[],"convertUsernameUUID":["username_uuid"],"getClusterById":["id"],"getRunningProcessesByClusterId":["cluster_id"],"getLoadersForVersion":["mc_version"],"getPackageBody":["provider","body"],"open":["input"],"getMultiplePackages":["provider","slugs"],"isClusterRunning":["cluster_id"],"removeCape":["access_token"],"getGlobalProfile":[],"setDiscordRPCMessage":["message"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"fetchLoggedInProfile":["access_token"],"readSettings":[],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"killProcess":["pid"],"refreshAccounts":[],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getLogs":["id"],"updateClusterProfile":["name","profile"],"searchPackages":["provider","query"],"updateClusterById":["id","request"],"getWorlds":["id"],"getProfileOrDefault":["name"],"refreshAccount":["uuid"],"getUsers":[],"getLogByName":["id","name"],"removeCluster":["id"],"launchCluster":["id","uuid","search_for_java"],"openMsaLogin":[],"getPackage":["provider","slug"],"writeSettings":["setting"],"getClusters":[],"getUsersFromAuthor":["provider","author"],"getGameVersions":[],"getUser":["uuid"],"getLinkedPackages":["cluster_id"],"removePackage":["cluster_id","package_hash"],"createCluster":["options"],"getDefaultUser":["fallback"],"setDefaultUser":["uuid"],"installModpack":["modpack","cluster_id"],"fetchMinecraftProfile":["uuid"],"createSettingsProfile":["name"],"changeSkin":["access_token","skin_url","skin_variant"]}', 'events':'{"process":["event"],"ingress":["event"],"message":["event"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'debug':'{"getLocale":[],"getPlatform":[],"isInDev":[],"getGitCommitHash":[],"getOsVersion":[],"getFamily":[],"getBuildTimestamp":[],"getPackageVersion":[],"openDevTools":[],"getType":[],"getArch":[]}', 'oneclient':'{"getVersions":[],"installUpdate":[],"getClustersGroupedByMajor":[],"extractBundleOverrides":["bundle_path","cluster_id"],"checkForUpdate":[],"getBundlesFor":["cluster_id"]}' } +export type Router = { 'events': { ingress: (event: IngressPayload) => Promise, +message: (event: MessagePayload) => Promise, +process: (event: ProcessPayload) => Promise }, 'folders': { fromCluster: (folderName: string) => Promise, openCluster: (folderName: string) => Promise }, -'oneclient': { getClustersGroupedByMajor: () => Promise>, -getBundlesFor: (clusterId: number) => Promise, -getVersions: () => Promise, -checkForUpdate: () => Promise, -installUpdate: () => Promise }, 'core': { getClusters: () => Promise, getClusterById: (id: number) => Promise, removeCluster: (id: number) => Promise, @@ -373,9 +360,23 @@ removeCape: (accessToken: string) => Promise, convertUsernameUUID: (usernameUuid: string) => Promise, setDiscordRPCMessage: (message: string) => Promise, open: (input: string) => Promise }, -'events': { ingress: (event: IngressPayload) => Promise, -message: (event: MessagePayload) => Promise, -process: (event: ProcessPayload) => Promise } }; +'oneclient': { getClustersGroupedByMajor: () => Promise>, +getBundlesFor: (clusterId: number) => Promise, +getVersions: () => Promise, +extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise, +checkForUpdate: () => Promise, +installUpdate: () => Promise }, +'debug': { openDevTools: () => Promise, +isInDev: () => Promise, +getArch: () => Promise, +getFamily: () => Promise, +getLocale: () => Promise, +getType: () => Promise, +getPlatform: () => Promise, +getOsVersion: () => Promise, +getGitCommitHash: () => Promise, +getBuildTimestamp: () => Promise, +getPackageVersion: () => Promise } }; export type { InferCommandOutput } diff --git a/apps/oneclient/frontend/src/components/DownloadMods.tsx b/apps/oneclient/frontend/src/components/DownloadMods.tsx index b50b2b1e..a9663a0b 100644 --- a/apps/oneclient/frontend/src/components/DownloadMods.tsx +++ b/apps/oneclient/frontend/src/components/DownloadMods.tsx @@ -1,11 +1,11 @@ -import type { ExternalPackage, ManagedVersionDependency, ModpackFile, Provider } from '@/bindings.gen'; +import type { ExternalPackage, ManagedVersionDependency, ModpackArchive, ModpackFile, Provider } from '@/bindings.gen'; import { getModMetaDataName, Overlay } from '@/components'; import { useSettings } from '@/hooks/useSettings'; import { bindings } from '@/main'; import { useCommandMut } from '@onelauncher/common'; import { Button } from '@onelauncher/common/components'; import { useNavigate } from '@tanstack/react-router'; -import { useEffect, useImperativeHandle, useState } from 'react'; +import { useEffect, useImperativeHandle, useRef, useState } from 'react'; import { DialogTrigger } from 'react-aria-components'; export interface DownloadModsRef { @@ -36,7 +36,7 @@ export function isManagedMod(mod: ModData): mod is ManagedModData { return mod.managed === true; } -export function DownloadMods({ modsPerCluster, ref }: { modsPerCluster: Record>; ref: React.Ref }) { +export function DownloadMods({ modsPerCluster, bundlesPerCluster, ref }: { modsPerCluster: Record>; bundlesPerCluster?: Record>; ref: React.Ref }) { const navigate = useNavigate(); const [isOpen, setOpen] = useState(false); const [mods, setMods] = useState([]); @@ -89,7 +89,7 @@ export function DownloadMods({ modsPerCluster, ref }: { modsPerCluster: Record setOpen(prev => !prev)}>Download Mods - + ); @@ -106,10 +106,12 @@ function downloadModsParallel(items: ModDataArray, limit: number, fn: (mod: ModD return Promise.all(workers); } -function DownloadingMods({ mods, setOpen, nextPath }: { mods: ModDataArray; setOpen: React.Dispatch>; nextPath: string }) { +function DownloadingMods({ mods, setOpen, nextPath, bundlesPerCluster }: { mods: ModDataArray; setOpen: React.Dispatch>; nextPath: string; bundlesPerCluster?: Record> }) { const navigate = useNavigate(); const [downloadedMods, setDownloadedMods] = useState(0); const [modName, setModName] = useState(null); + const [allDone, setAllDone] = useState(false); + const hasStarted = useRef(false); const download = useCommandMut(async (mod: ModData) => { if (isManagedMod(mod)) { if (mod.dependencies.length > 0) @@ -133,37 +135,72 @@ function DownloadingMods({ mods, setOpen, nextPath }: { mods: ModDataArray; setO let useParallelModDownloading = setting('parallel_mod_downloading'); useEffect(() => { + if (hasStarted.current) + return; + hasStarted.current = true; + const downloadAll = async () => { - if (useParallelModDownloading) - await downloadModsParallel(mods, 10, async (mod) => { - setModName(mod.name); - try { - await download.mutateAsync(mod); + try { + if (useParallelModDownloading) + await downloadModsParallel(mods, 10, async (mod) => { + setModName(mod.name); + try { + await download.mutateAsync(mod); + } + catch (e) { + console.warn(`Failed to download mod ${mod.name}:`, e); + } + finally { + setDownloadedMods(prev => prev + 1); + } + }); else + for (const mod of mods) { + setModName(mod.name); + try { + await download.mutateAsync(mod); + } + catch (e) { + console.warn(`Failed to download mod ${mod.name}:`, e); + } + finally { + setDownloadedMods(prev => prev + 1); + } } - finally { - setDownloadedMods(prev => prev + 1); - } - }); else - for (const mod of mods) { - setModName(mod.name); - try { - await download.mutateAsync(mod); - } - finally { - setDownloadedMods(prev => prev + 1); + + // Extract overrides from enabled bundles after all mods are downloaded + if (bundlesPerCluster) { + setModName('Extracting overrides...'); + for (const [clusterId, bundles] of Object.entries(bundlesPerCluster)) { + for (const bundle of bundles) { + if (bundle.manifest.enabled) { + try { + await bindings.oneclient.extractBundleOverrides(bundle.path, Number(clusterId)); + } + catch (e) { + console.error(`Failed to extract overrides for bundle ${bundle.manifest.name}:`, e); + } + } + } } } + } + catch (e) { + console.error('Error during mod download:', e); + } + finally { + setAllDone(true); + } }; downloadAll(); }, [mods]); useEffect(() => { - if (downloadedMods >= mods.length) { + if (allDone) { setOpen(false); navigate({ to: nextPath }); } - }, [downloadedMods, mods, navigate, nextPath, setOpen]); + }, [allDone, navigate, nextPath, setOpen]); return ( diff --git a/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx b/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx index 4ac471f6..075a60de 100644 --- a/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx +++ b/apps/oneclient/frontend/src/routes/onboarding/preferences/versionCategory.tsx @@ -61,6 +61,13 @@ function RouteComponent() { }, {} as Record>), ); + const bundlesPerCluster = useMemo(() => { + return clusters.reduce((acc, cluster, i) => { + acc[cluster.id] = bundleQueries[i]; + return acc; + }, {} as Record>); + }, [clusters, bundleQueries]); + const downloadModsRef = useRef(null); return ( @@ -82,7 +89,7 @@ function RouteComponent() {
- +
diff --git a/packages/core/src/api/packages/modpack/mod.rs b/packages/core/src/api/packages/modpack/mod.rs index b2e345ba..6fc18d5e 100644 --- a/packages/core/src/api/packages/modpack/mod.rs +++ b/packages/core/src/api/packages/modpack/mod.rs @@ -15,7 +15,7 @@ use crate::error::LauncherResult; use crate::store::ingress::SubIngress; pub mod data; -mod mrpack; +pub mod mrpack; mod polymrpack; #[cfg(test)] diff --git a/packages/core/src/api/packages/modpack/mrpack.rs b/packages/core/src/api/packages/modpack/mrpack.rs index dd773549..8693f881 100644 --- a/packages/core/src/api/packages/modpack/mrpack.rs +++ b/packages/core/src/api/packages/modpack/mrpack.rs @@ -256,7 +256,7 @@ pub(super) async fn download_and_link_packages( Ok(()) } -pub(super) async fn copy_overrides_folder( +pub async fn copy_overrides_folder( cluster: &clusters::Model, archive_path: &PathBuf, _ingress: &Option>,