diff --git a/src/equicordplugins/questCompleter/index.tsx b/src/equicordplugins/questCompleter/index.tsx index d474646b..24f08ba2 100644 --- a/src/equicordplugins/questCompleter/index.tsx +++ b/src/equicordplugins/questCompleter/index.tsx @@ -17,12 +17,195 @@ */ import { showNotification } from "@api/Notifications"; +import ErrorBoundary from "@components/ErrorBoundary"; import { Devs, EquicordDevs } from "@utils/constants"; import { getTheme, Theme } from "@utils/discord"; +import { classes } from "@utils/misc"; import definePlugin from "@utils/types"; -import { findByCode, findByProps } from "@webpack"; +import { findByCode, findByProps, findExportedComponentLazy } from "@webpack"; import { FluxDispatcher, Forms, RestAPI, Text, UserStore } from "@webpack/common"; +const HeaderBarIcon = findExportedComponentLazy("Icon", "Divider"); +const isApp = navigator.userAgent.includes("Electron/"); + +const QuestsIcon = () => props => ( + + + +); + +function ToolBarQuestsIcon() { + return ( + + + + ); +} + +function ToolBarHeader() { + return ( + + + + + ); +} + +async function openCompleteQuestUI() { + // check if user is sharing screen and there is someone that is watching the stream + const ApplicationStreamingStore = findByProps("getStreamerActiveStreamMetadata"); + const RunningGameStore = findByProps("getRunningGames"); + const ExperimentStore = findByProps("getGuildExperiments"); + const QuestsStore = findByProps("getQuest"); + const quest = [...QuestsStore.quests.values()].find(x => x.id !== "1248385850622869556" && x.userStatus?.enrolledAt && !x.userStatus?.completedAt && new Date(x.config.expiresAt).getTime() > Date.now()); + + if (!isApp) { + showNotification({ + title: "Quests Completer", + body: "This no longer works in browser. Use the desktop app!", + }); + } else if (!quest) { + showNotification({ + title: "Quests Completer", + body: "No Quests To Complete", + }); + } else { + const pid = Math.floor(Math.random() * 30000) + 1000; + const theme = getTheme() === Theme.Light + ? "light" + : "dark"; + + let applicationId, applicationName, secondsNeeded, secondsDone, canPlay, icon, questId; + if (quest.config.configVersion === 1) { + questId = quest.id; + applicationId = quest.config.applicationId; + applicationName = quest.config.applicationName; + secondsNeeded = quest.config.streamDurationRequirementMinutes * 60; + secondsDone = quest.userStatus?.streamProgressSeconds ?? 0; + icon = `https://cdn.discordapp.com/assets/quests/${questId}/${theme}/${quest.config.assets.gameTile}`; + canPlay = quest.config.variants.includes(2); + } else if (quest.config.configVersion === 2) { + questId = quest.id; + applicationId = quest.config.application.id; + applicationName = quest.config.application.name; + icon = `https://cdn.discordapp.com/assets/quests/${questId}/${theme}/${quest.config.assets.gameTile}`; + canPlay = ExperimentStore.getUserExperimentBucket("2024-04_quest_playtime_task") > 0 && quest.config.taskConfig.tasks.PLAY_ON_DESKTOP; + const taskName = canPlay ? "PLAY_ON_DESKTOP" : "STREAM_ON_DESKTOP"; + secondsNeeded = quest.config.taskConfig.tasks[taskName]?.target; + secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0; + } + if (canPlay) { + await RestAPI.get({ url: `/applications/public?application_ids=${applicationId}` }).then(res => { + const appData = res.body[0]; + const exeName = appData.executables.find(x => x.os === "win32").name.replace(">", ""); + + const games = RunningGameStore.getRunningGames(); + const fakeGame = { + cmdLine: `C:\\Program Files\\${appData.name}\\${exeName}`, + exeName, + exePath: `c:/program files/${appData.name.toLowerCase()}/${exeName}`, + hidden: false, + isLauncher: false, + id: applicationId, + name: appData.name, + pid: pid, + pidPath: [pid], + processName: appData.name, + start: Date.now(), + }; + games.push(fakeGame); + FluxDispatcher.dispatch({ type: "RUNNING_GAMES_CHANGE", removed: [], added: [fakeGame], games: games }); + + const fn = data => { + const progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value); + showNotification({ + title: `${applicationName} - Quests Completer`, + body: `Current progress: ${progress}/${secondsNeeded} seconds.`, + icon: icon, + }); + + if (progress >= secondsNeeded) { + showNotification({ + title: `${applicationName} - Quests Completer`, + body: "Quest Completed.", + icon: icon, + }); + + const idx = games.indexOf(fakeGame); + if (idx > -1) { + games.splice(idx, 1); + FluxDispatcher.dispatch({ type: "RUNNING_GAMES_CHANGE", removed: [fakeGame], added: [], games: [] }); + } + FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); + } + }; + FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); + }); + } else { + const stream = ApplicationStreamingStore.getAnyStreamForUser(UserStore.getCurrentUser()?.id); + if (!stream) { + showNotification({ + title: "You're not streaming - Quests Completer", + body: `${applicationName} requires you to be streaming.`, + icon: icon, + }); + } + const realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata; + ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({ + id: applicationId, + pid, + sourceName: null + }); + + const fn = data => { + const progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value); + showNotification({ + title: `${applicationName} - Quests Completer`, + body: `Current progress: ${progress}/${secondsNeeded} seconds.`, + icon: icon, + }); + + if (progress >= secondsNeeded) { + showNotification({ + title: `${applicationName} - Quests Completer`, + body: "Quest Completed.", + icon: icon, + }); + + ApplicationStreamingStore.getStreamerActiveStreamMetadata = realFunc; + FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); + } + }; + FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); + } + return; + } +} + export default definePlugin({ name: "QuestCompleter", description: "A plugin to complete quests without having the game installed.", @@ -34,14 +217,50 @@ export default definePlugin({ match: /(function .+?\(.+?\){let{inPopout:.+allowIdle.+?}=.+?\.\i\)\("popup"\),(.+?)=\[\];if\(.+?\){.+"chat-spacer"\)\)\),\(\d,.+?\.jsx\)\(.+?,{children:).+?}}/, replace: "$1[$self.renderQuestButton(),...$2]})}}" } + }, + { + find: "toolbar:function", + replacement: { + match: /(function \i\(\i\){)(.{1,200}toolbar.{1,200}mobileToolbar)/, + replace: "$1$self.toolbarAction(arguments[0]);$2" + } } ], - settingsAboutComponent() { - const isDesktop = navigator.userAgent.includes("discord/"); + renderQuestButton() { + const ToolTipButton = findByCode("}),color:\"currentColor\"})})}}"); + return ( + <> + + + + + ); + }, + toolbarAction(e) { + if (Array.isArray(e.toolbar)) + return e.toolbar.push( + + + + ); + + e.toolbar = [ + + + , + e.toolbar, + ]; + }, + settingsAboutComponent() { return (<> { - isDesktop ? + isApp ? The plugin should work properly because you are on the Desktop Client. @@ -51,164 +270,5 @@ export default definePlugin({ } ); - }, - start() { - const currentUserId: string = UserStore.getCurrentUser().id; - window.currentUserId = currentUserId; // this is here because discord will lag if we get the current user id every time - }, - renderQuestButton() { - const ToolTipButton = findByCode("}),color:\"currentColor\"})})}}"); - const QuestsIcon = () => props => ( - - - - - ); - - return ( - <> - - - - - - ); - }, - async openCompleteQuestUI() { - // check if user is sharing screen and there is someone that is watching the stream - const ApplicationStreamingStore = findByProps("getStreamerActiveStreamMetadata"); - const RunningGameStore = findByProps("getRunningGames"); - const ExperimentStore = findByProps("getGuildExperiments"); - const QuestsStore = findByProps("getQuest"); - const quest = [...QuestsStore.quests.values()].find(quest => quest.userStatus?.enrolledAt && !quest?.userStatus?.completedAt && new Date(quest?.config?.expiresAt) >= new Date()); - - const isApp = navigator.userAgent.includes("Electron/"); - if (!isApp) { - showNotification({ - title: "Quests Completer", - body: "This no longer works in browser. Use the desktop app!", - }); - } else if (!quest) { - showNotification({ - title: "Quests Completer", - body: "No Quests To Complete", - }); - } else { - const pid = Math.floor(Math.random() * 30000) + 1000; - const theme = getTheme() === Theme.Light - ? "light" - : "dark"; - - let applicationId, applicationName, secondsNeeded, secondsDone, canPlay, icon, questId; - if (quest.config.configVersion === 1) { - questId = quest.id; - applicationId = quest.config.applicationId; - applicationName = quest.config.applicationName; - secondsNeeded = quest.config.streamDurationRequirementMinutes * 60; - secondsDone = quest.userStatus?.streamProgressSeconds ?? 0; - icon = `https://cdn.discordapp.com/assets/quests/${questId}/${theme}/${quest.config.assets.gameTile}`; - canPlay = quest.config.variants.includes(2); - } else if (quest.config.configVersion === 2) { - questId = quest.id; - applicationId = quest.config.application.id; - applicationName = quest.config.application.name; - icon = `https://cdn.discordapp.com/assets/quests/${questId}/${theme}/${quest.config.assets.gameTile}`; - canPlay = ExperimentStore.getUserExperimentBucket("2024-04_quest_playtime_task") > 0 && quest.config.taskConfig.tasks.PLAY_ON_DESKTOP; - const taskName = canPlay ? "PLAY_ON_DESKTOP" : "STREAM_ON_DESKTOP"; - secondsNeeded = quest.config.taskConfig.tasks[taskName]?.target; - secondsDone = quest.userStatus?.progress?.[taskName]?.value ?? 0; - } - if (canPlay) { - await RestAPI.get({ url: `/applications/public?application_ids=${applicationId}` }).then(res => { - const appData = res.body[0]; - const exeName = appData.executables.find(x => x.os === "win32").name.replace(">", ""); - - const games = RunningGameStore.getRunningGames(); - const fakeGame = { - cmdLine: `C:\\Program Files\\${appData.name}\\${exeName}`, - exeName, - exePath: `c:/program files/${appData.name.toLowerCase()}/${exeName}`, - hidden: false, - isLauncher: false, - id: applicationId, - name: appData.name, - pid: pid, - pidPath: [pid], - processName: appData.name, - start: Date.now(), - }; - games.push(fakeGame); - FluxDispatcher.dispatch({ type: "RUNNING_GAMES_CHANGE", removed: [], added: [fakeGame], games: games }); - - const fn = data => { - const progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.PLAY_ON_DESKTOP.value); - showNotification({ - title: `${applicationName} - Quests Completer`, - body: `Current progress: ${progress}/${secondsNeeded} seconds.`, - icon: icon, - }); - - if (progress >= secondsNeeded) { - showNotification({ - title: `${applicationName} - Quests Completer`, - body: "Quest Completed", - icon: icon, - }); - - const idx = games.indexOf(fakeGame); - if (idx > -1) { - games.splice(idx, 1); - FluxDispatcher.dispatch({ type: "RUNNING_GAMES_CHANGE", removed: [fakeGame], added: [], games: [] }); - } - FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); - } - }; - FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); - }); - } else { - const realFunc = ApplicationStreamingStore.getStreamerActiveStreamMetadata; - ApplicationStreamingStore.getStreamerActiveStreamMetadata = () => ({ - id: applicationId, - pid, - sourceName: null - }); - - const fn = data => { - const progress = quest.config.configVersion === 1 ? data.userStatus.streamProgressSeconds : Math.floor(data.userStatus.progress.STREAM_ON_DESKTOP.value); - showNotification({ - title: `${applicationName} - Quests Completer`, - body: `Current progress: ${progress}/${secondsNeeded} seconds.`, - icon: icon, - }); - - if (progress >= secondsNeeded) { - showNotification({ - title: `${applicationName} - Quests Completer`, - body: "Quest Completed", - icon: icon, - }); - - ApplicationStreamingStore.getStreamerActiveStreamMetadata = realFunc; - FluxDispatcher.unsubscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); - } - }; - FluxDispatcher.subscribe("QUESTS_SEND_HEARTBEAT_SUCCESS", fn); - } - return; - } } });