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 Microsoft.CodeAnalysis;
using PathfindingLib.API.SmartPathfinding;
using PathfindingLib.Utilities;
using SmartEnemyPathfinding.Patches;
using SmartEnemyPathfinding.Utilities.IL;
using UnityEngine;
using UnityEngine.AI;
[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("2.3.0")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.3.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 SmartEnemyPathfinding
{
[BepInPlugin("Zaggy1024.SmartEnemyPathfinding", "SmartEnemyPathfinding", "0.0.2")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
public const string PluginName = "SmartEnemyPathfinding";
public const string PluginGUID = "Zaggy1024.SmartEnemyPathfinding";
public const string PluginVersion = "0.0.2";
private readonly Harmony harmony = new Harmony("Zaggy1024.SmartEnemyPathfinding");
internal static ConfigEntry<bool> GlobalRoaming;
internal static Plugin Instance { get; private set; }
internal ManualLogSource Logger => ((BaseUnityPlugin)this).Logger;
public void Awake()
{
Instance = this;
GlobalRoaming = ((BaseUnityPlugin)this).Config.Bind<bool>("Masked", "GlobalRoaming", false, "Whether the masked player search routine should take them through fire exits and the main entrance. When enabled, the masked will no longer run straight to the main entrance to leave the interior when no players are inside.");
harmony.PatchAll(typeof(PatchMaskedPlayerEnemy));
harmony.PatchAll(typeof(PatchEnemyAI));
}
}
}
namespace SmartEnemyPathfinding.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 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);
}
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 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 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 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 || 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 SmartEnemyPathfinding.Patches
{
[HarmonyPatch(typeof(EnemyAI))]
internal static class PatchEnemyAI
{
[HarmonyPrefix]
[HarmonyPatch("NavigateTowardsTargetPlayer")]
private static bool NavigateTowardsTargetPlayerPrefix(EnemyAI __instance)
{
MaskedPlayerEnemy val = (MaskedPlayerEnemy)(object)((__instance is MaskedPlayerEnemy) ? __instance : null);
if (val != null)
{
return PatchMaskedPlayerEnemy.NavigateTowardsTargetPlayerPrefix(val);
}
return true;
}
}
[HarmonyPatch(typeof(MaskedPlayerEnemy))]
internal static class PatchMaskedPlayerEnemy
{
private class TaskData
{
internal SmartPathTask task = new SmartPathTask();
internal bool lastPathWasDirect;
}
private enum GoToDestinationResult
{
Success,
InProgress,
Failure
}
[CompilerGenerated]
private static class <>O
{
public static SmartTraversalFunction <0>__RoamToSmartPathDestination;
}
private static readonly Dictionary<MaskedPlayerEnemy, float> originalSearchWidths = new Dictionary<MaskedPlayerEnemy, float>();
private static readonly Dictionary<MaskedPlayerEnemy, TaskData> tasks = new Dictionary<MaskedPlayerEnemy, TaskData>();
[HarmonyPrefix]
[HarmonyPatch(typeof(MaskedPlayerEnemy), "Awake")]
private static void AwakePrefix(MaskedPlayerEnemy __instance)
{
NavMeshAgent componentInChildren = ((Component)__instance).GetComponentInChildren<NavMeshAgent>();
if (!((Object)(object)componentInChildren == (Object)null))
{
SmartPathfinding.RegisterSmartAgent(componentInChildren);
}
}
[HarmonyPostfix]
[HarmonyPatch("Start")]
[HarmonyPatch("SetEnemyOutside")]
private static void ReplaceAINodesPostfix(MaskedPlayerEnemy __instance)
{
if (Plugin.GlobalRoaming.Value)
{
GameObject[] array = GameObject.FindGameObjectsWithTag("OutsideAINode");
GameObject[] array2 = GameObject.FindGameObjectsWithTag("AINode");
int num = 0;
GameObject[] array3 = (GameObject[])(object)new GameObject[array.Length + array2.Length];
ReadOnlySpan<GameObject> readOnlySpan = new ReadOnlySpan<GameObject>(array);
readOnlySpan.CopyTo(new Span<GameObject>(array3).Slice(num, readOnlySpan.Length));
num += readOnlySpan.Length;
ReadOnlySpan<GameObject> readOnlySpan2 = new ReadOnlySpan<GameObject>(array2);
readOnlySpan2.CopyTo(new Span<GameObject>(array3).Slice(num, readOnlySpan2.Length));
num += readOnlySpan2.Length;
((EnemyAI)__instance).allAINodes = array3;
}
}
private static SmartPathfindingLinkFlags GetAllowedPathLinks()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: 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_0010: 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)
SmartPathfindingLinkFlags val = (SmartPathfindingLinkFlags)7;
if (Plugin.GlobalRoaming.Value)
{
val = (SmartPathfindingLinkFlags)(val | 8);
}
return val;
}
private static void UseTeleport(MaskedPlayerEnemy masked, EntranceTeleport teleport)
{
//IL_0069: 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)
if (!((Object)(object)teleport.exitPoint == (Object)null) || teleport.FindExitPoint())
{
if (Plugin.GlobalRoaming.Value)
{
bool inProgress = masked.searchForPlayers.inProgress;
masked.searchForPlayers.inProgress = false;
masked.TeleportMaskedEnemyAndSync(teleport.exitPoint.position, !teleport.isEntranceToBuilding);
masked.searchForPlayers.inProgress = inProgress;
}
else
{
masked.TeleportMaskedEnemyAndSync(teleport.exitPoint.position, !teleport.isEntranceToBuilding);
}
}
}
private static bool GoToSmartPathDestination(MaskedPlayerEnemy masked, in SmartPathDestination destination)
{
//IL_0006: 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_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: 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_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Expected I4, but got Unknown
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
if (Vector3.Distance(((Component)masked).transform.position, ((SmartPathDestination)(ref destination)).Position) <= 1f && ((SmartPathDestination)(ref destination)).CanActivateDestination(((Component)masked).transform.position))
{
SmartDestinationType type = ((SmartPathDestination)(ref destination)).Type;
switch ((int)type)
{
case 1:
((EnemyAI)masked).agent.Warp(((SmartPathDestination)(ref destination)).InternalTeleport.Destination.position);
break;
case 3:
((SmartPathDestination)(ref destination)).ElevatorFloor.CallElevator();
break;
case 2:
UseTeleport(masked, ((SmartPathDestination)(ref destination)).EntranceTeleport);
break;
default:
return false;
case 0:
break;
}
}
((EnemyAI)masked).moveTowardsDestination = true;
((EnemyAI)masked).destination = ((SmartPathDestination)(ref destination)).Position;
return true;
}
private static bool SetDestinationToSmartPathDestination(MaskedPlayerEnemy masked, in SmartPathDestination destination)
{
((EnemyAI)masked).movingTowardsTargetPlayer = false;
return GoToSmartPathDestination(masked, in destination);
}
private static void RoamToSmartPathDestination(EnemyAI maskedAI, in SmartPathDestination destination)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
SetDestinationToSmartPathDestination((MaskedPlayerEnemy)maskedAI, in destination);
}
private static GoToDestinationResult GoToDestination(MaskedPlayerEnemy masked, Vector3 targetPosition)
{
//IL_0078: 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_007e: 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_003e: Unknown result type (might be due to invalid IL or missing references)
GoToDestinationResult result = GoToDestinationResult.InProgress;
if (tasks.TryGetValue(masked, out var value))
{
if (!value.task.IsResultReady(0))
{
return result;
}
SmartPathDestination? result2 = value.task.GetResult(0);
if (result2.HasValue)
{
SmartPathDestination destination = result2.GetValueOrDefault();
result = ((!SetDestinationToSmartPathDestination(masked, in destination)) ? GoToDestinationResult.Failure : GoToDestinationResult.Success);
}
else
{
result = GoToDestinationResult.Failure;
}
}
else
{
value = new TaskData();
tasks[masked] = value;
}
value.task.StartPathTask(((EnemyAI)masked).agent, AgentExtensions.GetPathOrigin(((EnemyAI)masked).agent), targetPosition, GetAllowedPathLinks());
return result;
}
private static bool CheckIfPlayersAreTargetable(MaskedPlayerEnemy masked)
{
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
if (Plugin.GlobalRoaming.Value)
{
return true;
}
if ((Object)(object)((EnemyAI)masked).GetClosestPlayer(false, false, false) == (Object)null)
{
switch (GoToDestination(masked, RoundManager.FindMainEntrancePosition(true, !((EnemyAI)masked).isOutside)))
{
case GoToDestinationResult.InProgress:
return false;
case GoToDestinationResult.Success:
((EnemyAI)masked).StopSearch(masked.searchForPlayers, true);
return false;
}
}
return true;
}
private static void StartSearch(MaskedPlayerEnemy masked, Vector3 searchStart, AISearchRoutine searchRoutine)
{
//IL_0064: 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_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Expected O, but got Unknown
if (searchRoutine == masked.searchForPlayers)
{
float value;
if (Plugin.GlobalRoaming.Value)
{
if (!originalSearchWidths.ContainsKey(masked))
{
originalSearchWidths[masked] = searchRoutine.searchWidth;
}
searchRoutine.searchWidth = float.PositiveInfinity;
}
else if (originalSearchWidths.TryGetValue(masked, out value))
{
searchRoutine.searchWidth = value;
originalSearchWidths.Remove(masked);
}
}
Config val = default(Config);
((Config)(ref val))..ctor(GetAllowedPathLinks());
if (Plugin.GlobalRoaming.Value)
{
val.timeToNavigateToCurrentDestination = 40f;
}
Config val2 = val;
object obj = <>O.<0>__RoamToSmartPathDestination;
if (obj == null)
{
SmartTraversalFunction val3 = RoamToSmartPathDestination;
<>O.<0>__RoamToSmartPathDestination = val3;
obj = (object)val3;
}
SmartRoaming.StartSmartSearch((EnemyAI)(object)masked, searchStart, val2, (SmartTraversalFunction)obj, searchRoutine);
}
internal static bool NavigateTowardsTargetPlayerPrefix(MaskedPlayerEnemy masked)
{
//IL_00a5: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_0051: 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_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Invalid comparison between Unknown and I4
PlayerControllerB targetPlayer = ((EnemyAI)masked).targetPlayer;
if ((Object)(object)targetPlayer == (Object)null)
{
return true;
}
bool result = false;
if (tasks.TryGetValue(masked, out var value))
{
if (!value.task.IsResultReady(0))
{
return value.lastPathWasDirect;
}
SmartPathDestination? result2 = value.task.GetResult(0);
if (result2.HasValue)
{
SmartPathDestination destination = result2.GetValueOrDefault();
value.lastPathWasDirect = (int)((SmartPathDestination)(ref destination)).Type == 0;
result = value.lastPathWasDirect;
if (!value.lastPathWasDirect)
{
GoToSmartPathDestination(masked, in destination);
}
}
}
else
{
value = new TaskData();
tasks[masked] = value;
}
value.task.StartPathTask(((EnemyAI)masked).agent, AgentExtensions.GetPathOrigin(((EnemyAI)masked).agent), ((Component)targetPlayer).transform.position, GetAllowedPathLinks());
return result;
}
[HarmonyTranspiler]
[HarmonyPatch("DoAIInterval")]
private static IEnumerable<CodeInstruction> DoAIIntervalTranspiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
{
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00f6: Expected O, but got Unknown
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: Expected O, but got Unknown
//IL_0139: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Expected O, but got Unknown
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_014d: Expected O, but got Unknown
//IL_0216: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Expected O, but got Unknown
Label operand;
ILInjector iLInjector = new ILInjector(instructions, generator).Find(ILMatcher.Call(typeof(Time).GetProperty("realtimeSinceStartup").GetMethod, "DoAIIntervalTranspiler", "E:\\Development\\Lethal Company\\Projects\\SmartEnemyPathfinding\\SmartEnemyPathfinding\\Patches\\PatchMaskedPlayerEnemy.cs", 232), ILMatcher.Ldarg(0), ILMatcher.Ldfld(typeof(MaskedPlayerEnemy).GetField("timeAtLastUsingEntrance", BindingFlags.Instance | BindingFlags.NonPublic), "DoAIIntervalTranspiler", "E:\\Development\\Lethal Company\\Projects\\SmartEnemyPathfinding\\SmartEnemyPathfinding\\Patches\\PatchMaskedPlayerEnemy.cs", 234), ILMatcher.Opcode(OpCodes.Sub), ILMatcher.LdcF32(3f), ILMatcher.Opcode(OpCodes.Ble_Un).CaptureOperandAs<Label>(out operand)).GoToMatchEnd();
if (!iLInjector.IsValid)
{
Plugin.Instance.Logger.LogError((object)"Failed to find the code block to make masked path through the entrance in MaskedPlayerEnemy.DoAIInterval().");
return instructions;
}
iLInjector.FindLabel(operand).DefineLabel(out var label).ReplaceLastMatch(new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchMaskedPlayerEnemy), "CheckIfPlayersAreTargetable", BindingFlags.Static | BindingFlags.NonPublic, new Type[1] { typeof(MaskedPlayerEnemy) })), new CodeInstruction(OpCodes.Brtrue_S, (object)label), new CodeInstruction(OpCodes.Ret, (object)null))
.GoToMatchEnd()
.AddLabel(label);
iLInjector.GoToStart();
while (true)
{
iLInjector.Find(ILMatcher.Call(typeof(EnemyAI).GetMethod("StartSearch", new Type[2]
{
typeof(Vector3),
typeof(AISearchRoutine)
}), "DoAIIntervalTranspiler", "E:\\Development\\Lethal Company\\Projects\\SmartEnemyPathfinding\\SmartEnemyPathfinding\\Patches\\PatchMaskedPlayerEnemy.cs", 266));
if (!iLInjector.IsValid)
{
break;
}
iLInjector.ReplaceLastMatch(new CodeInstruction(OpCodes.Call, (object)Reflection.GetMethod(typeof(PatchMaskedPlayerEnemy), "StartSearch", BindingFlags.Static | BindingFlags.NonPublic, new Type[3]
{
typeof(MaskedPlayerEnemy),
typeof(Vector3),
typeof(AISearchRoutine)
}))).GoToMatchEnd();
}
return iLInjector.ReleaseInstructions();
}
[HarmonyPostfix]
[HarmonyPatch("OnDestroy")]
private static void OnDestroyPostfix(MaskedPlayerEnemy __instance)
{
tasks.Remove(__instance);
}
}
internal static class Reflection
{
public static MethodInfo GetMethod(this Type type, string name, BindingFlags bindingFlags, Type[] parameters)
{
return type.GetMethod(name, bindingFlags, null, parameters, null);
}
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}