Decompiled source of IsMyFriendAlive v0.2.0

IsMyFriendAlive.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using GameNetcodeStuff;
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: AssemblyTitle("IsMyFriendAlive")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("IsMyFriendAlive")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("ab5d31f5-840a-470f-ad43-cd5fe63dcbe7")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace IsMyFriendAlive;

[BepInPlugin("thunder.deathsounds", "Is My Friend Alive", "0.2.0")]
public class DeathSoundPlugin : BaseUnityPlugin
{
	[CompilerGenerated]
	private sealed class <RestoreVolumeAfterDelay>d__14 : IEnumerator<object>, IDisposable, IEnumerator
	{
		private int <>1__state;

		private object <>2__current;

		public float delay;

		object IEnumerator<object>.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		object IEnumerator.Current
		{
			[DebuggerHidden]
			get
			{
				return <>2__current;
			}
		}

		[DebuggerHidden]
		public <RestoreVolumeAfterDelay>d__14(int <>1__state)
		{
			this.<>1__state = <>1__state;
		}

		[DebuggerHidden]
		void IDisposable.Dispose()
		{
			<>1__state = -2;
		}

		private bool MoveNext()
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			switch (<>1__state)
			{
			default:
				return false;
			case 0:
				<>1__state = -1;
				<>2__current = (object)new WaitForSeconds(delay);
				<>1__state = 1;
				return true;
			case 1:
				<>1__state = -1;
				AudioListener.volume = originalListenerVolume;
				isVolumeDucked = false;
				restoreCoroutine = null;
				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();
		}
	}

	private static ConfigEntry<float> SoundVolume;

	private static ConfigEntry<float> MainVolumeDecrease;

	private static List<AudioClip> deathSounds = new List<AudioClip>();

	private static AudioSource audioSource;

	private static float originalListenerVolume = 1f;

	private static bool isVolumeDucked = false;

	private static Coroutine restoreCoroutine;

	private static MonoBehaviour coroutineRunner;

	public static Dictionary<PlayerControllerB, bool> lastDeathState = new Dictionary<PlayerControllerB, bool>();

	private void Awake()
	{
		//IL_002f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0039: Expected O, but got Unknown
		//IL_006c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Expected O, but got Unknown
		//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Expected O, but got Unknown
		SoundVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Volume", 1f, new ConfigDescription("Thunder Sound Volume", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		MainVolumeDecrease = ((BaseUnityPlugin)this).Config.Bind<float>("Audio", "Game Volume", 0.2f, new ConfigDescription("How loud will the game main volume be when playing Thunderstorm Sound(0.2 means 20% from current value)", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
		audioSource = ((Component)this).gameObject.GetComponent<AudioSource>() ?? ((Component)this).gameObject.AddComponent<AudioSource>();
		audioSource.spatialBlend = 0f;
		audioSource.volume = SoundVolume.Value;
		audioSource.playOnAwake = false;
		audioSource.ignoreListenerVolume = true;
		if ((Object)(object)coroutineRunner == (Object)null)
		{
			coroutineRunner = (MonoBehaviour)(object)this;
		}
		LoadAllSounds();
		Harmony val = new Harmony("thunder.deathsounds");
		val.PatchAll(typeof(DeathPatch));
		((BaseUnityPlugin)this).Logger.LogInfo((object)$"IsMyFriendAlive Loaded, Sounds: {deathSounds.Count}");
	}

	private void LoadAllSounds()
	{
		string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
		if (!Directory.Exists(directoryName))
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("FolderIsMissing: " + directoryName));
			return;
		}
		string[] files = Directory.GetFiles(directoryName, "*.wav");
		string[] array = files;
		foreach (string text in array)
		{
			if (!text.EndsWith(".dll"))
			{
				string fileName = Path.GetFileName(text);
				AudioClip val = LoadWavSync(text);
				if ((Object)(object)val != (Object)null)
				{
					deathSounds.Add(val);
				}
			}
		}
	}

	private AudioClip LoadWavSync(string filePath)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Invalid comparison between Unknown and I4
		try
		{
			UnityWebRequest audioClip = UnityWebRequestMultimedia.GetAudioClip("file:///" + filePath, (AudioType)20);
			try
			{
				UnityWebRequestAsyncOperation val = audioClip.SendWebRequest();
				while (!((AsyncOperation)val).isDone)
				{
					Thread.Sleep(10);
				}
				if ((int)audioClip.result == 1)
				{
					AudioClip content = DownloadHandlerAudioClip.GetContent(audioClip);
					((Object)content).name = Path.GetFileName(filePath);
					return content;
				}
				((BaseUnityPlugin)this).Logger.LogError((object)("Error loading WAV: " + audioClip.error));
				return null;
			}
			finally
			{
				((IDisposable)audioClip)?.Dispose();
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Exception loading WAV: " + ex.Message));
			return null;
		}
	}

	public static void PlayRandomSound()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)audioSource == (Object)null)
		{
			GameObject val = new GameObject("DeathSoundSource");
			Object.DontDestroyOnLoad((Object)(object)val);
			audioSource = val.AddComponent<AudioSource>();
			audioSource.spatialBlend = 0f;
			audioSource.ignoreListenerVolume = true;
		}
		EnsureCoroutineRunner();
		if (deathSounds == null || deathSounds.Count == 0)
		{
			Debug.LogError((object)$"[IsMyFriendAlive] No sounds! Count: {deathSounds?.Count ?? 0}");
			return;
		}
		AudioClip val2 = deathSounds[Random.Range(0, deathSounds.Count)];
		if ((Object)(object)val2 == (Object)null)
		{
			Debug.LogError((object)"[IsMyFriendAlive] Selected clip is null!");
			return;
		}
		if (!isVolumeDucked)
		{
			originalListenerVolume = AudioListener.volume;
			AudioListener.volume = originalListenerVolume * MainVolumeDecrease.Value;
			isVolumeDucked = true;
		}
		if (audioSource.isPlaying)
		{
			audioSource.Stop();
		}
		if (restoreCoroutine != null && (Object)(object)coroutineRunner != (Object)null)
		{
			coroutineRunner.StopCoroutine(restoreCoroutine);
			restoreCoroutine = null;
		}
		audioSource.clip = val2;
		audioSource.volume = SoundVolume.Value;
		audioSource.Play();
		if ((Object)(object)coroutineRunner != (Object)null)
		{
			restoreCoroutine = coroutineRunner.StartCoroutine(RestoreVolumeAfterDelay(val2.length));
			return;
		}
		AudioListener.volume = originalListenerVolume;
		isVolumeDucked = false;
	}

	private static void EnsureCoroutineRunner()
	{
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001c: Expected O, but got Unknown
		if ((Object)(object)coroutineRunner == (Object)null)
		{
			GameObject val = new GameObject("DeathSoundCoroutineRunner");
			Object.DontDestroyOnLoad((Object)(object)val);
			coroutineRunner = (MonoBehaviour)(object)val.AddComponent<EmptyMonoBehaviour>();
		}
	}

	[IteratorStateMachine(typeof(<RestoreVolumeAfterDelay>d__14))]
	private static IEnumerator RestoreVolumeAfterDelay(float delay)
	{
		//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
		return new <RestoreVolumeAfterDelay>d__14(0)
		{
			delay = delay
		};
	}
}
internal class EmptyMonoBehaviour : MonoBehaviour
{
}
[HarmonyPatch(typeof(PlayerControllerB))]
internal static class DeathPatch
{
	[HarmonyPostfix]
	[HarmonyPatch("Update")]
	private static void OnUpdate(PlayerControllerB __instance)
	{
		if (!((Object)(object)__instance == (Object)null) && !((Object)(object)GameNetworkManager.Instance == (Object)null))
		{
			bool isPlayerDead = __instance.isPlayerDead;
			if (!DeathSoundPlugin.lastDeathState.TryGetValue(__instance, out var value))
			{
				value = false;
			}
			if (!value && isPlayerDead)
			{
				DeathSoundPlugin.PlayRandomSound();
			}
			DeathSoundPlugin.lastDeathState[__instance] = isPlayerDead;
		}
	}
}