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 d__14 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public float delay; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public 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 SoundVolume; private static ConfigEntry MainVolumeDecrease; private static List deathSounds = new List(); 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 lastDeathState = new Dictionary(); 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("Audio", "Volume", 1f, new ConfigDescription("Thunder Sound Volume", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); MainVolumeDecrease = ((BaseUnityPlugin)this).Config.Bind("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(0f, 1f), Array.Empty())); audioSource = ((Component)this).gameObject.GetComponent() ?? ((Component)this).gameObject.AddComponent(); 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.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(); } } [IteratorStateMachine(typeof(d__14))] private static IEnumerator RestoreVolumeAfterDelay(float delay) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new 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; } } }