Decompiled source of PathfindingLagFix Beta v2.0.8

PathfindingLagFix.dll

Decompiled 5 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Logging;
using GameNetcodeStuff;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using PathfindingLagFix.Patches;
using PathfindingLagFix.Utilities;
using PathfindingLagFix.Utilities.IL;
using PathfindingLib.API;
using PathfindingLib.Jobs;
using PathfindingLib.Utilities;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Experimental.AI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PathfindingLagFix")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PathfindingLagFix")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("fedb984b-16ae-458c-b2cc-19590627c578")]
[assembly: AssemblyFileVersion("2.0.8")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.0.8.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.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace PathfindingLagFix
{
	[BepInPlugin("Zaggy1024.PathfindingLagFix", "PathfindingLagFix", "2.0.8")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string MOD_NAME = "PathfindingLagFix";

		public const string MOD_UNIQUE_NAME = "Zaggy1024.PathfindingLagFix";

		public const string MOD_VERSION = "2.0.8";

		private readonly Harmony harmony = new Harmony("Zaggy1024.PathfindingLagFix");

		public static Plugin Instance { get; private set; }

		public ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;

		public void Awake()
		{
			Instance = this;
			harmony.PatchAll(typeof(PatchEnemyAI));
			harmony.PatchAll(typeof(PatchFlowermanAI));
			harmony.PatchAll(typeof(PatchCentipedeAI));
			harmony.PatchAll(typeof(PatchPufferAI));
			harmony.PatchAll(typeof(PatchDoublewingAI));
			harmony.PatchAll(typeof(PatchFlowerSnakeEnemy));
		}
	}
}
namespace PathfindingLagFix.Utilities
{
	internal static class AsyncDistancePathfinding
	{
		internal class EnemyDistancePathfindingStatus
		{
			public Coroutine Coroutine;

			public int CurrentSearchTypeID = -1;

			public GameObject[] AINodes;

			public Transform[] SortedNodes;

			public Vector3[] SortedPositions;

			public FindPathsToNodesJob Job;

			public JobHandle JobHandle;

			public Transform ChosenNode;

			public float MostOptimalDistance = float.PositiveInfinity;

			public void SortNodes(EnemyAI enemy, Vector3 target, bool furthestFirst)
			{
				//IL_007e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_0084: Unknown result type (might be due to invalid IL or missing references)
				//IL_0089: Unknown result type (might be due to invalid IL or missing references)
				//IL_005e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0063: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
				int num = enemy.allAINodes.Length;
				if (enemy.allAINodes != AINodes)
				{
					AINodes = enemy.allAINodes;
					SortedNodes = (Transform[])(object)new Transform[num];
					SortedPositions = (Vector3[])(object)new Vector3[num];
					for (int i = 0; i < num; i++)
					{
						Transform transform = AINodes[i].transform;
						SortedNodes[i] = transform;
						SortedPositions[i] = transform.position;
					}
				}
				for (int j = 1; j < num; j++)
				{
					Vector3 val = SortedPositions[j] - target;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					for (int num2 = j; num2 > 0; num2--)
					{
						val = SortedPositions[num2 - 1] - target;
						if ((((Vector3)(ref val)).sqrMagnitude <= sqrMagnitude) ^ furthestFirst)
						{
							break;
						}
						Swap<Transform>(ref SortedNodes[num2 - 1], ref SortedNodes[num2]);
						Swap<Vector3>(ref SortedPositions[num2 - 1], ref SortedPositions[num2]);
					}
				}
				static void Swap<T>(ref T a, ref T b)
				{
					T val2 = b;
					T val3 = a;
					a = val2;
					b = val3;
				}
			}

			public Transform RetrieveChosenNode(out float mostOptimalDistance)
			{
				Transform chosenNode = ChosenNode;
				mostOptimalDistance = MostOptimalDistance;
				if ((Object)(object)chosenNode == (Object)null)
				{
					return null;
				}
				ChosenNode = null;
				MostOptimalDistance = float.PositiveInfinity;
				CurrentSearchTypeID = -1;
				return chosenNode;
			}

			~EnemyDistancePathfindingStatus()
			{
				Job.FreeAllResources();
			}
		}

		internal delegate IEnumerator NodeSelectionCoroutine(EnemyDistancePathfindingStatus status);

		internal const float DEFAULT_CAP_DISTANCE = 60f;

		private static readonly IDMap<EnemyDistancePathfindingStatus> Statuses = new IDMap<EnemyDistancePathfindingStatus>(() => new EnemyDistancePathfindingStatus(), 1);

		internal static void RemoveStatus(EnemyAI enemy)
		{
			Statuses[enemy.thisEnemyIndex] = new EnemyDistancePathfindingStatus();
		}

		internal static EnemyDistancePathfindingStatus StartJobs(EnemyAI enemy, EnemyDistancePathfindingStatus status, Vector3 target, int count, bool farthestFirst)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			NavMeshAgent agent = enemy.agent;
			Vector3 pathOrigin = AgentExtensions.GetPathOrigin(agent);
			status.SortNodes(enemy, target, farthestFirst);
			ref FindPathsToNodesJob job = ref status.Job;
			job.Initialize(agent.agentTypeID, agent.areaMask, pathOrigin, status.SortedPositions);
			status.JobHandle = IJobForExtensions.ScheduleByRef<FindPathsToNodesJob>(ref job, count, default(JobHandle));
			return status;
		}

		internal static EnemyDistancePathfindingStatus StartChoosingNode(EnemyAI enemy, int searchTypeID, NodeSelectionCoroutine coroutine)
		{
			EnemyDistancePathfindingStatus enemyDistancePathfindingStatus = Statuses[enemy.thisEnemyIndex];
			if (enemyDistancePathfindingStatus.CurrentSearchTypeID == searchTypeID)
			{
				return enemyDistancePathfindingStatus;
			}
			if (enemyDistancePathfindingStatus.Coroutine != null)
			{
				enemyDistancePathfindingStatus.Job.Cancel();
				return enemyDistancePathfindingStatus;
			}
			enemyDistancePathfindingStatus.CurrentSearchTypeID = searchTypeID;
			enemyDistancePathfindingStatus.Coroutine = ((MonoBehaviour)enemy).StartCoroutine(coroutine(enemyDistancePathfindingStatus));
			return enemyDistancePathfindingStatus;
		}

		private static EnemyDistancePathfindingStatus StartChoosingNode(EnemyAI enemy, int searchTypeID, Vector3 target, bool farthestFirst, bool avoidLineOfSight, int offset, float capDistance)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			return StartChoosingNode(enemy, searchTypeID, (EnemyDistancePathfindingStatus status) => ChooseNodeCoroutine(enemy, status, target, farthestFirst, avoidLineOfSight, offset, capDistance));
		}

		internal static EnemyDistancePathfindingStatus StartChoosingFarthestNodeFromPosition(EnemyAI enemy, int searchTypeID, Vector3 target, bool avoidLineOfSight = false, int offset = 0, float capDistance = 0f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return StartChoosingNode(enemy, searchTypeID, target, farthestFirst: true, avoidLineOfSight, offset, capDistance);
		}

		internal static EnemyDistancePathfindingStatus StartChoosingClosestNodeToPosition(EnemyAI enemy, int searchTypeID, Vector3 target, bool avoidLineOfSight = false, int offset = 0, float capDistance = 0f)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			return StartChoosingNode(enemy, searchTypeID, target, farthestFirst: false, avoidLineOfSight, offset, capDistance);
		}

		internal static IEnumerator ChooseNodeCoroutine(EnemyAI enemy, EnemyDistancePathfindingStatus status, Vector3 target, bool farthestFirst, bool avoidLineOfSight, int offset, float capDistance)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (enemy.allAINodes.Length == 0 || !enemy.agent.isOnNavMesh)
			{
				status.ChosenNode = ((Component)enemy).transform;
				status.MostOptimalDistance = 0f;
				yield break;
			}
			int candidateCount = enemy.allAINodes.Length;
			StartJobs(enemy, status, target, candidateCount, farthestFirst);
			FindPathsToNodesJob job = status.Job;
			JobHandle jobHandle = status.JobHandle;
			int result = -1;
			float capDistanceSqr = capDistance * capDistance;
			while (result == -1)
			{
				yield return null;
				bool flag = true;
				int num = Math.Min(offset, candidateCount - 1);
				Vector3 position = ((Component)enemy).transform.position;
				for (int i = 0; i < candidateCount; i++)
				{
					if (capDistanceSqr > 0f)
					{
						Vector3 val = status.SortedPositions[i] - position;
						if (((Vector3)(ref val)).sqrMagnitude > capDistanceSqr)
						{
							break;
						}
					}
					PathQueryStatus val2 = job.Statuses[i];
					if ((int)PathQueryStatusExtensions.GetResult(val2) == 536870912)
					{
						flag = false;
						break;
					}
					if ((int)PathQueryStatusExtensions.GetResult(val2) == 1073741824)
					{
						NativeArray<NavMeshLocation> path = job.GetPath(i);
						NavMeshLocation val3 = path[0];
						PolygonId polygon = ((NavMeshLocation)(ref val3)).polygon;
						if (((PolygonId)(ref polygon)).IsNull())
						{
							Plugin.Instance.Logger.LogWarning((object)$"{i}: Path is null");
						}
						else if ((!avoidLineOfSight || !LineOfSight.PathIsBlockedByLineOfSight(path)) && num-- == 0)
						{
							result = i;
							break;
						}
					}
				}
				if (!flag || result != -1)
				{
					continue;
				}
				for (int j = 0; j < candidateCount; j++)
				{
					if ((int)PathQueryStatusExtensions.GetResult(job.Statuses[j]) == 1073741824)
					{
						result = j;
						break;
					}
				}
				break;
			}
			job.Cancel();
			if (result == -1 && status.SortedNodes.Length != 0)
			{
				result = 0;
			}
			if (result >= 0)
			{
				status.ChosenNode = status.SortedNodes[result];
				status.MostOptimalDistance = Vector3.Distance(target, status.SortedPositions[result]);
			}
			while (!((JobHandle)(ref jobHandle)).IsCompleted)
			{
				yield return null;
			}
			status.Coroutine = null;
		}
	}
	internal static class AsyncPlayerPathfinding
	{
		internal class EnemyToPlayerPathfindingStatus
		{
			internal FindPathsToNodesJob PathsToPlayersJob;

			internal JobHandle PathsToPlayersJobHandle;

			internal bool hasStarted;

			private int[] playerJobIndices = Array.Empty<int>();

			private readonly List<Vector3> validPlayerPositions = new List<Vector3>();

			private bool lastRetrievedStatusWasInProgress;

			internal void StartJobs(EnemyAI enemy)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
				//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
				//IL_0092: Unknown result type (might be due to invalid IL or missing references)
				hasStarted = true;
				NavMeshAgent agent = enemy.agent;
				Vector3 pathOrigin = AgentExtensions.GetPathOrigin(enemy.agent);
				PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts;
				if (playerJobIndices.Length != allPlayerScripts.Length)
				{
					playerJobIndices = new int[allPlayerScripts.Length];
				}
				validPlayerPositions.Clear();
				lastRetrievedStatusWasInProgress = false;
				int num = 0;
				for (int i = 0; i < allPlayerScripts.Length; i++)
				{
					PlayerControllerB val = allPlayerScripts[i];
					if (!enemy.PlayerIsTargetable(val, false, false))
					{
						playerJobIndices[i] = -1;
						continue;
					}
					playerJobIndices[i] = num++;
					validPlayerPositions.Add(((Component)val).transform.position);
				}
				PathsToPlayersJob.Initialize(agent.agentTypeID, agent.areaMask, pathOrigin, validPlayerPositions);
				PathsToPlayersJobHandle = IJobForExtensions.ScheduleByRef<FindPathsToNodesJob>(ref PathsToPlayersJob, validPlayerPositions.Count, default(JobHandle));
			}

			internal bool IsPathValid(int playerIndex)
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0037: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Unknown result type (might be due to invalid IL or missing references)
				//IL_003d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0043: Invalid comparison between Unknown and I4
				//IL_004e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0054: Invalid comparison between Unknown and I4
				if (!hasStarted)
				{
					return false;
				}
				if (playerIndex >= playerJobIndices.Length)
				{
					return false;
				}
				int num = playerJobIndices[playerIndex];
				if (num < 0)
				{
					return false;
				}
				PathQueryStatus result = PathQueryStatusExtensions.GetResult(PathsToPlayersJob.Statuses[num]);
				if ((int)result == 536870912)
				{
					lastRetrievedStatusWasInProgress = true;
					return false;
				}
				return (int)result == 1073741824;
			}

			internal void ResetIfResultsHaveBeenUsed()
			{
				if (hasStarted && (!lastRetrievedStatusWasInProgress || validPlayerPositions.Count <= 0))
				{
					hasStarted = false;
				}
			}

			~EnemyToPlayerPathfindingStatus()
			{
				PathsToPlayersJob.FreeAllResources();
			}
		}

		private static readonly IDMap<EnemyToPlayerPathfindingStatus> Statuses = new IDMap<EnemyToPlayerPathfindingStatus>(() => new EnemyToPlayerPathfindingStatus(), 1);

		internal static void RemoveStatus(EnemyAI enemy)
		{
			Statuses[enemy.thisEnemyIndex] = new EnemyToPlayerPathfindingStatus();
		}

		internal static EnemyToPlayerPathfindingStatus GetStatus(EnemyAI enemy)
		{
			return Statuses[enemy.thisEnemyIndex];
		}
	}
	internal static class AsyncRoamingPathfinding
	{
		internal class EnemyRoamingPathfindingStatus
		{
			internal FindPathsToNodesJob PathsFromEnemyJob;

			internal JobHandle PathsFromEnemyJobHandle;

			internal FindPathsToNodesJob PathsFromSearchStartJob;

			internal JobHandle PathsFromSearchStartJobHandle;

			private int nodeCount;

			internal void StartJobs(EnemyAI enemy)
			{
				//IL_0014: Unknown result type (might be due to invalid IL or missing references)
				//IL_0019: Unknown result type (might be due to invalid IL or missing references)
				//IL_0056: 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_0082: Unknown result type (might be due to invalid IL or missing references)
				//IL_009f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
				//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
				AISearchRoutine currentSearch = enemy.currentSearch;
				NavMeshAgent agent = enemy.agent;
				Vector3 pathOrigin = AgentExtensions.GetPathOrigin(enemy.agent);
				List<GameObject> unsearchedNodes = currentSearch.unsearchedNodes;
				nodeCount = unsearchedNodes.Count;
				Vector3[] array = (Vector3[])(object)new Vector3[nodeCount];
				for (int i = 0; i < unsearchedNodes.Count; i++)
				{
					array[GetJobIndex(i)] = unsearchedNodes[i].transform.position;
				}
				PathsFromEnemyJob.Initialize(agent.agentTypeID, agent.areaMask, pathOrigin, array, currentSearch.startedSearchAtSelf);
				PathsFromEnemyJobHandle = IJobForExtensions.ScheduleByRef<FindPathsToNodesJob>(ref PathsFromEnemyJob, unsearchedNodes.Count, default(JobHandle));
				if (!currentSearch.startedSearchAtSelf)
				{
					PathsFromSearchStartJob.Initialize(agent.agentTypeID, agent.areaMask, currentSearch.currentSearchStartPosition, array, calculateDistance: true);
					PathsFromSearchStartJobHandle = IJobForExtensions.ScheduleByRef<FindPathsToNodesJob>(ref PathsFromSearchStartJob, unsearchedNodes.Count, default(JobHandle));
				}
			}

			internal int GetJobIndex(int index)
			{
				return nodeCount - 1 - index;
			}

			~EnemyRoamingPathfindingStatus()
			{
				PathsFromEnemyJob.FreeAllResources();
				PathsFromSearchStartJob.FreeAllResources();
			}
		}

		private static readonly IDMap<EnemyRoamingPathfindingStatus> Statuses = new IDMap<EnemyRoamingPathfindingStatus>(() => new EnemyRoamingPathfindingStatus(), 1);

		internal static void RemoveStatus(EnemyAI enemy)
		{
			Statuses[enemy.thisEnemyIndex] = new EnemyRoamingPathfindingStatus();
		}

		internal static EnemyRoamingPathfindingStatus GetStatus(EnemyAI enemy)
		{
			return Statuses[enemy.thisEnemyIndex];
		}
	}
	internal struct FindPathsToNodesJob : IJobFor
	{
		[NativeDisableContainerSafetyRestriction]
		private static NativeArray<NavMeshQuery> StaticThreadQueries;

		private const float MAX_ORIGIN_DISTANCE = 5f;

		private const float MAX_ENDPOINT_DISTANCE = 1.5f;

		private const float MAX_ENDPOINT_DISTANCE_SQR = 2.25f;

		[ReadOnly]
		[NativeSetThreadIndex]
		internal int ThreadIndex;

		[ReadOnly]
		[NativeDisableContainerSafetyRestriction]
		[NativeDisableParallelForRestriction]
		internal NativeArray<NavMeshQuery> ThreadQueriesRef;

		[ReadOnly]
		private int AgentTypeID;

		[ReadOnly]
		private int AreaMask;

		[ReadOnly]
		private Vector3 Origin;

		[ReadOnly]
		[NativeDisableContainerSafetyRestriction]
		private NativeArray<Vector3> Destinations;

		[ReadOnly]
		private bool CalculateDistance;

		[ReadOnly]
		[NativeDisableContainerSafetyRestriction]
		private NativeArray<bool> Canceled;

		[WriteOnly]
		[NativeDisableContainerSafetyRestriction]
		internal NativeArray<PathQueryStatus> Statuses;

		[WriteOnly]
		[NativeDisableContainerSafetyRestriction]
		[NativeDisableParallelForRestriction]
		internal NativeArray<NavMeshLocation> Paths;

		[WriteOnly]
		[NativeDisableContainerSafetyRestriction]
		internal NativeArray<int> PathSizes;

		[WriteOnly]
		[NativeDisableContainerSafetyRestriction]
		internal NativeArray<float> PathDistances;

		public unsafe void Initialize(int agentTypeID, int areaMask, Vector3 origin, Vector3[] candidates, int count, bool calculateDistance = false)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			ThreadQueriesRef = Unsafe.Read<NativeArray<NavMeshQuery>>((void*)PathfindingJobSharedResources.GetPerThreadQueriesArray());
			CreateFixedArrays();
			AgentTypeID = agentTypeID;
			AreaMask = areaMask;
			Origin = origin;
			CalculateDistance = calculateDistance;
			EnsureCount(count);
			for (int i = 0; i < count; i++)
			{
				Statuses[i] = (PathQueryStatus)536870912;
			}
			if (calculateDistance)
			{
				for (int j = 0; j < count; j++)
				{
					PathDistances[j] = 0f;
				}
			}
			Canceled[0] = false;
			NativeArray<Vector3>.Copy(candidates, Destinations, count);
		}

		public void Initialize(int agentTypeID, int areaMask, Vector3 origin, Vector3[] candidates, bool calculateDistance = false)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Initialize(agentTypeID, areaMask, origin, candidates, candidates.Length, calculateDistance);
		}

		public void Initialize(int agentTypeID, int areaMask, Vector3 origin, List<Vector3> candidates, bool calculateDistance = false)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			Initialize(agentTypeID, areaMask, origin, NoAllocHelpers.ExtractArrayFromListT<Vector3>(candidates), candidates.Count, calculateDistance);
		}

		private void CreateFixedArrays()
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			Canceled = new NativeArray<bool>(1, (Allocator)4, (NativeArrayOptions)1);
		}

		private void DisposeFixedArrays()
		{
			Canceled.Dispose();
		}

		private void EnsureCount(int count)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			if (Destinations.Length < count)
			{
				DisposeResizeableArrays();
				if (count != 0)
				{
					Destinations = new NativeArray<Vector3>(count, (Allocator)4, (NativeArrayOptions)1);
					Statuses = new NativeArray<PathQueryStatus>(count, (Allocator)4, (NativeArrayOptions)1);
					Paths = new NativeArray<NavMeshLocation>(count * 128, (Allocator)4, (NativeArrayOptions)1);
					PathSizes = new NativeArray<int>(count, (Allocator)4, (NativeArrayOptions)1);
					PathDistances = new NativeArray<float>(count, (Allocator)4, (NativeArrayOptions)1);
				}
			}
		}

		private void DisposeResizeableArrays()
		{
			if (Destinations.IsCreated)
			{
				Destinations.Dispose();
				Statuses.Dispose();
				Paths.Dispose();
				PathSizes.Dispose();
				PathDistances.Dispose();
			}
		}

		public void Cancel()
		{
			if (Canceled.IsCreated)
			{
				Canceled[0] = true;
			}
		}

		public NativeArray<NavMeshLocation> GetPathBuffer(int index)
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			return Paths.GetSubArray(index * 128, 128);
		}

		public NativeArray<NavMeshLocation> GetPath(int index)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			return Paths.GetSubArray(index * 128, PathSizes[index]);
		}

		public void Execute(int index)
		{
			//IL_0031: 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_0050: 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_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Invalid comparison between Unknown and I4
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Invalid comparison between Unknown and I4
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: 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_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Invalid comparison between Unknown and I4
			//IL_0181: 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_018e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0195: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Invalid comparison between Unknown and I4
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0210: Unknown result type (might be due to invalid IL or missing references)
			//IL_0214: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: 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_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_023d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0242: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0265: Unknown result type (might be due to invalid IL or missing references)
			//IL_026a: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			if (Canceled[0])
			{
				Statuses[index] = (PathQueryStatus)int.MinValue;
				return;
			}
			NavMeshLock.BeginRead();
			NavMeshQuery val = ThreadQueriesRef[ThreadIndex];
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(5f, 5f, 5f);
			NavMeshLocation val3 = ((NavMeshQuery)(ref val)).MapLocation(Origin, val2, AgentTypeID, AreaMask);
			if (!((NavMeshQuery)(ref val)).IsValid(val3))
			{
				Statuses[index] = (PathQueryStatus)int.MinValue;
				NavMeshLock.EndRead();
				return;
			}
			Vector3 val4 = Destinations[index];
			Vector3 val5 = default(Vector3);
			((Vector3)(ref val5))..ctor(1.5f, 1.5f, 1.5f);
			NavMeshLocation val6 = ((NavMeshQuery)(ref val)).MapLocation(val4, val5, AgentTypeID, AreaMask);
			if (!((NavMeshQuery)(ref val)).IsValid(val6))
			{
				Statuses[index] = (PathQueryStatus)int.MinValue;
				NavMeshLock.EndRead();
				return;
			}
			PathQueryStatus val7 = ((NavMeshQuery)(ref val)).BeginFindPath(val3, val6, AreaMask, default(NativeArray<float>));
			if ((int)PathQueryStatusExtensions.GetResult(val7) == int.MinValue)
			{
				Statuses[index] = val7;
				NavMeshLock.EndRead();
				return;
			}
			int num = default(int);
			while ((int)PathQueryStatusExtensions.GetResult(val7) == 536870912)
			{
				val7 = ((NavMeshQuery)(ref val)).UpdateFindPath(NavMeshLock.RecommendedUpdateFindPathIterationCount, ref num);
				NavMeshLock.YieldRead();
			}
			int num2 = default(int);
			val7 = ((NavMeshQuery)(ref val)).EndFindPath(ref num2);
			if ((int)PathQueryStatusExtensions.GetResult(val7) != 1073741824)
			{
				Statuses[index] = val7;
				NavMeshLock.EndRead();
				return;
			}
			NativeArray<PolygonId> val8 = default(NativeArray<PolygonId>);
			val8..ctor(num2, (Allocator)2, (NativeArrayOptions)1);
			((NavMeshQuery)(ref val)).GetPathResult(NativeSlice<PolygonId>.op_Implicit(val8));
			int num3 = default(int);
			val7 = (PathQueryStatus)(NavMeshQueryUtils.FindStraightPath(val, float3.op_Implicit(Origin), float3.op_Implicit(val4), NativeSlice<PolygonId>.op_Implicit(val8), num2, GetPathBuffer(index), ref num3) | PathQueryStatusExtensions.GetDetail(val7));
			NavMeshLock.EndRead();
			PathSizes[index] = num3;
			val8.Dispose();
			if ((int)PathQueryStatusExtensions.GetResult(val7) != 1073741824)
			{
				Statuses[index] = val7;
				return;
			}
			NativeArray<NavMeshLocation> path = GetPath(index);
			NavMeshLocation val9 = path[path.Length - 1];
			Vector3 val10 = ((NavMeshLocation)(ref val9)).position - val4;
			if (((Vector3)(ref val10)).sqrMagnitude > 2.25f)
			{
				Statuses[index] = (PathQueryStatus)(int.MinValue | PathQueryStatusExtensions.GetDetail(val7));
				return;
			}
			if (CalculateDistance)
			{
				float num4 = 0f;
				for (int i = 1; i < path.Length; i++)
				{
					float num5 = num4;
					val9 = path[i - 1];
					Vector3 position = ((NavMeshLocation)(ref val9)).position;
					val9 = path[i];
					num4 = num5 + Vector3.Distance(position, ((NavMeshLocation)(ref val9)).position);
				}
				PathDistances[index] = num4;
			}
			Statuses[index] = val7;
		}

		internal void FreeAllResources()
		{
			DisposeResizeableArrays();
			DisposeFixedArrays();
		}
	}
	public class IDMap<T> : IEnumerable<T>, IEnumerable
	{
		private readonly Func<T> constructor;

		private T[] backingArray;

		public ref T this[int index] => ref GetItem(index);

		public int Count => backingArray.Length;

		public IDMap(Func<T> elementConstructor, int capacity)
		{
			constructor = elementConstructor;
			backingArray = new T[capacity];
			for (int i = 0; i < capacity; i++)
			{
				backingArray[i] = constructor();
			}
		}

		private void EnsureCapacity(int capacity)
		{
			if (backingArray.Length < capacity)
			{
				T[] array = new T[capacity];
				Array.Copy(backingArray, array, Math.Min(backingArray.Length, array.Length));
				for (int i = backingArray.Length; i < capacity; i++)
				{
					array[i] = constructor();
				}
				backingArray = array;
			}
		}

		public ref T GetItem(int index)
		{
			EnsureCapacity(index + 1);
			return ref backingArray[index];
		}

		public int IndexOf(T item)
		{
			return Array.IndexOf(backingArray, item);
		}

		public void Clear()
		{
			backingArray = Array.Empty<T>();
		}

		public bool Clear(T item)
		{
			int num = IndexOf(item);
			if (num == -1)
			{
				return false;
			}
			this[num] = default(T);
			return true;
		}

		public bool Contains(T item)
		{
			return Array.IndexOf(backingArray, item) != -1;
		}

		public void CopyTo(T[] array, int arrayIndex)
		{
			Array.Copy(backingArray, 0, array, arrayIndex, backingArray.Length);
		}

		public void CopyTo(int sourceIndex, T[] array, int arrayIndex, int count)
		{
			Array.Copy(backingArray, sourceIndex, array, arrayIndex, count);
		}

		public IEnumerator<T> GetEnumerator()
		{
			return ((IEnumerable<T>)backingArray).GetEnumerator();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			return backingArray.GetEnumerator();
		}
	}
	internal static class LineOfSight
	{
		private const int LINE_OF_SIGHT_LAYER_MASK = 262144;

		public static bool PathIsBlockedByLineOfSight(NativeArray<NavMeshLocation> path, Vector3? checkLOSToPosition = null)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: 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)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			if (path.Length <= 1)
			{
				return false;
			}
			bool flag = false;
			NavMeshLocation val = path[0];
			Vector3 val2 = ((NavMeshLocation)(ref val)).position;
			for (int i = 1; i < path.Length && i < 16; i++)
			{
				if (flag)
				{
					break;
				}
				val = path[i];
				Vector3 position = ((NavMeshLocation)(ref val)).position;
				if (checkLOSToPosition.HasValue)
				{
					Vector3 val3 = (val2 + position) * 0.5f;
					Vector3 val4 = Vector3.up * 0.25f;
					if (!Physics.Linecast(val3 + val4, checkLOSToPosition.Value + val4, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1))
					{
						return true;
					}
				}
				if (Physics.Linecast(val2, position, 262144))
				{
					return true;
				}
				val2 = position;
			}
			return false;
		}
	}
}
namespace PathfindingLagFix.Utilities.IL
{
	public class ILInjector
	{
		private const string INVALID = "Injector is invalid";

