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 HarmonyLib;
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 TouhouMeltdownBGM;
[BepInPlugin("com.cutyimodo.touhounuclearmeltdownbgm", "Touhou Meltdown BGM", "1.0.7")]
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.mp3 ({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();
}
}
internal static Plugin instance;
internal static AudioClip meltdownClip;
internal static AudioSource audioSource;
internal static bool isPlaying;
internal static bool wasTriggered;
private bool wasInOrbit = true;
internal static ConfigEntry<float> volumeConfig;
private string musicPath;
private Harmony harmony;
private float suppressCheckTimer;
private const float SUPPRESS_INTERVAL = 0.5f;
private void Awake()
{
//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Expected O, but got Unknown
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));
}
harmony = new Harmony("com.cutyimodo.touhounuclearmeltdownbgm");
PatchLungProp();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Touhou Meltdown BGM v1.0.7 loaded! (Harmony patch mode)");
}
private void PatchLungProp()
{
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Expected O, but got Unknown
Type type = null;
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
type = assembly.GetType("LungProp");
if (type != null)
{
break;
}
}
if (type == null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"LungProp type not found! Cannot patch.");
return;
}
MethodInfo method = type.GetMethod("EquipItem", BindingFlags.Instance | BindingFlags.Public);
if (method == null)
{
((BaseUnityPlugin)this).Logger.LogError((object)"LungProp.EquipItem method not found!");
return;
}
MethodInfo method2 = typeof(LungPropPatch).GetMethod("Prefix", BindingFlags.Static | BindingFlags.Public);
harmony.Patch((MethodBase)method, new HarmonyMethod(method2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched LungProp.EquipItem successfully!");
}
[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
};
}
internal void TriggerMeltdownMusic()
{
if (!wasTriggered)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"Apparatus pulled! Starting meltdown music...");
wasTriggered = true;
((MonoBehaviour)this).StartCoroutine(PlayMusic());
}
}
private void Update()
{
if (GetIsDisconnecting() && (isPlaying || wasTriggered))
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"Disconnecting detected, stopping music.");
if (audioSource != null)
{
audioSource.Stop();
}
isPlaying = false;
wasTriggered = false;
wasInOrbit = true;
return;
}
if (isPlaying && audioSource != null)
{
object startOfRound = GetStartOfRound();
if (startOfRound == null)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"StartOfRound gone, stopping music.");
audioSource.Stop();
isPlaying = false;
wasTriggered = false;
return;
}
}
object startOfRound2 = GetStartOfRound();
if (startOfRound2 != null)
{
if (!GetBool(startOfRound2, "shipHasLanded"))
{
if (!wasInOrbit && wasTriggered)
{
wasTriggered = false;
if (audioSource != null && isPlaying)
{
audioSource.Stop();
isPlaying = false;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"Left moon, reset meltdown trigger for next round.");
}
wasInOrbit = true;
}
else
{
wasInOrbit = false;
}
}
if (isPlaying && audioSource != null)
{
suppressCheckTimer += Time.deltaTime;
if (suppressCheckTimer >= 0.5f)
{
suppressCheckTimer = 0f;
SuppressOtherAudio();
}
object startOfRound3 = GetStartOfRound();
if (startOfRound3 != null && GetBool(startOfRound3, "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;
}
}
}
}
private void OnDestroy()
{
wasTriggered = false;
isPlaying = false;
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
}
[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 bool GetIsDisconnecting()
{
try
{
Type type = null;
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in assemblies)
{
type = assembly.GetType("GameNetworkManager");
if (type != null)
{
break;
}
}
if (type == null)
{
return false;
}
PropertyInfo property = type.GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
object obj = ((property != null) ? property.GetValue(null) : null);
if (obj == null)
{
FieldInfo field = type.GetField("Instance", BindingFlags.Static | BindingFlags.Public);
obj = ((field != null) ? field.GetValue(null) : null);
}
if (obj == null)
{
return false;
}
PropertyInfo property2 = type.GetProperty("isDisconnecting", BindingFlags.Instance | BindingFlags.Public);
if (property2 != null)
{
return (bool)property2.GetValue(obj);
}
FieldInfo field2 = type.GetField("isDisconnecting", BindingFlags.Instance | BindingFlags.Public);
if (field2 != null)
{
return (bool)field2.GetValue(obj);
}
return false;
}
catch
{
return false;
}
}
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;
}
}
public static class LungPropPatch
{
public static void Prefix(object __instance)
{
if (Plugin.instance != null && !Plugin.wasTriggered)
{
Type type = __instance.GetType();
FieldInfo field = type.GetField("isLungDocked", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
if (!(field == null) && (bool)field.GetValue(__instance))
{
Plugin.instance.TriggerMeltdownMusic();
}
}
}
}