Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MithrixChimeraMusic v1.2.2
MithrixChimeraMusic.dll
Decompiled 2 weeks agousing 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<Type, bool> <>9__22_0; internal void <Awake>b__16_0(orig_OnEnter orig, Phase1 self) { orig.Invoke(self); OnPhaseEnter("Phase1"); } internal void <Awake>b__16_1(orig_OnEnter orig, Phase2 self) { orig.Invoke(self); OnPhaseEnter("Phase2"); } internal void <Awake>b__16_2(orig_OnEnter orig, Phase3 self) { orig.Invoke(self); OnPhaseEnter("Phase3"); } internal void <Awake>b__16_3(orig_OnEnter orig, Phase4 self) { orig.Invoke(self); OnPhaseEnter("Phase4"); } internal void <Awake>b__16_4(orig_BeginGameOver orig, Run self, GameEndingDef ending) { StopSong(); currentPhase = null; orig.Invoke(self, ending); } internal void <Awake>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 <PostWwiseEvent>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<string> phaseChoice; private static ConfigEntry<float> volume; private static ConfigEntry<bool> muteGameMusic; private static ConfigEntry<string> pauseEventName; private static ConfigEntry<string> resumeEventName; private static ConfigEntry<bool> 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<string>("General", "PhaseToPlayDuring", "Phase2", "Which Mithrix phase to play during. Valid: Phase1, Phase2, Phase3, Phase4."); volume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Volume", 0.7f, "0.0 to 1.0. Requires game restart to apply."); muteGameMusic = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio", "MuteGameMusic", true, "Pause Wwise music while the song plays."); pauseEventName = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "PauseEventName", "Pause_Music_System", "Wwise event posted on phase enter."); resumeEventName = ((BaseUnityPlugin)this).Config.Bind<string>("Audio", "ResumeEventName", "Resume_Music_System", "Wwise event posted on phase exit."); debugPlayOnStageStart = ((BaseUnityPlugin)this).Config.Bind<bool>("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)); } } } }