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 DodgeCancel v0.2.2
DodgeCancel.dll
Decompiled a week agousing System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] namespace DodgeCancel; [BepInPlugin("com.burks.dodgecancel", "Dodge Cancel", "0.2.2")] public class DodgeCancelPlugin : BaseUnityPlugin { public const string GUID = "com.burks.dodgecancel"; public const string NAME = "Dodge Cancel"; public const string VERSION = "0.2.2"; public static ManualLogSource Log; public static ConfigEntry<bool> Enabled; public static ConfigEntry<bool> OnlyBeforeHit; public static ConfigEntry<bool> BlockCancel; public static ConfigEntry<float> ExtraStamina; private bool _on; private void Awake() { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Invalid comparison between Unknown and I4 //IL_009d: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Dodge rolling during an attack cancels the attack."); BlockCancel = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BlockCancels", true, "Pressing block during an attack also cancels the attack and raises your guard. Only a fresh press counts: holding block before you swing does not cancel the swing."); OnlyBeforeHit = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "OnlyBeforeTheHit", false, "true = you can only cancel during the wind-up, before the swing connects. false = any time during the attack."); ExtraStamina = ((BaseUnityPlugin)this).Config.Bind<float>("General", "ExtraStaminaCost", 0f, "Extra stamina a cancelling roll costs, on top of the normal roll."); if ((int)SystemInfo.graphicsDeviceType != 4) { new Harmony("com.burks.dodgecancel").PatchAll(Assembly.GetExecutingAssembly()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Dodge Cancel 0.2.2 loaded."); _on = true; } } private void Update() { if (_on) { try { Patches.Tick(); } catch (Exception) { } } } private void LateUpdate() { if (_on) { try { Patches.Tick(); } catch (Exception) { } } } } [HarmonyPatch] public static class Patches { private static readonly FieldRef<Player, float> QueuedDodge = AccessTools.FieldRefAccess<Player, float>("m_queuedDodgeTimer"); private static readonly FieldRef<Humanoid, Attack> CurrentAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_currentAttack"); private static readonly MethodInfo DodgeCost = AccessTools.Method(typeof(Player), "GetDodgeStaminaUse", (Type[])null, (Type[])null); private static bool _bypass; private static Attack _landed; private static bool _warned; private static readonly FieldRef<Character, bool> Blocking = AccessTools.FieldRefAccess<Character, bool>("m_blocking"); private static readonly FieldRef<Character, ZSyncAnimation> Zanim = AccessTools.FieldRefAccess<Character, ZSyncAnimation>("m_zanim"); private static readonly MethodInfo Blocker = AccessTools.Method(typeof(Humanoid), "GetCurrentBlocker", (Type[])null, (Type[])null); private static bool _raw; private static bool _wasBlocking; private static float _guardUntil; private static readonly FieldRef<Character, Animator> Anim = AccessTools.FieldRefAccess<Character, Animator>("m_animator"); private static readonly FieldRef<CharacterAnimEvent, Animator> EventAnim = AccessTools.FieldRefAccess<CharacterAnimEvent, Animator>("m_animator"); public static bool FastForwarding => _guardUntil > Time.time; [HarmonyPatch(typeof(Player), "UpdateDodge")] [HarmonyPrefix] public static void UpdateDodge_Prefix(Player __instance) { _bypass = false; try { if (!DodgeCancelPlugin.Enabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || QueuedDodge.Invoke(__instance) <= 0f || !((Character)__instance).InAttack() || !((Character)__instance).IsOnGround() || ((Character)__instance).IsDead() || ((Character)__instance).IsEncumbered() || ((Character)__instance).InDodge() || ((Character)__instance).IsStaggering()) { return; } Attack val = CurrentAttack.Invoke((Humanoid)(object)__instance); if (DodgeCancelPlugin.OnlyBeforeHit.Value && val != null && val == _landed) { return; } float num = Mathf.Max(0f, DodgeCancelPlugin.ExtraStamina.Value); float num2 = (float)DodgeCost.Invoke(__instance, null) + num; if (((Character)__instance).HaveStamina(num2)) { if (val != null) { val.Stop(); CurrentAttack.Invoke((Humanoid)(object)__instance) = null; } if (num > 0f) { ((Character)__instance).UseStamina(num); } _bypass = true; } } catch (Exception ex) { _bypass = false; if (!_warned) { _warned = true; DodgeCancelPlugin.Log.LogWarning((object)("Dodge cancel failed: " + ex)); } } } [HarmonyPatch(typeof(Player), "UpdateDodge")] [HarmonyFinalizer] public static void UpdateDodge_Finalizer() { _bypass = false; } [HarmonyPatch(typeof(Player), "InAttack")] [HarmonyPrefix] public static bool InAttack_Prefix(Player __instance, ref bool __result) { if (_raw || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return true; } if (!_bypass && Time.time >= _guardUntil) { return true; } __result = false; return false; } private static bool ReallyAttacking(Player p) { _raw = true; try { return ((Character)p).InAttack(); } finally { _raw = false; } } [HarmonyPatch(typeof(Humanoid), "UpdateBlock")] [HarmonyPrefix] public static void UpdateBlock_Prefix(Humanoid __instance) { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)__instance != (Object)(object)localPlayer) { return; } bool num = Blocking.Invoke((Character)(object)localPlayer); bool flag = num && !_wasBlocking; _wasBlocking = num; bool flag2 = ReallyAttacking(localPlayer); if (_guardUntil > Time.time && !flag2) { EndFastForward(localPlayer); } if (!flag || !flag2 || _guardUntil > Time.time || !DodgeCancelPlugin.Enabled.Value || !DodgeCancelPlugin.BlockCancel.Value || ((Character)localPlayer).IsDead() || ((Character)localPlayer).InDodge() || ((Character)localPlayer).IsStaggering() || ((Character)localPlayer).IsEncumbered() || ((Character)localPlayer).InPlaceMode() || Blocker.Invoke(localPlayer, null) == null) { return; } Attack val = CurrentAttack.Invoke((Humanoid)(object)localPlayer); if (DodgeCancelPlugin.OnlyBeforeHit.Value && val != null && val == _landed) { return; } float num2 = Mathf.Max(0f, DodgeCancelPlugin.ExtraStamina.Value); if (num2 > 0f) { if (!((Character)localPlayer).HaveStamina(num2)) { return; } ((Character)localPlayer).UseStamina(num2); } if (val != null) { val.Stop(); CurrentAttack.Invoke((Humanoid)(object)localPlayer) = null; } _guardUntil = Time.time + 2f; FastForward(localPlayer); } catch (Exception ex) { _guardUntil = 0f; if (!_warned) { _warned = true; DodgeCancelPlugin.Log.LogWarning((object)("Block cancel failed: " + ex)); } } } public static void FastForward(Player me) { Animator val = (((Object)(object)me != (Object)null) ? Anim.Invoke((Character)(object)me) : null); if ((Object)(object)val != (Object)null && FastForwarding) { val.speed = 25f; } } private static void EndFastForward(Player me) { _guardUntil = 0f; Animator val = (((Object)(object)me != (Object)null) ? Anim.Invoke((Character)(object)me) : null); if ((Object)(object)val != (Object)null) { val.speed = 1f; } } public static void Tick() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { _guardUntil = 0f; } else if (!(_guardUntil <= 0f)) { if (_guardUntil <= Time.time || !ReallyAttacking(localPlayer)) { EndFastForward(localPlayer); } else { FastForward(localPlayer); } } } [HarmonyPatch(typeof(CharacterAnimEvent), "OnAnimatorMove")] [HarmonyPrefix] public static bool OnAnimatorMove_Prefix(CharacterAnimEvent __instance) { if (!FastForwarding || (Object)(object)Player.m_localPlayer == (Object)null) { return true; } try { return (Object)(object)EventAnim.Invoke(__instance) != (Object)(object)Anim.Invoke((Character)(object)Player.m_localPlayer); } catch { return true; } } [HarmonyPatch(typeof(CharacterAnimEvent), "CustomFixedUpdate")] [HarmonyPostfix] public static void AnimFixedUpdate_Postfix(CharacterAnimEvent __instance) { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !FastForwarding) { return; } Animator val = Anim.Invoke((Character)(object)localPlayer); if (!((Object)(object)val == (Object)null) && !((Object)(object)EventAnim.Invoke(__instance) != (Object)(object)val)) { if (ReallyAttacking(localPlayer)) { val.speed = 25f; } else { EndFastForward(localPlayer); } } } catch { } } [HarmonyPatch(typeof(CharacterAnimEvent), "Speed")] [HarmonyPrefix] public static bool Speed_Prefix(CharacterAnimEvent __instance) { return OnAnimatorMove_Prefix(__instance); } [HarmonyPatch(typeof(CharacterAnimEvent), "FreezeFrame")] [HarmonyPrefix] public static bool FreezeFrame_Prefix(CharacterAnimEvent __instance) { return OnAnimatorMove_Prefix(__instance); } [HarmonyPatch(typeof(Attack), "OnAttackTrigger")] [HarmonyPostfix] public static void OnAttackTrigger_Postfix(Attack __instance) { _landed = __instance; } }