		private const string MATCH_END_INVALID = "The end of the last search was invalid";

		private List<CodeInstruction> instructions = instructions.ToList();

		private ILGenerator generator;

		private int index;

		private int matchEnd;

		public bool IsValid
		{
			get
			{
				if (instructions != null)
				{
					return IsIndexValid(index);
				}
				return false;
			}
		}

		public CodeInstruction Instruction
		{
			get
			{
				if (!IsIndexInRange(index))
				{
					return null;
				}
				return instructions[index];
			}
			set
			{
				if (!IsIndexInRange(index))
				{
					throw new InvalidOperationException($"Current index {index} is out of range of instruction count {instructions.Count}");
				}
				instructions[index] = value;
			}
		}

		public CodeInstruction LastMatchedInstruction
		{
			get
			{
				int num = matchEnd - 1;
				if (!IsIndexInRange(num))
				{
					return null;
				}
				return instructions[num];
			}
			set
			{
				int num = matchEnd - 1;
				if (!IsIndexInRange(num))
				{
					throw new InvalidOperationException($"Last matched index {index} is out of range of instruction count {instructions.Count}");
				}
				instructions[num] = value;
			}
		}

		public ICollection<CodeInstruction> Instructions => instructions.AsReadOnly();

		public ILInjector(IEnumerable<CodeInstruction> instructions, ILGenerator generator = null)
		{
			this.generator = generator;
			matchEnd = -1;
			base..ctor();
		}

