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 <ScanLoop>d__18 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public Plugin <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ScanLoop>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<bool> enableBlocking;
private ConfigEntry<bool> showDebugOverlay;
private ConfigEntry<bool> logActions;
private ConfigEntry<bool> detectBroadGhostNames;
private ConfigEntry<float> scanInterval;
private ConfigEntry<float> overlayKeepSeconds;
private ConfigEntry<int> maxOverlayItems;
private readonly HashSet<int> processedStrongGhostScareIds = new HashSet<int>();
private readonly HashSet<int> reportedBroadGhostIds = new HashSet<int>();
private readonly List<GhostRecord> recentRecords = new List<GhostRecord>();
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<bool>("General", "EnableBlocking", true, "If true, disables Ability_Ghost_*_Scare objects. If false, only detects them.");
showDebugOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "ShowDebugOverlay", false, "Show detected or blocked ghost scare objects on screen.");
logActions = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogActions", false, "Write detected or blocked ghost scare objects to BepInEx/LogOutput.log.");
detectBroadGhostNames = ((BaseUnityPlugin)this).Config.Bind<bool>("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<float>("Performance", "ScanInterval", 1f, "How often to scan loaded scenes for ghost scare triggers.");
overlayKeepSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Overlay", "OverlayKeepSeconds", 12f, "How long the on-screen overlay remains visible after the latest detection or block.");
maxOverlayItems = ((BaseUnityPlugin)this).Config.Bind<int>("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(<ScanLoop>d__18))]
private IEnumerator ScanLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ScanLoop>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;
}
}