diff --git a/src/equicordplugins/questify/index.tsx b/src/equicordplugins/questify/index.tsx index 6ab808632..0f98bc04f 100644 --- a/src/equicordplugins/questify/index.tsx +++ b/src/equicordplugins/questify/index.tsx @@ -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; const patchedMobileQuests = new Set(); -export const activeQuestIntervals = new Map(); +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); diff --git a/src/equicordplugins/questify/settings.tsx b/src/equicordplugins/questify/settings.tsx index eebed79bd..2169ed01f 100644 --- a/src/equicordplugins/questify/settings.tsx +++ b/src/equicordplugins/questify/settings.tsx @@ -1969,5 +1969,11 @@ export const settings = definePluginSettings({ description: "An array of Quest IDs that are ignored.", default: {} as Record, 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, + }, }); diff --git a/src/equicordplugins/questify/utils/components.tsx b/src/equicordplugins/questify/utils/components.tsx index 1f363a24b..73b265d54 100644 --- a/src/equicordplugins/questify/utils/components.tsx +++ b/src/equicordplugins/questify/utils/components.tsx @@ -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 { + 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,