Skip to content

Commit

Permalink
Fix issues with mod download/install progress tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
VilppeRiskidev committed Feb 3, 2025
1 parent c359b28 commit d03f65a
Show file tree
Hide file tree
Showing 7 changed files with 56 additions and 50 deletions.
6 changes: 3 additions & 3 deletions src/components/mixins/DownloadMixin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default class DownloadMixin extends Vue {
throw err;
}
} else if (status === StatusEnum.PENDING || status === StatusEnum.SUCCESS) {
store.commit('download/updateDownload', {assignId, downloadProgress, modName});
store.commit('download/updateDownload', {assignId, modName, downloadProgress});
}
}
Expand All @@ -85,8 +85,8 @@ export default class DownloadMixin extends Vue {
assignId: number
): Promise<void> {
await ProfileModList.requestLock(async () => {
const modList: ManifestV2[] = await installModsToProfile(downloadedMods, profile, undefined,(status, progress) => {
this.$store.commit('download/updateDownload', {assignId, installProgress: progress});
const modList: ManifestV2[] = await installModsToProfile(downloadedMods, profile, undefined,(status, modName, installProgress) => {
this.$store.commit('download/updateDownload', {assignId, modName, installProgress});
});
await this.$store.dispatch('profile/updateModList', modList);
throwForR2Error(await ConflictManagementProvider.instance.resolveConflicts(modList, profile));
Expand Down
14 changes: 12 additions & 2 deletions src/components/views/DownloadModModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,21 @@ import ProfileModList from '../../r2mm/mods/ProfileModList';
this.profile.asImmutableProfile(),
tsCombo,
this.ignoreCache,
(downloadProgress, modName, status, err) => { DownloadMixin.downloadProgressCallback(this.$store, assignId, downloadProgress, modName, status, err, () => this.setIsModProgressModalOpen(false)); }
(downloadProgress, modName, status, err) => {
DownloadMixin.downloadProgressCallback(
this.$store,
assignId,
downloadProgress,
modName,
status,
err,
() => this.setIsModProgressModalOpen(false)
);
}
);
} catch (e) {
this.setIsModProgressModalOpen(false);
this.$store.commit('download/updateDownload', { assignId: assignId, failed: true });
this.$store.commit('download/updateDownload', { assignId, failed: true });
this.$store.commit('error/handleError', R2Error.fromThrownValue(e));
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/UpdateAllInstalledModsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default class UpdateAllInstalledModsModal extends mixins(DownloadMixin)
);
this.setIsModProgressModalOpen(true);
ThunderstoreDownloaderProvider.instance.downloadLatestOfAll(modsWithUpdates, this.ignoreCache, (progress: number, modName: string, status: number, err: R2Error | null) => {
ThunderstoreDownloaderProvider.instance.downloadLatestOfAll(modsWithUpdates, this.ignoreCache, (downloadProgress: number, modName: string, status: number, err: R2Error | null) => {
try {
if (status === StatusEnum.FAILURE) {
this.setIsModProgressModalOpen(false);
Expand All @@ -59,7 +59,7 @@ export default class UpdateAllInstalledModsModal extends mixins(DownloadMixin)
throw err;
}
} else if (status === StatusEnum.PENDING) {
this.$store.commit('download/updateDownload', {assignId, downloadProgress: progress, modName});
this.$store.commit('download/updateDownload', {assignId, modName, downloadProgress});
}
} catch (e) {
this.$store.commit('error/handleError', R2Error.fromThrownValue(e));
Expand Down
38 changes: 17 additions & 21 deletions src/pages/DownloadMonitor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,26 @@
</div>

<div v-if="downloadObject.installProgress < 100" class="col">
<p>Installing:</p>
<p v-if="downloadObject.downloadProgress < 100">Installing: waiting for download to finish</p>
<p v-else>{{Math.min(Math.floor(downloadObject.installProgress), 100)}}% complete</p>
<Progress
:max='100'
:value='downloadObject.installProgress'
:className="['is-info']"
/>
<div v-if="downloadObject.downloadProgress < 100">
<p>Installing:</p>
<p v-if="downloadObject.downloadProgress < 100">Waiting for download to finish</p>
<Progress
:max='100'
:className="['is-info']"
/>
</div>
<div v-else>
<p>Installing: {{ downloadObject.modName }}</p>
<p>{{Math.min(Math.floor(downloadObject.installProgress), 100)}}% complete</p>
<Progress
:max='100'
:value='downloadObject.installProgress'
:className="['is-info']"
/>
</div>
</div>

</div>

<div v-else-if="downloadObject.failed">
<p>{{downloadObject.failed ? "Download failed" : `${Math.min(Math.floor(downloadObject.installProgress), 100)}% complete`}}</p>
<Progress
:max='100'
:value='100'
:className="['is-danger']"
/>
</div>

<div v-else>
<p>Status unknown</p>
</div>
</div>
</div>
</div>
Expand Down
29 changes: 14 additions & 15 deletions src/r2mm/downloading/BetterThunderstoreDownloader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,40 +98,39 @@ export default class BetterThunderstoreDownloader extends ThunderstoreDownloader
const dependencies = await this.getDependenciesWithCorrectVersions(combo, modList);
const allModsToDownload = [...dependencies, combo];

let modInProgressName = combo.getMod().getName();
let downloadCount = 0;
const singleModProgressCallback = (modName: string, progress: number, status: number, err: R2Error | null) => {
const singleModProgressCallback = (downloadProgress: number, status: number, err: R2Error | null) => {
if (status === StatusEnum.FAILURE) {
throw err;
}

let totalProgress: number;
let totalDownloadProgress: number;
if (status === StatusEnum.PENDING) {
totalProgress = this.generateProgressPercentage(progress, downloadCount, allModsToDownload.length);
totalDownloadProgress = this.generateProgressPercentage(downloadProgress, downloadCount, allModsToDownload.length);
} else if (status === StatusEnum.SUCCESS) {
totalProgress = this.generateProgressPercentage(100, downloadCount, allModsToDownload.length);
totalDownloadProgress = this.generateProgressPercentage(100, downloadCount, allModsToDownload.length);
downloadCount += 1;
} else {
console.error(`Ignore unknown status code "${status}"`);
return;
}
totalProgressCallback(totalProgress, modName, status, err);
totalProgressCallback(Math.round(totalDownloadProgress), modInProgressName, status, err);
}

for (const combo of allModsToDownload) {
if (!ignoreCache && await this.isVersionAlreadyDownloaded(combo)) {
totalProgressCallback(100, combo.getMod().getName(), StatusEnum.SUCCESS, null);
for (const comboInProgress of allModsToDownload) {
modInProgressName = comboInProgress.getMod().getName();

if (!ignoreCache && await this.isVersionAlreadyDownloaded(comboInProgress)) {
totalProgressCallback(100, modInProgressName, StatusEnum.SUCCESS, null);
continue;
}

try {
const response = await this._downloadCombo(combo, (progress, status, err) => {
singleModProgressCallback(combo.getMod().getName(), progress, status, err)
});
await this._saveDownloadResponse(response, combo, (progress, status, err) => {
singleModProgressCallback(combo.getMod().getName(), progress, status, err)
});
const response = await this._downloadCombo(comboInProgress, singleModProgressCallback);
await this._saveDownloadResponse(response, comboInProgress, singleModProgressCallback);
} catch(e) {
throw R2Error.fromThrownValue(e, `Failed to download mod ${combo.getVersion().getFullName()}`);
throw R2Error.fromThrownValue(e, `Failed to download mod ${comboInProgress.getVersion().getFullName()}`);
}
}
return allModsToDownload;
Expand Down
4 changes: 2 additions & 2 deletions src/store/modules/DownloadModule.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { ActionTree, GetterTree } from "vuex";

import { State as RootState } from "../../store";
import R2Error from "../../model/errors/R2Error";

interface DownloadProgress {
assignId: number;
Expand All @@ -14,7 +13,8 @@ interface DownloadProgress {

interface UpdateObject {
assignId: number;
progress?: number;
downloadProgress?: number;
installProgress?: number;
modName?: string;
failed?: boolean;
}
Expand Down
11 changes: 6 additions & 5 deletions src/utils/ProfileUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export async function installModsToProfile(
comboList: ThunderstoreCombo[],
profile: ImmutableProfile,
disabledModsOverride?: string[],
progressCallback?: (status: string, progress?: number) => void
progressCallback?: (status: string, modName?: string, progress?: number) => void
): Promise<ManifestV2[]> {
const profileMods = await ProfileModList.getModList(profile);
if (profileMods instanceof R2Error) {
Expand All @@ -75,10 +75,12 @@ export async function installModsToProfile(
const installedVersions = profileMods.map((m) => m.getDependencyString());
const disabledMods = disabledModsOverride || profileMods.filter((m) => !m.isEnabled()).map((m) => m.getName());
let currentMod;

let modName = 'Unknown';
try {
for (const [index, comboMod] of comboList.entries()) {
currentMod = comboMod;
modName = currentMod.getMod().getFullName();

const manifestMod = new ManifestV2().fromThunderstoreMod(comboMod.getMod(), comboMod.getVersion());

if (installedVersions.includes(manifestMod.getDependencyString())) {
Expand Down Expand Up @@ -106,12 +108,11 @@ export async function installModsToProfile(

if (typeof progressCallback === "function") {
const progress = Math.floor(((index + 1) / comboList.length) * 100);
progressCallback(`Copying mods to profile: ${progress}%`, progress);
progressCallback(`Copying mods to profile: ${progress}%`, modName, progress);
}
}
} catch (e) {
const originalError = R2Error.fromThrownValue(e);
const modName = currentMod ? currentMod.getMod().getFullName() : 'Unknown';
throw new R2Error(
`Failed to install mod [${modName}] to profile`,
'All mods/dependencies might not be installed properly. Please try again.',
Expand All @@ -121,7 +122,7 @@ export async function installModsToProfile(

throwForR2Error(await ProfileModList.saveModList(profile, profileMods));
if (typeof progressCallback === "function") {
progressCallback("Copying mods to profile: 100%", 100);
progressCallback("Copying mods to profile: 100%", modName, 100);
}
return profileMods;
}
Expand Down

0 comments on commit d03f65a

Please sign in to comment.