Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of BetterJukeboxIL2CPP v1.0.1
Mods/BetterJukebox_Il2CPP.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading; using AudioImportLib; using BetterJukebox; using BetterJukebox.Config; using BetterJukebox.Models; using BetterJukebox.Patches; using BetterJukebox.Services; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.InteropTypes; using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppScheduleOne.ObjectScripts; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.Reflection; using Il2CppTMPro; using MelonLoader; using MelonLoader.Preferences; using MelonLoader.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(Core), "BetterJukebox", "1.0.0", "Bars", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("BetterJukebox_Il2CPP")] [assembly: AssemblyConfiguration("IL2CPP")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BetterJukebox_Il2CPP")] [assembly: AssemblyTitle("BetterJukebox_Il2CPP")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BetterJukebox { public class Core : MelonMod { [CompilerGenerated] private sealed class <CheckSavedJukeboxes>d__20 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Core <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckSavedJukeboxes>d__20(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this._config.LogDebug("Waiting for scene to stabilize before checking for saved jukeboxes..."); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this._config.LogDebug("Beginning saved jukebox detection process..."); <>2__current = <>4__this._jukeboxPatcher.CheckForSavedJukeboxes(); <>1__state = 2; return true; case 2: <>1__state = -1; <>2__current = <>4__this._paginationManager.CheckForSavedJukeboxInterfaces(); <>1__state = 3; return true; case 3: <>1__state = -1; MelonCoroutines.Start(<>4__this.FinalJukeboxCheck()); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <FinalJukeboxCheck>d__21 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Core <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FinalJukeboxCheck>d__21(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(5f); <>1__state = 1; return true; case 1: <>1__state = -1; <>4__this._config.LogDebug("Performing final jukebox check..."); <>2__current = <>4__this._jukeboxPatcher.ScanForJukeboxes(repeat: false); <>1__state = 2; return true; case 2: <>1__state = -1; <>4__this._paginationManager.CheckForUnpatchedInterfaces(); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <InitializationSequence>d__15 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Core <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <InitializationSequence>d__15(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; <>4__this._config.LogDebug("Starting initialization sequence"); MelonPreferences_Entry<bool> showLoadingIndicator = <>4__this._config.ShowLoadingIndicator; if (showLoadingIndicator != null && showLoadingIndicator.Value) { <>4__this.CreateLoadingIndicator(); } <>2__current = <>4__this._trackManager.LoadAudioFiles(); <>1__state = 1; return true; } case 1: <>1__state = -1; if ((Object)(object)<>4__this._loadingIndicator != (Object)null) { Object.Destroy((Object)(object)<>4__this._loadingIndicator); <>4__this._loadingIndicator = null; <>4__this._loadingText = null; } if (<>4__this._trackManager.TracksLoaded) { <>4__this._harmonyPatches.SetupPatches(); <>4__this._patchesApplied = true; <>4__this._config.LogDebug("Harmony patches applied"); } <>4__this._initialLoadComplete = true; <>4__this._config.LogDebug("Initial loading sequence complete"); <>2__current = <>4__this.ScanCurrentScene(); <>1__state = 2; return true; case 2: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LoadAndPlayTrack>d__29 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Jukebox jukebox; public int trackID; public Track track; public Action<bool> onComplete; public Core <>4__this; private Exception <ex>5__1; private bool <playSuccess>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAndPlayTrack>d__29(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <ex>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = <>4__this._trackManager.EnsureTrackLoaded(track); <>1__state = 1; return true; case 1: <>1__state = -1; if ((Object)(object)track.Clip == (Object)null) { <>4__this._config.LogDebug("Failed to load track " + track.TrackName); onComplete?.Invoke(obj: false); return false; } <>4__this._config.LogDebug("Track loaded successfully, preparing to play: " + track.TrackName); <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 2; return true; case 2: <>1__state = -1; try { <>4__this._config.LogDebug($"Calling jukebox.PlayTrack({trackID}) directly"); jukebox.PlayTrack(trackID); <>4__this._config.LogDebug("Successfully played track " + track.TrackName); onComplete?.Invoke(obj: true); } catch (Exception ex) { <ex>5__1 = ex; <>4__this._config.LogDebug("Failed to play via PlayTrack method, attempting fallback: " + <ex>5__1.Message); <playSuccess>5__2 = <>4__this._jukeboxPatcher.ForcePlayTrack(jukebox, trackID); <>4__this._config.LogDebug($"Fallback attempt to play track {track.TrackName} result: {<playSuccess>5__2}"); onComplete?.Invoke(<playSuccess>5__2); } return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ScanCurrentScene>d__18 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Core <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ScanCurrentScene>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this._trackManager.TracksLoaded) { <>4__this._config.LogDebug("Scanning current scene for jukeboxes"); <>2__current = <>4__this._jukeboxPatcher.ScanForJukeboxes(repeat: false); <>1__state = 1; return true; } break; case 1: <>1__state = -1; <>4__this._paginationManager.CheckForUnpatchedInterfaces(); break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <UpdateLoadingProgress>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Core <>4__this; private int <percentage>5__1; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <UpdateLoadingProgress>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)<>4__this._loadingIndicator != (Object)null && (Object)(object)<>4__this._loadingText != (Object)null) { if (<>4__this._trackManager != null) { <percentage>5__1 = Mathf.RoundToInt(<>4__this._trackManager.LoadingProgress * 100f); ((TMP_Text)<>4__this._loadingText).text = $"BetterJukebox: Loading songs... {<percentage>5__1}%"; } <>2__current = (object)new WaitForSeconds(0.1f); <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Core _instance; private ModConfig _config; private TrackManager _trackManager; private JukeboxPatcher _jukeboxPatcher; private PaginationManager _paginationManager; private HarmonyPatches _harmonyPatches; private object _scanCoroutine; private bool _patchesApplied; private bool _initialLoadComplete; private GameObject _loadingIndicator; private TextMeshProUGUI _loadingText; private string CustomSongsFolder => Path.Combine(MelonEnvironment.ModsDirectory, "BetterJukebox"); public override void OnInitializeMelon() { _instance = this; InitializeServices(); MelonCoroutines.Start(InitializationSequence()); } private void InitializeServices() { _config = new ModConfig(); _config.Initialize(); _trackManager = new TrackManager(_config, CustomSongsFolder); _jukeboxPatcher = new JukeboxPatcher(_config, _trackManager); _paginationManager = new PaginationManager(_config, _jukeboxPatcher); _harmonyPatches = new HarmonyPatches(_jukeboxPatcher, _paginationManager, _trackManager); } [IteratorStateMachine(typeof(<InitializationSequence>d__15))] private IEnumerator InitializationSequence() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <InitializationSequence>d__15(0) { <>4__this = this }; } private void CreateLoadingIndicator() { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) try { _loadingIndicator = new GameObject("BetterJukeboxLoadingIndicator"); Canvas val = _loadingIndicator.AddComponent<Canvas>(); val.renderMode = (RenderMode)0; val.sortingOrder = 9999; CanvasScaler val2 = _loadingIndicator.AddComponent<CanvasScaler>(); val2.uiScaleMode = (ScaleMode)1; val2.referenceResolution = new Vector2(1920f, 1080f); GameObject val3 = new GameObject("Panel"); val3.transform.SetParent(((Component)val).transform, false); RectTransform val4 = val3.AddComponent<RectTransform>(); val4.anchorMin = new Vector2(1f, 0f); val4.anchorMax = new Vector2(1f, 0f); val4.pivot = new Vector2(1f, 0f); val4.anchoredPosition = new Vector2(-10f, 10f); val4.sizeDelta = new Vector2(300f, 40f); Image val5 = val3.AddComponent<Image>(); ((Graphic)val5).color = new Color(0f, 0f, 0f, 0.7f); GameObject val6 = new GameObject("LoadingText"); val6.transform.SetParent(val3.transform, false); RectTransform val7 = val6.AddComponent<RectTransform>(); val7.anchorMin = Vector2.zero; val7.anchorMax = Vector2.one; val7.offsetMin = new Vector2(10f, 5f); val7.offsetMax = new Vector2(-10f, -5f); _loadingText = val6.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_loadingText).text = "BetterJukebox: Loading songs..."; ((TMP_Text)_loadingText).fontSize = 14f; ((TMP_Text)_loadingText).alignment = (TextAlignmentOptions)513; ((Graphic)_loadingText).color = Color.white; MelonCoroutines.Start(UpdateLoadingProgress()); } catch (Exception ex) { _config.LogDebug("Failed to create loading indicator: " + ex.Message); } } [IteratorStateMachine(typeof(<UpdateLoadingProgress>d__17))] private IEnumerator UpdateLoadingProgress() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <UpdateLoadingProgress>d__17(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<ScanCurrentScene>d__18))] private IEnumerator ScanCurrentScene() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ScanCurrentScene>d__18(0) { <>4__this = this }; } public override void OnSceneWasInitialized(int buildIndex, string sceneName) { _config.LogDebug($"Scene Initialized: {sceneName} (index: {buildIndex}). Scanning for jukeboxes..."); if (_scanCoroutine != null) { MelonCoroutines.Stop(_scanCoroutine); } if (_initialLoadComplete) { _scanCoroutine = MelonCoroutines.Start(CheckSavedJukeboxes()); } } [IteratorStateMachine(typeof(<CheckSavedJukeboxes>d__20))] private IEnumerator CheckSavedJukeboxes() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckSavedJukeboxes>d__20(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<FinalJukeboxCheck>d__21))] private IEnumerator FinalJukeboxCheck() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FinalJukeboxCheck>d__21(0) { <>4__this = this }; } public override void OnLevelWasLoaded(int level) { if (_trackManager.TracksLoaded) { _config.LogDebug($"Level {level} was loaded. Running additional jukebox scan..."); MelonCoroutines.Start(_jukeboxPatcher.ScanForJukeboxes(repeat: false)); } } public override void OnUpdate() { if (_trackManager.TracksLoaded && !_patchesApplied) { _harmonyPatches.SetupPatches(); _patchesApplied = true; _config.LogDebug("Harmony patches applied during update"); MelonCoroutines.Start(ScanCurrentScene()); } if (_trackManager.TracksLoaded && Input.GetKeyDown((KeyCode)291)) { MelonLogger.Msg("Manually refreshing jukeboxes"); MelonCoroutines.Start(_jukeboxPatcher.ScanForJukeboxes(repeat: false)); _paginationManager.CheckForUnpatchedInterfaces(); } } public static void OnJukeboxAwake(Jukebox jukebox) { if (_instance != null && _instance._trackManager.TracksLoaded && (Object)(object)jukebox != (Object)null) { _instance._config.LogDebug($"Jukebox created/initialized: {((Object)jukebox).GetInstanceID()}"); _instance._jukeboxPatcher.PatchJukebox(jukebox); } } public static void OnSetupSongEntries(JukeboxInterface jukeboxInterface) { if (_instance != null && _instance._trackManager.TracksLoaded) { _instance._paginationManager.SetupPagination(jukeboxInterface); } } public static void OnJukeboxInterfaceOpen(JukeboxInterface jukeboxInterface) { if (_instance != null && _instance._trackManager.TracksLoaded) { _instance._paginationManager.UpdatePaginationUI(jukeboxInterface); } } public static bool OnRefreshSongEntries(JukeboxInterface jukeboxInterface) { if (_instance != null && _instance._trackManager.TracksLoaded) { _instance._paginationManager.RefreshPagination(jukeboxInterface); return false; } return true; } public static bool OnPlayTrack(Jukebox jukebox, int trackID) { if (_instance == null || !_instance._trackManager.TracksLoaded || (Object)(object)jukebox == (Object)null) { return true; } int originalTrackCount = _instance._jukeboxPatcher.GetOriginalTrackCount(((Object)jukebox).GetInstanceID()); if (trackID >= originalTrackCount && trackID < ((Il2CppArrayBase<Track>)(object)jukebox.TrackList).Length) { Track val = ((Il2CppArrayBase<Track>)(object)jukebox.TrackList)[trackID]; if (val != null && (Object)(object)val.Clip == (Object)null) { _instance._config.LogDebug("Lazy loading track " + val.TrackName + " before playing"); bool loadCompleted = false; bool loadSuccess = false; MelonCoroutines.Start(_instance.LoadAndPlayTrack(jukebox, trackID, val, delegate(bool success) { loadSuccess = success; loadCompleted = true; })); return false; } } return true; } [IteratorStateMachine(typeof(<LoadAndPlayTrack>d__29))] private IEnumerator LoadAndPlayTrack(Jukebox jukebox, int trackID, Track track, Action<bool> onComplete) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAndPlayTrack>d__29(0) { <>4__this = this, jukebox = jukebox, trackID = trackID, track = track, onComplete = onComplete }; } } } namespace BetterJukebox.Utils { public static class AudioUtils { public static AudioType GetAudioType(string filePath) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (filePath.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase)) { return (AudioType)13; } if (filePath.EndsWith(".wav", StringComparison.OrdinalIgnoreCase)) { return (AudioType)20; } return (AudioType)0; } } } namespace BetterJukebox.Services { public class JukeboxPatcher { [CompilerGenerated] private sealed class <CheckForSavedJukeboxes>d__9 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public JukeboxPatcher <>4__this; private Jukebox[] <finalScan>5__1; private int <finalPatched>5__2; private int <attempt>5__3; private Jukebox[] <jukeboxes>5__4; private int <patchedThisAttempt>5__5; private Jukebox[] <>s__6; private int <>s__7; private Jukebox <jukebox>5__8; private Jukebox[] <>s__9; private int <>s__10; private Jukebox <jukebox>5__11; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckForSavedJukeboxes>d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <finalScan>5__1 = null; <jukeboxes>5__4 = null; <>s__6 = null; <jukebox>5__8 = null; <>s__9 = null; <jukebox>5__11 = null; <>1__state = -2; } private bool MoveNext() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Expected O, but got Unknown //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(3f); <>1__state = 1; return true; case 1: <>1__state = -1; <attempt>5__3 = 0; goto IL_026d; case 2: <>1__state = -1; goto IL_0255; case 3: <>1__state = -1; goto IL_0255; case 4: { <>1__state = -1; <finalScan>5__1 = Il2CppArrayBase<Jukebox>.op_Implicit(Object.FindObjectsOfType<Jukebox>(true)); <finalPatched>5__2 = 0; <>s__9 = <finalScan>5__1; for (<>s__10 = 0; <>s__10 < <>s__9.Length; <>s__10++) { <jukebox>5__11 = <>s__9[<>s__10]; if ((Object)(object)<jukebox>5__11 != (Object)null && !<>4__this._patchedJukeboxIds.Contains(((Object)<jukebox>5__11).GetInstanceID())) { <>4__this.PatchJukebox(<jukebox>5__11); <finalPatched>5__2++; } <jukebox>5__11 = null; } <>s__9 = null; if (<finalPatched>5__2 > 0) { <>4__this._config.LogDebug($"Final scan patched {<finalPatched>5__2} additional jukeboxes"); } return false; } IL_026d: if (<attempt>5__3 < 3) { <>4__this._config.LogDebug($"Checking for saved jukeboxes (attempt {<attempt>5__3 + 1}/3)..."); <jukeboxes>5__4 = Il2CppArrayBase<Jukebox>.op_Implicit(Object.FindObjectsOfType<Jukebox>(true)); <patchedThisAttempt>5__5 = 0; <>4__this._config.LogDebug($"Found {<jukeboxes>5__4.Length} jukeboxes in the scene"); <>s__6 = <jukeboxes>5__4; for (<>s__7 = 0; <>s__7 < <>s__6.Length; <>s__7++) { <jukebox>5__8 = <>s__6[<>s__7]; if ((Object)(object)<jukebox>5__8 != (Object)null && !<>4__this._patchedJukeboxIds.Contains(((Object)<jukebox>5__8).GetInstanceID())) { <>4__this.PatchJukebox(<jukebox>5__8); <patchedThisAttempt>5__5++; } <jukebox>5__8 = null; } <>s__6 = null; if (<patchedThisAttempt>5__5 > 0) { <>4__this._config.LogDebug($"Patched {<patchedThisAttempt>5__5} saved jukeboxes in attempt {<attempt>5__3 + 1}"); } if (<patchedThisAttempt>5__5 == 0 && <attempt>5__3 < 2) { <>4__this._config.LogDebug("No new jukeboxes found, waiting to try again..."); <>2__current = (object)new WaitForSeconds(2f); <>1__state = 2; return true; } if (<patchedThisAttempt>5__5 > 0) { <>2__current = (object)new WaitForSeconds(1f); <>1__state = 3; return true; } } <>4__this._config.LogDebug($"Finished checking for saved jukeboxes, total patched: {<>4__this._patchedJukeboxIds.Count}"); <>2__current = (object)new WaitForSeconds(5f); <>1__state = 4; return true; IL_0255: <jukeboxes>5__4 = null; <attempt>5__3++; goto IL_026d; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LoadTrackForPlaying>d__11 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Track track; public Action<bool> onComplete; public JukeboxPatcher <>4__this; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadTrackForPlaying>d__11(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = <>4__this._trackManager.EnsureTrackLoaded(track, onComplete); <>1__state = 1; return true; case 1: <>1__state = -1; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <ScanForJukeboxes>d__7 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public bool repeat; public JukeboxPatcher <>4__this; private int <scanAttempts>5__1; private int <maxScanAttempts>5__2; private int <jukeboxesFound>5__3; private int <jukeboxesPatched>5__4; private Jukebox[] <jukeboxes>5__5; private Jukebox[] <>s__6; private int <>s__7; private Jukebox <jukebox>5__8; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ScanForJukeboxes>d__7(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <jukeboxes>5__5 = null; <>s__6 = null; <jukebox>5__8 = null; <>1__state = -2; } private bool MoveNext() { //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (<>4__this._trackManager.CustomTracks.Count == 0) { return false; } <scanAttempts>5__1 = 0; <maxScanAttempts>5__2 = ((!repeat) ? 1 : 10); <jukeboxesFound>5__3 = 0; <jukeboxesPatched>5__4 = 0; break; case 1: <>1__state = -1; <jukeboxes>5__5 = null; break; } if (<scanAttempts>5__1 < <maxScanAttempts>5__2) { <scanAttempts>5__1++; <>4__this._config.LogDebug($"Scanning for jukeboxes (attempt {<scanAttempts>5__1}/{<maxScanAttempts>5__2})..."); <jukeboxes>5__5 = Il2CppArrayBase<Jukebox>.op_Implicit(Object.FindObjectsOfType<Jukebox>(true)); <jukeboxesFound>5__3 = <jukeboxes>5__5.Length; if (<jukeboxes>5__5.Length != 0) { <>4__this._config.LogDebug($"Found {<jukeboxes>5__5.Length} jukeboxes"); <>s__6 = <jukeboxes>5__5; for (<>s__7 = 0; <>s__7 < <>s__6.Length; <>s__7++) { <jukebox>5__8 = <>s__6[<>s__7]; if ((Object)(object)<jukebox>5__8 != (Object)null && !<>4__this._patchedJukeboxIds.Contains(((Object)<jukebox>5__8).GetInstanceID())) { <>4__this.PatchJukebox(<jukebox>5__8); <jukeboxesPatched>5__4++; } <jukebox>5__8 = null; } <>s__6 = null; if (<jukeboxesPatched>5__4 > 0) { <>4__this._config.LogDebug($"Patched {<jukeboxesPatched>5__4} new jukeboxes"); } } else { <>4__this._config.LogDebug("No jukeboxes found in the current scene"); } if (<jukeboxesFound>5__3 <= 0 || <jukeboxesPatched>5__4 != <jukeboxesFound>5__3) { <>2__current = (object)new WaitForSeconds(5f); <>1__state = 1; return true; } } if ((<jukeboxesFound>5__3 == 0) & repeat) { MelonLogger.Warning("No jukeboxes found after multiple attempts. Try pressing F10 when near a jukebox for manual refresh."); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly ModConfig _config; private readonly TrackManager _trackManager; private readonly HashSet<int> _patchedJukeboxIds = new HashSet<int>(); private readonly Dictionary<int, int> _originalTrackCounts = new Dictionary<int, int>(); public JukeboxPatcher(ModConfig config, TrackManager trackManager) { _config = config; _trackManager = trackManager; } public bool IsJukeboxPatched(int jukeboxId) { return _patchedJukeboxIds.Contains(jukeboxId); } public int GetOriginalTrackCount(int jukeboxId) { if (_originalTrackCounts.TryGetValue(jukeboxId, out var value)) { return value; } return 0; } [IteratorStateMachine(typeof(<ScanForJukeboxes>d__7))] public IEnumerator ScanForJukeboxes(bool repeat = true) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ScanForJukeboxes>d__7(0) { <>4__this = this, repeat = repeat }; } public void PatchJukebox(Jukebox jukebox) { if ((Object)(object)jukebox == (Object)null || _trackManager.CustomTracks.Count == 0) { return; } int instanceID = ((Object)jukebox).GetInstanceID(); if (_patchedJukeboxIds.Contains(instanceID)) { _config.LogDebug($"Jukebox {instanceID} already patched, skipping"); return; } try { Track[] array = Il2CppArrayBase<Track>.op_Implicit((Il2CppArrayBase<Track>)(object)jukebox.TrackList); if (array == null) { MelonLogger.Warning($"Jukebox {instanceID} has null TrackList, skipping"); return; } _originalTrackCounts[instanceID] = array.Length; Track[] array2 = (Track[])(object)new Track[array.Length + _trackManager.CustomTracks.Count]; Array.Copy(array, array2, array.Length); for (int i = 0; i < _trackManager.CustomTracks.Count; i++) { array2[array.Length + i] = _trackManager.CustomTracks[i]; } jukebox.TrackList = Il2CppReferenceArray<Track>.op_Implicit(array2); Type il2CppType = ((Object)jukebox).GetIl2CppType(); FieldInfo field = il2CppType.GetField("_jukeboxState", (BindingFlags)36); if (field != (FieldInfo)null) { _config.LogDebug("Found _jukeboxState field via IL2CPP reflection"); Object value = field.GetValue((Object)(object)jukebox); if (value != null) { JukeboxState val = ((Il2CppObjectBase)value).Cast<JukeboxState>(); if (val != null && val.TrackOrder != null) { _config.LogDebug("Updating TrackOrder in JukeboxState"); int[] array3 = new int[array2.Length]; for (int j = 0; j < array3.Length; j++) { array3[j] = j; } val.TrackOrder = Il2CppStructArray<int>.op_Implicit(array3); _config.LogDebug($"Updated TrackOrder to include {array2.Length} tracks"); } else { MelonLogger.Warning("JukeboxState or TrackOrder is null"); } } else { MelonLogger.Warning("_jukeboxState field value is null"); } } else { MelonLogger.Warning("Could not find _jukeboxState field via IL2CPP reflection"); } _patchedJukeboxIds.Add(instanceID); _config.LogDebug($"Successfully patched jukebox {instanceID} with {_trackManager.CustomTracks.Count} custom tracks"); } catch (Exception ex) { MelonLogger.Error($"Failed to patch jukebox {instanceID}: {ex.Message}"); MelonLogger.Error(ex.StackTrace); } } [IteratorStateMachine(typeof(<CheckForSavedJukeboxes>d__9))] public IEnumerator CheckForSavedJukeboxes() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckForSavedJukeboxes>d__9(0) { <>4__this = this }; } public bool ForcePlayTrack(Jukebox jukebox, int trackID) { if ((Object)(object)jukebox == (Object)null || trackID < 0 || trackID >= ((Il2CppArrayBase<Track>)(object)jukebox.TrackList).Length) { MelonLogger.Error($"Invalid jukebox or track ID: {trackID}"); return false; } try { Track val = ((Il2CppArrayBase<Track>)(object)jukebox.TrackList)[trackID]; if (val == null) { MelonLogger.Error("Track is null"); return false; } if (trackID >= GetOriginalTrackCount(((Object)jukebox).GetInstanceID()) && (Object)(object)val.Clip == (Object)null) { _config.LogDebug("Track " + val.TrackName + " has null clip, loading it now..."); bool loadSuccess = false; MelonCoroutines.Start(LoadTrackForPlaying(val, delegate(bool success) { loadSuccess = success; })); float realtimeSinceStartup = Time.realtimeSinceStartup; while (!loadSuccess && Time.realtimeSinceStartup - realtimeSinceStartup < 2f) { Thread.Sleep(50); } if (!loadSuccess || (Object)(object)val.Clip == (Object)null) { MelonLogger.Error("Failed to load clip for track " + val.TrackName); return false; } } if ((Object)(object)val.Clip == (Object)null) { MelonLogger.Error("Track " + val.TrackName + " has null clip"); return false; } _config.LogDebug("Forcing play of track: " + val.TrackName); AudioSource val2 = null; try { FieldInfo field = ((Object)jukebox).GetIl2CppType().GetField("AudioSourceController", (BindingFlags)20); if (field != (FieldInfo)null) { Object value = field.GetValue((Object)(object)jukebox); if (value != null) { Component val3 = ((Il2CppObjectBase)value).Cast<Component>(); _config.LogDebug("Found AudioSourceController, attempting to get AudioSource"); PropertyInfo property = ((Object)val3).GetIl2CppType().GetProperty("AudioSource", (BindingFlags)20); if (property != (PropertyInfo)null) { Object value2 = property.GetValue((Object)(object)val3); if (value2 != null) { val2 = ((Il2CppObjectBase)value2).Cast<AudioSource>(); _config.LogDebug("Successfully got AudioSource via AudioSourceController property"); } } else { val2 = val3.GetComponent<AudioSource>(); if ((Object)(object)val2 != (Object)null) { _config.LogDebug("Got AudioSource via GetComponent on AudioSourceController"); } } } } } catch (Exception ex) { _config.LogDebug("Error getting AudioSource via AudioSourceController: " + ex.Message); } if ((Object)(object)val2 == (Object)null) { try { FieldInfo field2 = ((Object)jukebox).GetIl2CppType().GetField("_audioSource", (BindingFlags)36); if (field2 != (FieldInfo)null) { Object value3 = field2.GetValue((Object)(object)jukebox); if (value3 != null) { val2 = ((Il2CppObjectBase)value3).Cast<AudioSource>(); _config.LogDebug("Got AudioSource via _audioSource field"); } } else { _config.LogDebug("Could not find _audioSource field"); } } catch (Exception ex2) { _config.LogDebug("Error getting _audioSource field: " + ex2.Message); } } if ((Object)(object)val2 == (Object)null) { try { val2 = ((Component)jukebox).GetComponent<AudioSource>(); if ((Object)(object)val2 != (Object)null) { _config.LogDebug("Got AudioSource via GetComponent on Jukebox"); } else { val2 = ((Component)jukebox).GetComponentInChildren<AudioSource>(); if ((Object)(object)val2 != (Object)null) { _config.LogDebug("Got AudioSource via GetComponentInChildren on Jukebox"); } } } catch (Exception ex3) { _config.LogDebug("Error getting AudioSource via GetComponent: " + ex3.Message); } } if ((Object)(object)val2 == (Object)null) { MelonLogger.Error("Could not find AudioSource by any method"); return false; } val2.Stop(); val2.clip = val.Clip; val2.time = 0f; val2.volume = 1f; val2.Play(); _config.LogDebug($"Forced play of track {val.TrackName} - AudioSource playing: {val2.isPlaying}"); try { FieldInfo field3 = ((Object)jukebox).GetIl2CppType().GetField("_currentTrack", (BindingFlags)36); if (field3 != (FieldInfo)null) { field3.SetValue((Object)(object)jukebox, Object.op_Implicit(trackID)); _config.LogDebug($"Updated _currentTrack to {trackID}"); } } catch (Exception ex4) { MelonLogger.Warning("Error updating _currentTrack field: " + ex4.Message); } return val2.isPlaying; } catch (Exception ex5) { MelonLogger.Error("Error in ForcePlayTrack: " + ex5.Message); MelonLogger.Error(ex5.StackTrace); return false; } } [IteratorStateMachine(typeof(<LoadTrackForPlaying>d__11))] private IEnumerator LoadTrackForPlaying(Track track, Action<bool> onComplete) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadTrackForPlaying>d__11(0) { <>4__this = this, track = track, onComplete = onComplete }; } } public class PaginationManager { [CompilerGenerated] private sealed class <AnimateButtonScale>d__10 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Transform buttonTransform; public PaginationManager <>4__this; private Vector3 <originalScale>5__1; private float <duration>5__2; private float <elapsed>5__3; private float <t>5__4; private float <t>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AnimateButtonScale>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>4__this._config.LogDebug("AnimateButtonScale coroutine started"); <originalScale>5__1 = buttonTransform.localScale; <>4__this._config.LogDebug($"Original scale: {<originalScale>5__1}"); <duration>5__2 = 0.1f; <elapsed>5__3 = 0f; goto IL_0101; case 1: <>1__state = -1; goto IL_0101; case 2: { <>1__state = -1; break; } IL_0101: if (<elapsed>5__3 < <duration>5__2) { <t>5__4 = <elapsed>5__3 / <duration>5__2; buttonTransform.localScale = Vector3.Lerp(<originalScale>5__1, <originalScale>5__1 * 0.9f, <t>5__4); <elapsed>5__3 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } <>4__this._config.LogDebug("Button scale down complete"); <elapsed>5__3 = 0f; break; } if (<elapsed>5__3 < <duration>5__2) { <t>5__5 = <elapsed>5__3 / <duration>5__2; buttonTransform.localScale = Vector3.Lerp(<originalScale>5__1 * 0.9f, <originalScale>5__1, <t>5__5); <elapsed>5__3 += Time.deltaTime; <>2__current = null; <>1__state = 2; return true; } buttonTransform.localScale = <originalScale>5__1; <>4__this._config.LogDebug("Button animation complete"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <CheckForSavedJukeboxInterfaces>d__13 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PaginationManager <>4__this; private JukeboxInterface[] <finalInterfaces>5__1; private int <finalCount>5__2; private int <attempt>5__3; private JukeboxInterface[] <interfaces>5__4; private int <patchedCount>5__5; private JukeboxInterface[] <>s__6; private int <>s__7; private JukeboxInterface <jukeboxInterface>5__8; private int <jukeboxId>5__9; private JukeboxInterface[] <>s__10; private int <>s__11; private JukeboxInterface <jukeboxInterface>5__12; private int <jukeboxId>5__13; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CheckForSavedJukeboxInterfaces>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <finalInterfaces>5__1 = null; <interfaces>5__4 = null; <>s__6 = null; <jukeboxInterface>5__8 = null; <>s__10 = null; <jukeboxInterface>5__12 = null; <>1__state = -2; } private bool MoveNext() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Expected O, but got Unknown //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02ae: Expected O, but got Unknown //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(2f); <>1__state = 1; return true; case 1: <>1__state = -1; <attempt>5__3 = 0; goto IL_0327; case 2: <>1__state = -1; goto IL_030d; case 3: <>1__state = -1; goto IL_030d; case 4: { <>1__state = -1; <finalInterfaces>5__1 = Il2CppArrayBase<JukeboxInterface>.op_Implicit(Object.FindObjectsOfType<JukeboxInterface>(true)); <finalCount>5__2 = 0; <>s__10 = <finalInterfaces>5__1; for (<>s__11 = 0; <>s__11 < <>s__10.Length; <>s__11++) { <jukeboxInterface>5__12 = <>s__10[<>s__11]; if ((Object)(object)<jukeboxInterface>5__12 != (Object)null && (Object)(object)<jukeboxInterface>5__12.Jukebox != (Object)null && !<>4__this._paginationData.ContainsKey(<jukeboxInterface>5__12)) { <jukeboxId>5__13 = ((Object)<jukeboxInterface>5__12.Jukebox).GetInstanceID(); if (<>4__this._jukeboxPatcher.IsJukeboxPatched(<jukeboxId>5__13)) { <>4__this.RecreateSongEntries(<jukeboxInterface>5__12); <>4__this.SetupPagination(<jukeboxInterface>5__12); <finalCount>5__2++; } } <jukeboxInterface>5__12 = null; } <>s__10 = null; if (<finalCount>5__2 > 0) { <>4__this._config.LogDebug($"Final scan applied pagination to {<finalCount>5__2} additional interfaces"); } return false; } IL_0327: if (<attempt>5__3 < 3) { <>4__this._config.LogDebug($"Checking for saved jukebox interfaces (attempt {<attempt>5__3 + 1}/3)..."); <interfaces>5__4 = Il2CppArrayBase<JukeboxInterface>.op_Implicit(Object.FindObjectsOfType<JukeboxInterface>(true)); <patchedCount>5__5 = 0; <>4__this._config.LogDebug($"Found {<interfaces>5__4.Length} jukebox interfaces in the scene"); <>s__6 = <interfaces>5__4; for (<>s__7 = 0; <>s__7 < <>s__6.Length; <>s__7++) { <jukeboxInterface>5__8 = <>s__6[<>s__7]; if ((Object)(object)<jukeboxInterface>5__8 != (Object)null && (Object)(object)<jukeboxInterface>5__8.Jukebox != (Object)null) { <jukeboxId>5__9 = ((Object)<jukeboxInterface>5__8.Jukebox).GetInstanceID(); if (<>4__this._paginationData.ContainsKey(<jukeboxInterface>5__8)) { <>4__this._config.LogDebug($"Interface for jukebox {<jukeboxId>5__9} already has pagination"); continue; } if (<>4__this._jukeboxPatcher.IsJukeboxPatched(<jukeboxId>5__9)) { <>4__this._config.LogDebug($"Setting up pagination for patched jukebox {<jukeboxId>5__9}"); <>4__this.RecreateSongEntries(<jukeboxInterface>5__8); <>4__this.SetupPagination(<jukeboxInterface>5__8); <patchedCount>5__5++; } else { <>4__this._config.LogDebug($"Found interface for jukebox {<jukeboxId>5__9} but it's not patched yet"); } } <jukeboxInterface>5__8 = null; } <>s__6 = null; if (<patchedCount>5__5 > 0) { <>4__this._config.LogDebug($"Applied pagination to {<patchedCount>5__5} jukebox interfaces in attempt {<attempt>5__3 + 1}"); <>2__current = (object)new WaitForSeconds(1f); <>1__state = 2; return true; } if (<attempt>5__3 < 2) { <>4__this._config.LogDebug("No interfaces to update, waiting to try again..."); <>2__current = (object)new WaitForSeconds(2f); <>1__state = 3; return true; } } <>2__current = (object)new WaitForSeconds(4f); <>1__state = 4; return true; IL_030d: <interfaces>5__4 = null; <attempt>5__3++; goto IL_0327; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const int TRACKS_PER_PAGE = 27; private readonly ModConfig _config; private readonly JukeboxPatcher _jukeboxPatcher; private readonly Dictionary<JukeboxInterface, PaginationData> _paginationData = new Dictionary<JukeboxInterface, PaginationData>(); public PaginationManager(ModConfig config, JukeboxPatcher jukeboxPatcher) { _config = config; _jukeboxPatcher = jukeboxPatcher; } public void SetupPagination(JukeboxInterface jukeboxInterface) { //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_0388: Expected O, but got Unknown //IL_038f: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Expected O, but got Unknown //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Unknown result type (might be due to invalid IL or missing references) //IL_04c0: Unknown result type (might be due to invalid IL or missing references) //IL_04d8: Unknown result type (might be due to invalid IL or missing references) //IL_04f9: Unknown result type (might be due to invalid IL or missing references) //IL_051a: Unknown result type (might be due to invalid IL or missing references) //IL_053b: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Unknown result type (might be due to invalid IL or missing references) //IL_0583: Unknown result type (might be due to invalid IL or missing references) //IL_0590: Unknown result type (might be due to invalid IL or missing references) //IL_0597: Expected O, but got Unknown //IL_05e2: Unknown result type (might be due to invalid IL or missing references) //IL_05ef: Unknown result type (might be due to invalid IL or missing references) //IL_05fc: Unknown result type (might be due to invalid IL or missing references) //IL_064d: Unknown result type (might be due to invalid IL or missing references) //IL_065d: Unknown result type (might be due to invalid IL or missing references) //IL_0664: Expected O, but got Unknown //IL_06b0: Unknown result type (might be due to invalid IL or missing references) //IL_0711: Unknown result type (might be due to invalid IL or missing references) //IL_0722: Unknown result type (might be due to invalid IL or missing references) //IL_072c: Expected O, but got Unknown //IL_079d: Unknown result type (might be due to invalid IL or missing references) //IL_07cb: Unknown result type (might be due to invalid IL or missing references) //IL_084e: Unknown result type (might be due to invalid IL or missing references) //IL_0853: Unknown result type (might be due to invalid IL or missing references) //IL_086b: Unknown result type (might be due to invalid IL or missing references) //IL_088c: Unknown result type (might be due to invalid IL or missing references) //IL_08ad: Unknown result type (might be due to invalid IL or missing references) //IL_08ce: Unknown result type (might be due to invalid IL or missing references) //IL_08ef: Unknown result type (might be due to invalid IL or missing references) //IL_0916: Unknown result type (might be due to invalid IL or missing references) //IL_0923: Unknown result type (might be due to invalid IL or missing references) //IL_092a: Expected O, but got Unknown //IL_0975: Unknown result type (might be due to invalid IL or missing references) //IL_0982: Unknown result type (might be due to invalid IL or missing references) //IL_098f: Unknown result type (might be due to invalid IL or missing references) //IL_09e0: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_0488: Unknown result type (might be due to invalid IL or missing references) //IL_0804: Unknown result type (might be due to invalid IL or missing references) //IL_081b: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Expected O, but got Unknown //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)jukeboxInterface == (Object)null || (Object)(object)jukeboxInterface.Jukebox == (Object)null || (Object)(object)jukeboxInterface.EntryContainer == (Object)null) { _config.LogDebug("Cannot setup pagination, interface or required components are null"); return; } int length = ((Il2CppArrayBase<Track>)(object)jukeboxInterface.Jukebox.TrackList).Length; if (length <= 27) { _config.LogDebug($"No pagination needed, track count ({length}) <= tracks per page ({27})"); return; } if (_paginationData.ContainsKey(jukeboxInterface)) { if ((Object)(object)_paginationData[jukeboxInterface].PaginationUI != (Object)null) { Object.Destroy((Object)(object)_paginationData[jukeboxInterface].PaginationUI); } _paginationData.Remove(jukeboxInterface); } PaginationData paginationData = new PaginationData { CurrentPage = 0, TotalPages = Mathf.CeilToInt((float)length / 27f), OriginalSongEntries = new List<RectTransform>() }; FieldInfo fieldInfo = AccessTools.Field(typeof(JukeboxInterface), "songEntries"); if (fieldInfo != null) { paginationData.OriginalSongEntries = new List<RectTransform>(fieldInfo.GetValue(jukeboxInterface) as List<RectTransform>); } Canvas canvas = jukeboxInterface.Canvas; if ((Object)(object)canvas == (Object)null) { _config.LogDebug("Canvas is null, cannot create pagination UI"); return; } GameObject val = new GameObject("PaginationContainer"); val.AddComponent(Il2CppType.Of<RectTransform>()); val.transform.SetParent(((Component)canvas).transform, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0.5f, 0f); component.anchorMax = new Vector2(0.5f, 0f); component.pivot = new Vector2(0.5f, 0f); component.anchoredPosition = new Vector2(0f, 445f); component.sizeDelta = new Vector2(300f, 40f); Image val2 = ((Il2CppObjectBase)val.AddComponent(Il2CppType.Of<Image>())).Cast<Image>(); ((Graphic)val2).color = new Color(0.1f, 0.1f, 0.1f, 0.8f); try { Type val3 = Il2CppType.From(Type.GetType("UnityEngine.UI.Extensions.UICornerCut, Unity.UI.Extensions")); if (val3 != (Type)null && ((Il2CppObjectBase)val3).Pointer != IntPtr.Zero) { val.AddComponent(val3); _config.LogDebug("Added rounded corners but couldn't set the radius in IL2CPP build"); } } catch (Exception) { _config.LogDebug("Couldn't add rounded corners to pagination UI"); } HorizontalLayoutGroup val4 = ((Il2CppObjectBase)val.AddComponent(Il2CppType.Of<HorizontalLayoutGroup>())).Cast<HorizontalLayoutGroup>(); ((LayoutGroup)val4).childAlignment = (TextAnchor)4; ((HorizontalOrVerticalLayoutGroup)val4).spacing = 10f; ((LayoutGroup)val4).padding = new RectOffset(10, 10, 5, 5); GameObject prevButton = new GameObject("PrevButton"); prevButton.AddComponent(Il2CppType.Of<RectTransform>()); prevButton.AddComponent(Il2CppType.Of<CanvasRenderer>()); prevButton.AddComponent(Il2CppType.Of<Image>()); prevButton.AddComponent(Il2CppType.Of<Button>()); prevButton.transform.SetParent((Transform)(object)component, false); RectTransform component2 = prevButton.GetComponent<RectTransform>(); component2.sizeDelta = new Vector2(40f, 40f); Image component3 = prevButton.GetComponent<Image>(); ((Graphic)component3).color = new Color(0.15f, 0.15f, 0.15f, 0.9f); try { Outline val5 = ((Il2CppObjectBase)prevButton.AddComponent(Il2CppType.Of<Outline>())).Cast<Outline>(); ((Shadow)val5).effectColor = new Color(0.3f, 0.3f, 0.3f, 0.5f); ((Shadow)val5).effectDistance = new Vector2(1f, -1f); } catch (Exception) { _config.LogDebug("Couldn't add rounded style to pagination buttons"); } Button component4 = prevButton.GetComponent<Button>(); ColorBlock colors = ((Selectable)component4).colors; ((ColorBlock)(ref colors)).normalColor = new Color(0.15f, 0.15f, 0.15f, 0.9f); ((ColorBlock)(ref colors)).highlightedColor = new Color(0.25f, 0.25f, 0.25f, 1f); ((ColorBlock)(ref colors)).pressedColor = new Color(0.1f, 0.1f, 0.1f, 1f); ((ColorBlock)(ref colors)).selectedColor = new Color(0.25f, 0.25f, 0.25f, 1f); ((ColorBlock)(ref colors)).disabledColor = new Color(0.15f, 0.15f, 0.15f, 0.5f); ((ColorBlock)(ref colors)).colorMultiplier = 1.2f; ((ColorBlock)(ref colors)).fadeDuration = 0.1f; ((Selectable)component4).colors = colors; GameObject val6 = new GameObject("Text"); val6.AddComponent(Il2CppType.Of<RectTransform>()); val6.AddComponent(Il2CppType.Of<CanvasRenderer>()); val6.AddComponent(Il2CppType.Of<TextMeshProUGUI>()); val6.transform.SetParent(prevButton.transform, false); RectTransform component5 = val6.GetComponent<RectTransform>(); component5.anchorMin = Vector2.zero; component5.anchorMax = Vector2.one; component5.sizeDelta = Vector2.zero; TextMeshProUGUI component6 = val6.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component6).text = "<"; ((TMP_Text)component6).fontSize = 24f; ((TMP_Text)component6).alignment = (TextAlignmentOptions)514; ((Graphic)component6).color = new Color(0.8f, 0.8f, 0.8f, 1f); GameObject val7 = new GameObject("PageText"); val7.AddComponent(Il2CppType.Of<RectTransform>()); val7.AddComponent(Il2CppType.Of<CanvasRenderer>()); val7.AddComponent(Il2CppType.Of<TextMeshProUGUI>()); val7.transform.SetParent((Transform)(object)component, false); RectTransform component7 = val7.GetComponent<RectTransform>(); component7.sizeDelta = new Vector2(150f, 40f); TextMeshProUGUI component8 = val7.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component8).text = $"Page 1/{paginationData.TotalPages}"; ((TMP_Text)component8).fontSize = 18f; ((TMP_Text)component8).alignment = (TextAlignmentOptions)514; ((Graphic)component8).color = new Color(0.8f, 0.8f, 0.8f, 1f); GameObject nextButton = new GameObject("NextButton"); nextButton.AddComponent(Il2CppType.Of<RectTransform>()); nextButton.AddComponent(Il2CppType.Of<CanvasRenderer>()); nextButton.AddComponent(Il2CppType.Of<Image>()); nextButton.AddComponent(Il2CppType.Of<Button>()); nextButton.transform.SetParent((Transform)(object)component, false); RectTransform component9 = nextButton.GetComponent<RectTransform>(); component9.sizeDelta = new Vector2(40f, 40f); Image component10 = nextButton.GetComponent<Image>(); ((Graphic)component10).color = new Color(0.15f, 0.15f, 0.15f, 0.9f); try { Outline val8 = ((Il2CppObjectBase)nextButton.AddComponent(Il2CppType.Of<Outline>())).Cast<Outline>(); ((Shadow)val8).effectColor = new Color(0.3f, 0.3f, 0.3f, 0.5f); ((Shadow)val8).effectDistance = new Vector2(1f, -1f); } catch (Exception) { _config.LogDebug("Couldn't add rounded style to next button"); } Button component11 = nextButton.GetComponent<Button>(); ColorBlock colors2 = ((Selectable)component11).colors; ((ColorBlock)(ref colors2)).normalColor = new Color(0.15f, 0.15f, 0.15f, 0.9f); ((ColorBlock)(ref colors2)).highlightedColor = new Color(0.25f, 0.25f, 0.25f, 1f); ((ColorBlock)(ref colors2)).pressedColor = new Color(0.1f, 0.1f, 0.1f, 1f); ((ColorBlock)(ref colors2)).selectedColor = new Color(0.25f, 0.25f, 0.25f, 1f); ((ColorBlock)(ref colors2)).disabledColor = new Color(0.15f, 0.15f, 0.15f, 0.5f); ((ColorBlock)(ref colors2)).colorMultiplier = 1.2f; ((ColorBlock)(ref colors2)).fadeDuration = 0.1f; ((Selectable)component11).colors = colors2; GameObject val9 = new GameObject("Text"); val9.AddComponent(Il2CppType.Of<RectTransform>()); val9.AddComponent(Il2CppType.Of<CanvasRenderer>()); val9.AddComponent(Il2CppType.Of<TextMeshProUGUI>()); val9.transform.SetParent(nextButton.transform, false); RectTransform component12 = val9.GetComponent<RectTransform>(); component12.anchorMin = Vector2.zero; component12.anchorMax = Vector2.one; component12.sizeDelta = Vector2.zero; TextMeshProUGUI component13 = val9.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component13).text = ">"; ((TMP_Text)component13).fontSize = 24f; ((TMP_Text)component13).alignment = (TextAlignmentOptions)514; ((Graphic)component13).color = new Color(0.8f, 0.8f, 0.8f, 1f); paginationData.PaginationUI = val; paginationData.PrevButton = component4; paginationData.NextButton = component11; paginationData.PageText = component8; Action action = delegate { try { _config.LogDebug("IL2CPP Prev Button Clicked"); StartButtonAnimation(prevButton.transform); ChangePage(jukeboxInterface, -1); _config.LogDebug("IL2CPP Prev Action Completed"); } catch (Exception arg4) { MelonLogger.Error($"Error in IL2CPP Prev Action: {arg4}"); } }; Action action2 = delegate { try { _config.LogDebug("IL2CPP Next Button Clicked"); StartButtonAnimation(nextButton.transform); ChangePage(jukeboxInterface, 1); _config.LogDebug("IL2CPP Next Action Completed"); } catch (Exception arg3) { MelonLogger.Error($"Error in IL2CPP Next Action: {arg3}"); } }; _config.LogDebug("Adding IL2CPP button listeners"); try { ((UnityEvent)paginationData.PrevButton.onClick).AddListener(UnityAction.op_Implicit(action)); _config.LogDebug("Successfully added IL2CPP prev button listener"); } catch (Exception arg) { MelonLogger.Error($"Failed to add IL2CPP prev button listener: {arg}"); } try { ((UnityEvent)paginationData.NextButton.onClick).AddListener(UnityAction.op_Implicit(action2)); _config.LogDebug("Successfully added IL2CPP next button listener"); } catch (Exception arg2) { MelonLogger.Error($"Failed to add IL2CPP next button listener: {arg2}"); } _paginationData[jukeboxInterface] = paginationData; UpdatePaginationUI(jukeboxInterface); _config.LogDebug($"Pagination setup completed for jukebox: {((Object)jukeboxInterface.Jukebox).GetInstanceID()} with {paginationData.TotalPages} pages"); } catch (Exception ex4) { MelonLogger.Error("Failed to setup pagination: " + ex4.Message); MelonLogger.Error(ex4.StackTrace); } } public void ChangePage(JukeboxInterface jukeboxInterface, int delta) { _config.LogDebug($"ChangePage called with delta: {delta}"); if (!_paginationData.ContainsKey(jukeboxInterface)) { MelonLogger.Error("ChangePage failed: No pagination data for this interface"); return; } PaginationData paginationData = _paginationData[jukeboxInterface]; int num = paginationData.CurrentPage + delta; _config.LogDebug($"Current page: {paginationData.CurrentPage}, New page: {num}, Total pages: {paginationData.TotalPages}"); if (num >= 0 && num < paginationData.TotalPages) { _config.LogDebug($"Changing to page {num}"); paginationData.CurrentPage = num; UpdatePaginationUI(jukeboxInterface); RefreshPagination(jukeboxInterface); _config.LogDebug("Page change completed"); } else { _config.LogDebug($"Invalid page number: {num}, not changing"); } } public void UpdatePaginationUI(JukeboxInterface jukeboxInterface) { _config.LogDebug("UpdatePaginationUI called"); if (!_paginationData.ContainsKey(jukeboxInterface)) { MelonLogger.Error("UpdatePaginationUI failed: No pagination data for this interface"); return; } PaginationData paginationData = _paginationData[jukeboxInterface]; ((TMP_Text)paginationData.PageText).text = $"Page {paginationData.CurrentPage + 1}/{paginationData.TotalPages}"; _config.LogDebug("Updated page text to: " + ((TMP_Text)paginationData.PageText).text); ((Selectable)paginationData.PrevButton).interactable = paginationData.CurrentPage > 0; ((Selectable)paginationData.NextButton).interactable = paginationData.CurrentPage < paginationData.TotalPages - 1; _config.LogDebug($"Button states updated - Prev: {((Selectable)paginationData.PrevButton).interactable}, Next: {((Selectable)paginationData.NextButton).interactable}"); } public void RefreshPagination(JukeboxInterface jukeboxInterface) { _config.LogDebug("RefreshPagination called"); if (!_paginationData.ContainsKey(jukeboxInterface)) { MelonLogger.Error("RefreshPagination failed: No pagination data for this interface"); return; } PaginationData paginationData = _paginationData[jukeboxInterface]; Type il2CppType = ((Object)jukeboxInterface).GetIl2CppType(); FieldInfo field = il2CppType.GetField("songEntries", (BindingFlags)52); if (field == (FieldInfo)null) { MelonLogger.Error("RefreshPagination failed: songEntries field not found via IL2CPP reflection"); return; } Object value = field.GetValue((Object)(object)jukeboxInterface); if (value == null) { MelonLogger.Error("RefreshPagination failed: songEntries field value is null"); return; } List<RectTransform> list = new List<RectTransform>(); List<RectTransform> val = ((Il2CppObjectBase)value).Cast<List<RectTransform>>(); if (val == null) { MelonLogger.Error("RefreshPagination failed: Could not cast to IL2CPP List"); return; } for (int i = 0; i < val.Count; i++) { list.Add(val[i]); } _config.LogDebug($"Successfully accessed IL2CPP songEntries field with {list.Count} entries"); if (list == null) { MelonLogger.Error("RefreshPagination failed: songEntries list is null"); return; } Track[] array = Il2CppArrayBase<Track>.op_Implicit((Il2CppArrayBase<Track>)(object)jukeboxInterface.Jukebox.TrackList); _config.LogDebug($"Refreshing pagination - Total tracks: {array.Length}, Total entries: {list.Count}"); int num = paginationData.CurrentPage * 27; int num2 = Mathf.Min(num + 27, array.Length); _config.LogDebug($"Page range - Start index: {num}, End index: {num2}"); foreach (RectTransform item in list) { if ((Object)(object)item != (Object)null) { ((Component)item).gameObject.SetActive(false); } } int num3 = 0; for (int j = num; j < num2; j++) { if (j < list.Count && (Object)(object)list[j] != (Object)null) { ((Component)list[j]).gameObject.SetActive(true); num3++; Track val2 = array[j]; if (jukeboxInterface.Jukebox.currentTrack == val2 && jukeboxInterface.Jukebox.IsPlaying) { ((Component)((Transform)list[j]).Find("PlayPause/Icon")).GetComponent<Image>().sprite = jukeboxInterface.SongEntryPauseSprite; } else { ((Component)((Transform)list[j]).Find("PlayPause/Icon")).GetComponent<Image>().sprite = jukeboxInterface.SongEntryPlaySprite; } } } _config.LogDebug($"Refreshed pagination - Showing {num3} entries on page {paginationData.CurrentPage + 1}"); } private void StartButtonAnimation(Transform buttonTransform) { _config.LogDebug("StartButtonAnimation called"); if ((Object)(object)buttonTransform == (Object)null) { MelonLogger.Error("StartButtonAnimation failed: Button transform is null"); return; } try { object obj = MelonCoroutines.Start(AnimateButtonScale(buttonTransform)); _config.LogDebug("Button animation coroutine started"); } catch (Exception arg) { MelonLogger.Error($"Failed to start button animation coroutine: {arg}"); } } [IteratorStateMachine(typeof(<AnimateButtonScale>d__10))] private IEnumerator AnimateButtonScale(Transform buttonTransform) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AnimateButtonScale>d__10(0) { <>4__this = this, buttonTransform = buttonTransform }; } public void RecreateSongEntries(JukeboxInterface jukeboxInterface) { if ((Object)(object)jukeboxInterface == (Object)null || (Object)(object)jukeboxInterface.Jukebox == (Object)null || (Object)(object)jukeboxInterface.EntryContainer == (Object)null) { return; } try { Type il2CppType = ((Object)jukeboxInterface).GetIl2CppType(); FieldInfo field = il2CppType.GetField("songEntries", (BindingFlags)52); if (field == (FieldInfo)null) { _config.LogDebug("Cannot access songEntries field via IL2CPP reflection"); return; } Object value = field.GetValue((Object)(object)jukeboxInterface); if (value == null) { _config.LogDebug("SongEntries field value is null"); return; } List<RectTransform> list = new List<RectTransform>(); List<RectTransform> val = ((Il2CppObjectBase)value).Cast<List<RectTransform>>(); if (val == null) { _config.LogDebug("Could not cast to IL2CPP List"); return; } for (int i = 0; i < val.Count; i++) { list.Add(val[i]); } _config.LogDebug($"Successfully accessed IL2CPP songEntries field with {list.Count} entries"); if (list == null) { _config.LogDebug("Song entries list is null"); return; } Track[] array = Il2CppArrayBase<Track>.op_Implicit((Il2CppArrayBase<Track>)(object)jukeboxInterface.Jukebox.TrackList); int count = list.Count; int num = array.Length; _config.LogDebug($"Recreating song entries: Current UI entries: {count}, Total tracks: {num}"); foreach (RectTransform item in list) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)((Component)item).gameObject); } } list.Clear(); for (int j = 0; j < array.Length; j++) { Track val2 = array[j]; if (val2 == null) { continue; } GameObject entry = Object.Instantiate<GameObject>(jukeboxInterface.SongEntryPrefab, (Transform)(object)jukeboxInterface.EntryContainer); ((TMP_Text)((Component)entry.transform.Find("Name")).GetComponent<TextMeshProUGUI>()).text = val2.TrackName; ((TMP_Text)((Component)entry.transform.Find("Artist")).GetComponent<TextMeshProUGUI>()).text = val2.ArtistName; entry.transform.SetAsLastSibling(); int trackIndex = j; Action action = delegate { try { _config.LogDebug($"IL2CPP Song entry clicked at index {trackIndex}"); if ((Object)(object)jukeboxInterface.Jukebox != (Object)null && trackIndex < ((Il2CppArrayBase<Track>)(object)jukeboxInterface.Jukebox.TrackList).Length) { Track val4 = ((Il2CppArrayBase<Track>)(object)jukeboxInterface.Jukebox.TrackList)[trackIndex]; MelonLogger.Msg("Playing track: " + val4.TrackName); if ((Object)(object)val4.Clip != (Object)null) { _config.LogDebug("Track info - Name: " + val4.TrackName + ", ClipName: " + ((Object)val4.Clip).name + ", " + $"Length: {val4.Clip.length}s, " + $"Channels: {val4.Clip.channels}, " + $"Frequency: {val4.Clip.frequency}Hz, " + $"Samples: {val4.Clip.samples}"); } else { MelonLogger.Warning("Track " + val4.TrackName + " has NULL clip!"); } if (jukeboxInterface.Jukebox.IsPlaying) { if (jukeboxInterface.Jukebox.currentTrack == val4) { _config.LogDebug("Pausing current track"); try { jukeboxInterface.Jukebox.TogglePlay(); _config.LogDebug("Successfully toggled play state"); } catch (Exception ex2) { MelonLogger.Error("Error toggling play: " + ex2.Message); MelonLogger.Error(ex2.StackTrace); } } else { _config.LogDebug("Switching to new track"); try { jukeboxInterface.Jukebox.TogglePlay(); _config.LogDebug("Stopped current track"); _config.LogDebug($"Playing track at index {trackIndex}"); jukeboxInterface.Jukebox.PlayTrack(trackIndex); _config.LogDebug("PlayTrack called successfully"); if (jukeboxInterface.Jukebox.currentTrack != val4) { _config.LogDebug("PlayTrack didn't seem to change current track, trying direct audio source approach"); if (_jukeboxPatcher.ForcePlayTrack(jukeboxInterface.Jukebox, trackIndex)) { _config.LogDebug("Successfully forced track to play"); } else { MelonLogger.Warning("Failed to force play track, trying reflection-based approach"); FieldInfo field2 = ((Object)jukeboxInterface).GetIl2CppType().GetField("songEntries", (BindingFlags)52); if (field2 != (FieldInfo)null) { Object value2 = field2.GetValue((Object)(object)jukeboxInterface); if (value2 != null) { List<RectTransform> val5 = ((Il2CppObjectBase)value2).Cast<List<RectTransform>>(); if (val5 != null && trackIndex < val5.Count) { RectTransform val6 = val5[trackIndex]; MethodInfo method = ((Object)jukeboxInterface).GetIl2CppType().GetMethod("SongEntryClicked", (BindingFlags)20); if (method != (MethodInfo)null) { Il2CppReferenceArray<Object> val7 = new Il2CppReferenceArray<Object>(1L) { [0] = ((Il2CppObjectBase)val6).Cast<Object>() }; ((MethodBase)method).Invoke((Object)(object)jukeboxInterface, val7); _config.LogDebug("Called SongEntryClicked via reflection"); } } } } } } } catch (Exception ex3) { MelonLogger.Error("Error playing track: " + ex3.Message); MelonLogger.Error(ex3.StackTrace); } } } else { _config.LogDebug("Starting to play track"); try { jukeboxInterface.Jukebox.PlayTrack(trackIndex); _config.LogDebug("PlayTrack called successfully"); if (!jukeboxInterface.Jukebox.IsPlaying) { _config.LogDebug("Track did not start playing, trying direct audio source approach"); if (_jukeboxPatcher.ForcePlayTrack(jukeboxInterface.Jukebox, trackIndex)) { _config.LogDebug("Successfully forced track to play"); } else { MelonLogger.Warning("Failed to force play track"); } } } catch (Exception ex4) { MelonLogger.Error("Error playing track: " + ex4.Message); MelonLogger.Error(ex4.StackTrace); } } RefreshPagination(jukeboxInterface); if (!jukeboxInterface.Jukebox.IsPlaying) { MelonLogger.Warning("Jukebox is not playing after PlayTrack call!"); try { FieldInfo field3 = ((Object)jukeboxInterface.Jukebox).GetIl2CppType().GetField("_audioSource", (BindingFlags)36); if (field3 != (FieldInfo)null) { Object value3 = field3.GetValue((Object)(object)jukeboxInterface.Jukebox); if (value3 != null) { AudioSource val8 = ((Il2CppObjectBase)value3).Cast<AudioSource>(); _config.LogDebug($"AudioSource state - IsPlaying: {val8.isPlaying}, " + $"Volume: {val8.volume}, " + "Clip: " + (((Object)(object)val8.clip != (Object)null) ? ((Object)val8.clip).name : "NULL")); } else { MelonLogger.Warning("AudioSource field is null"); } } return; } catch (Exception ex5) { MelonLogger.Error("Error checking AudioSource: " + ex5.Message); return; } } _config.LogDebug("Jukebox is now playing!"); } else { MelonLogger.Error("Jukebox is null or track index is out of range"); MethodInfo method2 = ((Object)jukeboxInterface).GetIl2CppType().GetMethod("SongEntryClicked", (BindingFlags)20); if (method2 != (MethodInfo)null) { Il2CppReferenceArray<Object> val9 = new Il2CppReferenceArray<Object>(1L) { [0] = ((Il2CppObjectBase)entry.GetComponent<RectTransform>()).Cast<Object>() }; ((MethodBase)method2).Invoke((Object)(object)jukeboxInterface, val9); } else { MelonLogger.Error("Could not find SongEntryClicked method via IL2CPP reflection"); } } } catch (Exception ex6) { MelonLogger.Error("Error in song entry click handler: " + ex6.Message); MelonLogger.Error(ex6.StackTrace); } }; if (!_paginationData.ContainsKey(jukeboxInterface)) { _paginationData[jukeboxInterface] = new PaginationData(); } RectTransform component = entry.GetComponent<RectTransform>(); if ((Object)(object)component != (Object)null) { _paginationData[jukeboxInterface].EntryClickActions[component] = action; } ((UnityEvent)((Component)entry.transform.Find("PlayPause")).GetComponent<Button>().onClick).AddListener(UnityAction.op_Implicit(action)); list.Add(entry.GetComponent<RectTransform>()); } List<RectTransform> val3 = new List<RectTransform>(); foreach (RectTransform item2 in list) { val3.Add(item2); } field.SetValue((Object)(object)jukeboxInterface, (Object)(object)val3); _config.LogDebug($"Successfully recreated {list.Count} song entries for jukebox {((Object)jukeboxInterface.Jukebox).GetInstanceID()}"); } catch (Exception ex) { MelonLogger.Error("Failed to recreate song entries: " + ex.Message); MelonLogger.Error(ex.StackTrace); } } public void CheckForUnpatchedInterfaces() { JukeboxInterface[] array = Il2CppArrayBase<JukeboxInterface>.op_Implicit(Object.FindObjectsOfType<JukeboxInterface>()); bool flag = false; JukeboxInterface[] array2 = array; foreach (JukeboxInterface val in array2) { if ((Object)(object)val != (Object)null && !_paginationData.ContainsKey(val)) { Jukebox jukebox = val.Jukebox; int num = ((jukebox != null) ? ((Object)jukebox).GetInstanceID() : (-1)); if (num != -1 && _jukeboxPatcher.IsJukeboxPatched(num)) { _config.LogDebug($"Found JukeboxInterface for already patched jukebox {num}, recreating song entries and setting up pagination"); RecreateSongEntries(val); SetupPagination(val); flag = true; } } } if (flag) { _config.LogDebug("Applied pagination to newly found jukebox interfaces from saved game"); } } [IteratorStateMachine(typeof(<CheckForSavedJukeboxInterfaces>d__13))] public IEnumerator CheckForSavedJukeboxInterfaces() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CheckForSavedJukeboxInterfaces>d__13(0) { <>4__this = this }; } } public class TrackManager { [CompilerGenerated] private sealed class <EnsureTrackLoaded>d__18 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public Track track; public Action<bool> onComplete; public TrackManager <>4__this; private string <filePath>5__1; private bool <success>5__2; private AudioClip <clip>5__3; private string <clipInfo>5__4; private Exception <ex>5__5; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EnsureTrackLoaded>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <filePath>5__1 = null; <clip>5__3 = null; <clipInfo>5__4 = null; <ex>5__5 = null; <>1__state = -2; } private bool MoveNext() { //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_024e: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Invalid comparison between Unknown and I4 if (<>1__state != 0) { return false; } <>1__state = -1; if (track == null) { <>4__this._config.LogDebug("Cannot load null track"); onComplete?.Invoke(obj: false); return false; } if ((Object)(object)track.Clip != (Object)null) { <>4__this._config.LogDebug("Track " + track.TrackName + " is already loaded"); onComplete?.Invoke(obj: true); return false; } if (!<>4__this._trackPaths.TryGetValue(track.TrackName, out <filePath>5__1)) { MelonLogger.Error("Could not find file path for track " + track.TrackName); onComplete?.Invoke(obj: false); return false; } <>4__this._config.LogDebug("Loading audio for track: " + track.TrackName); <success>5__2 = false; try { <clip>5__3 = API.LoadAudioClip(<filePath>5__1, true); if ((Object)(object)<clip>5__3 == (Object)null) { MelonLogger.Error("AudioImportLib returned null clip for " + track.TrackName); onComplete?.Invoke(obj: false); return false; } <clipInfo>5__4 = "Name: " + ((Object)<clip>5__3).name + ", " + $"Length: {<clip>5__3.length}s, " + $"Channels: {<clip>5__3.channels}, " + $"Frequency: {<clip>5__3.frequency}Hz, " + $"Samples: {<clip>5__3.samples}, " + $"LoadState: {<clip>5__3.loadState}, " + $"Loaded: {(int)<clip>5__3.loadState == 2}"; <>4__this._config.LogDebug("AudioImportLib Clip info: " + <clipInfo>5__4); ((Object)<clip>5__3).name = track.TrackName; track.Clip = <clip>5__3; <>4__this._config.LogDebug("Successfully loaded audio for track: " + track.TrackName); <success>5__2 = true; <clip>5__3 = null; <clipInfo>5__4 = null; } catch (Exception ex) { <ex>5__5 = ex; MelonLogger.Error("Error loading track with AudioImportLib: " + <ex>5__5.Message); MelonLogger.Error(<ex>5__5.StackTrace); } onComplete?.Invoke(<success>5__2); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LoadAudioFiles>d__17 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public TrackManager <>4__this; private string[] <audioFiles>5__1; private int <totalFiles>5__2; private int <i>5__3; private string <audioFile>5__4; private string <fileName>5__5; private Track <track>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadAudioFiles>d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <audioFiles>5__1 = null; <audioFile>5__4 = null; <fileName>5__5 = null; <track>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Expected O, but got Unknown int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0234; } <>1__state = -1; if (!<>4__this._config.EnableCustomTracks.Value) { MelonLogger.Msg("Custom tracks are disabled in settings"); <>4__this.TracksLoaded = true; return false; } if (!Directory.Exists(<>4__this._customSongsFolder)) { Directory.CreateDirectory(<>4__this._customSongsFolder); MelonLogger.Msg("Created custom songs folder at " + <>4__this._customSongsFolder); MelonLogger.Msg("Place your .mp3 or .wav files in this folder"); <>4__this.TracksLoaded = true; return false; } <audioFiles>5__1 = (from file in Directory.GetFiles(<>4__this._customSongsFolder) where file.EndsWith(".mp3", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".wav", StringComparison.OrdinalIgnoreCase) select file).ToArray(); if (<audioFiles>5__1.Length == 0) { MelonLogger.Msg("No audio files found in " + <>4__this._customSongsFolder); <>4__this.TracksLoaded = true; return false; } MelonLogger.Msg($"Found {<audioFiles>5__1.Length} audio files"); <totalFiles>5__2 = <audioFiles>5__1.Length; <i>5__3 = 0; goto IL_025c; IL_025c: if (<i>5__3 < <audioFiles>5__1.Length) { <audioFile>5__4 = <audioFiles>5__1[<i>5__3]; <fileName>5__5 = Path.GetFileNameWithoutExtension(<audioFile>5__4); <>4__this._trackPaths[<fileName>5__5] = <audioFile>5__4; <track>5__6 = new Track { TrackName = <fileName>5__5, ArtistName = "Custom", Clip = null }; <>4__this.CustomTracks.Add(<track>5__6); <>4__this.LoadingProgress = (float)(<i>5__3 + 1) / (float)<totalFiles>5__2; if (<i>5__3 % 10 == 0) { <>2__current = null; <>1__state = 1; return true; } goto IL_0234; } <>4__this.TracksLoaded = true; MelonLogger.Msg($"Successfully indexed {<>4__this.CustomTracks.Count} custom tracks (lazy loading enabled)"); return false; IL_0234: <audioFile>5__4 = null; <fileName>5__5 = null; <track>5__6 = null; <i>5__3++; goto IL_025c; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <LoadTrackCoroutine>d__19 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public string audioFile; public Action<Track> onComplete; public TrackManager <>4__this; private string <fileName>5__1; private string <extension>5__2; private AudioClip <clip>5__3; private string <clipInfo>5__4; private Track <track>5__5; private Exception <ex>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <LoadTrackCoroutine>d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <fileName>5__1 = null; <extension>5__2 = null; <clip>5__3 = null; <clipInfo>5__4 = null; <track>5__5 = null; <ex>5__6 = null; <>1__state = -2; } private bool MoveNext() { //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Invalid comparison between Unknown and I4 //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Expected O, but got Unknown if (<>1__state != 0) { return false; } <>1__state = -1; <fileName>5__1 = Path.GetFileNameWithoutExtension(audioFile); <extension>5__2 = Path.GetExtension(audioFile).ToLowerInvariant(); <>4__this._config.LogDebug("Loading " + <fileName>5__1 + " via AudioImportLib"); try { <clip>5__3 = API.LoadAudioClip(audioFile, true); if ((Object)(object)<clip>5__3 == (Object)null) { MelonLogger.Error("AudioImportLib returned null clip for " + <fileName>5__1); onComplete?.Invoke(null); return false; } <clipInfo>5__4 = "Name: " + ((Object)<clip>5__3).name + ", " + $"Length: {<clip>5__3.length}s, " + $"Channels: {<clip>5__3.channels}, " + $"Frequency: {<clip>5__3.frequency}Hz, " + $"Samples: {<clip>5__3.samples}, " + $"LoadState: {<clip>5__3.loadState}, " + $"Loaded: {(int)<clip>5__3.loadState == 2}"; <>4__this._config.LogDebug("AudioImportLib Clip info: " + <clipInfo>5__4); ((Object)<clip>5__3).name = <fileName>5__1; <track>5__5 = new Track { TrackName = <fileName>5__1, ArtistName = "Custom", Clip = <clip>5__3 }; <>4__this._config.LogDebug("Successfully loaded track: " + <fileName>5__1); onComplete?.Invoke(<track>5__5); <clip>5__3 = null; <clipInfo>5__4 = null; <track>5__5 = null; } catch (Exception ex) { <ex>5__6 = ex; MelonLogger.Error("Error loading track with AudioImportLib: " + <ex>5__6.Message); MelonLogger.Error(<ex>5__6.StackTrace); onComplete?.Invoke(null); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly ModConfig _config; private readonly string _customSongsFolder; private readonly Dictionary<string, string> _trackPaths = new Dictionary<string, string>(); private const float BATCH_INTERVAL = 0.1f; public List<Track> CustomTracks { get; private set; } = new List<Track>(); public bool TracksLoaded { get; private set; } public float LoadingProgress { get; private set; } public TrackManager(ModConfig config, string customSongsFolder) { _config = config; _customSongsFolder = customSongsFolder; } [IteratorStateMachine(typeof(<LoadAudioFiles>d__17))] public IEnumerator LoadAudioFiles() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadAudioFiles>d__17(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<EnsureTrackLoaded>d__18))] public IEnumerator EnsureTrackLoaded(Track track, Action<bool> onComplete = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EnsureTrackLoaded>d__18(0) { <>4__this = this, track = track, onComplete = onComplete }; } [IteratorStateMachine(typeof(<LoadTrackCoroutine>d__19))] private IEnumerator LoadTrackCoroutine(string audioFile, Action<Track> onComplete) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <LoadTrackCoroutine>d__19(0) { <>4__this = this, audioFile = audioFile, onComplete = onComplete }; } } } namespace BetterJukebox.Patches { public class HarmonyPatches { private readonly JukeboxPatcher _jukeboxPatcher; private readonly PaginationManager _paginationManager; private readonly TrackManager _trackManager; private Harmony _harmony; public HarmonyPatches(JukeboxPatcher jukeboxPatcher, PaginationManager paginationManager, TrackManager trackManager) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown _jukeboxPatcher = jukeboxPatcher; _paginationManager = paginationManager; _trackManager = trackManager; _harmony = new Harmony("com.bars.BetterJukebox"); } public void SetupPatches() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Expected O, but got Unknown //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(Jukebox), "Awake", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(HarmonyPatches), "JukeboxAwakePostfix", (Type[])null, (Type[])null); if (methodInfo != null && methodInfo2 != null) { _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MelonLogger.Msg("Successfully patched Jukebox.Awake method"); } else { MelonLogger.Warning("Failed to patch Jukebox.Awake method. Will use fallback scanning instead."); } MethodInfo methodInfo3 = AccessTools.Method(typeof(JukeboxInterface), "SetupSongEntries", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.Method(typeof(HarmonyPatches), "SetupSongEntriesPostfix", (Type[])null, (Type[])null); if (methodInfo3 != null && methodInfo4 != null) { _harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MelonLogger.Msg("Successfully patched JukeboxInterface.SetupSongEntries method"); } else { MelonLogger.Warning("Failed to patch JukeboxInterface.SetupSongEntries method"); } MethodInfo methodInfo5 = AccessTools.Method(typeof(JukeboxInterface), "Open", (Type[])null, (Type[])null); MethodInfo methodInfo6 = AccessTools.Method(typeof(HarmonyPatches), "OpenPostfix", (Type[])null, (Type[])null); if (methodInfo5 != null && methodInfo6 != null) { _harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, new HarmonyMethod(methodInfo6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } MethodInfo methodInfo7 = AccessTools.Method(typeof(JukeboxInterface), "RefreshSongEntries", (Type[])null, (Type[])null); MethodInfo methodInfo8 = AccessTools.Method(typeof(HarmonyPatches), "RefreshSongEntriesPrefix", (Type[])null, (Type[])null); if (methodInfo7 != null && methodInfo8 != null) { _harmony.Patch((MethodBase)methodInfo7, new HarmonyMethod(methodInfo8), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } try { MethodInfo methodInfo9 = AccessTools.Method(typeof(Jukebox), "PlayTrack", (Type[])null, (Type[])null); if (methodInfo9 != null) { MethodInfo methodInfo10 = AccessTools.Method(typeof(HarmonyPatches), "PlayTrackPrefix", (Type[])null, (Type[])null); _harmony.Patch((MethodBase)methodInfo9, new HarmonyMethod(methodInfo10), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MelonLogger.Msg("Successfully patched Jukebox.PlayTrack method"); } else { MelonLogger.Warning("Could not find Jukebox.PlayTrack method"); } } catch (Exception ex) { MelonLogger.Warning("Failed to patch PlayTrack method: " + ex.Message); } } catch (Exception ex2) { MelonLogger.Error("Failed to setup Harmony patches: " + ex2.Message); MelonLogger.Error(ex2.StackTrace); } } public static void JukeboxAwakePostfix(Jukebox __instance) { Core.OnJukeboxAwake(__instance); } public static void SetupSongEntriesPostfix(JukeboxInterface __instance) { Core.OnSetupSongEntries(__instance); } public static void OpenPostfix(JukeboxInterface __instance) { Core.OnJukeboxInterfaceOpen(__instance); } public static bool RefreshSongEntriesPrefix(JukeboxInterface __instance) { return Core.OnRefreshSongEntries(__instance); } public static bool PlayTrackPrefix(Jukebox __instance, int trackID) { return Core.OnPlayTrack(__instance, trackID); } } } namespace BetterJukebox.Models { public class PaginationData { public Action PrevButtonAction; public Action NextButtonAction; public Dictionary<RectTransform, Action> EntryClickActions = new Dictionary<RectTransform, Action>(); public int CurrentPage { get; set; } = 0; public int TotalPages { get; set; } = 1; public GameObject PaginationUI { get; set; } public Button PrevButton { get; set; } public Button NextButton { get; set; } public TextMeshProUGUI PageText { get; set; } public List<RectTransform> OriginalSongEntries { get; set; } = new List<RectTransform>(); } } namespace BetterJukebox.Config { public class ModConfig { private MelonPreferences_Category _category;