Skip to content

Commit a2329b5

Browse files
committed
Fix cluster being stuck on downloading
1 parent 60e5356 commit a2329b5

File tree

4 files changed

+90
-37
lines changed

4 files changed

+90
-37
lines changed

apps/oneclient/frontend/src/bindings.gen.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,18 @@ export type VersionType =
303303
*/
304304
"old_beta"
305305

306-
const ARGS_MAP = { 'oneclient':'{"getClustersGroupedByMajor":[],"checkForUpdate":[],"getVersions":[],"installUpdate":[],"getBundlesFor":["cluster_id"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'debug':'{"getArch":[],"getBuildTimestamp":[],"isInDev":[],"getPlatform":[],"getType":[],"getOsVersion":[],"getPackageVersion":[],"getFamily":[],"openDevTools":[],"getLocale":[],"getGitCommitHash":[]}', 'events':'{"ingress":["event"],"message":["event"],"process":["event"]}', 'core':'{"killProcess":["pid"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getClusterById":["id"],"setDiscordRPCMessage":["message"],"fetchMinecraftProfile":["uuid"],"getLoadersForVersion":["mc_version"],"installModpack":["modpack","cluster_id"],"openMsaLogin":[],"createCluster":["options"],"updateClusterProfile":["name","profile"],"getPackage":["provider","slug"],"readSettings":[],"updateClusterById":["id","request"],"removeCape":["access_token"],"removeCluster":["id"],"getWorlds":["id"],"removeUser":["uuid"],"writeSettings":["setting"],"launchCluster":["id","uuid","search_for_java"],"getUsers":[],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"setDefaultUser":["uuid"],"getMultiplePackages":["provider","slugs"],"getClusters":[],"getProfileOrDefault":["name"],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"getUsersFromAuthor":["provider","author"],"getGlobalProfile":[],"getRunningProcessesByClusterId":["cluster_id"],"createSettingsProfile":["name"],"getLinkedPackages":["cluster_id"],"removePackage":["cluster_id","package_hash"],"fetchLoggedInProfile":["access_token"],"changeSkin":["access_token","skin_url","skin_variant"],"convertUsernameUUID":["username_uuid"],"getDefaultUser":["fallback"],"searchPackages":["provider","query"],"getPackageBody":["provider","body"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getLogByName":["id","name"],"changeCape":["access_token","cape_uuid"],"getScreenshots":["id"],"getGameVersions":[],"open":["input"],"getUser":["uuid"],"isClusterRunning":["cluster_id"],"getLogs":["id"],"getRunningProcesses":[]}' }
307-
export type Router = { 'events': { ingress: (event: IngressPayload) => Promise<void>,
308-
message: (event: MessagePayload) => Promise<void>,
309-
process: (event: ProcessPayload) => Promise<void> },
306+
const ARGS_MAP = { 'debug':'{"getPackageVersion":[],"getPlatform":[],"getLocale":[],"openDevTools":[],"getGitCommitHash":[],"getFamily":[],"getArch":[],"getType":[],"getOsVersion":[],"isInDev":[],"getBuildTimestamp":[]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'oneclient':'{"installUpdate":[],"getClustersGroupedByMajor":[],"getVersions":[],"getBundlesFor":["cluster_id"],"checkForUpdate":[]}', 'core':'{"readSettings":[],"getLinkedPackages":["cluster_id"],"createSettingsProfile":["name"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"],"getMultiplePackages":["provider","slugs"],"searchPackages":["provider","query"],"isClusterRunning":["cluster_id"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getUsersFromAuthor":["provider","author"],"getProfileOrDefault":["name"],"createCluster":["options"],"getLoadersForVersion":["mc_version"],"getGlobalProfile":[],"getWorlds":["id"],"fetchMinecraftProfile":["uuid"],"getLogs":["id"],"fetchLoggedInProfile":["access_token"],"changeCape":["access_token","cape_uuid"],"launchCluster":["id","uuid","search_for_java"],"getUsers":[],"getGameVersions":[],"removePackage":["cluster_id","package_hash"],"removeCape":["access_token"],"convertUsernameUUID":["username_uuid"],"getRunningProcesses":[],"removeCluster":["id"],"getRunningProcessesByClusterId":["cluster_id"],"getClusters":[],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"setDefaultUser":["uuid"],"getUser":["uuid"],"getLogByName":["id","name"],"changeSkin":["access_token","skin_url","skin_variant"],"removeUser":["uuid"],"getScreenshots":["id"],"setClusterStage":["id","stage"],"setDiscordRPCMessage":["message"],"open":["input"],"updateClusterById":["id","request"],"installModpack":["modpack","cluster_id"],"getPackage":["provider","slug"],"getDefaultUser":["fallback"],"openMsaLogin":[],"writeSettings":["setting"],"getClusterById":["id"],"killProcess":["pid"],"updateClusterProfile":["name","profile"],"getPackageBody":["provider","body"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"]}', 'events':'{"message":["event"],"process":["event"],"ingress":["event"]}' }
307+
export type Router = { 'debug': { openDevTools: () => Promise<void>,
308+
isInDev: () => Promise<boolean>,
309+
getArch: () => Promise<string>,
310+
getFamily: () => Promise<string>,
311+
getLocale: () => Promise<string | null>,
312+
getType: () => Promise<string>,
313+
getPlatform: () => Promise<string>,
314+
getOsVersion: () => Promise<string>,
315+
getGitCommitHash: () => Promise<string>,
316+
getBuildTimestamp: () => Promise<string>,
317+
getPackageVersion: () => Promise<string> },
310318
'oneclient': { getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
311319
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
312320
getVersions: () => Promise<OnlineClusterManifest>,
@@ -318,6 +326,7 @@ removeCluster: (id: number) => Promise<null>,
318326
createCluster: (options: CreateCluster) => Promise<ClusterModel>,
319327
launchCluster: (id: number, uuid: string | null, searchForJava: boolean | null) => Promise<null>,
320328
updateClusterById: (id: number, request: ClusterUpdate) => Promise<null>,
329+
setClusterStage: (id: number, stage: ClusterStage) => Promise<null>,
321330
getScreenshots: (id: number) => Promise<string[]>,
322331
getWorlds: (id: number) => Promise<string[]>,
323332
getLogs: (id: number) => Promise<string[]>,
@@ -360,19 +369,11 @@ removeCape: (accessToken: string) => Promise<MojangFullPlayerProfile>,
360369
convertUsernameUUID: (usernameUuid: string) => Promise<MowojangProfile>,
361370
setDiscordRPCMessage: (message: string) => Promise<null>,
362371
open: (input: string) => Promise<null> },
372+
'events': { ingress: (event: IngressPayload) => Promise<void>,
373+
message: (event: MessagePayload) => Promise<void>,
374+
process: (event: ProcessPayload) => Promise<void> },
363375
'folders': { fromCluster: (folderName: string) => Promise<string>,
364-
openCluster: (folderName: string) => Promise<null> },
365-
'debug': { openDevTools: () => Promise<void>,
366-
isInDev: () => Promise<boolean>,
367-
getArch: () => Promise<string>,
368-
getFamily: () => Promise<string>,
369-
getLocale: () => Promise<string | null>,
370-
getType: () => Promise<string>,
371-
getPlatform: () => Promise<string>,
372-
getOsVersion: () => Promise<string>,
373-
getGitCommitHash: () => Promise<string>,
374-
getBuildTimestamp: () => Promise<string>,
375-
getPackageVersion: () => Promise<string> } };
376+
openCluster: (folderName: string) => Promise<null> } };
376377

377378

378379
export type { InferCommandOutput }

apps/oneclient/frontend/src/components/LaunchButton.tsx

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export function LaunchButton({
6565
}: LaunchButtonProps) {
6666
const { data: currentAccount } = useCommandSuspense(['getDefaultUser'], () => bindings.core.getDefaultUser(true));
6767
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
68-
const launchCluster = useLaunchCluster(cluster.id);
68+
const { launch: launchCluster, showDownloadWarning, setShowDownloadWarning, forceLaunch } = useLaunchCluster(cluster.id);
6969
const isRunning = useIsRunning(cluster.id);
7070

7171
const [reason, setReason] = useState<'account' | 'packages' | 'kill' | null>(null);
@@ -85,21 +85,44 @@ export function LaunchButton({
8585
};
8686

8787
return (
88-
<Overlay.Trigger isOpen={reason !== null} onOpenChange={open => !open && setReason(null)}>
89-
<Button
90-
className={launchButtonVariants({ isRunning, className })}
91-
isDisabled={isDisabled}
92-
onPress={launch}
93-
{...rest}
94-
>
95-
{isRunning ? 'Running' : 'Launch'}
96-
</Button>
88+
<>
89+
<Overlay.Trigger isOpen={reason !== null} onOpenChange={open => !open && setReason(null)}>
90+
<Button
91+
className={launchButtonVariants({ isRunning, className })}
92+
isDisabled={isDisabled}
93+
onPress={launch}
94+
{...rest}
95+
>
96+
{isRunning ? 'Running' : 'Launch'}
97+
</Button>
9798

98-
<Overlay>
99-
{reason === 'kill' && <KillMinecraft setOpen={() => setReason(null)} />}
100-
{reason === 'packages' && <PromptForOnboarding cluster={cluster} launch={launch} setSkipPackagesCheck={setSkipPackagesCheck} />}
101-
{reason === 'account' && <NoAccountPopup />}
99+
<Overlay>
100+
{reason === 'kill' && <KillMinecraft setOpen={() => setReason(null)} />}
101+
{reason === 'packages' && <PromptForOnboarding cluster={cluster} launch={launch} setSkipPackagesCheck={setSkipPackagesCheck} />}
102+
{reason === 'account' && <NoAccountPopup />}
103+
</Overlay>
104+
</Overlay.Trigger>
105+
106+
<Overlay isOpen={showDownloadWarning} onOpenChange={setShowDownloadWarning}>
107+
<Overlay.Dialog>
108+
<Overlay.Title>Cluster is downloading</Overlay.Title>
109+
<div className="flex flex-col items-center">
110+
<p className="max-w-sm text-fg-secondary">The cluster is currently downloading. Launching it now might cause issues or corruption. Are you sure you want to proceed?</p>
111+
</div>
112+
<Overlay.Buttons
113+
buttons={[
114+
{ color: 'secondary', key: 'Cancel', children: 'Cancel', size: 'normal', onClick: () => setShowDownloadWarning(false) },
115+
{
116+
color: 'primary',
117+
key: 'Proceed',
118+
children: 'Proceed Anyways',
119+
size: 'normal',
120+
onClick: forceLaunch,
121+
},
122+
]}
123+
/>
124+
</Overlay.Dialog>
102125
</Overlay>
103-
</Overlay.Trigger>
126+
</>
104127
);
105128
}

apps/oneclient/frontend/src/hooks/useLaunchCluster.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ import { bindings } from '@/main';
22
import { toast } from '@/utils/toast';
33
import { getMessageFromError, isLauncherError } from '@onelauncher/common';
44
import { useNavigate } from '@tanstack/react-router';
5-
import { useCallback } from 'react';
5+
import { useCallback, useState } from 'react';
66

7-
export function useLaunchCluster(): (clusterId: number | undefined | null) => void;
8-
export function useLaunchCluster(clusterId: number | undefined | null): () => void;
7+
export function useLaunchCluster(): { launch: (clusterId: number | undefined | null) => void; showDownloadWarning: boolean; setShowDownloadWarning: (show: boolean) => void; forceLaunch: () => void };
8+
export function useLaunchCluster(clusterId: number | undefined | null): { launch: () => void; showDownloadWarning: boolean; setShowDownloadWarning: (show: boolean) => void; forceLaunch: () => void };
99

1010
export function useLaunchCluster(clusterId?: number | undefined | null) {
1111
const navigate = useNavigate();
12+
const [showDownloadWarning, setShowDownloadWarning] = useState(false);
13+
const [lastAttemptedId, setLastAttemptedId] = useState<number | null>(null);
1214

1315
const launch = useCallback(
1416
async (id?: number | null) => {
@@ -17,6 +19,8 @@ export function useLaunchCluster(clusterId?: number | undefined | null) {
1719
if (!targetId)
1820
return;
1921

22+
setLastAttemptedId(targetId);
23+
2024
try {
2125
await bindings.core.launchCluster(targetId, null, false);
2226

@@ -25,7 +29,12 @@ export function useLaunchCluster(clusterId?: number | undefined | null) {
2529
search: { clusterId: targetId },
2630
});
2731
}
28-
catch (err) {
32+
catch (err: any) {
33+
if (err.type === 'ClusterError' && err.data.type === 'ClusterDownloading') {
34+
setShowDownloadWarning(true);
35+
return;
36+
}
37+
2938
if (isLauncherError(err))
3039
toast({
3140
type: 'error',
@@ -37,5 +46,14 @@ export function useLaunchCluster(clusterId?: number | undefined | null) {
3746
[clusterId, navigate],
3847
);
3948

40-
return launch;
49+
const forceLaunch = useCallback(async () => {
50+
if (!lastAttemptedId)
51+
return;
52+
// @ts-ignore - ignoring
53+
await bindings.core.setClusterStage(lastAttemptedId, 'notready');
54+
setShowDownloadWarning(false);
55+
launch(lastAttemptedId);
56+
}, [lastAttemptedId, launch]);
57+
58+
return { launch, showDownloadWarning, setShowDownloadWarning, forceLaunch };
4159
}

packages/core/src/api/tauri/commands.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::store::processes::Process;
99
use crate::store::{Settings, State};
1010
use crate::utils::pagination::Paginated;
1111
use interpulse::api::minecraft::Version;
12+
use onelauncher_entity::cluster_stage::ClusterStage;
1213
use onelauncher_entity::icon::Icon;
1314
use onelauncher_entity::loader::GameLoader;
1415
use onelauncher_entity::package::Provider;
@@ -51,6 +52,9 @@ pub trait TauriLauncherApi {
5152
#[taurpc(alias = "updateClusterById")]
5253
async fn update_cluster_by_id(id: ClusterId, request: ClusterUpdate) -> LauncherResult<()>;
5354

55+
#[taurpc(alias = "setClusterStage")]
56+
async fn set_cluster_stage(id: ClusterId, stage: ClusterStage) -> LauncherResult<()>;
57+
5458
#[taurpc(alias = "getScreenshots")]
5559
async fn get_screenshots(id: ClusterId) -> LauncherResult<Vec<String>>;
5660

@@ -407,7 +411,14 @@ impl TauriLauncherApi for TauriLauncherApiImpl {
407411

408412
Ok(())
409413
}
410-
414+
async fn set_cluster_stage(self, id: ClusterId, stage: ClusterStage) -> LauncherResult<()> {
415+
api::cluster::dao::update_cluster_by_id(id, |mut model: ClusterPartial| async move {
416+
model.stage = Set(stage);
417+
Ok(model)
418+
})
419+
.await?;
420+
Ok(())
421+
}
411422
async fn get_screenshots(self, id: ClusterId) -> LauncherResult<Vec<String>> {
412423
let cluster = api::cluster::dao::get_cluster_by_id(id)
413424
.await?

0 commit comments

Comments
 (0)