Decompiled source of EnemyAnimationFix v1.4.3

EnemyAnimationFix.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using AIGraph;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Hook;
using BepInEx.Unity.IL2CPP.Utils.Collections;
using CullingSystem;
using Enemies;
using EnemyAnimationFix.API;
using EnemyAnimationFix.NativePatches;
using EnemyAnimationFix.NativePatches.KernelTools;
using EnemyAnimationFix.Networking.Foam;
using EnemyAnimationFix.Networking.Notify;
using EnemyAnimationFix.Patches;
using EnemyAnimationFix.Utils;
using EnemyAnimationFix.Utils.Extensions;
using GTFO.API;
using GTFO.API.Utilities;
using HarmonyLib;
using Iced.Intel;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppInterop.Runtime.Runtime;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.Class;
using Il2CppInterop.Runtime.Runtime.VersionSpecific.MethodInfo;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using StateMachines;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("EnemyAnimationFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+dbc340be9ef83557c72549df548af615f04937f1")]
[assembly: AssemblyProduct("EnemyAnimationFix")]
[assembly: AssemblyTitle("EnemyAnimationFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace EnemyAnimationFix
{
	public static class Configuration
	{
		private static readonly ConfigEntry<float> _syncLerpTime;

		private static readonly ConfigEntry<float> _minWaveSleepTime;

		private static readonly ConfigEntry<float> _maxWaveSleepTime;

		private static readonly ConfigEntry<bool> _disableCullNear;

		private static readonly ConfigFile configFile;

		public static float SyncLerpTime => _syncLerpTime.Value;

		public static float MinWaveSleepTime => _minWaveSleepTime.Value;

		public static float MaxWaveSleepTime => _maxWaveSleepTime.Value;

		public static bool DisableNearCull => _disableCullNear.Value;

		static Configuration()
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "EnemyAnimationFix.cfg"), true);
			string text = "Sync Settings";
			string text2 = "Amount of time the enemy position is smoothed over to match host position when they stop moving to attack/scream/etc.";
			_syncLerpTime = configFile.Bind<float>(text, "Sync Position Time", 0.25f, text2);
			text = "Wave Settings";
			text2 = "Minimum amount of time in seconds before enemies become active after spawning.";
			_minWaveSleepTime = configFile.Bind<float>(text, "Minimum Wave Inactive Time", 0f, text2);
			text2 = "Maximum amount of time in seconds before enemies become active after spawning.";
			_maxWaveSleepTime = configFile.Bind<float>(text, "Maximum Wave Inactive Time", 6f, text2);
			text = "Cull Settings";
			text2 = "Prevents nearby or attacking enemies from culling.\nThis fixes enemies not on screen failing to play footstep sounds or move when attacking.";
			_disableCullNear = configFile.Bind<bool>(text, "Disable Culling Nearby Enemies", true, text2);
		}

		internal static void Init()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			LiveEdit.CreateListener(Paths.ConfigPath, "EnemyAnimationFix.cfg", false).FileChanged += new LiveEditEventHandler(OnFileChanged);
		}

		private static void OnFileChanged(LiveEditEventArgs _)
		{
			configFile.Reload();
		}
	}
	[BepInPlugin("Dinorush.EnemyAnimationFix", "EnemyAnimationFix", "1.4.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	internal sealed class EntryPoint : BasePlugin
	{
		public const string MODNAME = "EnemyAnimationFix";

		public override void Load()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			new Harmony("EnemyAnimationFix").PatchAll();
			ChangeStatePatches.ApplyNativePatch();
			ValidTargetPatches.ApplyInstructionPatch();
			Configuration.Init();
			AssetAPI.OnStartupAssetsLoaded += AssetAPI_OnStartupAssetsLoaded;
			LevelAPI.OnLevelCleanup += LevelAPI_OnLevelCleanup;
			((BasePlugin)this).Log.LogMessage((object)"Loaded EnemyAnimationFix");
		}

		private void AssetAPI_OnStartupAssetsLoaded()
		{
			NotifyManager.Init();
			FoamManager.Init();
		}

		private void LevelAPI_OnLevelCleanup()
		{
			EB_InCombat.s_globalScreamTimer = 0f;
			EnemyMovementPatches.OnCleanup();
		}
	}
}
namespace EnemyAnimationFix.Utils
{
	internal static class DinoLogger
	{
		private static ManualLogSource logger = Logger.CreateLogSource("EnemyAnimationFix");

		public static void Log(string format, params object[] args)
		{
			Log(string.Format(format, args));
		}

		public static void Log(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)8, (object)str);
			}
		}

		public static void Warning(string format, params object[] args)
		{
			Warning(string.Format(format, args));
		}

		public static void Warning(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)4, (object)str);
			}
		}

		public static void Error(string format, params object[] args)
		{
			Error(string.Format(format, args));
		}

		public static void Error(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)2, (object)str);
			}
		}

		public static void Debug(string format, params object[] args)
		{
			Debug(string.Format(format, args));
		}

		public static void Debug(string str)
		{
			if (logger != null)
			{
				logger.Log((LogLevel)32, (object)str);
			}
		}
	}
}
namespace EnemyAnimationFix.Utils.Extensions
{
	internal static class EnemyAgentExt
	{
		public static void AddOnDeadOnce(this EnemyAgent agent, Action onDead)
		{
			Action onDead2 = onDead;
			bool called = false;
			agent.OnDeadCallback += Action.op_Implicit((Action)delegate
			{
				if (!called && !CheckpointManager.IsReloadingCheckpoint)
				{
					onDead2?.Invoke();
					called = true;
				}
			});
		}
	}
}
namespace EnemyAnimationFix.Patches
{
	[HarmonyPatch]
	internal static class EnemyAnimPatches
	{
		[HarmonyPatch(typeof(ES_Scream), "OnStateShouldBeActivated")]
		[HarmonyPrefix]
		private static void FixGiantScream(ES_Scream __instance, ref pES_EnemyScreamData data)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Invalid comparison between Unknown and I4
			if (NotifyManager.MasterHasFix && (int)((ES_Base)__instance).m_locomotion.AnimHandleName == 128)
			{
				data.AnimIndex = 0;
			}
		}

