Extract bundle overrides before downloading mods
This commit is contained in:
parent
e745c75cc8
commit
fe0b1eed06
3 changed files with 68 additions and 80 deletions
|
|
@ -303,11 +303,8 @@ export type VersionType =
|
|||
*/
|
||||
"old_beta"
|
||||
|
||||
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<void>,
|
||||
message: (event: MessagePayload) => Promise<void>,
|
||||
process: (event: ProcessPayload) => Promise<void> },
|
||||
'folders': { fromCluster: (folderName: string) => Promise<string>,
|
||||
const ARGS_MAP = { '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":[]}', '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"]}', 'oneclient':'{"getVersions":[],"installUpdate":[],"getClustersGroupedByMajor":[],"extractBundleOverrides":["bundle_path","cluster_id"],"checkForUpdate":[],"getBundlesFor":["cluster_id"]}' }
|
||||
export type Router = { 'folders': { fromCluster: (folderName: string) => Promise<string>,
|
||||
openCluster: (folderName: string) => Promise<null> },
|
||||
'core': { getClusters: () => Promise<ClusterModel[]>,
|
||||
getClusterById: (id: number) => Promise<ClusterModel | null>,
|
||||
|
|
@ -360,12 +357,6 @@ removeCape: (accessToken: string) => Promise<MojangFullPlayerProfile>,
|
|||
convertUsernameUUID: (usernameUuid: string) => Promise<MowojangProfile>,
|
||||
setDiscordRPCMessage: (message: string) => Promise<null>,
|
||||
open: (input: string) => Promise<null> },
|
||||
'oneclient': { getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
|
||||
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
|
||||
getVersions: () => Promise<OnlineClusterManifest>,
|
||||
extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise<null>,
|
||||
checkForUpdate: () => Promise<Update | null>,
|
||||
installUpdate: () => Promise<null> },
|
||||
'debug': { openDevTools: () => Promise<void>,
|
||||
isInDev: () => Promise<boolean>,
|
||||
getArch: () => Promise<string>,
|
||||
|
|
@ -376,7 +367,16 @@ getPlatform: () => Promise<string>,
|
|||
getOsVersion: () => Promise<string>,
|
||||
getGitCommitHash: () => Promise<string>,
|
||||
getBuildTimestamp: () => Promise<string>,
|
||||
getPackageVersion: () => Promise<string> } };
|
||||
getPackageVersion: () => Promise<string> },
|
||||
'events': { ingress: (event: IngressPayload) => Promise<void>,
|
||||
message: (event: MessagePayload) => Promise<void>,
|
||||
process: (event: ProcessPayload) => Promise<void> },
|
||||
'oneclient': { getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
|
||||
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
|
||||
getVersions: () => Promise<OnlineClusterManifest>,
|
||||
extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise<null>,
|
||||
checkForUpdate: () => Promise<Update | null>,
|
||||
installUpdate: () => Promise<null> } };
|
||||
|
||||
|
||||
export type { InferCommandOutput }
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import type { ExternalPackage, ManagedVersionDependency, ModpackArchive, ModpackFile, Provider } from '@/bindings.gen';
|
||||
import type { ExternalPackage, ManagedVersionDependency, 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, useRef, useState } from 'react';
|
||||
import { useEffect, useImperativeHandle, 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, bundlesPerCluster, ref }: { modsPerCluster: Record<string, Array<ModpackFile>>; bundlesPerCluster?: Record<string, Array<ModpackArchive>>; ref: React.Ref<DownloadModsRef> }) {
|
||||
export function DownloadMods({ modsPerCluster, ref }: { modsPerCluster: Record<string, Array<ModpackFile>>; ref: React.Ref<DownloadModsRef> }) {
|
||||
const navigate = useNavigate();
|
||||
const [isOpen, setOpen] = useState<boolean>(false);
|
||||
const [mods, setMods] = useState<ModDataArray>([]);
|
||||
|
|
@ -89,7 +89,7 @@ export function DownloadMods({ modsPerCluster, bundlesPerCluster, ref }: { modsP
|
|||
<Button className="mb-4" isDisabled={mods.length === 0} onPress={() => setOpen(prev => !prev)}>Download Mods</Button>
|
||||
|
||||
<Overlay isDismissable={false} isOpen={isOpen}>
|
||||
<DownloadingMods bundlesPerCluster={bundlesPerCluster} mods={mods} nextPath={nextPath} setOpen={setOpen} />
|
||||
<DownloadingMods mods={mods} nextPath={nextPath} setOpen={setOpen} />
|
||||
</Overlay>
|
||||
</DialogTrigger>
|
||||
);
|
||||
|
|
@ -106,12 +106,10 @@ function downloadModsParallel(items: ModDataArray, limit: number, fn: (mod: ModD
|
|||
return Promise.all(workers);
|
||||
}
|
||||
|
||||
function DownloadingMods({ mods, setOpen, nextPath, bundlesPerCluster }: { mods: ModDataArray; setOpen: React.Dispatch<React.SetStateAction<boolean>>; nextPath: string; bundlesPerCluster?: Record<string, Array<ModpackArchive>> }) {
|
||||
function DownloadingMods({ mods, setOpen, nextPath }: { mods: ModDataArray; setOpen: React.Dispatch<React.SetStateAction<boolean>>; nextPath: string }) {
|
||||
const navigate = useNavigate();
|
||||
const [downloadedMods, setDownloadedMods] = useState(0);
|
||||
const [modName, setModName] = useState<string | null>(null);
|
||||
const [allDone, setAllDone] = useState(false);
|
||||
const hasStarted = useRef(false);
|
||||
const download = useCommandMut(async (mod: ModData) => {
|
||||
if (isManagedMod(mod)) {
|
||||
if (mod.dependencies.length > 0)
|
||||
|
|
@ -135,72 +133,37 @@ function DownloadingMods({ mods, setOpen, nextPath, bundlesPerCluster }: { mods:
|
|||
let useParallelModDownloading = setting('parallel_mod_downloading');
|
||||
|
||||
useEffect(() => {
|
||||
if (hasStarted.current)
|
||||
return;
|
||||
hasStarted.current = true;
|
||||
|
||||
const downloadAll = async () => {
|
||||
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);
|
||||
}
|
||||
if (useParallelModDownloading)
|
||||
await downloadModsParallel(mods, 10, async (mod) => {
|
||||
setModName(mod.name);
|
||||
try {
|
||||
await download.mutateAsync(mod);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
setDownloadedMods(prev => prev + 1);
|
||||
}
|
||||
}); else
|
||||
for (const mod of mods) {
|
||||
setModName(mod.name);
|
||||
try {
|
||||
await download.mutateAsync(mod);
|
||||
}
|
||||
finally {
|
||||
setDownloadedMods(prev => prev + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.error('Error during mod download:', e);
|
||||
}
|
||||
finally {
|
||||
setAllDone(true);
|
||||
}
|
||||
};
|
||||
|
||||
downloadAll();
|
||||
}, [mods]);
|
||||
|
||||
useEffect(() => {
|
||||
if (allDone) {
|
||||
if (downloadedMods >= mods.length) {
|
||||
setOpen(false);
|
||||
navigate({ to: nextPath });
|
||||
}
|
||||
}, [allDone, navigate, nextPath, setOpen]);
|
||||
}, [downloadedMods, mods, navigate, nextPath, setOpen]);
|
||||
|
||||
return (
|
||||
<Overlay.Dialog isDismissable={false}>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Button } from '@onelauncher/common/components';
|
|||
import { createFileRoute } from '@tanstack/react-router';
|
||||
import { DotsVerticalIcon } from '@untitled-theme/icons-react';
|
||||
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
import { useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||
import { Button as AriaButton } from 'react-aria-components';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
|
|
@ -62,13 +62,38 @@ function RouteComponent() {
|
|||
);
|
||||
|
||||
const bundlesPerCluster = useMemo(() => {
|
||||
return clusters.reduce((acc, cluster, i) => {
|
||||
acc[cluster.id] = bundleQueries[i];
|
||||
return acc;
|
||||
}, {} as Record<string, Array<ModpackArchive>>);
|
||||
}, [clusters, bundleQueries]);
|
||||
const result: Record<number, Array<ModpackArchive>> = {};
|
||||
clusters.forEach((cluster, i) => {
|
||||
const selected = selectedClusters.some(sc => sc.mc_version === cluster.mc_version && sc.mc_loader === cluster.mc_loader);
|
||||
if (selected)
|
||||
result[cluster.id] = bundleQueries[i];
|
||||
});
|
||||
return result;
|
||||
}, [clusters, bundleQueries, selectedClusters]);
|
||||
|
||||
const downloadModsRef = useRef<DownloadModsRef>(null);
|
||||
const wrappedRef = useRef<DownloadModsRef>(null);
|
||||
|
||||
useImperativeHandle(wrappedRef, () => ({
|
||||
async openDownloadDialog(nextPath?: string) {
|
||||
// Extract overrides from all enabled bundles before downloading mods
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then delegate to the actual mod download dialog
|
||||
downloadModsRef.current?.openDownloadDialog(nextPath);
|
||||
},
|
||||
}), [bundlesPerCluster]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -89,13 +114,13 @@ function RouteComponent() {
|
|||
</div>
|
||||
|
||||
<div className="hidden">
|
||||
<DownloadMods bundlesPerCluster={bundlesPerCluster} modsPerCluster={modsPerCluster} ref={downloadModsRef} />
|
||||
<DownloadMods modsPerCluster={modsPerCluster} ref={downloadModsRef} />
|
||||
</div>
|
||||
</div>
|
||||
</OverlayScrollbarsComponent>
|
||||
</div>
|
||||
</div>
|
||||
<OnboardingNavigation disableNext={selectedClusters.length === 0} ref={downloadModsRef} />
|
||||
<OnboardingNavigation disableNext={selectedClusters.length === 0} ref={wrappedRef} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue