using System; using System.Collections; using System.Diagnostics; using System.IO; using System.Linq; using System.Media; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [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.bungo.mithrixchimeramusic", "Mithrix Chimera Music", "1.2.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_BeginStage <>9__16_5; public static Func <>9__22_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_BeginStage orig, Run self) { orig.Invoke(self); if (debugPlayOnStageStart.Value) { Log.LogInfo((object)"[Debug] Stage started, triggering song"); StartSong(); } } internal bool b__22_0(Type t) { return t.Name == "AkSoundEngine"; } } public const string GUID = "com.bungo.mithrixchimeramusic"; public const string NAME = "Mithrix Chimera Music"; public const string VERSION = "1.2.2"; private const string ResourceName = "MithrixChimeraMusic.intermission.wav"; internal static ManualLogSource Log; private static SoundPlayer player; 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 static GameObject akTarget; 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."); volume = ((BaseUnityPlugin)this).Config.Bind("General", "Volume", 0.7f, "0.0 to 1.0. Requires game restart to apply."); muteGameMusic = ((BaseUnityPlugin)this).Config.Bind("Audio", "MuteGameMusic", true, "Pause Wwise music while the song plays."); 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, "Play the song at the start of every stage."); ((MonoBehaviour)this).StartCoroutine(LoadCoroutine()); 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_BeginStage val6 = delegate(orig_BeginStage orig, Run self) { orig.Invoke(self); if (debugPlayOnStageStart.Value) { Log.LogInfo((object)"[Debug] Stage started, triggering song"); StartSong(); } }; <>c.<>9__16_5 = val6; obj6 = (object)val6; } Run.BeginStage += (hook_BeginStage)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 LoadCoroutine() { yield return null; Assembly executingAssembly = Assembly.GetExecutingAssembly(); Stream manifestResourceStream = executingAssembly.GetManifestResourceStream("MithrixChimeraMusic.intermission.wav"); if (manifestResourceStream == null) { Log.LogError((object)("Embedded resource 'MithrixChimeraMusic.intermission.wav' not found. Available: " + string.Join(", ", executingAssembly.GetManifestResourceNames()))); yield break; } byte[] array; using (MemoryStream memoryStream = new MemoryStream()) { manifestResourceStream.CopyTo(memoryStream); array = memoryStream.ToArray(); } manifestResourceStream.Dispose(); Log.LogInfo((object)$"WAV resource loaded: {array.Length} bytes"); ApplyVolumeToPCM16(array, volume.Value); string text = Path.Combine(Paths.CachePath, "MithrixChimeraMusic"); Directory.CreateDirectory(text); string text2 = Path.Combine(text, "intermission.wav"); File.WriteAllBytes(text2, array); Log.LogInfo((object)("Wrote WAV to " + text2)); try { player = new SoundPlayer(text2); player.LoadAsync(); Log.LogInfo((object)"SoundPlayer.LoadAsync called"); } catch (Exception arg) { Log.LogError((object)$"SoundPlayer init failed: {arg}"); yield break; } Log.LogInfo((object)"Mithrix Chimera Music loaded"); } private static void ApplyVolumeToPCM16(byte[] data, float v) { if (Math.Abs(v - 1f) < 0.001f) { return; } if (v < 0f) { v = 0f; } if (data.Length < 44) { return; } int num = 0; int num2 = 0; int num3 = -1; int num4 = 0; int num5; for (int i = 12; i <= data.Length - 8; i += 8 + num5 + (num5 & 1)) { string @string = Encoding.ASCII.GetString(data, i, 4); num5 = BitConverter.ToInt32(data, i + 4); if (@string == "fmt ") { num = BitConverter.ToInt16(data, i + 8); num2 = BitConverter.ToInt16(data, i + 22); } else if (@string == "data") { num3 = i + 8; num4 = num5; break; } } if (num != 1 || num2 != 16 || num3 < 0) { Log.LogWarning((object)$"Skipping volume scale (format={num}, bits={num2}); file plays at native volume"); return; } int num6 = Math.Min(num3 + num4, data.Length - 1); for (int j = num3; j + 1 < num6; j += 2) { int num7 = (int)((float)BitConverter.ToInt16(data, j) * v); if (num7 > 32767) { num7 = 32767; } if (num7 < -32768) { num7 = -32768; } data[j] = (byte)((uint)num7 & 0xFFu); data[j + 1] = (byte)((uint)(num7 >> 8) & 0xFFu); } Log.LogInfo((object)$"Applied volume scale {v:F2}"); } private static void StartSong() { if (player == null) { Log.LogWarning((object)"Phase entered before SoundPlayer ready"); return; } if (muteGameMusic.Value) { PostWwiseEvent(pauseEventName.Value); } try { player.PlayLooping(); Log.LogInfo((object)"Custom song started (SoundPlayer.PlayLooping)"); } catch (Exception ex) { Log.LogError((object)("PlayLooping failed: " + ex.Message)); } } private static void StopSong() { if (player != null) { try { player.Stop(); } catch (Exception ex) { Log.LogWarning((object)("Stop failed: " + ex.Message)); } if (muteGameMusic.Value) { PostWwiseEvent(resumeEventName.Value); } Log.LogInfo((object)"Custom song stopped"); } } private static void PostWwiseEvent(string eventName) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Expected O, but got Unknown 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) }); akTarget = new GameObject("MithrixChimeraMusicWwiseTarget"); Object.DontDestroyOnLoad((Object)(object)akTarget); } else { Log.LogWarning((object)"AkSoundEngine type not found, game music won't be muted"); } } if (akPostEvent != null && (Object)(object)akTarget != (Object)null) { akPostEvent.Invoke(null, new object[2] { eventName, akTarget }); Log.LogInfo((object)("Wwise event posted: " + eventName)); } } catch (Exception ex) { Log.LogWarning((object)("Wwise event post failed: " + ex.Message)); } } } }