		public ILInjector GoToStart()
		{
			matchEnd = index;
			index = 0;
			return this;
		}

		public ILInjector GoToEnd()
		{
			matchEnd = index;
			index = instructions.Count;
			return this;
		}

		public ILInjector Forward(int offset)
		{
			if (!IsValid)
			{
				return this;
			}
			matchEnd = index;
			index = Math.Clamp(index + offset, -1, instructions.Count);
			return this;
		}

		public ILInjector Back(int offset)
		{
			return Forward(-offset);
		}

		private void MarkInvalid()
		{
			index = -1;
			matchEnd = -1;
		}

		private void Search(bool forward, ILMatcher[] predicates)
		{
			if (!IsValid)
			{
				return;
			}
			int num = 1;
			if (!forward)
			{
				num = -1;
				index--;
			}
			while (forward ? (index < instructions.Count) : (index >= 0))
			{
				if (forward && index + predicates.Length > instructions.Count)
				{
					index = instructions.Count;
					break;
				}
				int i;
				for (i = 0; i < predicates.Length && predicates[i].Matches(instructions[index + i]); i++)
				{
				}
				if (i == predicates.Length)
				{
					matchEnd = index + i;
					return;
				}
				index += num;
			}
			MarkInvalid();
		}

		public ILInjector Find(params ILMatcher[] predicates)
		{
			Search(forward: true, predicates);
			return this;
		}