		[HarmonyPatch(typeof(ES_StrikerAttack), "OnAttackWindUp")]
		[HarmonyPatch(typeof(ES_ShooterAttack), "OnAttackWindUp")]
		[HarmonyPrefix]
		private static void FixFiddlerAttack(ES_EnemyAttackBase __instance, ref int attackIndex)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (NotifyManager.MasterHasFix && (int)((ES_Base)__instance).m_locomotion.AnimHandleName == 8)
			{
				attackIndex %= 2;
			}
		}

		[HarmonyPatch(typeof(ES_Hitreact), "DoHitReact")]
		[HarmonyPrefix]
		private static void FixLowStagger(ES_Hitreact __instance, ref int index, ES_HitreactType hitreactType, ImpactDirection impactDirection)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Invalid comparison between Unknown and I4
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Invalid comparison between Unknown and I4
			if (NotifyManager.MasterHasFix && (int)((ES_Base)__instance).m_locomotion.AnimHandleName == 16 && (int)hitreactType == 3 && (int)impactDirection == 2)
			{
				index %= 3;
			}
		}
	}
	[HarmonyPatch]
	internal static class EnemyAttackPatches
	{
		[HarmonyPatch(typeof(MovingEnemyTentacleBase), "BuildAndUpdateAttackSpline")]
		[HarmonyPostfix]
		private static void Post_AttackSplineBuilt(MovingEnemyTentacleBase __instance, bool __result)
		{
			if (!__result)
			{
				__instance.TentacleRelLen = __instance.MinLengthWhenIn;
				__instance.m_inAttackMove = false;
				__instance.m_goingIn = false;
				__instance.m_owner.Locomotion.ChangeState((ES_StateEnum)2);
			}
		}

		[HarmonyPatch(typeof(ES_StrikerAttack), "OnAttackPerform")]
		[HarmonyPostfix]
		private static void Post_StrikerAttackPerform(ES_StrikerAttack __instance)
		{
			if (TryGetTentacle(__instance, out MovingEnemyTentacleBase tentacle))
			{
				tentacle.m_inAttackMove = true;
			}
		}

		[HarmonyPatch(typeof(ES_ShooterAttack), "OnAttackPerform")]
		[HarmonyPostfix]
		private static void Post_ShooterAttackPerform(ES_ShooterAttack __instance)
		{
			if (!(((ES_EnemyAttackBase)__instance).m_attackDoneTimer >= Clock.Time))
			{
				EAB_ProjectileShooter projectileAbility = __instance.m_projectileAbility;
				((ES_EnemyAttackBase)__instance).m_attackDoneTimer = Clock.Time + (projectileAbility.m_shotDelayMin + projectileAbility.m_shotDelayMax) / 2f * (float)projectileAbility.m_burstCount * 0.7f + __instance.m_burstCoolDownBeforeExit;
			}
		}

		[HarmonyPatch(typeof(ES_StrikerAttack), "CommonExit")]
		[HarmonyPostfix]
		private static void Post_StrikerAttackExit(ES_StrikerAttack __instance)
		{
			if (NotifyManager.MasterHasFix && !(Clock.Time <= ((ES_EnemyAttackBase)__instance).m_performAttackTimer) && TryGetTentacle(__instance, out MovingEnemyTentacleBase tentacle) && tentacle.m_currentRoutine != null)
			{
				tentacle.SwitchCoroutine(tentacle.AttackIn(tentacle.m_attackInDuration));
			}
		}

		private static bool TryGetTentacle(ES_StrikerAttack attack, [MaybeNullWhen(false)] out MovingEnemyTentacleBase tentacle)
		{
			tentacle = null;
			EAB_MovingEnemeyTentacle tentacleAbility = attack.m_tentacleAbility;
			if ((Object)(object)tentacleAbility == (Object)null)
			{
				return false;
			}
			tentacle = tentacleAbility.m_tentacle;
			return (Object)(object)tentacle != (Object)null;
		}

		[HarmonyPatch(typeof(ES_PathMove), "Exit")]
		[HarmonyPostfix]
		private static void Post_TankPathMoveExit(ES_PathMove __instance)
		{
			if (NotifyManager.MasterHasFix)
			{
				EnemyAbilities abilities = ((ES_Base)__instance).m_enemyAgent.Abilities;
				if (!ResetTankTongues(abilities, (AgentAbility)2))
				{
					ResetTankTongues(abilities, (AgentAbility)1);
				}
			}
		}

		private static bool ResetTankTongues(EnemyAbilities abilities, AgentAbility abilityType)
		{
			//IL_0001: 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_000d: Expected I4, but got Unknown
			if (!((AgentAbilities)abilities).HasAbility(abilityType))
			{
				return false;
			}
			int num = (int)abilityType;
			bool result = false;
			foreach (EnemyAbility item in (Il2CppArrayBase<EnemyAbility>)(object)((Il2CppArrayBase<AbilityCompsWrapper>)(object)abilities.AbilityComps)[num].Comps)
			{
				EAB_MovingEnemyTentacleMultiple val = ((Il2CppObjectBase)item).TryCast<EAB_MovingEnemyTentacleMultiple>();
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				result = true;
				foreach (MovingEnemyTentacleBase item2 in (Il2CppArrayBase<MovingEnemyTentacleBase>)(object)val.m_tentacles)
				{
					if (item2.m_currentRoutine != null)
					{
						item2.SwitchCoroutine(item2.AttackIn(item2.m_attackInDuration));
					}
				}
			}
			return result;
		}

		[HarmonyPatch(typeof(ES_ShooterAttack), "CommonExit")]
		[HarmonyPostfix]
		private static void Post_ShooterAttackExit(ES_ShooterAttack __instance)
		{
			if (NotifyManager.MasterHasFix && !(Clock.Time <= ((ES_EnemyAttackBase)__instance).m_performAttackTimer))
			{
				__instance.m_projectileAbility.FireEnd();
			}
		}
	}
	[HarmonyPatch]
	internal class EnemyCullPatches
	{
		private static readonly List<(Animator animator, C_CullBucket bucket)> _nearbyCullers = new List<(Animator, C_CullBucket)>(5);

		private static readonly Dictionary<IntPtr, (EnemyAgent enemy, float sqrDist)> _cachedEnemies = new Dictionary<IntPtr, (EnemyAgent, float)>();

		private static float _nextUpdateTime = 0f;

		private const float UpdateInterval = 0.1f;

		private const float NearbySqrDist = 625f;

		private const int NearbyCap = 5;

		[HarmonyPatch(typeof(C_Camera), "PropagateFrustra")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void RestoreFootstepCullers()
		{
			if (!Configuration.DisableNearCull)
			{
				return;
			}
			CheckDeadCullers();
			float time = Clock.Time;
			if (time > _nextUpdateTime)
			{
				_nextUpdateTime = time + 0.1f;
				CacheCullers();
			}
			foreach (var nearbyCuller in _nearbyCullers)
			{
				C_CullBucket item = nearbyCuller.bucket;
				if (((C_Cullable)item).CullKey != C_Keys.CurrentCullKey)
				{
					((C_Cullable)item).CullKey = C_Keys.CurrentCullKey;
					((C_Cullable)item).Show();
				}
			}
		}

		private static void CheckDeadCullers()
		{
			for (int num = _nearbyCullers.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)_nearbyCullers[num].animator == (Object)null)
				{
					_nearbyCullers.RemoveAt(num);
				}
			}
		}

		private static void CacheCullers()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Invalid comparison between Unknown and I4
			foreach (var nearbyCuller in _nearbyCullers)
			{
				Animator item = nearbyCuller.animator;
				if ((int)item.cullingMode == 1)
				{
					item.cullingMode = (AnimatorCullingMode)2;
				}
			}
			_nearbyCullers.Clear();
			if (!PlayerManager.HasLocalPlayerAgent())
			{
				return;
			}
			PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
			Vector3 position = ((Agent)localPlayerAgent).Position;
			AIG_CourseNode courseNode = ((Agent)localPlayerAgent).CourseNode;
			CacheNearbyEnemies(courseNode, position);
			if (_cachedEnemies.Count < 5)
			{
				Enumerator<AIG_CoursePortal> enumerator2 = courseNode.m_portals.GetEnumerator();
				while (enumerator2.MoveNext())
				{
					AIG_CoursePortal current = enumerator2.Current;
					if (current.IsTraversable)
					{
						Bounds bounds = ((C_Cullable)current.m_cullPortal).Bounds;
						Vector3 val = ((Bounds)(ref bounds)).ClosestPoint(position) - position;
						if (((Vector3)(ref val)).sqrMagnitude < 625f)
						{
							CacheNearbyEnemies(current.GetOppositeNode(courseNode), position);
						}
					}
					if (_cachedEnemies.Count > 5)
					{
						break;
					}
				}
			}
			_nearbyCullers.AddRange(from kv in _cachedEnemies.OrderBy<KeyValuePair<IntPtr, (EnemyAgent, float)>, float>((KeyValuePair<IntPtr, (EnemyAgent enemy, float sqrDist)> kv) => kv.Value.sqrDist).Take(5)
				select (kv.Value.enemy.Locomotion.m_animator, kv.Value.enemy.MovingCuller.CullBucket));
			foreach (var nearbyCuller2 in _nearbyCullers)
			{
				Animator item2 = nearbyCuller2.animator;
				if ((int)item2.cullingMode == 2)
				{
					item2.cullingMode = (AnimatorCullingMode)1;
				}
			}
			_cachedEnemies.Clear();
		}

		private static void CacheNearbyEnemies(AIG_CourseNode node, Vector3 pos)
		{
			//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_0033: 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_0048: Invalid comparison between Unknown and I4
			Enumerator<EnemyAgent> enumerator = node.m_enemiesInNode.GetEnumerator();
			while (enumerator.MoveNext())
			{
				EnemyAgent current = enumerator.Current;
				if (!_cachedEnemies.ContainsKey(((Il2CppObjectBase)current).Pointer))
				{
					Vector3 val = current.Position - pos;
					float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
					if ((int)current.Locomotion.CurrentStateEnum == 2 && sqrMagnitude < 625f)
					{
						_cachedEnemies.Add(((Il2CppObjectBase)current).Pointer, (current, sqrMagnitude));
					}
					if (_cachedEnemies.Count > 5)
					{
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(EnemyAgent), "SetAnimatorCullingEnabled")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void FixFootstepCulling(EnemyAgent __instance, bool mode)
		{
			if (Configuration.DisableNearCull && mode)
			{
				Animator animator = __instance.Locomotion.m_animator;
				if (_nearbyCullers.Any<(Animator, C_CullBucket)>(((Animator animator, C_CullBucket bucket) pair) => ((Il2CppObjectBase)animator).Pointer == ((Il2CppObjectBase)pair.animator).Pointer))
				{
					animator.cullingMode = (AnimatorCullingMode)1;
				}
			}
		}

		[HarmonyPatch(typeof(ES_EnemyAttackBase), "DoStartAttack")]
		[HarmonyPatch(typeof(ES_StrikerMelee), "DoStartMeleeAttack")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void DisableAttackAnimCulling(ES_EnemyAttackBase __instance)
		{
			if (Configuration.DisableNearCull)
			{
				((ES_Base)__instance).m_locomotion.m_animator.cullingMode = (AnimatorCullingMode)0;
			}
		}

		[HarmonyPatch(typeof(ES_EnemyAttackBase), "CommonExit")]
		[HarmonyPatch(typeof(ES_StrikerMelee), "Exit")]
		[HarmonyPatch(typeof(ES_StrikerMelee), "SyncExit")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void EnableAttackCulling(ES_EnemyAttackBase __instance)
		{
			if (Configuration.DisableNearCull)
			{
				EnemyAgent agent = ((ES_Base)__instance).m_locomotion.m_agent;
				((Agent)agent).SetAnimatorCullingEnabled(agent.MovingCuller.m_animatorCullingEnabled);
			}
		}

		[HarmonyPatch(typeof(ES_Hitreact), "DoHitReact")]
		[HarmonyWrapSafe]
		[HarmonyPrefix]
		private static void DisableStaggerCulling(ES_HitreactBase __instance)
		{
			if (Configuration.DisableNearCull)
			{
				((ES_Base)__instance).m_locomotion.m_animator.cullingMode = (AnimatorCullingMode)0;
			}
		}

		[HarmonyPatch(typeof(ES_Hitreact), "Exit")]
		[HarmonyPatch(typeof(ES_Hitreact), "SyncExit")]
		[HarmonyWrapSafe]
		[HarmonyPostfix]
		private static void EnableStaggerCulling(ES_HitreactBase __instance)
		{
			if (Configuration.DisableNearCull)
			{
				EnemyAgent agent = ((ES_Base)__instance).m_locomotion.m_agent;
				((Agent)agent).SetAnimatorCullingEnabled(agent.MovingCuller.m_animatorCullingEnabled);
			}
		}
	}
	[HarmonyPatch]
	internal static class EnemyGluePatches
	{
		[HarmonyPatch(typeof(Dam_EnemyDamageBase), "AddToTotalGlueVolume")]
		[HarmonyPostfix]
		private static void SyncGlueData(Dam_EnemyDamageBase __instance)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			if ((int)__instance.Owner.Locomotion.CurrentStateEnum == 17)
			{
				ES_StuckInGlue stuckInGlue = __instance.Owner.Locomotion.StuckInGlue;
				if (stuckInGlue.m_glueFadeOutTriggered)
				{
					float num = (stuckInGlue.m_fadeOutDuration - stuckInGlue.m_fadeInDuration) * __instance.AttachedGlueRel * 1.44f;
					EnemyAppearance appearance = __instance.Owner.Appearance;
					appearance.m_lastGlueEnd = num / stuckInGlue.m_fadeOutDuration;
					appearance.SetGlueAmount(0f, num);
				}
			}
			if (SNet.IsMaster)
			{
				FoamManager.SendFoam(__instance.Owner, __instance.AttachedGlueRel);
			}
		}

		[HarmonyPatch(typeof(ES_StuckInGlue), "ActivateState")]
		[HarmonyPrefix]
		private static bool StopClientStateSwitch()
		{
			return SNet.IsMaster;
		}

		[HarmonyPatch(typeof(ES_StuckInGlue), "DoStartStuckInGlue")]
		[HarmonyPostfix]
		private static void FixFadeOutTime(ES_StuckInGlue __instance)
		{
			if (!SNet.IsMaster)
			{
				((ES_Base)__instance).m_enemyAgent.Damage.m_attachedGlueVolume = ((ES_Base)__instance).m_enemyAgent.EnemyBalancingData.GlueTolerance;
			}
			__instance.m_fadeOutTimer = __instance.m_fadeInTimer + (__instance.m_fadeOutDuration - __instance.m_fadeInDuration) * 0.1f;
		}
	}
	[HarmonyPatch]
	internal static class EnemyMovementPatches
	{
		[CompilerGenerated]
		private sealed class <LerpPosition>d__9 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public ES_PathMove pathMove;

			public EnemyAgent enemy;

			private Vector3 <posDiff>5__2;

			private float <lastTime>5__3;

			private float <totalTime>5__4;

			private float <prevProgress>5__5;

			private EnemyLocomotion <locomotion>5__6;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_0034: 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_0040: Unknown result type (might be due to invalid IL or missing references)
				//IL_0045: Unknown result type (might be due to invalid IL or missing references)
				//IL_004a: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
				//IL_00a9: Invalid comparison between Unknown and I4
				//IL_013d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0143: Unknown result type (might be due to invalid IL or missing references)
				//IL_014a: Unknown result type (might be due to invalid IL or missing references)
				//IL_014f: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					PositionSnapshotBuffer<pES_PathMoveData> positionBuffer = pathMove.m_positionBuffer;
					pES_PathMoveData val = positionBuffer[positionBuffer.Count - 1];
					<posDiff>5__2 = val.Position - ((Agent)enemy).m_position;
					<lastTime>5__3 = Clock.Time;
					<totalTime>5__4 = 0f;
					<prevProgress>5__5 = 0f;
					<locomotion>5__6 = enemy.Locomotion;
					break;
				}
				case 1:
				{
					<>1__state = -1;
					if ((int)<locomotion>5__6.CurrentStateEnum == 2)
					{
						_smoothRoutines.Remove(((Il2CppObjectBase)enemy).Pointer);
						return false;
					}
					float time = Clock.Time;
					<totalTime>5__4 += time - <lastTime>5__3;
					<lastTime>5__3 = time;
					float num = Math.Clamp(<totalTime>5__4 / Configuration.SyncLerpTime, 0f, 1f);
					float num2 = 1f - (1f - num) * (1f - num);
					float num3 = num2 - <prevProgress>5__5;
					<prevProgress>5__5 = num2;
					UpdatePosition(enemy, pathMove, ((Agent)enemy).m_position + <posDiff>5__2 * num3);
					break;
				}
				}
				if (<totalTime>5__4 < Configuration.SyncLerpTime)
				{
					<>2__current = null;
					<>1__state = 1;
					return true;
				}
				_smoothRoutines.Remove(((Il2CppObjectBase)enemy).Pointer);
				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();
			}
		}

		private const float MinBufferTime = 0.25f;

		private static readonly Dictionary<IntPtr, float> _exitTimes = new Dictionary<IntPtr, float>();

		private static readonly Dictionary<IntPtr, Coroutine> _smoothRoutines = new Dictionary<IntPtr, Coroutine>();

		private static readonly HashSet<IntPtr> _usedFogs = new HashSet<IntPtr>();

		public static void OnCleanup()
		{
			_exitTimes.Clear();
		}

		internal static bool Pre_ChangeState(StateMachine<ES_Base> __instance, ES_Base newState)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Invalid comparison between Unknown and I4
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Invalid comparison between Unknown and I4
			if (SNet.IsMaster)
			{
				return true;
			}
			if ((int)newState.m_stateEnum != 2)
			{
				return true;
			}
			IntPtr pointer = ((Il2CppObjectBase)newState.m_enemyAgent).Pointer;
			if ((int)__instance.m_currentState.m_stateEnum == 27 && _usedFogs.Remove(pointer))
			{
				return true;
			}
			if (Clock.Time >= _exitTimes.GetValueOrDefault(pointer))
			{
				return true;
			}
			ES_PathMove val = ((Il2CppObjectBase)newState).TryCast<ES_PathMove>();
			if (val == null || val.m_positionBuffer.Count == 0)
			{
				return true;
			}
			StartUpdatePosition(((ES_Base)val).m_enemyAgent, val);
			return false;
		}

		[HarmonyPatch(typeof(EnemyAgent), "SetMaxSfxLOD")]
		[HarmonyPostfix]
		private static void Pre_Exit(EnemyAgent __instance)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: 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_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c1: 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_00fb: Unknown result type (might be due to invalid IL or missing references)
			ES_PathMoveBase pathMove = __instance.Locomotion.PathMove;
			if ((int)((ES_Base)pathMove).m_stateEnum != 2)
			{
				return;
			}
			ES_PathMove val = ((Il2CppObjectBase)pathMove).TryCast<ES_PathMove>();
			if (val == null)
			{
				return;
			}
			IntPtr pointer = ((Il2CppObjectBase)__instance).Pointer;
			if (!_exitTimes.ContainsKey(pointer))
			{
				__instance.AddOnDeadOnce(delegate
				{
					_exitTimes.Remove(pointer);
				});
			}
			_exitTimes[((Il2CppObjectBase)__instance).Pointer] = Clock.Time + 0.25f;
			if (SNet.IsMaster)
			{
				pES_PathMoveData pathMoveData = val.m_pathMoveData;
				((pCourseNode)(ref pathMoveData.CourseNode)).Set(((Agent)__instance).CourseNode);
				pathMoveData.Position = ((Agent)__instance).m_position;
				((LowResVector3_NoY)(ref pathMoveData.Movement)).Set(val.m_moveDir, 1f);
				((LowResVector3_NoY_Normalized)(ref pathMoveData.TargetLookDir)).Value = ((Agent)__instance).TargetLookDir;
				pathMoveData.Tick++;
				val.m_pathMoveData = pathMoveData;
				{
					foreach (SNet_Player fixedClient in NotifyManager.FixedClients)
					{
						val.m_pathMovePacket.Send(pathMoveData, (SNet_ChannelType)4, fixedClient);
					}
					return;
				}
			}
			if (val.m_positionBuffer.Count != 0)
			{
				StartUpdatePosition(__instance, val);
			}
		}

		private static void StartUpdatePosition(EnemyAgent enemy, ES_PathMove pathMove)
		{
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			PositionSnapshotBuffer<pES_PathMoveData> positionBuffer = pathMove.m_positionBuffer;
			pES_PathMoveData val = positionBuffer[positionBuffer.Count - 1];
			enemy.Locomotion.ForceNode(val.CourseNode);
			pathMove.m_targetPosition = val.Position;
			((Agent)enemy).TargetLookDir = ((LowResVector3_NoY_Normalized)(ref val.TargetLookDir)).Value;
			pathMove.m_moveDir = ((LowResVector3_NoY)(ref val.Movement)).Get(1f);
			if (!enemy.MovingCuller.IsShown || Configuration.SyncLerpTime <= 0f)
			{
				UpdatePosition(enemy, pathMove, val.Position);
				return;
			}
			if (_smoothRoutines.TryGetValue(((Il2CppObjectBase)enemy).Pointer, out Coroutine value))
			{
				((MonoBehaviour)enemy).StopCoroutine(value);
			}
			_smoothRoutines[((Il2CppObjectBase)enemy).Pointer] = ((MonoBehaviour)enemy).StartCoroutine(CollectionExtensions.WrapToIl2Cpp(LerpPosition(enemy, pathMove)));
		}

		private static void UpdatePosition(EnemyAgent enemy, ES_PathMove pathMove, Vector3 pos)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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)
			((Component)enemy).transform.position = pos;
			((ES_PathMoveBase)pathMove).m_lastPos = pos;
			enemy.Position = pos;
			enemy.MovingCuller.UpdatePosition(((Agent)enemy).DimensionIndex, pos);
			((C_Cullable)enemy.MovingCuller.Culler).NeedsShadowRefresh = true;
		}

		[IteratorStateMachine(typeof(<LerpPosition>d__9))]
		private static IEnumerator LerpPosition(EnemyAgent enemy, ES_PathMove pathMove)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LerpPosition>d__9(0)
			{
				enemy = enemy,
				pathMove = pathMove
			};
		}

		[HarmonyPatch(typeof(EAB_FogSphere), "DoTrigger")]
		[HarmonyPostfix]
		private static void Post_TriggerFog(EAB_FogSphere __instance)
		{
			_usedFogs.Add(((Il2CppObjectBase)((EnemyAbility)__instance).m_owner).Pointer);
		}
	}
	[HarmonyPatch]
	internal static class EnemyScreamPatches
	{
		[HarmonyPatch(typeof(ES_Scream), "Enter")]
		[HarmonyPostfix]
		private static void FixScreamReset(ES_Scream __instance)
		{
			__instance.m_hasTriggeredPropagation = false;
		}
	}
	[HarmonyPatch]
	internal static class EnemyTargetPatches
	{
		[HarmonyPatch(typeof(EnemyGroup), "RegisterMember")]
		[HarmonyPostfix]
		private static void PostEnemyRegistered(EnemyAgent enemyAgent)
		{
			EnemyAgent enemyAgent2 = enemyAgent;
			enemyAgent2.m_hasValidTarget = false;
			enemyAgent2.m_validTargetInterval = Clock.Time + Random.RandomRange(Configuration.MinWaveSleepTime, Configuration.MaxWaveSleepTime);
			TakeDamageDelegate del = null;
			del = TakeDamageDelegate.op_Implicit((Action<float, ES_HitreactType>)delegate
			{
				enemyAgent2.m_validTargetInterval = 0f;
				EnemyAgent obj2 = enemyAgent2;
				obj2.TookDamage -= del;
			});
			EnemyAgent obj = enemyAgent2;
			obj.TookDamage += del;
		}

		[HarmonyPatch(typeof(EB_InCombat_MoveToNextNode_PathOpen), "UpdateBehaviour")]
		[HarmonyPostfix]
		private static void PathfindingFix(EB_InCombat_MoveToNextNode __instance)
		{
			if (((MachineState<EB_StateBase>)(object)((MachineState<EB_StateBase>)(object)__instance).m_machine.CurrentState).ENUM_ID != 5 && ((AgentAI)((EB_StateBase)__instance).m_ai).IsTargetValid && ((AgentAI)((EB_StateBase)__instance).m_ai).Target.m_nodeDistance <= 1)
			{
				((EB_InCombat)__instance).TryUpdateNavigation((EnemyCourseNavigationMode)1);
			}
		}

		[HarmonyPatch(typeof(EB_InCombat_MoveToNextNode_DestroyDoor), "UpdateBehaviour")]
		[HarmonyPrefix]
		private static void RemoteDoorFix(EB_InCombat_MoveToNextNode_DestroyDoor __instance, ref IntPtr __state)
		{
			EnemyCourseNavigation courseNavigation = ((EB_StateBase)__instance).m_ai.m_courseNavigation;
			__state = (courseNavigation.IsPathBlocked ? ((Il2CppObjectBase)courseNavigation.m_navPortal).Pointer : IntPtr.Zero);
		}

		[HarmonyPatch(typeof(EB_InCombat_MoveToNextNode_DestroyDoor), "UpdateBehaviour")]
		[HarmonyPostfix]
		private static void RemoteDoorFixPost(EB_InCombat_MoveToNextNode_DestroyDoor __instance, IntPtr __state)
		{
			if (!(__state == IntPtr.Zero))
			{
				EnemyCourseNavigation courseNavigation = ((EB_StateBase)__instance).m_ai.m_courseNavigation;
				if (courseNavigation.IsPathBlocked && ((Il2CppObjectBase)courseNavigation.m_navPortal).Pointer != __state)
				{
					((MachineState<EB_StateBase>)(object)__instance).m_machine.ChangeState((byte)9);
				}
			}
		}
	}
	[HarmonyPatch]
	internal static class NetworkingPatches
	{
		[HarmonyPatch(typeof(SNet_SyncManager), "OnFoundMaster")]
		[HarmonyPatch(typeof(SNet_SyncManager), "OnFoundNewMasterDuringMigration")]
		[HarmonyPostfix]
		private static void Post_Joined()
		{
			if (!SNet.IsMaster)
			{
				NotifyManager.SendNotify(SNet.Master);
			}
			else
			{
				NotifyManager.SetMaster();
			}
		}

		[HarmonyPatch(typeof(SNet_SyncManager), "OnPlayerJoinedSessionHub")]
		[HarmonyPostfix]
		private static void Post_Joined(SNet_Player player)
		{
			if (SNet.IsMaster && !player.IsLocal)
			{
				NotifyManager.SendNotify(player);
			}
		}

		[HarmonyPatch(typeof(SNet_SessionHub), "OnLeftLobby")]
		[HarmonyPatch(typeof(SNet_SessionHub), "RemovePlayerFromSession")]
		[HarmonyPrefix]
		private static void Pre_Eject(SNet_Player player)
		{
			if (SNet.IsMaster)
			{
				NotifyManager.RemoveClient(player);
			}
		}

		[HarmonyPatch(typeof(SNet_SyncManager), "OnResetSession")]
		[HarmonyPrefix]
		private static void Pre_OnReset()
		{
			NotifyManager.Reset();
		}
	}
}
namespace EnemyAnimationFix.Networking
{
	public abstract class SyncedEvent<T> where T : struct
	{
		public delegate void ReceiveHandler(T packet);

