Decompiled source of TouhouMeltdownMusic v1.4.1

plugins/TouhouMeltdownMusic/TouhouMeltdownMusic.dll

Decompiled a day ago
using 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;
	}
}