Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of PathfindingLagFix v2.4.0
PathfindingLagFix.dll
Decompiled a day ago
The result has been truncated due to the large size, download it to view full contents!
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.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using HarmonyLib.Public.Patching; using Microsoft.CodeAnalysis; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Collections.Generic; 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.Netcode; using Unity.Profiling; using Unity.Profiling.LowLevel; using Unity.Profiling.LowLevel.Unsafe; using UnityEngine; using UnityEngine.AI; using UnityEngine.Experimental.AI; using UnityEngine.SceneManagement; using UnityEngine.Scripting; [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.4.0")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("2.4.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsUnmanagedAttribute : Attribute { } [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 { internal struct ConfigOptions { private enum ConfigPreset { OnlyFixes, Vanilla } private static readonly ConfigOptions OnlyFixesPreset = new ConfigOptions { DistancePathfindingFallbackNodeSelection = DistancePathfindingFallbackNodeSelectionType.BestPathable }; private static readonly ConfigOptions VanillaPreset = new ConfigOptions { DistancePathfindingFallbackNodeSelection = DistancePathfindingFallbackNodeSelectionType.Vanilla }; internal static ConfigOptions CurrentOptions = OnlyFixesPreset; private const string presetDescription = "Select a preset to use as defaults for all options that change gameplay.\n\nOnlyFixes: Options that are intended to act solely as bug fixes and should retain the intention of the original code.\nVanilla: Options that completely match vanilla as much as possible."; private static ConfigEntry<ConfigPreset> presetOption; private const string distancePathfindingFallbackNodeSelectionDescription = "How nodes should be selected if the criteria for a distance based pathfinding operation (i.e. bracken evasion) fails.\n\nUsePreset: Use the option selected by the current preset.\nBestPathable: The enemy will go to the furthest/closest node that can be reached. This is the old behavior of PathfindingLagFix, and it guarantees the bracken will not get stuck when spotted.\nVanilla: The enemy will attempt to go to the furthest/closest node, regardless of whether it can be reached. This will cause brackens to sometimes stutter step towards the furthest position instead of moving smoothly.\nDontMove: The enemy will not move until it has a valid path to follow. For the bracken, this will result in it standing still and looking at the player until they look away."; private static ConfigEntry<DistancePathfindingFallbackNodeSelectionType> distancePathfindingFallbackNodeSelectionOption; internal DistancePathfindingFallbackNodeSelectionType DistancePathfindingFallbackNodeSelection; internal static void BindAllOptions(ConfigFile file) { presetOption = BindOption(file, "General", "Preset", ConfigPreset.OnlyFixes, "Select a preset to use as defaults for all options that change gameplay.\n\nOnlyFixes: Options that are intended to act solely as bug fixes and should retain the intention of the original code.\nVanilla: Options that completely match vanilla as much as possible."); distancePathfindingFallbackNodeSelectionOption = BindOption(file, "Behavior", "DistancePathfindingFallbackNodeSelection", DistancePathfindingFallbackNodeSelectionType.UsePreset, "How nodes should be selected if the criteria for a distance based pathfinding operation (i.e. bracken evasion) fails.\n\nUsePreset: Use the option selected by the current preset.\nBestPathable: The enemy will go to the furthest/closest node that can be reached. This is the old behavior of PathfindingLagFix, and it guarantees the bracken will not get stuck when spotted.\nVanilla: The enemy will attempt to go to the furthest/closest node, regardless of whether it can be reached. This will cause brackens to sometimes stutter step towards the furthest position instead of moving smoothly.\nDontMove: The enemy will not move until it has a valid path to follow. For the bracken, this will result in it standing still and looking at the player until they look away."); UpdateCurrentOptions(); } private static ConfigEntry<T> BindOption<T>(ConfigFile file, string section, string key, T defaultValue, string description) { ConfigEntry<T> obj = file.Bind<T>(section, key, defaultValue, description); obj.SettingChanged += delegate { UpdateCurrentOptions(); }; return obj; } private static void UpdateCurrentOptions() { CurrentOptions = presetOption.Value switch { ConfigPreset.OnlyFixes => OnlyFixesPreset, ConfigPreset.Vanilla => VanillaPreset, _ => throw new InvalidOperationException($"Unknown preset {presetOption.Value}"), }; if (distancePathfindingFallbackNodeSelectionOption.Value != 0) { CurrentOptions.DistancePathfindingFallbackNodeSelection = distancePathfindingFallbackNodeSelectionOption.Value; } Plugin.Instance.Logger.LogInfo((object)string.Format("{0} {1} is using preset {2} with options:", "Zaggy1024.PathfindingLagFix", "2.4.0", presetOption.Value)); Plugin.Instance.Logger.LogInfo((object)string.Format(" {0} = {1} ({2})", "DistancePathfindingFallbackNodeSelection", CurrentOptions.DistancePathfindingFallbackNodeSelection, distancePathfindingFallbackNodeSelectionOption.Value)); } } internal enum DistancePathfindingFallbackNodeSelectionType { UsePreset, BestPathable, Vanilla, DontMove } [BepInPlugin("Zaggy1024.PathfindingLagFix", "PathfindingLagFix", "2.4.0")] [BepInDependency("Zaggy1024.PathfindingLib", "2.3.0")] public class Plugin : BaseUnityPlugin { public const string MOD_NAME = "PathfindingLagFix"; public const string MOD_UNIQUE_NAME = "Zaggy1024.PathfindingLagFix"; public const string MOD_VERSION = "2.4.0"; 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; ConfigOptions.BindAllOptions(((BaseUnityPlugin)this).Config); harmony.PatchAll(typeof(PatchEnemyAI)); harmony.PatchAll(typeof(PatchFlowermanAI)); harmony.PatchAll(typeof(PatchCentipedeAI)); harmony.PatchAll(typeof(PatchPufferAI)); harmony.PatchAll(typeof(PatchDoublewingAI)); harmony.PatchAll(typeof(PatchFlowerSnakeEnemy)); harmony.PatchAll(typeof(PatchSpringManAI)); harmony.PatchAll(typeof(PatchBlobAI)); harmony.PatchAll(typeof(PatchCaveDwellerAI)); harmony.PatchAll(typeof(PatchStingrayAI)); PatchFindMainEntrance.ApplyPatches(harmony); } } } namespace PathfindingLagFix.Utilities { internal struct AssignGroundCastPointsAsDestinationsJob : IJobFor { [ReadOnly] private NativeArray<RaycastHit> Hits; [WriteOnly] private NativeArray<Vector3> Destinations; public void Initialize(NativeArray<RaycastHit> hits, NativeArray<Vector3> points) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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) Hits = hits; Destinations = points; } public void Execute(int index) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_001d: Unknown result type (might be due to invalid IL or missing references) RaycastHit val = Hits[index]; if (((RaycastHit)(ref val)).colliderInstanceID == 0) { Destinations[index] = FindPathsToNodesJob.INVALID_DESTINATION; return; } ref NativeArray<Vector3> destinations = ref Destinations; val = Hits[index]; destinations[index] = ((RaycastHit)(ref val)).point; } } 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); [CompilerGenerated] private sealed class <ChooseNodeCoroutine>d__10 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public EnemyAI enemy; public EnemyDistancePathfindingStatus status; public Vector3 target; public bool farthestFirst; public float capDistance; public int offset; public bool avoidLineOfSight; private int <candidateCount>5__2; private FindPathsToNodesJob <job>5__3; private JobHandle <jobHandle>5__4; private int <result>5__5; private float <capDistanceSqr>5__6; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <ChooseNodeCoroutine>d__10(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0120: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Invalid comparison between Unknown and I4 //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Invalid comparison between Unknown and I4 //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_02c2: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Invalid comparison between Unknown and I4 switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (enemy.allAINodes.Length == 0 || !enemy.agent.isOnNavMesh) { status.ChosenNode = ((Component)enemy).transform; status.MostOptimalDistance = 0f; return false; } <candidateCount>5__2 = enemy.allAINodes.Length; StartJobs(enemy, status, target, <candidateCount>5__2, farthestFirst); <job>5__3 = status.Job; <jobHandle>5__4 = status.JobHandle; <result>5__5 = -1; <capDistanceSqr>5__6 = capDistance * capDistance; goto IL_01e4; case 1: { <>1__state = -1; bool flag = true; int num = Math.Min(offset, <candidateCount>5__2 - 1); Vector3 position = ((Component)enemy).transform.position; for (int i = 0; i < <candidateCount>5__2; i++) { if (<capDistanceSqr>5__6 > 0f) { Vector3 val = status.SortedPositions[i] - position; if (((Vector3)(ref val)).sqrMagnitude > <capDistanceSqr>5__6) { continue; } } PathQueryStatus val2 = <job>5__3.Statuses[i]; if ((int)PathQueryStatusExtensions.GetResult(val2) == 536870912) { flag = false; break; } if ((int)PathQueryStatusExtensions.GetResult(val2) == 1073741824) { NativeArray<Vector3> path = <job>5__3.GetPath(i); if ((!avoidLineOfSight || !LineOfSight.PathIsBlockedByLineOfSight(path)) && num-- == 0) { <result>5__5 = i; break; } } } if (!flag) { goto IL_01e4; } goto IL_01f0; } case 2: { <>1__state = -1; break; } IL_01e4: if (<result>5__5 == -1) { <>2__current = null; <>1__state = 1; return true; } goto IL_01f0; IL_01f0: <job>5__3.Cancel(); if (<result>5__5 == -1) { switch (ConfigOptions.CurrentOptions.DistancePathfindingFallbackNodeSelection) { case DistancePathfindingFallbackNodeSelectionType.BestPathable: { for (int j = 0; j < <candidateCount>5__2; j++) { if ((int)PathQueryStatusExtensions.GetResult(<job>5__3.Statuses[j]) == 1073741824) { <result>5__5 = j; break; } } break; } case DistancePathfindingFallbackNodeSelectionType.Vanilla: <result>5__5 = 0; break; } } if (<result>5__5 == -1) { status.ChosenNode = ((Component)enemy).transform; status.MostOptimalDistance = 0f; } else { status.ChosenNode = status.SortedNodes[<result>5__5]; status.MostOptimalDistance = Vector3.Distance(target, status.SortedPositions[<result>5__5]); } break; } if (!((JobHandle)(ref <jobHandle>5__4)).IsCompleted) { <>2__current = null; <>1__state = 2; return true; } status.Coroutine = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal const float DEFAULT_CAP_DISTANCE = 40f; private static readonly EnemyMap<EnemyDistancePathfindingStatus> Statuses = new EnemyMap<EnemyDistancePathfindingStatus>(() => new EnemyDistancePathfindingStatus()); internal static void RemoveStatus(EnemyAI enemy) { Statuses.Remove(enemy); } internal static EnemyDistancePathfindingStatus StartJobs(EnemyAI enemy, EnemyDistancePathfindingStatus status, Vector3 target, int count, bool farthestFirst, bool calculateDistance = false) { //IL_0009: 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_0032: 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_0038: Unknown result type (might be due to invalid IL or missing references) NavMeshAgent agent = enemy.agent; status.SortNodes(enemy, target, farthestFirst); ref FindPathsToNodesJob job = ref status.Job; job.Initialize(agent, status.SortedPositions, calculateDistance); 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]; if (enemyDistancePathfindingStatus.CurrentSearchTypeID == searchTypeID) { return enemyDistancePathfindingStatus; } if (enemyDistancePathfindingStatus.Coroutine != null) { enemyDistancePathfindingStatus.Job.Cancel(); return enemyDistancePathfindingStatus; } enemyDistancePathfindingStatus.RetrieveChosenNode(out var _); 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); } [IteratorStateMachine(typeof(<ChooseNodeCoroutine>d__10))] 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) //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <ChooseNodeCoroutine>d__10(0) { enemy = enemy, status = status, target = target, farthestFirst = farthestFirst, avoidLineOfSight = avoidLineOfSight, offset = offset, capDistance = capDistance }; } } internal static class AsyncPlayerPathfinding { [Flags] internal enum PathOptions : byte { None = 0, GroundCast = 1, RequirePath = 2 } internal class EnemyToPlayerPathfindingStatus { internal enum JobsStatus { NotStarted, NotRetrieved, RetrievedJobsDone, RetrievedJobsIncomplete } [CompilerGenerated] private PathOptions <pathFlags>P; internal FindPathsToNodesJob PathsToPlayersJob; private AssignGroundCastPointsAsDestinationsJob AssignDestinationsJob; internal JobHandle JobHandle; private NativeArray<RaycastCommand> raycastCommands; private NativeArray<RaycastHit> raycastHits; private NativeArray<Vector3> playerPositions; private float inFlightJobsTime; private float currentJobsTime; private bool[] playersPathable; public EnemyToPlayerPathfindingStatus(PathOptions pathFlags) { <pathFlags>P = pathFlags; inFlightJobsTime = float.NegativeInfinity; currentJobsTime = float.NegativeInfinity; playersPathable = Array.Empty<bool>(); base..ctor(); } private void StartJobs(EnemyAI enemy) { //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_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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_0090: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_024a: 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_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) NavMeshAgent agent = enemy.agent; PlayerControllerB[] allPlayerScripts = StartOfRound.Instance.allPlayerScripts; if (playerPositions.Length != allPlayerScripts.Length) { Clear(); playerPositions = new NativeArray<Vector3>(allPlayerScripts.Length, (Allocator)4, (NativeArrayOptions)0); if (<pathFlags>P.HasFlag(PathOptions.GroundCast)) { raycastCommands = new NativeArray<RaycastCommand>(allPlayerScripts.Length, (Allocator)4, (NativeArrayOptions)0); raycastHits = new NativeArray<RaycastHit>(allPlayerScripts.Length, (Allocator)4, (NativeArrayOptions)0); } } for (int i = 0; i < allPlayerScripts.Length; i++) { PlayerControllerB val = allPlayerScripts[i]; if (!enemy.PlayerIsTargetable(val, false, false, true)) { playerPositions[i] = FindPathsToNodesJob.INVALID_DESTINATION; if (<pathFlags>P.HasFlag(PathOptions.GroundCast)) { raycastCommands[i] = default(RaycastCommand); raycastHits[i] = default(RaycastHit); } continue; } Vector3 position = ((Component)val).transform.position; playerPositions[i] = position; if (<pathFlags>P.HasFlag(PathOptions.GroundCast)) { QueryParameters @default = QueryParameters.Default; @default.layerMask = StartOfRound.Instance.collidersAndRoomMaskAndDefault; @default.hitTriggers = (QueryTriggerInteraction)1; QueryParameters val2 = @default; raycastCommands[i] = new RaycastCommand(position, Vector3.down, val2, 5f); raycastHits[i] = default(RaycastHit); } } JobHandle val3 = default(JobHandle); if (<pathFlags>P.HasFlag(PathOptions.GroundCast)) { val3 = RaycastCommand.ScheduleBatch(raycastCommands, raycastHits, 1, val3); } if (<pathFlags>P.HasFlag(PathOptions.GroundCast) && <pathFlags>P.HasFlag(PathOptions.RequirePath)) { AssignDestinationsJob.Initialize(raycastHits, playerPositions); val3 = IJobForExtensions.ScheduleByRef<AssignGroundCastPointsAsDestinationsJob>(ref AssignDestinationsJob, playerPositions.Length, val3); } if (<pathFlags>P.HasFlag(PathOptions.RequirePath)) { PathsToPlayersJob.Initialize(agent, playerPositions.Length); PathsToPlayersJob.SetDestinations(playerPositions); val3 = IJobForExtensions.ScheduleByRef<FindPathsToNodesJob>(ref PathsToPlayersJob, playerPositions.Length, val3); } JobHandle = val3; inFlightJobsTime = Time.time; } internal bool AllJobsAreDone() { return ((JobHandle)(ref JobHandle)).IsCompleted; } internal float UpdatePathsAndGetCalculationTime(EnemyAI enemy) { //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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Invalid comparison between Unknown and I4 //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!AllJobsAreDone()) { return currentJobsTime; } if (playersPathable.Length != playerPositions.Length) { Array.Resize(ref playersPathable, playerPositions.Length); } if (<pathFlags>P.HasFlag(PathOptions.RequirePath)) { for (int i = 0; i < playerPositions.Length; i++) { PathQueryStatus result = PathQueryStatusExtensions.GetResult(PathsToPlayersJob.Statuses[i]); playersPathable[i] = (int)result == 1073741824; } } else { if (!<pathFlags>P.HasFlag(PathOptions.GroundCast)) { throw new InvalidOperationException("Bad path flags"); } for (int j = 0; j < playerPositions.Length; j++) { bool[] array = playersPathable; int num = j; RaycastHit val = raycastHits[j]; array[num] = ((RaycastHit)(ref val)).colliderInstanceID != 0; } } currentJobsTime = inFlightJobsTime; StartJobs(enemy); return currentJobsTime; } internal bool CanReachPlayer(int playerIndex) { return playersPathable[playerIndex]; } internal void Invalidate() { currentJobsTime = float.NegativeInfinity; inFlightJobsTime = float.NegativeInfinity; } internal void Clear() { raycastCommands.Dispose(); raycastHits.Dispose(); playerPositions.Dispose(); playersPathable = Array.Empty<bool>(); } ~EnemyToPlayerPathfindingStatus() { PathsToPlayersJob.FreeAllResources(disposeDestinations: false); Clear(); } } private const byte PlayerPathFlagsMax = 3; private static readonly EnemyMap<EnemyToPlayerPathfindingStatus>[] Statuses = CreateStatusMaps(); private static EnemyMap<EnemyToPlayerPathfindingStatus>[] CreateStatusMaps() { EnemyMap<EnemyToPlayerPathfindingStatus>[] array = new EnemyMap<EnemyToPlayerPathfindingStatus>[3]; for (byte b = 0; b < 3; b++) { PathOptions flags = (PathOptions)(b + 1); array[b] = new EnemyMap<EnemyToPlayerPathfindingStatus>(() => new EnemyToPlayerPathfindingStatus(flags)); } return array; } internal static void RemoveStatus(EnemyAI enemy) { for (byte b = 0; b < 3; b++) { Statuses[b][enemy].Invalidate(); } } internal static EnemyToPlayerPathfindingStatus GetStatus(EnemyAI enemy, PathOptions flags) { return Statuses[(uint)(flags - 1)][enemy]; } } internal static class AsyncRoamingPathfinding { internal class EnemyRoamingPathfindingStatus { internal FindPathsToNodesJob PathsFromEnemyJob; internal JobHandle PathsFromEnemyJobHandle; internal FindPathsToNodesJob PathsFromSearchStartJob; internal JobHandle PathsFromSearchStartJobHandle; private Vector3[] nodePositions = Array.Empty<Vector3>(); private int nodeCount; internal void StartJobs(EnemyAI enemy) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) AISearchRoutine currentSearch = enemy.currentSearch; NavMeshAgent agent = enemy.agent; List<GameObject> unsearchedNodes = currentSearch.unsearchedNodes; nodeCount = unsearchedNodes.Count; if (nodeCount > nodePositions.Length) { nodePositions = (Vector3[])(object)new Vector3[nodeCount]; } for (int i = 0; i < unsearchedNodes.Count; i++) { nodePositions[GetJobIndex(i)] = unsearchedNodes[i].transform.position; } PathsFromEnemyJob.Initialize(agent, nodePositions, nodeCount, currentSearch.startedSearchAtSelf); PathsFromEnemyJobHandle = IJobForExtensions.ScheduleByRef<FindPathsToNodesJob>(ref PathsFromEnemyJob, unsearchedNodes.Count, default(JobHandle)); if (!currentSearch.startedSearchAtSelf) { PathsFromSearchStartJob.Initialize(-1, agent.areaMask, default(Span<float>), currentSearch.currentSearchStartPosition, nodePositions, nodeCount, 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 EnemyMap<EnemyRoamingPathfindingStatus> Statuses = new EnemyMap<EnemyRoamingPathfindingStatus>(() => new EnemyRoamingPathfindingStatus()); internal static void RemoveStatus(EnemyAI enemy) { Statuses.Remove(enemy); } internal static EnemyRoamingPathfindingStatus GetStatus(EnemyAI enemy) { return Statuses[enemy]; } } public class EnemyMap<T> { private readonly Func<T> constructor; private Dictionary<int, T> backingDictionary; public T this[EnemyAI enemy] => GetItem(enemy); public int Count => backingDictionary.Count; public EnemyMap(Func<T> elementConstructor) { constructor = elementConstructor; backingDictionary = new Dictionary<int, T>(); base..ctor(); } public T GetItem(EnemyAI enemy) { int instanceID = ((Object)enemy).GetInstanceID(); if (backingDictionary.TryGetValue(instanceID, out var value)) { return value; } value = constructor(); backingDictionary[instanceID] = value; return value; } public void Clear() { backingDictionary = new Dictionary<int, T>(); } public bool Remove(EnemyAI enemy) { return backingDictionary.Remove(((Object)enemy).GetInstanceID()); } public bool Contains(EnemyAI enemy) { return backingDictionary.ContainsKey(((Object)enemy).GetInstanceID()); } } internal struct FindPathsToNodesJob : IJobFor { public static readonly Vector3 INVALID_DESTINATION = new Vector3(float.NaN, float.NaN, float.NaN); [NativeDisableContainerSafetyRestriction] private static NativeArray<NavMeshQuery> StaticThreadQueries; private const float MAX_ENDPOINT_DISTANCE = 1.55f; private const float MAX_ENDPOINT_DISTANCE_SQR = 2.4025f; [ReadOnly] [NativeSetThreadIndex] internal int ThreadIndex; [ReadOnly] [NativeDisableContainerSafetyRestriction] [NativeDisableParallelForRestriction] internal NativeArray<NavMeshQuery> ThreadQueriesRef; [ReadOnly] private int AgentTypeID; [ReadOnly] private int AreaMask; [ReadOnly] private NativeArray<float> Costs; [ReadOnly] private Vector3 QueryExtents; [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<Vector3> Paths; [WriteOnly] [NativeDisableContainerSafetyRestriction] internal NativeArray<int> PathSizes; [WriteOnly] [NativeDisableContainerSafetyRestriction] internal NativeArray<float> PathDistances; public unsafe void Initialize(int agentTypeID, int areaMask, Span<float> costs, 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_0048: 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_0055: 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_0060: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) ThreadQueriesRef = Unsafe.Read<NativeArray<NavMeshQuery>>((void*)PathfindingJobSharedResources.GetPerThreadQueriesArray()); CreateFixedArrays(); AgentTypeID = agentTypeID; AreaMask = areaMask; if (costs == default(Span<float>)) { Costs.SetAllElements(1f); } else { Costs.CopyFrom(costs); } QueryExtents = NavMeshQueryUtils.GetQueryExtents(agentTypeID); Origin = origin; CalculateDistance = calculateDistance; EnsureCount(count); Statuses.SetAllElements<PathQueryStatus>((PathQueryStatus)536870912); if (calculateDistance) { PathDistances.SetAllElements(0f); } Canceled[0] = false; if (candidates != null) { if (Destinations.IsCreated) { Destinations.Dispose(); } if (count > 0) { Destinations = new NativeArray<Vector3>(count, (Allocator)4, (NativeArrayOptions)1); NativeArray<Vector3>.Copy(candidates, Destinations, count); } } } public void Initialize(NavMeshAgent agent, Vector3[] candidates, int count, bool calculateDistance = false) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) int agentTypeID = default(int); int areaMask = default(int); Span<float> costs = default(Span<float>); AgentExtensions.GetQueryFilter(agent, ref agentTypeID, ref areaMask, ref costs); Initialize(agentTypeID, areaMask, costs, AgentExtensions.GetPathOrigin(agent), candidates, count, calculateDistance); } public void Initialize(NavMeshAgent agent, int count, bool calculateDistance = false) { Initialize(agent, null, count, calculateDistance); } public void Initialize(int agentTypeID, int areaMask, Span<float> costs, Vector3 origin, Vector3[] candidates, bool calculateDistance = false) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) Initialize(agentTypeID, areaMask, costs, origin, candidates, candidates.Length, calculateDistance); } public void Initialize(NavMeshAgent agent, Vector3[] candidates, bool calculateDistance = false) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) int agentTypeID = default(int); int areaMask = default(int); Span<float> costs = default(Span<float>); AgentExtensions.GetQueryFilter(agent, ref agentTypeID, ref areaMask, ref costs); Initialize(agentTypeID, areaMask, costs, AgentExtensions.GetPathOrigin(agent), candidates, calculateDistance); } public void Initialize(int agentTypeID, int areaMask, Span<float> costs, Vector3 origin, List<Vector3> candidates, bool calculateDistance = false) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) Initialize(agentTypeID, areaMask, costs, origin, NoAllocHelpers.ExtractArrayFromListT<Vector3>(candidates), candidates.Count, calculateDistance); } public void Initialize(NavMeshAgent agent, List<Vector3> candidates, bool calculateDistance = false) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) int agentTypeID = default(int); int areaMask = default(int); Span<float> costs = default(Span<float>); AgentExtensions.GetQueryFilter(agent, ref agentTypeID, ref areaMask, ref costs); Initialize(agentTypeID, areaMask, costs, AgentExtensions.GetPathOrigin(agent), candidates, calculateDistance); } public void SetDestinations(NativeArray<Vector3> destinations) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Destinations = destinations; } private void CreateFixedArrays() { //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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (Canceled.Length != 1) { Costs = new NativeArray<float>(32, (Allocator)4, (NativeArrayOptions)1); 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_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_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) if (Statuses.Length < count) { DisposeResizeableArrays(); if (count != 0) { Statuses = new NativeArray<PathQueryStatus>(count, (Allocator)4, (NativeArrayOptions)1); Paths = new NativeArray<Vector3>(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 (Statuses.IsCreated) { Statuses.Dispose(); Paths.Dispose(); PathSizes.Dispose(); PathDistances.Dispose(); } } public void Cancel() { if (Canceled.IsCreated) { Canceled[0] = true; } } public NativeArray<Vector3> 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<Vector3> 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_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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_008c: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00ea: 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_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Invalid comparison between Unknown and I4 //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Invalid comparison between Unknown and I4 //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: 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_015c: Invalid comparison between Unknown and I4 //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0196: 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_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: 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_01e5: Invalid comparison between Unknown and I4 //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0236: 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_029b: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) if (Canceled[0]) { Statuses[index] = (PathQueryStatus)int.MinValue; return; } NavMeshReadLocker val = default(NavMeshReadLocker); ((NavMeshReadLocker)(ref val))..ctor(); try { Vector3 val2 = Destinations[index]; if (((Vector3)(ref val2)).Equals(INVALID_DESTINATION)) { Statuses[index] = (PathQueryStatus)int.MinValue; return; } NavMeshQuery val3 = ThreadQueriesRef[ThreadIndex]; NavMeshLocation val4 = ((NavMeshQuery)(ref val3)).MapLocation(Origin, QueryExtents, AgentTypeID, AreaMask); if (!((NavMeshQuery)(ref val3)).IsValid(val4)) { Statuses[index] = (PathQueryStatus)int.MinValue; return; } NavMeshLocation val5 = ((NavMeshQuery)(ref val3)).MapLocation(val2, QueryExtents, AgentTypeID, AreaMask); if (!((NavMeshQuery)(ref val3)).IsValid(val5)) { Statuses[index] = (PathQueryStatus)int.MinValue; return; } PathQueryStatus val6 = ((NavMeshQuery)(ref val3)).BeginFindPath(val4, val5, AreaMask, Costs); if ((int)PathQueryStatusExtensions.GetResult(val6) == int.MinValue) { Statuses[index] = val6; return; } int num = default(int); while ((int)PathQueryStatusExtensions.GetResult(val6) == 536870912) { val6 = ((NavMeshQuery)(ref val3)).UpdateFindPath(NavMeshLock.RecommendedUpdateFindPathIterationCount, ref num); ((NavMeshReadLocker)(ref val)).Yield(); } int num2 = default(int); val6 = ((NavMeshQuery)(ref val3)).EndFindPath(ref num2); if ((int)PathQueryStatusExtensions.GetResult(val6) != 1073741824) { Statuses[index] = val6; return; } NativeArray<PolygonId> val7 = new NativeArray<PolygonId>(num2, (Allocator)2, (NativeArrayOptions)1); ((NavMeshQuery)(ref val3)).GetPathResult(NativeSlice<PolygonId>.op_Implicit(val7)); NavMeshQuery val8 = val3; ref Vector3 origin = ref Origin; NativeSlice<PolygonId> val9 = NativeSlice<PolygonId>.op_Implicit(val7); int num3 = num2; NativeArray<Vector3> pathBuffer = GetPathBuffer(index); int num4 = default(int); val6 = (PathQueryStatus)(NavMeshQueryUtils.FindStraightPath(val8, ref origin, ref val2, ref val9, num3, ref pathBuffer, ref num4) | PathQueryStatusExtensions.GetDetail(val6)); ((NavMeshReadLocker)(ref val)).Dispose(); PathSizes[index] = num4; val7.Dispose(); if ((int)PathQueryStatusExtensions.GetResult(val6) != 1073741824) { Statuses[index] = val6; return; } NativeArray<Vector3> path = GetPath(index); Vector3 val10 = path[path.Length - 1] - val2; if (((Vector3)(ref val10)).sqrMagnitude > 2.4025f) { Statuses[index] = (PathQueryStatus)(int.MinValue | PathQueryStatusExtensions.GetDetail(val6)); return; } if (CalculateDistance) { float num5 = 0f; for (int i = 1; i < path.Length; i++) { num5 += Vector3.Distance(path[i - 1], path[i]); } PathDistances[index] = num5; } Statuses[index] = val6; } finally { ((IDisposable)(NavMeshReadLocker)(ref val)).Dispose(); } } internal void FreeAllResources(bool disposeDestinations = true) { DisposeResizeableArrays(); DisposeFixedArrays(); if (disposeDestinations) { Destinations.Dispose(); } } } internal static class LineOfSight { private const int LINE_OF_SIGHT_LAYER_MASK = 262144; public static bool PathIsBlockedByLineOfSight(NativeArray<Vector3> path, out float pathDistance, Vector3? checkLOSToPosition = null) { //IL_0021: 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_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: 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_0041: 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_0046: 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) //IL_0061: 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_0053: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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) pathDistance = 0f; if (path.Length == 0) { return true; } if (path.Length == 1) { return false; } Vector3 val = path[0]; for (int i = 1; i < path.Length && i < 16; i++) { Vector3 val2 = path[i - 1]; Vector3 val3 = path[i]; pathDistance += Vector3.Distance(val2, val3); if (i <= 5 || !(Vector3.Distance(val, val3) < 1.7f)) { val = val3; if (checkLOSToPosition.HasValue && !Physics.Linecast(val2, checkLOSToPosition.Value + Vector3.up * 0.3f, StartOfRound.Instance.collidersAndRoomMaskAndDefault, (QueryTriggerInteraction)1)) { return true; } if (Physics.Linecast(val2, val3, 262144)) { return true; } } } return false; } public static bool PathIsBlockedByLineOfSight(NativeArray<Vector3> path, Vector3? checkLOSToPosition = null) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) float pathDistance; return PathIsBlockedByLineOfSight(path, out pathDistance, checkLOSToPosition); } } internal static class NativeArrayUtils { internal unsafe static void SetAllElements<T>(this NativeArray<T> array, T value) where T : unmanaged { //IL_0000: Unknown result type (might be due to invalid IL or missing references) T* buffer = (T*)array.m_Buffer; int length = array.Length; for (int i = 0; i < length; i++) { buffer[i] = value; } } internal unsafe static void CopyFrom<T>(this NativeArray<T> array, Span<T> span) where T : struct { //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (array.Length < span.Length) { throw new InvalidOperationException($"NativeArray size {array.Length} is smaller than span size {span.Length}."); } UnsafeUtility.MemCpy(NativeArrayUnsafeUtility.GetUnsafePtr<T>(array), UnsafeUtility.AddressOf<T>(ref span[0]), (long)span.Length); } } [IgnoredByDeepProfiler] [UsedByNativeCode] internal struct ProfilerMarkerWithMetadata<T> where T : unmanaged { [IgnoredByDeepProfiler] [UsedByNativeCode] public struct AutoScope : IDisposable { [NativeDisableUnsafePtrRestriction] internal readonly ProfilerMarkerWithMetadata<T> marker; internal T value; internal bool on; [MethodImpl(MethodImplOptions.AggressiveInlining)] public AutoScope(in ProfilerMarkerWithMetadata<T> marker, T value) { on = false; this.marker = marker; this.value = value; Resume(); } public void Resume() { if (!on) { on = true; marker.Begin(in value); } } public void Pause() { if (on) { marker.End(); on = false; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Dispose() { Pause(); } } private readonly IntPtr ptr; private ProfilerMarkerData data; public ProfilerMarkerWithMetadata(string name, string metadata) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) data = default(ProfilerMarkerData); ptr = ProfilerUnsafeUtility.CreateMarker(name, (ushort)1, (MarkerFlags)0, 0); if (typeof(T) == typeof(int)) { data.Type = 2; } else if (typeof(T) == typeof(long)) { data.Type = 4; } else if (typeof(T) == typeof(uint)) { data.Type = 3; } else if (typeof(T) == typeof(ulong)) { data.Type = 5; } else if (typeof(T) == typeof(float)) { data.Type = 6; } else if (typeof(T) == typeof(double)) { data.Type = 7; } data.Size = (uint)UnsafeUtility.SizeOf<T>(); if (ptr != IntPtr.Zero) { ProfilerUnsafeUtility.SetMarkerMetadata(ptr, 0, metadata, data.Type, (byte)3); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void Begin(in T value) { fixed (ProfilerMarkerData* ptr = &data) { void* ptr2 = ptr; fixed (T* ptr3 = &value) { void* ptr4 = ptr3; data.Ptr = ptr4; ProfilerUnsafeUtility.BeginSampleWithMetadata(this.ptr, 1, ptr2); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void End() { ProfilerUnsafeUtility.EndSample(ptr); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public AutoScope Auto(T value) { return new AutoScope(in this, value); } } } namespace PathfindingLagFix.Utilities.IL { internal class ILInjector { [CompilerGenerated] private sealed class <GetRelativeInstructions>d__34 : IEnumerable<CodeInstruction>, IEnumerable, IEnumerator<CodeInstruction>, IEnumerator, IDisposable { private int <>1__state; private CodeInstruction <>2__current; private int <>l__initialThreadId; public ILInjector <>4__this; private int offset; public int <>3__offset; private int size; public int <>3__size; private int <i>5__2; CodeInstruction IEnumerator<CodeInstruction>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <GetRelativeInstructions>d__34(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; ILInjector iLInjector = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <i>5__2 = 0; break; case 1: <>1__state = -1; <i>5__2++; break; } if (<i>5__2 < size) { <>2__current = iLInjector.instructions[iLInjector.index + offset + <i>5__2]; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<CodeInstruction> IEnumerable<CodeInstruction>.GetEnumerator() { <GetRelativeInstructions>d__34 <GetRelativeInstructions>d__; if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; <GetRelativeInstructions>d__ = this; } else { <GetRelativeInstructions>d__ = new <GetRelativeInstructions>d__34(0) { <>4__this = <>4__this }; } <GetRelativeInstructions>d__.offset = <>3__offset; <GetRelativeInstructions>d__.size = <>3__size; return <GetRelativeInstructions>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<CodeInstruction>)this).GetEnumerator(); } } private const string INVALID = "Injector is invalid"; private List<CodeInstruction> instructions = instructions.ToList(); private ILGenerator generator; private int index; private int matchEnd; public int Index { get { return index; } set { index = value; } } 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) { if (label == default(Label)) { return this; } matchEnd = index; 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 ILInjector 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; return this; } [IteratorStateMachine(typeof(<GetRelativeInstructions>d__34))] public IEnumerable<CodeInstruction> GetRelativeInstructions(int offset, int size) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <GetRelativeInstructions>d__34(-2) { <>4__this = this, <>3__offset = offset, <>3__size = size }; } 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 ILInjector DefineLabel(out Label label) { if (generator == null) { throw new InvalidOperationException("No ILGenerator was provided"); } label = generator.DefineLabel(); return this; } public ILInjector AddLabel(out Label label) { DefineLabel(out label); return AddLabel(label); } public ILInjector AddLabel(Label label) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown Instruction = new CodeInstruction(Instruction); 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) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown if (!IsValid) { throw new InvalidOperationException("Injector is invalid"); } List<Label> labels = Instruction.labels; Instruction = new CodeInstruction(Instruction); Instruction.labels.Clear(); this.instructions.InsertRange(index, instructions); Instruction.labels.AddRange(labels); 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); List<Label> labels = instructions[start].labels; instructions.RemoveRange(start, size); index = start; matchEnd = start; instructions[start].labels.AddRange(labels); return this; } public ILInjector ReplaceLastMatch(params CodeInstruction[] replacementInstructions) { if (replacementInstructions.Length == 0) { throw new ArgumentException("Cannot replace a match with an empty array."); } GetLastMatchRange(out var start, out var size); List<Label> labels = instructions[start].labels; instructions.RemoveRange(start, size); instructions.InsertRange(start, replacementInstructions); index = start; matchEnd = start + replacementInstructions.Length; instructions[start].labels.AddRange(labels); 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); } } internal interface ILMatcher { bool Matches(CodeInstruction instruction); ILMatcher CaptureAs(out CodeInstruction variable) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown variable = new CodeInstruction(OpCodes.Nop, (object)null); return new InstructionCapturingMatcher(this, variable); } unsafe ILMatcher CaptureOperandAs<T>(out T operand) where T : unmanaged { operand = default(T); fixed (T* operand2 = &operand) { return new OperandCapturingMatcher<T>(this, operand2); } } ILMatcher Debug() { return new DebuggingMatcher(this); } static ILMatcher StackDelta(int pushes, int pops) { return new StackDeltaMatcher(pushes, pops); } static ILMatcher Push(int pushes) { return StackDelta(pushes, 0); } static ILMatcher Pop(int pops) { return StackDelta(0, pops); } static ILMatcher Not(ILMatcher matcher) { return new NotMatcher(matcher); } static ILMatcher Opcode(OpCode opcode) { return new OpcodeMatcher(opcode); } static ILMatcher Opcodes(params OpCode[] opcodes) { return new OpcodesMatcher(opcodes); } static ILMatcher OpcodeOperand(OpCode opcode, object operand) { return new OpcodeOperandMatcher(opcode, operand); } static ILMatcher Instruction(CodeInstruction instruction) { return new InstructionMatcher(instruction); } static ILMatcher Ldarg(int? arg = null) { return new LdargMatcher(arg); } static ILMatcher Ldloc(int? loc = null) { return new LdlocMatcher(loc); } static ILMatcher Stloc(int? loc = null) { return new StlocMatcher(loc); } static ILMatcher Ldc(int? value = null) { return new LdcI32Matcher(value); } static ILMatcher LdcF32(float? value = null) { return new LdcF32Matcher(value); } unsafe static ILMatcher LdlocCapture(out int localIndex) { localIndex = -1; fixed (int* localIndex2 = &localIndex) { return new LdlocCapturingMatcher(localIndex2); } } unsafe static ILMatcher LdlocFrom(in int localIndex) { fixed (int* localIndexPtr = &localIndex) { return new LdlocByRefMatcher(localIndexPtr); } } unsafe static ILMatcher StlocCapture(out int localIndex) { localIndex = -1; fixed (int* localIndex2 = &localIndex) { return new StlocCapturingMatcher(localIndex2); } } unsafe static ILMatcher StlocFrom(in int localIndex) { fixed (int* localIndexPtr = &localIndex) { return new StlocByRefMatcher(localIndexPtr); } } static ILMatcher Branch() { return new BranchMatcher(); } static ILMatcher Ldfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldfld() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Ldfld, field); } static ILMatcher Ldsfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldsfld() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Ldsfld, field); } static ILMatcher Stfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stfld() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Stfld, field); } static ILMatcher Stsfld(FieldInfo field, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (field == null) { Plugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stsfld() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return new OpcodeOperandMatcher(OpCodes.Stsfld, field); } static ILMatcher Callvirt(MethodBase method, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (method == null) { Plugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Callvirt() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return OpcodeOperand(OpCodes.Callvirt, method); } static ILMatcher Call(MethodBase method, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (method == null) { Plugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Call() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return OpcodeOperand(OpCodes.Call, method); } static ILMatcher Newobj(ConstructorInfo ctor, [CallerMemberName] string callerName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0) { if (ctor == null) { Plugin.Instance.Logger.LogWarning((object)$"Constructor passed to ILMatcher.Newobj() was null at {sourceFilePath}:{sourceLineNumber} ({callerName})"); } return OpcodeOperand(OpCodes.Newobj, ctor); } static ILMatcher Predicate(Func<CodeInstruction, bool> predicate) { return new PredicateMatcher(predicate); } static ILMatcher Predicate(Func<FieldInfo, bool> predicate) { return new PredicateMatcher((CodeInstruction insn) => insn.operand is FieldInfo arg && predicate(arg)); } } internal class StackDeltaMatcher : ILMatcher { private readonly int pushes; private readonly int pops; public StackDeltaMatcher(int pushes, int pops) { this.pushes = pushes; this.pops = pops; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (instruction.PushCount() == pushes) { return instruction.PopCount() == pops; } return false; } } internal 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); } } internal 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; } } internal 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); } } internal 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; } } internal 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; } } internal 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; } } internal 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; } } internal 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; } } internal class LdcI32Matcher : ILMatcher { private readonly int? value; public LdcI32Matcher(int? value) { this.value = value; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (!value.HasValue) { return instruction.GetLdcI32().HasValue; } return instruction.GetLdcI32() == value; } } internal class LdcF32Matcher : ILMatcher { private readonly float? value; public LdcF32Matcher(float? value) { this.value = value; base..ctor(); } public bool Matches(CodeInstruction instruction) { if (instruction.opcode == OpCodes.Ldc_R4) { if (value.HasValue) { return (float)instruction.operand == value.Value; } return true; } return false; } } internal class BranchMatcher : ILMatcher { public bool Matches(CodeInstruction instruction) { Label? label = default(Label?); return CodeInstructionExtensions.Branches(instruction, ref label); } } internal 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 class InstructionCapturingMatcher : ILMatcher { private readonly ILMatcher matcher; private readonly CodeInstruction variable; public InstructionCapturingMatcher(ILMatcher matcher, CodeInstruction variable) { this.matcher = matcher; this.variable = variable; base..ctor(); } public bool Matches(CodeInstruction instruction) { bool num = matcher.Matches(instruction); if (num) { variable.opcode = instruction.opcode; variable.operand = instruction.operand; variable.blocks = instruction.blocks.ToList(); variable.labels = instruction.labels.ToList(); } return num; } } internal class OperandCapturingMatcher<T> : ILMatcher where T : unmanaged { private readonly ILMatcher matcher; private unsafe readonly T* operand; public unsafe OperandCapturingMatcher(ILMatcher matcher, T* operand) { this.matcher = matcher; this.operand = operand; base..ctor(); } public unsafe bool Matches(CodeInstruction instruction) { bool num = matcher.Matches(instruction); if (num) { *operand = (T)instruction.operand; } return num; } } internal class LdlocCapturingMatcher : ILMatcher { private unsafe readonly int* localIndex; public unsafe LdlocCapturingMatcher(int* localIndex) { this.localIndex = localIndex; base..ctor(); } public unsafe bool Matches(CodeInstruction instruction) { int? ldlocIndex = instruction.GetLdlocIndex(); if (ldlocIndex.HasValue) { *localIndex = ldlocIndex.Value; return true; } return false; } } internal class LdlocByRefMatcher : ILMatcher { private unsafe readonly int* localIndexPtr; public unsafe LdlocByRefMatcher(int* localIndexPtr) { this.localIndexPtr = localIndexPtr; base..ctor(); } public unsafe bool Matches(CodeInstruction instruction) { return instruction.GetLdlocIndex() == *localIndexPtr; } } internal class StlocCapturingMatcher : ILMatcher { private unsafe readonly int* localIndex; public unsafe StlocCapturingMatcher(int* localIndex) { this.localIndex = localIndex; base..ctor(); } public unsafe bool Matches(CodeInstruction instruction) { int? stlocIndex = instruction.GetStlocIndex(); if (stlocIndex.HasValue) { *localIndex = stlocIndex.Value; return true; } return false; } } internal class StlocByRefMatcher : ILMatcher { private unsafe readonly int* localIndexPtr; public unsafe StlocByRefMatcher(int* localIndexPtr) { this.localIndexPtr = localIndexPtr; base..ctor(); } public unsafe bool Matches(CodeInstruction instruction) { return instruction.GetStlocIndex() == *localIndexPtr; } } internal class DebuggingMatcher : ILMatcher { private readonly ILMatcher matcher; public DebuggingMatcher(ILMatcher matcher) { this.matcher = matcher; base..ctor(); } public bool Matches(CodeInstruction instruction) { bool num = matcher.Matches(instruction); if (num) { Plugin.Instance.Logger.LogInfo((object)$"{matcher} matched {instruction}"); } return num; } } 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 || instruction.opcode == OpCodes.Newobj) { MethodBase obj = (MethodBase)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 || instruction.opcode == OpCodes.Newobj) { if (instruction.operand is MethodInfo methodInfo && methodInfo.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_S) { return instruction.operand as byte?; } if (opcode == OpCodes.Ldarg) { 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(EnemyAI))] internal class PatchAddProfilerMarkers { private static readonly Dictionary<MethodInfo, List<int>> callOffsets = new Dictionary<MethodInfo, List<int>>(); private static readonly Dictionary<string, ProfilerMarker> markers = new Dictionary<string, ProfilerMarker>(); private static string currentMarkerName = ""; internal static void ApplyPatches(Harmony harmony) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Expected O, but got Unknown Type[] types = typeof(EnemyAI).Assembly.GetTypes(); foreach (Type type in types) { if (type != typeof(EnemyAI) && !type.IsSubclassOf(typeof(EnemyAI))) { continue; } foreach (MethodInfo runtimeMethod in type.GetRuntimeMethods()) { if (runtimeMethod.DeclaringType != type || !MethodBaseExtensions.HasMethodBody((MethodBase)runtimeMethod)) { continue; } Collection<Instruction> instructions = PatchManager.GetMethodPatcher((MethodBase)runtimeMethod).CopyOriginal().Definition.Body.Instructions; bool flag = false; Enumerator<Instruction> enumerator2 = instructions.GetEnumerator(); try { while (enumerator2.MoveNext()) { Instruction current2 = enumerator2.Current; if (current2.OpCode != OpCodes.Call && current2.OpCode != OpCodes.Callvirt) { continue; } object operand = current2.Operand; MethodReference val = (MethodReference)((operand is MethodReference) ? operand : null); if (val != null && !(((MemberReference)((MemberReference)val).DeclaringType).Name != "EnemyAI")) { switch (((MemberReference)val).Name) { case "PathIsIntersectedByLineOfSight": case "ChooseFarthestNodeFromPosition": case "ChooseClosestNodeToPosition": flag = true; GetCallOffsets(runtimeMethod).Add(current2.Offset); break; } } } } finally { ((IDisposable)enumerator2).Dispose(); } if (flag) { new PatchProcessor(harmony, (MethodBase)runtimeMethod).AddTranspiler(new HarmonyMethod(Reflection.GetMethod(typeof(PatchAddProfilerMarkers), "CallerTranspiler", BindingFlags.Static | BindingFlags.NonPublic, new Type[3] { typeof(IEnumerable<CodeInstruction>), typeof(ILGenerator), typeof(MethodBase) })) { priority = 800 }).Patch(); } } } harmony.PatchAll(typeof(PatchAddProfilerMarkers)); } private static List<int> GetCallOffsets(MethodInfo method) { if (callOffsets.TryGetValue(method, out var value)) { return value; } value = new List<int>(); callOffsets[method] = value; return value; } private static IEnumerable<CodeInstruction> CallerTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodBase method) { //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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 if (!(method is MethodInfo method2)) { return instructions; } Plugin.Instance.Logger.LogInfo((object)("Begin caller transpiler for " + method.DeclaringType.FullName + "::" + method.Name)); if (Reflection.m_EnemyAI_PathIsIntersectedByLineOfSight == null) { Plugin.Instance.Logger.LogError((object)"Method info for EnemyAI::PathIsIntersec