Decompiled source of Rezero ReturnByDeath v2.0.3

plugins/ReturnByDeath.dll

Decompiled 2 months ago
using System;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using ReturnByDeath.Patches;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ReturnByDeath")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ReturnByDeath")]
[assembly: AssemblyCopyright("Copyright ©  2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("04f7ab02-1427-4ec5-b84a-1917d3c59b27")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ReturnByDeath
{
	[BepInPlugin("quocnam612.ReturnByDeath", "Rezero Return By Death SFX", "2.0.2")]
	public class ReturnByDeathBase : BaseUnityPlugin
	{
		private const string modGUID = "quocnam612.ReturnByDeath";

		private const string modName = "Rezero Return By Death SFX";

		private const string modVersion = "2.0.2";

		private readonly Harmony harmony = new Harmony("quocnam612.ReturnByDeath");

		public static ReturnByDeathBase Instance;

		internal ManualLogSource mls;

		internal static List<AudioClip> SoundFX;

		public static ConfigEntry<bool> EnableRbdSFX;

		public static ConfigEntry<bool> EnableWitchSFX;

		public static ConfigEntry<bool> EnableRingSFX;

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			mls = Logger.CreateLogSource("quocnam612.ReturnByDeath");
			mls.LogInfo((object)"[Rezero Return By Death SFX] v2.0.2 is loaded!");
			EnableRbdSFX = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Toggles", "EnableReturnByDeathSFX", true, "Toggle whether the Return By Death SFX (when player teleport)  is enabled.");
			EnableWitchSFX = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Toggles", "EnableWitchSFX", true, "Toggle whether the Witch SFX (when a dead body is seen and intense fear reached) is enabled.");
			EnableRingSFX = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio Toggles", "EnableRingSFX", true, "Toggle whether the Truck delivery music (Subaru phone ring) is enabled.");
			SoundFX = new List<AudioClip> { null, null, null, null, null };
			LoadSounds();
			harmony.PatchAll(typeof(ReturnByDeathBase));
			harmony.PatchAll(typeof(SoundManagerPatch));
			harmony.PatchAll(typeof(DeadBodyInfoPatch));
			harmony.PatchAll(typeof(ItemDropshipAudioPatch));
			harmony.PatchAll(typeof(ShipTeleporterPatch));
			LethalThingsPatch.Apply(harmony);
			mls = ((BaseUnityPlugin)this).Logger;
		}

		private void LoadSounds()
		{
			string path = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "sounds");
			string[] array = new string[5] { "rbd.wav", "witch1.wav", "witch2.wav", "ring.wav", "ringfar.wav" };
			for (int i = 0; i < array.Length; i++)
			{
				string text = array[i];
				string text2 = Path.Combine(path, text);
				if (!File.Exists(text2))
				{
					mls.LogError((object)("Missing sound file: " + text2));
					continue;
				}
				try
				{
					AudioClip value = LoadWav(text2);
					SoundFX[i] = value;
					mls.LogInfo((object)$"Loaded {text} as SoundFX[{i}]");
				}
				catch (Exception ex)
				{
					mls.LogError((object)("Failed to load " + text + ": " + ex.Message));
				}
			}
			ShipTeleporterPatch.ApplyToExisting();
			LethalThingsPatch.ApplyToExisting();
		}

		private static AudioClip LoadWav(string path)
		{
			using BinaryReader binaryReader = new BinaryReader(File.OpenRead(path));
			if (new string(binaryReader.ReadChars(4)) != "RIFF")
			{
				throw new InvalidDataException("Not a WAV file.");
			}
			binaryReader.ReadInt32();
			if (new string(binaryReader.ReadChars(4)) != "WAVE")
			{
				throw new InvalidDataException("Not a WAV file.");
			}
			short num = 0;
			short num2 = 0;
			int num3 = 0;
			short num4 = 0;
			byte[] array = null;
			while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
			{
				string text = new string(binaryReader.ReadChars(4));
				int num5 = binaryReader.ReadInt32();
				if (text == "fmt ")
				{
					num = binaryReader.ReadInt16();
					num2 = binaryReader.ReadInt16();
					num3 = binaryReader.ReadInt32();
					binaryReader.ReadInt32();
					binaryReader.ReadInt16();
					num4 = binaryReader.ReadInt16();
					binaryReader.BaseStream.Position += num5 - 16;
				}
				else if (text == "data")
				{
					array = binaryReader.ReadBytes(num5);
				}
				else
				{
					binaryReader.BaseStream.Position += num5;
				}
				if (num5 % 2 != 0)
				{
					binaryReader.BaseStream.Position++;
				}
			}
			if (num != 1 || num4 != 16 || num2 <= 0 || array == null)
			{
				throw new InvalidDataException("Only 16-bit PCM WAV files are supported.");
			}
			float[] array2 = new float[array.Length / 2];
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i] = (float)BitConverter.ToInt16(array, i * 2) / 32768f;
			}
			AudioClip val = AudioClip.Create(Path.GetFileNameWithoutExtension(path), array2.Length / num2, (int)num2, num3, false);
			val.SetData(array2, 0);
			return val;
		}
	}
}
namespace ReturnByDeath.Patches
{
	[HarmonyPatch(typeof(DeadBodyInfo), "DetectIfSeenByLocalPlayer")]
	internal class DeadBodyInfoPatch
	{
		[HarmonyPrefix]
		private static void Before(DeadBodyInfo __instance, ref bool __state)
		{
			if (ReturnByDeathBase.EnableWitchSFX.Value)
			{
				__state = __instance.seenByLocalPlayer;
			}
		}