		private bool _isSetup;

		public abstract string GUID { get; }

		public bool IsSetup => _isSetup;

		public string EventName { get; private set; } = string.Empty;


		public event ReceiveHandler? OnReceive;

		public event ReceiveHandler? OnReceiveLocal;

		public void Setup()
		{
			if (!_isSetup)
			{
				EventName = "EAF" + GUID;
				NetworkAPI.RegisterEvent<T>(EventName, (Action<ulong, T>)ReceiveClient_Callback);
				_isSetup = true;
			}
		}

		public void Send(T packetData, SNet_Player? target = null, SNet_ChannelType priority = 4)
		{
			//IL_0020: 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 ((Object)(object)target != (Object)null)
			{
				NetworkAPI.InvokeEvent<T>(EventName, packetData, target, priority);
			}
			else
			{
				NetworkAPI.InvokeEvent<T>(EventName, packetData, priority);
			}
			ReceiveLocal_Callback(packetData);
		}

		private void ReceiveLocal_Callback(T packet)
		{
			ReceiveLocal(packet);
			this.OnReceiveLocal?.Invoke(packet);
		}

		private void ReceiveClient_Callback(ulong sender, T packet)
		{
			Receive(packet);
			this.OnReceive?.Invoke(packet);
		}

		protected virtual void ReceiveLocal(T packet)
		{
		}

