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("NoAbomination")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NoAbomination")]
[assembly: AssemblyCopyright("Copyright © 2026")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("455c9416-1048-44be-96cf-cd45598d67b4")]
[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 NoForestAmbush;
[BepInPlugin("kumo.sulfur.no_forest_ambush", "No Forest Ambush", "1.3.0")]
public sealed class Plugin : BaseUnityPlugin
{
[CompilerGenerated]
private sealed class <CleanupBurst>d__14 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public string reason;
public Plugin <>4__this;
private int <iterations>5__1;
private float <interval>5__2;
private int <i>5__3;
private int <neutralized>5__4;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <CleanupBurst>d__14(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
<>4__this.cleanupBurstRunning = true;
if (<>4__this.logActions.Value)
{
((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Starting Forest Ambush cleanup burst: " + reason));
}
<iterations>5__1 = Mathf.Max(1, <>4__this.cleanupBurstIterations.Value);
<interval>5__2 = Mathf.Max(0.05f, <>4__this.cleanupBurstInterval.Value);
<i>5__3 = 0;
break;
case 1:
<>1__state = -1;
<i>5__3++;
break;
}
if (<i>5__3 < <iterations>5__1)
{
<neutralized>5__4 = <>4__this.NeutralizeForestAmbushObjectsInLoadedScenes();
if (<>4__this.logActions.Value && <neutralized>5__4 > 0)
{
((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Cleanup pass neutralized Forest Ambush objects: " + <neutralized>5__4));
}
<>2__current = (object)new WaitForSeconds(<interval>5__2);
<>1__state = 1;
return true;
}
<>4__this.cleanupBurstRunning = false;
if (<>4__this.logActions.Value)
{
((BaseUnityPlugin)<>4__this).Logger.LogInfo((object)("Finished Forest Ambush cleanup burst: " + reason));
}
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 <SceneSignatureWatchLoop>d__11 : IEnumerator<object>, IDisposable, IEnumerator
{
private int <>1__state;
private object <>2__current;
public Plugin <>4__this;
private int <currentSignature>5__1;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <SceneSignatureWatchLoop>d__11(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
switch (<>1__state)
{
default:
return false;
case 0:
<>1__state = -1;
break;
case 1:
<>1__state = -1;
<currentSignature>5__1 = <>4__this.ComputeSceneSignature();
if (<currentSignature>5__1 != <>4__this.lastSceneSignature)
{
<>4__this.lastSceneSignature = <currentSignature>5__1;
<>4__this.StartCleanupBurst("scene hierarchy changed");
}
break;
}
<>2__current = (object)new WaitForSeconds(Mathf.Max(0.25f, <>4__this.sceneSignatureCheckInterval.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> logActions;
private ConfigEntry<float> sceneSignatureCheckInterval;
private ConfigEntry<int> cleanupBurstIterations;
private ConfigEntry<float> cleanupBurstInterval;
private int lastSceneSignature;
private bool cleanupBurstRunning;
private readonly HashSet<int> neutralizedAmbushIds = new HashSet<int>();
private void Awake()
{
Log = ((BaseUnityPlugin)this).Logger;
logActions = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "LogActions", false, "Log neutralized Forest Ambush objects.");
sceneSignatureCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "SceneSignatureCheckInterval", 1f, "How often to cheaply check whether the loaded scene hierarchy changed.");
cleanupBurstIterations = ((BaseUnityPlugin)this).Config.Bind<int>("Performance", "CleanupBurstIterations", 24, "How many cleanup passes to run after a scene hierarchy change.");
cleanupBurstInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "CleanupBurstInterval", 0.2f, "Delay between cleanup passes during a cleanup burst.");
SceneManager.sceneLoaded += OnSceneLoaded;
lastSceneSignature = ComputeSceneSignature();
StartCleanupBurst("startup");
((MonoBehaviour)this).StartCoroutine(SceneSignatureWatchLoop());
((BaseUnityPlugin)this).Logger.LogInfo((object)"No Forest Ambush 1.3.0 loaded.");
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
neutralizedAmbushIds.Clear();
lastSceneSignature = ComputeSceneSignature();
StartCleanupBurst("scene loaded");
}
[IteratorStateMachine(typeof(<SceneSignatureWatchLoop>d__11))]
private IEnumerator SceneSignatureWatchLoop()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <SceneSignatureWatchLoop>d__11(0)
{
<>4__this = this
};
}
private int ComputeSceneSignature()
{
//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)
int num = 17;
num = num * 31 + SceneManager.sceneCount;
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene sceneAt = SceneManager.GetSceneAt(i);
if (((Scene)(ref sceneAt)).IsValid() && ((Scene)(ref sceneAt)).isLoaded)
{
num = num * 31 + ((Scene)(ref sceneAt)).name.GetHashCode();
num = num * 31 + ((Scene)(ref sceneAt)).rootCount;
}
}
return num;
}
private void StartCleanupBurst(string reason)
{
if (!cleanupBurstRunning)
{
((MonoBehaviour)this).StartCoroutine(CleanupBurst(reason));
}
}
[IteratorStateMachine(typeof(<CleanupBurst>d__14))]
private IEnumerator CleanupBurst(string reason)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <CleanupBurst>d__14(0)
{
<>4__this = this,
reason = reason
};
}
private int NeutralizeForestAmbushObjectsInLoadedScenes()
{
//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)
int num = 0;
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)
{
num += ScanTransformForForestAmbush(val.transform);
}
}
}
return num;
}
private int ScanTransformForForestAmbush(Transform transform)
{
if ((Object)(object)transform == (Object)null)
{
return 0;
}
GameObject gameObject = ((Component)transform).gameObject;
if ((Object)(object)gameObject == (Object)null)
{
return 0;
}
if (IsForestAmbushRootName(((Object)gameObject).name))
{
int instanceID = ((Object)gameObject).GetInstanceID();
if (neutralizedAmbushIds.Contains(instanceID))
{
return 0;
}
neutralizedAmbushIds.Add(instanceID);
NeutralizeForestAmbushRoot(gameObject);
return 1;
}
int num = 0;
for (int num2 = transform.childCount - 1; num2 >= 0; num2--)
{
num += ScanTransformForForestAmbush(transform.GetChild(num2));
}
return num;
}
private void NeutralizeForestAmbushRoot(GameObject ambushRoot)
{
if ((Object)(object)ambushRoot == (Object)null)
{
return;
}
Transform val = ambushRoot.transform.Find("Contents");
if ((Object)(object)val == (Object)null)
{
if (logActions.Value)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("Forest Ambush has no Contents: " + GetPath(ambushRoot)));
}
return;
}
GameObject gameObject = ((Component)val).gameObject;
DisableBehaviourComponentByTypeName(gameObject, "Animator");
DisableBehaviourComponentByTypeName(gameObject, "AudioSource");
for (int num = val.childCount - 1; num >= 0; num--)
{
Transform child = val.GetChild(num);
if (!((Object)(object)child == (Object)null))
{
GameObject gameObject2 = ((Component)child).gameObject;
string name = ((Object)gameObject2).name;
if (ShouldDisableAmbushVisualObject(name))
{
if (logActions.Value)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("Disabled Forest Ambush visual object: " + GetPath(gameObject2)));
}
gameObject2.SetActive(false);
}
}
}
if (logActions.Value)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("Neutralized Forest Ambush visuals only: " + GetPath(ambushRoot)));
}
}
private static bool ShouldDisableAmbushVisualObject(string objectName)
{
if (string.IsNullOrEmpty(objectName))
{
return false;
}
if (objectName.StartsWith("Tree", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (objectName.IndexOf("Particles", StringComparison.OrdinalIgnoreCase) >= 0)
{
return true;
}
return false;
}
private static bool IsForestAmbushRootName(string objectName)
{
if (string.IsNullOrEmpty(objectName))
{
return false;
}
return objectName.IndexOf("Event_Forest_Ambush", StringComparison.OrdinalIgnoreCase) >= 0 || objectName.IndexOf("Forest_Ambush", StringComparison.OrdinalIgnoreCase) >= 0;
}
private static void DisableBehaviourComponentByTypeName(GameObject go, string typeName)
{
if ((Object)(object)go == (Object)null || string.IsNullOrEmpty(typeName))
{
return;
}
Component[] components = go.GetComponents<Component>();
Component[] array = components;
foreach (Component val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
Type type = ((object)val).GetType();
if (string.Equals(type.Name, typeName, StringComparison.OrdinalIgnoreCase))
{
Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null);
if ((Object)(object)val2 != (Object)null)
{
val2.enabled = false;
}
}
}
}
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;
}
}