Decompiled source of ChasePenry v1.4.3

ChasePenry.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 System.Runtime.Versioning;
using BepInEx;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Networking;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("ChasePenry")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("ChasePenry")]
[assembly: AssemblyTitle("ChasePenry")]
[assembly: AssemblyVersion("1.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ChasePenry
{
	[BepInPlugin("com.yourname.chasepenry", "ChasePenry", "1.4.1")]
	public class ChasePenryPlugin : BaseUnityPlugin
	{
		public const string GUID = "com.yourname.chasepenry";

		public const string NAME = "ChasePenry";

		public const string VERSION = "1.4.1";

		private readonly Harmony harmony = new Harmony("com.yourname.chasepenry");

		public static List<AudioClip> MonsterDangerClips = new List<AudioClip>();

		public static List<AudioClip> DeadBodyClips = new List<AudioClip>();

		public static bool IsMonsterAlarmPlaying = false;

		public static bool IsBodyAlarmPlaying = false;

		public static ChasePenryPlugin Instance { get; private set; }

		private void Awake()
		{
			Instance = this;
			((BaseUnityPlugin)this).Logger.LogInfo((object)"ChasePenry v1.4.1 has loaded successfully!");
			harmony.PatchAll();
			((MonoBehaviour)this).StartCoroutine(LoadAllAudioFiles());
		}

		private IEnumerator LoadAllAudioFiles()
		{
			string pluginFolder = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location);
			if (string.IsNullOrEmpty(pluginFolder))
			{
				yield break;
			}
			string text = Path.Combine(pluginFolder, "danger_audio");
			if (Directory.Exists(text))
			{
				string[] files = Directory.GetFiles(text, "*.wav");
				string[] array = files;
				foreach (string filePath in array)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(LoadAudioClipFromFile(filePath, MonsterDangerClips));
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Danger folder not found at: " + text + ". Creating it for you."));
				Directory.CreateDirectory(text);
			}
			string text2 = Path.Combine(pluginFolder, "body_audio");
			if (Directory.Exists(text2))
			{
				string[] files2 = Directory.GetFiles(text2, "*.wav");
				string[] array = files2;
				foreach (string filePath2 in array)
				{
					yield return ((MonoBehaviour)this).StartCoroutine(LoadAudioClipFromFile(filePath2, DeadBodyClips));
				}
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)("Body folder not found at: " + text2 + ". Creating it for you."));
				Directory.CreateDirectory(text2);
			}
			((BaseUnityPlugin)this).Logger.LogInfo((object)$"[ChasePenry] Audio Loading Complete. Loaded {MonsterDangerClips.Count} danger sounds and {DeadBodyClips.Count} body sounds!");
		}

		private IEnumerator LoadAudioClipFromFile(string filePath, List<AudioClip> targetList)
		{
			UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip("file://" + filePath, (AudioType)20);
			try
			{
				yield return www.SendWebRequest();
				if ((int)www.result == 1)
				{
					AudioClip content = DownloadHandlerAudioClip.GetContent(www);
					if ((Object)(object)content != (Object)null)
					{
						((Object)content).name = Path.GetFileNameWithoutExtension(filePath);
						targetList.Add(content);
						((BaseUnityPlugin)this).Logger.LogInfo((object)("[ChasePenry] Successfully loaded clip: " + ((Object)content).name));
					}
				}
				else
				{
					((BaseUnityPlugin)this).Logger.LogError((object)("[ChasePenry] Failed to load audio file " + filePath + ": " + www.error));
				}
			}
			finally
			{
				((IDisposable)www)?.Dispose();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class ChasePenryPatch
	{
		private const float CheckDistance = 12f;

		private static AudioSource? activeMonsterSource = null;

		private static AudioSource? activeBodySource = null;

		private static float monsterLostSightTimer = 0f;

		private const float MonsterGraceDuration = 3f;

		private const float MonsterFadeOutDuration = 1.5f;

		private static float bodyPlayTimer = 0f;

		private const float BodyMaxPlayDuration = 5f;

		private const float BodyFadeOutDuration = 1.5f;

		private static HashSet<int> alertedBodyIDs = new HashSet<int>();

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void Postfix(PlayerControllerB __instance)
		{
			if ((Object)(object)__instance == (Object)null || !__instance.isPlayerControlled || __instance.isPlayerDead)
			{
				return;
			}
			AudioSource val = __instance.movementAudio;
			if ((Object)(object)val == (Object)null)
			{
				val = ((Component)__instance).gameObject.GetComponent<AudioSource>();
				if ((Object)(object)val == (Object)null)
				{
					val = ((Component)__instance).gameObject.AddComponent<AudioSource>();
				}
			}
			float deltaTime = Time.deltaTime;
			if (CheckMonsterLineOfSight(__instance))
			{
				monsterLostSightTimer = 0f;
				if (!ChasePenryPlugin.IsMonsterAlarmPlaying && ChasePenryPlugin.MonsterDangerClips.Count > 0)
				{
					ChasePenryPlugin.IsMonsterAlarmPlaying = true;
					AudioClip clip = ChasePenryPlugin.MonsterDangerClips[Random.Range(0, ChasePenryPlugin.MonsterDangerClips.Count)];
					val.clip = clip;
					val.loop = true;
					val.volume = 1f;
					val.Play();
					activeMonsterSource = val;
				}
				else if ((Object)(object)activeMonsterSource != (Object)null && activeMonsterSource.isPlaying)
				{
					activeMonsterSource.volume = 1f;
				}
			}
			else if (ChasePenryPlugin.IsMonsterAlarmPlaying)
			{
				monsterLostSightTimer += deltaTime;
				if (monsterLostSightTimer <= 3f)
				{
					if ((Object)(object)activeMonsterSource != (Object)null)
					{
						activeMonsterSource.volume = 1f;
					}
				}
				else
				{
					float num = (monsterLostSightTimer - 3f) / 1.5f;
					if ((Object)(object)activeMonsterSource != (Object)null && activeMonsterSource.isPlaying)
					{
						activeMonsterSource.volume = Mathf.Lerp(1f, 0f, num);
					}
					if (num >= 1f)
					{
						if ((Object)(object)activeMonsterSource != (Object)null)
						{
							activeMonsterSource.Stop();
						}
						ChasePenryPlugin.IsMonsterAlarmPlaying = false;
						activeMonsterSource = null;
						monsterLostSightTimer = 0f;
					}
				}
			}
			DeadBodyInfo visibleDeadBody = GetVisibleDeadBody(__instance);
			bool flag = (Object)(object)visibleDeadBody != (Object)null;
			if (flag && (Object)(object)visibleDeadBody != (Object)null && !ChasePenryPlugin.IsBodyAlarmPlaying && ChasePenryPlugin.DeadBodyClips.Count > 0)
			{
				int instanceID = ((Object)visibleDeadBody).GetInstanceID();
				if (!alertedBodyIDs.Contains(instanceID))
				{
					alertedBodyIDs.Add(instanceID);
					ChasePenryPlugin.IsBodyAlarmPlaying = true;
					bodyPlayTimer = 0f;
					AudioClip clip2 = ChasePenryPlugin.DeadBodyClips[Random.Range(0, ChasePenryPlugin.DeadBodyClips.Count)];
					val.clip = clip2;
					val.loop = false;
					val.volume = 1f;
					val.Play();
					activeBodySource = val;
				}
			}
			if (ChasePenryPlugin.IsBodyAlarmPlaying)
			{
				bodyPlayTimer += deltaTime;
				if (bodyPlayTimer >= 5f || !flag)
				{
					if (!flag && bodyPlayTimer < 5f)
					{
						if ((Object)(object)activeBodySource != (Object)null && activeBodySource.isPlaying)
						{
							activeBodySource.volume = Mathf.MoveTowards(activeBodySource.volume, 0f, deltaTime * 2f);
						}
					}
					else
					{
						float num2 = (bodyPlayTimer - 5f) / 1.5f;
						if ((Object)(object)activeBodySource != (Object)null && activeBodySource.isPlaying)
						{
							activeBodySource.volume = Mathf.Lerp(1f, 0f, num2);
						}
					}
					if (bodyPlayTimer >= 6.5f || (!flag && (Object)(object)activeBodySource != (Object)null && activeBodySource.volume <= 0.05f))
					{
						if ((Object)(object)activeBodySource != (Object)null)
						{
							activeBodySource.Stop();
						}
						ChasePenryPlugin.IsBodyAlarmPlaying = false;
						activeBodySource = null;
						bodyPlayTimer = 0f;
					}
				}
			}
			if (!flag && !ChasePenryPlugin.IsBodyAlarmPlaying)
			{
				CleanupDistantBodies();
			}
		}

		private static bool CheckMonsterLineOfSight(PlayerControllerB localPlayer)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			EnemyAI[] array = Object.FindObjectsOfType<EnemyAI>();
			if (array == null)
			{
				return false;
			}
			EnemyAI[] array2 = array;
			RaycastHit val3 = default(RaycastHit);
			foreach (EnemyAI val in array2)
			{
				if (!((Object)(object)val == (Object)null) && !val.isEnemyDead && Vector3.Distance(((Component)localPlayer).transform.position, ((Component)val).transform.position) <= 12f)
				{
					Vector3 position = ((Component)localPlayer.gameplayCamera).transform.position;
					Vector3 val2 = ((Component)val).transform.position + Vector3.up * 1f;
					if (!Physics.Linecast(position, val2, ref val3, StartOfRound.Instance.collidersAndRoomMask) || (Object)(object)((RaycastHit)(ref val3)).transform.root == (Object)(object)((Component)val).transform.root)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static DeadBodyInfo? GetVisibleDeadBody(PlayerControllerB localPlayer)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			DeadBodyInfo[] array = Object.FindObjectsOfType<DeadBodyInfo>();
			if (array == null)
			{
				return null;
			}
			DeadBodyInfo[] array2 = array;
			RaycastHit val3 = default(RaycastHit);
			foreach (DeadBodyInfo val in array2)
			{
				if (!((Object)(object)val == (Object)null) && Vector3.Distance(((Component)localPlayer).transform.position, ((Component)val).transform.position) <= 12f)
				{
					Vector3 position = ((Component)localPlayer.gameplayCamera).transform.position;
					Vector3 val2 = ((Component)val).transform.position + Vector3.up * 0.5f;
					if (!Physics.Linecast(position, val2, ref val3, StartOfRound.Instance.collidersAndRoomMask) || (Object)(object)((RaycastHit)(ref val3)).transform.root == (Object)(object)((Component)val).transform.root)
					{
						return val;
					}
				}
			}
			return null;
		}

		private static void CleanupDistantBodies()
		{
			DeadBodyInfo[] array = Object.FindObjectsOfType<DeadBodyInfo>();
			if (array == null || array.Length == 0)
			{
				alertedBodyIDs.Clear();
			}
		}
	}
}