Please disclose if your mod was created primarily 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 TouhouMeltdownMusic v1.4.1
plugins/TouhouMeltdownMusic/TouhouMeltdownMusic.dll
Decompiled 2 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] namespace TouhouMeltdownMusic; [BepInPlugin("com.cutyimodo.touhounuclearmeltdownmusic", "Touhou Nuclear Meltdown Music", "1.0.3")] public class Plugin : BaseUnityPlugin { [CompilerGenerated] private sealed class <FadeOutAndStop>d__19 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float duration; public Plugin <>4__this; private float <startVol>5__1; private float <elapsed>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <FadeOutAndStop>d__19(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 (!isPlaying || audioSource == null) { return false; } isPlaying = false; <startVol>5__1 = audioSource.volume; <elapsed>5__2 = 0f; break; case 1: <>1__state = -1; break; } if (<elapsed>5__2 < duration) { <elapsed>5__2 += Time.deltaTime; if (audioSource != null) { audioSource.volume = Mathf.Lerp(<startVol>5__1, 0f, <elapsed>5__2 / duration); } <>2__current = null; <>1__state = 1; return true; } if (audioSource != null) { audioSource.Stop(); audioSource.volume = <startVol>5__1; } ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)"Meltdown music stopped"); 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 <PlayMusic>d__18 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private float <timeout>5__1; private float <waited>5__2; private float <elapsed>5__3; private float <targetVol>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PlayMusic>d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Invalid comparison between Unknown and I4 //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Invalid comparison between Unknown and I4 switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (isPlaying) { return false; } <timeout>5__1 = 10f; <waited>5__2 = 0f; goto IL_007c; case 1: <>1__state = -1; goto IL_007c; case 2: { <>1__state = -1; break; } IL_007c: if ((meltdownClip == null || (int)meltdownClip.loadState == 1) && <waited>5__2 < <timeout>5__1) { <waited>5__2 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } if (meltdownClip == null || (int)meltdownClip.loadState != 2) { ((BaseUnityPlugin)<>4__this).Logger.LogError((object)$"Cannot play: audio clip not loaded (clip null: {meltdownClip == null})"); return false; } if (audioSource == null) { audioSource = ((Component)<>4__this).gameObject.AddComponent<AudioSource>(); audioSource.spatialBlend = 0f; audioSource.loop = true; audioSource.playOnAwake = false; audioSource.priority = 0; } audioSource.clip = meltdownClip; audioSource.volume = 0f; audioSource.Play(); isPlaying = true; <>4__this.SuppressOtherAudio(); ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"Playing meltdown music! (clip: {meltdownClip.length}s, {meltdownClip.channels}ch)"); <elapsed>5__3 = 0f; <targetVol>5__4 = volumeConfig.Value; break; } if (<elapsed>5__3 < 1f) { <elapsed>5__3 += Time.deltaTime; if (audioSource != null) { audioSource.volume = Mathf.Lerp(0f, <targetVol>5__4, <elapsed>5__3 / 1f); } <>2__current = null; <>1__state = 2; return true; } if (audioSource != null) { audioSource.volume = <targetVol>5__4; } 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 <PreloadAudio>d__13 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; private string <fileUri>5__1; private float <timeout>5__2; private float <waited>5__3; private UnityWebRequest <request>5__4; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <PreloadAudio>d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <fileUri>5__1 = null; <request>5__4 = null; <>1__state = -2; } private bool MoveNext() { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Invalid comparison between Unknown and I4 //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Invalid comparison between Unknown and I4 //IL_022a: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; goto end_IL_0000; case 0: <>1__state = -1; <fileUri>5__1 = "file:///" + <>4__this.musicPath.Replace("\\", "/"); <request>5__4 = UnityWebRequest.Get(<fileUri>5__1); <>1__state = -3; <request>5__4.downloadHandler = (DownloadHandler)new DownloadHandlerAudioClip(<fileUri>5__1, (AudioType)13); <>2__current = <request>5__4.SendWebRequest(); <>1__state = 1; result = true; goto end_IL_0000; case 1: <>1__state = -3; if (<request>5__4.isNetworkError || <request>5__4.isHttpError) { ((BaseUnityPlugin)<>4__this).Logger.LogError((object)("Failed to preload audio: " + <request>5__4.error)); result = false; <>m__Finally1(); } else { meltdownClip = DownloadHandlerAudioClip.GetContent(<request>5__4); <>m__Finally1(); <request>5__4 = null; if (meltdownClip != null) { <timeout>5__2 = 5f; <waited>5__3 = 0f; break; } ((BaseUnityPlugin)<>4__this).Logger.LogError((object)"Audio clip is null after preload"); result = false; } goto end_IL_0000; case 2: <>1__state = -1; break; } if ((int)meltdownClip.loadState == 1 && <waited>5__3 < <timeout>5__2) { <waited>5__3 += Time.deltaTime; <>2__current = null; <>1__state = 2; result = true; } else { if ((int)meltdownClip.loadState == 2) { ((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)$"Preloaded NuclearFusion.ogg ({meltdownClip.length}s, {meltdownClip.channels}ch)"); } else { ((BaseUnityPlugin)<>4__this).Logger.LogError((object)$"Audio preload failed, state: {meltdownClip.loadState}"); } result = false; } end_IL_0000:; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<request>5__4 != null) { ((IDisposable)<request>5__4).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static Plugin instance; private static AudioClip meltdownClip; private static AudioSource audioSource; private static bool isPlaying; private static bool wasTriggered; private static ConfigEntry<float> volumeConfig; private string musicPath; private Type lungPropType; private bool typesResolved; private bool typesFailed; private float suppressCheckTimer; private const float SUPPRESS_INTERVAL = 0.5f; private void Awake() { instance = this; volumeConfig = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Volume", 0.8f, "Music volume (0.0 - 1.0)"); string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); musicPath = Path.Combine(directoryName, "NuclearFusion.mp3"); if (File.Exists(musicPath)) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Found music file at " + musicPath)); ((MonoBehaviour)this).StartCoroutine(PreloadAudio()); } else { ((BaseUnityPlugin)this).Logger.LogError((object)("Music file not found at " + musicPath)); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Touhou Nuclear Meltdown Music v1.0.3 loaded! (polling mode, audio suppression)"); } [IteratorStateMachine(typeof(<PreloadAudio>d__13))] private IEnumerator PreloadAudio() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PreloadAudio>d__13(0) { <>4__this = this }; } private void ResolveTypes() { if (typesResolved || typesFailed) { return; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { lungPropType = assembly.GetType("LungProp"); if (lungPropType != null) { break; } } if (lungPropType == null) { typesFailed = true; ((BaseUnityPlugin)this).Logger.LogError((object)"LungProp type not found!"); } else { typesResolved = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)"Types resolved successfully"); } } private void Update() { ResolveTypes(); if (typesFailed) { return; } if (!wasTriggered) { Object[] array = Object.FindObjectsOfType(lungPropType); if (array != null) { Object[] array2 = array; foreach (Object obj in array2) { bool @bool = GetBool(obj, "isLungDocked"); bool bool2 = GetBool(obj, "isLungPowered"); if (!@bool && !bool2) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Apparatus pull detected! Starting music..."); wasTriggered = true; ((MonoBehaviour)this).StartCoroutine(PlayMusic()); break; } } } } if (isPlaying && audioSource != null) { object startOfRound = GetStartOfRound(); if (startOfRound == null) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"StartOfRound gone (main menu?), stopping music."); audioSource.Stop(); isPlaying = false; wasTriggered = false; return; } } if (isPlaying && audioSource != null) { suppressCheckTimer += Time.deltaTime; if (suppressCheckTimer >= 0.5f) { suppressCheckTimer = 0f; SuppressOtherAudio(); } object startOfRound2 = GetStartOfRound(); if (startOfRound2 != null && GetBool(startOfRound2, "shipIsLeaving")) { ((MonoBehaviour)this).StartCoroutine(FadeOutAndStop(2f)); } } } private void SuppressOtherAudio() { AudioSource[] array = Object.FindObjectsOfType<AudioSource>(); if (array == null) { return; } AudioSource[] array2 = array; foreach (AudioSource val in array2) { if (val != null && val != audioSource && val.isPlaying) { string text = ((((Component)val).gameObject != null) ? ((Object)((Component)val).gameObject).name.ToLower() : ""); string text2 = ((val.clip != null && ((Object)val.clip).name != null) ? ((Object)val.clip).name.ToLower() : ""); if (text.Contains("meltdown") || text.Contains("facilitymeltdown") || text2.Contains("meltdown")) { val.volume = 0f; val.mute = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Suppressed FacilityMeltdown audio: " + ((Object)((Component)val).gameObject).name + "/" + text2)); } } } } private void OnDestroy() { wasTriggered = false; isPlaying = false; } [IteratorStateMachine(typeof(<PlayMusic>d__18))] private IEnumerator PlayMusic() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <PlayMusic>d__18(0) { <>4__this = this }; } [IteratorStateMachine(typeof(<FadeOutAndStop>d__19))] private IEnumerator FadeOutAndStop(float duration) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <FadeOutAndStop>d__19(0) { <>4__this = this, duration = duration }; } private static object GetStartOfRound() { Type type = null; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { type = assembly.GetType("StartOfRound"); if (type != null) { break; } } if (type == null) { return null; } PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public); if (property != null) { return property.GetValue(null); } FieldInfo field = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public); if (field != null) { return field.GetValue(null); } return null; } private static bool GetBool(object obj, string name) { if (obj == null) { return false; } Type type = obj.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null) { return (bool)property.GetValue(obj); } FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public); if (field != null) { return (bool)field.GetValue(obj); } return false; } }