Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ChasePenry v1.4.3
ChasePenry.dll
Decompiled a day agousing 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(); } } } }