		protected virtual void Receive(T packet)
		{
		}
	}
}
namespace EnemyAnimationFix.Networking.Notify
{
	internal static class NotifyManager
	{
		private static readonly NotifySync _sync = new NotifySync();

		public static readonly List<SNet_Player> FixedClients = new List<SNet_Player>();

		public static bool MasterHasFix { get; private set; } = false;


		internal static void Init()
		{
			_sync.Setup();
		}

		internal static void SendNotify(SNet_Player player)
		{
			_sync.Send(new NotifyData
			{
				lookup = SNet.LocalPlayer.Lookup
			}, player, (SNet_ChannelType)0);
		}

		internal static void ReceiveNotify(SNet_Player player)
		{
			if (SNet.IsMaster)
			{
				FixedClients.Add(player);
			}
			else
			{
				MasterHasFix = true;
			}
		}

		internal static void SetMaster()
		{
			MasterHasFix = true;
		}

		internal static void Reset()
		{
			MasterHasFix = false;
			FixedClients.Clear();
		}

		internal static void RemoveClient(SNet_Player player)
		{
			for (int num = FixedClients.Count - 1; num >= 0; num--)
			{
				if ((Object)(object)FixedClients[num] == (Object)null || FixedClients[num].Lookup == player.Lookup)
				{
					FixedClients.RemoveAt(num);
				}
			}
		}
	}
	internal sealed class NotifySync : SyncedEvent<NotifyData>
	{
		public override string GUID => "NOTIF";

		protected override void Receive(NotifyData packet)
		{
			SNet_Player player = default(SNet_Player);
			if (SNet.TryGetPlayer(packet.lookup, ref player))
			{
				NotifyManager.ReceiveNotify(player);
			}
		}
	}
	public struct NotifyData
	{
		public ulong lookup;
	}
}
namespace EnemyAnimationFix.Networking.Foam
{
	internal static class FoamManager
	{
		private static readonly FoamSync _sync = new FoamSync();

		internal static void Init()
		{
			_sync.Setup();
		}

		internal static void SendFoam(EnemyAgent enemy, float foamRel)
		{
			FoamData packetData = default(FoamData);
			((pEnemyAgent)(ref packetData.enemy)).Set(enemy);
			((UFloat16)(ref packetData.foamRel)).Set(foamRel, 1f);
			foreach (SNet_Player fixedClient in NotifyManager.FixedClients)
			{
				_sync.Send(packetData, fixedClient, (SNet_ChannelType)4);
			}
		}

		internal static void ReceiveFoam(EnemyAgent enemy, float foamRel)
		{
			enemy.Damage.m_attachedGlueVolume = foamRel * enemy.EnemyBalancingData.GlueTolerance;
		}
	}
	internal sealed class FoamSync : SyncedEvent<FoamData>
	{
		public override string GUID => "FOAM";

		protected override void Receive(FoamData packet)
		{
			EnemyAgent enemy = default(EnemyAgent);
			if (((pEnemyAgent)(ref packet.enemy)).TryGet(ref enemy))
			{
				FoamManager.ReceiveFoam(enemy, ((UFloat16)(ref packet.foamRel)).Get(1f));
			}
		}
	}
	public struct FoamData
	{
		public pEnemyAgent enemy;

		public UFloat16 foamRel;
	}
}
namespace EnemyAnimationFix.NativePatches
{
	internal static class ChangeStatePatches
	{
		private unsafe delegate void d_ChangeStateFromQueue(IntPtr _this, Il2CppMethodInfo* methodInfo);

		private static INativeDetour? ChangeStateDetour;

		private static d_ChangeStateFromQueue? orig_ChangeStateFromQueue;

		internal unsafe static void ApplyNativePatch()
		{
			NativePatchAPI.AddChangeStatePrefix(FixMeleeCancel);
			NativePatchAPI.AddChangeStatePrefix(EnemyMovementPatches.Pre_ChangeState);
			INativeClassStruct val = UnityVersionHandler.Wrap((Il2CppClass*)(void*)Il2CppClassPointerStore<StateMachine<ES_Base>>.NativeClassPtr);
			for (int i = 0; i < val.MethodCount; i++)
			{
				INativeMethodInfoStruct val2 = UnityVersionHandler.Wrap(val.Methods[i]);
				if (Marshal.PtrToStringAnsi(val2.Name) == "ChangeStateFromQueue")
				{
					ChangeStateDetour = INativeDetour.CreateAndApply<d_ChangeStateFromQueue>(val2.MethodPointer, (d_ChangeStateFromQueue)ChangeStatePatch, ref orig_ChangeStateFromQueue);
					break;
				}
			}
		}