		public ILInjector ReverseFind(params ILMatcher[] predicates)
		{
			Search(forward: false, predicates);
			return this;
		}

		public ILInjector GoToPush(int popIndex)
		{
			if (!IsValid)
			{
				return this;
			}
			matchEnd = index;
			index--;
			int num = 0;
			while (index >= 0)
			{
				CodeInstruction instruction = instructions[index];
				num += instruction.PushCount();
				num -= instruction.PopCount();
				if (num > popIndex)
				{
					return this;
				}
				index--;
			}
			return this;
		}

		public ILInjector SkipBranch()
		{
			if (Instruction == null)
			{
				return this;
			}
			if (!(Instruction.operand is Label label))
			{
				throw new InvalidOperationException($"Current instruction is not a branch: {Instruction}");
			}
			return FindLabel(label);
		}

		public ILInjector FindLabel(Label label)
		{
			matchEnd = index + 1;
			for (index = 0; index < instructions.Count; index++)
			{
				if (instructions[index].labels.Contains(label))
				{
					return this;
				}
			}
			MarkInvalid();
			return this;
		}

		public ILInjector GoToMatchEnd()
		{
			index = matchEnd;
			return this;
		}

		public ILInjector GoToLastMatchedInstruction()
		{
			if (!IsIndexValid(matchEnd))
			{
				return this;
			}
			index = matchEnd - 1;
			return this;
		}

		private bool IsIndexValid(int index)
		{
			return index != -1;
		}

		private bool IsIndexInRange(int index)
		{
			if (index >= 0)
			{
				return index < instructions.Count;
			}
			return false;
		}

		public CodeInstruction GetRelativeInstruction(int offset)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			int num = index + offset;
			if (!IsIndexInRange(num))
			{
				throw new IndexOutOfRangeException($"Offset {offset} would read out of bounds at index {num}");
			}
			return instructions[num];
		}