		[HarmonyPostfix]
		private static void After(DeadBodyInfo __instance, bool __state)
		{
			if (ReturnByDeathBase.EnableWitchSFX.Value && !__state && __instance.seenByLocalPlayer)
			{
				SoundManagerPatch.TriggerWitch2();
			}
		}
	}
	[HarmonyPatch(typeof(ItemDropship), "Start")]
	internal class ItemDropshipAudioPatch
	{
		[HarmonyPostfix]
		private static void Postfix(ItemDropship __instance)
		{
			if (!ReturnByDeathBase.EnableRingSFX.Value || ReturnByDeathBase.SoundFX == null || ReturnByDeathBase.SoundFX.Count == 0)
			{
				return;
			}
			AudioSource[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<AudioSource>(true);
			AudioSource[] array = componentsInChildren;
			foreach (AudioSource val in array)
			{
				if (!((Object)(object)val.clip == (Object)null))
				{
					string name = ((Object)val.clip).name;
					if (name.Equals("IcecreamTruckV2VehicleDeliveryVer", StringComparison.OrdinalIgnoreCase))
					{
						val.clip = ReturnByDeathBase.SoundFX[3];
					}
					else if (name.Equals("IcecreamTruckV2VehicleDeliveryVerFar", StringComparison.OrdinalIgnoreCase))
					{
						val.clip = ReturnByDeathBase.SoundFX[4];
					}
					else if (name.Equals("IcecreamTruckV2", StringComparison.OrdinalIgnoreCase))
					{
						val.clip = ReturnByDeathBase.SoundFX[3];
					}
					else if (name.Equals("IcecreamTruckFar", StringComparison.OrdinalIgnoreCase))
					{
						val.clip = ReturnByDeathBase.SoundFX[4];
					}
				}
			}
		}
	}
	internal class LethalThingsPatch
	{
		internal static void Apply(Harmony harmony)
		{
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Expected O, but got Unknown
			if (!ReturnByDeathBase.EnableRbdSFX.Value)
			{
				return;
			}
			Type type = AccessTools.TypeByName("LethalThings.MonoBehaviours.TeleporterTrap");
			if (!(type == null))
			{
				MethodInfo methodInfo = AccessTools.Method(type, "__initializeVariables", (Type[])null, (Type[])null);
				if (methodInfo != null)
				{
					harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(LethalThingsPatch), "OverrideAudio", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				}
			}
		}

		private static void OverrideAudio(object __instance)
		{
			ApplySound(__instance);
		}

		internal static void ApplyToExisting()
		{
			if (!ReturnByDeathBase.EnableRbdSFX.Value)
			{
				return;
			}
			Type type = AccessTools.TypeByName("LethalThings.MonoBehaviours.TeleporterTrap");
			if (!(type == null))
			{
				Object[] array = Resources.FindObjectsOfTypeAll(type);
				foreach (Object instance in array)
				{
					ApplySound(instance);
				}
			}
		}

		private static void ApplySound(object instance)
		{
			if (ReturnByDeathBase.EnableRbdSFX.Value && ReturnByDeathBase.SoundFX != null && ReturnByDeathBase.SoundFX.Count > 0 && (Object)(object)ReturnByDeathBase.SoundFX[0] != (Object)null)
			{
				AccessTools.Field(instance.GetType(), "teleporterBeamUpSFX")?.SetValue(instance, ReturnByDeathBase.SoundFX[0]);
			}
		}
	}
	[HarmonyPatch(typeof(ShipTeleporter))]
	internal class ShipTeleporterPatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void OverrideAudio(ShipTeleporter __instance)
		{
			ApplySound(__instance);
		}

		internal static void ApplyToExisting()
		{
			ShipTeleporter[] array = Resources.FindObjectsOfTypeAll<ShipTeleporter>();
			foreach (ShipTeleporter teleporter in array)
			{
				ApplySound(teleporter);
			}
		}

		private static void ApplySound(ShipTeleporter teleporter)
		{
			if (ReturnByDeathBase.EnableRbdSFX.Value && ReturnByDeathBase.SoundFX != null && ReturnByDeathBase.SoundFX.Count > 0 && (Object)(object)ReturnByDeathBase.SoundFX[0] != (Object)null)
			{
				teleporter.teleporterBeamUpSFX = ReturnByDeathBase.SoundFX[0];
			}
		}
	}
	[HarmonyPatch(typeof(SoundManager))]
	internal class SoundManagerPatch
	{
		private static AudioSource witchAudioSource;

		private static int currentWitchTrack = -1;

		public static bool hasJustDiscoveredBody = false;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void CreateCustomWitchAudioSource(SoundManager __instance)
		{
			witchAudioSource = ((Component)__instance).gameObject.AddComponent<AudioSource>();
			witchAudioSource.playOnAwake = false;
			witchAudioSource.loop = true;
			witchAudioSource.volume = 0f;
		}

		public static void TriggerWitch2()
		{
			if (ReturnByDeathBase.EnableWitchSFX.Value)
			{
				hasJustDiscoveredBody = true;
			}
		}

		[HarmonyPatch("SetFearAudio")]
		[HarmonyPostfix]
		private static void UpdateWitchFearAudio(SoundManager __instance)
		{
			if (!ReturnByDeathBase.EnableWitchSFX.Value || (Object)(object)witchAudioSource == (Object)null)
			{
				return;
			}
			if (GameNetworkManager.Instance.localPlayerController.isPlayerDead)
			{
				witchAudioSource.volume = 0f;
				witchAudioSource.Stop();
				currentWitchTrack = -1;
				hasJustDiscoveredBody = false;
				return;
			}
			float fearLevel = StartOfRound.Instance.fearLevel;
			if (hasJustDiscoveredBody && currentWitchTrack == 2 && !witchAudioSource.isPlaying)
			{
				hasJustDiscoveredBody = false;
				currentWitchTrack = -1;
			}
			int num = -1;
			if (hasJustDiscoveredBody)
			{
				num = 2;
			}
			else if (fearLevel > 0.4f)
			{
				num = 1;
			}
			if (num != -1)
			{
				if (currentWitchTrack != num || !witchAudioSource.isPlaying)
				{
					currentWitchTrack = num;
					if (ReturnByDeathBase.SoundFX != null && ReturnByDeathBase.SoundFX.Count > num)
					{
						witchAudioSource.clip = ReturnByDeathBase.SoundFX[num];
						witchAudioSource.loop = num != 2;
						witchAudioSource.time = 0f;
						witchAudioSource.Play();
					}
				}
				float volume = ((num == 2) ? 1f : Mathf.Clamp(fearLevel - 0.2f, 0.1f, 1f));
				witchAudioSource.volume = volume;
			}
			else if (witchAudioSource.isPlaying)
			{
				witchAudioSource.volume = Mathf.Lerp(witchAudioSource.volume, 0f, 2f * Time.deltaTime);
				if (witchAudioSource.volume < 0.01f)
				{
					witchAudioSource.Stop();
					witchAudioSource.volume = 0f;
					currentWitchTrack = -1;
					hasJustDiscoveredBody = false;
				}
			}
		}
	}
}