		private unsafe static void ChangeStatePatch(IntPtr _this, Il2CppMethodInfo* methodInfo)
		{
			StateMachine<ES_Base> val = new StateMachine<ES_Base>(_this);
			if (val.CurrentState == null)
			{
				orig_ChangeStateFromQueue(_this, methodInfo);
				return;
			}
			ES_Base state = val.m_stateQueue.Peek();
			bool flag = true;
			try
			{
				flag = NativePatchAPI.RunChangeStatePrefix(val, state);
			}
			catch (Exception ex)
			{
				DinoLogger.Error("Error running ChangeStatePrefix: " + ex.StackTrace);
			}
			if (flag)
			{
				orig_ChangeStateFromQueue(_this, methodInfo);
			}
			else
			{
				val.m_stateQueue.Dequeue();
			}
			try
			{
				NativePatchAPI.RunChangeStatePostfix(val, state);
			}
			catch (Exception ex2)
			{
				DinoLogger.Error("Error running ChangeStatePostfix: " + ex2.StackTrace);
			}
		}

		private static bool FixMeleeCancel(StateMachine<ES_Base> __instance, ES_Base newState)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			ES_Base currentState = __instance.CurrentState;
			if (__instance.CurrentState == null || !NotifyManager.MasterHasFix || (int)newState.m_stateEnum != 2 || (int)currentState.m_stateEnum != 23)
			{
				return true;
			}
			ES_StrikerMelee val = ((Il2CppObjectBase)currentState).Cast<ES_StrikerMelee>();
			return (Clock.Time - val.m_startTime) * val.m_animSpeed >= val.m_attackData.Duration;
		}
	}
	internal static class ValidTargetPatches
	{
		private const int NOP = 144;

		private const int AddssLen = 8;

		public unsafe static void ApplyInstructionPatch()
		{
			INativeClassStruct val = UnityVersionHandler.Wrap((Il2CppClass*)(void*)Il2CppClassPointerStore<EnemyAgent>.NativeClassPtr);
			for (int i = 0; i < val.MethodCount; i++)
			{
				INativeMethodInfoStruct val2 = UnityVersionHandler.Wrap(val.Methods[i]);
				if (!(Marshal.PtrToStringAnsi(val2.Name) == "HasValidTarget"))
				{
					continue;
				}
				IntPtr intPtr = FindAdd(val2.MethodPointer);
				if (intPtr == IntPtr.Zero)
				{
					DinoLogger.Error("Unable to find instruction in HasValidTarget. Not applying fix for enemies stuck on spawning.");
					break;
				}
				using (new MemoryProtectionCookie(intPtr, Kernel32.MemoryProtectionConstant.ExecuteReadWrite, new IntPtr(16)))
				{
					for (int j = 0; j < 8; j++)
					{
						*(sbyte*)((long)intPtr + (long)new IntPtr(j)) = -112;
					}
					break;
				}
			}
		}

		private unsafe static IntPtr FindAdd(IntPtr methodPointer)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Invalid comparison between Unknown and I4
			StreamCodeReader val = new StreamCodeReader((Stream)new UnmanagedMemoryStream((byte*)(void*)methodPointer, 65536L, 65536L, FileAccess.Read));
			Decoder val2 = Decoder.Create(sizeof(void*) * 8, (CodeReader)(object)val, (DecoderOptions)0);
			val2.IP = (ulong)(long)methodPointer;
			Instruction val3 = default(Instruction);
			val2.Decode(ref val3);
			while ((int)((Instruction)(ref val3)).Mnemonic != 1620)
			{
				if ((int)((Instruction)(ref val3)).Mnemonic == 11)
				{
					val.Stream.Close();
					if (((Instruction)(ref val3)).NextIP - ((Instruction)(ref val3)).IP != 8)
					{
						DinoLogger.Error("EnemyAnimationFix found an instruction with an unexpected width.");
						return IntPtr.Zero;
					}
					return (IntPtr)(long)((Instruction)(ref val3)).IP;
				}
				val2.Decode(ref val3);
			}
			val.Stream.Close();
			return IntPtr.Zero;
		}
	}
}
namespace EnemyAnimationFix.NativePatches.KernelTools
{
	internal static class Kernel32
	{
		[Flags]
		public enum MemoryAllocationConstant : uint
		{
			Commit = 0x1000u,
			Reserve = 0x2000u,
			Reset = 0x80000u,
			ResetUndo = 0x1000000u,
			LargePages = 0x20000000u,
			Physical = 0x400000u,
			TopDown = 0x100000u,
			WriteWatch = 0x200000u
		}

