From e8376b52fed7d55947aa7336c3f7f31ec785f321 Mon Sep 17 00:00:00 2001 From: redphx <96280+redphx@users.noreply.github.com> Date: Fri, 1 Nov 2024 16:55:58 +0700 Subject: [PATCH] Add patch to modify __PRELOADED_STATE__ --- dist/better-xcloud.lite.user.js | 2 +- dist/better-xcloud.user.js | 61 +++++++++++++++++---------------- src/index.ts | 2 -- src/modules/patcher.ts | 12 +++++++ src/types/index.d.ts | 1 - src/utils/bx-exposed.ts | 44 ++++++++++++++++++++++++ src/utils/global.ts | 1 - src/utils/preload-state.ts | 56 ------------------------------ 8 files changed, 88 insertions(+), 91 deletions(-) delete mode 100644 src/utils/preload-state.ts diff --git a/dist/better-xcloud.lite.user.js b/dist/better-xcloud.lite.user.js index 160a42c..f7d624c 100644 --- a/dist/better-xcloud.lite.user.js +++ b/dist/better-xcloud.lite.user.js @@ -114,7 +114,6 @@ var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.inclu gsToken: "", isSignedIn: !1, isPlaying: !1, - appContext: {}, browser: { capabilities: { touch: browserHasTouchSupport, @@ -4430,6 +4429,7 @@ class SettingsNavigationDialog extends NavigationDialog { } var BxExposed = { getTitleInfo: () => STATES.currentStream.titleInfo, + modifyPreloadedState: !1, modifyTitleInfo: !1, setupGainNode: ($media, audioStream) => { if ($media instanceof HTMLAudioElement) $media.muted = !0, $media.addEventListener("playing", (e) => { diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js index 275f2f2..339f174 100644 --- a/dist/better-xcloud.user.js +++ b/dist/better-xcloud.user.js @@ -116,7 +116,6 @@ var userAgent = window.navigator.userAgent.toLowerCase(), isTv = userAgent.inclu gsToken: "", isSignedIn: !1, isPlaying: !1, - appContext: {}, browser: { capabilities: { touch: browserHasTouchSupport, @@ -4411,6 +4410,11 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) { let text = "/[;,/?:@&=+_`~$%#^*()!^\\u2122\\xae\\xa9]/g"; if (!str.includes(text)) return !1; return str = str.replace(text, "window.BX_EXPOSED.GameSlugRegexes[0]"), str = str.replace("/ {2,}/g", "window.BX_EXPOSED.GameSlugRegexes[1]"), str = str.replace("/ /g", "window.BX_EXPOSED.GameSlugRegexes[2]"), str; + }, + modifyPreloadedState(str) { + let text = "=window.__PRELOADED_STATE__;"; + if (!str.includes(text)) return !1; + return str = str.replace(text, "=window.BX_EXPOSED.modifyPreloadedState(window.__PRELOADED_STATE__);"), str; } }, PATCH_ORDERS = [ ...getPref("native_mkb_enabled") === "on" ? [ @@ -4419,6 +4423,7 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) { "disableNativeRequestPointerLock", "exposeInputSink" ] : [], + "modifyPreloadedState", "optimizeGameSlugGenerator", "detectBrowserRouterReady", "patchRequestInfoCrash", @@ -5776,6 +5781,30 @@ class ControllerShortcut { } var BxExposed = { getTitleInfo: () => STATES.currentStream.titleInfo, + modifyPreloadedState: (state) => { + let LOG_TAG3 = "PreloadState"; + try { + state.appContext.requestInfo.userAgent = window.navigator.userAgent; + } catch (e) { + BxLogger.error(LOG_TAG3, e); + } + try { + let sigls = state.xcloud.sigls; + if (STATES.userAgent.capabilities.touch) { + let customList = TouchController.getCustomList(), allGames = sigls["29a81209-df6f-41fd-a528-2ae6b91f719c"].data.products; + customList = customList.filter((id2) => allGames.includes(id2)), sigls["9c86f07a-f3e8-45ad-82a0-a1f759597059"]?.data.products.push(...customList); + } + } catch (e) { + BxLogger.error(LOG_TAG3, e); + } + try { + let sigls = state.xcloud.sigls; + if (BX_FLAGS.ForceNativeMkbTitles) sigls["8fa264dd-124f-4af3-97e8-596fcdf4b486"]?.data.products.push(...BX_FLAGS.ForceNativeMkbTitles); + } catch (e) { + BxLogger.error(LOG_TAG3, e); + } + return state; + }, modifyTitleInfo: function(titleInfo) { titleInfo = deepClone(titleInfo); let supportedInputTypes = titleInfo.details.supportedInputTypes; @@ -6963,34 +6992,6 @@ function onHistoryChanged(e) { if ($settings) $settings.classList.add("bx-gone"); NavigationDialogManager.getInstance().hide(), LoadingScreen.reset(), window.setTimeout(HeaderSection.watchHeader, 2000), BxEvent.dispatch(window, BxEvent.STREAM_STOPPED); } -var LOG_TAG3 = "PreloadState"; -function overridePreloadState() { - let _state; - Object.defineProperty(window, "__PRELOADED_STATE__", { - configurable: !0, - get: () => { - return _state; - }, - set: (state) => { - try { - state.appContext.requestInfo.userAgent = window.navigator.userAgent; - } catch (e) { - BxLogger.error(LOG_TAG3, e); - } - if (STATES.userAgent.capabilities.touch) try { - let sigls = state.xcloud.sigls; - if ("9c86f07a-f3e8-45ad-82a0-a1f759597059" in sigls) { - let customList = TouchController.getCustomList(), allGames = sigls["29a81209-df6f-41fd-a528-2ae6b91f719c"].data.products; - customList = customList.filter((id2) => allGames.includes(id2)), sigls["9c86f07a-f3e8-45ad-82a0-a1f759597059"]?.data.products.push(...customList); - } - if (BX_FLAGS.ForceNativeMkbTitles && "8fa264dd-124f-4af3-97e8-596fcdf4b486" in sigls) sigls["8fa264dd-124f-4af3-97e8-596fcdf4b486"]?.data.products.push(...BX_FLAGS.ForceNativeMkbTitles); - } catch (e) { - BxLogger.error(LOG_TAG3, e); - } - _state = state, STATES.appContext = deepClone(state.appContext); - } - }); -} function setCodecPreferences(sdp, preferredCodec) { let h264Pattern = /a=fmtp:(\d+).*profile-level-id=([0-9a-f]{6})/g, profilePrefix = preferredCodec === "high" ? "4d" : preferredCodec === "low" ? "420" : "42e", preferredCodecIds = [], matches = sdp.matchAll(h264Pattern) || []; for (let match of matches) { @@ -8044,7 +8045,7 @@ window.addEventListener(BxEvent.CAPTURE_SCREENSHOT, (e) => { function main() { if (getPref("game_msfs2020_force_native_mkb")) BX_FLAGS.ForceNativeMkbTitles.push("9PMQDM08SNK9"); if (patchRtcPeerConnection(), patchRtcCodecs(), interceptHttpRequests(), patchVideoApi(), patchCanvasContext(), AppInterface && patchPointerLockApi(), getPref("audio_enable_volume_control") && patchAudioContext(), getPref("block_tracking")) patchMeControl(), disableAdobeAudienceManager(); - if (RootDialogObserver.waitForRootDialog(), addCss(), GuideMenu.getInstance().addEventListeners(), StreamStatsCollector.setupEvents(), StreamBadges.setupEvents(), StreamStats.setupEvents(), updatePollingRate(), STATES.userAgent.capabilities.touch && TouchController.updateCustomList(), overridePreloadState(), VibrationManager.initialSetup(), BX_FLAGS.CheckForUpdate && checkForUpdate(), Patcher.init(), disablePwa(), getPref("xhome_enabled")) RemotePlayManager.detect(); + if (RootDialogObserver.waitForRootDialog(), addCss(), GuideMenu.getInstance().addEventListeners(), StreamStatsCollector.setupEvents(), StreamBadges.setupEvents(), StreamStats.setupEvents(), updatePollingRate(), STATES.userAgent.capabilities.touch && TouchController.updateCustomList(), VibrationManager.initialSetup(), BX_FLAGS.CheckForUpdate && checkForUpdate(), Patcher.init(), disablePwa(), getPref("xhome_enabled")) RemotePlayManager.detect(); if (getPref("stream_touch_controller") === "all") TouchController.setup(); if (getPref("mkb_enabled") && AppInterface) STATES.pointerServerPort = AppInterface.startPointerServer() || 9269, BxLogger.info("startPointerServer", "Port", STATES.pointerServerPort.toString()); if (getPref("ui_game_card_show_wait_time") && GameTile.setup(), EmulatedMkbHandler.setupEvents(), getPref("controller_show_connection_status")) window.addEventListener("gamepadconnected", (e) => showGamepadToast(e.gamepad)), window.addEventListener("gamepaddisconnected", (e) => showGamepadToast(e.gamepad)); diff --git a/src/index.ts b/src/index.ts index d4a4b0c..a957246 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,6 @@ import { Patcher } from "@modules/patcher"; import { RemotePlayManager } from "@/modules/remote-play-manager"; import { onHistoryChanged, patchHistoryMethod } from "@utils/history"; import { VibrationManager } from "@modules/vibration-manager"; -import { overridePreloadState } from "@utils/preload-state"; import { disableAdobeAudienceManager, patchAudioContext, patchCanvasContext, patchMeControl, patchPointerLockApi, patchRtcCodecs, patchRtcPeerConnection, patchVideoApi } from "@utils/monkey-patches"; import { AppInterface, STATES } from "@utils/global"; import { BxLogger } from "@utils/bx-logger"; @@ -362,7 +361,6 @@ function main() { if (isFullVersion()) { updatePollingRate(); STATES.userAgent.capabilities.touch && TouchController.updateCustomList(); - overridePreloadState(); VibrationManager.initialSetup(); diff --git a/src/modules/patcher.ts b/src/modules/patcher.ts index 8b03f31..6054ce4 100644 --- a/src/modules/patcher.ts +++ b/src/modules/patcher.ts @@ -985,6 +985,16 @@ if (this.baseStorageKey in window.BX_EXPOSED.overrideSettings) { return str; }, + + modifyPreloadedState(str: string) { + let text = '=window.__PRELOADED_STATE__;'; + if (!str.includes(text)) { + return false; + } + + str = str.replace(text, '=window.BX_EXPOSED.modifyPreloadedState(window.__PRELOADED_STATE__);'); + return str; + }, }; let PATCH_ORDERS: PatchArray = [ @@ -995,6 +1005,8 @@ let PATCH_ORDERS: PatchArray = [ 'exposeInputSink', ] : []), + 'modifyPreloadedState', + 'optimizeGameSlugGenerator', 'detectBrowserRouterReady', diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 9e0d117..c07208b 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -44,7 +44,6 @@ type BxStates = { isSignedIn: boolean; isPlaying: boolean; - appContext: any | null; browser: { capabilities: { diff --git a/src/utils/bx-exposed.ts b/src/utils/bx-exposed.ts index 2eeb07a..6b29e00 100644 --- a/src/utils/bx-exposed.ts +++ b/src/utils/bx-exposed.ts @@ -8,6 +8,8 @@ import { BX_FLAGS } from "./bx-flags"; import { NavigationDialogManager } from "@/modules/ui/dialog/navigation-dialog"; import { PrefKey } from "@/enums/pref-keys"; import { getPref, StreamTouchController } from "./settings-storages/global-settings-storage"; +import { GamePassCloudGallery } from "@/enums/game-pass-gallery"; +import { TouchController } from "@/modules/touch-controller"; export enum SupportedInputType { CONTROLLER = 'Controller', @@ -22,6 +24,48 @@ export type SupportedInputTypeValue = (typeof SupportedInputType)[keyof typeof S export const BxExposed = { getTitleInfo: () => STATES.currentStream.titleInfo, + modifyPreloadedState: isFullVersion() && ((state: any) => { + let LOG_TAG = 'PreloadState'; + + // Override User-Agent + try { + state.appContext.requestInfo.userAgent = window.navigator.userAgent; + } catch (e) { + BxLogger.error(LOG_TAG, e); + } + + // Add list of games with custom layouts to the official list + try { + const sigls = state.xcloud.sigls; + if (STATES.userAgent.capabilities.touch) { + // The list of custom touch controls + let customList = TouchController.getCustomList(); + + // Remove non-cloud games from the official list + const allGames = sigls[GamePassCloudGallery.ALL].data.products; + customList = customList.filter(id => allGames.includes(id)); + + // Add to the official touchlist + sigls[GamePassCloudGallery.TOUCH]?.data.products.push(...customList); + } + } catch (e) { + BxLogger.error(LOG_TAG, e); + } + + // Add forced Native MKB titles to the official list + try { + const sigls = state.xcloud.sigls; + if (BX_FLAGS.ForceNativeMkbTitles) { + // Add to the official list + sigls[GamePassCloudGallery.NATIVE_MKB]?.data.products.push(...BX_FLAGS.ForceNativeMkbTitles); + } + } catch (e) { + BxLogger.error(LOG_TAG, e); + } + + return state; + }), + modifyTitleInfo: isFullVersion() && function(titleInfo: XcloudTitleInfo): XcloudTitleInfo { // Clone the object since the original is read-only titleInfo = deepClone(titleInfo); diff --git a/src/utils/global.ts b/src/utils/global.ts index a948131..6d1ef76 100644 --- a/src/utils/global.ts +++ b/src/utils/global.ts @@ -23,7 +23,6 @@ export const STATES: BxStates = { isSignedIn: false, isPlaying: false, - appContext: {}, browser: { capabilities: { diff --git a/src/utils/preload-state.ts b/src/utils/preload-state.ts deleted file mode 100644 index 7b4c097..0000000 --- a/src/utils/preload-state.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { deepClone, STATES } from "@utils/global"; -import { BxLogger } from "./bx-logger"; -import { TouchController } from "@modules/touch-controller"; -import { GamePassCloudGallery } from "../enums/game-pass-gallery"; -import { BX_FLAGS } from "./bx-flags"; - -const LOG_TAG = 'PreloadState'; - -export function overridePreloadState() { - let _state: any; - - Object.defineProperty(window, '__PRELOADED_STATE__', { - configurable: true, - get: () => { - return _state; - }, - set: state => { - // Override User-Agent - try { - state.appContext.requestInfo.userAgent = window.navigator.userAgent; - } catch (e) { - BxLogger.error(LOG_TAG, e); - } - - // Add list of games with custom layouts to the official list - if (STATES.userAgent.capabilities.touch) { - try { - const sigls = state.xcloud.sigls; - if (GamePassCloudGallery.TOUCH in sigls) { - let customList = TouchController.getCustomList(); - - const allGames = sigls[GamePassCloudGallery.ALL].data.products; - - // Remove non-cloud games from the list - customList = customList.filter(id => allGames.includes(id)); - - // Add to the official list - sigls[GamePassCloudGallery.TOUCH]?.data.products.push(...customList); - } - - if (BX_FLAGS.ForceNativeMkbTitles && GamePassCloudGallery.NATIVE_MKB in sigls) { - // Add to the official list - sigls[GamePassCloudGallery.NATIVE_MKB]?.data.products.push(...BX_FLAGS.ForceNativeMkbTitles); - } - - } catch (e) { - BxLogger.error(LOG_TAG, e); - } - } - - // @ts-ignore - _state = state; - STATES.appContext = deepClone(state.appContext); - } - }); -}