Questify: Resume auto complete on reload. (#739)

This commit is contained in:
Etorix 2026-02-06 17:40:51 -08:00 • committed by GitHub
parent c9388a94c1
commit fe51bc22a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 4 deletions

View file

@ -9,7 +9,7 @@ import "./styles.css";
import { showNotification } from "@api/Notifications";
import { plugins } from "@api/PluginManager";
import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList";
import { migratePluginToSettings } from "@api/Settings";
import { migratePluginToSettings, Settings } from "@api/Settings";
import { ErrorBoundary, openPluginModal } from "@components/index";
import { EquicordDevs } from "@utils/constants";
import { copyToClipboard } from "@utils/index";
@ -19,12 +19,13 @@ import { ContextMenuApi, Menu, NavigationRouter, RestAPI, useEffect, useState }
import { JSX } from "react";
import { addIgnoredQuest, addRerenderCallback, autoFetchCompatible, fetchAndAlertQuests, maximumAutoFetchIntervalValue, minimumAutoFetchIntervalValue, questIsIgnored, removeIgnoredQuest, rerenderQuests, settings, startAutoFetchingQuests, stopAutoFetchingQuests, validateAndOverwriteIgnoredQuests } from "./settings";
import { ExcludedQuestMap, GuildlessServerListItem, Quest, QuestIcon, QuestMap, QuestStatus, QuestTaskType, RGB } from "./utils/components";
import { ActiveQuestIntervalsMap, ExcludedQuestMap, GuildlessServerListItem, Quest, QuestIcon, QuestMap, QuestStatus, QuestTaskType, RGB } from "./utils/components";
import { adjustRGB, decimalToRGB, fetchAndDispatchQuests, formatLowerBadge, getFormattedNow, getIgnoredQuestIDs, getQuestProgress, getQuestStatus, getQuestTarget, getQuestTask, isDarkish, leftClick, middleClick, normalizeQuestName, q, QuestifyLogger, questPath, QuestsStore, refreshQuest, reportPlayGameQuestProgress, reportVideoQuestProgress, rightClick, setIgnoredQuestIDs, videoQuestLeeway, waitUntilEnrolled } from "./utils/misc";
let initialQuestDataFetched = false;
const QuestifyNative = VencordNative.pluginHelpers.Questify as PluginNative<typeof import("./native")>;
const patchedMobileQuests = new Set<string>();
export const activeQuestIntervals = new Map<string, { progressTimeout: NodeJS.Timeout; rerenderTimeout: NodeJS.Timeout; progress: number; type: string; }>();
export const activeQuestIntervals = new ActiveQuestIntervalsMap();
function questMenuUnignoreAllClicked(): void {
validateAndOverwriteIgnoredQuests([]);
@ -1676,6 +1677,7 @@ export default definePlugin({
},
QUESTS_FETCH_CURRENT_QUESTS_SUCCESS(data) {
initialQuestDataFetched = true;
const source = data.source ? ` [${data.source}]` : "";
QuestifyLogger.info(`[${getFormattedNow()}] [QUESTS_FETCH_CURRENT_QUESTS_SUCCESS]${source}\n`, data);
validateAndOverwriteIgnoredQuests(undefined, data.quests);
@ -1745,12 +1747,52 @@ export default definePlugin({
if (!!intervalValid && autoFetchCompatible()) {
startAutoFetchingQuests();
}
const wasReload = window?.navigation?.activation?.navigationType === "reload";
const maybeResumable = !(settings.store.disableQuestsEverything || settings.store.disableQuestsFetchingQuests);
if (!wasReload || !maybeResumable) {
settings.store.resumeQuestIDs = settings.def.resumeQuestIDs.default;
return;
}
onceReady.then(() => {
const interval = setInterval(() => {
if (initialQuestDataFetched) {
clearInterval(interval);
const playResume = settings.store.resumeQuestIDs.play.map(id => QuestsStore.getQuest(id)).filter(Boolean);
const watchResume = settings.store.resumeQuestIDs.watch.map(id => QuestsStore.getQuest(id)).filter(Boolean);
const achievementResume = settings.store.resumeQuestIDs.achievement.map(id => QuestsStore.getQuest(id)).filter(Boolean);
settings.store.resumeQuestIDs.play = playResume.map(quest => quest!.id);
settings.store.resumeQuestIDs.watch = watchResume.map(quest => quest!.id);
settings.store.resumeQuestIDs.achievement = achievementResume.map(quest => quest!.id);
if (!playResume.length && !watchResume.length && !achievementResume.length) {
return;
}
QuestifyLogger.info(`[${getFormattedNow()}] Resuming background completion for Quests:`, {
play: playResume.map(q => q.config.messages.questName),
watch: watchResume.map(q => q.config.messages.questName),
achievement: achievementResume.map(q => q.config.messages.questName)
});
[...playResume, ...watchResume, ...achievementResume].forEach(quest => quest && processQuestForAutoComplete(quest));
}
}, 100);
});
},
stop() {
removeServerListElement(ServerListRenderPosition.Above, this.renderQuestifyButton);
stopAutoFetchingQuests();
if (!Settings.plugins.Questify.enabled) {
settings.store.resumeQuestIDs = settings.def.resumeQuestIDs.default;
}
activeQuestIntervals.forEach((intervalData, questId) => {
clearInterval(intervalData.progressTimeout);
clearTimeout(intervalData.rerenderTimeout);

View file

@ -1969,5 +1969,11 @@ export const settings = definePluginSettings({
description: "An array of Quest IDs that are ignored.",
default: {} as Record<string, string[]>,
hidden: true,
}
},
resumeQuestIDs: {
type: OptionType.CUSTOM,
description: "An array of Quest IDs that are being auto-completed in the background.",
default: { "watch": [], "play": [], "achievement": [] } as Record<"watch" | "play" | "achievement", string[]>, // Type to Quest ID
hidden: true,
},
});

View file

@ -9,6 +9,7 @@ import { findComponentByCodeLazy } from "@webpack";
import { SearchableSelect, useState } from "@webpack/common";
import { JSX } from "react";
import { settings } from "../settings";
import { formatLowerBadge } from "./misc";
// GuildlessServerListItem's built-in pill does not support unread state.
@ -19,6 +20,19 @@ export const ServerListItemUpperBadgeComponent = findComponentByCodeLazy("{icon:
export const RadioGroup = findComponentByCodeLazy(",{label:", ",description:", ",required:", ",errorMessage:", ",children:");
export const QuestTile = findComponentByCodeLazy(".rowIndex,trackGuildAndChannelMetadata");
export class ActiveQuestIntervalsMap extends Map<string, { progressTimeout: NodeJS.Timeout; rerenderTimeout: NodeJS.Timeout; progress: number; type: string; }> {
set(key: string, value: { progressTimeout: NodeJS.Timeout; rerenderTimeout: NodeJS.Timeout; progress: number; type: string; }): this {
settings.store.resumeQuestIDs[value.type].push(key);
return super.set(key, value);
}
delete(key: string): boolean {
const types = Object.keys(settings.def.resumeQuestIDs.default);
for (const type of types) { settings.store.resumeQuestIDs[type] = settings.store.resumeQuestIDs[type].filter((id: string) => id !== key); }
return super.delete(key);
}
}
export enum QuestRewardType {
UNKNOWN = 0,
REWARD_CODE = 1,