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 System.Threading;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using MonoMod.RuntimeDetour;
using PathfindingLib.API;
using PathfindingLib.Patches;
using PathfindingLib.Patches.Native;
using PathfindingLib.Utilities;
using PathfindingLib.Utilities.Internal.IL;
using Unity.AI.Navigation;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Jobs.LowLevel.Unsafe;
using Unity.Mathematics;
using Unity.Profiling;
using Unity.Profiling.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Experimental.AI;
using UnityEngine.Pool;
using UnityEngine.Scripting;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PathfindingLib")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PathfindingLib")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("fedb984b-16ae-458c-b2cc-19590627c578")]
[assembly: AssemblyFileVersion("0.1.1")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.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 PathfindingLib
{
[BepInPlugin("Zaggy1024.PathfindingLib", "PathfindingLib", "0.1.1")]
public class PathfindingLibPlugin : BaseUnityPlugin
{
public const string PluginName = "PathfindingLib";
public const string PluginGUID = "Zaggy1024.PathfindingLib";
public const string PluginVersion = "0.1.1";
private readonly Harmony harmony = new Harmony("Zaggy1024.PathfindingLib");
internal static PathfindingLibPlugin Instance { get; private set; }
internal ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;
public void Awake()
{
Instance = this;
ApplyAllNativePatches();
harmony.PatchAll(typeof(PatchNavMeshSurface));
}
private static ProcessModule GetUnityPlayerModule()
{
ProcessModuleCollection modules = Process.GetCurrentProcess().Modules;
for (int i = 0; i < modules.Count; i++)
{
ProcessModule processModule = modules[i];
if (processModule.ModuleName.Contains("UnityPlayer"))
{
return processModule;
}
}
return null;
}
private static void ApplyAllNativePatches()
{
ProcessModule unityPlayerModule = GetUnityPlayerModule();
NavMeshQueryUtils.SetUpNativeMethodPointers(unityPlayerModule.BaseAddress);
PatchApplyCarveResults.Apply(unityPlayerModule.BaseAddress);
}
}
}
namespace PathfindingLib.Utilities
{
public static class AgentExtensions
{
public static Vector3 GetPathOrigin(this NavMeshAgent agent)
{
//IL_001d: 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)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
if (agent.isOnOffMeshLink)
{
OffMeshLinkData currentOffMeshLinkData = agent.currentOffMeshLinkData;
return ((OffMeshLinkData)(ref currentOffMeshLinkData)).endPos;
}
return ((Component)agent).transform.position;
}
}
[Flags]
public enum StraightPathFlags : byte
{
Start = 1,
End = 2,
OffMeshConnection = 4
}
public static class NavMeshQueryUtils
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private unsafe delegate PathQueryStatus FindStraightPathDelegate(NavMeshQuery self, in Vector3 startPos, in Vector3 endPos, PolygonId* path, int pathSize, Vector3* straightPath, StraightPathFlags* straightPathFlags, PolygonId* straightPathRefs, ref int straightPathCount, int maxStraightPath);
public const int RecommendedCornerCount = 128;
private static FindStraightPathDelegate findStraightPathMethod;
public static int RequiredCornerCount(int pathPolygonCount)
{
return pathPolygonCount + 2;
}
public unsafe static PathQueryStatus FindStraightPath(this NavMeshQuery query, in Vector3 startPos, in Vector3 endPos, in NativeSlice<PolygonId> path, int pathSize, in NativeArray<Vector3> straightPath, in NativeArray<StraightPathFlags> straightPathFlags, in NativeArray<PolygonId> straightPathRefs, out int straightPathCount)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: 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)
//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_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_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_007d: 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_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: 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_00a5: Invalid comparison between Unknown and I4
//IL_00ae: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
if (path.Stride != UnsafeUtility.SizeOf<PolygonId>())
{
throw new ArgumentException("Path slice must have a stride equal to the size of PolygonId.");
}
if (straightPathFlags.Length < straightPath.Length)
{
throw new ArgumentException("Straight path flags buffer is too small.");
}
if (straightPathRefs.Length < straightPath.Length)
{
throw new ArgumentException("Straight path refs buffer is too small.");
}
straightPathCount = 0;
Vector3 endPos2 = default(Vector3);
PathQueryStatus closestPointOnPoly = NavMeshQuery.GetClosestPointOnPoly(query.m_NavMeshQuery, path[pathSize - 1], endPos, ref endPos2);
if ((int)closestPointOnPoly < 0)
{
return closestPointOnPoly;
}
return findStraightPathMethod(query, in startPos, in endPos2, path.GetPtr<PolygonId>(), pathSize, straightPath.GetPtr<Vector3>(), GetPtr(in straightPathFlags), straightPathRefs.GetPtr<PolygonId>(), ref straightPathCount, straightPath.Length);
}
public static PathQueryStatus FindStraightPath(this NavMeshQuery query, in Vector3 startPos, in Vector3 endPos, in NativeSlice<PolygonId> path, int pathSize, in NativeArray<Vector3> straightPath, out int straightPathCount)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: 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)
NativeArray<StraightPathFlags> straightPathFlags = default(NativeArray<StraightPathFlags>);
straightPathFlags..ctor(straightPath.Length, (Allocator)2, (NativeArrayOptions)1);
try
{
NativeArray<PolygonId> straightPathRefs = new NativeArray<PolygonId>(straightPath.Length, (Allocator)2, (NativeArrayOptions)1);
try
{
return query.FindStraightPath(in startPos, in endPos, in path, pathSize, in straightPath, in straightPathFlags, in straightPathRefs, out straightPathCount);
}
finally
{
((IDisposable)straightPathRefs).Dispose();
}
}
finally
{
((IDisposable)straightPathFlags).Dispose();
}
}
[Obsolete("Use NativeArray<Vector3> for the straightPath parameter")]
public static PathQueryStatus FindStraightPath(this NavMeshQuery query, float3 startPos, float3 endPos, NativeSlice<PolygonId> path, int pathSize, NativeArray<NavMeshLocation> straightPath, out int straightPathCount)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: 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_0070: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
NativeArray<Vector3> straightPath2 = default(NativeArray<Vector3>);
straightPath2..ctor(straightPath.Length, (Allocator)2, (NativeArrayOptions)1);
try
{
NativeArray<StraightPathFlags> straightPathFlags = new NativeArray<StraightPathFlags>(straightPath.Length, (Allocator)2, (NativeArrayOptions)1);
try
{
NativeArray<PolygonId> straightPathRefs = new NativeArray<PolygonId>(straightPath.Length, (Allocator)2, (NativeArrayOptions)1);
try
{
Vector3 startPos2 = float3.op_Implicit(startPos);
Vector3 endPos2 = float3.op_Implicit(endPos);
PathQueryStatus result = query.FindStraightPath(in startPos2, in endPos2, in path, pathSize, in straightPath2, in straightPathFlags, in straightPathRefs, out straightPathCount);
for (int i = 0; i < straightPathCount; i++)
{
straightPath[i] = new NavMeshLocation(straightPath2[i], straightPathRefs[i]);
}
return result;
}
finally
{
((IDisposable)straightPathRefs).Dispose();
}
}
finally
{
((IDisposable)straightPathFlags).Dispose();
}
}
finally
{
((IDisposable)straightPath2).Dispose();
}
}
internal static void SetUpNativeMethodPointers(IntPtr baseAddress)
{
ulong num = 10850928uL;
if (NativeHooksCommon.IsDebugBuild)
{
num = 19595328uL;
}
findStraightPathMethod = Marshal.GetDelegateForFunctionPointer<FindStraightPathDelegate>((IntPtr)((long)baseAddress + (long)num));
}
private unsafe static T* GetPtr<T>(this in NativeArray<T> array) where T : unmanaged
{
return (T*)array.m_Buffer;
}
private unsafe static T* GetPtr<T>(this in NativeSlice<T> slice) where T : unmanaged
{
return (T*)slice.m_Buffer;
}
}
public struct NavMeshReadLocker : IDisposable
{
private bool locked;
public NavMeshReadLocker()
{
locked = false;
NavMeshLock.BeginRead();
locked = true;
}
public void Yield()
{
NavMeshLock.YieldRead();
}
public void Dispose()
{
if (locked)
{
locked = false;
NavMeshLock.EndRead();
}
}
}
public static class PathQueryStatusExtensions
{
public static PathQueryStatus GetResult(this PathQueryStatus status)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return (PathQueryStatus)(status & -16777216);
}
public static PathQueryStatus GetDetail(this PathQueryStatus status)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
return (PathQueryStatus)(status & 0xFFFFFF);
}
}
[IgnoredByDeepProfiler]
[UsedByNativeCode]
public struct TogglableProfilerAuto : IDisposable
{
[NativeDisableUnsafePtrRestriction]
internal readonly IntPtr ptr;
internal bool on;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TogglableProfilerAuto(in ProfilerMarker marker)
{
ptr = marker.m_Ptr;
on = true;
ProfilerUnsafeUtility.BeginSample(ptr);
}
public void Pause()
{
if (on)
{
ProfilerUnsafeUtility.EndSample(ptr);
on = false;
}
}
public void Resume()
{
if (!on)
{
on = true;
ProfilerUnsafeUtility.BeginSample(ptr);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
if (on)
{
ProfilerUnsafeUtility.EndSample(ptr);
on = false;
}
}
}
}
namespace PathfindingLib.Utilities.Internal.IL
{
internal class ILInjector
{
[CompilerGenerated]
private sealed class <GetRelativeInstructions>d__31 : 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__31(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__31 <GetRelativeInstructions>d__;
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
<GetRelativeInstructions>d__ = this;
}
else
{
<GetRelativeInstructions>d__ = new <GetRelativeInstructions>d__31(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 bool IsValid
{
get
{
if (instructions != null)
{
return IsIndexValid(index);
}
return false;
}
}
public CodeInstruction Instruction
{
get
{
if (!IsIndexInRange(index))
{
return null;
}
return instructions[index];
}
set
{
if (!IsIndexInRange(index))
{
throw new InvalidOperationException($"Current index {index} is out of range of instruction count {instructions.Count}");
}
instructions[index] = value;
}
}
public CodeInstruction LastMatchedInstruction
{
get
{
int num = matchEnd - 1;
if (!IsIndexInRange(num))
{
return null;
}
return instructions[num];
}
set
{
int num = matchEnd - 1;
if (!IsIndexInRange(num))
{
throw new InvalidOperationException($"Last matched index {index} is out of range of instruction count {instructions.Count}");
}
instructions[num] = value;
}
}
public ICollection<CodeInstruction> Instructions => instructions.AsReadOnly();
public ILInjector(IEnumerable<CodeInstruction> instructions, ILGenerator generator = null)
{
this.generator = generator;
matchEnd = -1;
base..ctor();
}
public ILInjector GoToStart()
{
matchEnd = index;
index = 0;
return this;
}
public ILInjector GoToEnd()
{
matchEnd = index;
index = instructions.Count;
return this;
}
public ILInjector Forward(int offset)
{
if (!IsValid)
{
return this;
}
matchEnd = index;
index = Math.Clamp(index + offset, -1, instructions.Count);
return this;
}
public ILInjector Back(int offset)
{
return Forward(-offset);
}
private void MarkInvalid()
{
index = -1;
matchEnd = -1;
}
private void Search(bool forward, ILMatcher[] predicates)
{
if (!IsValid)
{
return;
}
int num = 1;
if (!forward)
{
num = -1;
index--;
}
while (forward ? (index < instructions.Count) : (index >= 0))
{
if (forward && index + predicates.Length > instructions.Count)
{
index = instructions.Count;
break;
}
int i;
for (i = 0; i < predicates.Length && predicates[i].Matches(instructions[index + i]); i++)
{
}
if (i == predicates.Length)
{
matchEnd = index + i;
return;
}
index += num;
}
MarkInvalid();
}
public ILInjector Find(params ILMatcher[] predicates)
{
Search(forward: true, predicates);
return this;
}
public ILInjector ReverseFind(params ILMatcher[] predicates)
{
Search(forward: false, predicates);
return this;
}
public ILInjector GoToPush(int popIndex)
{
if (!IsValid)
{
return this;
}
matchEnd = index;
index--;
int num = 0;
while (index >= 0)
{
CodeInstruction instruction = instructions[index];
num += instruction.PushCount();
num -= instruction.PopCount();
if (num > popIndex)
{
return this;
}
index--;
}
return this;
}
public ILInjector SkipBranch()
{
if (Instruction == null)
{
return this;
}
if (!(Instruction.operand is Label label))
{
throw new InvalidOperationException($"Current instruction is not a branch: {Instruction}");
}
return FindLabel(label);
}
public ILInjector FindLabel(Label label)
{
matchEnd = index + 1;
for (index = 0; index < instructions.Count; index++)
{
if (instructions[index].labels.Contains(label))
{
return this;
}
}
MarkInvalid();
return this;
}
public ILInjector GoToMatchEnd()
{
index = matchEnd;
return this;
}
public ILInjector GoToLastMatchedInstruction()
{
if (!IsIndexValid(matchEnd))
{
return this;
}
index = matchEnd - 1;
return this;
}
private bool IsIndexValid(int index)
{
return index != -1;
}
private bool IsIndexInRange(int index)
{
if (index >= 0)
{
return index < instructions.Count;
}
return false;
}
public CodeInstruction GetRelativeInstruction(int offset)
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
int num = index + offset;
if (!IsIndexInRange(num))
{
throw new IndexOutOfRangeException($"Offset {offset} would read out of bounds at index {num}");
}
return instructions[num];
}
public void SetRelativeInstruction(int offset, CodeInstruction instruction)
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
int num = index + offset;
if (!IsIndexInRange(num))
{
throw new IndexOutOfRangeException($"Offset {offset} would write out of bounds at index {num}");
}
instructions[num] = instruction;
}
[IteratorStateMachine(typeof(<GetRelativeInstructions>d__31))]
public IEnumerable<CodeInstruction> GetRelativeInstructions(int offset, int size)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <GetRelativeInstructions>d__31(-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 Label AddLabel()
{
if (generator == null)
{
throw new InvalidOperationException("No ILGenerator was provided");
}
Label label = generator.DefineLabel();
Instruction.labels.Add(label);
return label;
}
public ILInjector AddLabel(Label label)
{
Instruction.labels.Add(label);
return this;
}
public ILInjector InsertInPlace(params CodeInstruction[] instructions)
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
this.instructions.InsertRange(index, instructions);
if (matchEnd >= index)
{
matchEnd += instructions.Length;
}
return this;
}
public ILInjector Insert(params CodeInstruction[] instructions)
{
InsertInPlace(instructions);
index += instructions.Length;
return this;
}
public ILInjector InsertInPlaceAfterBranch(params CodeInstruction[] instructions)
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
List<Label> labels = Instruction.labels;
this.instructions.InsertRange(index, instructions);
Instruction.labels.AddRange(labels);
labels.Clear();
if (matchEnd >= index)
{
matchEnd += instructions.Length;
}
return this;
}
public ILInjector InsertAfterBranch(params CodeInstruction[] instructions)
{
InsertInPlaceAfterBranch(instructions);
index += instructions.Length;
return this;
}
public ILInjector RemoveAllPreviousInstructions()
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
instructions.RemoveRange(0, index);
matchEnd -= index;
if (matchEnd < 0)
{
matchEnd = 0;
}
index = 0;
return this;
}
public ILInjector Remove(int count = 1)
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid");
}
instructions.RemoveRange(index, count);
if (matchEnd > index)
{
matchEnd = Math.Max(index, matchEnd - count);
}
return this;
}
public ILInjector RemoveLastMatch()
{
GetLastMatchRange(out var start, out var size);
instructions.RemoveRange(start, size);
index = start;
matchEnd = start;
return this;
}
public ILInjector ReplaceLastMatch(params CodeInstruction[] instructions)
{
RemoveLastMatch();
Insert(instructions);
return this;
}
public List<CodeInstruction> ReleaseInstructions()
{
List<CodeInstruction> result = instructions;
instructions = null;
return result;
}
public ILInjector PrintContext(int context, string header = "")
{
if (!IsValid)
{
throw new InvalidOperationException("Injector is invalid (" + header + ")");
}
StringBuilder stringBuilder = new StringBuilder(header);
if (header.Length > 0)
{
stringBuilder.Append(':');
}
stringBuilder.AppendLine();
GetLastMatchRangeAbsolute(out var start, out var end);
int num = Math.Min(end + 1 + context, instructions.Count);
for (int i = Math.Max(start - context, 0); i < num; i++)
{
if (end == -1 && i == index)
{
stringBuilder.Append("╶> ");
}
else
{
if (i >= start && i < end)
{
stringBuilder.Append("│");
}
else
{
stringBuilder.Append(" ");
}
if (i == index)
{
stringBuilder.Append("╶> ");
}
else
{
stringBuilder.Append(" ");
}
}
stringBuilder.AppendLine($"{i}: {instructions[i]}");
}
PathfindingLibPlugin.Instance.Logger.LogInfo((object)stringBuilder);
return this;
}
public ILInjector PrintContext(string header = "")
{
return PrintContext(4, header);
}
}
internal interface ILMatcher
{
bool Matches(CodeInstruction instruction);
static NotMatcher Not(ILMatcher matcher)
{
return new NotMatcher(matcher);
}
static OpcodeMatcher Opcode(OpCode opcode)
{
return new OpcodeMatcher(opcode);
}
static OpcodesMatcher Opcodes(params OpCode[] opcodes)
{
return new OpcodesMatcher(opcodes);
}
static OpcodeOperandMatcher OpcodeOperand(OpCode opcode, object operand)
{
return new OpcodeOperandMatcher(opcode, operand);
}
static InstructionMatcher Instruction(CodeInstruction instruction)
{
return new InstructionMatcher(instruction);
}
static LdargMatcher Ldarg(int? arg = null)
{
return new LdargMatcher(arg);
}
static LdlocMatcher Ldloc(int? loc = null)
{
return new LdlocMatcher(loc);
}
static StlocMatcher Stloc(int? loc = null)
{
return new StlocMatcher(loc);
}
static LdcI32Matcher Ldc(int? value = null)
{
return new LdcI32Matcher(value);
}
static BranchMatcher Branch()
{
return new BranchMatcher();
}
static OpcodeOperandMatcher Ldfld(FieldInfo field)
{
if (field == null)
{
PathfindingLibPlugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Ldfld, field);
}
static OpcodeOperandMatcher Ldsfld(FieldInfo field)
{
if (field == null)
{
PathfindingLibPlugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Ldsfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Ldsfld, field);
}
static OpcodeOperandMatcher Stfld(FieldInfo field)
{
if (field == null)
{
PathfindingLibPlugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Stfld, field);
}
static OpcodeOperandMatcher Stsfld(FieldInfo field)
{
if (field == null)
{
PathfindingLibPlugin.Instance.Logger.LogWarning((object)$"Field passed to ILMatcher.Stsfld() was null\n{new StackTrace()}");
}
return new OpcodeOperandMatcher(OpCodes.Stsfld, field);
}
static OpcodeOperandMatcher Callvirt(MethodBase method)
{
if (method == null)
{
PathfindingLibPlugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Callvirt() was null\n{new StackTrace()}");
}
return OpcodeOperand(OpCodes.Callvirt, method);
}
static OpcodeOperandMatcher Call(MethodBase method)
{
if (method == null)
{
PathfindingLibPlugin.Instance.Logger.LogWarning((object)$"Method passed to ILMatcher.Call() was null\n{new StackTrace()}");
}
return OpcodeOperand(OpCodes.Call, method);
}
static PredicateMatcher Predicate(Func<CodeInstruction, bool> predicate)
{
return new PredicateMatcher(predicate);
}
static PredicateMatcher Predicate(Func<FieldInfo, bool> predicate)
{
return new PredicateMatcher((CodeInstruction insn) => insn.operand is FieldInfo arg && predicate(arg));
}
}
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 || !instruction.GetLdcI32().HasValue)
{
return instruction.GetLdcI32() == value;
}
return true;
}
}
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 static class InstructionUtilities
{
public static CodeInstruction MakeLdarg(int index)
{
//IL_0076: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Expected O, but got Unknown
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Expected O, but got Unknown
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Expected O, but got Unknown
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Expected O, but got Unknown
if (index < 256)
{
return (CodeInstruction)(index switch
{
0 => (object)new CodeInstruction(OpCodes.Ldarg_0, (object)null),
1 => (object)new CodeInstruction(OpCodes.Ldarg_1, (object)null),
2 => (object)new CodeInstruction(OpCodes.Ldarg_2, (object)null),
3 => (object)new CodeInstruction(OpCodes.Ldarg_3, (object)null),
_ => (object)new CodeInstruction(OpCodes.Ldarg_S, (object)index),
});
}
return new CodeInstruction(OpCodes.Ldarg, (object)index);
}
public static int PopCount(this CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt)
{
MethodInfo obj = (MethodInfo)instruction.operand;
int num = obj.GetParameters().Length;
if (!obj.IsStatic)
{
num++;
}
return num;
}
if (instruction.opcode == OpCodes.Ret)
{
return 1;
}
return instruction.opcode.StackBehaviourPop switch
{
StackBehaviour.Pop0 => 0,
StackBehaviour.Pop1 => 1,
StackBehaviour.Pop1_pop1 => 2,
StackBehaviour.Popi => 1,
StackBehaviour.Popi_pop1 => 2,
StackBehaviour.Popi_popi => 2,
StackBehaviour.Popi_popi8 => 2,
StackBehaviour.Popi_popi_popi => 3,
StackBehaviour.Popi_popr4 => 2,
StackBehaviour.Popi_popr8 => 2,
StackBehaviour.Popref => 1,
StackBehaviour.Popref_pop1 => 2,
StackBehaviour.Popref_popi => 2,
StackBehaviour.Popref_popi_popi => 3,
StackBehaviour.Popref_popi_popi8 => 3,
StackBehaviour.Popref_popi_popr4 => 3,
StackBehaviour.Popref_popi_popr8 => 3,
StackBehaviour.Popref_popi_popref => 3,
StackBehaviour.Varpop => throw new NotImplementedException($"Variable pop on non-call instruction '{instruction}'"),
StackBehaviour.Popref_popi_pop1 => 3,
_ => throw new NotSupportedException($"StackBehaviourPop of {instruction.opcode.StackBehaviourPop} was not a pop for instruction '{instruction}'"),
};
}
public static int PushCount(this CodeInstruction instruction)
{
if (instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt)
{
if (((MethodInfo)instruction.operand).ReturnType == typeof(void))
{
return 0;
}
return 1;
}
return instruction.opcode.StackBehaviourPush switch
{
StackBehaviour.Push0 => 0,
StackBehaviour.Push1 => 1,
StackBehaviour.Push1_push1 => 2,
StackBehaviour.Pushi => 1,
StackBehaviour.Pushi8 => 1,
StackBehaviour.Pushr4 => 1,
StackBehaviour.Pushr8 => 1,
StackBehaviour.Pushref => 1,
StackBehaviour.Varpush => throw new NotImplementedException($"Variable push on non-call instruction '{instruction}'"),
_ => throw new NotSupportedException($"StackBehaviourPush of {instruction.opcode.StackBehaviourPush} was not a push for instruction '{instruction}'"),
};
}
public static int? GetLdargIndex(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldarg_0)
{
return 0;
}
if (opcode == OpCodes.Ldarg_1)
{
return 1;
}
if (opcode == OpCodes.Ldarg_2)
{
return 2;
}
if (opcode == OpCodes.Ldarg_3)
{
return 3;
}
if (opcode == OpCodes.Ldarg || opcode == OpCodes.Ldarg_S)
{
return instruction.operand as int?;
}
return null;
}
public static int? GetLdlocIndex(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldloc_0)
{
return 0;
}
if (opcode == OpCodes.Ldloc_1)
{
return 1;
}
if (opcode == OpCodes.Ldloc_2)
{
return 2;
}
if (opcode == OpCodes.Ldloc_3)
{
return 3;
}
if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
{
return (instruction.operand as LocalBuilder)?.LocalIndex;
}
return null;
}
public static int? GetStlocIndex(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Stloc_0)
{
return 0;
}
if (opcode == OpCodes.Stloc_1)
{
return 1;
}
if (opcode == OpCodes.Stloc_2)
{
return 2;
}
if (opcode == OpCodes.Stloc_3)
{
return 3;
}
if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
{
return (instruction.operand as LocalBuilder)?.LocalIndex;
}
return null;
}
public static CodeInstruction LdlocToStloc(this CodeInstruction instruction)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldloc_0)
{
return new CodeInstruction(OpCodes.Stloc_0, (object)null);
}
if (opcode == OpCodes.Ldloc_1)
{
return new CodeInstruction(OpCodes.Stloc_1, (object)null);
}
if (opcode == OpCodes.Ldloc_2)
{
return new CodeInstruction(OpCodes.Stloc_2, (object)null);
}
if (opcode == OpCodes.Ldloc_3)
{
return new CodeInstruction(OpCodes.Stloc_3, (object)null);
}
if (opcode == OpCodes.Ldloc || opcode == OpCodes.Ldloc_S)
{
return new CodeInstruction(OpCodes.Stloc, instruction.operand);
}
return null;
}
public static CodeInstruction StlocToLdloc(this CodeInstruction instruction)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0039: Expected O, but got Unknown
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Expected O, but got Unknown
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_0096: Expected O, but got Unknown
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Stloc_0)
{
return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
}
if (opcode == OpCodes.Stloc_1)
{
return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
}
if (opcode == OpCodes.Stloc_2)
{
return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
}
if (opcode == OpCodes.Stloc_3)
{
return new CodeInstruction(OpCodes.Ldloc_3, (object)null);
}
if (opcode == OpCodes.Stloc || opcode == OpCodes.Stloc_S)
{
return new CodeInstruction(OpCodes.Ldloc, instruction.operand);
}
return null;
}
public static int? GetLdcI32(this CodeInstruction instruction)
{
OpCode opcode = instruction.opcode;
if (opcode == OpCodes.Ldc_I4_M1)
{
return -1;
}
if (opcode == OpCodes.Ldc_I4_0)
{
return 0;
}
if (opcode == OpCodes.Ldc_I4_1)
{
return 1;
}
if (opcode == OpCodes.Ldc_I4_2)
{
return 2;
}
if (opcode == OpCodes.Ldc_I4_3)
{
return 3;
}
if (opcode == OpCodes.Ldc_I4_4)
{
return 4;
}
if (opcode == OpCodes.Ldc_I4_5)
{
return 5;
}
if (opcode == OpCodes.Ldc_I4_6)
{
return 6;
}
if (opcode == OpCodes.Ldc_I4_7)
{
return 7;
}
if (opcode == OpCodes.Ldc_I4_8)
{
return 8;
}
if (opcode == OpCodes.Ldc_I4_S)
{
return instruction.operand as sbyte?;
}
if (opcode == OpCodes.Ldc_I4)
{
return instruction.operand as int?;
}
return null;
}
}
}
namespace PathfindingLib.Patches
{
[HarmonyPatch(typeof(NavMeshSurface))]
internal static class PatchNavMeshSurface
{
private static readonly MethodInfo m_BeginNavMeshWrite = typeof(NavMeshLock).GetMethod("BeginWrite", BindingFlags.Static | BindingFlags.Public);
private static readonly MethodInfo m_EndNavMeshWrite = typeof(NavMeshLock).GetMethod("EndWrite", BindingFlags.Static | BindingFlags.Public);
[HarmonyTranspiler]
[HarmonyPatch(typeof(NavMeshSurface), "BuildNavMesh")]
[HarmonyPatch(typeof(NavMeshSurface), "AddData")]
[HarmonyPatch(typeof(NavMeshSurface), "RemoveData")]
private static IEnumerable<CodeInstruction> LockWriteForDurationOfMethodTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Expected O, but got Unknown
return new ILInjector(instructions).Insert(new CodeInstruction(OpCodes.Call, (object)m_BeginNavMeshWrite)).GoToEnd().ReverseFind(ILMatcher.Opcode(OpCodes.Ret))
.Insert(new CodeInstruction(OpCodes.Call, (object)m_EndNavMeshWrite))
.ReleaseInstructions();
}
[HarmonyTranspiler]
[HarmonyPatch("UpdateDataIfTransformChanged")]
private static IEnumerable<CodeInstruction> UpdateDataIfTransformChangedTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Expected O, but got Unknown
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Expected O, but got Unknown
ILInjector iLInjector = new ILInjector(instructions).Find(ILMatcher.Ldarg(0), ILMatcher.Call(typeof(NavMeshSurface).GetMethod("RemoveData")));
if (!iLInjector.IsValid)
{
PathfindingLibPlugin.Instance.Logger.LogError((object)"Failed to find the call to RemoveData in NavMeshSurface.UpdateDataIfTransformChanged.");
return instructions;
}
iLInjector.Insert(new CodeInstruction(OpCodes.Call, (object)m_BeginNavMeshWrite)).Find(ILMatcher.Ldarg(0), ILMatcher.Call(typeof(NavMeshSurface).GetMethod("AddData"))).GoToMatchEnd();
if (!iLInjector.IsValid)
{
PathfindingLibPlugin.Instance.Logger.LogError((object)"Failed to find the call to AddData in NavMeshSurface.UpdateDataIfTransformChanged.");
return instructions;
}
return iLInjector.Insert(new CodeInstruction(OpCodes.Call, (object)m_EndNavMeshWrite)).ReleaseInstructions();
}
[HarmonyTranspiler]
[HarmonyPatch("UpdateNavMesh")]
private static IEnumerable<CodeInstruction> UpdateNavMeshTranspiler(IEnumerable<CodeInstruction> instructions)
{
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Expected O, but got Unknown
//IL_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Expected O, but got Unknown
//IL_0082: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Expected O, but got Unknown
return new ILInjector(instructions).Insert(new CodeInstruction(OpCodes.Call, (object)m_BeginNavMeshWrite)).Find(ILMatcher.Opcode(OpCodes.Ret)).Insert(new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Call, (object)typeof(PatchNavMeshSurface).GetMethod("EndNavMeshWriteAtEndOfAsyncOperation", BindingFlags.Static | BindingFlags.NonPublic, null, new Type[1] { typeof(AsyncOperation) }, null)))
.ReleaseInstructions();
}
private static void EndNavMeshWriteAtEndOfAsyncOperation(AsyncOperation operation)
{
operation.completed += delegate
{
NavMeshLock.EndWrite();
};
}
}
}
namespace PathfindingLib.Patches.Native
{
internal class NativeHooksCommon
{
internal static readonly bool IsDebugBuild = Debug.isDebugBuild;
}
internal static class PatchApplyCarveResults
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ApplyCarveResultsDelegate(IntPtr thisNavMeshCarving);
private static NativeDetour detour;
private static ApplyCarveResultsDelegate original;
internal static void Apply(IntPtr baseAddress)
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Expected O, but got Unknown
ulong num = 10899072uL;
if (NativeHooksCommon.IsDebugBuild)
{
num = 19667088uL;
}
IntPtr intPtr = (IntPtr)((long)baseAddress + (long)num);
IntPtr functionPointerForDelegate = Marshal.GetFunctionPointerForDelegate<ApplyCarveResultsDelegate>(ApplyCarveResultsDetour);
detour = new NativeDetour(intPtr, functionPointerForDelegate);
original = detour.GenerateTrampoline<ApplyCarveResultsDelegate>();
}
private unsafe static void ApplyCarveResultsDetour(IntPtr thisNavMeshCarving)
{
ulong num = 0uL;
ulong num2 = 0uL;
if (NativeHooksCommon.IsDebugBuild)
{
num = *(ulong*)((long)thisNavMeshCarving + 56);
num2 = *(ulong*)((long)thisNavMeshCarving + 64);
}
else
{
num = *(ulong*)((long)thisNavMeshCarving + 40);
num2 = *(ulong*)((long)thisNavMeshCarving + 48);
}
bool num3 = num2 > num;
if (num3)
{
NavMeshLock.BeginWrite();
}
original(thisNavMeshCarving);
if (num3)
{
NavMeshLock.EndWrite();
}
}
}
}
namespace PathfindingLib.Jobs
{
public struct FindPathJob : IJob, IDisposable
{
private const float MaximumOriginDistance = 5f;
private const float MaximumEndpointDistance = 1.5f;
private const float MaximumEndpointDistanceSquared = 2.25f;
[ReadOnly]
[NativeDisableContainerSafetyRestriction]
private NativeArray<NavMeshQuery> ThreadQueriesRef;
[ReadOnly]
private int AgentTypeID;
[ReadOnly]
private int AreaMask;
[ReadOnly]
private Vector3 Origin;
[ReadOnly]
private Vector3 Destination;
[ReadOnly]
[NativeSetThreadIndex]
private int ThreadIndex;
[WriteOnly]
private NativeArray<PathQueryStatus> Status;
[WriteOnly]
private NativeArray<float> PathLength;
public void Initialize(Vector3 origin, Vector3 destination, NavMeshAgent agent)
{
//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_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
ThreadQueriesRef = PathfindingJobSharedResources.GetPerThreadQueriesArray();
AgentTypeID = agent.agentTypeID;
AreaMask = agent.areaMask;
Origin = origin;
Destination = destination;
ThreadIndex = -1;
CreateArrays();
Status[0] = (PathQueryStatus)536870912;
PathLength[0] = float.MaxValue;
}
private void CreateArrays()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//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)
if (Status.Length != 1)
{
Status = new NativeArray<PathQueryStatus>(1, (Allocator)4, (NativeArrayOptions)1);
PathLength = new NativeArray<float>(1, (Allocator)4, (NativeArrayOptions)1);
}
}
private void DisposeArrays()
{
Status.Dispose();
PathLength.Dispose();
}
public void Execute()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: 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_0043: 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_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: 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_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00df: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00eb: Invalid comparison between Unknown and I4
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_011c: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Invalid comparison between Unknown and I4
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Unknown result type (might be due to invalid IL or missing references)
//IL_0131: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: 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_013f: Invalid comparison between Unknown and I4
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0160: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: 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_017b: 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_0182: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_0191: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01a5: 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_01b7: Unknown result type (might be due to invalid IL or missing references)
//IL_01c1: Invalid comparison between Unknown and I4
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01e9: 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_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01ca: Unknown result type (might be due to invalid IL or missing references)
//IL_0228: Unknown result type (might be due to invalid IL or missing references)
//IL_022d: 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)
NavMeshQuery val = ThreadQueriesRef[ThreadIndex];
using PathfindingLib.Utilities.NavMeshReadLocker navMeshReadLocker = new PathfindingLib.Utilities.NavMeshReadLocker();
Vector3 val2 = new Vector3(5f, 5f, 5f);
NavMeshLocation val3 = ((NavMeshQuery)(ref val)).MapLocation(Origin, val2, AgentTypeID, AreaMask);
if (!((NavMeshQuery)(ref val)).IsValid(((NavMeshLocation)(ref val3)).polygon))
{
Status[0] = (PathQueryStatus)int.MinValue;
return;
}
Vector3 val4 = new Vector3(1.5f, 1.5f, 1.5f);
NavMeshLocation val5 = ((NavMeshQuery)(ref val)).MapLocation(Destination, val4, AgentTypeID, AreaMask);
if (!((NavMeshQuery)(ref val)).IsValid(val5))
{
Status[0] = (PathQueryStatus)int.MinValue;
return;
}
PathQueryStatus status = ((NavMeshQuery)(ref val)).BeginFindPath(val3, val5, AreaMask, default(NativeArray<float>));
if ((int)status.GetResult() == int.MinValue)
{
Status[0] = (PathQueryStatus)int.MinValue;
return;
}
int num = default(int);
while ((int)status.GetResult() == 536870912)
{
status = ((NavMeshQuery)(ref val)).UpdateFindPath(NavMeshLock.RecommendedUpdateFindPathIterationCount, ref num);
navMeshReadLocker.Yield();
}
int num2 = default(int);
status = ((NavMeshQuery)(ref val)).EndFindPath(ref num2);
if ((int)status.GetResult() != 1073741824)
{
Status[0] = (PathQueryStatus)int.MinValue;
return;
}
NativeArray<PolygonId> val6 = new NativeArray<PolygonId>(num2, (Allocator)2, (NativeArrayOptions)1);
num2 = ((NavMeshQuery)(ref val)).GetPathResult(NativeSlice<PolygonId>.op_Implicit(val6));
NativeArray<Vector3> straightPath = new NativeArray<Vector3>(NavMeshQueryUtils.RequiredCornerCount(num2), (Allocator)2, (NativeArrayOptions)1);
try
{
NavMeshQuery query = val;
ref Vector3 origin = ref Origin;
ref Vector3 destination = ref Destination;
NativeSlice<PolygonId> path = NativeSlice<PolygonId>.op_Implicit(val6);
int straightPathCount;
PathQueryStatus val7 = query.FindStraightPath(in origin, in destination, in path, num2, in straightPath, out straightPathCount);
val6.Dispose();
navMeshReadLocker.Dispose();
if ((int)val7.GetResult() != 1073741824)
{
Status[0] = val7;
return;
}
Vector3 val8 = straightPath[straightPathCount - 1];
if (math.distancesq(float3.op_Implicit(Destination), float3.op_Implicit(val8)) > 2.25f)
{
Status[0] = (PathQueryStatus)int.MinValue;
return;
}
float num3 = 0f;
for (int i = 1; i < straightPathCount; i++)
{
num3 += math.distance(float3.op_Implicit(straightPath[i - 1]), float3.op_Implicit(straightPath[i]));
}
PathLength[0] = num3;
Status[0] = (PathQueryStatus)1073741824;
}
finally
{
((IDisposable)straightPath).Dispose();
}
}
public PathQueryStatus GetStatus()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
return Status[0];
}
public float GetPathLength()
{
return PathLength[0];
}
public void Dispose()
{
DisposeArrays();
}
}
public class PooledFindPathJob
{
private FindPathJob job;
public ref FindPathJob Job => ref job;
}
public static class JobPools
{
private static readonly ObjectPool<PooledFindPathJob> findPathPool = new ObjectPool<PooledFindPathJob>((Func<PooledFindPathJob>)(() => new PooledFindPathJob()), (Action<PooledFindPathJob>)null, (Action<PooledFindPathJob>)null, (Action<PooledFindPathJob>)delegate(PooledFindPathJob j)
{
j.Job.Dispose();
}, true, 10, 10000);
public static PooledFindPathJob GetFindPathJob()
{
return findPathPool.Get();
}
public static void ReleaseFindPathJob(PooledFindPathJob job)
{
if (job == null)
{
PathfindingLibPlugin.Instance.Logger.LogError((object)$"Attempted to free a null job\n{new StackTrace()}");
}
else
{
findPathPool.Release(job);
}
}
}
public static class PathfindingJobSharedResources
{
public const int MaximumPathPolygonCount = 4096;
[NativeDisableContainerSafetyRestriction]
private static NativeArray<NavMeshQuery> StaticThreadQueries;
public static ref readonly NativeArray<NavMeshQuery> GetPerThreadQueriesArray()
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: 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)
int threadIndexCount = JobsUtility.ThreadIndexCount;
if (StaticThreadQueries.Length >= threadIndexCount)
{
return ref StaticThreadQueries;
}
Application.quitting -= DisposeQueries;
NativeArray<NavMeshQuery> staticThreadQueries = default(NativeArray<NavMeshQuery>);
staticThreadQueries..ctor(threadIndexCount, (Allocator)4, (NativeArrayOptions)1);
for (int i = 0; i < StaticThreadQueries.Length; i++)
{
staticThreadQueries[i] = StaticThreadQueries[i];
}
for (int j = StaticThreadQueries.Length; j < threadIndexCount; j++)
{
staticThreadQueries[j] = new NavMeshQuery(NavMeshWorld.GetDefaultWorld(), (Allocator)4, 4096);
}
StaticThreadQueries.Dispose();
StaticThreadQueries = staticThreadQueries;
Application.quitting += DisposeQueries;
return ref StaticThreadQueries;
}
private static void DisposeQueries()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: 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)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
Enumerator<NavMeshQuery> enumerator = StaticThreadQueries.GetEnumerator();
try
{
while (enumerator.MoveNext())
{
NavMeshQuery current = enumerator.Current;
((NavMeshQuery)(ref current)).Dispose();
}
}
finally
{
((IDisposable)enumerator).Dispose();
}
StaticThreadQueries.Dispose();
Application.quitting -= DisposeQueries;
}
}
}
namespace PathfindingLib.API
{
public static class NavMeshLock
{
private const int recommendedSliceCount = 128;
[ThreadStatic]
private static int threadState = 0;
private static readonly object conditionVariable = new object();
private static int readersActive = 0;
private static int writersWaiting = 0;
private static bool writerActive = false;
public static int RecommendedUpdateFindPathIterationCount => 128;
public static void BeginWrite()
{
if (threadState < 0)
{
throw CreateAndPrintInvalidOperationException("Cannot begin a navmesh write while a read is ongoing.");
}
if (threadState++ > 0)
{
return;
}
lock (conditionVariable)
{
writersWaiting++;
while (readersActive > 0 || writerActive)
{
Monitor.Wait(conditionVariable);
}
writersWaiting--;
writerActive = true;
}
}
public static void EndWrite()
{
if (threadState <= 0)
{
throw CreateAndPrintInvalidOperationException("A navmesh write has not been started.");
}
if (--threadState > 0)
{
return;
}
lock (conditionVariable)
{
if (!writerActive)
{
throw CreateAndPrintInvalidOperationException("EndWrite() was called without first calling BeginWrite.");
}
writerActive = false;
Monitor.PulseAll(conditionVariable);
}
}
public static void BeginRead()
{
if (threadState > 0)
{
throw CreateAndPrintInvalidOperationException("Cannot begin a navmesh read while a write is ongoing.");
}
if (threadState-- < 0)
{
return;
}
lock (conditionVariable)
{
while (writersWaiting > 0 || writerActive)
{
Monitor.Wait(conditionVariable);
}
readersActive++;
}
}
public static void EndRead()
{
if (threadState >= 0)
{
throw CreateAndPrintInvalidOperationException("A navmesh read has not been started.");
}
if (++threadState < 0)
{
return;
}
lock (conditionVariable)
{
readersActive--;
if (readersActive < 0)
{
throw CreateAndPrintInvalidOperationException("EndRead() was called more times than BeginRead.");
}
if (readersActive == 0)
{
Monitor.PulseAll(conditionVariable);
}
}
}
public static void YieldRead()
{
EndRead();
BeginRead();
}
private static InvalidOperationException CreateAndPrintInvalidOperationException(string message)
{
PathfindingLibPlugin.Instance.Logger.LogError((object)message);
PathfindingLibPlugin.Instance.Logger.LogError((object)"Check Unity's Player.log to see the exception's stack trace.");
return new InvalidOperationException(message);
}
}
[Obsolete("Use PathfindingLib.Utilities.NavMeshReadLocker")]
internal class NavMeshReadLocker : IDisposable
{
private bool locked;
public NavMeshReadLocker()
{
NavMeshLock.BeginRead();
locked = true;
}
public void Yield()
{
NavMeshLock.YieldRead();
}
public void Dispose()
{
if (locked)
{
locked = false;
NavMeshLock.EndRead();
}
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}