		public void SetRelativeInstruction(int offset, CodeInstruction instruction)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			int num = index + offset;
			if (!IsIndexInRange(num))
			{
				throw new IndexOutOfRangeException($"Offset {offset} would write out of bounds at index {num}");
			}
			instructions[num] = instruction;
		}

		public IEnumerable<CodeInstruction> GetRelativeInstructions(int offset, int size)
		{
			for (int i = 0; i < size; i++)
			{
				yield return instructions[index + offset + i];
			}
		}

		public IEnumerable<CodeInstruction> GetRelativeInstructions(int size)
		{
			return GetRelativeInstructions(0, size);
		}

		private void GetLastMatchRangeAbsolute(out int start, out int end)
		{
			start = index;
			end = matchEnd;
			if (start > end)
			{
				int num = end;
				int num2 = start;
				start = num;
				end = num2;
			}
		}

		private void GetLastMatchRange(out int start, out int size)
		{
			GetLastMatchRangeAbsolute(out start, out var end);
			if (start < 0 || start >= instructions.Count)
			{
				throw new InvalidOperationException($"Last match range starts at invalid index {start}");
			}
			if (end < 0 || end > instructions.Count)
			{
				throw new InvalidOperationException($"Last match range ends at invalid index {end}");
			}
			size = end - start;
		}

		public List<CodeInstruction> GetLastMatch()
		{
			GetLastMatchRange(out var start, out var size);
			return instructions.GetRange(start, size);
		}

		public Label AddLabel()
		{
			if (generator == null)
			{
				throw new InvalidOperationException("No ILGenerator was provided");
			}
			Label label = generator.DefineLabel();
			Instruction.labels.Add(label);
			return label;
		}

		public ILInjector AddLabel(Label label)
		{
			Instruction.labels.Add(label);
			return this;
		}

		public ILInjector InsertInPlace(params CodeInstruction[] instructions)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			this.instructions.InsertRange(index, instructions);
			if (matchEnd >= index)
			{
				matchEnd += instructions.Length;
			}
			return this;
		}

		public ILInjector Insert(params CodeInstruction[] instructions)
		{
			InsertInPlace(instructions);
			index += instructions.Length;
			return this;
		}

		public ILInjector InsertInPlaceAfterBranch(params CodeInstruction[] instructions)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			List<Label> labels = Instruction.labels;
			this.instructions.InsertRange(index, instructions);
			Instruction.labels.AddRange(labels);
			labels.Clear();
			if (matchEnd >= index)
			{
				matchEnd += instructions.Length;
			}
			return this;
		}

		public ILInjector InsertAfterBranch(params CodeInstruction[] instructions)
		{
			InsertInPlaceAfterBranch(instructions);
			index += instructions.Length;
			return this;
		}

		public ILInjector RemoveAllPreviousInstructions()
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			instructions.RemoveRange(0, index);
			matchEnd -= index;
			if (matchEnd < 0)
			{
				matchEnd = 0;
			}
			index = 0;
			return this;
		}

		public ILInjector Remove(int count = 1)
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid");
			}
			instructions.RemoveRange(index, count);
			if (matchEnd > index)
			{
				matchEnd = Math.Max(index, matchEnd - count);
			}
			return this;
		}

		public ILInjector RemoveLastMatch()
		{
			GetLastMatchRange(out var start, out var size);
			instructions.RemoveRange(start, size);
			index = start;
			matchEnd = start;
			return this;
		}

		public ILInjector ReplaceLastMatch(params CodeInstruction[] instructions)
		{
			RemoveLastMatch();
			Insert(instructions);
			return this;
		}

		public List<CodeInstruction> ReleaseInstructions()
		{
			List<CodeInstruction> result = instructions;
			instructions = null;
			return result;
		}

		public ILInjector PrintContext(int context, string header = "")
		{
			if (!IsValid)
			{
				throw new InvalidOperationException("Injector is invalid (" + header + ")");
			}
			StringBuilder stringBuilder = new StringBuilder(header);
			if (header.Length > 0)
			{
				stringBuilder.Append(':');
			}
			stringBuilder.AppendLine();
			GetLastMatchRangeAbsolute(out var start, out var end);
			int num = Math.Min(end + 1 + context, instructions.Count);
			for (int i = Math.Max(start - context, 0); i < num; i++)
			{
				if (end == -1 && i == index)
				{
					stringBuilder.Append("╶> ");
				}
				else
				{
					if (i >= start && i < end)
					{
						stringBuilder.Append("│");
					}
					else
					{
						stringBuilder.Append(" ");
					}
					if (i == index)
					{
						stringBuilder.Append("╶> ");
					}
					else
					{
						stringBuilder.Append("   ");
					}
				}
				stringBuilder.AppendLine($"{i}: {instructions[i]}");
			}
			Plugin.Instance.Logger.LogInfo((object)stringBuilder);
			return this;
		}

		public ILInjector PrintContext(string header = "")
		{
			return PrintContext(4, header);
		}
	}
	public interface ILMatcher
	{
		private static OpCode[] branchInstructions = new OpCode[4]
		{
			OpCodes.Br,
			OpCodes.Br_S,
			OpCodes.Brfalse,
			OpCodes.Brfalse_S
		};

		bool Matches(CodeInstruction instruction);

		static NotMatcher Not(ILMatcher matcher)
		{
			return new NotMatcher(matcher);
		}

		static OpcodeMatcher Opcode(OpCode opcode)
		{
			return new OpcodeMatcher(opcode);
		}

		static OpcodesMatcher Opcodes(params OpCode[] opcodes)
		{
			return new OpcodesMatcher(opcodes);
		}

		static OpcodeOperandMatcher OpcodeOperand(OpCode opcode, object operand)
		{
			return new OpcodeOperandMatcher(opcode, operand);
		}

		static InstructionMatcher Instruction(CodeInstruction instruction)
		{
			return new InstructionMatcher(instruction);
		}

		static LdargMatcher Ldarg(int? arg = null)
		{
			return new LdargMatcher(arg);
		}

		static LdlocMatcher Ldloc(int? loc = null)
		{
			return new LdlocMatcher(loc);
		}

		static StlocMatcher Stloc(int? loc = null)
		{
			return new StlocMatcher(loc);
		}

		static LdcI32Matcher Ldc(int? value = null)
		{
			return new LdcI32Matcher(value);
		}

		static BranchMatcher Branch()
		{
			return new BranchMatcher();
		}

		static OpcodeOperandMatcher Ldfld(FieldInfo field)
		{
			if (field == null)
			{
				Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldfld() was null\n{new StackTrace()}");
			}
			return new OpcodeOperandMatcher(OpCodes.Ldfld, field);
		}

		static OpcodeOperandMatcher Ldsfld(FieldInfo field)
		{
			if (field == null)
			{
				Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldsfld() was null\n{new StackTrace()}");
			}
			return new OpcodeOperandMatcher(OpCodes.Ldsfld, field);
		}

		static OpcodeOperandMatcher Stfld(FieldInfo field)
		{
			if (field == null)
			{
				Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stfld() was null\n{new StackTrace()}");
			}
			return new OpcodeOperandMatcher(OpCodes.Stfld, field);
		}

		static OpcodeOperandMatcher Stsfld(FieldInfo field)
		{
			if (field == null)
			{
				Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stsfld() was null\n{new StackTrace()}");
			}
			return new OpcodeOperandMatcher(OpCodes.Stsfld, field);
		}

		static OpcodeOperandMatcher Callvirt(MethodBase method)
		{
			if (method == null)
			{
				Plugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Callvirt() was null\n{new StackTrace()}");
			}
			return OpcodeOperand(OpCodes.Callvirt, method);
		}

		static OpcodeOperandMatcher Call(MethodBase method)
		{
			if (method == null)
			{
				Plugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Call() was null\n{new StackTrace()}");
			}
			return OpcodeOperand(OpCodes.Call, method);
		}

		static PredicateMatcher Predicate(Func<CodeInstruction, bool> predicate)
		{
			return new PredicateMatcher(predicate);
		}

		static PredicateMatcher Predicate(Func<FieldInfo, bool> predicate)
		{
			return new PredicateMatcher((CodeInstruction insn) => insn.operand is FieldInfo arg && predicate(arg));
		}
	}
	public class NotMatcher : ILMatcher
	{
		private readonly ILMatcher matcher;

		public NotMatcher(ILMatcher matcher)
		{
			this.matcher = matcher;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			return !matcher.Matches(instruction);
		}
	}
	public class OpcodeMatcher : ILMatcher
	{
		private readonly OpCode opcode;

		public OpcodeMatcher(OpCode opcode)
		{
			this.opcode = opcode;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			return instruction.opcode == opcode;
		}
	}
	public class OpcodesMatcher : ILMatcher
	{
		private readonly OpCode[] opcodes;

		public OpcodesMatcher(OpCode[] opcodes)
		{
			this.opcodes = opcodes;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			return opcodes.Contains(instruction.opcode);
		}
	}
	public class OpcodeOperandMatcher : ILMatcher
	{
		private readonly OpCode opcode;

		private readonly object operand;

		public OpcodeOperandMatcher(OpCode opcode, object operand)
		{
			this.opcode = opcode;
			this.operand = operand;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (instruction.opcode == opcode)
			{
				return instruction.operand == operand;
			}
			return false;
		}
	}
	public class InstructionMatcher : ILMatcher
	{
		private readonly OpCode opcode = instruction.opcode;

		private readonly object operand = instruction.operand;

		private readonly Label[] labels = instruction.labels.ToArray();

		public InstructionMatcher(CodeInstruction instruction)
		{
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (instruction.opcode != opcode)
			{
				return false;
			}
			if (instruction.operand != operand)
			{
				return false;
			}
			if (instruction.labels.Count != labels.Length)
			{
				return false;
			}
			for (int i = 0; i < labels.Length; i++)
			{
				if (labels[i] != instruction.labels[i])
				{
					return false;
				}
			}
			return true;
		}
	}
	public class LdargMatcher : ILMatcher
	{
		private readonly int? arg;

		public LdargMatcher(int? arg)
		{
			this.arg = arg;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (!arg.HasValue)
			{
				return instruction.GetLdargIndex().HasValue;
			}
			return instruction.GetLdargIndex() == arg;
		}
	}
	public class LdlocMatcher : ILMatcher
	{
		private readonly int? loc;

		public LdlocMatcher(int? loc)
		{
			this.loc = loc;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (!loc.HasValue)
			{
				return instruction.GetLdlocIndex().HasValue;
			}
			return instruction.GetLdlocIndex() == loc;
		}
	}
	public class StlocMatcher : ILMatcher
	{
		private readonly int? loc;

		public StlocMatcher(int? loc)
		{
			this.loc = loc;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (!loc.HasValue)
			{
				return instruction.GetStlocIndex().HasValue;
			}
			return instruction.GetStlocIndex() == loc;
		}
	}
	public class LdcI32Matcher : ILMatcher
	{
		private readonly int? value;

		public LdcI32Matcher(int? value)
		{
			this.value = value;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			if (value.HasValue || !instruction.GetLdcI32().HasValue)
			{
				return instruction.GetLdcI32() == value;
			}
			return true;
		}
	}
	public class BranchMatcher : ILMatcher
	{
		public bool Matches(CodeInstruction instruction)
		{
			Label? label = default(Label?);
			return CodeInstructionExtensions.Branches(instruction, ref label);
		}
	}
	public class PredicateMatcher : ILMatcher
	{
		private readonly Func<CodeInstruction, bool> predicate;

		public PredicateMatcher(Func<CodeInstruction, bool> predicate)
		{
			this.predicate = predicate;
			base..ctor();
		}

		public bool Matches(CodeInstruction instruction)
		{
			return predicate(instruction);
		}
	}
	internal static class InstructionUtilities
	{
		public static CodeInstruction MakeLdarg(int index)
		{
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Expected O, but got Unknown
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Expected O, but got Unknown
			if (index < 256)
			{
				return (CodeInstruction)(index switch
				{
					0 => (object)new CodeInstruction(OpCodes.Ldarg_0, (object)null), 
					1 => (object)new CodeInstruction(OpCodes.Ldarg_1, (object)null), 
					2 => (object)new CodeInstruction(OpCodes.Ldarg_2, (object)null), 
					3 => (object)new CodeInstruction(OpCodes.Ldarg_3, (object)null), 
					_ => (object)new CodeInstruction(OpCodes.Ldarg_S, (object)index), 
				});
			}
			return new CodeInstruction(OpCodes.Ldarg, (object)index);
		}

		public static int PopCount(this CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt)
			{
				MethodInfo obj = (MethodInfo)instruction.operand;
				int num = obj.GetParameters().Length;
				if (!obj.IsStatic)
				{
					num++;
				}
				return num;
			}
			if (instruction.opcode == OpCodes.Ret)
			{
				return 1;
			}
			return instruction.opcode.StackBehaviourPop switch
			{
				StackBehaviour.Pop0 => 0, 
				StackBehaviour.Pop1 => 1, 
				StackBehaviour.Pop1_pop1 => 2, 
				StackBehaviour.Popi => 1, 
				StackBehaviour.Popi_pop1 => 2, 
				StackBehaviour.Popi_popi => 2, 
				StackBehaviour.Popi_popi8 => 2, 
				StackBehaviour.Popi_popi_popi => 3, 
				StackBehaviour.Popi_popr4 => 2, 
				StackBehaviour.Popi_popr8 => 2, 
				StackBehaviour.Popref => 1, 
				StackBehaviour.Popref_pop1 => 2, 
				StackBehaviour.Popref_popi => 2, 
				StackBehaviour.Popref_popi_popi => 3, 
				StackBehaviour.Popref_popi_popi8 => 3, 
				StackBehaviour.Popref_popi_popr4 => 3, 
				StackBehaviour.Popref_popi_popr8 => 3, 
				StackBehaviour.Popref_popi_popref => 3, 
				StackBehaviour.Varpop => throw new NotImplementedException($"Variable pop on non-call instruction '{instruction}'"), 
				StackBehaviour.Popref_popi_pop1 => 3, 
				_ => throw new NotSupportedException($"StackBehaviourPop of {instruction.opcode.StackBehaviourPop} was not a pop for instruction '{instruction}'"), 
			};
		}

		public static int PushCount(this CodeInstruction instruction)
		{
			if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt)
			{
				if (((MethodInfo)instruction.operand).ReturnType == typeof(void))
				{
					return 0;
				}
				return 1;
			}
			return instruction.opcode.StackBehaviourPush switch
			{
				StackBehaviour.Push0 => 0, 
				StackBehaviour.Push1 => 1, 
				StackBehaviour.Push1_push1 => 2, 
				StackBehaviour.Pushi => 1, 
				StackBehaviour.Pushi8 => 1, 
				StackBehaviour.Pushr4 => 1, 
				StackBehaviour.Pushr8 => 1, 
				StackBehaviour.Pushref => 1, 
				StackBehaviour.Varpush => throw new NotImplementedException($"Variable push on non-call instruction '{instruction}'"), 
				_ => throw new NotSupportedException($"StackBehaviourPush of {instruction.opcode.StackBehaviourPush} was not a push for instruction '{instruction}'"), 
			};
		}

		public static int? GetLdargIndex(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldarg_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Ldarg_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Ldarg_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Ldarg_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Ldarg || opcode == OpCodes.Ldarg_S)
			{
				return instruction.operand as int?;
			}
			return null;
		}

		public static int? GetLdlocIndex(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldloc_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Ldloc_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Ldloc_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Ldloc_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
			{
				return (instruction.operand as LocalBuilder)?.LocalIndex;
			}
			return null;
		}

		public static int? GetStlocIndex(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Stloc_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Stloc_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Stloc_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Stloc_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
			{
				return (instruction.operand as LocalBuilder)?.LocalIndex;
			}
			return null;
		}

		public static CodeInstruction LdlocToStloc(this CodeInstruction instruction)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldloc_0)
			{
				return new CodeInstruction(OpCodes.Stloc_0, (object)null);
			}
			if (opcode == OpCodes.Ldloc_1)
			{
				return new CodeInstruction(OpCodes.Stloc_1, (object)null);
			}
			if (opcode == OpCodes.Ldloc_2)
			{
				return new CodeInstruction(OpCodes.Stloc_2, (object)null);
			}
			if (opcode == OpCodes.Ldloc_3)
			{
				return new CodeInstruction(OpCodes.Stloc_3, (object)null);
			}
			if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
			{
				return new CodeInstruction(OpCodes.Stloc, instruction.operand);
			}
			return null;
		}

		public static CodeInstruction StlocToLdloc(this CodeInstruction instruction)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Expected O, but got Unknown
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Expected O, but got Unknown
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Expected O, but got Unknown
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Expected O, but got Unknown
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Stloc_0)
			{
				return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
			}
			if (opcode == OpCodes.Stloc_1)
			{
				return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
			}
			if (opcode == OpCodes.Stloc_2)
			{
				return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
			}
			if (opcode == OpCodes.Stloc_3)
			{
				return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
			}
			if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
			{
				return new CodeInstruction(OpCodes.Ldloc, instruction.operand);
			}
			return null;
		}

		public static int? GetLdcI32(this CodeInstruction instruction)
		{
			OpCode opcode = instruction.opcode;
			if (opcode == OpCodes.Ldc_I4_M1)
			{
				return -1;
			}
			if (opcode == OpCodes.Ldc_I4_0)
			{
				return 0;
			}
			if (opcode == OpCodes.Ldc_I4_1)
			{
				return 1;
			}
			if (opcode == OpCodes.Ldc_I4_2)
			{
				return 2;
			}
			if (opcode == OpCodes.Ldc_I4_3)
			{
				return 3;
			}
			if (opcode == OpCodes.Ldc_I4_4)
			{
				return 4;
			}
			if (opcode == OpCodes.Ldc_I4_5)
			{
				return 5;
			}
			if (opcode == OpCodes.Ldc_I4_6)
			{
				return 6;
			}
			if (opcode == OpCodes.Ldc_I4_7)
			{
				return 7;
			}
			if (opcode == OpCodes.Ldc_I4_8)
			{
				return 8;
			}
			if (opcode == OpCodes.Ldc_I4_S)
			{
				return instruction.operand as sbyte?;
			}
			if (opcode == OpCodes.Ldc_I4)
			{
				return instruction.operand as int?;
			}
			return null;
		}
	}
}
namespace PathfindingLagFix.Patches
{
	[HarmonyPatch(typeof(CentipedeAI))]
	internal static class PatchCentipedeAI
	{
		private static bool useAsync = true;

