From 27eed321c478a8933890ae1e6f6a350e9f58fa59 Mon Sep 17 00:00:00 2001 From: beebls Date: Tue, 23 Aug 2022 15:28:55 -0600 Subject: [PATCH 01/12] Callback funcitons for starting/stopping games and menus --- src/SteamClient.d.ts | 135 +++++++++++++++++++++++++++++++++++++++++++ src/index.tsx | 32 ++++++++++ 2 files changed, 167 insertions(+) create mode 100644 src/SteamClient.d.ts diff --git a/src/SteamClient.d.ts b/src/SteamClient.d.ts new file mode 100644 index 0000000..e6673a9 --- /dev/null +++ b/src/SteamClient.d.ts @@ -0,0 +1,135 @@ +// Lovingly borrowed from https://github.com/hulkrelax/deckfaqs under the MIT License + +// Non-exhaustive definition of the SteamClient that is available in the SP tab +// This object has a lot more properties/methods than are listed here +declare namespace SteamClient { + const Apps: { + GetAllShortcuts(): Promise; + RegisterForGameActionStart( + callback: ( + actionType: number, + strAppId: string, + actionName: string + ) => any + ): RegisteredEvent; + }; + const InstallFolder: { + GetInstallFolders(): Promise; + }; + const GameSessions: { + RegisterForAppLifetimeNotifications( + callback: (appState: AppState) => any + ): RegisteredEvent; + }; + const BrowserView: { + Create(): any; + CreatePopup(): any; + Destroy(e: any): void; + }; + + const Storage: { + GetJSON(key: string): Promise; + SetObject(key: string, value: {}): Promise; + }; +} + +declare const enum DisplayStatus { + Invalid = 0, + Launching = 1, + Uninstalling = 2, + Installing = 3, + Running = 4, + Validating = 5, + Updating = 6, + Downloading = 7, + Synchronizing = 8, + ReadyToInstall = 9, + ReadyToPreload = 10, + ReadyToLaunch = 11, + RegionRestricted = 12, + PresaleOnly = 13, + InvalidPlatform = 14, + PreloadComplete = 16, + BorrowerLocked = 17, + UpdatePaused = 18, + UpdateQueued = 19, + UpdateRequired = 20, + UpdateDisabled = 21, + DownloadPaused = 22, + DownloadQueued = 23, + DownloadRequired = 24, + DownloadDisabled = 25, + LicensePending = 26, + LicenseExpired = 27, + AvailForFree = 28, + AvailToBorrow = 29, + AvailGuestPass = 30, + Purchase = 31, + Unavailable = 32, + NotLaunchable = 33, + CloudError = 34, + CloudOutOfDate = 35, + Terminating = 36, +} + +type AppState = { + unAppID: number; + nInstanceID: number; + bRunning: boolean; +}; + +declare namespace appStore { + function GetAppOverviewByGameID(appId: number): AppOverview; +} + +type RegisteredEvent = { + unregister(): void; +}; + +type Shortcut = { + appid: number; + data: { + bIsApplication: true; + strAppName: string; + strSortAs: string; + strExePath: string; + strShortcutPath: string; + strArguments: string; + strIconPath: string; + }; +}; + +type AppOverview = { + appid: string; + display_name: string; + display_status: DisplayStatus; + sort_as: string; +}; + +type App = { + nAppID: number; + strAppName: string; + strSortAs: string; + rtLastPlayed: number; + strUsedSize: string; + strDLCSize: string; + strWorkshopSize: string; + strStagedSize: string; +}; + +type InstallFolder = { + nFolderIndex: number; + strFolderPath: string; + strUserLabel: string; + strDriveName: string; + strCapacity: string; + strFreeSpace: string; + strUsedSize: string; + strDLCSize: string; + strWorkshopSize: string; + strStagedSize: string; + bIsDefaultFolder: boolean; + bIsMounted: boolean; + bIsFixed: boolean; + vecApps: App[]; +}; diff --git a/src/index.tsx b/src/index.tsx index 4dcec33..51cffd7 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -255,6 +255,35 @@ export default definePlugin((serverApi: ServerAPI) => { state.setMusicLibraryOnly(data?.music_library_only || false); }); + const AppStateRegistrar = + // SteamClient is something exposed by the SP tab of SteamUI, it's not a decky-frontend-lib thingy, but you can still call it normally + // Refer to the SteamClient.d.ts or just console.log(SteamClient) to see all of it's methods + SteamClient.GameSessions.RegisterForAppLifetimeNotifications( + (update: AppState) => { + update.bRunning + ? console.log("GAME HAS BEEN STARTED") + : console.log("GAME HAS BEEN STOPPED"); + } + ); + + // This variable is used to debounce these, as they tend to get called multiple times and I don't want stacked audio + let sideMenuOpen = false; + beforePatch(Router, "OpenSideMenu", (args) => { + if (!sideMenuOpen) { + sideMenuOpen = true; + // AudioParent.GamepadUIAudio.PlayAudioURL("/sounds_custom/drip.wav"); we might not use PlayAudioURL but this is where you would call it for QAM music + console.log("Side Menu Opened"); + } + return args; + }); + beforePatch(Router, "CloseSideMenus", (args) => { + if (sideMenuOpen) { + sideMenuOpen = false; + console.log("Side Menu Closed"); + } + return args; + }); + serverApi.routerHook.addRoute("/audiopack-manager", () => ( @@ -270,10 +299,13 @@ export default definePlugin((serverApi: ServerAPI) => { ), icon: , onDismount: () => { + unpatch(Router, "OpenSideMenu"); + unpatch(Router, "CloseSideMenus"); unpatch( AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, "PlayAudioURL" ); + AppStateRegistrar.unregister(); }, }; }); From f0aaf1a52f4086a211e1e7a25b9061e745c534bb Mon Sep 17 00:00:00 2001 From: EMERALD Date: Tue, 23 Aug 2022 17:51:33 -0500 Subject: [PATCH 02/12] Update package and plugin JSONs --- package.json | 2 +- plugin.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 77bc3dc..7eb223d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "SDH-AudioLoader", - "version": "1.0.1", + "version": "1.1.0", "description": "Replaces and adds Steam Deck game UI sounds", "scripts": { "build": "shx rm -rf dist && rollup -c", diff --git a/plugin.json b/plugin.json index cf2536a..bd1e3be 100644 --- a/plugin.json +++ b/plugin.json @@ -4,7 +4,7 @@ "flags": ["debug", "_root"], "publish": { "tags": ["style", "media", "music"], - "description": "Replaces Steam UI sound effects with custom sounds.", + "description": "Replaces Steam UI sound effects with custom sounds and adds music to menus.", "image": "https://i.imgur.com/0Xuc1pr.png" } } From b3391d30e28f81c26a8e34597f590cce36a01fa5 Mon Sep 17 00:00:00 2001 From: EMERALD Date: Tue, 23 Aug 2022 21:08:39 -0500 Subject: [PATCH 03/12] Add support for music on startup --- src/index.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/index.tsx b/src/index.tsx index 51cffd7..5d39535 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -214,6 +214,7 @@ export default definePlugin((serverApi: ServerAPI) => { python.setServer(serverApi); const state: GlobalState = new GlobalState(); + let menuMusic: any = null; beforePatch( AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, @@ -290,6 +291,15 @@ export default definePlugin((serverApi: ServerAPI) => { )); + // Play menu music when starting plugin as this shouldn't happen inside of game + // TODO: Add check if game is currently running + menuMusic = + AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( + "/sounds_custom/saul.mp3", + 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk + ); + console.log(menuMusic); + return { title:
Audio Loader
, content: ( @@ -299,6 +309,11 @@ export default definePlugin((serverApi: ServerAPI) => { ), icon: , onDismount: () => { + if (menuMusic != null) { + menuMusic.StopPlayback(); + menuMusic = null; + } + unpatch(Router, "OpenSideMenu"); unpatch(Router, "CloseSideMenus"); unpatch( From 8bcdb59d19ddd8ccebb1b0e59e8cbc9566a56ad0 Mon Sep 17 00:00:00 2001 From: EMERALD Date: Tue, 23 Aug 2022 21:28:56 -0500 Subject: [PATCH 04/12] Add start/stop menu music based on game --- src/index.tsx | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 5d39535..abc3396 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -215,6 +215,7 @@ export default definePlugin((serverApi: ServerAPI) => { const state: GlobalState = new GlobalState(); let menuMusic: any = null; + let gamesRunning: Number[] = []; beforePatch( AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, @@ -261,9 +262,23 @@ export default definePlugin((serverApi: ServerAPI) => { // Refer to the SteamClient.d.ts or just console.log(SteamClient) to see all of it's methods SteamClient.GameSessions.RegisterForAppLifetimeNotifications( (update: AppState) => { - update.bRunning - ? console.log("GAME HAS BEEN STARTED") - : console.log("GAME HAS BEEN STOPPED"); + if (update.bRunning) { + gamesRunning.push(update.unAppID); + if (menuMusic != null) { + menuMusic.StopPlayback(); + menuMusic = null; + } + } else { + for (let i = gamesRunning.length; i >= 0; i--) { + if (gamesRunning[i] === update.unAppID) gamesRunning.splice(i, 1); + } + if (gamesRunning.length === 0) + menuMusic = + AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( + "/sounds_custom/saul.mp3", + 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk + ); + } } ); @@ -298,7 +313,6 @@ export default definePlugin((serverApi: ServerAPI) => { "/sounds_custom/saul.mp3", 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk ); - console.log(menuMusic); return { title:
Audio Loader
, From d94dde9523aaa094e9ebadfa4cc3ad12715fe83e Mon Sep 17 00:00:00 2001 From: beebls Date: Tue, 23 Aug 2022 23:07:58 -0600 Subject: [PATCH 05/12] Initial working music selector (multi-layered and buggy) --- main.py | 15 ++- src/index.tsx | 159 +++++++++++++++++++---------- src/pack-manager/UninstallPage.tsx | 21 ++-- src/state/GlobalState.tsx | 41 ++++---- 4 files changed, 146 insertions(+), 90 deletions(-) diff --git a/main.py b/main.py index 6423b50..7dd7857 100644 --- a/main.py +++ b/main.py @@ -4,9 +4,8 @@ from logging import getLogger starter_config_data = { - "music_enabled": False, - "music_library_only": False, - "selected_pack": "Default" + "selected_pack": "Default", + "selected_music": "None" } starter_config_string = json.dumps(starter_config_data) @@ -220,9 +219,8 @@ async def parse_packs(self, packsDir : str): packData = Pack(packPath, pack) if (packData.name not in [p.name for p in self.soundPacks]): - if (packData.music == False): - self.soundPacks.append(packData) - Log("Audio Loader - Sound pack {} added".format(packData.name)) + self.soundPacks.append(packData) + Log("Audio Loader - Sound pack {} added".format(packData.name)) except Exception as e: Log("Audio Loader - Error parsing sound pack: {}".format(e)) @@ -254,9 +252,8 @@ async def _load(self): async def _main(self): self.soundPacks = [] self.config = { - "music_enabled": False, - "music_library_only": False, - "selected_pack": "Default" + "selected_pack": "Default", + "selected_music": "None" } self.remote = RemoteInstall(self) diff --git a/src/index.tsx b/src/index.tsx index abc3396..34524a5 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -9,7 +9,6 @@ import { Router, beforePatch, unpatch, - ToggleField, SidebarNavigation, } from "decky-frontend-lib"; import { VFC, useMemo, useEffect, useState } from "react"; @@ -29,10 +28,10 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { setActiveSound, soundPacks, setSoundPacks, - musicEnabled, - setMusicEnabled, - musicLibraryOnly, - setMusicLibraryOnly, + menuMusic, + setMenuMusic, + selectedMusic, + setSelectedMusic, } = useGlobalState(); const [dummyFuncResult, setDummyResult] = useState(false); @@ -45,6 +44,24 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { dummyFuncTest(); }, []); + function restartMusicPlayer(newMusic: string) { + console.log(newMusic, menuMusic); + if (menuMusic !== null) { + menuMusic.StopPlayback(); + } + if (newMusic === "None") { + setMenuMusic(null); + } else { + const currentPack = soundPacks.find((e) => e.name === newMusic); + const newMenuMusic = + AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( + `/sounds_custom/${currentPack?.path || "/error"}/menu_music.mp3`, + 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk + ); + setMenuMusic(newMenuMusic); + } + } + function reloadPlugin() { dummyFuncTest(); python.resolve(python.reloadPacksDir(), () => { @@ -56,10 +73,11 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { python.resolve(python.getConfig(), (data: any) => { // This just has fallbacks incase the fetch fails or the config is improperly formatted setActiveSound(data?.selected_pack || "Default"); - setMusicEnabled(data?.music_enabled || false); - setMusicLibraryOnly(data?.music_library_only || false); + setSelectedMusic(data?.selected_music || "None"); }); + restartMusicPlayer(selectedMusic); + unpatch( AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, "PlayAudioURL" @@ -96,6 +114,20 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { return [ { label: "Default", data: -1 }, ...soundPacks + // Only shows sound packs + .filter((e) => !e.data.music) + .map((p, index) => ({ label: p.name, data: index })) + // TODO: because this sorts after assigning indexes, the sort might make the indexes out of order, make sure this doesn't happen + .sort((a, b) => a.label.localeCompare(b.label)), + ]; + }, [soundPacks]); + + const MusicPackDropdownOptions = useMemo(() => { + return [ + { label: "None", data: -1 }, + ...soundPacks + // Only show music packs + .filter((e) => e.data.music) .map((p, index) => ({ label: p.name, data: index })) // TODO: because this sorts after assigning indexes, the sort might make the indexes out of order, make sure this doesn't happen .sort((a, b) => a.label.localeCompare(b.label)), @@ -133,9 +165,8 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { setActiveSound(option.label); const configObj = { - music_enabled: musicEnabled, - music_library_only: musicLibraryOnly, selected_pack: option.label, + selected_music: selectedMusic, }; python.setConfig(configObj); }} @@ -146,23 +177,25 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { bottomSeparator={false} label="Music" menuLabel="Music" - rgOptions={[{ label: "Coming Soon", data: 0 }]} - selectedOption={0} - disabled={true} + rgOptions={MusicPackDropdownOptions} + selectedOption={ + MusicPackDropdownOptions.find((e) => e.label === selectedMusic) + ?.data ?? -1 + } + onChange={async (option) => { + setSelectedMusic(option.label); + + const configObj = { + selected_pack: activeSound, + selected_music: option.label, + }; + python.setConfig(configObj); + restartMusicPlayer(option.label); + }} /> - - - - - { } ); - // For some reason when I didn't make these arrow functions they gave me "can't set property of undefined errors", so just leave them as arrow functions - python.resolve(python.getSoundPacks(), (data: any) => { - state.setSoundPacks(data); - }); - python.resolve(python.getConfig(), (data: any) => { - // This just has fallbacks incase the fetch fails or the config is improperly formatted - state.setActiveSound(data?.selected_pack || "Default"); - state.setMusicEnabled(data?.music_enabled || false); - state.setMusicLibraryOnly(data?.music_library_only || false); + python.resolve(python.getSoundPacks(), (packs: any) => { + state.setSoundPacks(packs); + // This is nested in here so that all data has loaded before it attempts to find audio paths + python.resolve(python.getConfig(), (data: any) => { + // This sets the config data in globalState + state.setActiveSound(data?.selected_pack || "Default"); + const configSelectedMusic = data?.selected_music || "None"; + state.setSelectedMusic(configSelectedMusic); + + // Plays menu music initially + // TODO: Add check if game is currently running + if (configSelectedMusic !== "None") { + const { soundPacks } = state.getPublicState(); + const currentPack = soundPacks.find( + (e) => e.name === configSelectedMusic + ); + menuMusic = + AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( + `/sounds_custom/${currentPack?.path || "/error"}/menu_music.mp3`, + 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk + ); + state.setMenuMusic(menuMusic); + } + }); }); const AppStateRegistrar = @@ -262,22 +310,33 @@ export default definePlugin((serverApi: ServerAPI) => { // Refer to the SteamClient.d.ts or just console.log(SteamClient) to see all of it's methods SteamClient.GameSessions.RegisterForAppLifetimeNotifications( (update: AppState) => { - if (update.bRunning) { - gamesRunning.push(update.unAppID); - if (menuMusic != null) { - menuMusic.StopPlayback(); - menuMusic = null; - } - } else { - for (let i = gamesRunning.length; i >= 0; i--) { - if (gamesRunning[i] === update.unAppID) gamesRunning.splice(i, 1); - } - if (gamesRunning.length === 0) - menuMusic = - AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( - "/sounds_custom/saul.mp3", - 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk + const { soundPacks, menuMusic, selectedMusic } = state.getPublicState(); + if (selectedMusic !== "None") { + if (update.bRunning) { + gamesRunning.push(update.unAppID); + if (menuMusic != null) { + menuMusic.StopPlayback(); + state.setMenuMusic(null); + } + } else { + for (let i = gamesRunning.length; i >= 0; i--) { + if (gamesRunning[i] === update.unAppID) gamesRunning.splice(i, 1); + } + if (gamesRunning.length === 0) { + const currentMusic = soundPacks.find( + (e) => e.name === selectedMusic ); + const newMenuMusic = + AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( + `/sounds_custom/${ + currentMusic?.path || "/error" + }/menu_music.mp3`, + 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk + ); + // You need to update menuMusic in globalState after every change so that it reflects the changes the next time it checks + state.setMenuMusic(newMenuMusic); + } + } } } ); @@ -306,14 +365,6 @@ export default definePlugin((serverApi: ServerAPI) => { )); - // Play menu music when starting plugin as this shouldn't happen inside of game - // TODO: Add check if game is currently running - menuMusic = - AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( - "/sounds_custom/saul.mp3", - 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk - ); - return { title:
Audio Loader
, content: ( diff --git a/src/pack-manager/UninstallPage.tsx b/src/pack-manager/UninstallPage.tsx index 8f15aaa..b8dfcaa 100644 --- a/src/pack-manager/UninstallPage.tsx +++ b/src/pack-manager/UninstallPage.tsx @@ -12,8 +12,10 @@ export const UninstallPage: VFC = () => { setSoundPacks, activeSound, setActiveSound, - musicEnabled, - musicLibraryOnly, + selectedMusic, + setSelectedMusic, + menuMusic, + setMenuMusic, } = useGlobalState(); const [isUninstalling, setUninstalling] = useState(false); @@ -30,15 +32,22 @@ export const UninstallPage: VFC = () => { setUninstalling(true); python.resolve(python.deletePack(listEntry.data.name), () => { fetchLocalPacks(); - if (activeSound === listEntry.data.name) { + if ( + activeSound === listEntry.data.name || + selectedMusic === listEntry.data.name + ) { console.log( - "Audio Loader - Attempted to uninstall applied sound, changing applied sound to Default" + "Audio Loader - Attempted to uninstall applied sound/music, changing applied packs to Default" ); setActiveSound("Default"); + setSelectedMusic("None"); + if (menuMusic !== null) { + menuMusic.StopPlayback(); + setMenuMusic(null); + } const configObj = { - music_enabled: musicEnabled, - music_library_only: musicLibraryOnly, selected_pack: "Default", + selected_music: "None", }; python.setConfig(configObj); } diff --git a/src/state/GlobalState.tsx b/src/state/GlobalState.tsx index cbd91cb..0a3e9a2 100644 --- a/src/state/GlobalState.tsx +++ b/src/state/GlobalState.tsx @@ -3,10 +3,10 @@ import { createContext, FC, useContext, useEffect, useState } from "react"; import { Pack, packDbEntry } from "../classes"; interface PublicGlobalState { + menuMusic: any; activeSound: string; soundPacks: Pack[]; - musicEnabled: boolean; - musicLibraryOnly: boolean; + selectedMusic: string; browserPackList: packDbEntry[]; searchFieldValue: string; selectedSort: number; @@ -17,10 +17,10 @@ interface PublicGlobalState { // The localThemeEntry interface refers to the theme data as given by the python function, the Theme class refers to a theme after it has been formatted and the generate function has been added interface PublicGlobalStateContext extends PublicGlobalState { + setMenuMusic(value: any): void; setActiveSound(value: string): void; setSoundPacks(packArr: Pack[]): void; - setMusicEnabled(value: boolean): void; - setMusicLibraryOnly(value: boolean): void; + setSelectedMusic(value: string): void; setBrowserPackList(packArr: packDbEntry[]): void; setSearchValue(value: string): void; setSort(value: number): void; @@ -30,10 +30,10 @@ interface PublicGlobalStateContext extends PublicGlobalState { // This class creates the getter and setter functions for all of the global state data. export class GlobalState { + private menuMusic: any = null; private activeSound: string = "Default"; private soundPacks: Pack[] = []; - private musicEnabled: boolean = false; - private musicLibraryOnly: boolean = false; + private selectedMusic: string = "None"; private browserPackList: packDbEntry[] = []; private searchFieldValue: string = ""; private selectedSort: number = 3; @@ -48,10 +48,10 @@ export class GlobalState { getPublicState() { return { + menuMusic: this.menuMusic, activeSound: this.activeSound, soundPacks: this.soundPacks, - musicEnabled: this.musicEnabled, - musicLibraryOnly: this.musicLibraryOnly, + selectedMusic: this.selectedMusic, browserPackList: this.browserPackList, searchFieldValue: this.searchFieldValue, selectedSort: this.selectedSort, @@ -60,6 +60,11 @@ export class GlobalState { }; } + setMenuMusic(value: any) { + this.menuMusic = value; + this.forceUpdate; + } + setActiveSound(value: string) { this.activeSound = value; this.forceUpdate(); @@ -79,13 +84,8 @@ export class GlobalState { this.forceUpdate(); } - setMusicEnabled(value: boolean) { - this.musicEnabled = value; - this.forceUpdate(); - } - - setMusicLibraryOnly(value: boolean) { - this.musicLibraryOnly = value; + setSelectedMusic(value: string) { + this.selectedMusic = value; this.forceUpdate(); } @@ -146,14 +146,13 @@ export const GlobalStateContextProvider: FC = ({ globalStateClass.eventBus.removeEventListener("stateUpdate", onUpdate); }, []); + const setMenuMusic = (value: any) => globalStateClass.setMenuMusic(value); const setActiveSound = (value: string) => globalStateClass.setActiveSound(value); const setSoundPacks = (packArr: Pack[]) => globalStateClass.setSoundPacks(packArr); - const setMusicEnabled = (value: boolean) => - globalStateClass.setMusicEnabled(value); - const setMusicLibraryOnly = (value: boolean) => - globalStateClass.setMusicLibraryOnly(value); + const setSelectedMusic = (value: string) => + globalStateClass.setSelectedMusic(value); const setBrowserPackList = (packArr: packDbEntry[]) => globalStateClass.setBrowserPackList(packArr); const setSearchValue = (value: string) => @@ -167,10 +166,10 @@ export const GlobalStateContextProvider: FC = ({ Date: Wed, 24 Aug 2022 01:30:49 -0500 Subject: [PATCH 06/12] Various bug fixes --- src/index.tsx | 27 +++------------------------ src/pack-manager/UninstallPage.tsx | 18 +++++++++++------- src/state/GlobalState.tsx | 2 +- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 34524a5..b3f5b58 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -45,13 +45,12 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { }, []); function restartMusicPlayer(newMusic: string) { - console.log(newMusic, menuMusic); + console.log(menuMusic, newMusic); if (menuMusic !== null) { menuMusic.StopPlayback(); - } - if (newMusic === "None") { setMenuMusic(null); - } else { + } + if (newMusic !== "None") { const currentPack = soundPacks.find((e) => e.name === newMusic); const newMenuMusic = AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( @@ -341,24 +340,6 @@ export default definePlugin((serverApi: ServerAPI) => { } ); - // This variable is used to debounce these, as they tend to get called multiple times and I don't want stacked audio - let sideMenuOpen = false; - beforePatch(Router, "OpenSideMenu", (args) => { - if (!sideMenuOpen) { - sideMenuOpen = true; - // AudioParent.GamepadUIAudio.PlayAudioURL("/sounds_custom/drip.wav"); we might not use PlayAudioURL but this is where you would call it for QAM music - console.log("Side Menu Opened"); - } - return args; - }); - beforePatch(Router, "CloseSideMenus", (args) => { - if (sideMenuOpen) { - sideMenuOpen = false; - console.log("Side Menu Closed"); - } - return args; - }); - serverApi.routerHook.addRoute("/audiopack-manager", () => ( @@ -379,8 +360,6 @@ export default definePlugin((serverApi: ServerAPI) => { menuMusic = null; } - unpatch(Router, "OpenSideMenu"); - unpatch(Router, "CloseSideMenus"); unpatch( AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, "PlayAudioURL" diff --git a/src/pack-manager/UninstallPage.tsx b/src/pack-manager/UninstallPage.tsx index b8dfcaa..f193674 100644 --- a/src/pack-manager/UninstallPage.tsx +++ b/src/pack-manager/UninstallPage.tsx @@ -39,15 +39,19 @@ export const UninstallPage: VFC = () => { console.log( "Audio Loader - Attempted to uninstall applied sound/music, changing applied packs to Default" ); - setActiveSound("Default"); - setSelectedMusic("None"); - if (menuMusic !== null) { - menuMusic.StopPlayback(); - setMenuMusic(null); + if (activeSound === listEntry.data.name) setActiveSound("Default"); + if (selectedMusic === listEntry.data.name) { + setSelectedMusic("None"); + if (menuMusic !== null) { + menuMusic.StopPlayback(); + setMenuMusic(null); + } } const configObj = { - selected_pack: "Default", - selected_music: "None", + selected_pack: + activeSound === listEntry.data.name ? "Default" : activeSound, + selected_music: + selectedMusic === listEntry.data.name ? "None" : activeSound, }; python.setConfig(configObj); } diff --git a/src/state/GlobalState.tsx b/src/state/GlobalState.tsx index 0a3e9a2..5a1962d 100644 --- a/src/state/GlobalState.tsx +++ b/src/state/GlobalState.tsx @@ -62,7 +62,7 @@ export class GlobalState { setMenuMusic(value: any) { this.menuMusic = value; - this.forceUpdate; + this.forceUpdate(); } setActiveSound(value: string) { From 8c54d518ecff5fcd50132ef729a860327f6e4f13 Mon Sep 17 00:00:00 2001 From: EMERALD Date: Thu, 25 Aug 2022 17:52:25 -0500 Subject: [PATCH 07/12] Fix #5 --- src/pack-manager/UninstallPage.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pack-manager/UninstallPage.tsx b/src/pack-manager/UninstallPage.tsx index f193674..a0869ed 100644 --- a/src/pack-manager/UninstallPage.tsx +++ b/src/pack-manager/UninstallPage.tsx @@ -62,9 +62,7 @@ export const UninstallPage: VFC = () => { if (soundPacks.length === 0) { return ( - - No custom themes installed, find some in the 'Browse Themes' tab. - + No packs installed, find some in the 'Browse Packs' tab. ); } From c874295a8362d0a91b34a6a47c23bd2784a5cc2e Mon Sep 17 00:00:00 2001 From: EMERALD Date: Thu, 25 Aug 2022 17:55:47 -0500 Subject: [PATCH 08/12] Change no description styling --- src/pack-manager/PackBrowserPage.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pack-manager/PackBrowserPage.tsx b/src/pack-manager/PackBrowserPage.tsx index 87edfa9..fde4c9a 100644 --- a/src/pack-manager/PackBrowserPage.tsx +++ b/src/pack-manager/PackBrowserPage.tsx @@ -320,7 +320,9 @@ export const PackBrowserPage: VFC = () => { e.description ) : ( - No Description Provided + + No description provided. + )} From f11e55c4b369d5148dc6758b2d5c22837a933d74 Mon Sep 17 00:00:00 2001 From: beebls Date: Fri, 26 Aug 2022 19:38:21 -0600 Subject: [PATCH 09/12] Fix PackDb not reloading at all. I can't test it yet as there are no changes to the Db to reflect, but it now properly fetches, stores, and re-renders everything upon loading and hitting reload. --- src/index.tsx | 1 - src/pack-manager/PackBrowserPage.tsx | 15 +++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index b3f5b58..c3b7d97 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -45,7 +45,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { }, []); function restartMusicPlayer(newMusic: string) { - console.log(menuMusic, newMusic); if (menuMusic !== null) { menuMusic.StopPlayback(); setMenuMusic(null); diff --git a/src/pack-manager/PackBrowserPage.tsx b/src/pack-manager/PackBrowserPage.tsx index fde4c9a..edd7b03 100644 --- a/src/pack-manager/PackBrowserPage.tsx +++ b/src/pack-manager/PackBrowserPage.tsx @@ -30,12 +30,15 @@ export const PackBrowserPage: VFC = () => { } = useGlobalState(); async function fetchPackDb() { - const response = await python.fetchPackDb(); - if (response.success) { - setBrowserPackList(JSON.parse(response.result.body)); - } else { - console.log("AudioLoader - Fetching PackDb Failed"); - } + python.resolve(python.fetchPackDb(), (response: any) => { + if (response.body) { + setBrowserPackList(JSON.parse(response.body)); + } else { + console.log( + "AudioLoader - Fetching PackDb Failed, no json string was returned by the fetch" + ); + } + }); } function fetchLocalPacks() { From d77f8bc6836fc35d945a45788b418df3ffe12a33 Mon Sep 17 00:00:00 2001 From: EMERALD Date: Sat, 27 Aug 2022 13:16:13 -0500 Subject: [PATCH 10/12] Update pack browser to 1.1.0 standards --- src/pack-manager/PackBrowserPage.tsx | 4 +++- src/python.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pack-manager/PackBrowserPage.tsx b/src/pack-manager/PackBrowserPage.tsx index edd7b03..587e9db 100644 --- a/src/pack-manager/PackBrowserPage.tsx +++ b/src/pack-manager/PackBrowserPage.tsx @@ -65,7 +65,9 @@ export const PackBrowserPage: VFC = () => { // This checks for the theme name !e.name.toLowerCase().includes(searchFieldValue.toLowerCase()) && // This checks for the author name - !e.author.toLowerCase().includes(searchFieldValue.toLowerCase()) + !e.author.toLowerCase().includes(searchFieldValue.toLowerCase()) && + // This checks for the description + !e.description.toLowerCase().includes(searchFieldValue.toLowerCase()) ) { // return false just means it won't show in the list return false; diff --git a/src/python.ts b/src/python.ts index 8f07ad3..4c23add 100644 --- a/src/python.ts +++ b/src/python.ts @@ -32,7 +32,7 @@ export function setServer(s: ServerAPI) { export async function fetchPackDb(): Promise { return server!.fetchNoCors( - "https://github.com/EMERALD0874/AudioLoader-PackDB/releases/download/1.0.0/packs.json", + "https://github.com/EMERALD0874/AudioLoader-PackDB/releases/download/1.1.0/packs.json", { method: "GET" } ); } From 2b758d5d22926cca517e9d47cda13e1f1d6985a9 Mon Sep 17 00:00:00 2001 From: beebls Date: Sat, 27 Aug 2022 15:17:27 -0600 Subject: [PATCH 11/12] Move gamesRunning to globalstate Now music no longer plays if you change packs while in game --- src/index.tsx | 23 ++++++++++++++--------- src/state/GlobalState.tsx | 12 ++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index c3b7d97..9608148 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -25,6 +25,7 @@ import { const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { const { activeSound, + gamesRunning, setActiveSound, soundPacks, setSoundPacks, @@ -49,7 +50,8 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { menuMusic.StopPlayback(); setMenuMusic(null); } - if (newMusic !== "None") { + // This makes sure if you are in a game, music doesn't start playing + if (newMusic !== "None" && gamesRunning.length === 0) { const currentPack = soundPacks.find((e) => e.name === newMusic); const newMenuMusic = AudioParent.GamepadUIAudio.AudioPlaybackManager.PlayAudioURLWithRepeats( @@ -246,7 +248,6 @@ export default definePlugin((serverApi: ServerAPI) => { const state: GlobalState = new GlobalState(); let menuMusic: any = null; - let gamesRunning: Number[] = []; beforePatch( AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, @@ -308,19 +309,23 @@ export default definePlugin((serverApi: ServerAPI) => { // Refer to the SteamClient.d.ts or just console.log(SteamClient) to see all of it's methods SteamClient.GameSessions.RegisterForAppLifetimeNotifications( (update: AppState) => { - const { soundPacks, menuMusic, selectedMusic } = state.getPublicState(); + const { soundPacks, menuMusic, selectedMusic, gamesRunning } = + state.getPublicState(); if (selectedMusic !== "None") { if (update.bRunning) { - gamesRunning.push(update.unAppID); + // Because gamesRunning is in globalState, array methods like push and splice don't work + state.setGamesRunning([...gamesRunning, update.unAppID]); if (menuMusic != null) { menuMusic.StopPlayback(); state.setMenuMusic(null); } } else { - for (let i = gamesRunning.length; i >= 0; i--) { - if (gamesRunning[i] === update.unAppID) gamesRunning.splice(i, 1); - } - if (gamesRunning.length === 0) { + state.setGamesRunning( + gamesRunning.filter((e) => e !== update.unAppID) + ); + + // I'm re-using the filter here because I don't believe the getPublicState() method will update the values if they are changed + if (gamesRunning.filter((e) => e !== update.unAppID).length === 0) { const currentMusic = soundPacks.find( (e) => e.name === selectedMusic ); @@ -331,7 +336,7 @@ export default definePlugin((serverApi: ServerAPI) => { }/menu_music.mp3`, 999 // if someone complains this isn't infinite, just say it's a Feature™ for if you go afk ); - // You need to update menuMusic in globalState after every change so that it reflects the changes the next time it checks + // Update menuMusic in globalState after every change so that it reflects the changes the next time it checks state.setMenuMusic(newMenuMusic); } } diff --git a/src/state/GlobalState.tsx b/src/state/GlobalState.tsx index 5a1962d..418b6f6 100644 --- a/src/state/GlobalState.tsx +++ b/src/state/GlobalState.tsx @@ -4,6 +4,7 @@ import { Pack, packDbEntry } from "../classes"; interface PublicGlobalState { menuMusic: any; + gamesRunning: Number[]; activeSound: string; soundPacks: Pack[]; selectedMusic: string; @@ -18,6 +19,7 @@ interface PublicGlobalState { interface PublicGlobalStateContext extends PublicGlobalState { setMenuMusic(value: any): void; + setGamesRunning(gameArr: Number[]): void; setActiveSound(value: string): void; setSoundPacks(packArr: Pack[]): void; setSelectedMusic(value: string): void; @@ -31,6 +33,7 @@ interface PublicGlobalStateContext extends PublicGlobalState { // This class creates the getter and setter functions for all of the global state data. export class GlobalState { private menuMusic: any = null; + private gamesRunning: Number[] = []; private activeSound: string = "Default"; private soundPacks: Pack[] = []; private selectedMusic: string = "None"; @@ -49,6 +52,7 @@ export class GlobalState { getPublicState() { return { menuMusic: this.menuMusic, + gamesRunning: this.gamesRunning, activeSound: this.activeSound, soundPacks: this.soundPacks, selectedMusic: this.selectedMusic, @@ -65,6 +69,11 @@ export class GlobalState { this.forceUpdate(); } + setGamesRunning(gameArr: Number[]) { + this.gamesRunning = gameArr; + this.forceUpdate(); + } + setActiveSound(value: string) { this.activeSound = value; this.forceUpdate(); @@ -147,6 +156,8 @@ export const GlobalStateContextProvider: FC = ({ }, []); const setMenuMusic = (value: any) => globalStateClass.setMenuMusic(value); + const setGamesRunning = (gameArr: Number[]) => + globalStateClass.setGamesRunning(gameArr); const setActiveSound = (value: string) => globalStateClass.setActiveSound(value); const setSoundPacks = (packArr: Pack[]) => @@ -167,6 +178,7 @@ export const GlobalStateContextProvider: FC = ({ value={{ ...publicState, setMenuMusic, + setGamesRunning, setActiveSound, setSoundPacks, setSelectedMusic, From e8af9d47ae23ca445c0258087d93f49a3fe80cde Mon Sep 17 00:00:00 2001 From: EMERALD Date: Sat, 27 Aug 2022 16:34:53 -0500 Subject: [PATCH 12/12] Remove deprecated reload plugin button --- src/index.tsx | 58 --------------------------------------------------- 1 file changed, 58 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 9608148..a1516dc 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -28,7 +28,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { gamesRunning, setActiveSound, soundPacks, - setSoundPacks, menuMusic, setMenuMusic, selectedMusic, @@ -62,54 +61,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { } } - function reloadPlugin() { - dummyFuncTest(); - python.resolve(python.reloadPacksDir(), () => { - python.resolve(python.getSoundPacks(), (data: any) => { - setSoundPacks(data); - }); - }); - - python.resolve(python.getConfig(), (data: any) => { - // This just has fallbacks incase the fetch fails or the config is improperly formatted - setActiveSound(data?.selected_pack || "Default"); - setSelectedMusic(data?.selected_music || "None"); - }); - - restartMusicPlayer(selectedMusic); - - unpatch( - AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, - "PlayAudioURL" - ); - - beforePatch( - AudioParent.GamepadUIAudio.m_AudioPlaybackManager.__proto__, - "PlayAudioURL", - (args) => { - let newSoundURL: string = ""; - switch (activeSound) { - case "Default": - newSoundURL = args[0]; - break; - default: - const currentPack = soundPacks.find((e) => e.name === activeSound); - if (currentPack?.ignore.includes(args[0].slice(8))) { - newSoundURL = args[0]; - break; - } - newSoundURL = args[0].replace( - "sounds/", - `sounds_custom/${currentPack?.path || "/error"}/` - ); - break; - } - args[0] = newSoundURL; - return [newSoundURL]; - } - ); - } - const SoundPackDropdownOptions = useMemo(() => { return [ { label: "Default", data: -1 }, @@ -208,15 +159,6 @@ const Content: VFC<{ serverAPI: ServerAPI }> = ({}) => { Manage Packs
- - reloadPlugin()} - > - Reload Plugin - -
);