using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
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 Enemies;
using EnemyAnimationFix.API;
using EnemyAnimationFix.NativePatches;
using EnemyAnimationFix.NativePatches.KernelTools;
using EnemyAnimationFix.Networking.Notify;
using EnemyAnimationFix.Patches;
using EnemyAnimationFix.Utils;
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 Microsoft.CodeAnalysis;
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+8e12286379bdd7715aa435dc5f64c49f86f6b525")]
[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 ConfigFile configFile;
public static float MinWaveSleepTime { get; private set; }
public static float MaxWaveSleepTime { get; private set; }
public static event Action? OnReload;
static Configuration()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
MinWaveSleepTime = 0f;
MaxWaveSleepTime = 6f;
configFile = new ConfigFile(Path.Combine(Paths.ConfigPath, "EnemyAnimationFix.cfg"), true);
BindAll(configFile);
}
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();
string text = "Wave Settings";
MinWaveSleepTime = (float)configFile[text, "Minimum Wave Inactive Time"].BoxedValue;
MaxWaveSleepTime = (float)configFile[text, "Maximum Wave Inactive Time"].BoxedValue;
Configuration.OnReload?.Invoke();
}
private static void BindAll(ConfigFile config)
{
string text = "Wave Settings";
string text2 = "Minimum amount of time in seconds before enemies become active after spawning.";
MinWaveSleepTime = config.Bind<float>(text, "Minimum Wave Inactive Time", MinWaveSleepTime, text2).Value;
text2 = "Maximum amount of time in seconds before enemies become active after spawning.";
MaxWaveSleepTime = config.Bind<float>(text, "Maximum Wave Inactive Time", MaxWaveSleepTime, text2).Value;
}
}
[BepInPlugin("Dinorush.EnemyAnimationFix", "EnemyAnimationFix", "1.2.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal sealed class EntryPoint : BasePlugin
{
public const string MODNAME = "EnemyAnimationFix";
public override void Load()
{
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
((BasePlugin)this).Log.LogMessage((object)"Loading EnemyAnimationFix");
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();
}
private void LevelAPI_OnLevelCleanup()
{
EB_InCombat.s_globalScreamTimer = 0f;
}
}
}
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.Patches
{
[HarmonyPatch]
internal static class EnemyAttackPatches
{
[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)
EnemyAbility ability = abilities.GetAbility(abilityType, 0);
if ((Object)(object)ability == (Object)null)
{
return false;
}
EAB_MovingEnemyTentacleMultiple val = ((Il2CppObjectBase)ability).TryCast<EAB_MovingEnemyTentacleMultiple>();
if ((Object)(object)val == (Object)null)
{
return false;
}
foreach (MovingEnemyTentacleBase item in (Il2CppArrayBase<MovingEnemyTentacleBase>)(object)val.m_tentacles)
{
if (item.m_currentRoutine != null)
{
item.SwitchCoroutine(item.AttackIn(item.m_attackInDuration));
}
}
return true;
}
[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 static class EnemyGluePatches
{
[HarmonyPatch(typeof(Dam_EnemyDamageBase), "AddToTotalGlueVolume")]
[HarmonyPostfix]
private static void SyncGlueData(Dam_EnemyDamageBase __instance, GlueGunProjectile? proj, GlueVolumeDesc volume)
{
//IL_000a: 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_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
if (SNet.IsMaster)
{
pMiniDamageData val = default(pMiniDamageData);
float num = (((Object)(object)proj != (Object)null) ? proj.EffectMultiplier : 1f);
((UFloat16)(ref val.damage)).Set((volume.volume + volume.expandVolume) * num, 100f);
((Dam_SyncedDamageBase)__instance).m_glueDamagePacket.Send(val, (SNet_ChannelType)4);
}
}
[HarmonyPatch(typeof(ES_StuckInGlue), "ActivateState")]
[HarmonyPrefix]
private static bool StopClientStateSwitch()
{
return SNet.IsMaster;
}
}
[HarmonyPatch]
internal static class EnemyMovementPatches
{
private const float MinBufferTime = 0.1f;
private static float _exitTime;
private static bool _hasExited;
internal static bool Pre_ChangeState(StateMachine<ES_Base> _, ES_Base newState)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Invalid comparison between Unknown and I4
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
bool hasExited = _hasExited;
_hasExited = false;
if (SNet.IsMaster || (int)newState.m_stateEnum != 2 || Clock.Time - _exitTime > 0.1f)
{
return true;
}
ES_PathMove val = ((Il2CppObjectBase)newState).TryCast<ES_PathMove>();
if (val == null || val.m_positionBuffer.Count == 0)
{
return true;
}
if (!hasExited)
{
return true;
}
EnemyAgent enemyAgent = ((ES_Base)val).m_enemyAgent;
PositionSnapshotBuffer<pES_PathMoveData> positionBuffer = val.m_positionBuffer;
ForcePosition(enemyAgent, val, positionBuffer[positionBuffer.Count - 1]);
return false;
}
[HarmonyPatch(typeof(ES_PathMove), "Exit")]
[HarmonyPrefix]
private static void Pre_Exit(ES_PathMove __instance)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
_hasExited = true;
_exitTime = Clock.Time;
EnemyAgent enemyAgent = ((ES_Base)__instance).m_enemyAgent;
pES_PathMoveData val;
if (SNet.IsMaster)
{
val = __instance.m_pathMoveData;
((pCourseNode)(ref val.CourseNode)).Set(((Agent)enemyAgent).CourseNode);
val.Position = enemyAgent.Position;
((LowResVector3_NoY)(ref val.Movement)).Set(__instance.m_moveDir, 1f);
((LowResVector3_NoY_Normalized)(ref val.TargetLookDir)).Value = ((Agent)enemyAgent).TargetLookDir;
val.Tick++;
__instance.m_pathMoveData = val;
{
foreach (SNet_Player fixedClient in NotifyManager.FixedClients)
{
__instance.m_pathMovePacket.Send(val, (SNet_ChannelType)4, fixedClient);
}
return;
}
}
if (__instance.m_positionBuffer.Count != 0)
{
PositionSnapshotBuffer<pES_PathMoveData> positionBuffer = __instance.m_positionBuffer;
val = positionBuffer[positionBuffer.Count - 1];
ForcePosition(enemyAgent, __instance, val);
}
}
private static void ForcePosition(EnemyAgent enemy, ES_PathMove pathMove, pES_PathMoveData data)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_0035: 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_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: Unknown result type (might be due to invalid IL or missing references)
((Component)enemy).transform.position = enemy.Position;
enemy.MovingCuller.UpdatePosition(((Agent)enemy).DimensionIndex, enemy.Position);
enemy.Position = data.Position;
((ES_PathMoveBase)pathMove).m_lastPos = data.Position;
enemy.Locomotion.ForceNode(data.CourseNode);
pathMove.m_targetPosition = data.Position;
pathMove.m_moveDir = ((LowResVector3_NoY)(ref data.Movement)).Get(1f);
((Agent)enemy).TargetLookDir = ((LowResVector3_NoY_Normalized)(ref data.TargetLookDir)).Value;
((ES_PathMoveBase)pathMove).UpdateRotation();
((ES_PathMoveBase)pathMove).UpdateLocalAnimator();
pathMove.UpdateAnimationBlend(((ES_PathMoveBase)pathMove).m_animFwd, ((ES_PathMoveBase)pathMove).m_animRight, false);
}
}
[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.m_hasValidTarget = false;
enemyAgent.m_validTargetInterval = Clock.Time + Random.RandomRange(Configuration.MinWaveSleepTime, Configuration.MaxWaveSleepTime);
}
}
[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 = "EWC" + 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)4);
}
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 => "EAFNF";
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.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();
if (NativePatchAPI.RunChangeStatePrefix(val, state))
{
orig_ChangeStateFromQueue(_this, methodInfo);
}
else
{
val.m_stateQueue.Dequeue();
}
NativePatchAPI.RunChangeStatePostfix(val, state);
}
private static bool FixMeleeCancel(StateMachine<ES_Base> __instance, ES_Base newState)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Invalid comparison between Unknown and I4
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Invalid comparison between Unknown and I4
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
ES_Base currentState = __instance.CurrentState;
if (!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_0089: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: 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)
{
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.Dispose();
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);
}
}
}
}