		private const int HIDE_AWAY_FROM_MAIN_ID = 0;

		private const int HIDE_NEAR_PLAYER_ID = 1;

		private static bool ChooseHidingSpotRelativeToMainEntranceAsync(CentipedeAI centipede)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			if (!useAsync)
			{
				return false;
			}
			int num = ((EnemyAI)centipede).allAINodes.Length;
			Transform val = AsyncDistancePathfinding.StartChoosingFarthestNodeFromPosition((EnemyAI)(object)centipede, 0, centipede.mainEntrancePosition, avoidLineOfSight: false, (num / 2 + ((EnemyAI)centipede).thisEnemyIndex) % num).RetrieveChosenNode(out ((EnemyAI)centipede).mostOptimalDistance);
			if ((Object)(object)val != (Object)null)
			{
				centipede.choseHidingSpotNoPlayersNearby = true;
				centipede.SetDestinationToNode(val);
			}
			return true;
		}

		[HarmonyTranspiler]
		[HarmonyPatch("DoAIInterval")]
		private static IEnumerable<CodeInstruction> DoAIIntervalTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Expected O, but got Unknown
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Expected O, but got Unknown
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Expected O, but got Unknown
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldarg(0), ILMatcher.Ldfld(typeof(CentipedeAI).GetField("choseHidingSpotNoPlayersNearby", BindingFlags.Instance | BindingFlags.NonPublic)), ILMatcher.Opcode(OpCodes.Brtrue));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find instructions to check if a hiding spot is chosen in CentipedeAI.DoAIInterval().");
				return instructions;
			}
			Label label = (Label)iLInjector.LastMatchedInstruction.operand;
			return iLInjector.GoToMatchEnd().InsertInPlace(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchCentipedeAI), "ChooseHidingSpotRelativeToMainEntranceAsync", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(CentipedeAI) })), new CodeInstruction(OpCodes.Brtrue_S, (object)label)).ReleaseInstructions();
		}

		private static bool ChooseHidingSpotNearPlayer(CentipedeAI centipede, Vector3 targetPos)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			if (!useAsync)
			{
				return false;
			}
			Transform val = AsyncDistancePathfinding.StartChoosingClosestNodeToPosition((EnemyAI)(object)centipede, 1, targetPos, avoidLineOfSight: true, centipede.offsetNodeAmount).RetrieveChosenNode(out ((EnemyAI)centipede).mostOptimalDistance);
			if ((Object)(object)val != (Object)null)
			{
				centipede.SetDestinationToNode(val);
			}
			return true;
		}

		[HarmonyTranspiler]
		[HarmonyPatch("ChooseHidingSpotNearPlayer")]
		private static IEnumerable<CodeInstruction> ChooseHidingSpotNearPlayerTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Expected O, but got Unknown
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Expected O, but got Unknown
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Call(Reflection.m_EnemyAI_ChooseClosestNodeToPosition), ILMatcher.Stloc());
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find call to ChooseClosestNodeToPosition in CentipedeAI.ChooseHidingSpotNearPlayer().");
				return instructions;
			}
			Label label = generator.DefineLabel();
			return iLInjector.GoToPush(3).InsertAfterBranch(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldarg_1, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchCentipedeAI), "ChooseHidingSpotNearPlayer", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
			{
				typeof(CentipedeAI),
				typeof(Vector3)
			})), new CodeInstruction(OpCodes.Brfalse_S, (object)label), new CodeInstruction(OpCodes.Ret, (object)null)).AddLabel(label)
				.ReleaseInstructions();
		}
	}
	[HarmonyPatch(typeof(DoublewingAI))]
	internal static class PatchDoublewingAI
	{
		private const int EVADE_PLAYER_ID = 0;

		private static bool useAsync = true;

		private static PlayerControllerB GetPlayerToEvade(DoublewingAI doublewing)
		{
			return ((EnemyAI)doublewing).CheckLineOfSightForPlayer(80f, 8, 4);
		}

		private static AsyncDistancePathfinding.EnemyDistancePathfindingStatus StartEvasionPathfindingJob(DoublewingAI doublewing, PlayerControllerB player)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return AsyncDistancePathfinding.StartChoosingFarthestNodeFromPosition((EnemyAI)(object)doublewing, 0, ((Component)player).transform.position, avoidLineOfSight: false, Random.Range(0, ((EnemyAI)doublewing).allAINodes.Length / 2));
		}

		private static Transform ChoosePlayerEvasionNodeAsync(DoublewingAI doublewing, PlayerControllerB player)
		{
			return StartEvasionPathfindingJob(doublewing, player).RetrieveChosenNode(out ((EnemyAI)doublewing).mostOptimalDistance);
		}

		[HarmonyTranspiler]
		[HarmonyPatch("DoAIInterval")]
		private static IEnumerable<CodeInstruction> DoAIIntervalTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0164: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Expected O, but got Unknown
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Expected O, but got Unknown
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Expected O, but got Unknown
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d3: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e1: Expected O, but got Unknown
			//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Expected O, but got Unknown
			//IL_01ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0205: Expected O, but got Unknown
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0219: Expected O, but got Unknown
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Expected O, but got Unknown
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Call(Reflection.m_EnemyAI_CheckLineOfSightForPlayer), ILMatcher.Stloc());
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find instructions to find the player to evade from in DoublewingAI.DoAIInterval().");
				return instructions;
			}
			CodeInstruction val = iLInjector.LastMatchedInstruction.StlocToLdloc();
			iLInjector.Find(ILMatcher.Ldloc(val.GetLdlocIndex()), ILMatcher.Call(Reflection.m_Object_op_Implicit), ILMatcher.Opcode(OpCodes.Brfalse));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find instructions to check if a player is in line of sight in DoublewingAI.DoAIInterval().");
				return instructions;
			}
			Label label = (Label)iLInjector.LastMatchedInstruction.operand;
			iLInjector.GoToMatchEnd().Find(ILMatcher.Call(Reflection.m_EnemyAI_ChooseFarthestNodeFromPosition), ILMatcher.Stloc());
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find instructions to choose player evasion node in DoublewingAI.DoAIInterval().");
				return instructions;
			}
			CodeInstruction lastMatchedInstruction = iLInjector.LastMatchedInstruction;
			Label label2 = generator.DefineLabel();
			iLInjector.GetRelativeInstruction(2).labels.Add(label2);
			Label label3 = generator.DefineLabel();
			return iLInjector.GoToPush(6).Insert(new CodeInstruction(OpCodes.Ldsfld, (object)typeof(PatchDoublewingAI).GetField("useAsync", BindingFlags.Static | BindingFlags.NonPublic)), new CodeInstruction(OpCodes.Brfalse_S, (object)label3), new CodeInstruction(OpCodes.Ldarg_0, (object)null), val, new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchDoublewingAI), "ChoosePlayerEvasionNodeAsync", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
			{
				typeof(DoublewingAI),
				typeof(PlayerControllerB)
			})), new CodeInstruction(OpCodes.Dup, (object)null), lastMatchedInstruction, new CodeInstruction(OpCodes.Ldnull, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.m_Object_op_Equality), new CodeInstruction(OpCodes.Brtrue_S, (object)label), new CodeInstruction(OpCodes.Br, (object)label2)).AddLabel(label3)
				.ReleaseInstructions();
		}

		[HarmonyPostfix]
		[HarmonyPatch("AlertBird")]
		[HarmonyPatch("AlertBirdByOther")]
		private static void AlertBirdPostfix(DoublewingAI __instance)
		{
			if (useAsync && ((NetworkBehaviour)__instance).IsOwner)
			{
				PlayerControllerB playerToEvade = GetPlayerToEvade(__instance);
				if (playerToEvade != null)
				{
					StartEvasionPathfindingJob(__instance, playerToEvade);
				}
			}
		}
	}
	[HarmonyPatch(typeof(EnemyAI))]
	internal static class PatchEnemyAI
	{
		private static bool useAsyncRoaming = true;

		private static bool useAsyncPlayerPaths = false;

		private static bool StopPreviousJobAndStartNewOne(EnemyAI enemy)
		{
			if (!useAsyncRoaming)
			{
				return false;
			}
			AsyncRoamingPathfinding.EnemyRoamingPathfindingStatus status = AsyncRoamingPathfinding.GetStatus(enemy);
			if (!((JobHandle)(ref status.PathsFromEnemyJobHandle)).IsCompleted || !((JobHandle)(ref status.PathsFromSearchStartJobHandle)).IsCompleted)
			{
				status.PathsFromEnemyJob.Cancel();
				status.PathsFromSearchStartJob.Cancel();
				return true;
			}
			status.StartJobs(enemy);
			return false;
		}

		private static PathQueryStatus GetPathStatus(EnemyAI enemy, int index)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Invalid comparison between Unknown and I4
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			if (!useAsyncRoaming)
			{
				return (PathQueryStatus)1073741824;
			}
			AsyncRoamingPathfinding.EnemyRoamingPathfindingStatus status = AsyncRoamingPathfinding.GetStatus(enemy);
			if (!status.PathsFromEnemyJob.Statuses.IsCreated)
			{
				StopPreviousJobAndStartNewOne(enemy);
			}
			int jobIndex = status.GetJobIndex(index);
			PathQueryStatus result = PathQueryStatusExtensions.GetResult(status.PathsFromEnemyJob.Statuses[jobIndex]);
			if (!enemy.currentSearch.startedSearchAtSelf && (int)PathQueryStatusExtensions.GetResult(status.PathsFromSearchStartJob.Statuses[jobIndex]) == 536870912)
			{
				result = (PathQueryStatus)536870912;
			}
			return result;
		}

		private static void SetPathDistance(EnemyAI enemy, int index)
		{
			AsyncRoamingPathfinding.EnemyRoamingPathfindingStatus status = AsyncRoamingPathfinding.GetStatus(enemy);
			FindPathsToNodesJob findPathsToNodesJob = (enemy.currentSearch.startedSearchAtSelf ? status.PathsFromEnemyJob : status.PathsFromSearchStartJob);
			if (findPathsToNodesJob.PathDistances.IsCreated)
			{
				enemy.pathDistance = findPathsToNodesJob.PathDistances[status.GetJobIndex(index)];
			}
			else
			{
				enemy.pathDistance = 0f;
			}
		}

		private static void CancelJobs(EnemyAI enemy)
		{
			AsyncRoamingPathfinding.EnemyRoamingPathfindingStatus status = AsyncRoamingPathfinding.GetStatus(enemy);
			status.PathsFromEnemyJob.Cancel();
			status.PathsFromSearchStartJob.Cancel();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		private static IEnumerable<CodeInstruction> ChooseNextNodeInSearchRoutineTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase method, ILGenerator generator)
		{
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Expected O, but got Unknown
			//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01be: Expected O, but got Unknown
			//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Expected O, but got Unknown
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e0: Expected O, but got Unknown
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Expected O, but got Unknown
			//IL_01f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01fc: Expected O, but got Unknown
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_020a: Expected O, but got Unknown
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0218: Expected O, but got Unknown
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0226: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Expected O, but got Unknown
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0244: Expected O, but got Unknown
			//IL_02ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f3: Expected O, but got Unknown
			//IL_02fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0301: Expected O, but got Unknown
			//IL_0309: Unknown result type (might be due to invalid IL or missing references)
			//IL_030f: Expected O, but got Unknown
			//IL_034c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Expected O, but got Unknown
			//IL_035a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0360: Expected O, but got Unknown
			//IL_0369: Unknown result type (might be due to invalid IL or missing references)
			//IL_036f: Expected O, but got Unknown
			//IL_0380: Unknown result type (might be due to invalid IL or missing references)
			//IL_0386: Expected O, but got Unknown
			//IL_0394: Unknown result type (might be due to invalid IL or missing references)
			//IL_039a: Expected O, but got Unknown
			//IL_03a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a8: Expected O, but got Unknown
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Expected O, but got Unknown
			//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c6: Expected O, but got Unknown
			//IL_03cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d5: Expected O, but got Unknown
			//IL_03de: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Expected O, but got Unknown
			//IL_03ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f3: Expected O, but got Unknown
			//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Expected O, but got Unknown
			//IL_040b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Expected O, but got Unknown
			//IL_041b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0434: Expected O, but got Unknown
			//IL_0447: Unknown result type (might be due to invalid IL or missing references)
			//IL_044d: Expected O, but got Unknown
			//IL_045c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Expected O, but got Unknown
			//IL_046b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0471: Expected O, but got Unknown
			//IL_047a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0480: Expected O, but got Unknown
			//IL_0489: Unknown result type (might be due to invalid IL or missing references)
			//IL_048f: Expected O, but got Unknown
			//IL_049c: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a2: Expected O, but got Unknown
			//IL_04b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b7: Expected O, but got Unknown
			//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_05c5: Expected O, but got Unknown
			//IL_05d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_05d9: Expected O, but got Unknown
			//IL_069d: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a3: Expected O, but got Unknown
			//IL_06b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06b7: Expected O, but got Unknown
			//IL_06bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c5: Expected O, but got Unknown
			//IL_06cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d3: Expected O, but got Unknown
			//IL_06db: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e1: Expected O, but got Unknown
			//IL_071e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0724: Expected O, but got Unknown
			//IL_0732: Unknown result type (might be due to invalid IL or missing references)
			//IL_0738: Expected O, but got Unknown
			//IL_0781: Unknown result type (might be due to invalid IL or missing references)
			//IL_0787: Expected O, but got Unknown
			//IL_07b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_07bd: Expected O, but got Unknown
			FieldInfo fieldInfo = null;
			FieldInfo fieldInfo2 = null;
			FieldInfo fieldInfo3 = null;
			FieldInfo[] fields = method.DeclaringType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (FieldInfo fieldInfo4 in fields)
			{
				if (fieldInfo == null && fieldInfo4.Name.EndsWith("state"))
				{
					fieldInfo = fieldInfo4;
				}
				else if (fieldInfo2 == null && fieldInfo4.Name.EndsWith("current"))
				{
					fieldInfo2 = fieldInfo4;
				}
				else if (fieldInfo3 == null && fieldInfo4.Name.StartsWith("<i>"))
				{
					fieldInfo3 = fieldInfo4;
				}
			}
			if (fieldInfo == null)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the 'state' field in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			if (fieldInfo2 == null)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the 'current' field in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			if (fieldInfo3 == null)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the 'i' field in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Opcode(OpCodes.Switch));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the switch in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			Label[] array = (Label[])iLInjector.Instruction.operand;
			iLInjector.FindLabel(array[0]);
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the switch case 0 in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			Label label = generator.DefineLabel();
			iLInjector.InsertAfterBranch(new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchEnemyAI), "StopPreviousJobAndStartNewOne", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(EnemyAI) })), new CodeInstruction(OpCodes.Brfalse_S, (object)label), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldc_I4_0, (object)null), new CodeInstruction(OpCodes.Stfld, (object)fieldInfo), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldnull, (object)null), new CodeInstruction(OpCodes.Stfld, (object)fieldInfo2), new CodeInstruction(OpCodes.Ldc_I4_1, (object)null), new CodeInstruction(OpCodes.Ret, (object)null)).AddLabel(label);
			iLInjector.FindLabel(array[2]).Find(ILMatcher.Ldarg(0), ILMatcher.Ldc(-1), ILMatcher.Stfld(fieldInfo)).GoToMatchEnd();
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the switch case 2 in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			LocalBuilder localBuilder = generator.DeclareLocal(typeof(PathQueryStatus));
			Label label2 = generator.DefineLabel();
			Label label3 = generator.DefineLabel();
			Label label4 = generator.DefineLabel();
			iLInjector.InsertAfterBranch(new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo3), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchEnemyAI), "GetPathStatus", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
			{
				typeof(EnemyAI),
				typeof(int)
			})), new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Stloc, (object)localBuilder), new CodeInstruction(OpCodes.Ldc_I4, (object)536870912), new CodeInstruction(OpCodes.Bne_Un_S, (object)label2), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldc_I4_2, (object)null), new CodeInstruction(OpCodes.Stfld, (object)fieldInfo), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldnull, (object)null), new CodeInstruction(OpCodes.Stfld, (object)fieldInfo2), new CodeInstruction(OpCodes.Ldc_I4_1, (object)null), new CodeInstruction(OpCodes.Ret, (object)null), CodeInstructionExtensions.WithLabels(new CodeInstruction(OpCodes.Ldloc, (object)localBuilder), new Label[1] { label2 }), new CodeInstruction(OpCodes.Ldc_I4, (object)int.MinValue), new CodeInstruction(OpCodes.Bne_Un_S, (object)label3), new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo3), new CodeInstruction(OpCodes.Call, (object)Reflection.m_EnemyAI_EliminateNodeFromSearch), new CodeInstruction(OpCodes.Br, (object)label4)).AddLabel(label3);
			iLInjector.Find(ILMatcher.Call(Reflection.m_EnemyAI_PathIsIntersectedByLineOfSight)).Find(ILMatcher.Call(Reflection.m_EnemyAI_EliminateNodeFromSearch), ILMatcher.Opcode(OpCodes.Br));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find where AI nodes are eliminated for failing to find a path in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			Label label5 = generator.DefineLabel();
			Label label6 = (Label)iLInjector.LastMatchedInstruction.operand;
			iLInjector.GoToMatchEnd().AddLabel(label5).Back(2)
				.ReverseFind(ILMatcher.Call(Reflection.m_EnemyAI_EliminateNodeFromSearch), ILMatcher.Opcode(OpCodes.Br))
				.GoToMatchEnd();
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the instruction before a path is tested in the enumerator for EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			FieldInfo field = typeof(PatchEnemyAI).GetField("useAsyncRoaming", BindingFlags.Static | BindingFlags.NonPublic);
			iLInjector.InsertAfterBranch(new CodeInstruction(OpCodes.Ldsfld, (object)field), new CodeInstruction(OpCodes.Brtrue_S, (object)label5));
			iLInjector.Find(ILMatcher.Call(Reflection.m_EnemyAI_GetPathDistance), ILMatcher.Opcode(OpCodes.Pop)).ReverseFind(ILMatcher.Ldloc(1), ILMatcher.Ldfld(Reflection.f_EnemyAI_currentSearch), ILMatcher.Ldfld(typeof(AISearchRoutine).GetField("startedSearchAtSelf")), ILMatcher.Opcode(OpCodes.Brtrue));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the call to get the path distance in EnemyAI.ChooseNextNodeInSearchRoutine().");
				return instructions;
			}
			Label label7 = (Label)iLInjector.LastMatchedInstruction.operand;
			Label label8 = generator.DefineLabel();
			iLInjector.InsertAfterBranch(new CodeInstruction(OpCodes.Ldsfld, (object)field), new CodeInstruction(OpCodes.Brfalse_S, (object)label8), new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo3), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchEnemyAI), "SetPathDistance", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
			{
				typeof(EnemyAI),
				typeof(int)
			})), new CodeInstruction(OpCodes.Br, (object)label7)).AddLabel(label8);
			iLInjector.FindLabel(label6).AddLabel(label4);
			return iLInjector.GoToEnd().ReverseFind(ILMatcher.Opcode(OpCodes.Ret)).Insert(new CodeInstruction(OpCodes.Ldloc_1, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchEnemyAI), "CancelJobs", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(EnemyAI) })))
				.ReleaseInstructions();
		}

		private static bool IsPathToPlayerInvalid(EnemyAI enemy, int playerIndex)
		{
			AsyncPlayerPathfinding.EnemyToPlayerPathfindingStatus status = AsyncPlayerPathfinding.GetStatus(enemy);
			if (!status.hasStarted)
			{
				status.StartJobs(enemy);
				return true;
			}
			return !status.IsPathValid(playerIndex);
		}

		private static void ResetPathToPlayerStatus(EnemyAI enemy)
		{
			AsyncPlayerPathfinding.EnemyToPlayerPathfindingStatus status = AsyncPlayerPathfinding.GetStatus(enemy);
			status.ResetIfResultsHaveBeenUsed();
			if (!status.hasStarted && useAsyncPlayerPaths)
			{
				status.StartJobs(enemy);
			}
		}

		private static IEnumerator ResetPathToPlayerStatusAtEndOfFrame(EnemyAI enemy)
		{
			yield return (object)new WaitForEndOfFrame();
			ResetPathToPlayerStatus(enemy);
		}

		[HarmonyTranspiler]
		[HarmonyPatch("TargetClosestPlayer")]
		private static IEnumerable<CodeInstruction> TargetClosestPlayerTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Expected O, but got Unknown
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Expected O, but got Unknown
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Expected O, but got Unknown
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			//IL_019f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_0219: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Expected O, but got Unknown
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_022d: Expected O, but got Unknown
			//IL_025d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0263: Expected O, but got Unknown
			//IL_026f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Expected O, but got Unknown
			//IL_027d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0283: Expected O, but got Unknown
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldarg(0), ILMatcher.Call(typeof(StartOfRound).GetMethod("get_Instance")), ILMatcher.Ldfld(typeof(StartOfRound).GetField("allPlayerScripts")), ILMatcher.Ldloc(), ILMatcher.Opcode(OpCodes.Ldelem_Ref), ILMatcher.Callvirt(Reflection.m_Component_get_transform), ILMatcher.Callvirt(Reflection.m_Transform_get_position), ILMatcher.Ldc(0), ILMatcher.Ldc(0), ILMatcher.Ldc(0), ILMatcher.Call(Reflection.m_EnemyAI_PathIsIntersectedByLineOfSight));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the call to check if the enemy can path to a player in EnemyAI.TargetClosestPlayer().");
				return instructions;
			}
			CodeInstruction relativeInstruction = iLInjector.GetRelativeInstruction(3);
			Label label = generator.DefineLabel();
			Label label2 = generator.DefineLabel();
			iLInjector.Insert(new CodeInstruction(OpCodes.Ldsfld, (object)typeof(PatchEnemyAI).GetField("useAsyncPlayerPaths", BindingFlags.Static | BindingFlags.NonPublic)), new CodeInstruction(OpCodes.Brfalse_S, (object)label), new CodeInstruction(OpCodes.Ldarg_0, (object)null), relativeInstruction, new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchEnemyAI), "IsPathToPlayerInvalid", BindingFlags.Static | BindingFlags.NonPublic, new Type[2]
			{
				typeof(EnemyAI),
				typeof(int)
			})), new CodeInstruction(OpCodes.Br_S, (object)label2)).AddLabel(label).GoToMatchEnd()
				.AddLabel(label2);
			iLInjector.Find(ILMatcher.Ldarg(0), ILMatcher.Ldfld(Reflection.f_EnemyAI_targetPlayer));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find the check for whether a target player was found in EnemyAI.TargetClosestPlayer().");
				return instructions;
			}
			Label label3 = generator.DefineLabel();
			return iLInjector.Insert(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchEnemyAI), "ResetPathToPlayerStatusAtEndOfFrame", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(EnemyAI) })), new CodeInstruction(OpCodes.Call, (object)Reflection.m_MonoBehaviour_StartCoroutine), new CodeInstruction(OpCodes.Pop, (object)null)).AddLabel(label3).ReleaseInstructions();
		}

		[HarmonyPostfix]
		[HarmonyPatch("OnDestroy")]
		private static void OnDestroyPostfix(EnemyAI __instance)
		{
			AsyncDistancePathfinding.RemoveStatus(__instance);
			AsyncPlayerPathfinding.RemoveStatus(__instance);
			AsyncRoamingPathfinding.RemoveStatus(__instance);
		}
	}
	[HarmonyPatch(typeof(FlowermanAI))]
	internal static class PatchFlowermanAI
	{
		private static readonly FieldInfo f_FlowermanAI_mainEntrancePosition = AccessTools.Field(typeof(FlowermanAI), "mainEntrancePosition");

		private static readonly MethodInfo m_FlowermanAI_ChooseClosestNodeToPlayer = typeof(FlowermanAI).GetMethod("ChooseClosestNodeToPlayer", Array.Empty<Type>());

		private static readonly FieldInfo f_PatchFlowermanAI_useAsync = typeof(PatchFlowermanAI).GetField("useAsync");

		private static bool useAsync = true;

		private const int FAR_FROM_MAIN_ID = 0;

		private const int EVADE_PLAYER_ID = 1;

		private const int SNEAK_TO_PLAYER_ID = 2;

		private static bool ChooseFarthestNodeFromMainEntranceAsync(FlowermanAI flowerman)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			if (useAsync)
			{
				Transform val = AsyncDistancePathfinding.StartChoosingFarthestNodeFromPosition((EnemyAI)(object)flowerman, 0, flowerman.mainEntrancePosition).RetrieveChosenNode(out ((EnemyAI)flowerman).mostOptimalDistance);
				if ((Object)(object)val != (Object)null)
				{
					if ((Object)(object)((EnemyAI)flowerman).favoriteSpot == (Object)null)
					{
						((EnemyAI)flowerman).favoriteSpot = val;
					}
					((EnemyAI)flowerman).targetNode = val;
					((EnemyAI)flowerman).SetDestinationToPosition(val.position, false);
				}
				return true;
			}
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch("DoAIInterval")]
		private static IEnumerable<CodeInstruction> DoAIIntervalTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0162: Expected O, but got Unknown
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Expected O, but got Unknown
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Call(m_FlowermanAI_ChooseClosestNodeToPlayer), ILMatcher.Branch()).GoToMatchEnd();
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find call to ChooseClosestNodeToPlayer in FlowermanAI.DoAIInterval().");
				return instructions;
			}
			Label label = (Label)iLInjector.GetRelativeInstruction(-1).operand;
			iLInjector.Find(ILMatcher.Ldarg(0), ILMatcher.Ldarg(0), ILMatcher.Ldfld(typeof(FlowermanAI).GetField("mainEntrancePosition", BindingFlags.Instance | BindingFlags.NonPublic)), ILMatcher.Ldc(0), ILMatcher.Ldc(0), ILMatcher.Ldc(0), ILMatcher.Ldc(50), ILMatcher.Ldc(0), ILMatcher.Call(Reflection.m_EnemyAI_ChooseFarthestNodeFromPosition));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find call to ChooseFarthestNodeFromPosition in FlowermanAI.DoAIInterval().");
				return instructions;
			}
			return iLInjector.InsertInPlaceAfterBranch(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchFlowermanAI), "ChooseFarthestNodeFromMainEntranceAsync", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(FlowermanAI) })), new CodeInstruction(OpCodes.Brtrue_S, (object)label)).ReleaseInstructions();
		}

		private static bool ChoosePlayerEvasionNodeAsync(FlowermanAI flowerman)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			if (!useAsync)
			{
				return false;
			}
			Transform val = AsyncDistancePathfinding.StartChoosingFarthestNodeFromPosition((EnemyAI)(object)flowerman, 1, ((Component)((EnemyAI)flowerman).targetPlayer).transform.position, avoidLineOfSight: true, 0, 60f).RetrieveChosenNode(out ((EnemyAI)flowerman).mostOptimalDistance);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			flowerman.farthestNodeFromTargetPlayer = val;
			return false;
		}

		[HarmonyTranspiler]
		[HarmonyPatch("AvoidClosestPlayer")]
		private static IEnumerable<CodeInstruction> AvoidClosestPlayerTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Expected O, but got Unknown
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Expected O, but got Unknown
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fd: Expected O, but got Unknown
			ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldarg(0), ILMatcher.Ldfld(typeof(FlowermanAI).GetField("farthestNodeFromTargetPlayer", BindingFlags.Instance | BindingFlags.NonPublic)), ILMatcher.Opcode(OpCodes.Ldnull), ILMatcher.Call(Reflection.m_Object_op_Equality), ILMatcher.Opcode(OpCodes.Brfalse));
			if (!iLInjector.IsValid)
			{
				Plugin.Instance.Logger.LogError((object)"Failed to find check for the farthest node from the target player in FlowermanAI.AvoidClosestPlayer().");
				return instructions;
			}
			Label label = generator.DefineLabel();
			return iLInjector.AddLabel(label).InsertInPlace(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchFlowermanAI), "ChoosePlayerEvasionNodeAsync", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(FlowermanAI) })), new CodeInstruction(OpCodes.Brfalse_S