		[Flags]
		public enum MemoryProtectionConstant : uint
		{
			NoAccess = 1u,
			ReadOnly = 2u,
			ReadWrite = 4u,
			WriteCopy = 8u,
			Execute = 0x10u,
			ExecuteRead = 0x20u,
			ExecuteReadWrite = 0x40u,
			ExecuteWriteCopy = 0x80u
		}

		[DllImport("kernel32.dll")]
		public static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, MemoryAllocationConstant flAllocationType, MemoryProtectionConstant flProtect);

		[DllImport("kernel32.dll")]
		public static extern bool VirtualProtect(IntPtr lpAddress, IntPtr dwSize, MemoryProtectionConstant flNewProtect, out MemoryProtectionConstant lpflOldProtect);
	}
	internal struct MemoryProtectionCookie : IDisposable
	{
		private Kernel32.MemoryProtectionConstant m_OldProtection;

		private readonly IntPtr m_Address;

		private readonly IntPtr m_Size;

		public MemoryProtectionCookie(IntPtr address, Kernel32.MemoryProtectionConstant newProtection, IntPtr size)
		{
			m_Address = address;
			m_Size = size;
			if (!Kernel32.VirtualProtect(m_Address, m_Size, newProtection, out m_OldProtection))
			{
				Environment.FailFast($"Failed to protect address 0x{m_Address:X2} with protection {newProtection}");
			}
		}

		public void Dispose()
		{
			if (!Kernel32.VirtualProtect(m_Address, m_Size, m_OldProtection, out m_OldProtection))
			{
				Environment.FailFast($"Failed to revert memory protection of address 0x{m_Address:X2}");
			}
		}
	}
}
namespace EnemyAnimationFix.API
{
	public static class NativePatchAPI
	{
		public delegate bool ChangeStatePrefix(StateMachine<ES_Base> __instance, ES_Base state);

		public delegate void ChangeStatePostfix(StateMachine<ES_Base> __instance, ES_Base state);

		private static readonly List<ChangeStatePrefix> s_changePrefix = new List<ChangeStatePrefix>();

		private static readonly List<ChangeStatePostfix> s_changePostfix = new List<ChangeStatePostfix>();

		public static void AddChangeStatePrefix(ChangeStatePrefix detectPrefix)
		{
			s_changePrefix.Add(detectPrefix);
		}

		public static void AddChangeStatePostfix(ChangeStatePostfix detectPostfix)
		{
			s_changePostfix.Add(detectPostfix);
		}

		internal static bool RunChangeStatePrefix(StateMachine<ES_Base> __instance, ES_Base state)
		{
			bool flag = true;
			foreach (ChangeStatePrefix item in s_changePrefix)
			{
				flag &= item(__instance, state);
			}
			return flag;
		}

		internal static void RunChangeStatePostfix(StateMachine<ES_Base> __instance, ES_Base state)
		{
			foreach (ChangeStatePostfix item in s_changePostfix)
			{
				item(__instance, state);
			}
		}
	}
}