Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AttackCancel v1.27.0
BepInEx/plugins/AttackCancel/AttackCancel.dll
Decompiled a week agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("AttackCancel")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AttackCancel")] [assembly: AssemblyTitle("AttackCancel")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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; } } [CompilerGenerated] [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; } } } [BepInPlugin("IDRdh7", "Attack Cancel/Counter", "1.27.0")] public class AttackCancel : BaseUnityPlugin { private static AttackCancel Instance; private ConfigEntry<bool> modEnabled; private ConfigEntry<bool> debugMessages; private static FieldInfo CurrentAttack; private static FieldInfo CurrentAttackIsSecondary; private static FieldInfo BlockingField; private static MethodInfo AttackAbort; private static MethodInfo AttackStop; private static bool suppressPlayerInAttack; private static bool forceBlockState; private void Awake() { //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Expected O, but got Unknown //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Expected O, but got Unknown Instance = this; modEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Mod Enabled", true, "Enable or disable instant attack cancellation."); debugMessages = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Debug Messages", false, "Enable debug log messages."); CurrentAttack = AccessTools.Field(typeof(Humanoid), "m_currentAttack"); CurrentAttackIsSecondary = AccessTools.Field(typeof(Humanoid), "m_currentAttackIsSecondary"); BlockingField = AccessTools.Field(typeof(Character), "m_blocking"); if (CurrentAttack != null) { Type fieldType = CurrentAttack.FieldType; AttackAbort = AccessTools.Method(fieldType, "Abort", (Type[])null, (Type[])null); AttackStop = AccessTools.Method(fieldType, "Stop", (Type[])null, (Type[])null); } Harmony val = new Harmony("IDRdh7.AttackCancel"); MethodInfo methodInfo = AccessTools.Method(typeof(Player), "SetControls", new Type[12] { typeof(Vector3), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo != null) { val.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(AttackCancel), "SetControlsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Attack Cancel] Patched Player.SetControls"); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"[Attack Cancel] Player.SetControls not found"); } MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "InAttack", (Type[])null, (Type[])null); if (methodInfo2 != null) { val.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(AttackCancel), "PlayerInAttackPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Attack Cancel] Patched Player.InAttack"); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"[Attack Cancel] Player.InAttack not found"); } MethodInfo methodInfo3 = AccessTools.Method(typeof(Humanoid), "IsBlocking", (Type[])null, (Type[])null); if (methodInfo3 != null) { val.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(AttackCancel), "IsBlockingPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Attack Cancel] Patched Humanoid.IsBlocking"); } else { ((BaseUnityPlugin)this).Logger.LogError((object)"[Attack Cancel] Humanoid.IsBlocking not found"); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"[Attack Cancel] Loaded 1.27.0"); } private void Update() { if (!modEnabled.Value) { suppressPlayerInAttack = false; forceBlockState = false; } } private static object GetCurrentAttack(Player player) { if (CurrentAttack == null || (Object)(object)player == (Object)null) { return null; } return CurrentAttack.GetValue(player); } private static void ClearAttackReference(Player player) { if (CurrentAttack != null) { CurrentAttack.SetValue(player, null); } if (CurrentAttackIsSecondary != null) { CurrentAttackIsSecondary.SetValue(player, false); } } private static void CancelBlock(Player player) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) object currentAttack = GetCurrentAttack(player); if (currentAttack == null) { return; } try { if (AttackStop != null) { AttackStop.Invoke(currentAttack, null); } else if (AttackAbort != null) { AttackAbort.Invoke(currentAttack, null); } ClearAttackReference(player); suppressPlayerInAttack = true; forceBlockState = true; ((Character)player).ForceJump(new Vector3(0f, -20f, 0f), true); if (Instance.debugMessages.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[Attack Cancel] BLOCK CANCEL | Stop + ForceJump | no manual block trigger"); } } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("[Attack Cancel] Block cancel failed: " + ex)); suppressPlayerInAttack = false; forceBlockState = false; } } private static void CancelDodge(Player player) { object currentAttack = GetCurrentAttack(player); if (currentAttack == null) { return; } try { if (AttackAbort != null) { AttackAbort.Invoke(currentAttack, null); } ClearAttackReference(player); suppressPlayerInAttack = true; if (Instance.debugMessages.Value) { ((BaseUnityPlugin)Instance).Logger.LogInfo((object)"[Attack Cancel] DODGE CANCEL | Abort"); } } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("[Attack Cancel] Dodge cancel failed: " + ex)); } } public static void SetControlsPrefix(Player __instance, ref Vector3 movedir, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold, ref bool block, ref bool blockHold, ref bool jump, ref bool crouch, ref bool run, ref bool autoRun, ref bool dodge) { if ((Object)(object)Instance == (Object)null || !Instance.modEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } if (attack | secondaryAttack) { suppressPlayerInAttack = false; forceBlockState = false; } else if (!blockHold) { suppressPlayerInAttack = false; forceBlockState = false; } else if (GetCurrentAttack(__instance) != null) { if (jump) { CancelDodge(__instance); } else { CancelBlock(__instance); } } } public static bool PlayerInAttackPrefix(Player __instance, ref bool __result) { if ((Object)(object)Instance == (Object)null || !Instance.modEnabled.Value || !suppressPlayerInAttack || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } __result = false; return false; } public static bool IsBlockingPrefix(Humanoid __instance, ref bool __result) { if ((Object)(object)Instance == (Object)null || !Instance.modEnabled.Value || !forceBlockState || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } bool flag = false; if (BlockingField != null) { object value = BlockingField.GetValue(__instance); if (value is bool) { flag = (bool)value; } } if (!flag) { return true; } __result = true; return false; } }