diff --git a/dist/better-xcloud.lite.user.js b/dist/better-xcloud.lite.user.js index 2b7c84b..70ed99c 100755 --- a/dist/better-xcloud.lite.user.js +++ b/dist/better-xcloud.lite.user.js @@ -141,7 +141,7 @@ function deepClone(obj) { } var BxEvent; ((BxEvent) => { - BxEvent.JUMP_BACK_IN_READY = "bx-jump-back-in-ready", BxEvent.POPSTATE = "bx-popstate", BxEvent.STREAM_SESSION_READY = "bx-stream-session-ready", BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED = "bx-custom-touch-layouts-loaded", BxEvent.TOUCH_LAYOUT_MANAGER_READY = "bx-touch-layout-manager-ready", BxEvent.REMOTE_PLAY_READY = "bx-remote-play-ready", BxEvent.REMOTE_PLAY_FAILED = "bx-remote-play-failed", BxEvent.GAME_BAR_ACTION_ACTIVATED = "bx-game-bar-action-activated", BxEvent.MICROPHONE_STATE_CHANGED = "bx-microphone-state-changed", BxEvent.SPEAKER_STATE_CHANGED = "bx-speaker-state-changed", BxEvent.VIDEO_VISIBILITY_CHANGED = "bx-video-visibility-changed", BxEvent.CAPTURE_SCREENSHOT = "bx-capture-screenshot", BxEvent.POINTER_LOCK_REQUESTED = "bx-pointer-lock-requested", BxEvent.POINTER_LOCK_EXITED = "bx-pointer-lock-exited", BxEvent.NAVIGATION_FOCUS_CHANGED = "bx-nav-focus-changed", BxEvent.XCLOUD_DIALOG_SHOWN = "bx-xcloud-dialog-shown", BxEvent.XCLOUD_DIALOG_DISMISSED = "bx-xcloud-dialog-dismissed", BxEvent.XCLOUD_GUIDE_MENU_SHOWN = "bx-xcloud-guide-menu-shown", BxEvent.XCLOUD_POLLING_MODE_CHANGED = "bx-xcloud-polling-mode-changed", BxEvent.XCLOUD_RENDERING_COMPONENT = "bx-xcloud-rendering-component", BxEvent.XCLOUD_ROUTER_HISTORY_READY = "bx-xcloud-router-history-ready"; + BxEvent.JUMP_BACK_IN_READY = "bx-jump-back-in-ready", BxEvent.POPSTATE = "bx-popstate", BxEvent.STREAM_SESSION_READY = "bx-stream-session-ready", BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED = "bx-custom-touch-layouts-loaded", BxEvent.TOUCH_LAYOUT_MANAGER_READY = "bx-touch-layout-manager-ready", BxEvent.REMOTE_PLAY_READY = "bx-remote-play-ready", BxEvent.REMOTE_PLAY_FAILED = "bx-remote-play-failed", BxEvent.GAME_BAR_ACTION_ACTIVATED = "bx-game-bar-action-activated", BxEvent.MICROPHONE_STATE_CHANGED = "bx-microphone-state-changed", BxEvent.SPEAKER_STATE_CHANGED = "bx-speaker-state-changed", BxEvent.VIDEO_VISIBILITY_CHANGED = "bx-video-visibility-changed", BxEvent.CAPTURE_SCREENSHOT = "bx-capture-screenshot", BxEvent.POINTER_LOCK_REQUESTED = "bx-pointer-lock-requested", BxEvent.POINTER_LOCK_EXITED = "bx-pointer-lock-exited", BxEvent.NAVIGATION_FOCUS_CHANGED = "bx-nav-focus-changed", BxEvent.XCLOUD_GUIDE_MENU_SHOWN = "bx-xcloud-guide-menu-shown", BxEvent.XCLOUD_POLLING_MODE_CHANGED = "bx-xcloud-polling-mode-changed", BxEvent.XCLOUD_RENDERING_COMPONENT = "bx-xcloud-rendering-component", BxEvent.XCLOUD_ROUTER_HISTORY_READY = "bx-xcloud-router-history-ready"; function dispatch(target, eventName, data) { if (!target) return; if (!eventName) { @@ -158,12 +158,22 @@ var BxEvent; window.BxEvent = BxEvent; class BxEventBus { listeners = new Map; - static Script = new BxEventBus; - static Stream = new BxEventBus; + group; + static Script = new BxEventBus("script"); + static Stream = new BxEventBus("stream"); + constructor(group) { + this.group = group; + } on(event, callback) { if (!this.listeners.has(event)) this.listeners.set(event, new Set); this.listeners.get(event).add(callback), BX_FLAGS.Debug && BxLogger.warning("EventBus", "on", event, callback); } + once(event, callback) { + let wrapper = (...args) => { + callback(...args), this.off(event, wrapper); + }; + this.on(event, wrapper); + } off(event, callback) { if (BX_FLAGS.Debug && BxLogger.warning("EventBus", "off", event, callback), !callback) { this.listeners.delete(event); @@ -177,10 +187,10 @@ class BxEventBus { this.listeners.clear(); } emit(event, payload) { - BX_FLAGS.Debug && BxLogger.warning("EventBus", "emit", event, payload); let callbacks = this.listeners.get(event) || []; for (let callback of callbacks) callback(payload); + AppInterface && AppInterface.onEventBus(this.group + "." + event), BX_FLAGS.Debug && BxLogger.warning("EventBus", "emit", event, payload); } } window.BxEventBus = BxEventBus; @@ -207,7 +217,7 @@ class GhPagesUtils { static getNativeMkbCustomList(update = !1) { let key = "BetterXcloud.GhPages.ForceNativeMkb"; update && NATIVE_FETCH(GhPagesUtils.getUrl("native-mkb/ids.json")).then((response) => response.json()).then((json) => { - if (json.$schemaVersion === 1) window.localStorage.setItem(key, JSON.stringify(json)), BxEventBus.Script.emit("listForcedNativeMkbUpdated", { + if (json.$schemaVersion === 1) window.localStorage.setItem(key, JSON.stringify(json)), BxEventBus.Script.emit("list.forcedNativeMkb.updated", { data: json }); }); @@ -908,7 +918,7 @@ class BaseSettingsStore { return this.settings[key]; } setSetting(key, value, emitEvent = !1) { - return value = this.validateValue("set", key, value), this.settings[key] = this.validateValue("get", key, value), this.saveSettings(), emitEvent && BxEventBus.Script.emit("settingChanged", { + return value = this.validateValue("set", key, value), this.settings[key] = this.validateValue("get", key, value), this.saveSettings(), emitEvent && BxEventBus.Script.emit("setting.changed", { storageKey: this.storageKey, settingKey: key, settingValue: value @@ -1542,7 +1552,7 @@ class GlobalSettingsStorage extends BaseSettingsStore { default: [], unsupported: !AppInterface && UserAgent.isMobile(), ready: (setting) => { - if (!setting.unsupported) setting.multipleOptions = GhPagesUtils.getNativeMkbCustomList(!0), BxEventBus.Script.on("listForcedNativeMkbUpdated", (payload) => { + if (!setting.unsupported) setting.multipleOptions = GhPagesUtils.getNativeMkbCustomList(!0), BxEventBus.Script.on("list.forcedNativeMkb.updated", (payload) => { setting.multipleOptions = payload.data.data; }); }, @@ -2171,7 +2181,7 @@ class StreamStatsCollector { } catch (e) {} } static setupEvents() { - BxEventBus.Stream.on("statePlaying", () => { + BxEventBus.Stream.on("state.playing", () => { StreamStatsCollector.getInstance().reset(); }); } @@ -2309,7 +2319,7 @@ class StreamStats { this.refreshStyles(), document.documentElement.appendChild(this.$container); } static setupEvents() { - BxEventBus.Stream.on("statePlaying", () => { + BxEventBus.Stream.on("state.playing", () => { let PREF_STATS_QUICK_GLANCE = getPref("stats.quickGlance.enabled"), PREF_STATS_SHOW_WHEN_PLAYING = getPref("stats.showWhenPlaying"), streamStats = StreamStats.getInstance(); if (PREF_STATS_SHOW_WHEN_PLAYING) streamStats.start(); else if (PREF_STATS_QUICK_GLANCE) streamStats.quickGlanceSetup(), !PREF_STATS_SHOW_WHEN_PLAYING && streamStats.start(!0); @@ -2603,7 +2613,7 @@ class StreamSettings { if (!STATES.browser.capabilities.deviceVibration) return; let mode = StreamSettings.getPref("deviceVibration.mode"), intensity = 0; if (mode === "on" || mode === "auto" && !hasGamepad()) intensity = StreamSettings.getPref("deviceVibration.intensity") / 100; - StreamSettings.settings.deviceVibrationIntensity = intensity, BxEventBus.Script.emit("deviceVibrationUpdated", {}); + StreamSettings.settings.deviceVibrationIntensity = intensity, BxEventBus.Script.emit("deviceVibration.updated", {}); } static async refreshMkbSettings() { let settings = StreamSettings.settings, presetId = StreamSettings.getPref("mkb.p1.preset.mappingId"), orgPreset = await MkbMappingPresetsTable.getInstance().getPreset(presetId), orgPresetData = orgPreset.data, converted = { @@ -2617,12 +2627,12 @@ class StreamSettings { if (typeof keyName === "string") converted.mapping[keyName] = buttonIndex; } let mouse = converted.mouse; - mouse["sensitivityX"] *= 0.001, mouse["sensitivityY"] *= 0.001, mouse["deadzoneCounterweight"] *= 0.01, settings.mkbPreset = converted, setPref("mkb.p1.preset.mappingId", orgPreset.id), BxEventBus.Script.emit("mkbSettingUpdated", {}); + mouse["sensitivityX"] *= 0.001, mouse["sensitivityY"] *= 0.001, mouse["deadzoneCounterweight"] *= 0.01, settings.mkbPreset = converted, setPref("mkb.p1.preset.mappingId", orgPreset.id), BxEventBus.Script.emit("mkb.setting.updated", {}); } static async refreshKeyboardShortcuts() { let settings = StreamSettings.settings, presetId = StreamSettings.getPref("keyboardShortcuts.preset.inGameId"); if (presetId === 0) { - settings.keyboardShortcuts = null, setPref("keyboardShortcuts.preset.inGameId", presetId), BxEventBus.Script.emit("keyboardShortcutsUpdated", {}); + settings.keyboardShortcuts = null, setPref("keyboardShortcuts.preset.inGameId", presetId), BxEventBus.Script.emit("keyboardShortcuts.updated", {}); return; } let orgPreset = await KeyboardShortcutsTable.getInstance().getPreset(presetId), orgPresetData = orgPreset.data.mapping, converted = {}, action; @@ -2630,7 +2640,7 @@ class StreamSettings { let info = orgPresetData[action], key = `${info.code}:${info.modifiers || 0}`; converted[key] = action; } - settings.keyboardShortcuts = converted, setPref("keyboardShortcuts.preset.inGameId", orgPreset.id), BxEventBus.Script.emit("keyboardShortcutsUpdated", {}); + settings.keyboardShortcuts = converted, setPref("keyboardShortcuts.preset.inGameId", orgPreset.id), BxEventBus.Script.emit("keyboardShortcuts.updated", {}); } static async refreshAllSettings() { window.BX_STREAM_SETTINGS = StreamSettings.settings, await StreamSettings.refreshControllerSettings(), await StreamSettings.refreshMkbSettings(), await StreamSettings.refreshKeyboardShortcuts(); @@ -2657,7 +2667,7 @@ class MkbPopup { $btnActivate; mkbHandler; constructor() { - this.render(), BxEventBus.Script.on("keyboardShortcutsUpdated", () => { + this.render(), BxEventBus.Script.on("keyboardShortcuts.updated", () => { let $newButton = this.createActivateButton(); this.$btnActivate.replaceWith($newButton), this.$btnActivate = $newButton; }); @@ -2751,9 +2761,6 @@ class NativeMkbHandler extends MkbHandler { case "keyup": this.onKeyboardEvent(event); break; - case BxEvent.XCLOUD_DIALOG_SHOWN: - this.onDialogShown(); - break; case BxEvent.POINTER_LOCK_REQUESTED: this.onPointerLockRequested(event); break; @@ -2772,7 +2779,7 @@ class NativeMkbHandler extends MkbHandler { } catch (e) { Toast.show("Cannot enable Mouse & Keyboard feature"); } - this.mouseVerticalMultiply = getPref("nativeMkb.scroll.sensitivityY"), this.mouseHorizontalMultiply = getPref("nativeMkb.scroll.sensitivityX"), window.addEventListener("keyup", this), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this), window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this); + this.mouseVerticalMultiply = getPref("nativeMkb.scroll.sensitivityY"), this.mouseHorizontalMultiply = getPref("nativeMkb.scroll.sensitivityX"), window.addEventListener("keyup", this), window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this), BxEventBus.Script.on("dialog.shown", this.onDialogShown); let shortcutKey = StreamSettings.findKeyboardShortcut("mkb.toggle"); if (shortcutKey) { let msg = t("press-key-to-toggle-mkb", { key: `${KeyHelper.codeToKeyName(shortcutKey)}` }); @@ -2802,7 +2809,7 @@ class NativeMkbHandler extends MkbHandler { this.resetMouseInput(), this.enabled = !1, this.updateInputConfigurationAsync(!1), this.waitForMouseData(!0); } destroy() { - this.pointerClient?.stop(), this.stop(), window.removeEventListener("keyup", this), window.removeEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this), window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this), this.waitForMouseData(!1), document.pointerLockElement && document.exitPointerLock(); + this.pointerClient?.stop(), this.stop(), window.removeEventListener("keyup", this), window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this), BxEventBus.Script.off("dialog.shown", this.onDialogShown), this.waitForMouseData(!1), document.pointerLockElement && document.exitPointerLock(); } handleMouseMove(data) { this.sendMouseInput({ @@ -3115,7 +3122,7 @@ class EmulatedMkbHandler extends MkbHandler { } if (this.initialized = !0, this.refreshPresetData(), this.enabled = !1, AppInterface) this.mouseDataProvider = new WebSocketMouseDataProvider(this); else this.mouseDataProvider = new PointerLockMouseDataProvider(this); - if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); + if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), BxEventBus.Script.on("dialog.shown", this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); else document.addEventListener("pointerlockchange", this.onPointerLockChange), document.addEventListener("pointerlockerror", this.onPointerLockError); if (MkbPopup.getInstance().reset(), AppInterface) { let shortcutKey = StreamSettings.findKeyboardShortcut("mkb.toggle"); @@ -3130,7 +3137,7 @@ class EmulatedMkbHandler extends MkbHandler { if (!this.initialized) return; if (this.initialized = !1, this.isPolling = !1, this.enabled = !1, this.stop(), this.waitForMouseData(!1), document.pointerLockElement && document.exitPointerLock(), window.removeEventListener("keydown", this.onKeyboardEvent), window.removeEventListener("keyup", this.onKeyboardEvent), AppInterface) window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this); else document.removeEventListener("pointerlockchange", this.onPointerLockChange), document.removeEventListener("pointerlockerror", this.onPointerLockError); - window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.removeEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), this.mouseDataProvider?.destroy(), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged); + window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), BxEventBus.Script.off("dialog.shown", this.onDialogShown), this.mouseDataProvider?.destroy(), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged); } updateGamepadSlots() { this.VIRTUAL_GAMEPAD.index = getPref("mkb.p1.slot") - 1; @@ -3357,10 +3364,10 @@ class NavigationDialogManager { this.gamepadHoldingIntervalId && window.clearInterval(this.gamepadHoldingIntervalId), this.gamepadHoldingIntervalId = null; } show(dialog, configs = {}, clearStack = !1) { - this.clearGamepadHoldingInterval(), BxEvent.dispatch(window, BxEvent.XCLOUD_DIALOG_SHOWN), window.BX_EXPOSED.disableGamepadPolling = !0, document.body.classList.add("bx-no-scroll"), this.unmountCurrentDialog(), this.dialogsStack.push(dialog), this.dialog = dialog, dialog.onBeforeMount(configs), this.$container.appendChild(dialog.getContent()), dialog.onMounted(configs), this.$overlay.classList.remove("bx-gone"), this.$overlay.classList.toggle("bx-invisible", !dialog.isOverlayVisible()), this.$container.classList.remove("bx-gone"), this.$container.addEventListener("keydown", this), this.startGamepadPolling(); + this.clearGamepadHoldingInterval(), BxEventBus.Script.emit("dialog.shown", {}), window.BX_EXPOSED.disableGamepadPolling = !0, document.body.classList.add("bx-no-scroll"), this.unmountCurrentDialog(), this.dialogsStack.push(dialog), this.dialog = dialog, dialog.onBeforeMount(configs), this.$container.appendChild(dialog.getContent()), dialog.onMounted(configs), this.$overlay.classList.remove("bx-gone"), this.$overlay.classList.toggle("bx-invisible", !dialog.isOverlayVisible()), this.$container.classList.remove("bx-gone"), this.$container.addEventListener("keydown", this), this.startGamepadPolling(); } hide() { - if (this.clearGamepadHoldingInterval(), document.body.classList.remove("bx-no-scroll"), BxEvent.dispatch(window, BxEvent.XCLOUD_DIALOG_DISMISSED), this.$overlay.classList.add("bx-gone"), this.$overlay.classList.remove("bx-invisible"), this.$container.classList.add("bx-gone"), this.$container.removeEventListener("keydown", this), this.stopGamepadPolling(), this.dialog) { + if (this.clearGamepadHoldingInterval(), document.body.classList.remove("bx-no-scroll"), BxEventBus.Script.emit("dialog.dismissed", {}), this.$overlay.classList.add("bx-gone"), this.$overlay.classList.remove("bx-invisible"), this.$container.classList.add("bx-gone"), this.$container.removeEventListener("keydown", this), this.stopGamepadPolling(), this.dialog) { let dialogIndex = this.dialogsStack.indexOf(this.dialog); if (dialogIndex > -1) this.dialogsStack = this.dialogsStack.slice(0, dialogIndex); } @@ -4281,7 +4288,7 @@ class SettingsDialog extends NavigationDialog { }, onCreated: (setting, $elm) => { let $range = $elm.querySelector("input[type=range"); - BxEventBus.Script.on("settingChanged", (payload) => { + BxEventBus.Script.on("setting.changed", (payload) => { let { storageKey, settingKey, settingValue } = payload; if (storageKey === "BetterXcloud" && settingKey === "audio.volume") $range.value = settingValue, BxEvent.dispatch($range, "input", { ignoreOnChange: !0 }); }); @@ -5168,9 +5175,9 @@ class GuideMenu { label: t("better-xcloud"), style: 128 | 64 | 1, onClick: () => { - window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, (e) => { + BxEventBus.Script.once("xcloudDialogDismissed", () => { setTimeout(() => SettingsDialog.getInstance().show(), 50); - }, { once: !0 }), this.closeGuideMenu(); + }), this.closeGuideMenu(); } }), closeApp: AppInterface && createButton({ @@ -5458,7 +5465,7 @@ class XcloudInterceptor { ip && request.headers.set("X-Forwarded-For", ip); } let response = await NATIVE_FETCH(request, init); - if (response.status !== 200) return BxEventBus.Script.emit("xcloudServerUnavailable", {}), response; + if (response.status !== 200) return BxEventBus.Script.emit("xcloud.server.unavailable", {}), response; let obj = await response.clone().json(); RemotePlayManager.getInstance()?.setXcloudToken(obj.gsToken); let serverRegex = /\/\/(\w+)\./, serverExtra = XcloudInterceptor.SERVER_EXTRA_INFO, region; @@ -5470,7 +5477,7 @@ class XcloudInterceptor { else region.contintent = "other"; region.shortName = shortName.toUpperCase(), STATES.serverRegions[region.name] = Object.assign({}, region); } - BxEventBus.Script.emit("xcloudServerReady", {}); + BxEventBus.Script.emit("xcloud.server.ready", {}); let preferredRegion = getPreferredServerRegion(); if (preferredRegion && preferredRegion in STATES.serverRegions) { let tmp = Object.assign({}, STATES.serverRegions[preferredRegion]); @@ -5479,7 +5486,7 @@ class XcloudInterceptor { return STATES.gsToken = obj.gsToken, response.json = () => Promise.resolve(obj), response; } static async handlePlay(request, init) { - BxEventBus.Stream.emit("stateLoading", {}); + BxEventBus.Stream.emit("state.loading", {}); let PREF_STREAM_TARGET_RESOLUTION = getPref("stream.video.resolution"), PREF_STREAM_PREFERRED_LOCALE = getPref("stream.locale"), url = typeof request === "string" ? request : request.url, parsedUrl = new URL(url), badgeRegion = parsedUrl.host.split(".", 1)[0]; for (let regionName in STATES.serverRegions) { let region = STATES.serverRegions[regionName]; @@ -5515,7 +5522,7 @@ class XcloudInterceptor { if (request.method !== "GET") return NATIVE_FETCH(request, init); let response = await NATIVE_FETCH(request, init), text = await response.clone().text(); if (!text.length) return response; - BxEventBus.Stream.emit("stateStarting", {}); + BxEventBus.Stream.emit("state.starting", {}); let obj = JSON.parse(text), overrides = JSON.parse(obj.clientStreamingConfigOverrides || "{}") || {}; overrides.inputConfiguration = overrides.inputConfiguration || {}, overrides.inputConfiguration.enableVibration = !0; let overrideMkb = null; @@ -5745,7 +5752,7 @@ function patchHistoryMethod(type) { } function onHistoryChanged(e) { if (e && e.arguments && e.arguments[0] && e.arguments[0].origin === "better-xcloud") return; - window.setTimeout(RemotePlayManager.detect, 10), NavigationDialogManager.getInstance().hide(), LoadingScreen.reset(), window.setTimeout(HeaderSection.watchHeader, 2000), BxEventBus.Stream.emit("stateStopped", {}); + window.setTimeout(RemotePlayManager.detect, 10), NavigationDialogManager.getInstance().hide(), LoadingScreen.reset(), window.setTimeout(HeaderSection.watchHeader, 2000), BxEventBus.Stream.emit("state.stopped", {}); } 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) || []; @@ -6101,7 +6108,7 @@ function patchVideoApi() { contrast: getPref("video.contrast"), brightness: getPref("video.brightness") }; - STATES.currentStream.streamPlayer = new StreamPlayer(this, getPref("video.player.type"), playerOptions), BxEventBus.Stream.emit("statePlaying", { + STATES.currentStream.streamPlayer = new StreamPlayer(this, getPref("video.player.type"), playerOptions), BxEventBus.Stream.emit("state.playing", { $video: this }); }, nativePlay = HTMLMediaElement.prototype.play; @@ -6302,7 +6309,7 @@ class StreamUiHandler { if (!($elm instanceof HTMLElement)) return; let className = $elm.className || ""; if (className.includes("PureErrorPage")) { - BxEventBus.Stream.emit("stateError", {}); + BxEventBus.Stream.emit("state.error", {}); return; } if (className.startsWith("StreamMenu-module__container")) { @@ -6373,7 +6380,7 @@ class RootDialogObserver { if ($addedElm instanceof HTMLElement) RootDialogObserver.handleAddedElement($root, $addedElm); } let shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0); - if (shown !== beingShown) beingShown = shown, BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED); + if (shown !== beingShown) beingShown = shown, BxEventBus.Script.emit(shown ? "dialog.shown" : "dialog.dismissed", {}); } }).observe($root, { subtree: !0, childList: !0 }); } @@ -6423,25 +6430,25 @@ window.addEventListener(BxEvent.POPSTATE, onHistoryChanged); window.addEventListener("popstate", onHistoryChanged); window.history.pushState = patchHistoryMethod("pushState"); window.history.replaceState = patchHistoryMethod("replaceState"); -BxEventBus.Script.on("xcloudServerUnavailable", () => { - if (BxEventBus.Script.off("xcloudServerUnavailable", null), STATES.supportedRegion = !1, window.setTimeout(HeaderSection.watchHeader, 2000), document.querySelector("div[class^=UnsupportedMarketPage-module__container]")) SettingsDialog.getInstance().show(); +BxEventBus.Script.once("xcloudServerUnavailable", () => { + if (STATES.supportedRegion = !1, window.setTimeout(HeaderSection.watchHeader, 2000), document.querySelector("div[class^=UnsupportedMarketPage-module__container]")) SettingsDialog.getInstance().show(); }); -BxEventBus.Script.on("xcloudServerReady", () => { +BxEventBus.Script.on("xcloud.server.ready", () => { STATES.isSignedIn = !0, window.setTimeout(HeaderSection.watchHeader, 2000); }); -BxEventBus.Stream.on("stateLoading", () => { +BxEventBus.Stream.on("state.loading", () => { if (window.location.pathname.includes("/launch/") && STATES.currentStream.titleInfo) STATES.currentStream.titleSlug = productTitleToSlug(STATES.currentStream.titleInfo.product.title); else STATES.currentStream.titleSlug = "remote-play"; }); -getPref("loadingScreen.gameArt.show") && BxEventBus.Script.on("titleInfoReady", LoadingScreen.setup); -BxEventBus.Stream.on("stateStarting", () => { +getPref("loadingScreen.gameArt.show") && BxEventBus.Script.on("titleInfo.ready", LoadingScreen.setup); +BxEventBus.Stream.on("state.starting", () => { LoadingScreen.hide(); }); -BxEventBus.Stream.on("statePlaying", (payload) => { +BxEventBus.Stream.on("state.playing", (payload) => { window.BX_STREAM_SETTINGS = StreamSettings.settings, StreamSettings.refreshAllSettings(), STATES.isPlaying = !0, StreamUiHandler.observe(), updateVideoPlayer(); }); -BxEventBus.Stream.on("stateError", () => { - BxEventBus.Stream.emit("stateStopped", {}); +BxEventBus.Stream.on("state.error", () => { + BxEventBus.Stream.emit("state.stopped", {}); }); BxEventBus.Stream.on("dataChannelCreated", (payload) => { let { dataChannel } = payload; @@ -6462,9 +6469,9 @@ function unload() { if (!STATES.isPlaying) return; STATES.currentStream.streamPlayer?.destroy(), STATES.isPlaying = !1, STATES.currentStream = {}, window.BX_EXPOSED.shouldShowSensorControls = !1, window.BX_EXPOSED.stopTakRendering = !1, NavigationDialogManager.getInstance().hide(), StreamStats.getInstance().destroy(), StreamBadges.getInstance().destroy(); } -BxEventBus.Stream.on("stateStopped", unload); +BxEventBus.Stream.on("state.stopped", unload); window.addEventListener("pagehide", (e) => { - BxEventBus.Stream.emit("stateStopped", {}); + BxEventBus.Stream.emit("state.stopped", {}); }); function main() { if (GhPagesUtils.fetchLatestCommit(), getPref("nativeMkb.mode") !== "off") { diff --git a/dist/better-xcloud.user.js b/dist/better-xcloud.user.js index cc4763b..69639a2 100755 --- a/dist/better-xcloud.user.js +++ b/dist/better-xcloud.user.js @@ -143,7 +143,7 @@ function deepClone(obj) { } var BxEvent; ((BxEvent) => { - BxEvent.JUMP_BACK_IN_READY = "bx-jump-back-in-ready", BxEvent.POPSTATE = "bx-popstate", BxEvent.STREAM_SESSION_READY = "bx-stream-session-ready", BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED = "bx-custom-touch-layouts-loaded", BxEvent.TOUCH_LAYOUT_MANAGER_READY = "bx-touch-layout-manager-ready", BxEvent.REMOTE_PLAY_READY = "bx-remote-play-ready", BxEvent.REMOTE_PLAY_FAILED = "bx-remote-play-failed", BxEvent.GAME_BAR_ACTION_ACTIVATED = "bx-game-bar-action-activated", BxEvent.MICROPHONE_STATE_CHANGED = "bx-microphone-state-changed", BxEvent.SPEAKER_STATE_CHANGED = "bx-speaker-state-changed", BxEvent.VIDEO_VISIBILITY_CHANGED = "bx-video-visibility-changed", BxEvent.CAPTURE_SCREENSHOT = "bx-capture-screenshot", BxEvent.POINTER_LOCK_REQUESTED = "bx-pointer-lock-requested", BxEvent.POINTER_LOCK_EXITED = "bx-pointer-lock-exited", BxEvent.NAVIGATION_FOCUS_CHANGED = "bx-nav-focus-changed", BxEvent.XCLOUD_DIALOG_SHOWN = "bx-xcloud-dialog-shown", BxEvent.XCLOUD_DIALOG_DISMISSED = "bx-xcloud-dialog-dismissed", BxEvent.XCLOUD_GUIDE_MENU_SHOWN = "bx-xcloud-guide-menu-shown", BxEvent.XCLOUD_POLLING_MODE_CHANGED = "bx-xcloud-polling-mode-changed", BxEvent.XCLOUD_RENDERING_COMPONENT = "bx-xcloud-rendering-component", BxEvent.XCLOUD_ROUTER_HISTORY_READY = "bx-xcloud-router-history-ready"; + BxEvent.JUMP_BACK_IN_READY = "bx-jump-back-in-ready", BxEvent.POPSTATE = "bx-popstate", BxEvent.STREAM_SESSION_READY = "bx-stream-session-ready", BxEvent.CUSTOM_TOUCH_LAYOUTS_LOADED = "bx-custom-touch-layouts-loaded", BxEvent.TOUCH_LAYOUT_MANAGER_READY = "bx-touch-layout-manager-ready", BxEvent.REMOTE_PLAY_READY = "bx-remote-play-ready", BxEvent.REMOTE_PLAY_FAILED = "bx-remote-play-failed", BxEvent.GAME_BAR_ACTION_ACTIVATED = "bx-game-bar-action-activated", BxEvent.MICROPHONE_STATE_CHANGED = "bx-microphone-state-changed", BxEvent.SPEAKER_STATE_CHANGED = "bx-speaker-state-changed", BxEvent.VIDEO_VISIBILITY_CHANGED = "bx-video-visibility-changed", BxEvent.CAPTURE_SCREENSHOT = "bx-capture-screenshot", BxEvent.POINTER_LOCK_REQUESTED = "bx-pointer-lock-requested", BxEvent.POINTER_LOCK_EXITED = "bx-pointer-lock-exited", BxEvent.NAVIGATION_FOCUS_CHANGED = "bx-nav-focus-changed", BxEvent.XCLOUD_GUIDE_MENU_SHOWN = "bx-xcloud-guide-menu-shown", BxEvent.XCLOUD_POLLING_MODE_CHANGED = "bx-xcloud-polling-mode-changed", BxEvent.XCLOUD_RENDERING_COMPONENT = "bx-xcloud-rendering-component", BxEvent.XCLOUD_ROUTER_HISTORY_READY = "bx-xcloud-router-history-ready"; function dispatch(target, eventName, data) { if (!target) return; if (!eventName) { @@ -187,12 +187,22 @@ var GamepadKeyName = { }; class BxEventBus { listeners = new Map; - static Script = new BxEventBus; - static Stream = new BxEventBus; + group; + static Script = new BxEventBus("script"); + static Stream = new BxEventBus("stream"); + constructor(group) { + this.group = group; + } on(event, callback) { if (!this.listeners.has(event)) this.listeners.set(event, new Set); this.listeners.get(event).add(callback), BX_FLAGS.Debug && BxLogger.warning("EventBus", "on", event, callback); } + once(event, callback) { + let wrapper = (...args) => { + callback(...args), this.off(event, wrapper); + }; + this.on(event, wrapper); + } off(event, callback) { if (BX_FLAGS.Debug && BxLogger.warning("EventBus", "off", event, callback), !callback) { this.listeners.delete(event); @@ -206,10 +216,10 @@ class BxEventBus { this.listeners.clear(); } emit(event, payload) { - BX_FLAGS.Debug && BxLogger.warning("EventBus", "emit", event, payload); let callbacks = this.listeners.get(event) || []; for (let callback of callbacks) callback(payload); + AppInterface && AppInterface.onEventBus(this.group + "." + event), BX_FLAGS.Debug && BxLogger.warning("EventBus", "emit", event, payload); } } window.BxEventBus = BxEventBus; @@ -236,7 +246,7 @@ class GhPagesUtils { static getNativeMkbCustomList(update = !1) { let key = "BetterXcloud.GhPages.ForceNativeMkb"; update && NATIVE_FETCH(GhPagesUtils.getUrl("native-mkb/ids.json")).then((response) => response.json()).then((json) => { - if (json.$schemaVersion === 1) window.localStorage.setItem(key, JSON.stringify(json)), BxEventBus.Script.emit("listForcedNativeMkbUpdated", { + if (json.$schemaVersion === 1) window.localStorage.setItem(key, JSON.stringify(json)), BxEventBus.Script.emit("list.forcedNativeMkb.updated", { data: json }); }); @@ -983,7 +993,7 @@ class BaseSettingsStore { return this.settings[key]; } setSetting(key, value, emitEvent = !1) { - return value = this.validateValue("set", key, value), this.settings[key] = this.validateValue("get", key, value), this.saveSettings(), emitEvent && BxEventBus.Script.emit("settingChanged", { + return value = this.validateValue("set", key, value), this.settings[key] = this.validateValue("get", key, value), this.saveSettings(), emitEvent && BxEventBus.Script.emit("setting.changed", { storageKey: this.storageKey, settingKey: key, settingValue: value @@ -1617,7 +1627,7 @@ class GlobalSettingsStorage extends BaseSettingsStore { default: [], unsupported: !AppInterface && UserAgent.isMobile(), ready: (setting) => { - if (!setting.unsupported) setting.multipleOptions = GhPagesUtils.getNativeMkbCustomList(!0), BxEventBus.Script.on("listForcedNativeMkbUpdated", (payload) => { + if (!setting.unsupported) setting.multipleOptions = GhPagesUtils.getNativeMkbCustomList(!0), BxEventBus.Script.on("list.forcedNativeMkb.updated", (payload) => { setting.multipleOptions = payload.data.data; }); }, @@ -2280,7 +2290,7 @@ class StreamStatsCollector { } catch (e) {} } static setupEvents() { - BxEventBus.Stream.on("statePlaying", () => { + BxEventBus.Stream.on("state.playing", () => { StreamStatsCollector.getInstance().reset(); }); } @@ -2418,7 +2428,7 @@ class StreamStats { this.refreshStyles(), document.documentElement.appendChild(this.$container); } static setupEvents() { - BxEventBus.Stream.on("statePlaying", () => { + BxEventBus.Stream.on("state.playing", () => { let PREF_STATS_QUICK_GLANCE = getPref("stats.quickGlance.enabled"), PREF_STATS_SHOW_WHEN_PLAYING = getPref("stats.showWhenPlaying"), streamStats = StreamStats.getInstance(); if (PREF_STATS_SHOW_WHEN_PLAYING) streamStats.start(); else if (PREF_STATS_QUICK_GLANCE) streamStats.quickGlanceSetup(), !PREF_STATS_SHOW_WHEN_PLAYING && streamStats.start(!0); @@ -2718,7 +2728,7 @@ class StreamSettings { if (!STATES.browser.capabilities.deviceVibration) return; let mode = StreamSettings.getPref("deviceVibration.mode"), intensity = 0; if (mode === "on" || mode === "auto" && !hasGamepad()) intensity = StreamSettings.getPref("deviceVibration.intensity") / 100; - StreamSettings.settings.deviceVibrationIntensity = intensity, BxEventBus.Script.emit("deviceVibrationUpdated", {}); + StreamSettings.settings.deviceVibrationIntensity = intensity, BxEventBus.Script.emit("deviceVibration.updated", {}); } static async refreshMkbSettings() { let settings = StreamSettings.settings, presetId = StreamSettings.getPref("mkb.p1.preset.mappingId"), orgPreset = await MkbMappingPresetsTable.getInstance().getPreset(presetId), orgPresetData = orgPreset.data, converted = { @@ -2732,12 +2742,12 @@ class StreamSettings { if (typeof keyName === "string") converted.mapping[keyName] = buttonIndex; } let mouse = converted.mouse; - mouse["sensitivityX"] *= 0.001, mouse["sensitivityY"] *= 0.001, mouse["deadzoneCounterweight"] *= 0.01, settings.mkbPreset = converted, setPref("mkb.p1.preset.mappingId", orgPreset.id), BxEventBus.Script.emit("mkbSettingUpdated", {}); + mouse["sensitivityX"] *= 0.001, mouse["sensitivityY"] *= 0.001, mouse["deadzoneCounterweight"] *= 0.01, settings.mkbPreset = converted, setPref("mkb.p1.preset.mappingId", orgPreset.id), BxEventBus.Script.emit("mkb.setting.updated", {}); } static async refreshKeyboardShortcuts() { let settings = StreamSettings.settings, presetId = StreamSettings.getPref("keyboardShortcuts.preset.inGameId"); if (presetId === 0) { - settings.keyboardShortcuts = null, setPref("keyboardShortcuts.preset.inGameId", presetId), BxEventBus.Script.emit("keyboardShortcutsUpdated", {}); + settings.keyboardShortcuts = null, setPref("keyboardShortcuts.preset.inGameId", presetId), BxEventBus.Script.emit("keyboardShortcuts.updated", {}); return; } let orgPreset = await KeyboardShortcutsTable.getInstance().getPreset(presetId), orgPresetData = orgPreset.data.mapping, converted = {}, action; @@ -2745,7 +2755,7 @@ class StreamSettings { let info = orgPresetData[action], key = `${info.code}:${info.modifiers || 0}`; converted[key] = action; } - settings.keyboardShortcuts = converted, setPref("keyboardShortcuts.preset.inGameId", orgPreset.id), BxEventBus.Script.emit("keyboardShortcutsUpdated", {}); + settings.keyboardShortcuts = converted, setPref("keyboardShortcuts.preset.inGameId", orgPreset.id), BxEventBus.Script.emit("keyboardShortcuts.updated", {}); } static async refreshAllSettings() { window.BX_STREAM_SETTINGS = StreamSettings.settings, await StreamSettings.refreshControllerSettings(), await StreamSettings.refreshMkbSettings(), await StreamSettings.refreshKeyboardShortcuts(); @@ -2772,7 +2782,7 @@ class MkbPopup { $btnActivate; mkbHandler; constructor() { - this.render(), BxEventBus.Script.on("keyboardShortcutsUpdated", () => { + this.render(), BxEventBus.Script.on("keyboardShortcuts.updated", () => { let $newButton = this.createActivateButton(); this.$btnActivate.replaceWith($newButton), this.$btnActivate = $newButton; }); @@ -2866,9 +2876,6 @@ class NativeMkbHandler extends MkbHandler { case "keyup": this.onKeyboardEvent(event); break; - case BxEvent.XCLOUD_DIALOG_SHOWN: - this.onDialogShown(); - break; case BxEvent.POINTER_LOCK_REQUESTED: this.onPointerLockRequested(event); break; @@ -2887,7 +2894,7 @@ class NativeMkbHandler extends MkbHandler { } catch (e) { Toast.show("Cannot enable Mouse & Keyboard feature"); } - this.mouseVerticalMultiply = getPref("nativeMkb.scroll.sensitivityY"), this.mouseHorizontalMultiply = getPref("nativeMkb.scroll.sensitivityX"), window.addEventListener("keyup", this), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this), window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this); + this.mouseVerticalMultiply = getPref("nativeMkb.scroll.sensitivityY"), this.mouseHorizontalMultiply = getPref("nativeMkb.scroll.sensitivityX"), window.addEventListener("keyup", this), window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this), BxEventBus.Script.on("dialog.shown", this.onDialogShown); let shortcutKey = StreamSettings.findKeyboardShortcut("mkb.toggle"); if (shortcutKey) { let msg = t("press-key-to-toggle-mkb", { key: `${KeyHelper.codeToKeyName(shortcutKey)}` }); @@ -2917,7 +2924,7 @@ class NativeMkbHandler extends MkbHandler { this.resetMouseInput(), this.enabled = !1, this.updateInputConfigurationAsync(!1), this.waitForMouseData(!0); } destroy() { - this.pointerClient?.stop(), this.stop(), window.removeEventListener("keyup", this), window.removeEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this), window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this), this.waitForMouseData(!1), document.pointerLockElement && document.exitPointerLock(); + this.pointerClient?.stop(), this.stop(), window.removeEventListener("keyup", this), window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this), BxEventBus.Script.off("dialog.shown", this.onDialogShown), this.waitForMouseData(!1), document.pointerLockElement && document.exitPointerLock(); } handleMouseMove(data) { this.sendMouseInput({ @@ -3230,7 +3237,7 @@ class EmulatedMkbHandler extends MkbHandler { } if (this.initialized = !0, this.refreshPresetData(), this.enabled = !1, AppInterface) this.mouseDataProvider = new WebSocketMouseDataProvider(this); else this.mouseDataProvider = new PointerLockMouseDataProvider(this); - if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); + if (this.mouseDataProvider.init(), window.addEventListener("keydown", this.onKeyboardEvent), window.addEventListener("keyup", this.onKeyboardEvent), window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), BxEventBus.Script.on("dialog.shown", this.onDialogShown), AppInterface) window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); else document.addEventListener("pointerlockchange", this.onPointerLockChange), document.addEventListener("pointerlockerror", this.onPointerLockError); if (MkbPopup.getInstance().reset(), AppInterface) { let shortcutKey = StreamSettings.findKeyboardShortcut("mkb.toggle"); @@ -3245,7 +3252,7 @@ class EmulatedMkbHandler extends MkbHandler { if (!this.initialized) return; if (this.initialized = !1, this.isPolling = !1, this.enabled = !1, this.stop(), this.waitForMouseData(!1), document.pointerLockElement && document.exitPointerLock(), window.removeEventListener("keydown", this.onKeyboardEvent), window.removeEventListener("keyup", this.onKeyboardEvent), AppInterface) window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this), window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this); else document.removeEventListener("pointerlockchange", this.onPointerLockChange), document.removeEventListener("pointerlockerror", this.onPointerLockError); - window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), window.removeEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown), this.mouseDataProvider?.destroy(), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged); + window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged), BxEventBus.Script.off("dialog.shown", this.onDialogShown), this.mouseDataProvider?.destroy(), window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged); } updateGamepadSlots() { this.VIRTUAL_GAMEPAD.index = getPref("mkb.p1.slot") - 1; @@ -3267,11 +3274,11 @@ class EmulatedMkbHandler extends MkbHandler { this.waitForMouseData(!0), this.mouseDataProvider?.stop(); } static setupEvents() { - if (BxEventBus.Stream.on("statePlaying", () => { + if (BxEventBus.Stream.on("state.playing", () => { if (STATES.currentStream.titleInfo?.details.hasMkbSupport) NativeMkbHandler.getInstance()?.init(); else EmulatedMkbHandler.getInstance()?.init(); }), EmulatedMkbHandler.isAllowed()) - BxEventBus.Script.on("mkbSettingUpdated", () => { + BxEventBus.Script.on("mkb.setting.updated", () => { EmulatedMkbHandler.getInstance()?.refreshPresetData(); }); } @@ -3480,10 +3487,10 @@ class NavigationDialogManager { this.gamepadHoldingIntervalId && window.clearInterval(this.gamepadHoldingIntervalId), this.gamepadHoldingIntervalId = null; } show(dialog, configs = {}, clearStack = !1) { - this.clearGamepadHoldingInterval(), BxEvent.dispatch(window, BxEvent.XCLOUD_DIALOG_SHOWN), window.BX_EXPOSED.disableGamepadPolling = !0, document.body.classList.add("bx-no-scroll"), this.unmountCurrentDialog(), this.dialogsStack.push(dialog), this.dialog = dialog, dialog.onBeforeMount(configs), this.$container.appendChild(dialog.getContent()), dialog.onMounted(configs), this.$overlay.classList.remove("bx-gone"), this.$overlay.classList.toggle("bx-invisible", !dialog.isOverlayVisible()), this.$container.classList.remove("bx-gone"), this.$container.addEventListener("keydown", this), this.startGamepadPolling(); + this.clearGamepadHoldingInterval(), BxEventBus.Script.emit("dialog.shown", {}), window.BX_EXPOSED.disableGamepadPolling = !0, document.body.classList.add("bx-no-scroll"), this.unmountCurrentDialog(), this.dialogsStack.push(dialog), this.dialog = dialog, dialog.onBeforeMount(configs), this.$container.appendChild(dialog.getContent()), dialog.onMounted(configs), this.$overlay.classList.remove("bx-gone"), this.$overlay.classList.toggle("bx-invisible", !dialog.isOverlayVisible()), this.$container.classList.remove("bx-gone"), this.$container.addEventListener("keydown", this), this.startGamepadPolling(); } hide() { - if (this.clearGamepadHoldingInterval(), document.body.classList.remove("bx-no-scroll"), BxEvent.dispatch(window, BxEvent.XCLOUD_DIALOG_DISMISSED), this.$overlay.classList.add("bx-gone"), this.$overlay.classList.remove("bx-invisible"), this.$container.classList.add("bx-gone"), this.$container.removeEventListener("keydown", this), this.stopGamepadPolling(), this.dialog) { + if (this.clearGamepadHoldingInterval(), document.body.classList.remove("bx-no-scroll"), BxEventBus.Script.emit("dialog.dismissed", {}), this.$overlay.classList.add("bx-gone"), this.$overlay.classList.remove("bx-invisible"), this.$container.classList.add("bx-gone"), this.$container.removeEventListener("keydown", this), this.stopGamepadPolling(), this.dialog) { let dialogIndex = this.dialogsStack.indexOf(this.dialog); if (dialogIndex > -1) this.dialogsStack = this.dialogsStack.slice(0, dialogIndex); } @@ -6141,7 +6148,7 @@ class SettingsDialog extends NavigationDialog { }, onCreated: (setting, $elm) => { let $range = $elm.querySelector("input[type=range"); - BxEventBus.Script.on("settingChanged", (payload) => { + BxEventBus.Script.on("setting.changed", (payload) => { let { storageKey, settingKey, settingValue } = payload; if (storageKey === "BetterXcloud" && settingKey === "audio.volume") $range.value = settingValue, BxEvent.dispatch($range, "input", { ignoreOnChange: !0 }); }); @@ -6990,7 +6997,7 @@ var BxExposed = { if (touchControllerAvailability === "off") supportedInputTypes = supportedInputTypes.filter((i) => i !== "CustomTouchOverlay" && i !== "GenericTouch"), titleInfo.details.supportedTabs = []; if (titleInfo.details.hasNativeTouchSupport = supportedInputTypes.includes("NativeTouch"), titleInfo.details.hasTouchSupport = titleInfo.details.hasNativeTouchSupport || supportedInputTypes.includes("CustomTouchOverlay") || supportedInputTypes.includes("GenericTouch"), !titleInfo.details.hasTouchSupport && touchControllerAvailability === "all") titleInfo.details.hasFakeTouchSupport = !0, supportedInputTypes.push("GenericTouch"); } - return titleInfo.details.supportedInputTypes = supportedInputTypes, STATES.currentStream.titleInfo = titleInfo, BxEventBus.Script.emit("titleInfoReady", {}), titleInfo; + return titleInfo.details.supportedInputTypes = supportedInputTypes, STATES.currentStream.titleInfo = titleInfo, BxEventBus.Script.emit("titleInfo.ready", {}), titleInfo; }, setupGainNode: ($media, audioStream) => { if ($media instanceof HTMLAudioElement) $media.muted = !0, $media.addEventListener("playing", (e) => { @@ -7312,7 +7319,7 @@ class XhomeInterceptor { return NATIVE_FETCH(request); } static async handleConfiguration(request) { - BxEventBus.Stream.emit("stateStarting", {}); + BxEventBus.Stream.emit("state.starting", {}); let response = await NATIVE_FETCH(request), obj = await response.clone().json(), serverDetails = obj.serverDetails, pairs = [ ["ipAddress", "port"], ["ipV4Address", "ipV4Port"], @@ -7357,7 +7364,7 @@ class XhomeInterceptor { }), NATIVE_FETCH(request); } static async handlePlay(request) { - BxEventBus.Stream.emit("stateLoading", {}); + BxEventBus.Stream.emit("state.loading", {}); let body = await request.clone().json(), newRequest = new Request(request, { body: JSON.stringify(body) }); @@ -7467,9 +7474,9 @@ class GuideMenu { label: t("better-xcloud"), style: 128 | 64 | 1, onClick: () => { - window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, (e) => { + BxEventBus.Script.once("xcloudDialogDismissed", () => { setTimeout(() => SettingsDialog.getInstance().show(), 50); - }, { once: !0 }), this.closeGuideMenu(); + }), this.closeGuideMenu(); } }), closeApp: AppInterface && createButton({ @@ -7766,7 +7773,7 @@ class XcloudInterceptor { ip && request.headers.set("X-Forwarded-For", ip); } let response = await NATIVE_FETCH(request, init); - if (response.status !== 200) return BxEventBus.Script.emit("xcloudServerUnavailable", {}), response; + if (response.status !== 200) return BxEventBus.Script.emit("xcloud.server.unavailable", {}), response; let obj = await response.clone().json(); RemotePlayManager.getInstance()?.setXcloudToken(obj.gsToken); let serverRegex = /\/\/(\w+)\./, serverExtra = XcloudInterceptor.SERVER_EXTRA_INFO, region; @@ -7778,7 +7785,7 @@ class XcloudInterceptor { else region.contintent = "other"; region.shortName = shortName.toUpperCase(), STATES.serverRegions[region.name] = Object.assign({}, region); } - BxEventBus.Script.emit("xcloudServerReady", {}); + BxEventBus.Script.emit("xcloud.server.ready", {}); let preferredRegion = getPreferredServerRegion(); if (preferredRegion && preferredRegion in STATES.serverRegions) { let tmp = Object.assign({}, STATES.serverRegions[preferredRegion]); @@ -7787,7 +7794,7 @@ class XcloudInterceptor { return STATES.gsToken = obj.gsToken, response.json = () => Promise.resolve(obj), response; } static async handlePlay(request, init) { - BxEventBus.Stream.emit("stateLoading", {}); + BxEventBus.Stream.emit("state.loading", {}); let PREF_STREAM_TARGET_RESOLUTION = getPref("stream.video.resolution"), PREF_STREAM_PREFERRED_LOCALE = getPref("stream.locale"), url = typeof request === "string" ? request : request.url, parsedUrl = new URL(url), badgeRegion = parsedUrl.host.split(".", 1)[0]; for (let regionName in STATES.serverRegions) { let region = STATES.serverRegions[regionName]; @@ -7825,7 +7832,7 @@ class XcloudInterceptor { else TouchController.enable(); let response = await NATIVE_FETCH(request, init), text = await response.clone().text(); if (!text.length) return response; - BxEventBus.Stream.emit("stateStarting", {}); + BxEventBus.Stream.emit("state.starting", {}); let obj = JSON.parse(text), overrides = JSON.parse(obj.clientStreamingConfigOverrides || "{}") || {}; overrides.inputConfiguration = overrides.inputConfiguration || {}, overrides.inputConfiguration.enableVibration = !0; let overrideMkb = null; @@ -8089,7 +8096,7 @@ function patchHistoryMethod(type) { } function onHistoryChanged(e) { if (e && e.arguments && e.arguments[0] && e.arguments[0].origin === "better-xcloud") return; - window.setTimeout(RemotePlayManager.detect, 10), NavigationDialogManager.getInstance().hide(), LoadingScreen.reset(), window.setTimeout(HeaderSection.watchHeader, 2000), BxEventBus.Stream.emit("stateStopped", {}); + window.setTimeout(RemotePlayManager.detect, 10), NavigationDialogManager.getInstance().hide(), LoadingScreen.reset(), window.setTimeout(HeaderSection.watchHeader, 2000), BxEventBus.Stream.emit("state.stopped", {}); } 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) || []; @@ -8446,7 +8453,7 @@ function patchVideoApi() { contrast: getPref("video.contrast"), brightness: getPref("video.brightness") }; - STATES.currentStream.streamPlayer = new StreamPlayer(this, getPref("video.player.type"), playerOptions), BxEventBus.Stream.emit("statePlaying", { + STATES.currentStream.streamPlayer = new StreamPlayer(this, getPref("video.player.type"), playerOptions), BxEventBus.Stream.emit("state.playing", { $video: this }); }, nativePlay = HTMLMediaElement.prototype.play; @@ -9004,7 +9011,7 @@ class StreamUiHandler { if (!($elm instanceof HTMLElement)) return; let className = $elm.className || ""; if (className.includes("PureErrorPage")) { - BxEventBus.Stream.emit("stateError", {}); + BxEventBus.Stream.emit("state.error", {}); return; } if (className.startsWith("StreamMenu-module__container")) { @@ -9075,7 +9082,7 @@ class RootDialogObserver { if ($addedElm instanceof HTMLElement) RootDialogObserver.handleAddedElement($root, $addedElm); } let shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0); - if (shown !== beingShown) beingShown = shown, BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED); + if (shown !== beingShown) beingShown = shown, BxEventBus.Script.emit(shown ? "dialog.shown" : "dialog.dismissed", {}); } }).observe($root, { subtree: !0, childList: !0 }); } @@ -9132,7 +9139,7 @@ class DeviceVibrationManager { this.boundOnMessage = this.onMessage.bind(this), BxEventBus.Stream.on("dataChannelCreated", (payload) => { let { dataChannel } = payload; if (dataChannel?.label === "input") this.reset(), this.dataChannel = dataChannel, this.setupDataChannel(); - }), BxEventBus.Script.on("deviceVibrationUpdated", () => this.setupDataChannel()); + }), BxEventBus.Script.on("deviceVibration.updated", () => this.setupDataChannel()); } setupDataChannel() { if (!this.dataChannel) return; @@ -9222,25 +9229,25 @@ window.addEventListener(BxEvent.POPSTATE, onHistoryChanged); window.addEventListener("popstate", onHistoryChanged); window.history.pushState = patchHistoryMethod("pushState"); window.history.replaceState = patchHistoryMethod("replaceState"); -BxEventBus.Script.on("xcloudServerUnavailable", () => { - if (BxEventBus.Script.off("xcloudServerUnavailable", null), STATES.supportedRegion = !1, window.setTimeout(HeaderSection.watchHeader, 2000), document.querySelector("div[class^=UnsupportedMarketPage-module__container]")) SettingsDialog.getInstance().show(); +BxEventBus.Script.once("xcloudServerUnavailable", () => { + if (STATES.supportedRegion = !1, window.setTimeout(HeaderSection.watchHeader, 2000), document.querySelector("div[class^=UnsupportedMarketPage-module__container]")) SettingsDialog.getInstance().show(); }); -BxEventBus.Script.on("xcloudServerReady", () => { +BxEventBus.Script.on("xcloud.server.ready", () => { STATES.isSignedIn = !0, window.setTimeout(HeaderSection.watchHeader, 2000); }); -BxEventBus.Stream.on("stateLoading", () => { +BxEventBus.Stream.on("state.loading", () => { if (window.location.pathname.includes("/launch/") && STATES.currentStream.titleInfo) STATES.currentStream.titleSlug = productTitleToSlug(STATES.currentStream.titleInfo.product.title); else STATES.currentStream.titleSlug = "remote-play"; }); -getPref("loadingScreen.gameArt.show") && BxEventBus.Script.on("titleInfoReady", LoadingScreen.setup); -BxEventBus.Stream.on("stateStarting", () => { +getPref("loadingScreen.gameArt.show") && BxEventBus.Script.on("titleInfo.ready", LoadingScreen.setup); +BxEventBus.Stream.on("state.starting", () => { LoadingScreen.hide(); { let cursorHider = MouseCursorHider.getInstance(); if (cursorHider) cursorHider.start(), cursorHider.hide(); } }); -BxEventBus.Stream.on("statePlaying", (payload) => { +BxEventBus.Stream.on("state.playing", (payload) => { window.BX_STREAM_SETTINGS = StreamSettings.settings, StreamSettings.refreshAllSettings(), STATES.isPlaying = !0, StreamUiHandler.observe(); { let gameBar = GameBar.getInstance(); @@ -9251,8 +9258,8 @@ BxEventBus.Stream.on("statePlaying", (payload) => { } updateVideoPlayer(); }); -BxEventBus.Stream.on("stateError", () => { - BxEventBus.Stream.emit("stateStopped", {}); +BxEventBus.Stream.on("state.error", () => { + BxEventBus.Stream.emit("state.stopped", {}); }); window.addEventListener(BxEvent.XCLOUD_RENDERING_COMPONENT, (e) => { if (e.component === "product-detail") ProductDetailsPage.injectButtons(); @@ -9276,9 +9283,9 @@ function unload() { if (!STATES.isPlaying) return; KeyboardShortcutHandler.getInstance().stop(), EmulatedMkbHandler.getInstance()?.destroy(), NativeMkbHandler.getInstance()?.destroy(), DeviceVibrationManager.getInstance()?.reset(), STATES.currentStream.streamPlayer?.destroy(), STATES.isPlaying = !1, STATES.currentStream = {}, window.BX_EXPOSED.shouldShowSensorControls = !1, window.BX_EXPOSED.stopTakRendering = !1, NavigationDialogManager.getInstance().hide(), StreamStats.getInstance().destroy(), StreamBadges.getInstance().destroy(), MouseCursorHider.getInstance()?.stop(), TouchController.reset(), GameBar.getInstance()?.disable(); } -BxEventBus.Stream.on("stateStopped", unload); +BxEventBus.Stream.on("state.stopped", unload); window.addEventListener("pagehide", (e) => { - BxEventBus.Stream.emit("stateStopped", {}); + BxEventBus.Stream.emit("state.stopped", {}); }); window.addEventListener(BxEvent.CAPTURE_SCREENSHOT, (e) => { ScreenshotManager.getInstance().takeScreenshot(); diff --git a/src/index.ts b/src/index.ts index 587350c..d0fd88b 100755 --- a/src/index.ts +++ b/src/index.ts @@ -191,9 +191,7 @@ window.addEventListener('popstate', onHistoryChanged); window.history.pushState = patchHistoryMethod('pushState'); window.history.replaceState = patchHistoryMethod('replaceState'); -BxEventBus.Script.on('xcloudServerUnavailable', () => { - BxEventBus.Script.off('xcloudServerUnavailable', null); - +BxEventBus.Script.once('xcloudServerUnavailable', () => { STATES.supportedRegion = false; window.setTimeout(HeaderSection.watchHeader, 2000); @@ -204,12 +202,12 @@ BxEventBus.Script.on('xcloudServerUnavailable', () => { } }); -BxEventBus.Script.on('xcloudServerReady', () => { +BxEventBus.Script.on('xcloud.server.ready', () => { STATES.isSignedIn = true; window.setTimeout(HeaderSection.watchHeader, 2000); }); -BxEventBus.Stream.on('stateLoading', () => { +BxEventBus.Stream.on('state.loading', () => { // Get title ID for screenshot's name if (window.location.pathname.includes('/launch/') && STATES.currentStream.titleInfo) { STATES.currentStream.titleSlug = productTitleToSlug(STATES.currentStream.titleInfo.product.title); @@ -219,9 +217,9 @@ BxEventBus.Stream.on('stateLoading', () => { }); // Setup loading screen -getPref(PrefKey.LOADING_SCREEN_GAME_ART) && BxEventBus.Script.on('titleInfoReady', LoadingScreen.setup); +getPref(PrefKey.LOADING_SCREEN_GAME_ART) && BxEventBus.Script.on('titleInfo.ready', LoadingScreen.setup); -BxEventBus.Stream.on('stateStarting', () => { +BxEventBus.Stream.on('state.starting', () => { // Hide loading screen LoadingScreen.hide(); @@ -235,7 +233,7 @@ BxEventBus.Stream.on('stateStarting', () => { } }); -BxEventBus.Stream.on('statePlaying', payload => { +BxEventBus.Stream.on('state.playing', payload => { window.BX_STREAM_SETTINGS = StreamSettings.settings; StreamSettings.refreshAllSettings(); @@ -265,8 +263,8 @@ BxEventBus.Stream.on('statePlaying', payload => { updateVideoPlayer(); }); -BxEventBus.Stream.on('stateError', () => { - BxEventBus.Stream.emit('stateStopped', {}); +BxEventBus.Stream.on('state.error', () => { + BxEventBus.Stream.emit('state.stopped', {}); }); isFullVersion() && window.addEventListener(BxEvent.XCLOUD_RENDERING_COMPONENT, e => { @@ -346,9 +344,9 @@ function unload() { } } -BxEventBus.Stream.on('stateStopped', unload); +BxEventBus.Stream.on('state.stopped', unload); window.addEventListener('pagehide', e => { - BxEventBus.Stream.emit('stateStopped', {}); + BxEventBus.Stream.emit('state.stopped', {}); }); isFullVersion() && window.addEventListener(BxEvent.CAPTURE_SCREENSHOT, e => { diff --git a/src/modules/device-vibration-manager.ts b/src/modules/device-vibration-manager.ts index b53d255..f3aa5d7 100755 --- a/src/modules/device-vibration-manager.ts +++ b/src/modules/device-vibration-manager.ts @@ -47,7 +47,7 @@ export class DeviceVibrationManager { } }); - BxEventBus.Script.on('deviceVibrationUpdated', () => this.setupDataChannel()); + BxEventBus.Script.on('deviceVibration.updated', () => this.setupDataChannel()); } private setupDataChannel() { diff --git a/src/modules/mkb/mkb-handler.ts b/src/modules/mkb/mkb-handler.ts index 3cbfdc6..76c51c5 100755 --- a/src/modules/mkb/mkb-handler.ts +++ b/src/modules/mkb/mkb-handler.ts @@ -518,7 +518,7 @@ export class EmulatedMkbHandler extends MkbHandler { window.addEventListener('keyup', this.onKeyboardEvent); window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged); - window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown); + BxEventBus.Script.on('dialog.shown', this.onDialogShown); if (AppInterface) { // Android app doesn't support PointerLock API so we need to use a different method @@ -569,7 +569,7 @@ export class EmulatedMkbHandler extends MkbHandler { } window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this.onPollingModeChanged); - window.removeEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this.onDialogShown); + BxEventBus.Script.off('dialog.shown', this.onDialogShown); this.mouseDataProvider?.destroy(); @@ -640,7 +640,7 @@ export class EmulatedMkbHandler extends MkbHandler { static setupEvents() { if (isFullVersion()) { - BxEventBus.Stream.on('statePlaying', () => { + BxEventBus.Stream.on('state.playing', () => { if (STATES.currentStream.titleInfo?.details.hasMkbSupport) { // Enable native MKB in Android app NativeMkbHandler.getInstance()?.init(); @@ -650,7 +650,7 @@ export class EmulatedMkbHandler extends MkbHandler { }); if (EmulatedMkbHandler.isAllowed()) { - BxEventBus.Script.on('mkbSettingUpdated', () => { + BxEventBus.Script.on('mkb.setting.updated', () => { EmulatedMkbHandler.getInstance()?.refreshPresetData(); }); } diff --git a/src/modules/mkb/mkb-popup.ts b/src/modules/mkb/mkb-popup.ts index 4e0c924..f0bb0f6 100755 --- a/src/modules/mkb/mkb-popup.ts +++ b/src/modules/mkb/mkb-popup.ts @@ -24,7 +24,7 @@ export class MkbPopup { constructor() { this.render(); - BxEventBus.Script.on('keyboardShortcutsUpdated', () => { + BxEventBus.Script.on('keyboardShortcuts.updated', () => { const $newButton = this.createActivateButton(); this.$btnActivate.replaceWith($newButton); this.$btnActivate = $newButton; diff --git a/src/modules/mkb/native-mkb-handler.ts b/src/modules/mkb/native-mkb-handler.ts index 3523280..4c2e920 100755 --- a/src/modules/mkb/native-mkb-handler.ts +++ b/src/modules/mkb/native-mkb-handler.ts @@ -12,6 +12,7 @@ import { KeyHelper } from "./key-helper"; import { StreamSettings } from "@/utils/stream-settings"; import { ShortcutAction } from "@/enums/shortcut-actions"; import { NativeMkbMode } from "@/enums/pref-values"; +import { BxEventBus } from "@/utils/bx-event-bus"; type NativeMouseData = { X: number, @@ -100,10 +101,6 @@ export class NativeMkbHandler extends MkbHandler { this.onKeyboardEvent(event as KeyboardEvent); break; - case BxEvent.XCLOUD_DIALOG_SHOWN: - this.onDialogShown(); - break; - case BxEvent.POINTER_LOCK_REQUESTED: this.onPointerLockRequested(event); break; @@ -135,10 +132,10 @@ export class NativeMkbHandler extends MkbHandler { window.addEventListener('keyup', this); - window.addEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this); window.addEventListener(BxEvent.POINTER_LOCK_REQUESTED, this); window.addEventListener(BxEvent.POINTER_LOCK_EXITED, this); window.addEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this); + BxEventBus.Script.on('dialog.shown', this.onDialogShown); const shortcutKey = StreamSettings.findKeyboardShortcut(ShortcutAction.MKB_TOGGLE); if (shortcutKey) { @@ -199,10 +196,10 @@ export class NativeMkbHandler extends MkbHandler { window.removeEventListener('keyup', this); - window.removeEventListener(BxEvent.XCLOUD_DIALOG_SHOWN, this); window.removeEventListener(BxEvent.POINTER_LOCK_REQUESTED, this); window.removeEventListener(BxEvent.POINTER_LOCK_EXITED, this); window.removeEventListener(BxEvent.XCLOUD_POLLING_MODE_CHANGED, this); + BxEventBus.Script.off('dialog.shown', this.onDialogShown); this.waitForMouseData(false); document.pointerLockElement && document.exitPointerLock(); diff --git a/src/modules/stream/stream-stats.ts b/src/modules/stream/stream-stats.ts index 894d5ab..4d54e21 100755 --- a/src/modules/stream/stream-stats.ts +++ b/src/modules/stream/stream-stats.ts @@ -230,7 +230,7 @@ export class StreamStats { } static setupEvents() { - BxEventBus.Stream.on('statePlaying', () => { + BxEventBus.Stream.on('state.playing', () => { const PREF_STATS_QUICK_GLANCE = getPref(PrefKey.STATS_QUICK_GLANCE_ENABLED); const PREF_STATS_SHOW_WHEN_PLAYING = getPref(PrefKey.STATS_SHOW_WHEN_PLAYING); diff --git a/src/modules/stream/stream-ui.ts b/src/modules/stream/stream-ui.ts index 25a0cd9..c12a6ff 100755 --- a/src/modules/stream/stream-ui.ts +++ b/src/modules/stream/stream-ui.ts @@ -243,7 +243,7 @@ export class StreamUiHandler { // Error Page: .PureErrorPage.ErrorScreen if (className.includes('PureErrorPage')) { - BxEventBus.Stream.emit('stateError', {}); + BxEventBus.Stream.emit('state.error', {}); return; } diff --git a/src/modules/ui/dialog/navigation-dialog.ts b/src/modules/ui/dialog/navigation-dialog.ts index c95d6a8..6f1e8f3 100755 --- a/src/modules/ui/dialog/navigation-dialog.ts +++ b/src/modules/ui/dialog/navigation-dialog.ts @@ -2,6 +2,7 @@ import { GamepadKey } from "@/enums/gamepad"; import { PrefKey } from "@/enums/pref-keys"; import { VIRTUAL_GAMEPAD_ID } from "@/modules/mkb/mkb-handler"; import { BxEvent } from "@/utils/bx-event"; +import { BxEventBus } from "@/utils/bx-event-bus"; import { BxLogger } from "@/utils/bx-logger"; import { CE, isElementVisible } from "@/utils/html"; import { setNearby } from "@/utils/navigation-utils"; @@ -439,7 +440,7 @@ export class NavigationDialogManager { show(dialog: NavigationDialog, configs={}, clearStack=false) { this.clearGamepadHoldingInterval(); - BxEvent.dispatch(window, BxEvent.XCLOUD_DIALOG_SHOWN); + BxEventBus.Script.emit('dialog.shown', {}); // Stop xCloud's navigation polling window.BX_EXPOSED.disableGamepadPolling = true; @@ -479,7 +480,7 @@ export class NavigationDialogManager { // Unlock scroll bar document.body.classList.remove('bx-no-scroll'); - BxEvent.dispatch(window, BxEvent.XCLOUD_DIALOG_DISMISSED); + BxEventBus.Script.emit('dialog.dismissed', {}); // Hide content this.$overlay.classList.add('bx-gone'); diff --git a/src/modules/ui/dialog/settings-dialog.ts b/src/modules/ui/dialog/settings-dialog.ts index bdf1d8d..1434b5a 100755 --- a/src/modules/ui/dialog/settings-dialog.ts +++ b/src/modules/ui/dialog/settings-dialog.ts @@ -436,7 +436,7 @@ export class SettingsDialog extends NavigationDialog { onCreated: (setting: SettingTabSectionItem, $elm: HTMLElement) => { const $range = $elm.querySelector('input[type=range')!; - BxEventBus.Script.on('settingChanged', payload => { + BxEventBus.Script.on('setting.changed', payload => { const { storageKey, settingKey, settingValue } = payload; if (storageKey === StorageKey.GLOBAL && settingKey === PrefKey.AUDIO_VOLUME) { $range.value = settingValue; diff --git a/src/modules/ui/guide-menu.ts b/src/modules/ui/guide-menu.ts index 5896b07..b3bc494 100755 --- a/src/modules/ui/guide-menu.ts +++ b/src/modules/ui/guide-menu.ts @@ -7,6 +7,7 @@ import { t } from "@/utils/translation"; import { SettingsDialog } from "./dialog/settings-dialog"; import { TrueAchievements } from "@/utils/true-achievements"; import { BxIcon } from "@/utils/bx-icon"; +import { BxEventBus } from "@/utils/bx-event-bus"; export enum GuideMenuTab { HOME = 'home', @@ -40,9 +41,9 @@ export class GuideMenu { style: ButtonStyle.FULL_WIDTH | ButtonStyle.FOCUSABLE | ButtonStyle.PRIMARY, onClick: () => { // Wait until the Guide dialog is closed - window.addEventListener(BxEvent.XCLOUD_DIALOG_DISMISSED, e => { + BxEventBus.Script.once('xcloudDialogDismissed', () => { setTimeout(() => SettingsDialog.getInstance().show(), 50); - }, { once: true }); + }); // Close all xCloud's dialogs this.closeGuideMenu(); diff --git a/src/utils/bx-event-bus.ts b/src/utils/bx-event-bus.ts index 34ef372..c78ba7b 100644 --- a/src/utils/bx-event-bus.ts +++ b/src/utils/bx-event-bus.ts @@ -1,26 +1,30 @@ import type { PrefKey, StorageKey } from "@/enums/pref-keys"; import { BX_FLAGS } from "./bx-flags"; import { BxLogger } from "./bx-logger"; +import { AppInterface } from "./global"; type EventCallback = (payload: T) => void; type ScriptEvents = { - xcloudServerReady: {}; - xcloudServerUnavailable: {}; + 'xcloud.server.ready': {}; + 'xcloud.server.unavailable': {}; - titleInfoReady: {}; - settingChanged: { + 'dialog.shown': {}, + 'dialog.dismissed': {}, + + 'titleInfo.ready': {}; + 'setting.changed': { storageKey: StorageKey; settingKey: PrefKey; settingValue: any; }; - mkbSettingUpdated: {}; - keyboardShortcutsUpdated: {}; - deviceVibrationUpdated: {}; + 'mkb.setting.updated': {}; + 'keyboardShortcuts.updated': {}; + 'deviceVibration.updated': {}; // GH pages - listForcedNativeMkbUpdated: { + 'list.forcedNativeMkb.updated': { data: { data: any; }; @@ -28,20 +32,25 @@ type ScriptEvents = { }; type StreamEvents = { - stateLoading: {}; - stateStarting: {}; - statePlaying: { $video?: HTMLVideoElement }; - stateStopped: {}; - stateError: {}; + 'state.loading': {}; + 'state.starting': {}; + 'state.playing': { $video?: HTMLVideoElement }; + 'state.stopped': {}; + 'state.error': {}; dataChannelCreated: { dataChannel: RTCDataChannel }; }; export class BxEventBus> { private listeners: Map>> = new Map(); + private group: string; - static readonly Script = new BxEventBus(); - static readonly Stream = new BxEventBus(); + static readonly Script = new BxEventBus('script'); + static readonly Stream = new BxEventBus('stream'); + + constructor(group: string) { + this.group = group; + } on(event: K, callback: EventCallback): void { if (!this.listeners.has(event)) { @@ -52,6 +61,16 @@ export class BxEventBus> { BX_FLAGS.Debug && BxLogger.warning('EventBus', 'on', event, callback); } + once(event: string, callback: EventCallback): void { + const wrapper = (...args: any[]) => { + // @ts-ignore + callback(...args); + this.off(event, wrapper); + }; + + this.on(event, wrapper); + } + off(event: K, callback: EventCallback | null): void { BX_FLAGS.Debug && BxLogger.warning('EventBus', 'off', event, callback); @@ -77,12 +96,13 @@ export class BxEventBus> { } emit(event: K, payload: TEvents[K]): void { - BX_FLAGS.Debug && BxLogger.warning('EventBus', 'emit', event, payload); - const callbacks = this.listeners.get(event) || []; for (const callback of callbacks) { callback(payload); } + + AppInterface && AppInterface.onEventBus(this.group + '.' + (event as string)); + BX_FLAGS.Debug && BxLogger.warning('EventBus', 'emit', event, payload); } } diff --git a/src/utils/bx-event.ts b/src/utils/bx-event.ts index ce4a4d3..8b7129a 100755 --- a/src/utils/bx-event.ts +++ b/src/utils/bx-event.ts @@ -28,10 +28,6 @@ export namespace BxEvent { export const NAVIGATION_FOCUS_CHANGED = 'bx-nav-focus-changed'; - // xCloud Dialog events - export const XCLOUD_DIALOG_SHOWN = 'bx-xcloud-dialog-shown'; - export const XCLOUD_DIALOG_DISMISSED = 'bx-xcloud-dialog-dismissed'; - export const XCLOUD_GUIDE_MENU_SHOWN = 'bx-xcloud-guide-menu-shown'; export const XCLOUD_POLLING_MODE_CHANGED = 'bx-xcloud-polling-mode-changed'; diff --git a/src/utils/bx-exposed.ts b/src/utils/bx-exposed.ts index 1732992..e8783a7 100755 --- a/src/utils/bx-exposed.ts +++ b/src/utils/bx-exposed.ts @@ -139,7 +139,7 @@ export const BxExposed = { // Save this info in STATES STATES.currentStream.titleInfo = titleInfo; - BxEventBus.Script.emit('titleInfoReady', {}); + BxEventBus.Script.emit('titleInfo.ready', {}); return titleInfo; }, diff --git a/src/utils/gh-pages.ts b/src/utils/gh-pages.ts index 0a70c33..e40e312 100755 --- a/src/utils/gh-pages.ts +++ b/src/utils/gh-pages.ts @@ -53,7 +53,7 @@ export class GhPagesUtils { if (json.$schemaVersion === supportedSchema) { // Save to storage window.localStorage.setItem(key, JSON.stringify(json)); - BxEventBus.Script.emit('listForcedNativeMkbUpdated', { + BxEventBus.Script.emit('list.forcedNativeMkb.updated', { data: json, }); } diff --git a/src/utils/history.ts b/src/utils/history.ts index 4991edb..3cb9add 100755 --- a/src/utils/history.ts +++ b/src/utils/history.ts @@ -33,5 +33,5 @@ export function onHistoryChanged(e: PopStateEvent) { LoadingScreen.reset(); window.setTimeout(HeaderSection.watchHeader, 2000); - BxEventBus.Stream.emit('stateStopped', {}); + BxEventBus.Stream.emit('state.stopped', {}); } diff --git a/src/utils/monkey-patches.ts b/src/utils/monkey-patches.ts index 38ee7d9..b384570 100755 --- a/src/utils/monkey-patches.ts +++ b/src/utils/monkey-patches.ts @@ -28,7 +28,7 @@ export function patchVideoApi() { } satisfies StreamPlayerOptions; STATES.currentStream.streamPlayer = new StreamPlayer(this, getPref(PrefKey.VIDEO_PLAYER_TYPE), playerOptions); - BxEventBus.Stream.emit('statePlaying', { + BxEventBus.Stream.emit('state.playing', { $video: this, }) } diff --git a/src/utils/root-dialog-observer.ts b/src/utils/root-dialog-observer.ts index 13db166..ca93ac0 100755 --- a/src/utils/root-dialog-observer.ts +++ b/src/utils/root-dialog-observer.ts @@ -1,5 +1,4 @@ import { GuideMenu } from "@/modules/ui/guide-menu"; -import { BxEvent } from "./bx-event"; import { BX_FLAGS } from "./bx-flags"; import { BxLogger } from "./bx-logger"; import { BxIcon } from "./bx-icon"; @@ -7,6 +6,7 @@ import { AppInterface } from "./global"; import { createButton, ButtonStyle } from "./html"; import { t } from "./translation"; import { parseDetailsPath } from "./utils"; +import { BxEventBus } from "./bx-event-bus"; export class RootDialogObserver { @@ -85,7 +85,7 @@ export class RootDialogObserver { const shown = !!($root.firstElementChild && $root.firstElementChild.childElementCount > 0); if (shown !== beingShown) { beingShown = shown; - BxEvent.dispatch(window, shown ? BxEvent.XCLOUD_DIALOG_SHOWN : BxEvent.XCLOUD_DIALOG_DISMISSED); + BxEventBus.Script.emit(shown ? 'dialog.shown' : 'dialog.dismissed', {}); } } }); diff --git a/src/utils/settings-storages/base-settings-storage.ts b/src/utils/settings-storages/base-settings-storage.ts index 04acc5a..fe3d8f0 100755 --- a/src/utils/settings-storages/base-settings-storage.ts +++ b/src/utils/settings-storages/base-settings-storage.ts @@ -93,7 +93,7 @@ export class BaseSettingsStore { this.settings[key] = this.validateValue('get', key, value); this.saveSettings(); - emitEvent && BxEventBus.Script.emit('settingChanged', { + emitEvent && BxEventBus.Script.emit('setting.changed', { storageKey: this.storageKey, settingKey: key, settingValue: value, diff --git a/src/utils/settings-storages/global-settings-storage.ts b/src/utils/settings-storages/global-settings-storage.ts index 25418de..18671c8 100755 --- a/src/utils/settings-storages/global-settings-storage.ts +++ b/src/utils/settings-storages/global-settings-storage.ts @@ -432,7 +432,7 @@ export class GlobalSettingsStorage extends BaseSettingsStorage { if (!setting.unsupported) { (setting as any).multipleOptions = GhPagesUtils.getNativeMkbCustomList(true); - BxEventBus.Script.on('listForcedNativeMkbUpdated', payload => { + BxEventBus.Script.on('list.forcedNativeMkb.updated', payload => { (setting as any).multipleOptions = payload.data.data; }); } diff --git a/src/utils/stream-settings.ts b/src/utils/stream-settings.ts index d99d876..961a95d 100755 --- a/src/utils/stream-settings.ts +++ b/src/utils/stream-settings.ts @@ -110,7 +110,7 @@ export class StreamSettings { } StreamSettings.settings.deviceVibrationIntensity = intensity; - BxEventBus.Script.emit('deviceVibrationUpdated', {}); + BxEventBus.Script.emit('deviceVibration.updated', {}); } static async refreshMkbSettings() { @@ -148,7 +148,7 @@ export class StreamSettings { settings.mkbPreset = converted; setPref(PrefKey.MKB_P1_MAPPING_PRESET_ID, orgPreset.id); - BxEventBus.Script.emit('mkbSettingUpdated', {}); + BxEventBus.Script.emit('mkb.setting.updated', {}); } static async refreshKeyboardShortcuts() { @@ -159,7 +159,7 @@ export class StreamSettings { settings.keyboardShortcuts = null; setPref(PrefKey.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID, presetId); - BxEventBus.Script.emit('keyboardShortcutsUpdated', {}); + BxEventBus.Script.emit('keyboardShortcuts.updated', {}); return; } @@ -179,7 +179,7 @@ export class StreamSettings { settings.keyboardShortcuts = converted; setPref(PrefKey.KEYBOARD_SHORTCUTS_IN_GAME_PRESET_ID, orgPreset.id); - BxEventBus.Script.emit('keyboardShortcutsUpdated', {}); + BxEventBus.Script.emit('keyboardShortcuts.updated', {}); } static async refreshAllSettings() { diff --git a/src/utils/stream-stats-collector.ts b/src/utils/stream-stats-collector.ts index dc9d86e..4649f6d 100755 --- a/src/utils/stream-stats-collector.ts +++ b/src/utils/stream-stats-collector.ts @@ -310,7 +310,7 @@ export class StreamStatsCollector { } static setupEvents() { - BxEventBus.Stream.on('statePlaying', () => { + BxEventBus.Stream.on('state.playing', () => { StreamStatsCollector.getInstance().reset(); }); } diff --git a/src/utils/xcloud-interceptor.ts b/src/utils/xcloud-interceptor.ts index 0ed02be..f8e50bd 100755 --- a/src/utils/xcloud-interceptor.ts +++ b/src/utils/xcloud-interceptor.ts @@ -52,7 +52,7 @@ export class XcloudInterceptor { const response = await NATIVE_FETCH(request, init); if (response.status !== 200) { // Unsupported region - BxEventBus.Script.emit('xcloudServerUnavailable', {}); + BxEventBus.Script.emit('xcloud.server.unavailable', {}); return response; } @@ -89,7 +89,7 @@ export class XcloudInterceptor { STATES.serverRegions[region.name] = Object.assign({}, region); } - BxEventBus.Script.emit('xcloudServerReady', {}); + BxEventBus.Script.emit('xcloud.server.ready', {}); const preferredRegion = getPreferredServerRegion(); if (preferredRegion && preferredRegion in STATES.serverRegions) { @@ -107,7 +107,7 @@ export class XcloudInterceptor { } private static async handlePlay(request: RequestInfo | URL, init?: RequestInit) { - BxEventBus.Stream.emit('stateLoading', {}); + BxEventBus.Stream.emit('state.loading', {}); const PREF_STREAM_TARGET_RESOLUTION = getPref(PrefKey.STREAM_RESOLUTION); const PREF_STREAM_PREFERRED_LOCALE = getPref(PrefKey.STREAM_PREFERRED_LOCALE); @@ -189,7 +189,7 @@ export class XcloudInterceptor { return response; } - BxEventBus.Stream.emit('stateStarting', {}); + BxEventBus.Stream.emit('state.starting', {}); const obj = JSON.parse(text); let overrides = JSON.parse(obj.clientStreamingConfigOverrides || '{}') || {}; diff --git a/src/utils/xhome-interceptor.ts b/src/utils/xhome-interceptor.ts index 8f6c073..32e492d 100755 --- a/src/utils/xhome-interceptor.ts +++ b/src/utils/xhome-interceptor.ts @@ -36,7 +36,7 @@ export class XhomeInterceptor { } private static async handleConfiguration(request: Request | URL) { - BxEventBus.Stream.emit('stateStarting', {}); + BxEventBus.Stream.emit('state.starting', {}); const response = await NATIVE_FETCH(request); const obj = await response.clone().json(); @@ -125,7 +125,7 @@ export class XhomeInterceptor { } private static async handlePlay(request: RequestInfo | URL) { - BxEventBus.Stream.emit('stateLoading', {}); + BxEventBus.Stream.emit('state.loading', {}); const clone = (request as Request).clone(); const body = await clone.json();