From ef086cd1c49960357147c7878befeb1b3b1570fd Mon Sep 17 00:00:00 2001 From: thororen1234 <78185467+thororen1234@users.noreply.github.com> Date: Tue, 2 Jul 2024 13:29:10 -0400 Subject: [PATCH] Quest Stuff --- .../discordColorways/index.tsx | 2 +- src/equicordplugins/questCompleter/index.tsx | 214 ++++++++++++++++++ src/equicordplugins/whosWatching/index.tsx | 1 - 3 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 src/equicordplugins/questCompleter/index.tsx diff --git a/src/equicordplugins/discordColorways/index.tsx b/src/equicordplugins/discordColorways/index.tsx index 5881309f..7c6a6033 100644 --- a/src/equicordplugins/discordColorways/index.tsx +++ b/src/equicordplugins/discordColorways/index.tsx @@ -89,7 +89,7 @@ export let ColorPicker: React.FunctionComponent = () => { }); if (customColorways) { - if (!customColorways[0].colorways) { + if (!customColorways[0]?.colorways) { DataStore.set("customColorways", [{ name: "Custom", colorways: customColorways }]); } } else { diff --git a/src/equicordplugins/questCompleter/index.tsx b/src/equicordplugins/questCompleter/index.tsx new file mode 100644 index 00000000..bd4b7cd6 --- /dev/null +++ b/src/equicordplugins/questCompleter/index.tsx @@ -0,0 +1,214 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { showNotification } from "@api/Notifications"; +import { Devs, EquicordDevs } from "@utils/constants"; +import { getTheme, Theme } from "@utils/discord"; +import definePlugin from "@utils/types"; +import { findByCode, findByProps } from "@webpack"; +import { FluxDispatcher, Forms, RestAPI, Text, UserStore } from "@webpack/common"; + +export default definePlugin({ + name: "QuestCompleter", + description: "A plugin to complete quests without having the game installed.", + authors: [Devs.HappyEnderman, EquicordDevs.SerStars, EquicordDevs.thororen], + patches: [ + { + find: "\"invite-button\"", + replacement: { + match: /(function .+?\(.+?\){let{inPopout:.+allowIdle.+?}=.+?\.\i\)\("popup"\),(.+?)=\[\];if\(.+?\){.+"chat-spacer"\)\)\),\(\d,.+?\.jsx\)\(.+?,{children:).+?}}/, + replace: "$1[$self.renderQuestButton(),...$2]})}}" + } + } + ], + settingsAboutComponent() { + const isDesktop = navigator.userAgent.includes("discord/"); + + return (<> + { + isDesktop ? + + The plugin should work properly because you are on the Desktop Client. + + : + + This plugin won't work because you are not on the Desktop Client. + + } + ); + }, + 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} minutes.`, + 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} minutes.`, + 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; + } + } +}); diff --git a/src/equicordplugins/whosWatching/index.tsx b/src/equicordplugins/whosWatching/index.tsx index f16cfa69..4af65138 100644 --- a/src/equicordplugins/whosWatching/index.tsx +++ b/src/equicordplugins/whosWatching/index.tsx @@ -39,7 +39,6 @@ const settings = definePluginSettings({ function encodeStreamKey(stream) { const { streamType, guildId, channelId, ownerId } = stream; - console.log(streamType); switch (streamType) { case "guild": return [streamType, guildId, channelId, ownerId].join(":");