using System; using System.Collections; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EntityStates.Missions.BrotherEncounter; using Microsoft.CodeAnalysis; using On.EntityStates.Missions.BrotherEncounter; using On.RoR2; using RoR2; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MithrixChimeraMusic")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MithrixChimeraMusic")] [assembly: AssemblyTitle("MithrixChimeraMusic")] [assembly: AssemblyVersion("1.0.0.0")] [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 MithrixChimeraMusic { [BepInPlugin("com.emerson.mithrixchimeramusic", "Mithrix Chimera Music", "1.0.2")] public class Plugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static hook_OnEnter <>9__16_0; public static hook_OnEnter <>9__16_1; public static hook_OnEnter <>9__16_2; public static hook_OnEnter <>9__16_3; public static hook_BeginGameOver <>9__16_4; public static hook_Start <>9__16_5; public static Func <>9__21_0; internal void b__16_0(orig_OnEnter orig, Phase1 self) { orig.Invoke(self); OnPhaseEnter("Phase1"); } internal void b__16_1(orig_OnEnter orig, Phase2 self) { orig.Invoke(self); OnPhaseEnter("Phase2"); } internal void b__16_2(orig_OnEnter orig, Phase3 self) { orig.Invoke(self); OnPhaseEnter("Phase3"); } internal void b__16_3(orig_OnEnter orig, Phase4 self) { orig.Invoke(self); OnPhaseEnter("Phase4"); } internal void b__16_4(orig_BeginGameOver orig, Run self, GameEndingDef ending) { StopSong(); currentPhase = null; orig.Invoke(self, ending); } internal void b__16_5(orig_Start orig, Stage self) { orig.Invoke(self); if (debugPlayOnStageStart.Value) { Log.LogInfo((object)"[Debug] Stage started — triggering song"); StartSong(); } } internal bool b__21_0(Type t) { return t.Name == "AkSoundEngine"; } } public const string GUID = "com.emerson.mithrixchimeramusic"; public const string NAME = "Mithrix Chimera Music"; public const string VERSION = "1.0.2"; private const string ResourceName = "MithrixChimeraMusic.intermission.ogg"; internal static ManualLogSource Log; private static AudioClip clip; private static AudioSource source; private static ConfigEntry phaseChoice; private static ConfigEntry volume; private static ConfigEntry muteGameMusic; private static ConfigEntry pauseEventName; private static ConfigEntry resumeEventName; private static ConfigEntry debugPlayOnStageStart; private static MethodInfo akPostEvent; private static bool akLookupAttempted; private static string currentPhase; private void Awake() { //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; phaseChoice = ((BaseUnityPlugin)this).Config.Bind("General", "PhaseToPlayDuring", "Phase2", "Which Mithrix phase to play during. Valid: Phase1, Phase2, Phase3, Phase4. Watch the BepInEx console — every phase entry is logged so you can verify."); volume = ((BaseUnityPlugin)this).Config.Bind("General", "Volume", 0.7f, "0.0 to 1.0"); muteGameMusic = ((BaseUnityPlugin)this).Config.Bind("Audio", "MuteGameMusic", true, "Try to pause Wwise music while the song plays. Best-effort — falls back to overlap if the Wwise call fails."); pauseEventName = ((BaseUnityPlugin)this).Config.Bind("Audio", "PauseEventName", "Pause_Music_System", "Wwise event posted on phase enter."); resumeEventName = ((BaseUnityPlugin)this).Config.Bind("Audio", "ResumeEventName", "Resume_Music_System", "Wwise event posted on phase exit."); debugPlayOnStageStart = ((BaseUnityPlugin)this).Config.Bind("Debug", "PlayOnStageStart", false, "DEBUG: play the song at the start of every stage instead of waiting for the Mithrix fight. Useful for verifying audio works without grinding to phase 2."); ((MonoBehaviour)this).StartCoroutine(LoadClipCoroutine()); object obj = <>c.<>9__16_0; if (obj == null) { hook_OnEnter val = delegate(orig_OnEnter orig, Phase1 self) { orig.Invoke(self); OnPhaseEnter("Phase1"); }; <>c.<>9__16_0 = val; obj = (object)val; } Phase1.OnEnter += (hook_OnEnter)obj; object obj2 = <>c.<>9__16_1; if (obj2 == null) { hook_OnEnter val2 = delegate(orig_OnEnter orig, Phase2 self) { orig.Invoke(self); OnPhaseEnter("Phase2"); }; <>c.<>9__16_1 = val2; obj2 = (object)val2; } Phase2.OnEnter += (hook_OnEnter)obj2; object obj3 = <>c.<>9__16_2; if (obj3 == null) { hook_OnEnter val3 = delegate(orig_OnEnter orig, Phase3 self) { orig.Invoke(self); OnPhaseEnter("Phase3"); }; <>c.<>9__16_2 = val3; obj3 = (object)val3; } Phase3.OnEnter += (hook_OnEnter)obj3; object obj4 = <>c.<>9__16_3; if (obj4 == null) { hook_OnEnter val4 = delegate(orig_OnEnter orig, Phase4 self) { orig.Invoke(self); OnPhaseEnter("Phase4"); }; <>c.<>9__16_3 = val4; obj4 = (object)val4; } Phase4.OnEnter += (hook_OnEnter)obj4; object obj5 = <>c.<>9__16_4; if (obj5 == null) { hook_BeginGameOver val5 = delegate(orig_BeginGameOver orig, Run self, GameEndingDef ending) { StopSong(); currentPhase = null; orig.Invoke(self, ending); }; <>c.<>9__16_4 = val5; obj5 = (object)val5; } Run.BeginGameOver += (hook_BeginGameOver)obj5; object obj6 = <>c.<>9__16_5; if (obj6 == null) { hook_Start val6 = delegate(orig_Start orig, Stage self) { orig.Invoke(self); if (debugPlayOnStageStart.Value) { Log.LogInfo((object)"[Debug] Stage started — triggering song"); StartSong(); } }; <>c.<>9__16_5 = val6; obj6 = (object)val6; } Stage.Start += (hook_Start)obj6; } private static void OnPhaseEnter(string name) { Log.LogInfo((object)("[Mithrix] Entered phase: " + name)); if (currentPhase == phaseChoice.Value && name != phaseChoice.Value) { StopSong(); } currentPhase = name; if (name == phaseChoice.Value) { StartSong(); } } private IEnumerator LoadClipCoroutine() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream("MithrixChimeraMusic.intermission.ogg"); if (manifestResourceStream == null) { Log.LogError((object)("Embedded resource 'MithrixChimeraMusic.intermission.ogg' not found. Available: " + string.Join(", ", executingAssembly.GetManifestResourceNames()))); yield break; } string text = Path.Combine(Application.temporaryCachePath, "mithrix_chimera_song.ogg"); using (FileStream destination = File.Create(text)) { manifestResourceStream.CopyTo(destination); } manifestResourceStream.Dispose(); Log.LogInfo((object)$"Wrote OGG to {text} ({new FileInfo(text).Length} bytes)"); string absoluteUri = new Uri(text).AbsoluteUri; UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(absoluteUri, (AudioType)14); try { ((DownloadHandlerAudioClip)req.downloadHandler).streamAudio = false; yield return req.SendWebRequest(); if ((int)req.result != 1) { Log.LogError((object)("Audio load failed: " + req.error)); yield break; } clip = DownloadHandlerAudioClip.GetContent(req); if ((Object)(object)clip == (Object)null || clip.length <= 0f) { ManualLogSource log = Log; object arg = (Object)(object)clip == (Object)null; AudioClip obj = clip; log.LogError((object)$"AudioClip invalid (null={arg}, length={((obj != null) ? new float?(obj.length) : null)})"); yield break; } ((Object)clip).name = "MithrixChimeraSong"; Log.LogInfo((object)$"Clip loaded: {clip.length:F1}s, {clip.channels}ch, {clip.frequency}Hz, samples={clip.samples}"); GameObject val = new GameObject("MithrixChimeraMusicSource"); Object.DontDestroyOnLoad((Object)val); source = val.AddComponent(); source.clip = clip; source.loop = true; source.playOnAwake = false; source.spatialBlend = 0f; source.bypassEffects = true; source.bypassListenerEffects = true; source.bypassReverbZones = true; source.ignoreListenerPause = true; source.ignoreListenerVolume = false; source.volume = volume.Value; Log.LogInfo((object)"Mithrix Chimera Music loaded"); } finally { ((IDisposable)req)?.Dispose(); } } private static void StartSong() { if ((Object)(object)source == (Object)null) { Log.LogWarning((object)"Phase entered before AudioSource created"); } else if ((Object)(object)source.clip == (Object)null) { Log.LogError((object)"StartSong called but clip is null — load failed silently"); } else if (!source.isPlaying) { if (muteGameMusic.Value) { PostWwiseEvent(pauseEventName.Value); } source.volume = volume.Value; AudioListener.pause = false; source.Play(); Log.LogInfo((object)$"Custom song started (volume={source.volume}, listenerVol={AudioListener.volume}, listenerPaused={AudioListener.pause}, isPlaying={source.isPlaying})"); } } private static void StopSong() { if (!((Object)(object)source == (Object)null)) { source.Stop(); if (muteGameMusic.Value) { PostWwiseEvent(resumeEventName.Value); } Log.LogInfo((object)"Custom song stopped"); } } private static void PostWwiseEvent(string eventName) { try { if (!akLookupAttempted) { akLookupAttempted = true; Type type = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { type = assembly.GetTypes().FirstOrDefault((Type t) => t.Name == "AkSoundEngine"); } catch { continue; } if (type != null) { break; } } if (type != null) { akPostEvent = type.GetMethod("PostEvent", new Type[2] { typeof(string), typeof(GameObject) }); } else { Log.LogWarning((object)"AkSoundEngine type not found at runtime — game music won't be muted"); } } if (akPostEvent != null && (Object)(object)source != (Object)null) { akPostEvent.Invoke(null, new object[2] { eventName, ((Component)source).gameObject }); } } catch (Exception ex) { Log.LogWarning((object)("Wwise event post failed: " + ex.Message)); } } } }