using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Dread.Config; using Dread.Systems; using HarmonyLib; using Microsoft.CodeAnalysis; using NVorbis; using UnityEngine; using UnityEngine.AI; using UnityEngine.Networking; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("Dread")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+49218814e949aff1f8c5034f59e79d37d90a0126")] [assembly: AssemblyProduct("Dread")] [assembly: AssemblyTitle("Dread")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [CompilerGenerated] internal sealed class <>z__ReadOnlyArray : IEnumerable, ICollection, IList, IEnumerable, IReadOnlyCollection, IReadOnlyList, ICollection, IList { int ICollection.Count => _items.Length; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; object IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; int IReadOnlyCollection.Count => _items.Length; T IReadOnlyList.this[int index] => _items[index]; int ICollection.Count => _items.Length; bool ICollection.IsReadOnly => true; T IList.this[int index] { get { return _items[index]; } set { throw new NotSupportedException(); } } public <>z__ReadOnlyArray(T[] items) { _items = items; } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.CopyTo(Array array, int index) { ((ICollection)_items).CopyTo(array, index); } int IList.Add(object value) { throw new NotSupportedException(); } void IList.Clear() { throw new NotSupportedException(); } bool IList.Contains(object value) { return ((IList)_items).Contains(value); } int IList.IndexOf(object value) { return ((IList)_items).IndexOf(value); } void IList.Insert(int index, object value) { throw new NotSupportedException(); } void IList.Remove(object value) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)_items).GetEnumerator(); } void ICollection.Add(T item) { throw new NotSupportedException(); } void ICollection.Clear() { throw new NotSupportedException(); } bool ICollection.Contains(T item) { return ((ICollection)_items).Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { ((ICollection)_items).CopyTo(array, arrayIndex); } bool ICollection.Remove(T item) { throw new NotSupportedException(); } int IList.IndexOf(T item) { return ((IList)_items).IndexOf(item); } void IList.Insert(int index, T item) { throw new NotSupportedException(); } void IList.RemoveAt(int index) { throw new NotSupportedException(); } } namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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] [Microsoft.CodeAnalysis.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 Dread { [BepInPlugin("elytraking.dread", "Dread", "1.6.1")] public class Plugin : BaseUnityPlugin { public const string GUID = "elytraking.dread"; public const string NAME = "Dread"; public const string VERSION = "1.6.1"; internal static ManualLogSource Logger; private readonly Harmony _harmony = new Harmony("elytraking.dread"); private EventHandler? _logLevelHandler; internal static Harmony HarmonyInstance { get; private set; } private static bool MonsterPatchesEnabled { get { if (DreadConfig.MonsterAggressionEnabled.Value) { return !DreadConfig.CompatibilityMode.Value; } return false; } } private void Awake() { PluginDependencyResolver.Register(); Logger = ((BaseUnityPlugin)this).Logger; HarmonyInstance = _harmony; DreadConfig.Initialize(((BaseUnityPlugin)this).Config); LoggingService.Initialize(DreadConfig.LogLevelEntry.Value); _logLevelHandler = delegate { LoggingService.SetLevel(DreadConfig.LogLevelEntry.Value); }; DreadConfig.LogLevelEntry.SettingChanged += _logLevelHandler; ApplyMonsterPatches(); if (DreadConfig.CrouchSpeedBoostEnabled.Value) { PlayerControllerAwakePatch.Apply(_harmony); } if (DreadConfig.DebugConsoleGuardEnabled.Value) { DebugConsoleGuardPatch.Apply(_harmony); } DreadConfig.MonsterAggressionEnabled.SettingChanged += delegate { ApplyMonsterPatches(); }; DreadConfig.CompatibilityMode.SettingChanged += delegate { ApplyMonsterPatches(); }; DreadConfig.CrouchSpeedBoostEnabled.SettingChanged += delegate { if (DreadConfig.CrouchSpeedBoostEnabled.Value) { PlayerControllerAwakePatch.Apply(_harmony); } else { PlayerControllerAwakePatch.Remove(_harmony); } }; DreadConfig.DebugConsoleGuardEnabled.SettingChanged += delegate { if (DreadConfig.DebugConsoleGuardEnabled.Value) { DebugConsoleGuardPatch.Apply(_harmony); } else { DebugConsoleGuardPatch.Remove(_harmony); } }; LoggingService.PrintAsciiArt(); LoggingService.LogInfo("Dread v1.6.1 loaded."); SceneManager.sceneLoaded += OnSceneLoaded; } private void ApplyMonsterPatches() { if (MonsterPatchesEnabled) { EnemyNavMeshAgentAwakePatch.Apply(_harmony); EnemyDirectorSetInvestigatePatch.Apply(_harmony); } else { EnemyNavMeshAgentAwakePatch.Remove(_harmony); EnemyDirectorSetInvestigatePatch.Remove(_harmony); } } private void Start() { RepoConfigCompat.TryApply(_harmony); } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (DreadSystemInitializer.TryInitialize()) { SceneManager.sceneLoaded -= OnSceneLoaded; } } private void OnDestroy() { if (_logLevelHandler != null) { DreadConfig.LogLevelEntry.SettingChanged -= _logLevelHandler; } } } } namespace Dread.Systems { public static class AudioClipLoader { [CompilerGenerated] private sealed class <>c__DisplayClass6_0 { public AudioClip clip; internal void b__0(AudioClip? c) { clip = c; } } [CompilerGenerated] private sealed class d__5 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string fileName; public Action onLoaded; private UnityWebRequest 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_013c: Unknown result type (might be due to invalid IL or missing references) bool result; try { switch (<>1__state) { default: result = false; break; case 0: { <>1__state = -1; if (Cache.TryGetValue(fileName, out AudioClip value)) { onLoaded(value); result = false; break; } string fullPath = Path.GetFullPath(Path.Combine(AudioDirectory, fileName)); if (!File.Exists(fullPath)) { LoggingService.LogWarning("[AudioClipLoader] Missing audio file: " + fileName); onLoaded(null); result = false; break; } if (TryLoadWithNvorbis(fullPath, fileName, out AudioClip clip)) { Cache[fileName] = clip; onLoaded(clip); result = false; break; } if (!UnityWebRequestCompat.IsUsable) { LoggingService.LogWarning("[AudioClipLoader] NVorbis failed and UnityWebRequest is unavailable for " + fileName); onLoaded(null); result = false; break; } string text2 = ToFileUri(fullPath); 5__2 = UnityWebRequestMultimedia.GetAudioClip(text2, (AudioType)0); <>1__state = -3; <>2__current = 5__2.SendWebRequest(); <>1__state = 1; result = true; break; } case 1: <>1__state = -3; if ((int)5__2.result == 0) { AudioClip content = DownloadHandlerAudioClip.GetContent(5__2); content.name = fileName; Cache[fileName] = content; onLoaded(content); } else { string requestHandlerError = GetRequestHandlerError(5__2); string text = ((!string.IsNullOrEmpty(5__2.error)) ? 5__2.error : ((!string.IsNullOrEmpty(requestHandlerError)) ? requestHandlerError : "no error details")); LoggingService.LogWarning("[AudioClipLoader] Failed to load " + fileName + ": " + text); onLoaded(null); } result = false; <>m__Finally1(); break; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (5__2 != null) { ((IDisposable)5__2).Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__6 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public IEnumerable fileNames; public Action onLoaded; private <>c__DisplayClass6_0 <>8__1; private IEnumerator <>7__wrap1; private string 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__6(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>8__1 = null; <>7__wrap1 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = fileNames.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; onLoaded(5__3, <>8__1.clip); <>8__1 = null; 5__3 = null; break; } if (<>7__wrap1.MoveNext()) { 5__3 = <>7__wrap1.Current; <>8__1 = new <>c__DisplayClass6_0(); <>8__1.clip = null; <>2__current = LoadClip(5__3, delegate(AudioClip? c) { <>8__1.clip = c; }); <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly Dictionary Cache; public static string AudioDirectory { get; } static AudioClipLoader() { Cache = new Dictionary(); AudioDirectory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "audio"); } [IteratorStateMachine(typeof(d__5))] public static IEnumerator LoadClip(string fileName, Action onLoaded) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(0) { fileName = fileName, onLoaded = onLoaded }; } [IteratorStateMachine(typeof(d__6))] public static IEnumerator LoadClips(IEnumerable fileNames, Action onLoaded) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__6(0) { fileNames = fileNames, onLoaded = onLoaded }; } public static void ClearCache() { Cache.Clear(); } public static string ToFileUri(string path) { path = Path.GetFullPath(path); if (path.Length > 0 && path[0] == '/') { path = "Z:" + path.Replace('/', Path.DirectorySeparatorChar); } return "file:///" + path.Replace('\\', '/'); } internal static bool TryLoadWithNvorbis(string path, string clipName, out AudioClip clip) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Expected O, but got Unknown //IL_011b: Expected O, but got Unknown clip = null; try { VorbisReader val = new VorbisReader(path); try { int channels = val.Channels; int sampleRate = val.SampleRate; if (channels <= 0 || sampleRate <= 0) { return false; } float[] array = new float[Math.Max(channels * 2048, sampleRate / 10 * channels)]; List list = new List(Math.Max(channels * 4096, (int)Math.Min(val.TotalSamples, 2000000L))); int num; while ((num = val.ReadSamples(array, 0, array.Length)) > 0) { for (int i = 0; i < num; i++) { list.Add(array[i]); } } int count = list.Count; if (count < channels) { return false; } int num2 = count / channels; float[] pcm = list.ToArray(); int pcmReadPos = 0; clip = AudioClip.Create(Path.GetFileNameWithoutExtension(clipName), num2, channels, sampleRate, false, (PCMReaderCallback)delegate(float[] data) { int num4 = pcm.Length - pcmReadPos; if (num4 <= 0) { for (int j = 0; j < data.Length; j++) { data[j] = 0f; } } else { int num5 = Math.Min(data.Length, num4); Array.Copy(pcm, pcmReadPos, data, 0, num5); pcmReadPos += num5; for (int k = num5; k < data.Length; k++) { data[k] = 0f; } } }, (PCMSetPositionCallback)delegate(int position) { int num3 = position * channels; if (num3 < 0) { num3 = 0; } else if (num3 > pcm.Length) { num3 = pcm.Length; } pcmReadPos = num3; }); clip.name = clipName; return true; } finally { ((IDisposable)val)?.Dispose(); } } catch (Exception ex) { LoggingService.LogVerbose("[AudioClipLoader] NVorbis failed for " + clipName + ": " + ex.Message); return false; } } internal static string? GetDownloadHandlerError(object? handler) { if (handler == null) { return null; } return handler.GetType().GetProperty("error")?.GetValue(handler) as string; } internal static string? GetRequestHandlerError(UnityWebRequest req) { try { return GetDownloadHandlerError(typeof(UnityWebRequest).GetProperty("downloadHandler")?.GetValue(req)); } catch { return null; } } } public class AudioDreadSystem : MonoBehaviour { [CompilerGenerated] private sealed class d__9 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AudioDreadSystem <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; AudioDreadSystem CS$<>8__locals0 = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; goto IL_0042; case 1: <>1__state = -1; goto IL_0042; case 2: { <>1__state = -1; LoggingService.LogInfo($"[AudioDread] Loaded {CS$<>8__locals0._clips.Count}/{ClipNames.Length} clips."); DreadRuntimeState.AudioClipCount = CS$<>8__locals0._clips.Count; ((MonoBehaviour)CS$<>8__locals0).StartCoroutine(CS$<>8__locals0.PlayLoop()); return false; } IL_0042: if (!CS$<>8__locals0._sceneLoaded || SemiFunc.MenuLevel()) { <>2__current = null; <>1__state = 1; return true; } <>2__current = AudioClipLoader.LoadClips(ClipNames, delegate(string name, AudioClip? clip) { if (clip != null) { CS$<>8__locals0._clips.Add(clip); } }); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__10 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AudioDreadSystem <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown int num = <>1__state; AudioDreadSystem audioDreadSystem = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(30f); <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; LoggingService.LogVerbose("[AudioDread] Checking audio play..."); if (DreadConfig.AudioEnabled.Value && !SemiFunc.MenuLevel() && audioDreadSystem._clips.Count != 0) { if (audioDreadSystem._mainCam == null) { audioDreadSystem._mainCam = Camera.main; } if (audioDreadSystem._mainCam != null) { audioDreadSystem.PlayRandomSound(); DreadRuntimeState.AudioClipCount = audioDreadSystem._clips.Count; } } break; } float num2 = Random.Range(60f, 180f) / DreadConfig.AudioFrequency.Value; audioDreadSystem._nextPlayAt = Time.time + num2; DreadRuntimeState.AudioNextPlayIn = num2; <>2__current = (object)new WaitForSeconds(num2); <>1__state = 2; return true; } 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 readonly List _clips = new List(); private Camera? _mainCam; private bool _sceneLoaded; private float _nextPlayAt = -1f; private static readonly string[] ClipNames = new string[4] { "scraping.ogg", "footsteps.ogg", "breathing.ogg", "whisper.ogg" }; private static readonly Dictionary ClipWeights = new Dictionary { { "scraping.ogg", 0.6f }, { "footsteps.ogg", 0.6f }, { "breathing.ogg", 0.3f }, { "whisper.ogg", 0.1f } }; private void Start() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) LoggingService.LogVerbose("[AudioDread] Awake starting..."); SceneManager.sceneLoaded += OnSceneLoaded; OnSceneLoaded(SceneManager.GetActiveScene(), (LoadSceneMode)0); ((MonoBehaviour)this).StartCoroutine(LoadClips()); } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _sceneLoaded = true; _mainCam = Camera.main; } [IteratorStateMachine(typeof(d__9))] private IEnumerator LoadClips() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__10))] private IEnumerator PlayLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(0) { <>4__this = this }; } private void Update() { if (_nextPlayAt > 0f) { float num = _nextPlayAt - Time.time; DreadRuntimeState.AudioNextPlayIn = ((num < 0f) ? 0f : num); } } private AudioClip PickWeightedClip() { if (_clips.Count == 0) { return null; } float num = 0f; foreach (AudioClip clip in _clips) { num += (ClipWeights.TryGetValue(clip.name, out var value) ? value : 1f); } float num2 = Random.Range(0f, num); foreach (AudioClip clip2 in _clips) { num2 -= (ClipWeights.TryGetValue(clip2.name, out var value2) ? value2 : 1f); if (num2 <= 0f) { return clip2; } } return _clips[_clips.Count - 1]; } private void PlayRandomSound() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) //IL_007c: 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) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown if (_mainCam == null) { _mainCam = Camera.main; } if (_mainCam != null) { AudioClip val = PickWeightedClip(); if (val != null) { Camera? mainCam = _mainCam; Vector3 val2 = new Vector3(Random.Range(-1f, 1f), Random.Range(-0.3f, 0.3f), Random.Range(-1f, 1f)); Vector3 val3 = ((Vector3)(ref val2)).normalized * Random.Range(5f, 15f); Vector3 position = mainCam.transform.position + val3; GameObject val4 = new GameObject("DreadSound"); val4.transform.position = position; AudioSource obj = val4.AddComponent(); obj.clip = val; float pitch = (obj.pitch = Random.Range(0.5f, 1.5f)); obj.spatialBlend = 1f; obj.volume = DreadConfig.AudioVolume.Value; obj.rolloffMode = (AudioRolloffMode)0; obj.minDistance = 1f; obj.maxDistance = 25f; obj.Play(); Object.Destroy((Object)val4, AudioPlayUtil.PlayLifetimeSeconds(val, pitch)); } } } } internal static class AudioPlayUtil { internal static float PlayLifetimeSeconds(AudioClip clip, float pitch, float paddingSeconds = 0.5f) { return clip.length / Math.Max(pitch, 0.01f) + paddingSeconds; } } public class DebugOverlaySystem : MonoBehaviour { private struct RowData { public string Left; public string Right; public Color Color; public byte Kind; } private readonly List _rows = new List(16); private static readonly GUIContent EmptyContent = new GUIContent(); private const byte RowNormal = 0; private const byte RowHeader = 1; private const byte RowSep = 2; private static readonly Color ColAccent = new Color(0.96f, 0.55f, 0.38f); private static readonly Color ColDim = new Color(0.62f, 0.64f, 0.7f); private static readonly Color ColValue = new Color(0.92f, 0.93f, 0.96f); private static readonly Color ColGood = new Color(0.48f, 0.9f, 0.55f); private static readonly Color ColWarn = new Color(0.97f, 0.84f, 0.42f); private static readonly Color ColBad = new Color(0.96f, 0.46f, 0.46f); private Texture2D? _bgTex; private Texture2D? _sepTex; private GUIStyle? _boxStyle; private GUIStyle? _headerStyle; private GUIStyle? _hintStyle; private GUIStyle? _labelStyle; private GUIStyle? _valueStyle; private GUIStyle? _sepStyle; private bool _visible; private bool _loggedDisabledWhileRunning; private float _smoothedDelta; private float _minFps; private float _minFpsResetAt; private float _memMB; private float _nextStatRefresh; private void OnGUI() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) if (!GuardOverlayEnabled() || !IsOverlayVisible()) { return; } EnsureStyles(); BuildRows(); float num = 16f + (float)_rows.Count * 18f; Rect val = default(Rect); ((Rect)(ref val))..ctor(12f, 140f, 320f, num); GUI.Box(val, EmptyContent, _boxStyle); float num2 = ((Rect)(ref val)).x + 10f; float num3 = ((Rect)(ref val)).y + 6f; float num4 = 300f; for (int i = 0; i < _rows.Count; i++) { RowData rowData = _rows[i]; if (rowData.Kind == 2) { GUI.Box(new Rect(num2, num3 + 9f - 1f, num4, 1f), EmptyContent, _sepStyle); } else if (rowData.Kind == 1) { GUI.Label(new Rect(num2, num3, num4, 18f), rowData.Left, _headerStyle); GUI.Label(new Rect(num2 + num4 - 36f, num3 + 2f, 36f, 18f), rowData.Right, _hintStyle); } else { GUI.Label(new Rect(num2, num3, 82f, 18f), rowData.Left, _labelStyle); GUIStyle valueStyle = _valueStyle; valueStyle.normal.textColor = rowData.Color; GUI.Label(new Rect(num2 + 82f, num3, num4 - 82f, 18f), rowData.Right, valueStyle); } num3 += 18f; } } private void BuildRows() { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Unknown result type (might be due to invalid IL or missing references) _rows.Clear(); AddHeader("DREAD 1.6.1", "F10"); AddSep(); float num = ((_smoothedDelta > 0f) ? (1f / _smoothedDelta) : 0f); float num2 = _smoothedDelta * 1000f; Color color = ((num >= 60f) ? ColGood : ((num >= 30f) ? ColWarn : ColBad)); AddRow("FPS", $"{num:F0}", color); AddRow("Frame", $"{num2:F1} ms min {_minFps:F0} fps", ColValue); AddRow("Memory", $"{_memMB:F0} MB", ColValue); AddRow("GC", $"g0 {GC.CollectionCount(0)} g1 {GC.CollectionCount(1)} g2 {GC.CollectionCount(2)}", ColDim); AddRow("Screen", $"{Screen.width}x{Screen.height}", ColDim); AddRow("Frames", Time.frameCount.ToString(), ColDim); AddSep(); float nearestEnemyDist = DreadRuntimeState.NearestEnemyDist; string right = ((nearestEnemyDist >= 1.7014117E+38f) ? "none" : $"{nearestEnemyDist:F1} m (range 15m)"); AddRow("Enemy", right, ColValue); AddRow("Tension", "adrenaline " + OnOff(DreadRuntimeState.AdrenalineActive), ColValue); AddRow("Sprint", $"panic {OnOff(DreadRuntimeState.PanicSprintActive)} cd {DreadRuntimeState.PanicSprintCooldown:F0}s", ColValue); AddRow("Break", BreakSummary(), BreakColor()); AddRow("Break+", "clips " + OnOff(DreadRuntimeState.PsychoticBreakClipsLoaded) + " " + $"enemies {DreadRuntimeState.PsychoticBreakEnemyCount} " + $"threat {DreadRuntimeState.PsychoticBreakThreatCount}s " + $"next {DreadRuntimeState.PsychoticBreakNextCheckIn:F0}s", ColDim); AddRow("Audio", AudioSummary(), ColValue); AddSep(); AddRow("Config", "compat" + PlusMinus(DreadConfig.CompatibilityMode.Value) + " aggr" + PlusMinus(DreadConfig.MonsterAggressionEnabled.Value) + " maud" + PlusMinus(DreadConfig.MonsterAudioEnabled.Value) + " aud" + PlusMinus(DreadConfig.AudioEnabled.Value) + " srv" + PlusMinus(DreadConfig.DebugServerEnabled.Value), ColDim); AddRow("Patches", DreadRuntimeState.DreadPatchCount.ToString(), ColValue); } private void AddRow(string left, string right, Color color) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) _rows.Add(new RowData { Left = left, Right = right, Color = color, Kind = 0 }); } private void AddHeader(string left, string right) { _rows.Add(new RowData { Left = left, Right = right, Kind = 1 }); } private void AddSep() { _rows.Add(new RowData { Left = string.Empty, Right = string.Empty, Kind = 2 }); } private static string BreakSummary() { if (!DreadRuntimeState.PsychoticBreakEnabled) { return "off"; } if (DreadRuntimeState.PsychoticBreakEpisodeActive) { float num = DreadRuntimeState.PsychoticBreakEpisodeDuration - DreadRuntimeState.PsychoticBreakEpisodeTimer; return $"ACTIVE {num:F1}s"; } if (!DreadRuntimeState.PsychoticBreakCanTrigger && !string.IsNullOrEmpty(DreadRuntimeState.PsychoticBreakBlockReason)) { return "blocked: " + DreadRuntimeState.PsychoticBreakBlockReason; } return $"ready next {DreadRuntimeState.PsychoticBreakNextCheckIn:F0}s " + $"threat {DreadRuntimeState.PsychoticBreakThreatCount}s"; } private static Color BreakColor() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (!DreadRuntimeState.PsychoticBreakEnabled) { return ColDim; } if (DreadRuntimeState.PsychoticBreakEpisodeActive) { return ColBad; } if (!DreadRuntimeState.PsychoticBreakCanTrigger) { return ColWarn; } return ColGood; } private static string AudioSummary() { string arg = ((DreadRuntimeState.AudioNextPlayIn >= 0f) ? $"next {DreadRuntimeState.AudioNextPlayIn:F0}s" : "next n/a"); return $"{DreadRuntimeState.AudioClipCount}/4 {arg}"; } private static string OnOff(bool value) { if (!value) { return "off"; } return "ON"; } private static string PlusMinus(bool value) { if (!value) { return "-"; } return "+"; } private static int CountDreadPatches() { if (Plugin.HarmonyInstance == null) { return 0; } int num = 0; try { foreach (MethodBase allPatchedMethod in Harmony.GetAllPatchedMethods()) { Patches patchInfo = Harmony.GetPatchInfo(allPatchedMethod); if (patchInfo != null) { ReadOnlyCollection prefixes = patchInfo.Prefixes; if (prefixes != null && prefixes.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } ReadOnlyCollection postfixes = patchInfo.Postfixes; if (postfixes != null && postfixes.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } ReadOnlyCollection transpilers = patchInfo.Transpilers; if (transpilers != null && transpilers.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } ReadOnlyCollection finalizers = patchInfo.Finalizers; if (finalizers != null && finalizers.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } } } return num; } catch { return -1; } } private void EnsureStyles() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0042: 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_0066: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Expected O, but got Unknown //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown if (_boxStyle == null) { _bgTex = MakeTexture(new Color(0.05f, 0.05f, 0.07f, 0.88f)); _sepTex = MakeTexture(new Color(0.45f, 0.47f, 0.52f, 0.5f)); _boxStyle = new GUIStyle(GUI.skin.box); _boxStyle.normal.background = _bgTex; _headerStyle = new GUIStyle(GUI.skin.label) { fontSize = 15, wordWrap = false }; _headerStyle.normal.textColor = ColAccent; _hintStyle = new GUIStyle(GUI.skin.label) { fontSize = 11, wordWrap = false }; _hintStyle.normal.textColor = ColDim; _labelStyle = new GUIStyle(GUI.skin.label) { fontSize = 13, wordWrap = false }; _labelStyle.normal.textColor = ColDim; _valueStyle = new GUIStyle(GUI.skin.label) { fontSize = 13, wordWrap = false }; _valueStyle.normal.textColor = ColValue; _sepStyle = new GUIStyle(GUI.skin.box); _sepStyle.normal.background = _sepTex; } } private static Texture2D MakeTexture(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, color); val.Apply(); return val; } private void Awake() { _visible = DreadConfig.DebugOverlayEnabled.Value; DreadConfig.DebugOverlayEnabled.SettingChanged += OnOverlayConfigChanged; ((Behaviour)this).enabled = DreadConfig.DebugOverlayEnabled.Value; } private void OnDestroy() { DreadConfig.DebugOverlayEnabled.SettingChanged -= OnOverlayConfigChanged; } private void OnOverlayConfigChanged(object? sender, EventArgs e) { _visible = DreadConfig.DebugOverlayEnabled.Value; ((Behaviour)this).enabled = DreadConfig.DebugOverlayEnabled.Value; } private void Update() { if (GuardOverlayEnabled()) { SampleFrameStats(); if (Input.GetKeyDown((KeyCode)291)) { _visible = !_visible; } if (IsOverlayVisible() && Time.realtimeSinceStartup >= _nextStatRefresh) { _nextStatRefresh = Time.realtimeSinceStartup + 0.5f; DreadRuntimeState.DreadPatchCount = CountDreadPatches(); _memMB = (float)GC.GetTotalMemory(forceFullCollection: false) / 1048576f; } } } private void SampleFrameStats() { float unscaledDeltaTime = Time.unscaledDeltaTime; if (!(unscaledDeltaTime <= 0f)) { _smoothedDelta = ((_smoothedDelta <= 0f) ? unscaledDeltaTime : (_smoothedDelta + (unscaledDeltaTime - _smoothedDelta) * 0.1f)); float num = 1f / unscaledDeltaTime; float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup >= _minFpsResetAt) { _minFps = num; _minFpsResetAt = realtimeSinceStartup + 2f; } else if (num < _minFps) { _minFps = num; } } } private bool IsOverlayVisible() { if (_visible) { return !SemiFunc.MenuLevel(); } return false; } private bool GuardOverlayEnabled() { if (DreadConfig.DebugOverlayEnabled.Value) { return true; } if (!_loggedDisabledWhileRunning) { _loggedDisabledWhileRunning = true; LoggingService.LogError("DebugOverlaySystem ran while DebugOverlayEnabled is false: enable/disable wiring regressed (PERF-2)."); } return false; } } public class DebugServerSystem : MonoBehaviour { private class DebugCommand { public string RequestJson; public string? Response; public ManualResetEventSlim Done = new ManualResetEventSlim(initialState: false); } private class LogEntry { public string Level; public string Message; public string Timestamp; } private class DebugLogListener : ILogListener, IDisposable { private readonly DebugServerSystem _owner; public LogLevel LogLevelFilter => (LogLevel)63; public DebugLogListener(DebugServerSystem owner) { _owner = owner; } public void LogEvent(object sender, LogEventArgs e) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) _owner.AddLogEntry($"[{e.Level}]", e.Data?.ToString() ?? ""); } public void Dispose() { } } [Serializable] private class RequestEnvelope { public int id; public string? cmd; } [Serializable] private class PingResponse { public bool pong = true; public string? version; public int port; } [Serializable] private class StateResponse { public string version = ""; public string scene = ""; public int enemyCount; public float nearestEnemyDist = -1f; public float playerHp = -1f; public float playerStamina = -1f; public int debugServerPort; public bool isEnabled; } [Serializable] private class ConfigResponse { public bool audioEnabled; public float audioFrequency; public float audioVolume; public bool monsterAggression; public bool monsterAudio; public bool crouchSpeedBoost; public bool fakeFootsteps; public bool adrenaline; public bool lowStaminaSound; public bool panicSprint; public bool errorReporting; public bool compatibilityMode; public bool compatibilitySkipConflictingPatches; public bool debugConsoleGuard; public bool psychoticBreak; public float psychoticBreakTriggerChance; public float psychoticBreakDuration; public bool psychoticBreakOncePerMatch; public bool debugServerEnabled; public int debugServerPort; public bool debugOverlayEnabled; public string logLevel = ""; public ConfigSectionEntry[] sections; } [Serializable] private class ConfigSectionEntry { public string section = ""; public ConfigKeyEntry[] keys; } [Serializable] private class ConfigKeyEntry { public string key = ""; public string debugKey = ""; public string value = ""; public string type = ""; public string description = ""; public bool restartRequired; } [Serializable] private class SetConfigResult { public string status = "ok"; public string debugKey = ""; public string value = ""; public string warning = ""; public string? error; public static SetConfigResult Ok(string debugKey, string value) { return new SetConfigResult { debugKey = debugKey, value = value }; } public static SetConfigResult Fail(string error) { return new SetConfigResult { status = "error", error = error }; } } [Serializable] private class VerifyResponse { public VerifyCheck[] checks; } [Serializable] private class VerifyCheck { public string id = ""; public bool ok; public string message = ""; } [Serializable] private class TriggerResponse { public bool triggered; } [Serializable] private class RuntimeStateResponse { public float nearestEnemyDist = -1f; public bool psychoticBreakEnabled; public bool psychoticBreakCanTrigger; public string psychoticBreakBlockReason = ""; public bool psychoticBreakEpisodeActive; public float psychoticBreakEpisodeTimer; public float psychoticBreakEpisodeDuration; public float psychoticBreakNextCheckIn; public int psychoticBreakThreatCount; public int psychoticBreakEnemyCount; public bool psychoticBreakClipsLoaded; public bool adrenalineActive; public bool panicSprintActive; public float panicSprintCooldown; public int audioClipCount; public float audioNextPlayIn = -1f; public int dreadPatchCount; public bool debugOverlayEnabled; public bool debugOverlayPresent; } [Serializable] private class ShutdownResponse { public string status = "shutting down"; } [Serializable] private class LogsResponse { public LogEntry[] logs; } [Serializable] private class PatchesResponse { public PatchEntry[] patches; } [Serializable] private class PatchEntry { public string method = ""; public int prefixes; public int postfixes; public int transpilers; public int finalizers; public string[] owners; } [Serializable] private class SetConfigRequest { public string? cmd; public SetConfigData? data; } [Serializable] private class SetConfigData { public string? section; public string? key; public string? value; } private const int MaxMessageBytes = 4096; private const int ReadTimeoutMs = 5000; private const int CommandTimeoutMs = 10000; private const int MaxLogEntries = 200; private const int MaxQueueDepth = 256; private const int AcceptPollMs = 50; private const int ShutdownJoinMs = 250; private Thread? _serverThread; private TcpListener? _listener; private volatile bool _running; private volatile bool _shutdownComplete; private readonly Queue _queue = new Queue(32); private readonly List _logBuffer = new List(200); private readonly object _logLock = new object(); private int _boundPort; private DebugLogListener? _logListener; private void Start() { if (!DreadConfig.DebugServerEnabled.Value) { ((Behaviour)this).enabled = false; return; } int value = DreadConfig.DebugServerPort.Value; _listener = new TcpListener(IPAddress.Loopback, value); try { _listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); _listener.Start(); _boundPort = value; } catch (SocketException) { value++; try { _listener = new TcpListener(IPAddress.Loopback, value); _listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, optionValue: true); _listener.Start(); _boundPort = value; } catch (Exception ex) { Plugin.Logger.LogError((object)$"[Dread DebugServer] Failed to bind on {value - 1} or {value}: {ex.Message}"); _listener = null; ((Behaviour)this).enabled = false; return; } } _logListener = new DebugLogListener(this); Logger.Listeners.Add((ILogListener)(object)_logListener); _running = true; _serverThread = new Thread(ServerLoop) { IsBackground = true, Name = "DreadDebugServer" }; _serverThread.Start(); Application.quitting += OnApplicationQuit; Plugin.Logger.LogInfo((object)$"[Dread DebugServer] LISTENING 127.0.0.1:{_boundPort}"); } private void OnApplicationQuit() { ShutdownServer(); } private void OnDestroy() { Application.quitting -= OnApplicationQuit; ShutdownServer(); } private void ShutdownServer() { if (!_shutdownComplete) { _shutdownComplete = true; _running = false; if (_logListener != null) { Logger.Listeners.Remove((ILogListener)(object)_logListener); _logListener = null; } ReleasePendingCommands(); try { _listener?.Server?.Close(); } catch { } try { _listener?.Stop(); } catch { } _listener = null; Thread serverThread = _serverThread; if (serverThread != null && serverThread.IsAlive && Thread.CurrentThread != serverThread) { serverThread.Join(250); } _serverThread = null; } } private void ReleasePendingCommands() { lock (_queue) { while (_queue.Count > 0) { DebugCommand debugCommand = _queue.Dequeue(); int id = 0; try { id = JsonUtility.FromJson(debugCommand.RequestJson).id; } catch { } debugCommand.Response = MakeResponse(id, ok: false, "server shutting down", -1); debugCommand.Done.Set(); } } } private bool WaitForCommandDone(DebugCommand cmd) { int num = Environment.TickCount + 10000; while (_running) { int num2 = num - Environment.TickCount; if (num2 <= 0) { break; } int millisecondsTimeout = ((num2 > 100) ? 100 : num2); if (cmd.Done.Wait(millisecondsTimeout)) { return true; } } int id = 0; try { id = JsonUtility.FromJson(cmd.RequestJson).id; } catch { } cmd.Response = MakeResponse(id, ok: false, "server shutting down", -1); cmd.Done.Set(); return false; } private void AddLogEntry(string level, string message) { lock (_logLock) { _logBuffer.Add(new LogEntry { Level = level, Message = message, Timestamp = DateTime.UtcNow.ToString("O") }); if (_logBuffer.Count > 200) { _logBuffer.RemoveAt(0); } } } private void ServerLoop() { while (_running) { try { if (_listener == null) { break; } if (!_listener.Pending()) { Thread.Sleep(50); continue; } using TcpClient tcpClient = _listener.AcceptTcpClient(); tcpClient.ReceiveTimeout = 5000; using NetworkStream networkStream = tcpClient.GetStream(); using StreamReader streamReader = new StreamReader(networkStream, Encoding.UTF8); while (_running) { string text; try { text = streamReader.ReadLine(); } catch (IOException) { break; } if (text == null) { break; } text = text.Trim(); if (text.Length == 0) { continue; } DebugCommand debugCommand = new DebugCommand { RequestJson = text }; lock (_queue) { if (_queue.Count >= 256) { RequestEnvelope requestEnvelope; try { requestEnvelope = JsonUtility.FromJson(text); } catch { requestEnvelope = new RequestEnvelope(); } string s = $"{{\"id\":{requestEnvelope.id},\"ok\":false," + "\"error\":\"queue full\",\"code\":-1}}\n"; byte[] bytes = Encoding.UTF8.GetBytes(s); try { networkStream.Write(bytes, 0, bytes.Length); } catch (IOException) { } break; } _queue.Enqueue(debugCommand); goto IL_012d; } IL_012d: if (!WaitForCommandDone(debugCommand)) { if (_running) { Plugin.Logger.LogWarning((object)"[Dread DebugServer] Command timed out"); } break; } byte[] bytes2 = Encoding.UTF8.GetBytes((debugCommand.Response ?? "{}") + "\n"); try { networkStream.Write(bytes2, 0, bytes2.Length); } catch (IOException) { break; } } } catch (ObjectDisposedException) { break; } catch (Exception ex5) when (_running) { Plugin.Logger.LogWarning((object)("[Dread DebugServer] Connection error: " + ex5.Message)); Thread.Sleep(500); } } } private void Update() { while (true) { DebugCommand debugCommand; lock (_queue) { if (_queue.Count == 0) { break; } debugCommand = _queue.Dequeue(); } try { debugCommand.Response = ExecuteCommand(debugCommand.RequestJson); } catch (Exception ex) { int id = 0; try { id = JsonUtility.FromJson(debugCommand.RequestJson).id; } catch { } debugCommand.Response = MakeResponse(id, ok: false, Sanitize(ex.Message), -1); Plugin.Logger.LogError((object)$"[Dread DebugServer] Command error: {ex}"); } finally { debugCommand.Done.Set(); } } } private string ExecuteCommand(string rawJson) { RequestEnvelope requestEnvelope; try { requestEnvelope = JsonUtility.FromJson(rawJson); } catch { return MakeResponse(0, ok: false, "invalid JSON", -3); } if (requestEnvelope.cmd == null) { return MakeResponse(requestEnvelope.id, ok: false, "Missing cmd field", -3); } switch (requestEnvelope.cmd) { case "ping": return MakeResponse(requestEnvelope.id, ok: true, new PingResponse { version = "1.6.1", port = _boundPort }); case "get_state": return MakeResponse(requestEnvelope.id, ok: true, CaptureState()); case "get_config": return MakeResponse(requestEnvelope.id, ok: true, CaptureConfig()); case "set_config": { SetConfigRequest setConfigRequest; try { setConfigRequest = JsonUtility.FromJson(rawJson); } catch { return MakeResponse(requestEnvelope.id, ok: false, "invalid JSON", -3); } if (setConfigRequest.data?.section == null || setConfigRequest.data?.key == null || setConfigRequest.data?.value == null) { return MakeResponse(requestEnvelope.id, ok: false, "Missing section, key, or value", -3); } SetConfigResult setConfigResult = SetConfigValue(setConfigRequest.data.section, setConfigRequest.data.key, setConfigRequest.data.value); if (setConfigResult.error != null) { return MakeResponse(requestEnvelope.id, ok: false, setConfigResult.error, -3); } return MakeResponse(requestEnvelope.id, ok: true, setConfigResult); } case "get_patches": return MakeResponse(requestEnvelope.id, ok: true, GetHarmonyPatches()); case "get_logs": lock (_logLock) { return MakeResponse(requestEnvelope.id, ok: true, new LogsResponse { logs = _logBuffer.ToArray() }); } case "shutdown": Plugin.Logger.LogInfo((object)"[Dread DebugServer] Shutdown requested via debug command"); _running = false; try { _listener?.Server?.Close(); } catch { } try { _listener?.Stop(); } catch { } _listener = null; ReleasePendingCommands(); return MakeResponse(requestEnvelope.id, ok: true, new ShutdownResponse()); case "verify": return MakeResponse(requestEnvelope.id, ok: true, RunVerifyChecks()); case "trigger_test_crash": return TriggerTestCrash(requestEnvelope.id); case "force_psychotic_break": return ForcePsychoticBreak(requestEnvelope.id); case "get_runtime_state": return MakeResponse(requestEnvelope.id, ok: true, CaptureRuntimeState()); default: return MakeResponse(requestEnvelope.id, ok: false, "Unknown command: " + requestEnvelope.cmd, -2); } } private StateResponse CaptureState() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) string scene = "unknown"; int enemyCount = 0; float num = -1f; float playerHp = -1f; float playerStamina = -1f; try { Scene activeScene = SceneManager.GetActiveScene(); scene = ((Scene)(ref activeScene)).name ?? "unknown"; EnemyHealth[] array = Object.FindObjectsOfType(); enemyCount = array.Length; PlayerController val = Object.FindObjectOfType(); if (val != null) { playerHp = ReadPlayerFloat(val, "Health", "health", "playerHealth"); playerStamina = ReadPlayerFloat(val, "stamina", "Stamina", "energy"); EnemyHealth[] array2 = array; foreach (EnemyHealth val2 in array2) { if (val2.CurrentHealth > 0) { float num2 = Vector3.Distance(((Component)val2).transform.position, ((Component)val).transform.position); if (num < 0f || num2 < num) { num = num2; } } } } } catch { } return new StateResponse { version = "1.6.1", scene = scene, enemyCount = enemyCount, nearestEnemyDist = num, playerHp = playerHp, playerStamina = playerStamina, debugServerPort = _boundPort, isEnabled = DreadConfig.DebugServerEnabled.Value }; } private static ConfigResponse CaptureConfig() { return new ConfigResponse { audioEnabled = DreadConfig.AudioEnabled.Value, audioFrequency = DreadConfig.AudioFrequency.Value, audioVolume = DreadConfig.AudioVolume.Value, monsterAggression = DreadConfig.MonsterAggressionEnabled.Value, monsterAudio = DreadConfig.MonsterAudioEnabled.Value, crouchSpeedBoost = DreadConfig.CrouchSpeedBoostEnabled.Value, fakeFootsteps = DreadConfig.FakeFootstepsEnabled.Value, adrenaline = DreadConfig.AdrenalineEnabled.Value, lowStaminaSound = DreadConfig.LowStaminaSoundEnabled.Value, panicSprint = DreadConfig.PanicSprintEnabled.Value, errorReporting = DreadConfig.ErrorReportingEnabled.Value, compatibilityMode = DreadConfig.CompatibilityMode.Value, compatibilitySkipConflictingPatches = DreadConfig.CompatibilitySkipConflictingPatches.Value, debugConsoleGuard = DreadConfig.DebugConsoleGuardEnabled.Value, psychoticBreak = DreadConfig.PsychoticBreakEnabled.Value, psychoticBreakTriggerChance = DreadConfig.PsychoticBreakTriggerChance.Value, psychoticBreakDuration = DreadConfig.PsychoticBreakDuration.Value, psychoticBreakOncePerMatch = DreadConfig.PsychoticBreakOncePerMatch.Value, debugServerEnabled = DreadConfig.DebugServerEnabled.Value, debugServerPort = DreadConfig.DebugServerPort.Value, debugOverlayEnabled = DreadConfig.DebugOverlayEnabled.Value, logLevel = DreadConfig.LogLevelEntry.Value.ToString(), sections = BuildConfigSections() }; } private static ConfigSectionEntry[] BuildConfigSections() { return new ConfigSectionEntry[11] { Section("1. Audio Dread", Entry("Enabled", "audio.enabled", (ConfigEntryBase)(object)DreadConfig.AudioEnabled), Entry("Frequency", "audio.frequency", (ConfigEntryBase)(object)DreadConfig.AudioFrequency), Entry("Volume", "audio.volume", (ConfigEntryBase)(object)DreadConfig.AudioVolume)), Section("2. Monster Overhaul", Entry("AggressionEnabled", "monster.aggression", (ConfigEntryBase)(object)DreadConfig.MonsterAggressionEnabled), Entry("AudioEnabled", "monster.audio", (ConfigEntryBase)(object)DreadConfig.MonsterAudioEnabled)), Section("3. Tension", Entry("FakeFootstepsEnabled", "tension.fakeFootsteps", (ConfigEntryBase)(object)DreadConfig.FakeFootstepsEnabled), Entry("AdrenalineEnabled", "tension.adrenaline", (ConfigEntryBase)(object)DreadConfig.AdrenalineEnabled), Entry("LowStaminaSoundEnabled", "tension.lowStamina", (ConfigEntryBase)(object)DreadConfig.LowStaminaSoundEnabled), Entry("PanicSprintEnabled", "tension.panicSprint", (ConfigEntryBase)(object)DreadConfig.PanicSprintEnabled)), Section("4. Psychotic Break", Entry("PsychoticBreakEnabled", "psychoticBreak.enabled", (ConfigEntryBase)(object)DreadConfig.PsychoticBreakEnabled), Entry("PsychoticBreakTriggerChance", "psychoticBreak.triggerChance", (ConfigEntryBase)(object)DreadConfig.PsychoticBreakTriggerChance), Entry("PsychoticBreakDuration", "psychoticBreak.duration", (ConfigEntryBase)(object)DreadConfig.PsychoticBreakDuration), Entry("PsychoticBreakOncePerMatch", "psychoticBreak.oncePerMatch", (ConfigEntryBase)(object)DreadConfig.PsychoticBreakOncePerMatch)), Section("5. QOL", Entry("CrouchSpeedBoost", "crouch.speed", (ConfigEntryBase)(object)DreadConfig.CrouchSpeedBoostEnabled)), Section("6. Compatibility", Entry("CompatibilityMode", "compatibility.mode", (ConfigEntryBase)(object)DreadConfig.CompatibilityMode), Entry("SkipConflictingPatches", "compatibility.skipConflictingPatches", (ConfigEntryBase)(object)DreadConfig.CompatibilitySkipConflictingPatches), Entry("DebugConsoleGuardEnabled", "compatibility.debugConsoleGuard", (ConfigEntryBase)(object)DreadConfig.DebugConsoleGuardEnabled)), Section("7. Error Reporting", Entry("ErrorReportingEnabled", "errorReporting", (ConfigEntryBase)(object)DreadConfig.ErrorReportingEnabled)), Section("8. Debug Overlay", Entry("DebugOverlayEnabled", "overlay.enabled", (ConfigEntryBase)(object)DreadConfig.DebugOverlayEnabled)), Section("9. Debug Server", Entry("DebugServerEnabled", "debugServer.enabled", (ConfigEntryBase)(object)DreadConfig.DebugServerEnabled, restartRequired: true), Entry("DebugServerPort", "debugServer.port", (ConfigEntryBase)(object)DreadConfig.DebugServerPort, restartRequired: true)), Section("10. Logging", Entry("LogLevel", "logging.level", (ConfigEntryBase)(object)DreadConfig.LogLevelEntry)), Section("11. Testing", Entry("Crash Game", "testing.crash", (ConfigEntryBase)(object)DreadConfig.TestCrashButton)) }; } private static ConfigSectionEntry Section(string section, params ConfigKeyEntry[] keys) { return new ConfigSectionEntry { section = section, keys = keys }; } private static ConfigKeyEntry Entry(string key, string debugKey, ConfigEntryBase entry, bool restartRequired = false) { string type = ((entry is ConfigEntry) ? "bool" : ((entry is ConfigEntry) ? "float" : ((entry is ConfigEntry) ? "int" : ((entry is ConfigEntry) ? "LogLevel" : "string")))); return new ConfigKeyEntry { key = key, debugKey = debugKey, value = ConfigValueToString(entry), type = type, description = (entry.Description.Description ?? ""), restartRequired = restartRequired }; } private static string ConfigValueToString(ConfigEntryBase entry) { if (!(entry is ConfigEntry val)) { if (!(entry is ConfigEntry val2)) { if (!(entry is ConfigEntry val3)) { if (entry is ConfigEntry val4) { return val4.Value.ToString(); } return ""; } return val3.Value.ToString(); } return val2.Value.ToString(CultureInfo.InvariantCulture); } return val.Value ? "true" : "false"; } private static SetConfigResult SetConfigValue(string section, string key, string value) { Dictionary obj = new Dictionary { ["audio.enabled"] = ((ConfigEntryBase)(object)DreadConfig.AudioEnabled, false), ["audio.frequency"] = ((ConfigEntryBase)(object)DreadConfig.AudioFrequency, false), ["audio.volume"] = ((ConfigEntryBase)(object)DreadConfig.AudioVolume, false), ["monster.aggression"] = ((ConfigEntryBase)(object)DreadConfig.MonsterAggressionEnabled, false), ["monster.audio"] = ((ConfigEntryBase)(object)DreadConfig.MonsterAudioEnabled, false), ["crouch.speed"] = ((ConfigEntryBase)(object)DreadConfig.CrouchSpeedBoostEnabled, false), ["tension.fakeFootsteps"] = ((ConfigEntryBase)(object)DreadConfig.FakeFootstepsEnabled, false), ["tension.adrenaline"] = ((ConfigEntryBase)(object)DreadConfig.AdrenalineEnabled, false), ["tension.lowStamina"] = ((ConfigEntryBase)(object)DreadConfig.LowStaminaSoundEnabled, false), ["tension.panicSprint"] = ((ConfigEntryBase)(object)DreadConfig.PanicSprintEnabled, false), ["errorReporting"] = ((ConfigEntryBase)(object)DreadConfig.ErrorReportingEnabled, false), ["compatibility.mode"] = ((ConfigEntryBase)(object)DreadConfig.CompatibilityMode, false), ["compatibility.skipConflictingPatches"] = ((ConfigEntryBase)(object)DreadConfig.CompatibilitySkipConflictingPatches, false), ["compatibility.debugConsoleGuard"] = ((ConfigEntryBase)(object)DreadConfig.DebugConsoleGuardEnabled, false), ["psychoticBreak.enabled"] = ((ConfigEntryBase)(object)DreadConfig.PsychoticBreakEnabled, false), ["psychoticBreak.triggerChance"] = ((ConfigEntryBase)(object)DreadConfig.PsychoticBreakTriggerChance, false), ["psychoticBreak.duration"] = ((ConfigEntryBase)(object)DreadConfig.PsychoticBreakDuration, false), ["psychoticBreak.oncePerMatch"] = ((ConfigEntryBase)(object)DreadConfig.PsychoticBreakOncePerMatch, false), ["testing.crash"] = ((ConfigEntryBase)(object)DreadConfig.TestCrashButton, false), ["debugServer.enabled"] = ((ConfigEntryBase)(object)DreadConfig.DebugServerEnabled, true), ["debugServer.port"] = ((ConfigEntryBase)(object)DreadConfig.DebugServerPort, true), ["overlay.enabled"] = ((ConfigEntryBase)(object)DreadConfig.DebugOverlayEnabled, false), ["logging.level"] = ((ConfigEntryBase)(object)DreadConfig.LogLevelEntry, false) }; string text = (string.IsNullOrEmpty(section) ? key : (string.IsNullOrEmpty(key) ? section : (section + "." + key))); if (!obj.TryGetValue(text, out var value2) || value2.Item1 == null) { return SetConfigResult.Fail("Unknown config: " + section + "/" + key + " (debug key: " + text + ")"); } try { if (value2.Item1 is ConfigEntry val) { val.Value = bool.Parse(value); } else if (value2.Item1 is ConfigEntry val2) { val2.Value = float.Parse(value); } else if (value2.Item1 is ConfigEntry val3) { val3.Value = int.Parse(value); } else { if (!(value2.Item1 is ConfigEntry val4)) { return SetConfigResult.Fail("Unsupported config type for " + section + "/" + key); } val4.Value = (LogLevel)Enum.Parse(typeof(LogLevel), value, ignoreCase: true); } } catch (Exception ex) { return SetConfigResult.Fail("Failed to set " + section + "/" + key + ": " + ex.Message); } SetConfigResult setConfigResult = SetConfigResult.Ok(text, value); if (value2.Item2) { setConfigResult.warning = "Restart the game for debug server bind changes to take effect."; } return setConfigResult; } private VerifyResponse RunVerifyChecks() { List list = new List { Check("version", !string.IsNullOrEmpty("1.6.1"), "version=1.6.1"), Check("debug_server_listening", _running && _listener != null, $"port={_boundPort}"), Check("systems_count", CountActiveSystems() >= 7, $"count={CountActiveSystems()}"), Check("audio_clips", DreadRuntimeState.AudioClipCount > 0, $"loaded={DreadRuntimeState.AudioClipCount}/4"), Check("psychotic_break_clips", DreadRuntimeState.PsychoticBreakClipsLoaded, DreadRuntimeState.PsychoticBreakClipsLoaded ? "all loaded" : "missing clips"), Check("overlay_present", Object.FindObjectOfType() != null, "DebugOverlaySystem host"), Check("harmony_patches", GetDreadPatchCount() > 0, $"dreadPatches={GetDreadPatchCount()}") }; return new VerifyResponse { checks = list.ToArray() }; } private static int CountActiveSystems() { int num = 0; if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } if (Object.FindObjectOfType() != null) { num++; } return num; } private static int GetDreadPatchCount() { if (DreadRuntimeState.DreadPatchCount > 0) { return DreadRuntimeState.DreadPatchCount; } if (Plugin.HarmonyInstance == null) { return 0; } int num = 0; try { foreach (MethodBase allPatchedMethod in Harmony.GetAllPatchedMethods()) { Patches patchInfo = Harmony.GetPatchInfo(allPatchedMethod); if (patchInfo != null) { ReadOnlyCollection prefixes = patchInfo.Prefixes; if (prefixes != null && prefixes.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } ReadOnlyCollection postfixes = patchInfo.Postfixes; if (postfixes != null && postfixes.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } ReadOnlyCollection transpilers = patchInfo.Transpilers; if (transpilers != null && transpilers.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } ReadOnlyCollection finalizers = patchInfo.Finalizers; if (finalizers != null && finalizers.Any((Patch p) => p.owner == "elytraking.dread")) { num++; } } } return num; } catch { return -1; } } private static VerifyCheck Check(string id, bool ok, string message) { return new VerifyCheck { id = id, ok = ok, message = message }; } private static string TriggerTestCrash(int id) { if (!DreadConfig.DebugServerEnabled.Value) { return MakeResponse(id, ok: false, "Debug server disabled", -3); } TestCrashSystem.TriggerForDebug(); return MakeResponse(id, ok: true, new TriggerResponse { triggered = true }); } private static string ForcePsychoticBreak(int id) { if (!DreadConfig.DebugServerEnabled.Value) { return MakeResponse(id, ok: false, "Debug server disabled", -3); } PsychoticBreakSystem psychoticBreakSystem = Object.FindObjectOfType(); if (psychoticBreakSystem == null) { return MakeResponse(id, ok: false, "PsychoticBreakSystem not found", -3); } try { psychoticBreakSystem.ForceEpisodeForDebug(); } catch (Exception ex) { return MakeResponse(id, ok: false, ex.Message, -1); } return MakeResponse(id, ok: true, new TriggerResponse { triggered = true }); } private static RuntimeStateResponse CaptureRuntimeState() { float nearestEnemyDist = DreadRuntimeState.NearestEnemyDist; return new RuntimeStateResponse { nearestEnemyDist = ((nearestEnemyDist >= 1.7014117E+38f) ? (-1f) : nearestEnemyDist), psychoticBreakEnabled = DreadRuntimeState.PsychoticBreakEnabled, psychoticBreakCanTrigger = DreadRuntimeState.PsychoticBreakCanTrigger, psychoticBreakBlockReason = DreadRuntimeState.PsychoticBreakBlockReason, psychoticBreakEpisodeActive = DreadRuntimeState.PsychoticBreakEpisodeActive, psychoticBreakEpisodeTimer = DreadRuntimeState.PsychoticBreakEpisodeTimer, psychoticBreakEpisodeDuration = DreadRuntimeState.PsychoticBreakEpisodeDuration, psychoticBreakNextCheckIn = DreadRuntimeState.PsychoticBreakNextCheckIn, psychoticBreakThreatCount = DreadRuntimeState.PsychoticBreakThreatCount, psychoticBreakEnemyCount = DreadRuntimeState.PsychoticBreakEnemyCount, psychoticBreakClipsLoaded = DreadRuntimeState.PsychoticBreakClipsLoaded, adrenalineActive = DreadRuntimeState.AdrenalineActive, panicSprintActive = DreadRuntimeState.PanicSprintActive, panicSprintCooldown = DreadRuntimeState.PanicSprintCooldown, audioClipCount = DreadRuntimeState.AudioClipCount, audioNextPlayIn = DreadRuntimeState.AudioNextPlayIn, dreadPatchCount = DreadRuntimeState.DreadPatchCount, debugOverlayEnabled = DreadConfig.DebugOverlayEnabled.Value, debugOverlayPresent = (Object.FindObjectOfType() != null) }; } private PatchesResponse GetHarmonyPatches() { if (Plugin.HarmonyInstance == null) { return new PatchesResponse { patches = Array.Empty() }; } List list = new List(); try { foreach (MethodBase allPatchedMethod in Harmony.GetAllPatchedMethods()) { Patches patchInfo = Harmony.GetPatchInfo(allPatchedMethod); list.Add(new PatchEntry { method = GeneralExtensions.FullDescription(allPatchedMethod), prefixes = (patchInfo?.Prefixes?.Count).GetValueOrDefault(), postfixes = (patchInfo?.Postfixes?.Count).GetValueOrDefault(), transpilers = (patchInfo?.Transpilers?.Count).GetValueOrDefault(), finalizers = (patchInfo?.Finalizers?.Count).GetValueOrDefault(), owners = (patchInfo?.Prefixes?.Select((Patch p) => p.owner).Concat(patchInfo?.Postfixes?.Select((Patch p) => p.owner) ?? Enumerable.Empty()).Distinct() .ToArray() ?? Array.Empty()) }); } } catch (Exception ex) { Plugin.Logger.LogWarning((object)("[Dread DebugServer] get_patches error: " + ex.Message)); } return new PatchesResponse { patches = list.ToArray() }; } private static string MakeResponse(int id, bool ok, object data) { string arg = JsonUtility.ToJson(data); return string.Format("{{\"id\":{0},\"ok\":{1},\"data\":{2}}}", id, ok ? "true" : "false", arg); } private static string MakeResponse(int id, bool ok, string error, int code) { string text = Sanitize(error); return string.Format("{{\"id\":{0},\"ok\":{1},\"error\":\"{2}\",\"code\":{3}}}", id, ok ? "true" : "false", text, code); } private static float ReadPlayerFloat(PlayerController player, params string[] names) { foreach (string text in names) { try { return Traverse.Create((object)player).Property(text, (object[])null).Value; } catch { } try { return Traverse.Create((object)player).Field(text).Value; } catch { } } return -1f; } private static string Sanitize(string s) { if (string.IsNullOrEmpty(s)) { return ""; } StringBuilder stringBuilder = new StringBuilder(s.Length); foreach (char c in s) { if (c == '"') { stringBuilder.Append("\\\""); } else if (c == '\\') { stringBuilder.Append("\\\\"); } else if (c == '\n') { stringBuilder.Append("\\n"); } else if (c == '\r') { stringBuilder.Append("\\r"); } else if (c == '\t') { stringBuilder.Append("\\t"); } else if (c < ' ') { stringBuilder.Append($"\\u{(int)c:x4}"); } else { stringBuilder.Append(c); } } return stringBuilder.ToString(); } } internal static class DreadRuntimeState { public static float NearestEnemyDist { get; internal set; } = float.MaxValue; public static bool AdrenalineActive { get; internal set; } public static bool PanicSprintActive { get; internal set; } public static float PanicSprintCooldown { get; internal set; } public static bool PsychoticBreakEnabled { get; internal set; } public static bool PsychoticBreakCanTrigger { get; internal set; } public static string PsychoticBreakBlockReason { get; internal set; } = ""; public static bool PsychoticBreakEpisodeActive { get; internal set; } public static float PsychoticBreakEpisodeTimer { get; internal set; } public static float PsychoticBreakEpisodeDuration { get; internal set; } public static float PsychoticBreakNextCheckIn { get; internal set; } public static int PsychoticBreakThreatCount { get; internal set; } public static int PsychoticBreakEnemyCount { get; internal set; } public static bool PsychoticBreakClipsLoaded { get; internal set; } public static int AudioClipCount { get; internal set; } public static float AudioNextPlayIn { get; internal set; } = -1f; public static int DreadPatchCount { get; internal set; } } internal static class DreadSystemInitializer { private static bool _initialized; public static bool TryInitialize() { if (_initialized) { return true; } if (!EnsureUnityEngineUiLoaded()) { LoggingService.LogVerbose("[Dread] Deferring system init until UnityEngine.UI is available"); return false; } _initialized = true; int num = 0; int num2 = 0; foreach (SystemRegistration item in DreadSystemRegistry.Registrations.OrderBy((SystemRegistration r) => r.OrderGroup)) { if (item.IsEnabled == null || item.IsEnabled()) { num2++; num += TryAddSystem(item.SystemType, item.HostName); } } RepoConfigCompat.TryApply(Plugin.HarmonyInstance); if (num > 0) { if (num < num2) { LoggingService.LogInfo($"Systems initialized ({num}/{num2})"); } else { LoggingService.LogInfo($"Systems initialized ({num})"); } } else if (num2 > 0) { LoggingService.LogError("All systems failed to initialize."); } else { LoggingService.LogVerbose("[Dread] No runtime systems enabled for initialization."); } return true; } private static int TryAddSystem(Type systemType, string hostName) { try { if (CreateSystemHost(hostName).AddComponent(systemType) == null) { LoggingService.LogError("Failed to add " + systemType.Name + " component: Unity could not instantiate the script (check BepInEx log for TypeLoadException)"); return 0; } return 1; } catch (Exception ex) { bool flag = ((ex is TypeLoadException || ex is ReflectionTypeLoadException) ? true : false); string text = ((!flag) ? ex.Message : (ex.InnerException?.Message ?? ex.Message)); LoggingService.LogError("Failed to add " + systemType.Name + " component: " + text); return 0; } } private static bool EnsureUnityEngineUiLoaded() { try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "UnityEngine.UI", StringComparison.Ordinal)) { return assembly.GetType("UnityEngine.UI.RawImage") != null; } } return Assembly.Load("UnityEngine.UI").GetType("UnityEngine.UI.RawImage") != null; } catch (Exception ex) { LoggingService.LogVerbose("[Dread] UnityEngine.UI not ready: " + ex.Message); return false; } } private static GameObject CreateSystemHost(string name) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown //IL_000d: Expected O, but got Unknown GameObject val = new GameObject(name); Object.DontDestroyOnLoad((Object)val); return val; } } internal enum SystemOrderGroup { Core, Debug } internal sealed class SystemRegistration { public string Id { get; } public Type SystemType { get; } public string HostName { get; } public SystemOrderGroup OrderGroup { get; } public Func? IsEnabled { get; } public SystemRegistration(string id, Type systemType, string hostName, SystemOrderGroup orderGroup, Func? isEnabled = null) { Id = id; SystemType = systemType; HostName = hostName; OrderGroup = orderGroup; IsEnabled = isEnabled; } } internal static class DreadSystemRegistry { public static IReadOnlyList Registrations { get; } = new <>z__ReadOnlyArray(new SystemRegistration[9] { new SystemRegistration("audio-dread", typeof(AudioDreadSystem), "DreadAudioHost", SystemOrderGroup.Core), new SystemRegistration("monster-overhaul", typeof(MonsterOverhaulSystem), "DreadMonsterHost", SystemOrderGroup.Core), new SystemRegistration("tension", typeof(TensionSystem), "DreadTensionHost", SystemOrderGroup.Core), new SystemRegistration("error-reporter", typeof(ErrorReporterSystem), "DreadErrorHost", SystemOrderGroup.Core), new SystemRegistration("error-reporting-prompt", typeof(ErrorReportingPromptSystem), "DreadErrorReportingPromptHost", SystemOrderGroup.Core), new SystemRegistration("psychotic-break", typeof(PsychoticBreakSystem), "DreadPsychoticBreakHost", SystemOrderGroup.Core), new SystemRegistration("test-crash", typeof(TestCrashSystem), "DreadTestCrashHost", SystemOrderGroup.Debug), new SystemRegistration("debug-server", typeof(DebugServerSystem), "DreadDebugHost", SystemOrderGroup.Debug), new SystemRegistration("debug-overlay", typeof(DebugOverlaySystem), "DreadDebugOverlayHost", SystemOrderGroup.Debug) }); } internal static class EnemyHealthCompat { internal static bool IsValid(EnemyHealth? enemy) { if (enemy == null) { return false; } try { return ((Component)enemy).gameObject != null; } catch { return false; } } internal static bool IsAliveForVisibility(EnemyHealth enemy) { if (!IsValid(enemy)) { return false; } try { if (!((Component)enemy).gameObject.activeInHierarchy) { return false; } } catch { return false; } if (TryReadHealth(enemy, out var hp)) { return hp > 0f; } return true; } private static bool TryReadHealth(EnemyHealth enemy, out float hp) { hp = 0f; if (!IsValid(enemy)) { return false; } Traverse traverse = Traverse.Create((object)enemy); string[] array = new string[6] { "CurrentHealth", "currentHealth", "health", "Health", "HP", "hp" }; foreach (string name in array) { if (TryReadFloatMember(traverse, name, out hp)) { return true; } if (TryReadIntMember(traverse, name, out var value)) { hp = value; return true; } } return false; } private static bool TryReadFloatMember(Traverse traverse, string name, out float value) { value = 0f; try { value = traverse.Property(name, (object[])null).Value; return true; } catch { } try { value = traverse.Field(name).Value; return true; } catch { } return false; } private static bool TryReadIntMember(Traverse traverse, string name, out int value) { value = 0; try { value = traverse.Property(name, (object[])null).Value; return true; } catch { } try { value = traverse.Field(name).Value; return true; } catch { } return false; } } internal static class EnemyScanCache { private static EnemyHealth[] _enemies = Array.Empty(); private static float _nextRefresh = -1f; private const float RefreshInterval = 0.5f; public static int Count => _enemies.Length; public static EnemyHealth[] GetEnemies() { RefreshIfNeeded(); return _enemies; } public static float NearestDistance(Vector3 origin) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) RefreshIfNeeded(); float num = float.MaxValue; for (int i = 0; i < _enemies.Length; i++) { EnemyHealth enemy = _enemies[i]; if (EnemyHealthCompat.IsValid(enemy)) { float num2 = Vector3.Distance(origin, GetFocusPosition(enemy)); if (num2 < num) { num = num2; } } } return num; } public static Vector3 GetFocusPosition(EnemyHealth enemy) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if (!EnemyHealthCompat.IsValid(enemy)) { return Vector3.zero; } try { return ((Component)enemy).transform.position; } catch { return Vector3.zero; } } public static void Invalidate() { _nextRefresh = -1f; } private static void RefreshIfNeeded() { if (Time.time < _nextRefresh) { return; } _nextRefresh = Time.time + 0.5f; EnemyHealth[] array = Object.FindObjectsOfType(); if (array == null || array.Length == 0) { _enemies = Array.Empty(); return; } int num = 0; for (int i = 0; i < array.Length; i++) { if (EnemyHealthCompat.IsValid(array[i])) { array[num++] = array[i]; } } if (num == 0) { _enemies = Array.Empty(); return; } EnemyHealth[] array2 = (EnemyHealth[])(object)new EnemyHealth[num]; Array.Copy(array, array2, num); _enemies = array2; } } public class ErrorReporterSystem : MonoBehaviour { [CompilerGenerated] private static class <>O { public static LogCallback <0>__OnLogMessageReceived; public static EventHandler <1>__OnErrorReportingSettingChanged; } [CompilerGenerated] private sealed class d__12 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Exception ex; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__12(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //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) if (<>1__state != 0) { return false; } <>1__state = -1; if (!ErrorReportingConsent.IsReportingAllowed()) { LoggingService.LogWarning("[ErrorReporter] Error reporting is not allowed yet (disabled or first-run prompt pending)."); return false; } LoggingService.LogInfo("[ErrorReporter] Sending test crash report (sync POST)..."); try { string message = this.ex.GetType().Name + ": " + this.ex.Message; string stack = this.ex.StackTrace ?? string.Empty; Scene activeScene = SceneManager.GetActiveScene(); string scene = ((Scene)(ref activeScene)).name ?? "unknown"; ErrorReport errorReport = ErrorReportPayloadCapture.BuildTestCrashReport(this.ex, message, stack, scene); ErrorPayload errorPayload = new ErrorPayload { ModVersion = "1.6.1", GameVersion = Application.version, UnityVersion = Application.unityVersion, Reports = new ErrorReport[1] { errorReport } }; if (ErrorReportUploader.TryPostPayloadSync(errorPayload, out string responseBody, out string error)) { if (ErrorReportUploader.HasWorkerReportFailures(responseBody, errorPayload.Reports)) { LoggingService.LogWarning("Test crash report reached worker but GitHub step failed. Response: " + responseBody); } else { LoggingService.LogInfo("Test crash report sent. Response: " + responseBody); } } else { LoggingService.LogWarning("Test crash report POST failed: " + error); } } catch (Exception ex) { LoggingService.LogWarning("[ErrorReporter] Test crash report failed: " + ex.Message); } 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(); } } [CompilerGenerated] private sealed class d__19 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ErrorReporterSystem <>4__this; public List batch; private ErrorPayload 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__19(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { bool result; try { int num = <>1__state; ErrorReporterSystem errorReporterSystem = <>4__this; switch (num) { default: result = false; break; case 0: { <>1__state = -1; errorReporterSystem._sendInProgress = true; <>1__state = -3; LoggingService.LogVerbose("[ErrorReporter] Sending report..."); 5__2 = new ErrorPayload { ModVersion = "1.6.1", GameVersion = Application.version, UnityVersion = Application.unityVersion, Reports = batch.ToArray() }; ErrorReportUploader.EncodePayload(5__2, out string json); string text = ErrorReportUploader.ValidateBatchJson(json); if (text != null) { LoggingService.LogWarning("[ErrorReporter] " + text); errorReporterSystem.RequeueFailedBatch(batch); result = false; <>m__Finally1(); } else { <>2__current = null; <>1__state = 1; result = true; } break; } case 1: { <>1__state = -3; if (!ErrorReportUploader.TryPostPayloadSync(5__2, out string responseBody, out string error)) { LoggingService.LogWarning("Error report HTTP failed: " + error); errorReporterSystem.RequeueFailedBatch(batch); } else { errorReporterSystem.HandleWorkerResponse(responseBody, batch); } 5__2 = null; <>m__Finally1(); result = false; break; } } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } return result; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; <>4__this._sendInProgress = false; } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly List _buffer = new List(); private float _lastFlushTime; private volatile bool _shouldFlush; private bool _sendInProgress; private const float FlushInterval = 300f; private void OnEnable() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown LoggingService.LogVerbose("[ErrorReporter] Awake starting..."); object obj = <>O.<0>__OnLogMessageReceived; if (obj == null) { LogCallback val = OnLogMessageReceived; <>O.<0>__OnLogMessageReceived = val; obj = (object)val; } Application.logMessageReceived += (LogCallback)obj; SceneManager.sceneLoaded += OnSceneLoaded; DreadConfig.ErrorReportingEnabled.SettingChanged += OnErrorReportingSettingChanged; _lastFlushTime = Time.realtimeSinceStartup; } private void OnDisable() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown object obj = <>O.<0>__OnLogMessageReceived; if (obj == null) { LogCallback val = OnLogMessageReceived; <>O.<0>__OnLogMessageReceived = val; obj = (object)val; } Application.logMessageReceived -= (LogCallback)obj; SceneManager.sceneLoaded -= OnSceneLoaded; DreadConfig.ErrorReportingEnabled.SettingChanged -= OnErrorReportingSettingChanged; FlushNow(); } private static void OnErrorReportingSettingChanged(object sender, EventArgs e) { if (ErrorReportingConsent.IsReportingAllowed()) { LoggingService.LogInfo("[Dread] Error reporting enabled. Anonymous error reporting (on by default for new installs). When enabled, serious Unity errors may be sent to the developer to fix bugs. To disable: set ErrorReportingEnabled = false in BepInEx/config/elytraking.dread.cfg (section 7. Error Reporting in elytraking.dread.cfg). REPOConfig lists the toggle only (no per-toggle description API); use the cfg file or Configuration Manager (F1) for full text."); } } private static void OnLogMessageReceived(string logString, string stackTrace, LogType type) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (!ShouldIgnoreUnityLog(logString, stackTrace)) { EnqueueLog(logString, stackTrace, type); } } private static bool ShouldIgnoreUnityLog(string logString, string stackTrace) { if (!logString.Contains("BadImageFormatException")) { return false; } if (logString.IndexOf("zero rva", StringComparison.OrdinalIgnoreCase) < 0) { return stackTrace.IndexOf("UnityEngine.Networking", StringComparison.Ordinal) >= 0; } return true; } internal static void EnqueueLog(string logString, string stackTrace, LogType type) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) ErrorReportLogQueue.EnqueueLog(logString, stackTrace, type); } private void Update() { ProcessPendingLogs(); if (_shouldFlush || Time.realtimeSinceStartup - _lastFlushTime >= 300f) { FlushNow(); } } [IteratorStateMachine(typeof(d__12))] internal IEnumerator ReportTestCrashAndWait(Exception ex) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__12(0) { ex = ex }; } private void ProcessPendingLogs() { try { ProcessPendingLogsCore(); } catch (Exception ex) { LoggingService.LogWarning("[ErrorReporter] Failed to process pending logs: " + ex.Message); } } private void ProcessPendingLogsCore() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 if (!ErrorReportingConsent.IsReportingAllowed() || !ErrorReportLogQueue.TryDequeueBatch(out ErrorReportLogQueue.RawLogEntry[] batch)) { return; } GameStateData gameState = ErrorReportPayloadCapture.CaptureGameState(); SystemInfoData systemInfo = ErrorReportPayloadCapture.CaptureSystemInfoSafe(); DisplayInfoData display = ErrorReportPayloadCapture.CaptureDisplayInfoSafe(); ConfigData config = ErrorReportPayloadCapture.CaptureConfig(); Scene activeScene = SceneManager.GetActiveScene(); string scene = ((Scene)(ref activeScene)).name ?? "unknown"; ErrorReportLogQueue.RawLogEntry[] array = batch; foreach (ErrorReportLogQueue.RawLogEntry rawLogEntry in array) { ErrorReport item = new ErrorReport { Hash = ErrorReportLogQueue.ComputeHash(rawLogEntry.StackTrace, rawLogEntry.Message), Timestamp = DateTime.UtcNow.ToString("o"), Type = (((int)rawLogEntry.Type == 4) ? "exception" : "error"), ExceptionType = ErrorReportPayloadCapture.ParseExceptionType(rawLogEntry.Message), Message = ErrorReportPayloadCapture.Truncate(rawLogEntry.Message, 500), StackTrace = ErrorReportPayloadCapture.Truncate(rawLogEntry.StackTrace, 3000), Scene = scene, GameState = gameState, SystemInfo = systemInfo, Display = display, Config = config }; lock (_buffer) { _buffer.Add(item); if (_buffer.Count >= 50) { _shouldFlush = true; } } } } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { FlushNow(); } private void FlushNow() { if (_sendInProgress || !ErrorReportingConsent.IsReportingAllowed()) { return; } List batch; lock (_buffer) { if (_buffer.Count == 0) { return; } batch = new List(_buffer); _buffer.Clear(); } _shouldFlush = false; _lastFlushTime = Time.realtimeSinceStartup; ((MonoBehaviour)this).StartCoroutine(SendBatch(batch)); } private void RequeueFailedBatch(List batch) { if (batch.Count != 0) { lock (_buffer) { _buffer.AddRange(batch); } LoggingService.LogWarning($"[ErrorReporter] Re-queued {batch.Count} report(s) after failed send."); } } private void HandleWorkerResponse(string body, List batch) { List list = ErrorReportUploader.CollectFailedReports(body, batch); if (list.Count > 0) { LoggingService.LogWarning($"[ErrorReporter] Worker reported {list.Count} GitHub failure(s). Response: {body}"); RequeueFailedBatch(list); } else if (ErrorReportUploader.HasUnmappedWorkerErrors(body)) { LoggingService.LogWarning("[ErrorReporter] Worker returned errors; re-queuing full batch. Response: " + body); RequeueFailedBatch(batch); } else { LoggingService.LogInfo($"Sent {batch.Count} error report(s). Response: {body}"); } } [IteratorStateMachine(typeof(d__19))] private IEnumerator SendBatch(List batch) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__19(0) { <>4__this = this, batch = batch }; } } internal static class ErrorReportingConsent { public static bool IsReportingAllowed() { if (!DreadConfig.ErrorReportingEnabled.Value) { return false; } if (!DreadConfig.ErrorReportingPromptShown.Value) { return false; } return true; } } internal static class ErrorReportingPrivacyCopy { public const string ShortSummary = "Anonymous error reporting (on by default for new installs). When enabled, serious Unity errors may be sent to the developer to fix bugs."; public const string DisableInstructions = "To disable: set ErrorReportingEnabled = false in BepInEx/config/elytraking.dread.cfg (section 7. Error Reporting in elytraking.dread.cfg). REPOConfig lists the toggle only (no per-toggle description API); use the cfg file or Configuration Manager (F1) for full text."; public static readonly string[] DataBullets; public static readonly string FullDescription; static ErrorReportingPrivacyCopy() { DataBullets = new string[9] { "Exception type, message (length-capped), stack trace (length-capped), and a dedupe hash", "Active scene name and session play time", "Enemy counts (alive, total, nearby)", "Player HP, stamina, and world position when available", "OS, CPU, RAM, GPU, device model, and may include VRAM, GPU driver version, and shader level", "Screen resolution, refresh rate, DPI, and fullscreen mode", "Eleven named Dread settings (toggles plus audio frequency and volume), including this setting", "Not sent: your username, Steam profile, or deliberate PII", "Default on for new installs; turn off anytime via the first-run prompt or cfg" }; StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("Anonymous error reporting (on by default for new installs). When enabled, serious Unity errors may be sent to the developer to fix bugs."); stringBuilder.Append(" Reports go to the developer through a Cloudflare Worker and may create or update "); stringBuilder.Append("public GitHub issues labeled auto-reported. Requires network; delivery is not "); stringBuilder.Append("instant and offline play may delay or drop batches. Does not intentionally include "); stringBuilder.Append("your account name, Steam ID, voice or chat, or files outside the game. When "); stringBuilder.Append("enabled, reports may include: "); for (int i = 0; i <= 6; i++) { if (i > 0) { stringBuilder.Append("; "); } stringBuilder.Append(DataBullets[i]); } stringBuilder.Append(". "); stringBuilder.Append(DataBullets[7]); stringBuilder.Append(". "); stringBuilder.Append(DataBullets[8]); stringBuilder.Append(". Some fields may be omitted if capture fails. "); stringBuilder.Append("To disable: set ErrorReportingEnabled = false in BepInEx/config/elytraking.dread.cfg (section 7. Error Reporting in elytraking.dread.cfg). REPOConfig lists the toggle only (no per-toggle description API); use the cfg file or Configuration Manager (F1) for full text."); FullDescription = stringBuilder.ToString(); } } public class ErrorReportingPromptSystem : MonoBehaviour { private enum PromptState : byte { Pending, Visible, Dismissed } private const int GuiDepth = 10000; private const float WindowWidth = 580f; private const float MinWindowHeight = 500f; private const float Pad = 18f; private const float ButtonHeight = 36f; private const float ButtonGap = 10f; private const float BulletGap = 6f; private const float MinBulletRowHeight = 22f; private const string ModBrandTitle = "DREAD"; private const string ModBrandSubtitle = "elytraking-Dread · atmospheric horror mod for R.E.P.O."; private const string ModBrandAsk = "This mod (not the base game) is asking permission before it may send anonymous error reports."; private static readonly GUIContent EmptyContent = new GUIContent(); private static readonly Color ColAccent = new Color(0.96f, 0.55f, 0.38f); private static readonly Color ColDim = new Color(0.62f, 0.64f, 0.7f); private static readonly Color ColBody = new Color(0.92f, 0.93f, 0.96f); private static readonly Color ColOverlay = new Color(0.02f, 0.02f, 0.04f, 0.72f); private static readonly Color ColPanel = new Color(0.08f, 0.08f, 0.11f, 0.96f); private static readonly Color ColButton = new Color(0.14f, 0.14f, 0.18f, 1f); private static readonly Color ColButtonHover = new Color(0.22f, 0.22f, 0.28f, 1f); private static readonly Color ColButtonPrimary = new Color(0.28f, 0.16f, 0.12f, 1f); private static readonly Color ColButtonPrimaryHover = new Color(0.38f, 0.22f, 0.16f, 1f); private PromptState _state; private Vector2 _scrollPosition; private bool _cursorCaptured; private CursorLockMode _savedLockState; private bool _savedCursorVisible; private bool _inputLocked; private bool _layoutReady; private float _windowHeight = 500f; private float _summaryHeight; private float _hintHeight; private float _scrollContentHeight; private float _scrollViewHeight; private float[]? _bulletHeights; private Texture2D? _overlayTex; private Texture2D? _panelTex; private Texture2D? _buttonTex; private Texture2D? _buttonHoverTex; private Texture2D? _buttonPrimaryTex; private Texture2D? _buttonPrimaryHoverTex; private GUIStyle? _overlayStyle; private GUIStyle? _panelStyle; private GUIStyle? _brandStyle; private GUIStyle? _subtitleStyle; private GUIStyle? _askStyle; private GUIStyle? _sectionStyle; private GUIStyle? _bodyStyle; private GUIStyle? _hintStyle; private GUIStyle? _buttonStyle; private GUIStyle? _buttonPrimaryStyle; private void Start() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) SceneManager.sceneLoaded += OnSceneLoaded; DreadConfig.ErrorReportingPromptShown.SettingChanged += OnPromptShownConfigChanged; TryActivatePrompt(SceneManager.GetActiveScene()); } private void OnDestroy() { SceneManager.sceneLoaded -= OnSceneLoaded; DreadConfig.ErrorReportingPromptShown.SettingChanged -= OnPromptShownConfigChanged; ReleasePromptCapture(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) TryActivatePrompt(scene); } private void OnPromptShownConfigChanged(object? sender, EventArgs e) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) SyncPromptStateFromConfig(); TryActivatePrompt(SceneManager.GetActiveScene()); } private void SyncPromptStateFromConfig() { if (DreadConfig.ErrorReportingPromptShown.Value) { if (_state == PromptState.Visible) { ReleasePromptCapture(); } _state = PromptState.Dismissed; } else if (_state == PromptState.Dismissed) { ReleasePromptCapture(); _state = PromptState.Pending; _layoutReady = false; } } private void TryActivatePrompt(Scene scene) { SyncPromptStateFromConfig(); if (_state == PromptState.Dismissed) { return; } if (SemiFunc.MenuLevel()) { if (_state == PromptState.Visible) { ReleasePromptCapture(); _state = PromptState.Pending; } } else if (_state == PromptState.Pending) { _state = PromptState.Visible; } } private void Update() { if (_state == PromptState.Visible) { MaintainCursorForPrompt(); if (!_inputLocked) { LockLocalPlayerInput(); _inputLocked = true; } } } private void OnGUI() { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02ee: Unknown result type (might be due to invalid IL or missing references) if (_state == PromptState.Visible) { EnsureStyles(); float num = ((Screen.height > 100) ? ((float)Screen.height) : 1080f); float num2 = 544f; EnsureLayout(num2, num); MaintainCursorForPrompt(); int depth = GUI.depth; GUI.depth = 10000; GUI.Box(new Rect(0f, 0f, (float)Screen.width, num), EmptyContent, _overlayStyle); float num3 = ((float)Screen.width - 580f) * 0.5f; float num4 = (num - _windowHeight) * 0.5f; Rect val = default(Rect); ((Rect)(ref val))..ctor(num3, num4, 580f, _windowHeight); GUI.Box(val, EmptyContent, _panelStyle); float num5 = ((Rect)(ref val)).x + 18f; float num6 = ((Rect)(ref val)).y + 18f; GUI.Label(new Rect(num5, num6, num2, 30f), "DREAD", _brandStyle); num6 += 32f; GUI.Label(new Rect(num5, num6, num2, 20f), "elytraking-Dread · atmospheric horror mod for R.E.P.O.", _subtitleStyle); num6 += 22f; GUI.Label(new Rect(num5, num6, num2, 36f), "This mod (not the base game) is asking permission before it may send anonymous error reports.", _askStyle); num6 += 40f; GUI.Label(new Rect(num5, num6, num2, 22f), "Error reporting", _sectionStyle); num6 += 26f; GUI.Label(new Rect(num5, num6, num2, _summaryHeight), "Anonymous error reporting (on by default for new installs). When enabled, serious Unity errors may be sent to the developer to fix bugs.", _bodyStyle); num6 += _summaryHeight + 10f; Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(num5, num6, num2, _scrollViewHeight); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(0f, 0f, num2 - 22f, _scrollContentHeight); _scrollPosition = GUI.BeginScrollView(val2, _scrollPosition, val3); float num7 = 0f; string[] dataBullets = ErrorReportingPrivacyCopy.DataBullets; for (int i = 0; i < dataBullets.Length; i++) { float num8 = _bulletHeights[i]; GUI.Label(new Rect(0f, num7, ((Rect)(ref val3)).width, num8 - 6f), "• " + dataBullets[i], _bodyStyle); num7 += num8; } GUI.EndScrollView(); num6 += _scrollViewHeight + 10f; GUI.Label(new Rect(num5, num6, num2, _hintHeight), "To disable: set ErrorReportingEnabled = false in BepInEx/config/elytraking.dread.cfg (section 7. Error Reporting in elytraking.dread.cfg). REPOConfig lists the toggle only (no per-toggle description API); use the cfg file or Configuration Manager (F1) for full text.", _hintStyle); num6 += _hintHeight + 12f; float num9 = (num2 - 10f) * 0.5f; if (GUI.Button(new Rect(num5, num6, num9, 36f), "Keep reporting on", _buttonPrimaryStyle)) { OnPromptChoice(keepReporting: true); } if (GUI.Button(new Rect(num5 + num9 + 10f, num6, num9, 36f), "Turn off reporting", _buttonStyle)) { OnPromptChoice(keepReporting: false); } GUI.depth = depth; } } private void EnsureLayout(float innerW, float screenH) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Expected O, but got Unknown //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown if (!_layoutReady) { _summaryHeight = _bodyStyle.CalcHeight(new GUIContent("Anonymous error reporting (on by default for new installs). When enabled, serious Unity errors may be sent to the developer to fix bugs."), innerW); _hintHeight = _hintStyle.CalcHeight(new GUIContent("To disable: set ErrorReportingEnabled = false in BepInEx/config/elytraking.dread.cfg (section 7. Error Reporting in elytraking.dread.cfg). REPOConfig lists the toggle only (no per-toggle description API); use the cfg file or Configuration Manager (F1) for full text."), innerW); float num = innerW - 22f; string[] dataBullets = ErrorReportingPrivacyCopy.DataBullets; _bulletHeights = new float[dataBullets.Length]; _scrollContentHeight = 4f; for (int i = 0; i < dataBullets.Length; i++) { float num2 = _bodyStyle.CalcHeight(new GUIContent("• " + dataBullets[i]), num); _bulletHeights[i] = Mathf.Max(num2, 22f) + 6f; _scrollContentHeight += _bulletHeights[i]; } float num3 = screenH * 0.38f; _scrollViewHeight = Mathf.Min(_scrollContentHeight, num3); _windowHeight = Mathf.Min(screenH * 0.92f, 156f + _summaryHeight + 10f + _scrollViewHeight + 10f + _hintHeight + 66f); _windowHeight = Mathf.Max(_windowHeight, 500f); _layoutReady = true; } } private void MaintainCursorForPrompt() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (!_cursorCaptured) { _savedLockState = Cursor.lockState; _savedCursorVisible = Cursor.visible; _cursorCaptured = true; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } private void ReleasePromptCapture() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) if (_cursorCaptured) { Cursor.lockState = _savedLockState; Cursor.visible = _savedCursorVisible; _cursorCaptured = false; } if (_inputLocked) { UnlockLocalPlayerInput(); _inputLocked = false; } } private static void LockLocalPlayerInput() { PlayerController instance = PlayerController.instance; if (instance != null) { SetPlayerInputLocked(instance, locked: true); } } private static void UnlockLocalPlayerInput() { PlayerController instance = PlayerController.instance; if (instance != null) { SetPlayerInputLocked(instance, locked: false); } } private static void SetPlayerInputLocked(PlayerController pc, bool locked) { bool flag = false; try { Traverse.Create((object)pc).Field("inputLocked").Value = locked; flag = true; } catch { } try { Traverse.Create((object)pc).Field("interactDisabled").Value = locked; flag = true; } catch { } try { Traverse.Create((object)pc).Field("InputLocked").Value = locked; flag = true; } catch { } try { Traverse.Create((object)pc).Field("InteractDisabled").Value = locked; flag = true; } catch { } if (!flag) { LoggingService.LogVerbose("[Dread] Error reporting prompt: could not lock PlayerController input fields"); } } private void EnsureStyles() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Expected O, but got Unknown //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Expected O, but got Unknown //IL_020b: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) if (_panelStyle == null) { _overlayTex = MakeTexture(ColOverlay); _panelTex = MakeTexture(ColPanel); _buttonTex = MakeTexture(ColButton); _buttonHoverTex = MakeTexture(ColButtonHover); _buttonPrimaryTex = MakeTexture(ColButtonPrimary); _buttonPrimaryHoverTex = MakeTexture(ColButtonPrimaryHover); _overlayStyle = new GUIStyle(GUI.skin.box); _overlayStyle.normal.background = _overlayTex; _panelStyle = new GUIStyle(GUI.skin.box); _panelStyle.normal.background = _panelTex; _brandStyle = new GUIStyle(GUI.skin.label) { fontSize = 22, wordWrap = false }; _brandStyle.normal.textColor = ColAccent; _subtitleStyle = new GUIStyle(GUI.skin.label) { fontSize = 12, wordWrap = true }; _subtitleStyle.normal.textColor = ColDim; _askStyle = new GUIStyle(GUI.skin.label) { fontSize = 12, wordWrap = true }; _askStyle.normal.textColor = ColBody; _sectionStyle = new GUIStyle(GUI.skin.label) { fontSize = 15, wordWrap = false }; _sectionStyle.normal.textColor = ColAccent; _bodyStyle = new GUIStyle(GUI.skin.label) { fontSize = 13, wordWrap = true }; _bodyStyle.normal.textColor = ColBody; _hintStyle = new GUIStyle(GUI.skin.label) { fontSize = 11, wordWrap = true }; _hintStyle.normal.textColor = ColDim; _buttonStyle = BuildButtonStyle(_buttonTex, _buttonHoverTex, ColBody); _buttonPrimaryStyle = BuildButtonStyle(_buttonPrimaryTex, _buttonPrimaryHoverTex, ColAccent); } } private static GUIStyle BuildButtonStyle(Texture2D normal, Texture2D hover, Color textColor) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.button) { fontSize = 13 }; val.normal.background = normal; val.hover.background = hover; val.active.background = hover; val.normal.textColor = textColor; val.hover.textColor = textColor; val.active.textColor = textColor; return val; } private static Texture2D MakeTexture(Color color) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1); val.SetPixel(0, 0, color); val.Apply(); return val; } private void OnPromptChoice(bool keepReporting) { DreadConfig.ErrorReportingEnabled.Value = keepReporting; DreadConfig.ErrorReportingPromptShown.Value = true; DreadConfig.SaveToDisk(); _state = PromptState.Dismissed; ReleasePromptCapture(); if (keepReporting) { LoggingService.LogInfo("[Dread] Error reporting enabled. Anonymous error reporting (on by default for new installs). When enabled, serious Unity errors may be sent to the developer to fix bugs. To disable: set ErrorReportingEnabled = false in BepInEx/config/elytraking.dread.cfg (section 7. Error Reporting in elytraking.dread.cfg). REPOConfig lists the toggle only (no per-toggle description API); use the cfg file or Configuration Manager (F1) for full text."); } else { LoggingService.LogInfo("[Dread] Anonymous error reporting turned off."); } } } internal static class ErrorReportLogQueue { internal sealed class RawLogEntry { public string Message = string.Empty; public string StackTrace = string.Empty; public LogType Type; } internal const int MaxPendingLogs = 100; internal const int MaxProcessPerFrame = 3; private const float DedupeCooldownSeconds = 60f; private const int HashPrefixLength = 16; private static readonly Queue PendingLogs = new Queue(32); private static readonly object LogsLock = new object(); private static readonly Dictionary RecentHashes = new Dictionary(); internal static void EnqueueLog(string logString, string stackTrace, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) if (((int)type != 4 && (int)type != 0) || !ErrorReportingConsent.IsReportingAllowed() || IsIgnoredSpam(logString, stackTrace)) { return; } string key = ComputeHash(stackTrace, logString); float realtimeSinceStartup = Time.realtimeSinceStartup; lock (LogsLock) { if (!RecentHashes.TryGetValue(key, out var value) || !(realtimeSinceStartup - value < 60f)) { RecentHashes[key] = realtimeSinceStartup; if (PendingLogs.Count < 100) { PendingLogs.Enqueue(new RawLogEntry { Message = logString, StackTrace = stackTrace, Type = type }); } } } } internal static bool TryDequeueBatch(out RawLogEntry[] batch) { lock (LogsLock) { if (PendingLogs.Count == 0) { batch = Array.Empty(); return false; } int num = Math.Min(3, PendingLogs.Count); batch = new RawLogEntry[num]; for (int i = 0; i < num; i++) { batch[i] = PendingLogs.Dequeue(); } return true; } } internal static bool IsIgnoredSpam(string message, string stackTrace) { if (message.IndexOf("[Dread TestCrash]", StringComparison.Ordinal) >= 0 || stackTrace.IndexOf("TestCrashSystem", StringComparison.Ordinal) >= 0) { return true; } if (message.IndexOf("DebugConsoleUI", StringComparison.Ordinal) >= 0 || stackTrace.IndexOf("DebugConsoleUI", StringComparison.Ordinal) >= 0) { return true; } if (message.IndexOf("DebugTester", StringComparison.Ordinal) >= 0 || stackTrace.IndexOf("SemiFunc.DebugTester", StringComparison.Ordinal) >= 0 || stackTrace.IndexOf("DebugTester", StringComparison.Ordinal) >= 0) { return true; } return false; } internal static string ComputeHash(string stackTrace, string message) { using SHA256 sHA = SHA256.Create(); string s = stackTrace + "\n" + message; byte[] array = sHA.ComputeHash(Encoding.UTF8.GetBytes(s)); StringBuilder stringBuilder = new StringBuilder(); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("x2")); } return stringBuilder.ToString().Substring(0, 16); } } internal static class ErrorReportPayloadCapture { internal const int MaxStackTraceLength = 3000; internal const int MaxMessageLength = 500; private const float ProximityRange = 15f; private const int PlayerMaxHp = 100; internal static string ParseExceptionType(string logString) { int num = logString.IndexOf(':'); if (num <= 0) { return "Unknown"; } return logString.Substring(0, num); } internal static ErrorReport BuildTestCrashReport(Exception ex, string message, string stack, string scene) { return new ErrorReport { Hash = ErrorReportLogQueue.ComputeHash(stack, message + "|testcrash|" + DateTime.UtcNow.Ticks), Timestamp = DateTime.UtcNow.ToString("o"), Type = "exception", ExceptionType = ex.GetType().Name, Message = Truncate(message, 500), StackTrace = Truncate(stack, 3000), Scene = scene, GameState = CreateMinimalGameState(scene), SystemInfo = CaptureSystemInfoSafe(), Display = CaptureDisplayInfoSafe(), Config = CaptureConfigSafe() }; } internal static SystemInfoData CaptureSystemInfoSafe() { SystemInfoData info = new SystemInfoData(); TrySet(delegate { info.Os = SystemInfo.operatingSystem; }); TrySet(delegate { info.OsFamily = SystemInfo.operatingSystemFamily.ToString(); }); TrySet(delegate { info.Cpu = SystemInfo.processorType; }); TrySet(delegate { info.CpuCores = SystemInfo.processorCount; }); TrySet(delegate { info.CpuFrequencyMHz = SystemInfo.processorFrequency; }); TrySet(delegate { info.MemoryMB = SystemInfo.systemMemorySize; }); TrySet(delegate { info.Gpu = SystemInfo.graphicsDeviceName; }); TrySet(delegate { info.GpuVendor = SystemInfo.graphicsDeviceVendor; }); TrySet(delegate { info.GpuDriverVersion = SystemInfo.graphicsDeviceVersion; }); TrySet(delegate { info.GpuShaderLevel = SystemInfo.graphicsShaderLevel; }); TrySet(delegate { info.VramMB = SystemInfo.graphicsMemorySize; }); TrySet(delegate { info.DeviceType = SystemInfo.deviceType.ToString(); }); TrySet(delegate { info.DeviceModel = SystemInfo.deviceModel; }); return info; } internal static DisplayInfoData CaptureDisplayInfoSafe() { DisplayInfoData display = new DisplayInfoData(); TrySet(delegate { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) Resolution currentResolution = Screen.currentResolution; display.Width = currentResolution.width; display.Height = currentResolution.height; display.RefreshRate = currentResolution.refreshRate; }); TrySet(delegate { display.Dpi = Screen.dpi; }); TrySet(delegate { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) DisplayInfoData displayInfoData = display; FullScreenMode fullScreenMode = Screen.fullScreenMode; displayInfoData.FullScreenMode = ((object)(FullScreenMode)(ref fullScreenMode)).ToString(); }); return display; } internal static ConfigData CaptureConfigSafe() { ConfigData config = new ConfigData(); TrySet(delegate { config.AudioEnabled = DreadConfig.AudioEnabled.Value; }); TrySet(delegate { config.AudioFrequency = DreadConfig.AudioFrequency.Value; }); TrySet(delegate { config.AudioVolume = DreadConfig.AudioVolume.Value; }); TrySet(delegate { config.AggressionEnabled = DreadConfig.MonsterAggressionEnabled.Value; }); TrySet(delegate { config.AggressionAudioEnabled = DreadConfig.MonsterAudioEnabled.Value; }); TrySet(delegate { config.FakeFootsteps = DreadConfig.FakeFootstepsEnabled.Value; }); TrySet(delegate { config.Adrenaline = DreadConfig.AdrenalineEnabled.Value; }); TrySet(delegate { config.LowStaminaSound = DreadConfig.LowStaminaSoundEnabled.Value; }); TrySet(delegate { config.PanicSprint = DreadConfig.PanicSprintEnabled.Value; }); TrySet(delegate { config.CrouchSpeedBoost = DreadConfig.CrouchSpeedBoostEnabled.Value; }); TrySet(delegate { config.ErrorReportingEnabled = DreadConfig.ErrorReportingEnabled.Value; }); return config; } internal static ConfigData CaptureConfig() { return CaptureConfigSafe(); } internal static GameStateData CreateMinimalGameState(string scene) { return new GameStateData { SceneName = scene, PlayTimeSeconds = (int)Time.realtimeSinceStartup }; } internal static GameStateData CaptureGameState() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) GameStateData gameStateData = new GameStateData(); Scene activeScene = SceneManager.GetActiveScene(); gameStateData.SceneName = ((Scene)(ref activeScene)).name ?? "unknown"; GameStateData gameStateData2 = gameStateData; try { EnemyHealth[] array = Object.FindObjectsOfType(); gameStateData2.EnemiesTotal = array.Length; int num = 0; int num2 = 0; PlayerController val = null; try { val = Object.FindObjectOfType(); } catch { } EnemyHealth[] array2 = array; foreach (EnemyHealth val2 in array2) { try { if (val2.CurrentHealth > 0) { num++; } if (val != null && Vector3.Distance(((Component)val2).transform.position, ((Component)val).transform.position) < 15f) { num2++; } } catch { } } gameStateData2.EnemiesAlive = num; gameStateData2.EnemiesNearby = num2; if (val != null) { try { gameStateData2.PlayerHp = (int)(val.Health * 100f); gameStateData2.PlayerMaxHp = 100; gameStateData2.PlayerStamina = (int)(val.stamina * 100f); gameStateData2.PlayerPosition = ((Component)val).transform.position; } catch { } } } catch { LoggingService.LogWarning("Failed to capture game state for error report"); } gameStateData2.PlayTimeSeconds = (int)Time.realtimeSinceStartup; return gameStateData2; } internal static string Truncate(string value, int maxLength) { if (value == null || value.Length <= maxLength) { return value; } return value.Substring(0, maxLength); } private static void TrySet(Action setter) { try { setter(); } catch { } } } internal static class ErrorReportUploader { internal const string WorkerUrl = "https://dread-error-reporter.nox-heights.workers.dev/api/report"; internal const int MaxBatchSize = 50; internal static bool TryPostPayloadSync(ErrorPayload payload, out string responseBody, out string error) { responseBody = string.Empty; error = string.Empty; try { string text = ErrorReportJson.SerializePayload(payload); if (string.IsNullOrEmpty(text) || text.IndexOf("\"Reports\":[", StringComparison.Ordinal) < 0) { error = $"JSON serializer produced invalid payload (length={text?.Length ?? 0})"; return false; } HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("https://dread-error-reporter.nox-heights.workers.dev/api/report"); httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "application/json"; httpWebRequest.Timeout = 15000; byte[] bytes = Encoding.UTF8.GetBytes(text); httpWebRequest.ContentLength = bytes.Length; using (Stream stream = httpWebRequest.GetRequestStream()) { stream.Write(bytes, 0, bytes.Length); } using HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); using StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream() ?? Stream.Null); responseBody = streamReader.ReadToEnd(); return httpWebResponse.StatusCode == HttpStatusCode.OK; } catch (WebException ex) { if (ex.Response is HttpWebResponse httpWebResponse2) { using StreamReader streamReader2 = new StreamReader(httpWebResponse2.GetResponseStream() ?? Stream.Null); responseBody = streamReader2.ReadToEnd(); error = $"HTTP {(int)httpWebResponse2.StatusCode}: {responseBody}"; } else { error = ex.Message; } return false; } catch (Exception ex2) { error = ex2.Message; return false; } } internal static List CollectFailedReports(string body, List batch) { List list = new List(); foreach (ErrorReport item in batch) { if (IsReportFailedInResponse(body, item.Hash)) { list.Add(item); } } return list; } internal static bool HasWorkerReportFailures(string body, ErrorReport[] reports) { if (string.IsNullOrEmpty(body)) { return false; } foreach (ErrorReport errorReport in reports) { if (errorReport != null && IsReportFailedInResponse(body, errorReport.Hash)) { return true; } } return HasUnmappedWorkerErrors(body); } internal static bool HasUnmappedWorkerErrors(string body) { if (body.IndexOf("\"status\":\"error\"", StringComparison.Ordinal) < 0) { return body.IndexOf("\"status\": \"error\"", StringComparison.Ordinal) >= 0; } return true; } internal static bool IsReportFailedInResponse(string body, string hash) { if (string.IsNullOrEmpty(body) || string.IsNullOrEmpty(hash)) { return false; } string text = "\"hash\":\"" + hash + "\""; int startIndex = 0; while ((startIndex = body.IndexOf(text, startIndex, StringComparison.Ordinal)) >= 0) { int num = Math.Min(body.Length, startIndex + 256); string text2 = body.Substring(startIndex, num - startIndex); if (text2.IndexOf("\"status\":\"error\"", StringComparison.Ordinal) >= 0 || text2.IndexOf("\"status\": \"error\"", StringComparison.Ordinal) >= 0) { return true; } startIndex += text.Length; } return false; } internal static string? ValidateBatchJson(string json) { if (json.IndexOf("\"Reports\":[", StringComparison.Ordinal) < 0) { return $"JSON missing Reports (len={json.Length}); re-queuing batch."; } return null; } internal static byte[] EncodePayload(ErrorPayload payload, out string json) { json = ErrorReportJson.SerializePayload(payload); return Encoding.UTF8.GetBytes(json); } } internal static class ErrorReportJson { public static string SerializePayload(ErrorPayload payload) { StringBuilder stringBuilder = new StringBuilder(2048); stringBuilder.Append('{'); AppendStringField(stringBuilder, "ModVersion", payload.ModVersion, first: true); AppendStringField(stringBuilder, "GameVersion", payload.GameVersion); AppendStringField(stringBuilder, "UnityVersion", payload.UnityVersion); stringBuilder.Append(",\"Reports\":["); ErrorReport[] reports = payload.Reports; if (reports != null) { for (int i = 0; i < reports.Length; i++) { if (i > 0) { stringBuilder.Append(','); } AppendReport(stringBuilder, reports[i]); } } stringBuilder.Append("]}"); return stringBuilder.ToString(); } private static void AppendReport(StringBuilder sb, ErrorReport? report) { if (report == null) { report = new ErrorReport(); } sb.Append('{'); AppendStringField(sb, "Hash", report.Hash, first: true); AppendStringField(sb, "Timestamp", report.Timestamp); AppendStringField(sb, "Type", report.Type); AppendStringField(sb, "ExceptionType", report.ExceptionType); AppendStringField(sb, "Message", report.Message); AppendStringField(sb, "StackTrace", report.StackTrace); AppendStringField(sb, "Scene", report.Scene); sb.Append(",\"GameState\":"); AppendGameState(sb, report.GameState); sb.Append(",\"SystemInfo\":"); AppendSystemInfo(sb, report.SystemInfo); sb.Append(",\"Display\":"); AppendDisplay(sb, report.Display); sb.Append(",\"Config\":"); AppendConfig(sb, report.Config); sb.Append('}'); } private static void AppendGameState(StringBuilder sb, GameStateData state) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) if (state == null) { state = new GameStateData(); } sb.Append('{'); AppendStringField(sb, "SceneName", state.SceneName, first: true); AppendIntField(sb, "EnemiesAlive", state.EnemiesAlive); AppendIntField(sb, "EnemiesTotal", state.EnemiesTotal); AppendIntField(sb, "EnemiesNearby", state.EnemiesNearby); AppendIntField(sb, "PlayerHp", state.PlayerHp); AppendIntField(sb, "PlayerMaxHp", state.PlayerMaxHp); AppendIntField(sb, "PlayerStamina", state.PlayerStamina); sb.Append(",\"PlayerPosition\":"); AppendVector3(sb, state.PlayerPosition); AppendIntField(sb, "PlayTimeSeconds", state.PlayTimeSeconds); sb.Append('}'); } private static void AppendSystemInfo(StringBuilder sb, SystemInfoData info) { if (info == null) { info = new SystemInfoData(); } sb.Append('{'); AppendStringField(sb, "Os", info.Os, first: true); AppendStringField(sb, "OsFamily", info.OsFamily); AppendStringField(sb, "Cpu", info.Cpu); AppendIntField(sb, "CpuCores", info.CpuCores); AppendIntField(sb, "CpuFrequencyMHz", info.CpuFrequencyMHz); AppendIntField(sb, "MemoryMB", info.MemoryMB); AppendStringField(sb, "Gpu", info.Gpu); AppendStringField(sb, "GpuVendor", info.GpuVendor); AppendStringField(sb, "GpuDriverVersion", info.GpuDriverVersion); AppendIntField(sb, "GpuShaderLevel", info.GpuShaderLevel); AppendIntField(sb, "VramMB", info.VramMB); AppendStringField(sb, "DeviceType", info.DeviceType); AppendStringField(sb, "DeviceModel", info.DeviceModel); sb.Append('}'); } private static void AppendDisplay(StringBuilder sb, DisplayInfoData display) { if (display == null) { display = new DisplayInfoData(); } sb.Append('{'); AppendIntField(sb, "Width", display.Width, first: true); AppendIntField(sb, "Height", display.Height); AppendIntField(sb, "RefreshRate", display.RefreshRate); AppendFloatField(sb, "Dpi", display.Dpi); AppendStringField(sb, "FullScreenMode", display.FullScreenMode); sb.Append('}'); } private static void AppendConfig(StringBuilder sb, ConfigData config) { if (config == null) { config = new ConfigData(); } sb.Append('{'); AppendBoolField(sb, "AudioEnabled", config.AudioEnabled, first: true); AppendFloatField(sb, "AudioFrequency", config.AudioFrequency); AppendFloatField(sb, "AudioVolume", config.AudioVolume); AppendBoolField(sb, "AggressionEnabled", config.AggressionEnabled); AppendBoolField(sb, "AggressionAudioEnabled", config.AggressionAudioEnabled); AppendBoolField(sb, "FakeFootsteps", config.FakeFootsteps); AppendBoolField(sb, "Adrenaline", config.Adrenaline); AppendBoolField(sb, "LowStaminaSound", config.LowStaminaSound); AppendBoolField(sb, "PanicSprint", config.PanicSprint); AppendBoolField(sb, "CrouchSpeedBoost", config.CrouchSpeedBoost); AppendBoolField(sb, "ErrorReportingEnabled", config.ErrorReportingEnabled); sb.Append('}'); } private static void AppendVector3(StringBuilder sb, Vector3 v) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) sb.Append('{'); AppendFloatField(sb, "x", v.x, first: true); AppendFloatField(sb, "y", v.y); AppendFloatField(sb, "z", v.z); sb.Append('}'); } private static void AppendStringField(StringBuilder sb, string name, string? value, bool first = false) { if (!first) { sb.Append(','); } sb.Append('"').Append(name).Append("\":"); AppendEscapedString(sb, value ?? string.Empty); } private static void AppendIntField(StringBuilder sb, string name, int value, bool first = false) { if (!first) { sb.Append(','); } sb.Append('"').Append(name).Append("\":") .Append(value.ToString(CultureInfo.InvariantCulture)); } private static void AppendFloatField(StringBuilder sb, string name, float value, bool first = false) { if (!first) { sb.Append(','); } sb.Append('"').Append(name).Append("\":") .Append(value.ToString(CultureInfo.InvariantCulture)); } private static void AppendBoolField(StringBuilder sb, string name, bool value, bool first = false) { if (!first) { sb.Append(','); } sb.Append('"').Append(name).Append("\":") .Append(value ? "true" : "false"); } private static void AppendEscapedString(StringBuilder sb, string value) { sb.Append('"'); foreach (char c in value) { switch (c) { case '"': sb.Append("\\\""); continue; case '\\': sb.Append("\\\\"); continue; case '\n': sb.Append("\\n"); continue; case '\r': sb.Append("\\r"); continue; case '\t': sb.Append("\\t"); continue; } if (c < ' ') { StringBuilder stringBuilder = sb.Append("\\u"); int num = c; stringBuilder.Append(num.ToString("x4")); } else { sb.Append(c); } } sb.Append('"'); } } [Serializable] internal class ErrorPayload { public string ModVersion = string.Empty; public string GameVersion = string.Empty; public string UnityVersion = string.Empty; public ErrorReport[] Reports = Array.Empty(); } [Serializable] internal class ErrorReport { public string Hash = string.Empty; public string Timestamp = string.Empty; public string Type = string.Empty; public string ExceptionType = string.Empty; public string Message = string.Empty; public string StackTrace = string.Empty; public string Scene = string.Empty; public GameStateData GameState = new GameStateData(); public SystemInfoData SystemInfo = new SystemInfoData(); public DisplayInfoData Display = new DisplayInfoData(); public ConfigData Config = new ConfigData(); } [Serializable] internal class GameStateData { public string SceneName = string.Empty; public int EnemiesAlive; public int EnemiesTotal; public int EnemiesNearby; public int PlayerHp; public int PlayerMaxHp; public int PlayerStamina; public Vector3 PlayerPosition; public int PlayTimeSeconds; } [Serializable] internal class SystemInfoData { public string Os = string.Empty; public string OsFamily = string.Empty; public string Cpu = string.Empty; public int CpuCores; public int CpuFrequencyMHz; public int MemoryMB; public string Gpu = string.Empty; public string GpuVendor = string.Empty; public string GpuDriverVersion = string.Empty; public int GpuShaderLevel; public int VramMB; public string DeviceType = string.Empty; public string DeviceModel = string.Empty; } [Serializable] internal class DisplayInfoData { public int Width; public int Height; public int RefreshRate; public float Dpi; public string FullScreenMode = string.Empty; } [Serializable] internal class ConfigData { public bool AudioEnabled; public float AudioFrequency; public float AudioVolume; public bool AggressionEnabled; public bool AggressionAudioEnabled; public bool FakeFootsteps; public bool Adrenaline; public bool LowStaminaSound; public bool PanicSprint; public bool CrouchSpeedBoost; public bool ErrorReportingEnabled; } public class FlashlightStateTracker : MonoBehaviour { public Light? Flashlight; } internal static class HarmonyPatchCompat { private static readonly HashSet SkipWarningsLogged = new HashSet(StringComparer.Ordinal); private static readonly MethodInfo? IsMasterClientMethod = AccessTools.Method(typeof(SemiFunc), "IsMasterClient", (Type[])null, (Type[])null); internal static bool IsMasterClient() { try { if (IsMasterClientMethod == null) { return true; } object obj = IsMasterClientMethod.Invoke(null, null); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } catch { return true; } } internal static bool ShouldSkipDueToForeignPatches(MethodBase method, string patchLabel) { if (!DreadConfig.CompatibilitySkipConflictingPatches.Value) { return false; } Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInfo == null) { return false; } if (!HasForeignOwners(patchInfo)) { return false; } if (SkipWarningsLogged.Add(patchLabel)) { LoggingService.LogWarning("[Dread] Skipping " + patchLabel + ": target already patched by another mod (CompatibilitySkipConflictingPatches=true)"); } return true; } private static bool HasForeignOwners(Patches info) { foreach (Patch prefix in info.Prefixes) { if (!IsDreadOwner(prefix.owner)) { return true; } } foreach (Patch postfix in info.Postfixes) { if (!IsDreadOwner(postfix.owner)) { return true; } } foreach (Patch transpiler in info.Transpilers) { if (!IsDreadOwner(transpiler.owner)) { return true; } } foreach (Patch finalizer in info.Finalizers) { if (!IsDreadOwner(finalizer.owner)) { return true; } } return false; } private static bool IsDreadOwner(string owner) { return string.Equals(owner, "elytraking.dread", StringComparison.Ordinal); } } public enum LogLevel { None, Error, Debug, Verbose } public static class LoggingService { private static LogLevel _current = LogLevel.Debug; private static readonly string[] AsciiArtLines = new string[28] { " ███ ███ ███ ███ ", " ███░ ███░ ███░ ███░ ", " ███░ ███░ ███░ ███░ ", " ███░ ███░ ███░ ███░ ", " ███░ ███░ ███░ ███░ ", "██░ ███░ ███░ ███░ ", "░ ███░ ███░ ███░ █", " ░░░ ░░░ ░░░ ░░", " ███ ███ ███ ███ ", " ███@@@@@@@ @@@@@@@ @@@@@@@@ ██@@@@@@ @@@@@@@█░ ", " ███░ @@@@@@@@ @@@@@@@@ @@@@@@@@██@@@@@@@@ @@@@@@@@ ", "██░ @@! @@@ █@@! @@@ @@! ███░ @@! @@@ @@! @@@ ", "░ !@! @!@██!@! @!@ !@!███░ !@! @!@ █!@! @!@ █", " @!@ !@!░ @!@!!@! @!!!:! @!@!@!@!██@!@ !@! ███", " !@! !!! !!@!@! █!!!!!: !!!@!!!!░ !@! !!! ███░ ", " !!: !!! !!: :!! ░░!!: !!: ░!!! !!: !!! ░░░ ", " ███ :!: !:! :!:█ !:! :!: ███:!: !:! :!: !:! ", "██░ :::: :: █::░ ::: :: ::::░ :: ::: :::: :: ", "░ :: : :███░: : : : ::█:: : : : █::░: : █", " ███░ ███░ ███░ ███", " ███░ ███░ ███░ ███░ ", " ███░ ███░ ███░ ███░ ", " ███░ ███░ ███░ ███░ ", " ░░░ ░░░ ░░░ ░░░ ", " ███ ███ ███ █", " ███░ ███░ ███░ ███", " ███░ ███░ ███░ ███░ ", " ███░ ███░ ███░ ███░ " }; public static LogLevel CurrentLevel => _current; public static void Initialize(LogLevel level) { _current = level; } public static void SetLevel(LogLevel level) { _current = level; } public static void LogError(string message) { if (_current >= LogLevel.Error) { Plugin.Logger.LogError((object)message); } } public static void LogWarning(string message) { if (_current >= LogLevel.Debug) { Plugin.Logger.LogWarning((object)message); } } public static void LogInfo(string message) { if (_current >= LogLevel.Debug) { Plugin.Logger.LogInfo((object)message); } } public static void LogDebug(string message) { if (_current >= LogLevel.Debug) { Plugin.Logger.LogDebug((object)message); } } public static void LogVerbose(string message) { if (_current >= LogLevel.Verbose) { Plugin.Logger.LogInfo((object)("[V] " + message)); } } public static void PrintAsciiArt() { StringBuilder stringBuilder = new StringBuilder(); string[] asciiArtLines = AsciiArtLines; foreach (string value in asciiArtLines) { stringBuilder.AppendLine(value); } Plugin.Logger.LogInfo((object)stringBuilder.ToString()); } } public class MonsterOverhaulSystem : MonoBehaviour { [CompilerGenerated] private sealed class d__4 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public MonsterOverhaulSystem <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__4(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected O, but got Unknown int num = <>1__state; MonsterOverhaulSystem monsterOverhaulSystem = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; if (DreadConfig.MonsterAudioEnabled.Value && monsterOverhaulSystem._inLevel && !SemiFunc.MenuLevel()) { EnemyHealth[] array = Object.FindObjectsOfType(); LoggingService.LogVerbose($"[MonsterOverhaul] Processing {array.Length} enemies..."); EnemyHealth[] array2 = array; foreach (EnemyHealth val in array2) { if (val != null && ((Component)val).GetComponent() == null) { ((Component)val).gameObject.AddComponent(); ApplyAudioTweaks(((Component)val).gameObject); } } } } else { <>1__state = -1; } <>2__current = (object)new WaitForSeconds(4f); <>1__state = 1; return true; } 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 bool _inLevel; private void Start() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) LoggingService.LogVerbose("[MonsterOverhaul] Awake starting..."); SceneManager.sceneLoaded += OnSceneLoaded; Scene activeScene = SceneManager.GetActiveScene(); string name = ((Scene)(ref activeScene)).name; _inLevel = !name.Contains("Menu") && !name.Contains("Main"); ((MonoBehaviour)this).StartCoroutine(MonsterAudioLoop()); } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); SceneManager.sceneLoaded -= OnSceneLoaded; } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _inLevel = !((Scene)(ref scene)).name.Contains("Menu") && !((Scene)(ref scene)).name.Contains("Main"); } [IteratorStateMachine(typeof(d__4))] private IEnumerator MonsterAudioLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__4(0) { <>4__this = this }; } private static bool IsSourcePlaying(AudioSource src) { try { PropertyInfo property = typeof(AudioSource).GetProperty("isPlaying"); return property != null && (bool)property.GetValue(src); } catch { return false; } } private static void ApplyAudioTweaks(GameObject enemy) { AudioSource[] componentsInChildren = enemy.GetComponentsInChildren(); foreach (AudioSource val in componentsInChildren) { if (val != null && !IsSourcePlaying(val)) { val.pitch = Random.Range(0.85f, 1.15f); val.spatialBlend = 1f; } } } } internal class DreadAudioTweaked : MonoBehaviour { } internal static class OverlayTextureUtil { public static Texture2D? CreateSolid(Color color) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) string[] array = new string[5] { "ARGB32", "RGBA32", "RGB24", "Alpha8", "RGBA4444" }; foreach (string formatName in array) { Texture2D val = TryCreateFilled(2, 2, formatName, (int _, int _) => color); if (val != null) { return val; } } return null; } public static Texture2D? CreateVignette(int size) { string[] array = new string[5] { "ARGB32", "RGBA32", "RGB24", "Alpha8", "RGBA4444" }; foreach (string formatName in array) { Texture2D val = TryCreateFilled(size, size, formatName, delegate(int x, int y) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) float num = (float)x / (float)(size - 1) - 0.5f; float num2 = (float)y / (float)(size - 1) - 0.5f; float num3 = Mathf.Clamp01((Mathf.Sqrt(num * num + num2 * num2) * 2f - 0.3f) / 0.7f); return new Color(0f, 0f, 0f, num3); }); if (val != null) { return val; } } return null; } private static Texture2D? TryCreateFilled(int width, int height, string formatName, Func pixel) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) try { TextureFormat val = (TextureFormat)Enum.Parse(typeof(TextureFormat), formatName); if (!IsFormatUsable(val)) { return null; } Texture2D val2 = new Texture2D(width, height, val, false); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { val2.SetPixel(i, j, pixel(i, j)); } } val2.Apply(); return val2; } catch { return null; } } private static bool IsFormatUsable(TextureFormat format) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) try { MethodInfo method = typeof(SystemInfo).GetMethod("SupportsTextureFormat", new Type[1] { typeof(TextureFormat) }); if (method == null) { return true; } return (bool)method.Invoke(null, new object[1] { format }); } catch { return true; } } } internal static class DebugConsoleGuardPatch { private static MethodInfo? _original; private static bool _loggedSuppression; internal static void Apply(Harmony harmony) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown if (!(_original != null)) { Type type = AccessTools.TypeByName("DebugConsoleUI"); _original = ((type != null) ? AccessTools.Method(type, "Update", (Type[])null, (Type[])null) : null); if (_original == null) { LoggingService.LogVerbose("[Dread] DebugConsoleUI.Update not found; debug console guard skipped"); return; } harmony.Patch((MethodBase)_original, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DebugConsoleGuardPatch), "SuppressNullReference", (Type[])null), (HarmonyMethod)null); LoggingService.LogInfo("[Dread] Debug console NRE guard active"); } } internal static void Remove(Harmony harmony) { if (!(_original == null)) { harmony.Unpatch((MethodBase)_original, AccessTools.Method(typeof(DebugConsoleGuardPatch), "SuppressNullReference", (Type[])null, (Type[])null)); _original = null; } } private static Exception SuppressNullReference(Exception __exception) { if (!(__exception is NullReferenceException)) { return __exception; } if (!_loggedSuppression) { _loggedSuppression = true; LoggingService.LogVerbose("[Dread] Suppressed DebugConsoleUI NullReferenceException from broken debug hook"); } return null; } } internal static class EnemyDirectorSetInvestigatePatch { private static MethodInfo? _original; internal static void Apply(Harmony harmony) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown if (!(_original != null) && !DreadConfig.CompatibilityMode.Value) { _original = AccessTools.Method(typeof(EnemyDirector), "SetInvestigate", (Type[])null, (Type[])null); if (_original == null) { LoggingService.LogWarning("[Dread] EnemyDirector.SetInvestigate not found; investigate patch skipped"); } else if (!HarmonyPatchCompat.ShouldSkipDueToForeignPatches(_original, "EnemyDirector.SetInvestigate")) { HarmonyMethod val = new HarmonyMethod(typeof(EnemyDirectorSetInvestigatePatch), "Prefix", (Type[])null); harmony.Patch((MethodBase)_original, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } internal static void Remove(Harmony harmony) { if (!(_original == null)) { harmony.Unpatch((MethodBase)_original, AccessTools.Method(typeof(EnemyDirectorSetInvestigatePatch), "Prefix", (Type[])null, (Type[])null)); _original = null; } } [HarmonyPriority(800)] private static void Prefix(ref float radius) { if (DreadConfig.MonsterAggressionEnabled.Value && !DreadConfig.CompatibilityMode.Value && HarmonyPatchCompat.IsMasterClient() && radius < float.MaxValue) { radius *= 1.5f; } } } internal static class EnemyNavMeshAgentAwakePatch { private static MethodInfo? _original; internal static void Apply(Harmony harmony) { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown if (!(_original != null) && !DreadConfig.CompatibilityMode.Value) { _original = AccessTools.Method(typeof(EnemyNavMeshAgent), "Awake", (Type[])null, (Type[])null); if (_original == null) { LoggingService.LogWarning("[Dread] EnemyNavMeshAgent.Awake not found; aggression patch skipped"); } else if (!HarmonyPatchCompat.ShouldSkipDueToForeignPatches(_original, "EnemyNavMeshAgent.Awake")) { harmony.Patch((MethodBase)_original, (HarmonyMethod)null, new HarmonyMethod(typeof(EnemyNavMeshAgentAwakePatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } internal static void Remove(Harmony harmony) { if (!(_original == null)) { harmony.Unpatch((MethodBase)_original, AccessTools.Method(typeof(EnemyNavMeshAgentAwakePatch), "Postfix", (Type[])null, (Type[])null)); _original = null; } } [HarmonyPriority(0)] private static void Postfix(EnemyNavMeshAgent __instance) { if (!DreadConfig.MonsterAggressionEnabled.Value || DreadConfig.CompatibilityMode.Value || !HarmonyPatchCompat.IsMasterClient()) { return; } try { NavMeshAgent agent = __instance.Agent; if (agent != null) { agent.speed *= 1.2f; agent.acceleration *= 1.2f; } } catch (Exception ex) { LoggingService.LogVerbose("[Dread] EnemyNavMeshAgent patch skipped: " + ex.Message); } } } internal static class PlayerControllerAwakePatch { private static MethodInfo? _original; internal static void Apply(Harmony harmony) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown if (!(_original != null)) { _original = AccessTools.Method(typeof(PlayerController), "Awake", (Type[])null, (Type[])null); if (_original == null) { LoggingService.LogWarning("[Dread] PlayerController.Awake not found; crouch speed patch skipped"); } else { harmony.Patch((MethodBase)_original, (HarmonyMethod)null, new HarmonyMethod(typeof(PlayerControllerAwakePatch), "Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } } internal static void Remove(Harmony harmony) { if (!(_original == null)) { harmony.Unpatch((MethodBase)_original, AccessTools.Method(typeof(PlayerControllerAwakePatch), "Postfix", (Type[])null, (Type[])null)); _original = null; } } private static void Postfix(PlayerController __instance) { if (!DreadConfig.CrouchSpeedBoostEnabled.Value) { return; } try { __instance.CrouchSpeed *= 1.3f; } catch (Exception ex) { LoggingService.LogVerbose("[Dread] CrouchSpeedBoost patch skipped: " + ex.Message); } } } internal static class PlayerControllerCompat { private static readonly Dictionary CrouchBoolFieldsByType = new Dictionary(); private static readonly string[] CrouchMemberNames = new string[8] { "Crouching", "Crawling", "isCrouching", "isCrawling", "crouching", "crawling", "IsCrouching", "IsCrawling" }; public static float GetHealth(PlayerController pc) { if (pc == null) { return -1f; } try { return Traverse.Create((object)pc).Property("Health", (object[])null).Value; } catch { } try { return Traverse.Create((object)pc).Field("health").Value; } catch { } try { return Traverse.Create((object)pc).Field("Health").Value; } catch { } return -1f; } public static bool IsAlive(PlayerController pc) { float health = GetHealth(pc); if (!(health < 0f)) { return health > 0f; } return true; } public static float GetStamina(PlayerController pc) { if (pc == null) { return -1f; } string[] array = new string[5] { "EnergyCurrent", "stamina", "Stamina", "energy", "Energy" }; foreach (string text in array) { try { return Traverse.Create((object)pc).Field(text).Value; } catch { } try { return Traverse.Create((object)pc).Property(text, (object[])null).Value; } catch { } } return -1f; } public static bool IsCrouching(PlayerController pc) { if (pc == null) { return false; } if (TryReadCrouch(pc)) { return true; } try { object value = Traverse.Create((object)pc).Field("playerAvatarScript").GetValue(); if (value != null && TryReadCrouch(value)) { return true; } } catch { } return false; } public static bool IsHidingVulnerable(PlayerController pc) { if (!IsCrouching(pc)) { return PlayerTumbleCompat.IsInTumble(pc); } return true; } private static bool TryReadCrouch(object target) { string[] crouchMemberNames = CrouchMemberNames; foreach (string name in crouchMemberNames) { if (TryGetBoolMember(target, name, out var value) && value) { return true; } } FieldInfo[] crouchBoolFields = GetCrouchBoolFields(target.GetType()); foreach (FieldInfo fieldInfo in crouchBoolFields) { try { if ((bool)fieldInfo.GetValue(target)) { return true; } } catch { } } return false; } private static FieldInfo[] GetCrouchBoolFields(Type type) { lock (CrouchBoolFieldsByType) { if (CrouchBoolFieldsByType.TryGetValue(type, out FieldInfo[] value)) { return value; } List list = new List(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType != typeof(bool))) { string name = fieldInfo.Name; if (name.IndexOf("crouch", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("crawl", StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(fieldInfo); } } } FieldInfo[] array = list.ToArray(); CrouchBoolFieldsByType[type] = array; return array; } } private static bool TryGetBoolMember(object target, string name, out bool value) { value = false; try { value = Traverse.Create(target).Field(name).Value; return true; } catch { } try { value = Traverse.Create(target).Property(name, (object[])null).Value; return true; } catch { } return false; } } internal static class PlayerTumbleCompat { private static bool _forcedActive; private static readonly Dictionary TumbleBoolFieldsByType = new Dictionary(); private static readonly Dictionary AvatarTumbleFieldByType = new Dictionary(); private static readonly Dictionary TumbleSetMethodByType = new Dictionary(); private static readonly Dictionary TumbleRequestMethodByType = new Dictionary(); private static readonly string[] TumbleActiveMemberNames = new string[12] { "tumbling", "Tumbling", "isTumbling", "IsTumbling", "fallen", "Fallen", "isFallen", "IsFallen", "active", "Active", "isActive", "IsActive" }; public static bool IsInTumble(PlayerController pc) { object obj = ResolveTumble(pc); if (obj == null) { return false; } string[] tumbleActiveMemberNames = TumbleActiveMemberNames; foreach (string text in tumbleActiveMemberNames) { try { if (Traverse.Create(obj).Field(text).Value) { return true; } } catch { } try { if (Traverse.Create(obj).Property(text, (object[])null).Value) { return true; } } catch { } } FieldInfo[] tumbleBoolFields = GetTumbleBoolFields(obj.GetType()); foreach (FieldInfo fieldInfo in tumbleBoolFields) { try { if ((bool)fieldInfo.GetValue(obj)) { return true; } } catch { } } return false; } public static bool ApplyForcedTumble(PlayerController pc) { object obj = ResolveTumble(pc); if (obj == null) { return false; } if (!InvokeTumble(obj, active: true)) { return false; } _forcedActive = true; return true; } public static void MaintainForcedTumble(PlayerController pc) { if (_forcedActive && pc != null) { object obj = ResolveTumble(pc); if (obj != null) { InvokeTumble(obj, active: true); } } } public static void ReleaseForcedTumble(PlayerController? pc) { if (!_forcedActive) { return; } _forcedActive = false; if (pc != null) { object obj = ResolveTumble(pc); if (obj != null) { InvokeTumble(obj, active: false); } } } private static object? ResolveTumble(PlayerController pc) { object localAvatar = GetLocalAvatar(pc); if (localAvatar == null) { return null; } try { return Traverse.Create(localAvatar).Field("tumble").GetValue(); } catch { } FieldInfo avatarTumbleField = GetAvatarTumbleField(localAvatar.GetType()); if (avatarTumbleField == null) { return null; } try { return avatarTumbleField.GetValue(localAvatar); } catch { return null; } } private static object? GetLocalAvatar(PlayerController pc) { if (pc == null) { return null; } try { object value = Traverse.Create((object)pc).Field("playerAvatarScript").GetValue(); if (value != null) { return value; } } catch { } try { Type type = AccessTools.TypeByName("PlayerAvatar"); if (type == null) { return null; } try { object value2 = Traverse.Create(type).Property("instance", (object[])null).GetValue(); if (value2 != null) { return value2; } } catch { } FieldInfo fieldInfo = AccessTools.Field(type, "instance"); if (fieldInfo != null) { return fieldInfo.GetValue(null); } } catch { } return null; } private static bool InvokeTumble(object tumble, bool active) { Type type = tumble.GetType(); MethodInfo[] array = new MethodInfo[2] { GetTumbleSetMethod(type), GetTumbleRequestMethod(type) }; foreach (MethodInfo methodInfo in array) { if (!(methodInfo == null)) { try { methodInfo.Invoke(tumble, new object[2] { active, false }); return true; } catch { } } } return false; } private static FieldInfo[] GetTumbleBoolFields(Type type) { lock (TumbleBoolFieldsByType) { if (TumbleBoolFieldsByType.TryGetValue(type, out FieldInfo[] value)) { return value; } List list = new List(); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!(fieldInfo.FieldType != typeof(bool))) { string name = fieldInfo.Name; if (name.IndexOf("tumble", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("fall", StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(fieldInfo); } } } FieldInfo[] array = list.ToArray(); TumbleBoolFieldsByType[type] = array; return array; } } private static FieldInfo? GetAvatarTumbleField(Type avatarType) { lock (AvatarTumbleFieldByType) { if (AvatarTumbleFieldByType.TryGetValue(avatarType, out FieldInfo value)) { return value; } FieldInfo fieldInfo = null; FieldInfo[] fields = avatarType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo2 in fields) { if (fieldInfo2.Name.Equals("tumble", StringComparison.OrdinalIgnoreCase)) { fieldInfo = fieldInfo2; break; } } AvatarTumbleFieldByType[avatarType] = fieldInfo; return fieldInfo; } } private static MethodInfo? GetTumbleSetMethod(Type tumbleType) { lock (TumbleSetMethodByType) { if (TumbleSetMethodByType.TryGetValue(tumbleType, out MethodInfo value)) { return value; } MethodInfo methodInfo = AccessTools.Method(tumbleType, "TumbleSet", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); TumbleSetMethodByType[tumbleType] = methodInfo; return methodInfo; } } private static MethodInfo? GetTumbleRequestMethod(Type tumbleType) { lock (TumbleRequestMethodByType) { if (TumbleRequestMethodByType.TryGetValue(tumbleType, out MethodInfo value)) { return value; } MethodInfo methodInfo = AccessTools.Method(tumbleType, "TumbleRequest", new Type[2] { typeof(bool), typeof(bool) }, (Type[])null); TumbleRequestMethodByType[tumbleType] = methodInfo; return methodInfo; } } } internal static class PluginDependencyResolver { private static bool _registered; public static void Register() { if (_registered) { return; } _registered = true; string pluginDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); AppDomain.CurrentDomain.AssemblyResolve += delegate(object _, ResolveEventArgs args) { string name = new AssemblyName(args.Name).Name; if (string.IsNullOrEmpty(name)) { return null; } string text = Path.Combine(pluginDir, name + ".dll"); if (!File.Exists(text)) { return null; } try { return Assembly.LoadFrom(text); } catch { return null; } }; } } public class PsychoticBreakSystem : MonoBehaviour { [CompilerGenerated] private sealed class d__10 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PsychoticBreakSystem <>4__this; private Camera 5__2; private Vector3 5__3; private Vector3 5__4; private float 5__5; private float 5__6; object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) int num = <>1__state; PsychoticBreakSystem psychoticBreakSystem = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = psychoticBreakSystem._mainCam; if (5__2 == null) { return false; } 5__3 = 5__2.transform.localEulerAngles; 5__4 = 5__2.transform.localPosition; 5__5 = 0.5f; 5__6 = 0f; break; case 1: <>1__state = -1; break; } if (5__6 < 5__5) { float num2 = 5__6 / 5__5; float num3 = Mathf.Lerp(15f, 0f, num2); float num4 = Mathf.Lerp(-0.3f, 0f, num2); 5__2.transform.localEulerAngles = new Vector3(5__3.x, 5__3.y, 5__3.z + num3); 5__2.transform.localPosition = 5__4 + new Vector3(0f, num4, 0f); 5__6 += Time.deltaTime; <>2__current = null; <>1__state = 1; return true; } 5__2.transform.localEulerAngles = 5__3; 5__2.transform.localPosition = 5__4; 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(); } } [CompilerGenerated] private sealed class d__2 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public PsychoticBreakSystem <>4__this; object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object? IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__2(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; PsychoticBreakSystem CS$<>8__locals0 = <>4__this; string[] fileNames; switch (num) { default: return false; case 0: <>1__state = -1; goto IL_0042; case 1: <>1__state = -1; goto IL_0042; case 2: { <>1__state = -1; return false; } IL_0042: if (!CS$<>8__locals0._sceneLoaded || SemiFunc.MenuLevel()) { <>2__current = null; <>1__state = 1; return true; } fileNames = new string[4] { "scream_peak.ogg", "scream_distant.ogg", "scream_threat.ogg", "footsteps.ogg" }; <>2__current = AudioClipLoader.LoadClips(fileNames, delegate(string name, AudioClip? clip) { switch (name) { case "scream_peak.ogg": CS$<>8__locals0._peakScreamClip = clip; break; case "scream_distant.ogg": CS$<>8__locals0._distantScreamClip = clip; break; case "scream_threat.ogg": CS$<>8__locals0._threatScreamClip = clip; break; case "footsteps.ogg": CS$<>8__locals0._footstepClip = clip; break; } if (clip != null) { LoggingService.LogInfo("[PsychoticBreak] Loaded " + name); } else { LoggingService.LogWarning("[PsychoticBreak] Missing or failed: " + name); } }); <>1__state = 2; return true; } } 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 bool _enabled; private float _triggerChance; private float _episodeDuration; private bool _oncePerMatch; private bool _episodeActive; private bool _hasTriggeredThisMatch; private float _nextTriggerCheck; private float _episodeTimer; private Camera? _mainCam; private float _threatMemoryUntil; private const float ThreatMemoryDuration = 30f; internal const float ThreatRange = 15f; internal const float SoloRange = 30f; private AudioClip? _peakScreamClip; private AudioClip? _distantScreamClip; private AudioClip? _threatScreamClip; private AudioClip? _footstepClip; private AudioSource? _footstepSource; private AudioSource? _distantScreamSource; private bool _hasPlayedPeakScream; private GameObject? _overlayRoot; private Component? _darknessImage; private Component? _vignetteImage; private Texture2D? _vignetteTexture; private EnemyHealth[]? _cachedEnemies; private float _phantomSoundAccumulator; private float _tumbleMaintainTimer; private bool _sceneLoaded; private bool _typeInitFailed; private string _lastLoggedBlockReason = ""; private bool _cachedAnyEnemyVisible; private float _nextVisibilityRefresh; internal const int VisionBlockMask = -1; private const float VisibilityRefreshInterval = 0.25f; private static PlayerController[]? _cachedPlayers; private static float _nextPlayerRefresh; private void CleanupFootstepSource() { if (_footstepSource != null) { Object.Destroy((Object)(object)((Component)_footstepSource).gameObject, 0f); _footstepSource = null; } } private void CleanupDistantScreamSource() { if (_distantScreamSource != null) { Object.Destroy((Object)(object)((Component)_distantScreamSource).gameObject, 0f); _distantScreamSource = null; } } [IteratorStateMachine(typeof(d__2))] private IEnumerator LoadAudioClips() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__2(0) { <>4__this = this }; } private void PlayCirclingFootsteps() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown if (_footstepClip != null) { GameObject val = new GameObject("DreadPsychoticFootsteps"); Object.DontDestroyOnLoad((Object)(object)val); _footstepSource = val.AddComponent(); _footstepSource.clip = _footstepClip; _footstepSource.loop = true; _footstepSource.spatialBlend = 0f; _footstepSource.volume = 0.3f; _footstepSource.panStereo = -1f; _footstepSource.Play(); } } private void PlayDistantScream() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown if (_distantScreamClip != null) { GameObject val = new GameObject("DreadDistantScream"); Object.DontDestroyOnLoad((Object)(object)val); _distantScreamSource = val.AddComponent(); _distantScreamSource.clip = _distantScreamClip; _distantScreamSource.loop = false; _distantScreamSource.spatialBlend = 0f; _distantScreamSource.volume = 0.35f; _distantScreamSource.Play(); } } private void PlayPeakScream() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown if (_peakScreamClip != null && _mainCam != null) { GameObject val = new GameObject("DreadPeakScream"); Object.DontDestroyOnLoad((Object)val); AudioSource val2 = val.AddComponent(); val2.clip = _peakScreamClip; val2.spatialBlend = 0f; val2.volume = 0.9f; val2.Play(); Object.Destroy((Object)val, AudioPlayUtil.PlayLifetimeSeconds(_peakScreamClip, val2.pitch, 1f)); } } private void SpawnPhantomSound() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown if (_threatScreamClip != null) { Camera mainCam = _mainCam; if (mainCam != null) { AudioClip threatScreamClip = _threatScreamClip; Vector3 val = Random.insideUnitSphere * Random.Range(5f, 15f); Vector3 position = mainCam.transform.position + val; GameObject val2 = new GameObject("DreadPhantomSound"); val2.transform.position = position; AudioSource obj = val2.AddComponent(); obj.clip = threatScreamClip; float pitch = (obj.pitch = Random.Range(0.5f, 1.5f)); obj.spatialBlend = 1f; obj.volume = Random.Range(0.4f, 0.8f); obj.rolloffMode = (AudioRolloffMode)0; obj.minDistance = 1f; obj.maxDistance = 25f; obj.Play(); Object.Destroy((Object)val2, AudioPlayUtil.PlayLifetimeSeconds(threatScreamClip, pitch, 1f)); } } } private void StartEpisode(bool countAsMatchTrigger = true) { _episodeActive = true; if (countAsMatchTrigger) { _hasTriggeredThisMatch = true; } _episodeTimer = 0f; _phantomSoundAccumulator = 0f; _tumbleMaintainTimer = 0f; _nextTriggerCheck = Time.time + 10f; _hasPlayedPeakScream = false; LockPlayerForEpisode(PlayerController.instance); CreateOverlay(); PlayCirclingFootsteps(); PlayDistantScream(); LoggingService.LogInfo("[Dread] Psychotic Break triggered!"); } private void UpdateEpisode() { _episodeTimer += Time.deltaTime; float episodeTimer = _episodeTimer; if (episodeTimer >= _episodeDuration) { EndEpisode(); return; } _tumbleMaintainTimer -= Time.deltaTime; if (_tumbleMaintainTimer <= 0f) { _tumbleMaintainTimer = 0.4f; MaintainPlayerFallenState(PlayerController.instance); } float num = _episodeDuration * 0.15f; float num2 = _episodeDuration * 0.5f; float num3 = _episodeDuration * 0.8f; if (episodeTimer < num) { float darknessAlpha = Mathf.Lerp(0f, 0.85f, episodeTimer / num); SetDarknessAlpha(darknessAlpha); SetVignetteAlpha(0f); return; } if (episodeTimer < num2) { float num4 = (episodeTimer - num) / (num2 - num); float num5 = Mathf.Sin(Time.time * Mathf.Lerp(10f, 30f, num4)) * 0.5f + 0.5f; float num6 = Mathf.Lerp(0.1f, 0.6f, num4); SetVignetteAlpha(num6 * num5); SetDarknessAlpha(0.85f); if (_footstepSource != null) { _footstepSource.panStereo = Mathf.Lerp(-1f, 1f, num4); } return; } if (episodeTimer < num3) { if (!_hasPlayedPeakScream) { _hasPlayedPeakScream = true; PlayPeakScream(); } float num7 = (episodeTimer - num2) / (num3 - num2); float num8 = Mathf.Lerp(0.5f, 0.9f, num7); float num9 = Mathf.Sin(Time.time * 35f) * 0.3f + 0.7f; SetVignetteAlpha(num8 * num9); SetDarknessAlpha(0.85f); if (_footstepSource != null) { _footstepSource.panStereo = Mathf.Sin(Time.time * 4f) * 0.8f; _footstepSource.volume = Mathf.Lerp(0.5f, 1f, num7); } _phantomSoundAccumulator += Time.deltaTime * 0.3f; if (_phantomSoundAccumulator >= 1f) { _phantomSoundAccumulator = 0f; SpawnPhantomSound(); } return; } float num10 = (episodeTimer - num3) / (_episodeDuration - num3); if (num10 < 0.5f) { float num11 = Mathf.Lerp(0.9f, 1f, num10 * 2f); SetVignetteAlpha(0.95f * num11); SetDarknessAlpha(0.9f * num11); } else { SetDarknessAlpha(0f); SetVignetteAlpha(0f); } if (_footstepSource != null) { if (num10 < 0.5f) { _footstepSource.volume = Mathf.Lerp(1f, 0f, num10 * 2f); _footstepSource.panStereo = Mathf.Sin(Time.time * 8f) * 0.9f; } else { _footstepSource.Stop(); } } if (episodeTimer >= _episodeDuration - 0.5f) { EndEpisode(); } } private void EndEpisode() { LoggingService.LogVerbose("[PsychoticBreak] Episode ending..."); _episodeActive = false; SetDarknessAlpha(0f); SetVignetteAlpha(0f); PlayerController instance = PlayerController.instance; RestorePlayerControl(instance); if (instance != null) { ((MonoBehaviour)this).StartCoroutine(DoStumble()); } CleanupFootstepSource(); CleanupDistantScreamSource(); CleanupOverlay(); LoggingService.LogInfo("[Dread] Psychotic Break ended."); } [IteratorStateMachine(typeof(d__10))] private IEnumerator DoStumble() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(0) { <>4__this = this }; } private void CreateOverlay() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_0101: Unknown result type (might be due to invalid IL or missing references) if (_overlayRoot != null) { return; } Type type = ResolveRawImageType(); if (type == null) { LoggingService.LogError("[PsychoticBreak] UnityEngine.UI.RawImage not available"); return; } Type type2 = ResolveCanvasType(); if (type2 == null) { LoggingService.LogError("[PsychoticBreak] UnityEngine.Canvas not available"); return; } GameObject val = new GameObject("DreadPsychoticBreakOverlay"); Object.DontDestroyOnLoad((Object)(object)val); _overlayRoot = val; ConfigureCanvas(AddRuntimeComponent(val, type2)); GameObject val2 = new GameObject("Darkness"); val2.transform.SetParent(val.transform, false); _darknessImage = AddRuntimeComponent(val2, type); SetRawImageColor(_darknessImage, new Color(0f, 0f, 0f, 0f)); StretchToParent(_darknessImage); GameObject val3 = new GameObject("Vignette"); val3.transform.SetParent(val.transform, false); _vignetteImage = AddRuntimeComponent(val3, type); SetRawImageColor(_vignetteImage, new Color(0f, 0f, 0f, 0f)); StretchToParent(_vignetteImage); _vignetteTexture = OverlayTextureUtil.CreateVignette(256); if (_vignetteTexture == null) { LoggingService.LogWarning("[PsychoticBreak] Vignette texture unavailable; overlay may be incomplete"); } else { SetRawImageTexture(_vignetteImage, _vignetteTexture); } } private static Type? ResolveRawImageType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "UnityEngine.UI", StringComparison.Ordinal)) { return assembly.GetType("UnityEngine.UI.RawImage"); } } return Type.GetType("UnityEngine.UI.RawImage, UnityEngine.UI"); } private static Type? ResolveCanvasType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string name = assembly.GetName().Name; if ((name == "UnityEngine.UIModule" || name == "UnityEngine") ? true : false) { Type type = assembly.GetType("UnityEngine.Canvas"); if (type != null) { return type; } } } return Type.GetType("UnityEngine.Canvas, UnityEngine.UIModule") ?? Type.GetType("UnityEngine.Canvas, UnityEngine"); } private static void ConfigureCanvas(Component canvas) { ((object)canvas).GetType().GetProperty("renderMode")?.SetValue(canvas, (object)(RenderMode)0, null); ((object)canvas).GetType().GetProperty("sortingOrder")?.SetValue(canvas, 999, null); } private static Component AddRuntimeComponent(GameObject go, Type componentType) { return go.AddComponent(componentType); } private static void StretchToParent(Component rawImage) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) Type type = ((object)rawImage).GetType().Assembly.GetType("UnityEngine.RectTransform") ?? Type.GetType("UnityEngine.RectTransform, UnityEngine.CoreModule"); if (!(type == null)) { Component component = rawImage.GetComponent(type); if (component != null) { PropertyInfo? property = type.GetProperty("anchorMin"); PropertyInfo property2 = type.GetProperty("anchorMax"); PropertyInfo property3 = type.GetProperty("sizeDelta"); property?.SetValue(component, Vector2.zero, null); property2?.SetValue(component, Vector2.one, null); property3?.SetValue(component, Vector2.zero, null); } } } private static void SetRawImageColor(Component rawImage, Color color) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) ((object)rawImage).GetType().GetProperty("color")?.SetValue(rawImage, color, null); } private static void SetRawImageTexture(Component rawImage, Texture2D texture) { ((object)rawImage).GetType().GetProperty("texture")?.SetValue(rawImage, texture, null); } private void CleanupOverlay() { if (_overlayRoot != null) { Object.Destroy((Object)(object)_overlayRoot, 0f); _overlayRoot = null; } _darknessImage = null; _vignetteImage = null; if (_vignetteTexture != null) { Object.Destroy((Object)(object)_vignetteTexture, 0f); _vignetteTexture = null; } } private void SetDarknessAlpha(float alpha) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (_darknessImage != null) { SetRawImageColor(_darknessImage, new Color(0f, 0f, 0f, Mathf.Clamp01(alpha))); } } private void SetVignetteAlpha(float alpha) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) if (_vignetteImage != null) { SetRawImageColor(_vignetteImage, new Color(0f, 0f, 0f, Mathf.Clamp01(alpha))); } } private static void LockPlayerForEpisode(PlayerController? pc) { if (pc != null) { DisableFlashlight(pc); LockInput(pc); if (!PlayerTumbleCompat.ApplyForcedTumble(pc)) { LoggingService.LogVerbose("[PsychoticBreak] Tumble lock unavailable; input lock only"); } } } private static void MaintainPlayerFallenState(PlayerController? pc) { if (pc != null) { PlayerTumbleCompat.MaintainForcedTumble(pc); LockInput(pc); } } private static void RestorePlayerControl(PlayerController? pc) { PlayerTumbleCompat.ReleaseForcedTumble(pc); if (pc != null) { UnlockInput(pc); RestoreFlashlight(pc); } } private static void DisableFlashlight(PlayerController pc) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) Light componentInChildren = ((Component)pc).GetComponentInChildren(); if (componentInChildren != null && ((Behaviour)componentInChildren).enabled) { ((Behaviour)componentInChildren).enabled = false; GameObject val = new GameObject("DreadFlashlightTracker"); val.transform.SetParent(((Component)pc).transform); val.AddComponent().Flashlight = componentInChildren; } } private static void RestoreFlashlight(PlayerController pc) { FlashlightStateTracker componentInChildren = ((Component)pc).GetComponentInChildren(); if (componentInChildren != null && componentInChildren.Flashlight != null) { ((Behaviour)componentInChildren.Flashlight).enabled = true; } Object.Destroy((Object)(object)((componentInChildren != null) ? ((Component)componentInChildren).gameObject : null), 0f); } private static void LockInput(PlayerController pc) { bool flag = false; try { Traverse.Create((object)pc).Field("inputLocked").Value = true; flag = true; } catch { } try { Traverse.Create((object)pc).Field("interactDisabled").Value = true; flag = true; } catch { } try { Traverse.Create((object)pc).Field("InputLocked").Value = true; flag = true; } catch { } try { Traverse.Create((object)pc).Field("InteractDisabled").Value = true; flag = true; } catch { } if (!flag) { LoggingService.LogWarning("[Dread] LockInput: no matching field found on PlayerController"); } } private static void UnlockInput(PlayerController pc) { bool flag = false; try { Traverse.Create((object)pc).Field("inputLocked").Value = false; flag = true; } catch { } try { Traverse.Create((object)pc).Field("interactDisabled").Value = false; flag = true; } catch { } try { Traverse.Create((object)pc).Field("InputLocked").Value = false; flag = true; } catch { } try { Traverse.Create((object)pc).Field("InteractDisabled").Value = false; flag = true; } catch { } if (!flag) { LoggingService.LogWarning("[Dread] UnlockInput: no matching field found on PlayerController"); } } private void Start() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) LoggingService.LogVerbose("[PsychoticBreak] Awake starting..."); SceneManager.sceneLoaded += OnSceneLoaded; _mainCam = Camera.main; RefreshConfig(); OnSceneLoaded(SceneManager.GetActiveScene(), (LoadSceneMode)0); DreadConfig.PsychoticBreakEnabled.SettingChanged += OnConfigChanged; DreadConfig.CompatibilityMode.SettingChanged += OnConfigChanged; DreadConfig.PsychoticBreakTriggerChance.SettingChanged += OnConfigChanged; DreadConfig.PsychoticBreakDuration.SettingChanged += OnConfigChanged; DreadConfig.PsychoticBreakOncePerMatch.SettingChanged += OnConfigChanged; ((MonoBehaviour)this).StartCoroutine(LoadAudioClips()); } private void RefreshConfig() { _enabled = DreadConfig.PsychoticBreakEnabled.Value; _triggerChance = DreadConfig.PsychoticBreakTriggerChance.Value; _episodeDuration = DreadConfig.PsychoticBreakDuration.Value; _oncePerMatch = DreadConfig.PsychoticBreakOncePerMatch.Value; } private void OnConfigChanged(object? sender, EventArgs e) { RefreshConfig(); } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); SceneManager.sceneLoaded -= OnSceneLoaded; DreadConfig.PsychoticBreakEnabled.SettingChanged -= OnConfigChanged; DreadConfig.PsychoticBreakTriggerChance.SettingChanged -= OnConfigChanged; DreadConfig.PsychoticBreakDuration.SettingChanged -= OnConfigChanged; DreadConfig.PsychoticBreakOncePerMatch.SettingChanged -= OnConfigChanged; DreadConfig.CompatibilityMode.SettingChanged -= OnConfigChanged; _peakScreamClip = null; _distantScreamClip = null; _threatScreamClip = null; _footstepClip = null; CleanupOverlay(); CleanupFootstepSource(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { _sceneLoaded = true; if (_episodeActive) { RestorePlayerControl(PlayerController.instance); } _episodeActive = false; _threatMemoryUntil = 0f; _cachedEnemies = null; _mainCam = Camera.main; EnemyScanCache.Invalidate(); CleanupOverlay(); CleanupFootstepSource(); CleanupDistantScreamSource(); if (SemiFunc.MenuLevel()) { _hasTriggeredThisMatch = false; } } private void Update() { if (_typeInitFailed) { return; } try { UpdateInternal(); } catch (TypeInitializationException ex) { _typeInitFailed = true; ((Behaviour)this).enabled = false; string text = ex.InnerException?.Message ?? ex.Message; LoggingService.LogError("[PsychoticBreak] Disabled after init failure: " + text); } } private void UpdateInternal() { if (_episodeActive) { if (DreadConfig.CompatibilityMode.Value) { EndEpisode(); return; } UpdateEpisode(); PublishRuntimeState(); return; } if (!_enabled || DreadConfig.CompatibilityMode.Value || SemiFunc.MenuLevel()) { PublishRuntimeState(); return; } if (_oncePerMatch && _hasTriggeredThisMatch) { PublishRuntimeState(); return; } UpdateThreatTimestamps(); if (Time.time < _nextTriggerCheck) { PublishRuntimeState(); return; } _nextTriggerCheck = Time.time + 2f; if (!CanTrigger()) { PublishRuntimeState(); return; } if (Random.value < _triggerChance) { StartEpisode(); } PublishRuntimeState(); } private void PublishRuntimeState() { DreadRuntimeState.PsychoticBreakEnabled = _enabled && !DreadConfig.CompatibilityMode.Value; DreadRuntimeState.PsychoticBreakEpisodeActive = _episodeActive; DreadRuntimeState.PsychoticBreakEpisodeTimer = _episodeTimer; DreadRuntimeState.PsychoticBreakEpisodeDuration = _episodeDuration; float num = _nextTriggerCheck - Time.time; DreadRuntimeState.PsychoticBreakNextCheckIn = ((num < 0f) ? 0f : num); DreadRuntimeState.PsychoticBreakThreatCount = GetThreatMemorySecondsRemaining(); DreadRuntimeState.PsychoticBreakEnemyCount = EnemyScanCache.Count; DreadRuntimeState.PsychoticBreakClipsLoaded = AreClipsLoaded(); if (_episodeActive) { DreadRuntimeState.PsychoticBreakCanTrigger = false; DreadRuntimeState.PsychoticBreakBlockReason = "episode active"; return; } string triggerBlockReason = GetTriggerBlockReason(); DreadRuntimeState.PsychoticBreakBlockReason = triggerBlockReason ?? ""; DreadRuntimeState.PsychoticBreakCanTrigger = triggerBlockReason == null; string text = triggerBlockReason ?? "ready"; if (text != _lastLoggedBlockReason) { _lastLoggedBlockReason = text; if (triggerBlockReason != null) { LoggingService.LogInfo("[PsychoticBreak] Blocked: " + triggerBlockReason); } } } private bool AreClipsLoaded() { if (_peakScreamClip != null && _distantScreamClip != null && _threatScreamClip != null) { return _footstepClip != null; } return false; } public void ForceEpisodeForDebug() { if (!_episodeActive) { if (SemiFunc.MenuLevel()) { LoggingService.LogWarning("[PsychoticBreak] ForceEpisode ignored on menu level"); } else { StartEpisode(countAsMatchTrigger: false); } } } private string? GetTriggerBlockReason() { if (!_enabled) { return "disabled"; } if (DreadConfig.CompatibilityMode.Value) { return "compatibility mode"; } if (SemiFunc.MenuLevel()) { return "menu level"; } if (_oncePerMatch && _hasTriggeredThisMatch) { return "once per match"; } if (!AreClipsLoaded()) { return "clips not loaded"; } PlayerController instance = PlayerController.instance; if (instance == null) { return "no player"; } if (!IsSolo(instance)) { return "not solo"; } if (!HasRecentThreat()) { return "no recent threat"; } if (IsAnyEnemyVisibleCached()) { return "visible enemy"; } if (!IsHidingVulnerable(instance)) { return "not hiding"; } return null; } private void UpdateThreatTimestamps() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (_mainCam == null) { _mainCam = Camera.main; } Vector3? threatScanOrigin = GetThreatScanOrigin(); if (!threatScanOrigin.HasValue) { return; } _cachedEnemies = EnemyScanCache.GetEnemies(); EnemyHealth[] cachedEnemies = _cachedEnemies; foreach (EnemyHealth enemy in cachedEnemies) { if (EnemyHealthCompat.IsValid(enemy) && Vector3.Distance(threatScanOrigin.Value, EnemyScanCache.GetFocusPosition(enemy)) < 15f) { _threatMemoryUntil = Time.time + 30f; break; } } } private bool HasRecentThreat() { return Time.time < _threatMemoryUntil; } private int GetThreatMemorySecondsRemaining() { if (!HasRecentThreat()) { return 0; } return (int)Math.Ceiling(_threatMemoryUntil - Time.time); } private Vector3? GetThreatScanOrigin() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) PlayerController instance = PlayerController.instance; if (instance != null) { try { return ((Component)instance).transform.position; } catch { } } if (_mainCam == null) { _mainCam = Camera.main; } if (_mainCam == null) { return null; } return _mainCam.transform.position; } private bool CanTrigger() { LoggingService.LogVerbose("[PsychoticBreak] Checking trigger condition..."); PlayerController instance = PlayerController.instance; if (instance == null) { return false; } if (!IsSolo(instance)) { return false; } if (!HasRecentThreat()) { return false; } if (IsAnyEnemyVisibleCached()) { return false; } if (!IsHidingVulnerable(instance)) { return false; } if (!AreClipsLoaded()) { return false; } return true; } private static bool IsSolo(PlayerController pc) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (Time.time >= _nextPlayerRefresh) { _nextPlayerRefresh = Time.time + 2f; _cachedPlayers = Object.FindObjectsOfType(); } PlayerController[] cachedPlayers = _cachedPlayers; if (cachedPlayers == null) { return true; } PlayerController[] array = cachedPlayers; foreach (PlayerController val in array) { if (val != null && val != pc && IsPlayerAlive(val) && Vector3.Distance(((Component)pc).transform.position, ((Component)val).transform.position) < 30f) { return false; } } return true; } private static bool IsPlayerAlive(PlayerController pc) { return PlayerControllerCompat.IsAlive(pc); } private bool IsAnyEnemyVisibleCached() { if (Time.time < _nextVisibilityRefresh) { return _cachedAnyEnemyVisible; } _nextVisibilityRefresh = Time.time + 0.25f; _cachedAnyEnemyVisible = IsAnyEnemyVisible(_cachedEnemies); return _cachedAnyEnemyVisible; } private bool IsAnyEnemyVisible(EnemyHealth[]? enemies) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: 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) Camera mainCam = _mainCam; if (mainCam == null || enemies == null) { return false; } Vector3 position; try { position = mainCam.transform.position; } catch { return false; } RaycastHit val2 = default(RaycastHit); foreach (EnemyHealth val in enemies) { if (!EnemyHealthCompat.IsValid(val)) { continue; } try { if (EnemyHealthCompat.IsAliveForVisibility(val)) { Vector3 focusPosition = EnemyScanCache.GetFocusPosition(val); if (Vector3.Distance(position, focusPosition) < 0.75f) { return true; } if (!Physics.Linecast(position, focusPosition, ref val2, -1, (QueryTriggerInteraction)1)) { return true; } if (((RaycastHit)(ref val2)).collider != null && ((Component)((RaycastHit)(ref val2)).collider).transform.IsChildOf(((Component)val).transform)) { return true; } } } catch { } } return false; } private static bool IsHidingVulnerable(PlayerController pc) { return PlayerControllerCompat.IsHidingVulnerable(pc); } } internal static class RepoConfigCompat { internal static void TryApply(Harmony harmony) { RepoConfigSliderLabelCompat.TryApply(harmony); } } internal static class RepoConfigSliderLabelCompat { private const float LabelColumnLocalX = 100f; private static bool _applied; internal static void TryApply(Harmony harmony) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown if (_applied) { return; } if (!IsRepoConfigLoaded()) { LoggingService.LogVerbose("[Dread] REPOConfig not loaded; slider label compat skipped (use elytraking.dread.cfg)"); return; } Type type = FindMenuApiType(); if (type == null) { return; } HarmonyMethod val = new HarmonyMethod(typeof(RepoConfigSliderLabelCompat), "AfterCreateSlider", (Type[])null); int num = 0; foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (string.Equals(declaredMethod.Name, "CreateREPOSlider", StringComparison.Ordinal)) { ParameterInfo[] parameters = declaredMethod.GetParameters(); if (parameters.Length >= 2 && !(parameters[0].ParameterType != typeof(string)) && !(parameters[1].ParameterType != typeof(string))) { harmony.Patch((MethodBase)declaredMethod, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } } } Type type2 = FindRepoSliderType(); if (type2 != null) { MethodInfo methodInfo = AccessTools.Method(type2, "HandleDescription", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(RepoConfigSliderLabelCompat), "AfterHandleDescription", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } if (num != 0) { _applied = true; LoggingService.LogInfo($"[Dread] REPOConfig slider label compat active ({num} hooks)"); } } internal static bool IsRepoConfigLoaded() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { if (string.Equals(assemblies[i].GetName().Name, "REPOConfig", StringComparison.Ordinal)) { return true; } } return false; } private static void AfterCreateSlider(object __result, string text, string description) { if (__result != null && !string.IsNullOrEmpty(text) && string.IsNullOrEmpty(description)) { Type type = __result.GetType(); FieldInfo field = type.GetField("labelTMP", BindingFlags.Instance | BindingFlags.Public); FieldInfo? field2 = type.GetField("descriptionTMP", BindingFlags.Instance | BindingFlags.Public); object obj = field?.GetValue(__result); object? tmp = field2?.GetValue(__result); SetTmpText(obj, text); SetTmpText(tmp, string.Empty); SetGameObjectActive(tmp, active: false); SetLocalX(obj, 100f); ConfigureLabelForLeftColumn(obj); ForceCompactSliderRow(__result); } } private static void AfterHandleDescription(object __instance) { if (__instance != null) { Type type = __instance.GetType(); object tmp = type.GetField("descriptionTMP", BindingFlags.Instance | BindingFlags.Public)?.GetValue(__instance); object obj = type.GetField("labelTMP", BindingFlags.Instance | BindingFlags.Public)?.GetValue(__instance); if (!string.IsNullOrEmpty(GetTmpText(obj)) && string.IsNullOrEmpty(GetTmpText(tmp))) { SetTmpText(tmp, string.Empty); SetGameObjectActive(tmp, active: false); SetLocalX(obj, 100f); ConfigureLabelForLeftColumn(obj); ForceCompactSliderRow(__instance); } } } private static void ForceCompactSliderRow(object slider) { try { Type type = slider.GetType(); FieldInfo field = type.GetField("backgroundFillRectTransform", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo? field2 = type.GetField("backgroundOutlineRectTransform", BindingFlags.Instance | BindingFlags.NonPublic); SetSizeDelta(field?.GetValue(slider), 109.8f, 15f); SetSizeDelta(field2?.GetValue(slider), 108f, 15f); object obj = type.GetField("repoScrollViewElement", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(slider); obj?.GetType().GetField("bottomPadding", BindingFlags.Instance | BindingFlags.Public)?.SetValue(obj, 1f); } catch { } } private static void SetSizeDelta(object? rectTransform, float width, float height) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (rectTransform != null) { PropertyInfo property = rectTransform.GetType().GetProperty("sizeDelta", BindingFlags.Instance | BindingFlags.Public); object obj = property?.GetValue(rectTransform); if (obj is Vector2) { Vector2 val = (Vector2)obj; val.x = width; val.y = height; property.SetValue(rectTransform, val); } } } private static void SetLocalX(object? target, float x) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) Component val = (Component)((target is Component) ? target : null); if (val != null) { Vector3 localPosition = val.transform.localPosition; localPosition.x = x; val.transform.localPosition = localPosition; } } private static void ConfigureLabelForLeftColumn(object? labelTmp) { //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) if (labelTmp == null) { return; } try { Type type = labelTmp.GetType(); PropertyInfo property = type.GetProperty("alignment", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.PropertyType.IsEnum) { property.SetValue(labelTmp, Enum.Parse(property.PropertyType, "Left")); } PropertyInfo property2 = type.GetProperty("overflowMode", BindingFlags.Instance | BindingFlags.Public); if (property2 != null && property2.PropertyType.IsEnum) { string[] array = new string[3] { "Overflow", "Ellipsis", "Visible" }; foreach (string value in array) { try { property2.SetValue(labelTmp, Enum.Parse(property2.PropertyType, value)); } catch { continue; } break; } } Component val = (Component)((labelTmp is Component) ? labelTmp : null); if (val != null) { Transform transform = val.transform; PropertyInfo property3 = ((object)transform).GetType().GetProperty("sizeDelta", BindingFlags.Instance | BindingFlags.Public); object obj2 = property3?.GetValue(transform); if (obj2 is Vector2) { Vector2 val2 = (Vector2)obj2; val2.x = Math.Max(val2.x, 180f); property3.SetValue(transform, val2); } } } catch { } } private static void SetGameObjectActive(object? tmp, bool active) { if (tmp == null) { return; } try { Component val = (Component)((tmp is Component) ? tmp : null); object obj = ((val != null) ? val.gameObject : null); obj?.GetType().GetMethod("SetActive", new Type[1] { typeof(bool) })?.Invoke(obj, new object[1] { active }); } catch { } } internal static Type? FindMenuApiType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "MenuLib", StringComparison.Ordinal)) { return assembly.GetType("MenuLib.MenuAPI"); } } return null; } private static Type? FindRepoSliderType() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "MenuLib", StringComparison.Ordinal)) { return assembly.GetType("MenuLib.MonoBehaviors.REPOSlider"); } } return null; } private static string GetTmpText(object? tmp) { if (tmp == null) { return ""; } return tmp.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.GetValue(tmp)?.ToString() ?? ""; } private static void SetTmpText(object? tmp, string value) { tmp?.GetType().GetProperty("text", BindingFlags.Instance | BindingFlags.Public)?.SetValue(tmp, value); } } public class TensionSystem : MonoBehaviour { [CompilerGenerated] private sealed class <>c__DisplayClass27_0 { public AudioClip clip; internal void b__0(AudioClip? c) { clip = c; } } [CompilerGenerated] private sealed class d__28 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public TensionSystem <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown int num = <>1__state; TensionSystem tensionSystem = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = (object)new WaitForSeconds(45f); <>1__state = 1; return true; case 1: <>1__state = -1; break; case 2: <>1__state = -1; break; case 3: <>1__state = -1; break; case 4: <>1__state = -1; break; } if (!DreadConfig.FakeFootstepsEnabled.Value || SemiFunc.MenuLevel() || tensionSystem._footstepClip == null || PlayerController.instance == null) { <>2__current = (object)new WaitForSeconds(1f); <>1__state = 2; return true; } Camera mainCam = tensionSystem._mainCam; if (mainCam == null) { <>2__current = (object)new WaitForSeconds(1f); <>1__state = 3; return true; } LoggingService.LogVerbose("[Tension] Checking fake footsteps..."); if (Random.value <= 0.35f) { tensionSystem.SpawnFakeFootstep(mainCam); } <>2__current = (object)new WaitForSeconds(Random.Range(60f, 90f)); <>1__state = 4; return true; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__26 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public TensionSystem <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; TensionSystem CS$<>8__locals0 = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = AudioClipLoader.LoadClips(BreathCandidates, delegate(string name, AudioClip? clip) { if (clip != null) { CS$<>8__locals0._breathClips.Add(clip); } }); <>1__state = 1; return true; case 1: <>1__state = -1; 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(); } } [CompilerGenerated] private sealed class d__27 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private <>c__DisplayClass27_0 <>8__1; public TensionSystem <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__27(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>8__1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; TensionSystem tensionSystem = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>8__1 = new <>c__DisplayClass27_0(); <>8__1.clip = null; <>2__current = AudioClipLoader.LoadClip("footsteps.ogg", delegate(AudioClip? c) { <>8__1.clip = c; }); <>1__state = 1; return true; case 1: <>1__state = -1; if (<>8__1.clip != null) { tensionSystem._footstepClip = <>8__1.clip; } 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 AudioSource? _breathSource; private readonly List _breathClips = new List(); private AudioClip? _footstepClip; private float _nextScan; private float _nearestDist = float.MaxValue; private Camera? _mainCam; private float _originalDrain = -1f; private bool _wasSprintingForBreath; private float _breathCooldown; private bool _wasSprinting; private float _panicTimer; private float _panicCooldown; private float _originalSprintMultiplier = -1f; private const float ProximityRange = 15f; private static readonly string[] BreathCandidates = new string[3] { "breathing.ogg", "breath2.ogg", "breath3.ogg" }; private void Start() { LoggingService.LogVerbose("[Tension] Awake starting..."); SceneManager.sceneLoaded += OnSceneLoaded; _mainCam = Camera.main; _breathSource = ((Component)this).gameObject.AddComponent(); _breathSource.spatialBlend = 0f; _breathSource.loop = false; _breathSource.playOnAwake = false; ((MonoBehaviour)this).StartCoroutine(LoadBreathClips()); ((MonoBehaviour)this).StartCoroutine(LoadFootstepClip()); ((MonoBehaviour)this).StartCoroutine(FakeFootstepLoop()); } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); SceneManager.sceneLoaded -= OnSceneLoaded; RestoreDrain(); RestoreSprintMultiplier(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { RestoreDrain(); RestoreSprintMultiplier(); AudioClipLoader.ClearCache(); _mainCam = Camera.main; _originalDrain = -1f; _panicTimer = 0f; _panicCooldown = 0f; _originalSprintMultiplier = -1f; _wasSprinting = false; _wasSprintingForBreath = false; _breathCooldown = 0f; } private void Update() { if (Time.time >= _nextScan) { _nextScan = Time.time + 0.5f; _nearestDist = (SemiFunc.MenuLevel() ? float.MaxValue : FindNearestEnemyDist()); } UpdateAdrenaline(); UpdateLowStamina(); UpdatePanicSprint(); PublishRuntimeState(); } private void PublishRuntimeState() { DreadRuntimeState.NearestEnemyDist = _nearestDist; PlayerController instance = PlayerController.instance; bool adrenalineActive = false; if (instance != null && _originalDrain >= 0f && DreadConfig.AdrenalineEnabled.Value && !DreadConfig.CompatibilityMode.Value && !SemiFunc.MenuLevel() && _nearestDist < 15f) { adrenalineActive = instance.EnergySprintDrain < _originalDrain * 0.95f; } DreadRuntimeState.AdrenalineActive = adrenalineActive; DreadRuntimeState.PanicSprintActive = _panicTimer > 0f; DreadRuntimeState.PanicSprintCooldown = ((_panicCooldown < 0f) ? 0f : _panicCooldown); } private void UpdateAdrenaline() { if (!DreadConfig.AdrenalineEnabled.Value || DreadConfig.CompatibilityMode.Value || SemiFunc.MenuLevel()) { RestoreDrain(); return; } PlayerController instance = PlayerController.instance; if (instance != null) { if (_originalDrain < 0f) { _originalDrain = instance.EnergySprintDrain; } float num = ((_nearestDist < 15f) ? (_originalDrain * Mathf.Lerp(0.3f, 1f, _nearestDist / 15f)) : _originalDrain); instance.EnergySprintDrain = Mathf.MoveTowards(instance.EnergySprintDrain, num, 0.5f * Time.deltaTime); } } private void RestoreDrain() { if (_originalDrain >= 0f && PlayerController.instance != null) { PlayerController.instance.EnergySprintDrain = _originalDrain; } } private void RestoreSprintMultiplier() { if (_originalSprintMultiplier >= 0f && PlayerController.instance != null) { Traverse.Create((object)PlayerController.instance).Field("SprintSpeedMultiplier").Value = _originalSprintMultiplier; _originalSprintMultiplier = -1f; } } private void UpdateLowStamina() { if (!DreadConfig.LowStaminaSoundEnabled.Value || SemiFunc.MenuLevel()) { _breathCooldown = 0f; return; } _breathCooldown -= Time.deltaTime; if (_breathSource == null || _breathClips.Count == 0) { return; } PlayerController instance = PlayerController.instance; if (instance != null && !(instance.EnergyStart <= 0f)) { bool sprinting = instance.sprinting; bool flag = instance.EnergyCurrent <= instance.EnergyStart * 0.1f; if (_wasSprintingForBreath && !sprinting && flag && _breathCooldown <= 0f) { _breathCooldown = 60f; AudioClip clip = _breathClips[Random.Range(0, _breathClips.Count)]; _breathSource.clip = clip; _breathSource.pitch = Random.Range(0.88f, 1.15f); _breathSource.volume = 1f; _breathSource.Play(); } _wasSprintingForBreath = sprinting; } } private void UpdatePanicSprint() { if (!DreadConfig.PanicSprintEnabled.Value || DreadConfig.CompatibilityMode.Value || SemiFunc.MenuLevel()) { if (_originalSprintMultiplier >= 0f) { RestoreSprintMultiplier(); } return; } PlayerController instance = PlayerController.instance; if (instance == null) { return; } _panicCooldown -= Time.deltaTime; bool sprinting = instance.sprinting; if (_originalSprintMultiplier >= 0f) { _panicTimer -= Time.deltaTime; if (_panicTimer <= 0f) { _panicCooldown = 20f; if (_originalSprintMultiplier >= 0f) { Traverse.Create((object)instance).Field("SprintSpeedMultiplier").Value = _originalSprintMultiplier; _originalSprintMultiplier = -1f; } } } else if (!_wasSprinting && sprinting && _nearestDist < 15f && _panicCooldown <= 0f) { Traverse val = Traverse.Create((object)instance); _originalSprintMultiplier = val.Field("SprintSpeedMultiplier").Value; val.Field("SprintSpeedMultiplier").Value = _originalSprintMultiplier * 1.25f; _panicTimer = 2f; } _wasSprinting = sprinting; } private float FindNearestEnemyDist() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (_mainCam == null) { _mainCam = Camera.main; } Camera mainCam = _mainCam; if (mainCam == null) { return float.MaxValue; } float num = float.MaxValue; EnemyHealth[] array = Object.FindObjectsOfType(); foreach (EnemyHealth val in array) { if (val != null) { float num2 = Vector3.Distance(mainCam.transform.position, ((Component)val).transform.position); if (num2 < num) { num = num2; } } } return num; } [IteratorStateMachine(typeof(d__26))] private IEnumerator LoadBreathClips() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__26(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__27))] private IEnumerator LoadFootstepClip() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__27(0) { <>4__this = this }; } [IteratorStateMachine(typeof(d__28))] private IEnumerator FakeFootstepLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__28(0) { <>4__this = this }; } private void SpawnFakeFootstep(Camera cam) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0081: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) Vector3 val = -cam.transform.forward; Vector3 val2 = cam.transform.right * Random.Range(-0.8f, 0.8f); Vector3 position = cam.transform.position; Vector3 val3 = val + val2; Vector3 position2 = position + ((Vector3)(ref val3)).normalized * Random.Range(2.5f, 5f); position2.y -= 1.5f; GameObject val4 = new GameObject("DreadFakeStep"); val4.transform.position = position2; AudioSource obj = val4.AddComponent(); obj.clip = _footstepClip; float pitch = (obj.pitch = Random.Range(0.5f, 1.5f)); obj.spatialBlend = 1f; obj.volume = 0.55f; obj.rolloffMode = (AudioRolloffMode)0; obj.minDistance = 0.5f; obj.maxDistance = 8f; obj.Play(); if (_footstepClip != null) { Object.Destroy((Object)(object)val4, AudioPlayUtil.PlayLifetimeSeconds(_footstepClip, pitch)); } else { Object.Destroy((Object)(object)val4, 0.5f); } } } public class TestCrashSystem : MonoBehaviour { [CompilerGenerated] private sealed class d__9 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; private IEnumerator 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__9(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; } else { <>1__state = -1; 5__2 = SendTestCrashReport(); } bool flag; try { flag = 5__2.MoveNext(); } catch (Exception ex) { LoggingService.LogWarning("[Dread TestCrash] Report coroutine failed: " + ex.Message); goto IL_006f; } if (flag) { <>2__current = 5__2.Current; <>1__state = 1; return true; } goto IL_006f; IL_006f: ExitProcess(); 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(); } } [CompilerGenerated] private sealed class d__10 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; InvalidOperationException ex = new InvalidOperationException("[Dread TestCrash] Game crashed deliberately via the 'Crash Game' config button to verify error reporting."); Debug.LogException((Exception)ex); ErrorReporterSystem errorReporterSystem = Object.FindObjectOfType(); if (errorReporterSystem != null) { <>2__current = errorReporterSystem.ReportTestCrashAndWait(ex); <>1__state = 1; return true; } LoggingService.LogWarning("[Dread TestCrash] ErrorReporterSystem not found; no report sent."); break; } case 1: <>1__state = -1; break; } 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 TestCrashSystem? _instance; private bool _pendingCrash; private void Awake() { _instance = this; } private void Start() { DreadConfig.TestCrashButton.SettingChanged += OnTestCrashRequested; } private void OnDestroy() { DreadConfig.TestCrashButton.SettingChanged -= OnTestCrashRequested; if (_instance == this) { _instance = null; } } private void OnTestCrashRequested(object? sender, EventArgs e) { if (DreadConfig.TestCrashButton.Value) { DreadConfig.TestCrashButton.Value = false; QueueCrash(); } } private void Update() { if (_pendingCrash) { _pendingCrash = false; ((MonoBehaviour)this).StartCoroutine(CrashSequence()); } } public static void TriggerForDebug() { if (_instance != null) { _instance.QueueCrash(); return; } throw new InvalidOperationException("[Dread TestCrash] TestCrashSystem not initialized (load into a level first)."); } private void QueueCrash() { _pendingCrash = true; } [IteratorStateMachine(typeof(d__9))] private IEnumerator CrashSequence() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__9(0); } [IteratorStateMachine(typeof(d__10))] private static IEnumerator SendTestCrashReport() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__10(0); } private static void ExitProcess() { LoggingService.LogInfo("[Dread TestCrash] Exiting game process now."); Process.GetCurrentProcess().Kill(); } } internal static class UnityWebRequestCompat { private static bool _probed; private static bool _usable; internal static bool IsUsable { get { if (!_probed) { Probe(); } return _usable; } } private static void Probe() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown _probed = true; try { UnityWebRequest val = new UnityWebRequest("http://127.0.0.1/", "HEAD"); try { _ = val.method; _usable = true; } finally { ((IDisposable)val)?.Dispose(); } } catch (BadImageFormatException) { _usable = false; LoggingService.LogWarning("[Dread] UnityWebRequest unavailable (stub/zero-RVA build); using HTTP/NVorbis-only paths."); } catch (Exception ex2) { _usable = false; LoggingService.LogVerbose("[Dread] UnityWebRequest probe failed: " + ex2.Message); } } } } namespace Dread.Config { public static class DreadConfig { private static ConfigFile? _configFile; public static ConfigEntry AudioEnabled; public static ConfigEntry AudioFrequency; public static ConfigEntry AudioVolume; public static ConfigEntry MonsterAggressionEnabled; public static ConfigEntry MonsterAudioEnabled; public static ConfigEntry FakeFootstepsEnabled; public static ConfigEntry AdrenalineEnabled; public static ConfigEntry LowStaminaSoundEnabled; public static ConfigEntry PanicSprintEnabled; public static ConfigEntry PsychoticBreakEnabled; public static ConfigEntry PsychoticBreakTriggerChance; public static ConfigEntry PsychoticBreakDuration; public static ConfigEntry PsychoticBreakOncePerMatch; public static ConfigEntry CrouchSpeedBoostEnabled; public static ConfigEntry CompatibilityMode; public static ConfigEntry CompatibilitySkipConflictingPatches; public static ConfigEntry DebugConsoleGuardEnabled; public static ConfigEntry ErrorReportingEnabled; public static ConfigEntry ErrorReportingPromptShown; public static ConfigEntry DebugOverlayEnabled; public static ConfigEntry DebugServerEnabled; public static ConfigEntry DebugServerPort; public static ConfigEntry LogLevelEntry; public static ConfigEntry TestCrashButton; private static bool _initialized; public static void Initialize(ConfigFile cfg) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown //IL_02e2: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Expected O, but got Unknown //IL_0338: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Expected O, but got Unknown if (_initialized) { return; } _configFile = cfg; AudioEnabled = cfg.Bind("1. Audio Dread", "Enabled", true, "Ambient horror sounds during runs."); AudioFrequency = cfg.Bind("1. Audio Dread", "Frequency", 1f, new ConfigDescription("Sound frequency multiplier. 1 = default, 2 = twice as often.", (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); AudioVolume = cfg.Bind("1. Audio Dread", "Volume", 0.4f, new ConfigDescription("Ambient sound volume (0.0 - 1.0).", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); MonsterAggressionEnabled = cfg.Bind("2. Monster Overhaul", "AggressionEnabled", true, "Increase monster speed. HOST ONLY."); MonsterAudioEnabled = cfg.Bind("2. Monster Overhaul", "AudioEnabled", true, "Lower monster pitch for deeper, scarier sounds."); FakeFootstepsEnabled = cfg.Bind("3. Tension", "FakeFootstepsEnabled", true, "Occasionally plays footstep sounds behind you with no source."); AdrenalineEnabled = cfg.Bind("3. Tension", "AdrenalineEnabled", true, "Sprint drains up to 70% slower when an enemy is nearby (within 15m)."); LowStaminaSoundEnabled = cfg.Bind("3. Tension", "LowStaminaSoundEnabled", true, "Plays a gasp sound when sprint energy drops below 10%."); PanicSprintEnabled = cfg.Bind("3. Tension", "PanicSprintEnabled", true, "Brief 1.25x speed burst when sprinting near an enemy (within 15m). 20s cooldown."); PsychoticBreakEnabled = cfg.Bind("4. Psychotic Break", "PsychoticBreakEnabled", true, "Master toggle for the Psychotic Break system."); PsychoticBreakTriggerChance = cfg.Bind("4. Psychotic Break", "PsychoticBreakTriggerChance", 0.01f, new ConfigDescription("Probability per 2s check (0-1). 0.01 = 1%.", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); PsychoticBreakDuration = cfg.Bind("4. Psychotic Break", "PsychoticBreakDuration", 20f, new ConfigDescription("Episode length in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange(5f, 60f), Array.Empty())); PsychoticBreakOncePerMatch = cfg.Bind("4. Psychotic Break", "PsychoticBreakOncePerMatch", true, "Limit to one episode per match."); CrouchSpeedBoostEnabled = cfg.Bind("5. QOL", "CrouchSpeedBoost", true, "Crouch movement is 30% faster."); CompatibilityMode = cfg.Bind("6. Compatibility", "CompatibilityMode", false, "Ambient audio only: disables monster Harmony patches, adrenaline/panic sprint mutation, and psychotic break. Use when another mod conflicts with Dread."); CompatibilitySkipConflictingPatches = cfg.Bind("6. Compatibility", "SkipConflictingPatches", false, "If another mod already patched the same game method, skip Dread's patch and log once."); DebugConsoleGuardEnabled = cfg.Bind("6. Compatibility", "DebugConsoleGuardEnabled", true, "Suppress NullReferenceException spam from broken DebugConsoleUI hooks (common with MenuLib/REPOConfig). Disable to see raw console errors."); ErrorReportingEnabled = cfg.Bind("7. Error Reporting", "ErrorReportingEnabled", true, ErrorReportingPrivacyCopy.FullDescription); ErrorReportingPromptShown = cfg.Bind("7. Error Reporting", "ErrorReportingPromptShown", false, "Internal: set true after first-run error reporting disclosure. Do not edit unless resetting the prompt."); DebugOverlayEnabled = cfg.Bind("8. Debug Overlay", "DebugOverlayEnabled", false, "Show an in-game IMGUI debug HUD during runs. Press F10 to toggle visibility at runtime. Hidden on menu levels."); DebugServerEnabled = cfg.Bind("9. Debug Server", "DebugServerEnabled", false, "Enable the TCP debug server for AI-assisted debugging (localhost only)."); DebugServerPort = cfg.Bind("9. Debug Server", "DebugServerPort", 15432, new ConfigDescription("Port for the debug server. Falls back to +1 if unavailable.", (AcceptableValueBase)(object)new AcceptableValueRange(1024, 65535), Array.Empty())); LogLevelEntry = cfg.Bind("10. Logging", "LogLevel", LogLevel.Debug, "Logging verbosity. None = suppress all output, Error = only errors, Debug = info + warnings + errors, Verbose = everything including debug traces."); TestCrashButton = cfg.Bind("11. Testing", "Crash Game", false, new ConfigDescription("Turn ON to deliberately crash the game and verify error reporting (resets to off). Use only when error reporting is enabled.", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { ShowAsButton = true } })); ConfigEntryBase[] array = (ConfigEntryBase[])(object)new ConfigEntryBase[24] { (ConfigEntryBase)AudioEnabled, (ConfigEntryBase)AudioFrequency, (ConfigEntryBase)AudioVolume, (ConfigEntryBase)MonsterAggressionEnabled, (ConfigEntryBase)MonsterAudioEnabled, (ConfigEntryBase)FakeFootstepsEnabled, (ConfigEntryBase)AdrenalineEnabled, (ConfigEntryBase)LowStaminaSoundEnabled, (ConfigEntryBase)PanicSprintEnabled, (ConfigEntryBase)PsychoticBreakEnabled, (ConfigEntryBase)PsychoticBreakTriggerChance, (ConfigEntryBase)PsychoticBreakDuration, (ConfigEntryBase)PsychoticBreakOncePerMatch, (ConfigEntryBase)CrouchSpeedBoostEnabled, (ConfigEntryBase)CompatibilityMode, (ConfigEntryBase)CompatibilitySkipConflictingPatches, (ConfigEntryBase)DebugConsoleGuardEnabled, (ConfigEntryBase)ErrorReportingEnabled, (ConfigEntryBase)ErrorReportingPromptShown, (ConfigEntryBase)DebugOverlayEnabled, (ConfigEntryBase)DebugServerEnabled, (ConfigEntryBase)DebugServerPort, (ConfigEntryBase)LogLevelEntry, (ConfigEntryBase)TestCrashButton }; for (int i = 0; i < array.Length; i++) { if (array[i] == null) { LoggingService.LogError($"[Dread] Config field at index {i} is null after Initialize!"); } } _initialized = true; LoggingService.LogInfo("[Dread] Config initialized successfully."); } public static void EnsureInitialized() { if (!_initialized) { LoggingService.LogError("[Dread] DreadConfig accessed before Initialize() was called!"); } } public static void SaveToDisk() { ConfigFile? configFile = _configFile; if (configFile != null) { configFile.Save(); } } } internal class ConfigurationManagerAttributes { public bool? ShowAsButton; } internal static class RepoConfigTags { public const string HideFromRepoConfig = "HideFromREPOConfig"; } }