Files
discord-decomp/modules/quests/managers/QuestProgressManager.tsx
T
2026-11-01 12:12:55 +02:00

384 lines
17 KiB
TypeScript

// Metro module 16727 (f16728).
import EmbeddedActivitiesStore from "../../activities/EmbeddedActivitiesStore";
import FramesStore from "../../frames/FramesStore";
import RunningGameStore_native from "../../game_detection/RunningGameStore.native";
import ApplicationStreamingStore from "../../../stores/ApplicationStreamingStore";
import DetectableGameStore from "../../../stores/DetectableGameStore";
import SortedVoiceStateStore from "../../../stores/views/SortedVoiceStateStore";
import QuestStore from "../QuestStore";
import UnenrolledActivityQuestStore from "../UnenrolledActivityQuestStore";
import { QuestsExperimentLocations, DISCORD_APPLICATION_ID } from "../QuestConstants";
import Durations from "../../../utils/Durations";
import { getQuestLogger } from "../lib/getQuestLogger";
import * as _QuestDataUtils from "../utils/QuestDataUtils";
import { getEligibleQuestsForApplicationId } from "../utils/QuestMatchingUtils";
import { QuestVariants } from "../../../_bundle/Module5034";
import { sendHeartbeat } from "../QuestActionCreators";
import { ROBLOX_APPLICATION_ID } from "../../roblox_subgame_detection/RobloxSubgameTypes";
import { isRobloxSubgame } from "../../roblox_subgame_detection/RobloxSubgameUtils";
import AutomaticLifecycleManager from "../../../lib/AutomaticLifecycleManager";
import { FirstPartyQuestTaskTypes, FirstPartyQuestTaskTypesSets } from "../../../_bundle/Module5040";
import { getQuestTaskDetails, getDesktopApplicationIds, getStreamingApplicationId, getPlayActivityApplicationId } from "../utils/QuestTaskUtils";
import { encodeStreamKey } from "../../go_live/utils/StreamKeyUtils";
import { assertNever } from "../../../utils/GlobalUtils";
import { removeExecutablePathPrefix } from "../../game_detection/GameAnalyticsUtils";
import { isPlayAnyActivityQuest } from "../utils/QuestUtils";
function $mk118584($env) {
return (a0) => {
let r1 = a0 != null;
if (r1) {
r1 = a0.config.features.includes(QuestVariants.MANUAL_HEARTBEAT_INITIALIZATION);
}
return !r1;
};
}
let handleEmbeddedActivityLaunchSuccess, isQuestRobloxRelated, c12056_13, c12056_14, c12056_15, c12056_19;
let env12056 = {};
const isQuestProgressable = function isQuestProgressable(a0) {
const isQuestExpired = _QuestDataUtils.isQuestExpired(a0);
return (isQuestExpired ? !isQuestExpired : a0.userStatus != null) && a0.userStatus.enrolledAt != null && a0.userStatus.completedAt == null;
};
handleEmbeddedActivityLaunchSuccess = function handleEmbeddedActivityLaunchSuccess(a0) {
const autoEnroll = UnenrolledActivityQuestStore.getState().autoEnroll;
for (const item of getEligibleQuestsForApplicationId(QuestStore.quests, a0)) {
if (!autoEnroll) {
continue;
}
const features = item.config.features;
if (!features.includes(QuestVariants.MOBILE_ACTIVITY_QUEST)) {
continue;
}
return require(dependencyMap[16]).enrollInQuest(item.id, {
questContent: require(dependencyMap[17]).QuestContent.RUNNING_ACTIVITY,
questContentCTA: require(dependencyMap[18]).QuestContentCTA.START_QUEST,
sourceQuestContent: require(dependencyMap[17]).QuestContent.RUNNING_ACTIVITY
});
}
};
isQuestRobloxRelated = function isQuestRobloxRelated(a0, a1) {
return a1 != null && (a0.some((item) => item === ROBLOX_APPLICATION_ID) && isRobloxSubgame(a1));
};
c12056_13 = 1 * Durations.Millis.MINUTE;
c12056_14 = 1 * Durations.Millis.SECOND;
c12056_15 = getQuestLogger({
location: QuestsExperimentLocations.QUESTS_MANAGER
});
class QuestProgressManager extends AutomaticLifecycleManager {
constructor() {
let c23395_0, c23395_1;
super(...arguments);
const _this = this;
const heartbeats = {};
heartbeats[FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP] = new Map();
heartbeats[FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP] = new Map();
heartbeats[FirstPartyQuestTaskTypes.PLAY_ACTIVITY] = new Map();
this.heartbeats = heartbeats;
this.calculateHeartbeatDurationMs = (a0) => {
const r7 = QuestStore.quests.get(a0);
if (r7 != null && r7.config != null && r7.userStatus != null) {
const questTaskDetails = getQuestTaskDetails(r7, FirstPartyQuestTaskTypesSets.DESKTOP);
const r33 = Math.max(0, (questTaskDetails.targetSeconds - questTaskDetails.progressSeconds) * Durations.Millis.SECOND);
let r34 = c12056_13;
if (r33 <= r34) {
r34 = r33 + c12056_14;
}
return r34;
}
return c12056_13;
};
this.initiateHeartbeat = (a0, a1, c28507_2) => {
let maybeSendHeartbeat2;
const questId = a0;
const r11 = _this.heartbeats[a1];
let c28507_3 = r11;
if (r11.has(a0)) {
c12056_15.log(`~ initiateHeartbeat -> Heartbeat already initiated for questId: ${a0}`);
} else {
maybeSendHeartbeat2 = () => {
const activelyProgressingQuests = _this.getActivelyProgressingQuests(a1);
if (activelyProgressingQuests.has(questId)) {
const r30 = activelyProgressingQuests.get(questId);
let applicationId = r30?.applicationId;
if (applicationId == null) {
applicationId = c28507_2?.applicationId;
}
const executableFingerprint = r30?.executableFingerprint;
let executablePath = r30?.executablePath;
if (executablePath == null) {
executablePath = c28507_2?.executablePath;
}
if (a1 === FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP) {
const currentUserActiveStream = ApplicationStreamingStore.getCurrentUserActiveStream();
if (currentUserActiveStream == null) {
c12056_15.log(`~ initiateHeartbeat -> Attempted to beat for stream quest but no active stream, terminating heartbeat for questId: ${questId}`);
_this.terminateHeartbeat(questId, a1);
return void 0;
}
const streamKey = encodeStreamKey(currentUserActiveStream);
c12056_15.log(`~ initiateHeartbeat -> Sending heartbeat for questId: ${questId}`);
sendHeartbeat({
questId,
streamKey,
applicationId,
executablePath,
executableFingerprint
});
} else {
c12056_15.log(`~ initiateHeartbeat -> Sending heartbeat for questId: ${questId}`);
sendHeartbeat({
questId,
applicationId,
executablePath,
executableFingerprint
});
}
c28507_3.set(questId, window.setTimeout(maybeSendHeartbeat2, _this.calculateHeartbeatDurationMs(questId)));
} else {
c12056_15.log(`~ initiateHeartbeat -> Quest ${questId} is no longer actively progressing, terminating heartbeat`);
_this.terminateHeartbeat(questId, a1);
}
};
c12056_15.log(`~ initiateHeartbeat -> Initiating heartbeat for Quest ${a0}`);
maybeSendHeartbeat2();
}
};
this.terminateHeartbeat = (a0, a1) => {
const r10 = _this.heartbeats[a1];
const r12 = r10.get(a0);
if (r12 != null) {
c12056_15.log(`~ terminateHeartbeat -> Terminating heartbeat for questId: ${a0}`);
window.clearTimeout(r12);
r10.delete(a0);
const r29 = QuestStore.quests.get(a0);
let r1 = r29 != null;
if (r1) {
const isQuestExpired = _QuestDataUtils.isQuestExpired(r29);
r1 = (isQuestExpired ? !isQuestExpired : r29.userStatus != null) && r29.userStatus.enrolledAt != null && r29.userStatus.completedAt == null;
}
if (r1) {
c12056_15.log(`~ terminateHeartbeat -> Sending terminal heartbeat for questId: ${a0}`);
sendHeartbeat({
questId: a0,
terminal: true
});
}
}
};
this.handleSendHeartbeatSuccess = ({ questId: questId3, userStatus }) => {
c12056_15.log(`~ handleSendHeartbeatSuccess -> Heartbeat succeeded for questId: ${questId3})`);
if (userStatus.completedAt != null) {
c12056_15.log(`~ handleSendHeartbeatSuccess -> Quest ${questId3} completed, terminating any heartbeats for it`);
for (const item of Object.keys(_this.heartbeats)) {
_this.terminateHeartbeat(questId3, item);
}
}
};
this.handleSendHeartbeatFailure = (a0) => {
c12056_15.log(`~ handleSendHeartbeatFailure -> Heartbeat failed for questId: ${a0.questId}`);
};
const actions = {
QUESTS_FETCH_CURRENT_QUESTS_SUCCESS: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP, FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP], "QUESTS_FETCH_CURRENT_QUESTS_SUCCESS"),
QUESTS_ENROLL_SUCCESS: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP, FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP, FirstPartyQuestTaskTypes.PLAY_ACTIVITY], "QUESTS_ENROLL_SUCCESS", (a0) => !(a0 != null && a0.config.features.includes(QuestVariants.MANUAL_HEARTBEAT_INITIALIZATION))),
QUESTS_SEND_HEARTBEAT_SUCCESS: this.handleSendHeartbeatSuccess,
QUESTS_SEND_HEARTBEAT_FAILURE: this.handleSendHeartbeatFailure,
QUESTS_PREVIEW_UPDATE_SUCCESS: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP, FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP, FirstPartyQuestTaskTypes.PLAY_ACTIVITY], "QUESTS_PREVIEW_UPDATE_SUCCESS"),
RUNNING_GAMES_CHANGE: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP], "RUNNING_GAMES_CHANGE"),
RUNNING_NON_GAMES_CHANGE: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP], "RUNNING_NON_GAMES_CHANGE"),
STREAM_START: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP], "STREAM_START"),
STREAM_CREATE: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP], "STREAM_CREATE"),
STREAM_CLOSE: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP], "STREAM_CLOSE"),
PASSIVE_UPDATE_V2: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP], "PASSIVE_UPDATE_V2"),
VOICE_STATE_UPDATES: () => _this.syncHeartbeats([FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP], "VOICE_STATE_UPDATES"),
EMBEDDED_ACTIVITY_LAUNCH_SUCCESS: (a0) => {
handleEmbeddedActivityLaunchSuccess(a0.applicationId);
},
FRAME_LAUNCH: null,
FRAME_STOP: null,
EMBEDDED_ACTIVITY_UPDATE_V2: null,
QUEST_APPLICATION_START_TIMER: null
};
c23395_0 = void 0;
c23395_1 = this;
c23395_0 = async (c31107_0) => {
let c31107_2;
let env31840;
c31107_2 = void 0;
const r9 = env31840 = {
$parent: env12056
};
let c31107_1 = r9;
env31840[0] = void 0;
env31840[0] = c31107_0.applicationId;
await void 0;
await (0, handleEmbeddedActivityLaunchSuccess)(env31840[0]);
c23395_1.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ACTIVITY], "FRAME_LAUNCH", $mk118584(env12056));
};
actions.FRAME_LAUNCH = function FRAME_LAUNCH(a0) {
return c23395_0.apply(this, arguments);
};
actions.FRAME_STOP = () => {
_this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ACTIVITY], "FRAME_STOP");
};
actions.EMBEDDED_ACTIVITY_UPDATE_V2 = () => {
_this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ACTIVITY], "EMBEDDED_ACTIVITY_UPDATE_V2", (a0) => !(a0 != null && a0.config.features.includes(QuestVariants.MANUAL_HEARTBEAT_INITIALIZATION)));
};
actions.QUEST_APPLICATION_START_TIMER = ({ questId: questId2 }) => {
_this.syncHeartbeats([FirstPartyQuestTaskTypes.PLAY_ACTIVITY], "QUEST_APPLICATION_START_TIMER", (a0) => a0 != null && a0.id === questId2 && (a0 != null && a0.config.features.includes(QuestVariants.MANUAL_HEARTBEAT_INITIALIZATION)));
};
this.actions = actions;
}
syncHeartbeats(a0, a1, a2) {}
getActivelyProgressingQuests(a0) {
if (FirstPartyQuestTaskTypes.PLAY_ON_DESKTOP === a0) {
return this.getActivelyProgressingPlayOnDesktopQuests();
}
if (FirstPartyQuestTaskTypes.STREAM_ON_DESKTOP === a0) {
return this.getActivelyProgressingStreamOnDesktopQuests();
}
if (FirstPartyQuestTaskTypes.PLAY_ACTIVITY === a0) {
return this.getActivelyProgressingActivityQuests();
}
assertNever(a0);
}
getActivelyProgressingPlayOnDesktopQuests() {
let r30;
const map = new Map();
let c23396_0 = map;
const runningGames = RunningGameStore_native.getRunningGames();
const runningNonGames = RunningGameStore_native.getRunningNonGames();
const quests = QuestStore.quests;
c12056_15.log("~ getActivelyProgressingPlayOnDesktopQuestIds -> Running games: ", runningGames, "Running non-games: ", runningNonGames);
const r41 = {};
let c23396_2 = r41;
let r43 = runningGames[Symbol.iterator]();
const next = r43.next;
while (true) {
const r47 = r43 === void 0 ? void 0 : (r30 = next.call(r43)).done ? r43 = void 0 : r30.value;
if (r43 === void 0) {
for (const item of runningNonGames) {
if (item.id != null) {
r41[item.id] = item;
}
}
const _loop = function _loop(a0) {
const r9 = c23396_2[a0];
const executablePath = removeExecutablePathPrefix(r9.exePath);
for (const item of quests.values()) {
const desktopApplicationIds = getDesktopApplicationIds(item);
if (isQuestProgressable(item) && desktopApplicationIds != null) {
const applicationId = desktopApplicationIds.find((desktopApplicationId) => desktopApplicationId === a0);
if (applicationId != null) {
c23396_0.set(item.id, {
applicationId,
executablePath,
executableFingerprint: r9.executableFingerprint
});
} else if (isQuestRobloxRelated(desktopApplicationIds, r9)) {
c23396_0.set(item.id, {
applicationId: require(dependencyMap[19]).ROBLOX_APPLICATION_ID,
executablePath,
executableFingerprint: r9.executableFingerprint
});
}
}
}
};
for (const item2 of Object.keys(r41)) {
_loop(item2);
}
c12056_15.log("~ getActivelyProgressingPlayOnDesktopQuestIds -> Actively progressing questIds: ", Array.from(map.keys()));
return map;
} else {
try {
if (!r47.isLauncher) {
if (r47.id == null) {
const overrideForGame = RunningGameStore_native.getOverrideForGame(r47);
if (r47.distributor == null && overrideForGame != null) {
continue;
}
const r62 = DetectableGameStore.findGame(r47);
if (r62?.id != null) {
r41[r62.id] = r47;
}
} else {
r41[r47.id] = r47;
}
}
} catch (r69) {
if (r43 !== void 0 && typeof r43.return === "function") {
try {
r43.return();
} catch {}
}
throw r69;
}
}
}
}
getActivelyProgressingStreamOnDesktopQuests() {
const map = new Map();
const currentUserActiveStream = ApplicationStreamingStore.getCurrentUserActiveStream();
if (currentUserActiveStream == null) {
return map;
}
if (SortedVoiceStateStore.countVoiceStatesForChannel(currentUserActiveStream.channelId) < 2) {
return map;
}
const streamerActiveStreamMetadata = ApplicationStreamingStore.getStreamerActiveStreamMetadata();
if (streamerActiveStreamMetadata == null) {
return map;
}
c12056_15.log("~ getActivelyProgressingStreamOnDesktopQuestIds -> Active stream metadata: ", streamerActiveStreamMetadata);
const id = streamerActiveStreamMetadata.id;
if (id == null) {
return map;
}
for (const item of QuestStore.quests.values()) {
const streamingApplicationId = getStreamingApplicationId(item);
if (isQuestProgressable(item) && streamingApplicationId != null && streamingApplicationId === id) {
map.set(item.id, {
applicationId: id
});
}
}
c12056_15.log("~ getActivelyProgressingStreamOnDesktopQuestIds -> Actively progressing questIds: ", Array.from(map.keys()));
return map;
}
getActivelyProgressingActivityQuests() {
const map = new Map();
const selfEmbeddedActivities = EmbeddedActivitiesStore.getSelfEmbeddedActivities();
const connectedFrame = FramesStore.getConnectedFrame();
const set = new Set(selfEmbeddedActivities.keys());
if (connectedFrame != null) {
set.add(connectedFrame.applicationId);
}
c12056_15.log("~ getActivelyProgressingActivityQuestIds -> Running activity applicationIds: ", Array.from(set));
if (set.size === 0) {
return map;
}
for (const item2 of set) {
const applicationId = item2;
for (const item of QuestStore.quests.values()) {
const playActivityApplicationId = getPlayActivityApplicationId(item);
if (isQuestProgressable(item) && playActivityApplicationId != null && playActivityApplicationId === applicationId) {
map.set(item.id, {
applicationId
});
}
}
}
for (const item3 of QuestStore.quests.values()) {
if (isQuestProgressable(item3) && isPlayAnyActivityQuest(item3)) {
map.set(item3.id, {
applicationId: DISCORD_APPLICATION_ID
});
}
}
c12056_15.log("~ getActivelyProgressingActivityQuestIds -> Actively progressing questIds: ", Array.from(map.keys()));
return map;
}
}
c12056_19 = QuestProgressManager;
const r75 = new QuestProgressManager();
export default r75;