Decompiled source of Unfair Enemies Tweaks v1.0.0

BepInEx/plugins/UnfairMonsters.dll

Decompiled a month ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
using UnityEngine.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp-firstpass")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: IgnoresAccessChecksTo("Autodesk.Fbx")]
[assembly: IgnoresAccessChecksTo("Facepunch.Steamworks.Win64")]
[assembly: IgnoresAccessChecksTo("FbxBuildTestAssets")]
[assembly: IgnoresAccessChecksTo("Klattersynth")]
[assembly: IgnoresAccessChecksTo("Photon3Unity3D")]
[assembly: IgnoresAccessChecksTo("PhotonChat")]
[assembly: IgnoresAccessChecksTo("PhotonRealtime")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking")]
[assembly: IgnoresAccessChecksTo("PhotonUnityNetworking.Utilities")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.API")]
[assembly: IgnoresAccessChecksTo("PhotonVoice")]
[assembly: IgnoresAccessChecksTo("PhotonVoice.PUN")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime")]
[assembly: IgnoresAccessChecksTo("SingularityGroup.HotReload.Runtime.Public")]
[assembly: IgnoresAccessChecksTo("Sirenix.OdinInspector.Attributes")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization.Config")]
[assembly: IgnoresAccessChecksTo("Sirenix.Serialization")]
[assembly: IgnoresAccessChecksTo("Sirenix.Utilities")]
[assembly: IgnoresAccessChecksTo("Unity.AI.Navigation")]
[assembly: IgnoresAccessChecksTo("Unity.Formats.Fbx.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem")]
[assembly: IgnoresAccessChecksTo("Unity.InputSystem.ForUI")]
[assembly: IgnoresAccessChecksTo("Unity.Postprocessing.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.Core.ShaderLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary")]
[assembly: IgnoresAccessChecksTo("Unity.TextMeshPro")]
[assembly: IgnoresAccessChecksTo("Unity.Timeline")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Antlr3.Runtime")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Core")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.Flow")]
[assembly: IgnoresAccessChecksTo("Unity.VisualScripting.State")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ARModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.NVIDIAModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UI")]
[assembly: IgnoresAccessChecksTo("websocket-sharp")]
[assembly: AssemblyCompany("PlusBlankPlus")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("VisionMonsters")]
[assembly: AssemblyTitle("VisionMonsters")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
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 VisionMonsters
{
	public class EnemyAIHelper : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <ScanLoop>d__13 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public EnemyAIHelper <>4__this;

			object? IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object? IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ScanLoop>d__13(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_009d: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Expected O, but got Unknown
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0088: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (Plugin.RadarScanInterval == null)
					{
						ManualLogSource? log = <>4__this._log;
						if (log != null)
						{
							log.LogError((object)"ScanLoop cannot start: RadarScanInterval config is null.");
						}
						return false;
					}
					if (<>4__this.scanWaitSeconds == null)
					{
						<>4__this.scanWaitSeconds = new WaitForSeconds(Plugin.RadarScanInterval.Value);
					}
					<>2__current = (object)new WaitForSeconds(Random.Range(1f, Plugin.RadarScanInterval.Value));
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					break;
				case 2:
					<>1__state = -1;
					break;
				}
				if (((Behaviour)<>4__this).enabled && Plugin.EnableCheatingAI != null && Plugin.EnableCheatingAI.Value && SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)<>4__this.enemyRef != (Object)null && ((Behaviour)<>4__this.enemyRef).isActiveAndEnabled)
				{
					<>4__this.ScanForPlayers();
				}
				<>2__current = <>4__this.scanWaitSeconds;
				<>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();
			}
		}

		internal Enemy? enemyRef;

		private Coroutine? _scanCoroutine;

		private ManualLogSource? _log;

		public Vector3 lastKnownPlayerPosition = Vector3.zero;

		public float timeSincePlayerKnown = float.MaxValue;

		public bool hasMemory = false;

		private WaitForSeconds? scanWaitSeconds;

		private void Awake()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: Expected O, but got Unknown
			_log = Plugin.Log;
			enemyRef = ((Component)this).GetComponent<Enemy>();
			if ((Object)(object)enemyRef == (Object)null)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogError((object)("EnemyAIHelper could not find Enemy component on " + ((Object)((Component)this).gameObject).name));
				}
				((Behaviour)this).enabled = false;
			}
			else if (Plugin.RadarScanInterval == null || Plugin.MemoryDuration == null || Plugin.RadarScanRadius == null || Plugin.EnableCheatingAI == null)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)("EnemyAIHelper cannot run on " + ((Object)((Component)this).gameObject).name + ": required config entries are null."));
				}
				((Behaviour)this).enabled = false;
			}
			else
			{
				scanWaitSeconds = new WaitForSeconds(Plugin.RadarScanInterval.Value);
				timeSincePlayerKnown = float.MaxValue;
			}
		}

		private void OnEnable()
		{
			//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)
			if (((Behaviour)this).enabled)
			{
				lastKnownPlayerPosition = Vector3.zero;
				timeSincePlayerKnown = float.MaxValue;
				hasMemory = false;
				if (_scanCoroutine == null && (Object)(object)enemyRef != (Object)null)
				{
					_scanCoroutine = ((MonoBehaviour)this).StartCoroutine(ScanLoop());
				}
			}
		}

		private void OnDisable()
		{
			if (_scanCoroutine != null)
			{
				((MonoBehaviour)this).StopCoroutine(_scanCoroutine);
				_scanCoroutine = null;
			}
		}

		private void Update()
		{
			if (!((Behaviour)this).enabled || (Object)(object)enemyRef == (Object)null || Plugin.EnableCheatingAI == null || !Plugin.EnableCheatingAI.Value || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			if (hasMemory)
			{
				if (Plugin.MemoryDuration != null)
				{
					timeSincePlayerKnown += Time.deltaTime;
					if (timeSincePlayerKnown >= Plugin.MemoryDuration.Value)
					{
						hasMemory = false;
					}
				}
				else
				{
					hasMemory = false;
				}
			}
			if (HasFreshMemory())
			{
				TryForceInvestigation();
			}
		}

		public void UpdateMemory(Vector3 position)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			if (((Behaviour)this).enabled && Plugin.EnableCheatingAI != null && Plugin.EnableCheatingAI.Value)
			{
				lastKnownPlayerPosition = position;
				timeSincePlayerKnown = 0f;
				hasMemory = true;
			}
		}

		public bool HasFreshMemory()
		{
			if (!((Behaviour)this).enabled || Plugin.MemoryDuration == null)
			{
				return false;
			}
			return hasMemory && timeSincePlayerKnown < Plugin.MemoryDuration.Value;
		}

		[IteratorStateMachine(typeof(<ScanLoop>d__13))]
		private IEnumerator ScanLoop()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ScanLoop>d__13(0)
			{
				<>4__this = this
			};
		}

		private void ScanForPlayers()
		{
			//IL_004e: 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_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemyRef == (Object)null || (Object)(object)enemyRef.CenterTransform == (Object)null || Plugin.RadarScanRadius == null)
			{
				return;
			}
			float value = Plugin.RadarScanRadius.Value;
			Vector3 position = enemyRef.CenterTransform.position;
			PlayerAvatar val = null;
			float num = float.MaxValue;
			Collider[] array = Physics.OverlapSphere(position, value, LayerMask.GetMask(new string[1] { "Player" }), (QueryTriggerInteraction)1);
			Collider[] array2 = array;
			foreach (Collider val2 in array2)
			{
				if (((Component)val2).transform.IsChildOf(((Component)enemyRef).transform))
				{
					continue;
				}
				PlayerAvatar componentInParent = ((Component)val2).GetComponentInParent<PlayerAvatar>();
				if ((Object)(object)componentInParent != (Object)null && !componentInParent.isDisabled)
				{
					Vector3 val3 = ((Component)componentInParent).transform.position - position;
					float sqrMagnitude = ((Vector3)(ref val3)).sqrMagnitude;
					if (sqrMagnitude < num)
					{
						num = sqrMagnitude;
						val = componentInParent;
					}
				}
			}
			if ((Object)(object)val != (Object)null)
			{
				UpdateMemory(((Component)val).transform.position);
			}
		}

		private void TryForceInvestigation()
		{
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Invalid comparison between Unknown and I4
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_014b: 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_0118: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)enemyRef == (Object)null || (Object)(object)EnemyDirector.instance == (Object)null || !hasMemory || !CanInterruptForInvestigation(enemyRef.CurrentState))
			{
				return;
			}
			float num = Vector3.Distance(((Component)enemyRef).transform.position, lastKnownPlayerPosition);
			if (!(num > 5f))
			{
				return;
			}
			if ((int)enemyRef.CurrentState == 7)
			{
				EnemyNavMeshAgent navMeshAgent = enemyRef.NavMeshAgent;
				if (navMeshAgent != null && navMeshAgent.HasPath())
				{
					if (!(Vector3.Distance(enemyRef.NavMeshAgent.Agent.destination, lastKnownPlayerPosition) > 3f))
					{
						return;
					}
					if ((Object)(object)enemyRef.StateInvestigate != (Object)null)
					{
						enemyRef.StateInvestigate.Set(lastKnownPlayerPosition);
						return;
					}
					EnemyNavMeshAgent navMeshAgent2 = enemyRef.NavMeshAgent;
					if (navMeshAgent2 != null)
					{
						navMeshAgent2.SetDestination(lastKnownPlayerPosition);
					}
					return;
				}
			}
			if ((Object)(object)enemyRef.StateInvestigate != (Object)null)
			{
				enemyRef.StateInvestigate.Set(lastKnownPlayerPosition);
			}
			else
			{
				EnemyDirector.instance.SetInvestigate(lastKnownPlayerPosition, 10f);
			}
		}

		private bool CanInterruptForInvestigation(EnemyState currentState)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: 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_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected I4, but got Unknown
			switch (currentState - 1)
			{
			case 1:
			case 5:
			case 6:
				return true;
			case 0:
			case 2:
			case 3:
			case 4:
			case 8:
			case 9:
			case 10:
				return false;
			default:
				return true;
			}
		}
	}
	public enum Formation
	{
		Line,
		Triangle,
		Box,
		Circle,
		Loose
	}
	public class EnemyGroup
	{
		public Enemy? Leader { get; private set; }

		public List<GroupAIHelper> Followers { get; private set; } = new List<GroupAIHelper>();


		public Formation CurrentFormation { get; set; }

		public Vector3 CurrentPatrolTarget { get; set; }

		public EnemyType GroupEnemyType { get; private set; }

		public bool IsValid { get; private set; } = true;


		public EnemyGroup(Enemy leader, Formation formation)
		{
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)leader == (Object)null)
			{
				throw new ArgumentNullException("leader");
			}
			Leader = leader;
			GroupEnemyType = leader.Type;
			CurrentFormation = formation;
			CurrentPatrolTarget = ((Component)leader).transform.position;
		}

		public void AddFollower(GroupAIHelper follower)
		{
			if ((Object)(object)follower != (Object)null && (Object)(object)Leader != (Object)null && (Object)(object)follower.enemyRef != (Object)(object)Leader && !Followers.Contains(follower))
			{
				Followers.Add(follower);
				follower.AssignToGroup(this, isLeader: false);
			}
		}

		public void RemoveMember(GroupAIHelper member)
		{
			if ((Object)(object)member != (Object)null && Followers.Remove(member))
			{
				if (Plugin.MinGroupSize != null && Followers.Count < Plugin.MinGroupSize.Value - 1)
				{
					DisbandGroup();
				}
				else
				{
					AssignFormationOffsets();
				}
			}
		}

		public void DisbandGroup()
		{
			if (!IsValid)
			{
				return;
			}
			IsValid = false;
			Enemy? leader = Leader;
			if (leader != null)
			{
				((Component)leader).GetComponent<GroupAIHelper>()?.LeaveGroup();
			}
			Leader = null;
			foreach (GroupAIHelper item in Followers.ToList())
			{
				item?.LeaveGroup();
			}
			Followers.Clear();
		}

		public void AssignFormationOffsets()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: 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_02e5: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)Leader == (Object)null || !IsValid)
			{
				return;
			}
			int count = Followers.Count;
			float num = 2.5f;
			GroupAIHelper component = ((Component)Leader).GetComponent<GroupAIHelper>();
			if ((Object)(object)component == (Object)null)
			{
				DisbandGroup();
				return;
			}
			component.SetFormationOffset(Vector3.zero);
			component.AssignToGroup(this, isLeader: true);
			Formation formation = CurrentFormation;
			bool flag = count >= 2;
			bool flag2 = count >= 3;
			if (formation == Formation.Triangle && !flag)
			{
				formation = Formation.Line;
			}
			if (formation == Formation.Box && !flag2)
			{
				formation = Formation.Triangle;
			}
			if (formation == Formation.Triangle && !flag)
			{
				formation = Formation.Line;
			}
			for (int i = 0; i < count; i++)
			{
				Vector3 zero = Vector3.zero;
				switch (formation)
				{
				case Formation.Line:
					((Vector3)(ref zero))..ctor(0f, 0f, (0f - num) * (float)(i + 1));
					break;
				case Formation.Triangle:
					switch (i)
					{
					case 0:
						((Vector3)(ref zero))..ctor((0f - num) * 0.8f, 0f, 0f - num);
						break;
					case 1:
						((Vector3)(ref zero))..ctor(num * 0.8f, 0f, 0f - num);
						break;
					default:
						((Vector3)(ref zero))..ctor(0f, 0f, (0f - num) * (1f + (float)(i - 1) * 0.8f));
						break;
					}
					break;
				case Formation.Box:
					switch (i)
					{
					case 0:
						((Vector3)(ref zero))..ctor(num, 0f, 0f);
						break;
					case 1:
						((Vector3)(ref zero))..ctor(0f, 0f, 0f - num);
						break;
					case 2:
						((Vector3)(ref zero))..ctor(num, 0f, 0f - num);
						break;
					default:
						((Vector3)(ref zero))..ctor(num * 0.5f, 0f, (0f - num) * (1f + (float)(i - 2) * 0.8f));
						break;
					}
					break;
				case Formation.Circle:
				{
					float num4 = 360f / (float)(count + 1);
					float num5 = num * 0.6f * (float)(count + 1) / MathF.PI;
					float num6 = (float)(i + 1) * num4 * (MathF.PI / 180f);
					((Vector3)(ref zero))..ctor(Mathf.Sin(num6) * num5, 0f, Mathf.Cos(num6) * num5 - num5 * 0.5f);
					break;
				}
				default:
				{
					float num2 = Random.Range(-75f, 75f) * (MathF.PI / 180f);
					float num3 = num * (1f + (float)i * 0.3f) * Random.Range(0.7f, 1.3f);
					((Vector3)(ref zero))..ctor(Mathf.Sin(num2) * num3 * 0.6f, 0f, (0f - Mathf.Cos(num2)) * num3);
					break;
				}
				}
				Followers[i].SetFormationOffset(zero);
				Followers[i].AssignToGroup(this, isLeader: false);
			}
		}
	}
	[RequireComponent(typeof(PhotonView))]
	public class GroupAIHelper : MonoBehaviourPun
	{
		internal Enemy? enemyRef;

		internal NavMeshAgent? agent;

		private ManualLogSource? _log;

		private PhotonView? pv;

		public EnemyGroup? CurrentGroup { get; private set; }

		public bool IsInGroup => CurrentGroup != null && CurrentGroup.IsValid;

		public bool IsLeader { get; private set; } = false;


		public Vector3 FormationOffset { get; private set; } = Vector3.zero;


		public Vector3 CurrentWorldTargetPosition { get; private set; } = Vector3.zero;


		private void Awake()
		{
			_log = Plugin.Log;
			enemyRef = ((Component)this).GetComponent<Enemy>();
			agent = ((Component)this).GetComponent<NavMeshAgent>();
			pv = ((Component)this).GetComponent<PhotonView>();
			if ((Object)(object)enemyRef == (Object)null)
			{
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogError((object)("GroupAIHelper missing Enemy on " + ((Object)((Component)this).gameObject).name));
				}
				((Behaviour)this).enabled = false;
			}
			else if ((Object)(object)pv == (Object)null)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)("GroupAIHelper missing PhotonView on " + ((Object)((Component)this).gameObject).name));
				}
				((Behaviour)this).enabled = false;
			}
			else if ((Object)(object)agent == (Object)null && enemyRef.HasNavMeshAgent)
			{
				agent = ((Component)this).GetComponentInChildren<NavMeshAgent>();
			}
		}

		private void Start()
		{
			if (((Behaviour)this).enabled && SemiFunc.IsMasterClientOrSingleplayer())
			{
				ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
				if (enableGrouping != null && enableGrouping.Value)
				{
					((MonoBehaviour)this).Invoke("RegisterWithManager", Random.Range(0.5f, 1f));
				}
			}
		}

		private void OnDestroy()
		{
			if (((Behaviour)this).enabled && SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)GroupPatrolManager.Instance != (Object)null)
			{
				ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
				if (enableGrouping != null && enableGrouping.Value)
				{
					GroupPatrolManager.Instance.UnregisterEnemy(this);
				}
			}
			LeaveGroupInternal();
		}

		private void RegisterWithManager()
		{
			if ((Object)(object)GroupPatrolManager.Instance != (Object)null && (Object)(object)enemyRef != (Object)null)
			{
				GroupPatrolManager.Instance.RegisterEnemy(this);
				return;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				Enemy? obj = enemyRef;
				log.LogError((object)("Failed to register " + ((obj != null) ? ((Object)obj).name : null) + ": GroupPatrolManager instance is null."));
			}
		}

		public void AssignToGroup(EnemyGroup group, bool isLeader)
		{
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)pv == (Object)null)
			{
				return;
			}
			CurrentGroup = group;
			IsLeader = isLeader;
			int num = (((Object)(object)group.Leader != (Object)null) ? ((MonoBehaviourPun)group.Leader).photonView.ViewID : (-1));
			if (num != -1)
			{
				pv.RPC("AssignToGroupRPC", (RpcTarget)6, new object[3] { num, isLeader, FormationOffset });
				return;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				Enemy? obj = enemyRef;
				log.LogError((object)("HOST: Cannot send AssignToGroupRPC for " + ((obj != null) ? ((Object)obj).name : null) + " because leader is null!"));
			}
		}

		[PunRPC]
		public void AssignToGroupRPC(int leaderViewID, bool isLeader, Vector3 formationOffset)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			IsLeader = isLeader;
			FormationOffset = formationOffset;
			PhotonView val = PhotonView.Find(leaderViewID);
			Enemy val2 = ((val != null) ? ((Component)val).GetComponent<Enemy>() : null);
			if ((Object)(object)val2 != (Object)null)
			{
				CurrentGroup = null;
				return;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				PhotonView? obj = pv;
				log.LogError((object)$"CLIENT {((obj != null) ? new int?(obj.ViewID) : null)}: Received AssignToGroupRPC but could not find leader with ViewID {leaderViewID}!");
			}
			LeaveGroupInternal();
		}

		public void SetFormationOffset(Vector3 offset)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			FormationOffset = offset;
		}

		public void LeaveGroup()
		{
			if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)pv == (Object)null))
			{
				if (CurrentGroup != null || IsLeader)
				{
					pv.RPC("LeaveGroupRPC", (RpcTarget)6, Array.Empty<object>());
				}
				LeaveGroupInternal();
			}
		}

		[PunRPC]
		public void LeaveGroupRPC()
		{
			LeaveGroupInternal();
		}

		private void LeaveGroupInternal()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			CurrentGroup = null;
			IsLeader = false;
			FormationOffset = Vector3.zero;
			CurrentWorldTargetPosition = Vector3.zero;
		}

		public bool TryGroupMovement()
		{
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: 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_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: 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_015e: 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_008c: 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_0176: 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_01b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Expected O, but got Unknown
			//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Invalid comparison between Unknown and I4
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Invalid comparison between Unknown and I4
			//IL_0285: Unknown result type (might be due to invalid IL or missing references)
			bool flag = !IsLeader && CurrentGroup != null && CurrentGroup.IsValid && (Object)(object)CurrentGroup.Leader != (Object)null;
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				PhotonView val = PhotonView.Find((((Component)this).GetComponent<PhotonView>().InstantiationData != null) ? ((int)((Component)this).GetComponent<PhotonView>().InstantiationData[0]) : (-1));
				flag = !IsLeader && (Object)(object)val != (Object)null;
				flag = !IsLeader && FormationOffset != Vector3.zero;
			}
			if (flag)
			{
				if (SemiFunc.IsMasterClientOrSingleplayer())
				{
					if ((Object)(object)agent == (Object)null || !((Behaviour)agent).enabled || !agent.isOnNavMesh || CurrentGroup == null || (Object)(object)CurrentGroup.Leader == (Object)null || !((Behaviour)CurrentGroup.Leader).isActiveAndEnabled)
					{
						return false;
					}
					Vector3 position = ((Component)CurrentGroup.Leader).transform.position;
					Quaternion rotation = ((Component)CurrentGroup.Leader).transform.rotation;
					Vector3 val2 = position + rotation * FormationOffset;
					NavMeshHit val3 = default(NavMeshHit);
					if (NavMesh.SamplePosition(val2, ref val3, 1f, -1))
					{
						CurrentWorldTargetPosition = ((NavMeshHit)(ref val3)).position;
					}
					else
					{
						NavMeshHit val4 = default(NavMeshHit);
						if (!NavMesh.SamplePosition(position, ref val4, 1f, -1))
						{
							return false;
						}
						CurrentWorldTargetPosition = ((NavMeshHit)(ref val4)).position;
					}
					if (Vector3.Distance(((Component)this).transform.position, CurrentWorldTargetPosition) > agent.stoppingDistance + 0.5f)
					{
						NavMeshPath val5 = new NavMeshPath();
						if (agent.CalculatePath(CurrentWorldTargetPosition, val5) && (int)val5.status == 0)
						{
							agent.SetDestination(CurrentWorldTargetPosition);
							return true;
						}
						if (Vector3.Distance(((Component)this).transform.position, position) > agent.stoppingDistance + 1f && agent.CalculatePath(position, val5) && (int)val5.status == 0)
						{
							agent.SetDestination(position);
							return true;
						}
						return false;
					}
					if (agent.hasPath)
					{
						agent.ResetPath();
					}
					return false;
				}
				if ((Object)(object)agent != (Object)null && ((Behaviour)agent).enabled && agent.isOnNavMesh && agent.hasPath)
				{
					agent.ResetPath();
				}
				return true;
			}
			return false;
		}

		public void BreakFormationTemporarily()
		{
			if (SemiFunc.IsMasterClientOrSingleplayer())
			{
				if (IsInGroup)
				{
					CurrentGroup?.RemoveMember(this);
				}
			}
			else
			{
				LeaveGroupInternal();
			}
		}
	}
	public class GroupPatrolManager : MonoBehaviour
	{
		private List<EnemyGroup> activeGroups = new List<EnemyGroup>();

		private Dictionary<EnemyType, List<GroupAIHelper>> potentialGroupMembers = new Dictionary<EnemyType, List<GroupAIHelper>>();

		private float groupCheckTimer = 0f;

		private ManualLogSource? _log;

		public static GroupPatrolManager? Instance { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this)
			{
				Object.Destroy((Object)(object)((Component)this).gameObject);
				return;
			}
			Instance = this;
			_log = Plugin.Log;
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)"GroupPatrolManager Initialized.");
			}
			if (Plugin.GroupCheckInterval == null)
			{
				ManualLogSource? log2 = _log;
				if (log2 != null)
				{
					log2.LogError((object)"GroupPatrolManager cannot run: GroupCheckInterval config is null.");
				}
				((Behaviour)this).enabled = false;
			}
			else
			{
				groupCheckTimer = Plugin.GroupCheckInterval.Value;
			}
		}

		private void OnDestroy()
		{
			if (!((Object)(object)Instance == (Object)(object)this))
			{
				return;
			}
			Instance = null;
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogInfo((object)"GroupPatrolManager Cleaning Up Groups...");
			}
			foreach (EnemyGroup item in activeGroups.ToList())
			{
				item.DisbandGroup();
			}
			activeGroups.Clear();
			potentialGroupMembers.Clear();
			ManualLogSource? log2 = _log;
			if (log2 != null)
			{
				log2.LogInfo((object)"GroupPatrolManager Destroyed.");
			}
		}

		private void Update()
		{
			if (!((Behaviour)this).enabled || !SemiFunc.IsMasterClientOrSingleplayer() || Plugin.EnableGrouping == null)
			{
				return;
			}
			if (!Plugin.EnableGrouping.Value)
			{
				if (activeGroups.Count <= 0)
				{
					return;
				}
				ManualLogSource? log = _log;
				if (log != null)
				{
					log.LogInfo((object)"Grouping disabled, disbanding...");
				}
				foreach (EnemyGroup item in activeGroups.ToList())
				{
					item.DisbandGroup();
				}
				activeGroups.Clear();
				potentialGroupMembers.Clear();
				return;
			}
			groupCheckTimer -= Time.deltaTime;
			if (groupCheckTimer <= 0f)
			{
				TryFormGroups();
				CleanupInvalidGroups();
				if (Plugin.GroupCheckInterval != null)
				{
					groupCheckTimer = Plugin.GroupCheckInterval.Value + Random.Range(-1f, 1f);
				}
				else
				{
					groupCheckTimer = 10f;
				}
			}
			UpdateGroupPatrols();
		}

		public void RegisterEnemy(GroupAIHelper helper)
		{
			//IL_002a: 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_0036: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			if (((Behaviour)this).enabled && !((Object)(object)helper?.enemyRef == (Object)null))
			{
				EnemyType type = helper.enemyRef.Type;
				if (!potentialGroupMembers.ContainsKey(type))
				{
					potentialGroupMembers[type] = new List<GroupAIHelper>();
				}
				if (!potentialGroupMembers[type].Contains(helper) && !helper.IsInGroup)
				{
					potentialGroupMembers[type].Add(helper);
				}
			}
		}

		public void UnregisterEnemy(GroupAIHelper helper)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			if (!((Behaviour)this).enabled || (Object)(object)helper?.enemyRef == (Object)null)
			{
				return;
			}
			if (helper.IsInGroup && helper.CurrentGroup != null)
			{
				if (helper.IsLeader)
				{
					helper.CurrentGroup.DisbandGroup();
				}
				else
				{
					helper.CurrentGroup.RemoveMember(helper);
				}
			}
			EnemyType type = helper.enemyRef.Type;
			if (potentialGroupMembers.ContainsKey(type))
			{
				potentialGroupMembers[type].Remove(helper);
			}
		}

		private void TryFormGroups()
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.MinGroupSize == null || Plugin.MaxGroupSize == null)
			{
				return;
			}
			int value = Plugin.MinGroupSize.Value;
			int value2 = Plugin.MaxGroupSize.Value;
			List<EnemyType> list = potentialGroupMembers.Keys.ToList();
			foreach (EnemyType item in list)
			{
				if (!potentialGroupMembers.ContainsKey(item))
				{
					continue;
				}
				List<GroupAIHelper> list2 = potentialGroupMembers[item];
				list2.RemoveAll((GroupAIHelper h) => (Object)(object)h == (Object)null || (Object)(object)h.enemyRef == (Object)null || !((Behaviour)h.enemyRef).isActiveAndEnabled || h.IsInGroup);
				while (list2.Count >= value)
				{
					int num = Mathf.Min(Random.Range(value, value2 + 1), list2.Count);
					List<GroupAIHelper> list3 = list2.Where((GroupAIHelper p) => (Object)(object)p != (Object)null && (Object)(object)p.enemyRef != (Object)null && ((Behaviour)p.enemyRef).isActiveAndEnabled && !p.IsInGroup).ToList();
					if (list3.Count < value)
					{
						break;
					}
					num = Mathf.Min(num, list3.Count);
					List<GroupAIHelper> list4 = list3.Take(num).ToList();
					GroupAIHelper groupAIHelper = list4[0];
					if ((Object)(object)groupAIHelper.enemyRef == (Object)null)
					{
						ManualLogSource? log = _log;
						if (log != null)
						{
							log.LogError((object)"Selected leader has null enemyRef!");
						}
						list2.Remove(groupAIHelper);
						continue;
					}
					Formation formation = ParseFormation(Plugin.FormationType?.Value ?? "Loose");
					EnemyGroup enemyGroup = new EnemyGroup(groupAIHelper.enemyRef, formation);
					groupAIHelper.AssignToGroup(enemyGroup, isLeader: true);
					for (int i = 1; i < list4.Count; i++)
					{
						enemyGroup.AddFollower(list4[i]);
					}
					foreach (GroupAIHelper item2 in list4)
					{
						list2.Remove(item2);
					}
					activeGroups.Add(enemyGroup);
					ManualLogSource? log2 = _log;
					if (log2 != null)
					{
						log2.LogInfo((object)$"Formed group for {item} size {num}.");
					}
				}
			}
		}

		private void CleanupInvalidGroups()
		{
			activeGroups.RemoveAll((EnemyGroup group) => !group.IsValid || (Object)(object)group.Leader == (Object)null || !((Behaviour)group.Leader).isActiveAndEnabled);
		}

		private void UpdateGroupPatrols()
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Expected O, but got Unknown
			//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Invalid comparison between Unknown and I4
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			foreach (EnemyGroup activeGroup in activeGroups)
			{
				if (!activeGroup.IsValid || (Object)(object)activeGroup.Leader == (Object)null || !((Behaviour)activeGroup.Leader).isActiveAndEnabled)
				{
					continue;
				}
				NavMeshAgent val = activeGroup.Leader.NavMeshAgent?.Agent;
				if (!((Object)(object)val != (Object)null) || !((Behaviour)val).enabled || !val.isOnNavMesh || (val.hasPath && !(val.remainingDistance < val.stoppingDistance + 1.5f)))
				{
					continue;
				}
				LevelPoint val2 = FindNewPatrolPoint(((Component)activeGroup.Leader).transform.position);
				if ((Object)(object)val2 != (Object)null)
				{
					NavMeshPath val3 = new NavMeshPath();
					if (val.CalculatePath(((Component)val2).transform.position, val3) && (int)val3.status == 0)
					{
						activeGroup.CurrentPatrolTarget = ((Component)val2).transform.position;
						val.SetDestination(activeGroup.CurrentPatrolTarget);
					}
					else if (val.hasPath)
					{
						val.ResetPath();
					}
				}
				else if (val.hasPath)
				{
					val.ResetPath();
				}
			}
		}

		private LevelPoint? FindNewPatrolPoint(Vector3 currentPos)
		{
			//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)
			if (LevelGenerator.Instance?.LevelPathPoints == null || LevelGenerator.Instance.LevelPathPoints.Count == 0)
			{
				return null;
			}
			List<LevelPoint> list = LevelGenerator.Instance.LevelPathPoints.Where((LevelPoint p) => (Object)(object)p != (Object)null && Vector3.Distance(((Component)p).transform.position, currentPos) > 10f).ToList();
			if (list.Count > 0)
			{
				return list[Random.Range(0, list.Count)];
			}
			return LevelGenerator.Instance.LevelPathPoints[Random.Range(0, LevelGenerator.Instance.LevelPathPoints.Count)];
		}

		private Formation ParseFormation(string formationName)
		{
			if (Enum.TryParse<Formation>(formationName, ignoreCase: true, out var result))
			{
				return result;
			}
			ManualLogSource? log = _log;
			if (log != null)
			{
				log.LogWarning((object)("Invalid FormationType '" + formationName + "'. Defaulting to Loose."));
			}
			return Formation.Loose;
		}
	}
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInPlugin("PlusBlankPlus.VisionMonsters", "Vision and Hearing Monsters", "1.3.3")]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGuid = "PlusBlankPlus.VisionMonsters";

		public const string PluginName = "Vision and Hearing Monsters";

		public const string PluginVersion = "1.3.3";

		public static ConfigEntry<float>? VisionDistanceMultiplier;

		public static ConfigEntry<float>? CloseVisionDistanceMultiplier;

		public static ConfigEntry<float>? CrouchCloseVisionDistanceMultiplier;

		public static ConfigEntry<float>? PhysObjectVisionRadiusMultiplier;

		public static ConfigEntry<float>? SoundSensitivityMultiplier;

		public static ConfigEntry<bool>? EnableCheatingAI;

		public static ConfigEntry<float>? RadarScanRadius;

		public static ConfigEntry<float>? RadarScanInterval;

		public static ConfigEntry<float>? MemoryDuration;

		public static ConfigEntry<bool>? EnableGrouping;

		public static ConfigEntry<int>? MinGroupSize;

		public static ConfigEntry<int>? MaxGroupSize;

		public static ConfigEntry<float>? GroupCheckInterval;

		public static ConfigEntry<string>? FormationType;

		internal static ManualLogSource? Log;

		internal static bool firstPatchLogDone;

		private void Awake()
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Expected O, but got Unknown
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Expected O, but got Unknown
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: 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_01f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fe: Expected O, but got Unknown
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Expected O, but got Unknown
			//IL_0283: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Expected O, but got Unknown
			//IL_02b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: Expected O, but got Unknown
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fc: Expected O, but got Unknown
			//IL_0353: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Expected O, but got Unknown
			//IL_037d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0383: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			ManualLogSource? log = Log;
			if (log != null)
			{
				log.LogInfo((object)"Loading Vision and Hearing Monsters v1.3.3...");
			}
			ManualLogSource? log2 = Log;
			if (log2 != null)
			{
				log2.LogInfo((object)"Binding configuration...");
			}
			VisionDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "VisionDistanceMultiplier", 1f, new ConfigDescription("Multiplier for base vision distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 20f), Array.Empty<object>()));
			CloseVisionDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "CloseVisionDistanceMultiplier", 1f, new ConfigDescription("Multiplier for close standing vision.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
			CrouchCloseVisionDistanceMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "CrouchCloseVisionDistanceMultiplier", 1f, new ConfigDescription("Multiplier for close crouched vision.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
			PhysObjectVisionRadiusMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("1. Vision", "PhysObjectVisionRadiusMultiplier", 1f, new ConfigDescription("Multiplier for physics object vision radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 10f), Array.Empty<object>()));
			SoundSensitivityMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("2. Hearing", "SoundSensitivityMultiplier", 1f, new ConfigDescription("Multiplier for sound investigation radius.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), Array.Empty<object>()));
			EnableCheatingAI = ((BaseUnityPlugin)this).Config.Bind<bool>("3. Cheating AI", "EnableCheatingAI", false, "Enables unfair AI enhancements (Radar, Memory, Targeted Patrols).");
			RadarScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3. Cheating AI", "RadarScanRadius", 25f, new ConfigDescription("Radius (meters) for enemy 'radar' scans (ignores walls).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 100f), Array.Empty<object>()));
			RadarScanInterval = ((BaseUnityPlugin)this).Config.Bind<float>("3. Cheating AI", "RadarScanInterval", 5f, new ConfigDescription("How often (seconds) each enemy performs a radar scan.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>()));
			MemoryDuration = ((BaseUnityPlugin)this).Config.Bind<float>("3. Cheating AI", "MemoryDuration", 60f, new ConfigDescription("How long (seconds) enemy remembers player's last known location.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 300f), Array.Empty<object>()));
			EnableGrouping = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Group Patrolling", "EnableGrouping", false, "Enables enemies of the same type to form patrol groups.");
			MinGroupSize = ((BaseUnityPlugin)this).Config.Bind<int>("4. Group Patrolling", "MinGroupSize", 2, new ConfigDescription("Minimum number of same-type enemies needed to form a group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>()));
			MaxGroupSize = ((BaseUnityPlugin)this).Config.Bind<int>("4. Group Patrolling", "MaxGroupSize", 4, new ConfigDescription("Maximum number of enemies in a single patrol group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2, 10), Array.Empty<object>()));
			GroupCheckInterval = ((BaseUnityPlugin)this).Config.Bind<float>("4. Group Patrolling", "GroupCheckInterval", 10f, new ConfigDescription("How often (seconds) the manager tries to form new groups.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 60f), Array.Empty<object>()));
			FormationType = ((BaseUnityPlugin)this).Config.Bind<string>("4. Group Patrolling", "FormationType", "Loose", new ConfigDescription("How grouped enemies attempt to arrange themselves while patrolling.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { "Line", "Triangle", "Box", "Circle", "Loose" }), Array.Empty<object>()));
			ManualLogSource? log3 = Log;
			if (log3 != null)
			{
				log3.LogInfo((object)"Applying patches for PlusBlankPlus.VisionMonsters...");
			}
			Harmony val = new Harmony("PlusBlankPlus.VisionMonsters");
			try
			{
				val.PatchAll(Assembly.GetExecutingAssembly());
				ManualLogSource? log4 = Log;
				if (log4 != null)
				{
					log4.LogInfo((object)"Patches applied successfully!");
				}
			}
			catch (Exception ex)
			{
				ManualLogSource? log5 = Log;
				if (log5 != null)
				{
					log5.LogError((object)("Error applying Harmony patches: " + ex.Message));
				}
				ManualLogSource? log6 = Log;
				if (log6 != null)
				{
					log6.LogError((object)("Stack trace: " + ex.StackTrace));
				}
				if (ex is ReflectionTypeLoadException ex2 && ex2.LoaderExceptions != null)
				{
					Exception[] loaderExceptions = ex2.LoaderExceptions;
					foreach (Exception ex3 in loaderExceptions)
					{
						if (ex3 != null)
						{
							ManualLogSource? log7 = Log;
							if (log7 != null)
							{
								log7.LogError((object)("LoaderException: " + ex3.Message));
							}
						}
					}
				}
			}
			ManualLogSource? log8 = Log;
			if (log8 != null)
			{
				log8.LogInfo((object)"Plugin Vision and Hearing Monsters (PlusBlankPlus.VisionMonsters) version 1.3.3 is loaded!");
			}
		}
	}
	[HarmonyPatch(typeof(GameDirector))]
	internal static class GameDirectorStartPatch
	{
		private static bool managerChecked;

		[HarmonyPatch("Start")]
		[HarmonyPostfix]
		private static void CreateGroupManagerIfNeeded()
		{
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			if (managerChecked)
			{
				return;
			}
			managerChecked = true;
			ManualLogSource? log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)"GameDirector.Start Postfix: Checking if Group Manager needs creation...");
			}
			ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
			if (enableGrouping != null && enableGrouping.Value && SemiFunc.IsMasterClientOrSingleplayer())
			{
				if ((Object)(object)GroupPatrolManager.Instance == (Object)null)
				{
					ManualLogSource? log2 = Plugin.Log;
					if (log2 != null)
					{
						log2.LogInfo((object)"HOST: Creating GroupPatrolManager GameObject via GameDirector.Start patch...");
					}
					GameObject val = new GameObject("GroupPatrolManager_MOD");
					if ((Object)(object)val.AddComponent<GroupPatrolManager>() != (Object)null)
					{
						Object.DontDestroyOnLoad((Object)(object)val);
						ManualLogSource? log3 = Plugin.Log;
						if (log3 != null)
						{
							log3.LogInfo((object)"GroupPatrolManager created successfully.");
						}
					}
					else
					{
						ManualLogSource? log4 = Plugin.Log;
						if (log4 != null)
						{
							log4.LogError((object)"Failed to add GroupPatrolManager component!");
						}
						Object.Destroy((Object)(object)val);
					}
				}
				else
				{
					ManualLogSource? log5 = Plugin.Log;
					if (log5 != null)
					{
						log5.LogInfo((object)"GroupPatrolManager instance already exists.");
					}
				}
				return;
			}
			ConfigEntry<bool>? enableGrouping2 = Plugin.EnableGrouping;
			if (enableGrouping2 != null && enableGrouping2.Value)
			{
				ManualLogSource? log6 = Plugin.Log;
				if (log6 != null)
				{
					log6.LogInfo((object)"CLIENT: Grouping enabled, manager runs on host.");
				}
			}
			else
			{
				ManualLogSource? log7 = Plugin.Log;
				if (log7 != null)
				{
					log7.LogInfo((object)"Grouping disabled, manager not created.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyVision))]
	internal static class EnemyVisionPatches
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void ModifyVisionRanges(EnemyVision __instance)
		{
			if ((Object)(object)__instance == (Object)null || Plugin.Log == null || Plugin.VisionDistanceMultiplier == null || Plugin.CloseVisionDistanceMultiplier == null || Plugin.CrouchCloseVisionDistanceMultiplier == null || Plugin.PhysObjectVisionRadiusMultiplier == null)
			{
				return;
			}
			try
			{
				float visionDistance = __instance.VisionDistance;
				__instance.VisionDistance *= Plugin.VisionDistanceMultiplier.Value;
				__instance.VisionDistanceClose *= Plugin.CloseVisionDistanceMultiplier.Value;
				__instance.VisionDistanceCloseCrouch *= Plugin.CrouchCloseVisionDistanceMultiplier.Value;
				__instance.PhysObjectVisionRadius *= Plugin.PhysObjectVisionRadiusMultiplier.Value;
				if (__instance.PhysObjectVisionRadiusOverride > 0f)
				{
					__instance.PhysObjectVisionRadiusOverride *= Plugin.PhysObjectVisionRadiusMultiplier.Value;
				}
				if (!Plugin.firstPatchLogDone && (Object)(object)((Component)__instance).gameObject != (Object)null)
				{
					Plugin.Log.LogInfo((object)string.Format("[{0}] Modifying EnemyVision on {1}: Vision={2}->{3}", "Vision and Hearing Monsters", ((Object)((Component)__instance).gameObject).name, visionDistance, __instance.VisionDistance));
				}
			}
			catch (Exception arg)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"Error in ModifyVisionRanges patch: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyDirector))]
	internal static class EnemyDirectorPatches
	{
		[HarmonyPatch("SetInvestigate")]
		[HarmonyPrefix]
		private static void ModifyInvestigationRadius(ref float radius)
		{
			if (Plugin.Log == null || Plugin.SoundSensitivityMultiplier == null)
			{
				return;
			}
			try
			{
				radius *= Plugin.SoundSensitivityMultiplier.Value;
				if (!Plugin.firstPatchLogDone)
				{
					Plugin.Log.LogInfo((object)string.Format("[{0}] Sound Sensitivity Multiplier Applied: {1}.", "Vision and Hearing Monsters", Plugin.SoundSensitivityMultiplier.Value));
					Plugin.firstPatchLogDone = true;
				}
			}
			catch (Exception arg)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogError((object)$"Error in ModifyInvestigationRadius patch: {arg}");
				}
			}
		}
	}
	[HarmonyPatch(typeof(Enemy))]
	internal static class EnemyAwakePatch
	{
		[HarmonyPatch("Awake")]
		[HarmonyPostfix]
		private static void AddAIHelperComponents(Enemy __instance)
		{
			if ((Object)(object)((__instance != null) ? ((Component)__instance).gameObject : null) == (Object)null)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"AddAIHelperComponents patch __instance null.");
				}
				return;
			}
			if ((Object)(object)((Component)__instance).gameObject.GetComponent<EnemyAIHelper>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<EnemyAIHelper>();
			}
			if ((Object)(object)((Component)__instance).gameObject.GetComponent<GroupAIHelper>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<GroupAIHelper>();
			}
		}
	}
	[HarmonyPatch(typeof(EnemyHealth))]
	internal static class EnemyHealthPatch
	{
		[HarmonyPatch("DeathImpulseRPC")]
		[HarmonyPrefix]
		private static void UnregisterOnDeathConfirmed(EnemyHealth __instance)
		{
			ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
			if (enableGrouping == null || !enableGrouping.Value || !SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			if ((Object)(object)__instance != (Object)null && (Object)(object)GroupPatrolManager.Instance != (Object)null)
			{
				GroupAIHelper component = ((Component)__instance).GetComponent<GroupAIHelper>();
				if ((Object)(object)component != (Object)null)
				{
					GroupPatrolManager.Instance.UnregisterEnemy(component);
				}
			}
			else if ((Object)(object)__instance == (Object)null)
			{
				ManualLogSource? log = Plugin.Log;
				if (log != null)
				{
					log.LogWarning((object)"UnregisterOnDeathConfirmed patch __instance null.");
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyVision))]
	internal static class EnemyVisionTriggerPatch
	{
		[HarmonyPatch("VisionTrigger")]
		[HarmonyPrefix]
		private static void UpdateMemoryAndBreakFormationOnVision(EnemyVision __instance, PlayerAvatar player)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null) && !((Object)(object)player == (Object)null))
			{
				ConfigEntry<bool>? enableCheatingAI = Plugin.EnableCheatingAI;
				if (enableCheatingAI != null && enableCheatingAI.Value)
				{
					((Component)__instance).GetComponent<EnemyAIHelper>()?.UpdateMemory(((Component)player).transform.position);
				}
				ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
				if (enableGrouping != null && enableGrouping.Value)
				{
					((Component)__instance).GetComponent<GroupAIHelper>()?.BreakFormationTemporarily();
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyStateInvestigate))]
	internal static class EnemyInvestigatePatch
	{
		[HarmonyPatch("Set")]
		[HarmonyPrefix]
		private static void UpdateMemoryAndBreakFormationOnInvestigate(EnemyStateInvestigate __instance, Vector3 position)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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_00bf: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)__instance == (Object)null))
			{
				EnemyAIHelper component = ((Component)__instance).GetComponent<EnemyAIHelper>();
				GroupAIHelper component2 = ((Component)__instance).GetComponent<GroupAIHelper>();
				ConfigEntry<bool>? enableCheatingAI = Plugin.EnableCheatingAI;
				if (enableCheatingAI != null && enableCheatingAI.Value && (Object)(object)component != (Object)null && (!component.HasFreshMemory() || Vector3.Distance(((Component)__instance).transform.position, position) < Vector3.Distance(((Component)__instance).transform.position, component.lastKnownPlayerPosition)))
				{
					component.UpdateMemory(position);
				}
				ConfigEntry<bool>? enableGrouping = Plugin.EnableGrouping;
				if (enableGrouping != null && enableGrouping.Value && (Object)(object)component2 != (Object)null && component2.IsInGroup && component2.CurrentGroup != null && Vector3.Distance(position, component2.CurrentGroup.CurrentPatrolTarget) > 5f)
				{
					component2.BreakFormationTemporarily();
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyStateRoaming))]
	internal static class EnemyRoamingPatch
	{
		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static bool OverrideRoamingMovement(EnemyStateRoaming __instance)
		{
			if (Plugin.EnableGrouping == null || !Plugin.EnableGrouping.Value)
			{
				return true;
			}
			GroupAIHelper groupAIHelper = ((__instance != null) ? ((Component)__instance).GetComponent<GroupAIHelper>() : null);
			if ((Object)(object)groupAIHelper != (Object)null && groupAIHelper.TryGroupMovement())
			{
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(EnemyStateChaseBegin))]
	internal static class EnemyStateChaseBeginPatch
	{
		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static void BreakFormationOnChaseBegin(EnemyStateChaseBegin __instance)
		{
			if (Plugin.EnableGrouping != null && Plugin.EnableGrouping.Value && __instance != null)
			{
				((Component)__instance).GetComponent<GroupAIHelper>()?.BreakFormationTemporarily();
			}
		}
	}
	[HarmonyPatch(typeof(EnemyStateChase))]
	internal static class EnemyStateChasePatch
	{
		[HarmonyPatch("Update")]
		[HarmonyPrefix]
		private static void BreakFormationOnChase(EnemyStateChase __instance)
		{
			if (Plugin.EnableGrouping != null && Plugin.EnableGrouping.Value && __instance != null)
			{
				((Component)__instance).GetComponent<GroupAIHelper>()?.BreakFormationTemporarily();
			}
		}
	}
}