using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("No Ghost Scares")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("No Ghost Scares")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("7d9b1509-8e9d-4dcd-9c8f-d9bd2c037790")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace NoGhostScares; [BepInPlugin("kumo.sulfur.no_ghost_scares", "No Ghost Scares", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { private sealed class GhostRecord { public string TimeText; public string Action; public string Category; public string ObjectName; public string Path; public bool ActiveSelf; public bool ActiveInHierarchy; } [CompilerGenerated] private sealed class d__18 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Plugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__18(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } <>4__this.ScanLoadedScenes(); <>2__current = (object)new WaitForSeconds(Mathf.Max(0.2f, <>4__this.scanInterval.Value)); <>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(); } } internal static ManualLogSource Log; private ConfigEntry enableBlocking; private ConfigEntry showDebugOverlay; private ConfigEntry logActions; private ConfigEntry detectBroadGhostNames; private ConfigEntry scanInterval; private ConfigEntry overlayKeepSeconds; private ConfigEntry maxOverlayItems; private readonly HashSet processedStrongGhostScareIds = new HashSet(); private readonly HashSet reportedBroadGhostIds = new HashSet(); private readonly List recentRecords = new List(); private float lastRecordTime = -9999f; private GUIStyle titleStyle; private GUIStyle textStyle; private GUIStyle smallTextStyle; private GUIStyle boxStyle; private static readonly string[] BroadGhostKeywords = new string[8] { "Ghost", "Wraith", "Poltergeist", "Apparition", "Scare", "Haunt", "Specter", "Spectre" }; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; enableBlocking = ((BaseUnityPlugin)this).Config.Bind("General", "EnableBlocking", true, "If true, disables Ability_Ghost_*_Scare objects. If false, only detects them."); showDebugOverlay = ((BaseUnityPlugin)this).Config.Bind("Debug", "ShowDebugOverlay", false, "Show detected or blocked ghost scare objects on screen."); logActions = ((BaseUnityPlugin)this).Config.Bind("Debug", "LogActions", false, "Write detected or blocked ghost scare objects to BepInEx/LogOutput.log."); detectBroadGhostNames = ((BaseUnityPlugin)this).Config.Bind("Debug", "DetectBroadGhostNames", false, "Debug only. Also show broad ghost-related names like GhostParticles or Unit_Enemy_Ghost. These are never blocked."); scanInterval = ((BaseUnityPlugin)this).Config.Bind("Performance", "ScanInterval", 1f, "How often to scan loaded scenes for ghost scare triggers."); overlayKeepSeconds = ((BaseUnityPlugin)this).Config.Bind("Overlay", "OverlayKeepSeconds", 12f, "How long the on-screen overlay remains visible after the latest detection or block."); maxOverlayItems = ((BaseUnityPlugin)this).Config.Bind("Overlay", "MaxOverlayItems", 8, "Maximum number of recent records shown on screen."); ((MonoBehaviour)this).StartCoroutine(ScanLoop()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"No Ghost Scares 1.0.0 loaded."); } [IteratorStateMachine(typeof(d__18))] private IEnumerator ScanLoop() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__18(0) { <>4__this = this }; } private void ScanLoadedScenes() { //IL_0007: 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) for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); if (((Scene)(ref sceneAt)).IsValid() && ((Scene)(ref sceneAt)).isLoaded) { GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects(); GameObject[] array = rootGameObjects; foreach (GameObject val in array) { ScanTransform(val.transform); } } } } private void ScanTransform(Transform transform) { if ((Object)(object)transform == (Object)null) { return; } GameObject gameObject = ((Component)transform).gameObject; if ((Object)(object)gameObject == (Object)null) { return; } string name = ((Object)gameObject).name; if (IsStrongGhostScareObject(name)) { ProcessStrongGhostScare(gameObject); return; } if (detectBroadGhostNames.Value && IsBroadGhostRelatedObject(name)) { ReportBroadGhostRelatedObject(gameObject); } for (int i = 0; i < transform.childCount; i++) { ScanTransform(transform.GetChild(i)); } } private void ProcessStrongGhostScare(GameObject go) { if ((Object)(object)go == (Object)null) { return; } int instanceID = ((Object)go).GetInstanceID(); if (processedStrongGhostScareIds.Contains(instanceID)) { return; } processedStrongGhostScareIds.Add(instanceID); if (enableBlocking.Value) { AddRecord("BLOCKED", "StrongGhostScare", ((Object)go).name, GetPath(go), go.activeSelf, go.activeInHierarchy); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Blocked ghost scare object: " + GetPath(go))); } go.SetActive(false); Object.Destroy((Object)(object)go); } else { AddRecord("DETECTED_ONLY", "StrongGhostScare", ((Object)go).name, GetPath(go), go.activeSelf, go.activeInHierarchy); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Detected ghost scare object, blocking disabled: " + GetPath(go))); } } } private void ReportBroadGhostRelatedObject(GameObject go) { if ((Object)(object)go == (Object)null) { return; } int instanceID = ((Object)go).GetInstanceID(); if (!reportedBroadGhostIds.Contains(instanceID)) { reportedBroadGhostIds.Add(instanceID); AddRecord("DEBUG_ONLY", "BroadGhostRelated", ((Object)go).name, GetPath(go), go.activeSelf, go.activeInHierarchy); if (logActions.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)("Debug-only broad ghost related object: " + GetPath(go))); } } } private void AddRecord(string action, string category, string objectName, string path, bool activeSelf, bool activeInHierarchy) { GhostRecord item = new GhostRecord { TimeText = DateTime.Now.ToString("HH:mm:ss"), Action = action, Category = category, ObjectName = objectName, Path = path, ActiveSelf = activeSelf, ActiveInHierarchy = activeInHierarchy }; recentRecords.Insert(0, item); int num = Mathf.Max(12, maxOverlayItems.Value * 3); while (recentRecords.Count > num) { recentRecords.RemoveAt(recentRecords.Count - 1); } lastRecordTime = Time.realtimeSinceStartup; } private static bool IsStrongGhostScareObject(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } return objectName.IndexOf("Ability_Ghost_", StringComparison.OrdinalIgnoreCase) >= 0 && objectName.IndexOf("_Scare", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsBroadGhostRelatedObject(string objectName) { if (string.IsNullOrEmpty(objectName)) { return false; } string[] broadGhostKeywords = BroadGhostKeywords; foreach (string value in broadGhostKeywords) { if (objectName.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return true; } } return false; } private void OnGUI() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) if (!showDebugOverlay.Value || recentRecords.Count == 0) { return; } float num = Time.realtimeSinceStartup - lastRecordTime; if (!(num > overlayKeepSeconds.Value)) { EnsureGuiStyles(); int num2 = Mathf.Min(Mathf.Max(1, maxOverlayItems.Value), recentRecords.Count); float num3 = 820f; float num4 = 22f; float num5 = 112f + (float)num2 * 58f; Rect val = default(Rect); ((Rect)(ref val))..ctor(20f, 20f, num3, num5); GUI.Box(val, GUIContent.none, boxStyle); float num6 = ((Rect)(ref val)).x + 14f; float num7 = ((Rect)(ref val)).y + 12f; string text = (enableBlocking.Value ? "BLOCKING ON" : "BLOCKING OFF / DETECT ONLY"); GUI.Label(new Rect(num6, num7, num3 - 28f, 26f), "NO GHOST SCARES DEBUG - " + text, titleStyle); num7 += 28f; string text2 = (enableBlocking.Value ? "Detected Ability_Ghost_*_Scare objects are being blocked." : "Detected Ability_Ghost_*_Scare objects are only shown. They are not blocked."); GUI.Label(new Rect(num6, num7, num3 - 28f, 22f), text2, smallTextStyle); num7 += 28f; GUI.Label(new Rect(num6, num7, num3 - 28f, 22f), "Recent records: " + recentRecords.Count + " | Showing: " + num2, textStyle); num7 += 28f; for (int i = 0; i < num2; i++) { GhostRecord ghostRecord = recentRecords[i]; string text3 = "[" + ghostRecord.TimeText + "] " + ghostRecord.Action + " | " + ghostRecord.Category + " | " + ghostRecord.ObjectName + " | active=" + ghostRecord.ActiveInHierarchy; string text4 = ShortenPath(ghostRecord.Path, 120); GUI.Label(new Rect(num6, num7, num3 - 28f, num4), text3, textStyle); num7 += num4; GUI.Label(new Rect(num6, num7, num3 - 28f, 34f), text4, smallTextStyle); num7 += 36f; } } } private void EnsureGuiStyles() { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0041: 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_0061: Expected O, but got Unknown //IL_007a: 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_009a: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) if (titleStyle == null) { titleStyle = new GUIStyle(GUI.skin.label); titleStyle.fontSize = 18; titleStyle.normal.textColor = Color.white; textStyle = new GUIStyle(GUI.skin.label); textStyle.fontSize = 14; textStyle.normal.textColor = Color.white; smallTextStyle = new GUIStyle(GUI.skin.label); smallTextStyle.fontSize = 12; smallTextStyle.wordWrap = true; smallTextStyle.normal.textColor = Color.white; boxStyle = new GUIStyle(GUI.skin.box); boxStyle.normal.textColor = Color.white; } } private static string ShortenPath(string path, int maxLength) { if (string.IsNullOrEmpty(path)) { return string.Empty; } if (path.Length <= maxLength) { return path; } int num = maxLength / 2 - 4; int num2 = maxLength - num - 6; if (num <= 0 || num2 <= 0) { return path.Substring(0, maxLength); } return path.Substring(0, num) + " ... " + path.Substring(path.Length - num2); } private static string GetPath(GameObject go) { if ((Object)(object)go == (Object)null) { return string.Empty; } string text = ((Object)go).name; Transform parent = go.transform.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } }