using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; using Bombanana; using HarmonyLib; using Microsoft.CodeAnalysis; 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("BombananaNoSlapCooldown")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("BombananaNoSlapCooldown")] [assembly: AssemblyTitle("BombananaNoSlapCooldown")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace BombananaNoSlapCooldown { [BepInPlugin("codaaaaaa.bombanana.noslapcooldown", "Remove Slap Cooldown", "1.0.0")] public class Plugin : BasePlugin { public const string Guid = "codaaaaaa.bombanana.noslapcooldown"; internal const float BypassStamp = -9999f; internal static ManualLogSource Logger; internal static ConfigEntry Enabled; internal static ConfigEntry CooldownSeconds; internal static ConfigEntry Verbose; internal static ConfigEntry WindupSpeedMultiplier; internal static ConfigEntry AlsoSpeedUpRecovery; internal static ConfigEntry RemoveImpactCooldown; internal const float MinPhase = 0.01f; internal static readonly Dictionary LastAllowedSlap = new Dictionary(); private static readonly HashSet LoggedKeys = new HashSet(); private static bool _loggedOriginal; private Harmony _harmony; private static float _vanillaWindup; private static float _vanillaTwist; private static float _vanillaForward; private static float _vanillaHold; private static float _vanillaReturn; public override void Load() { //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown Logger = ((BasePlugin)this).Log; Enabled = ((BasePlugin)this).Config.Bind("General", "Enabled", true, "Master switch. False = vanilla slap cooldown."); CooldownSeconds = ((BasePlugin)this).Config.Bind("General", "CooldownSeconds", 0f, "Seconds between slaps. 0 = no cooldown at all. Any value above 0 replaces the game's cooldown with your own."); Verbose = ((BasePlugin)this).Config.Bind("General", "Verbose", true, "Log the first time each gate is hit, so you can confirm all three are actually being bypassed. Set false once you are happy."); WindupSpeedMultiplier = ((BasePlugin)this).Config.Bind("Windup", "WindupSpeedMultiplier", 4f, "How much faster the hand travels before the slap connects (windup + twist + forward). 1 = vanilla, 4 = four times faster, very high = practically instant. The hit registers when the hand reaches the target, so this is what removes the wind-up delay."); AlsoSpeedUpRecovery = ((BasePlugin)this).Config.Bind("Windup", "AlsoSpeedUpRecovery", true, "Apply the same multiplier to the post-impact phases (hold + return), so the hand snaps back too."); RemoveImpactCooldown = ((BasePlugin)this).Config.Bind("General", "RemoveImpactCooldown", true, "Also clear the victim-side throttle (PlayerThrowableImpactEffects.playerImpactCooldown), which otherwise swallows the reaction to rapid repeat slaps on the same player."); _harmony = new Harmony("codaaaaaa.bombanana.noslapcooldown"); _harmony.PatchAll(typeof(Patch_SlapInteraction_LateUpdate)); _harmony.PatchAll(typeof(Patch_SlapInteraction_Awake)); _harmony.PatchAll(typeof(Patch_PlayerBase_RequestSlap)); _harmony.PatchAll(typeof(Patch_PlayerBase_RequestSlapServerRpc)); _harmony.PatchAll(typeof(Patch_ImpactEffects_HandleSlapImpact)); Logger.LogInfo((object)("Patched. Enabled=" + Enabled.Value + ", CooldownSeconds=" + CooldownSeconds.Value)); Logger.LogInfo((object)"Gate 3 (server) applies to every attacker once YOU host -- Harmony patches the method, not one instance."); } public override bool Unload() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } return ((BasePlugin)this).Unload(); } internal static float TargetCooldown() { float value = CooldownSeconds.Value; if (!(value > 0f)) { return 0f; } return value; } internal static void LogOnce(string key, string message) { if (Verbose.Value && LoggedKeys.Add(key)) { Logger.LogInfo((object)message); } } private static float Scale(float duration, float multiplier) { if (multiplier <= 1f) { return duration; } float num = duration / multiplier; if (!(num < 0.01f)) { return num; } return 0.01f; } internal static void ApplyTuning(PlayerSlapInteraction inst) { LogVanillaOnce(inst); float num = TargetCooldown(); if (inst.slapCooldown != num) { LogOnce("gate1", "[gate 1/4] local input: slapCooldown pinned to " + num.ToString("0.###") + "s"); inst.slapCooldown = num; } float value = WindupSpeedMultiplier.Value; if (!(value <= 1f)) { inst.handWindupDuration = Scale(_vanillaWindup, value); inst.handTwistDuration = Scale(_vanillaTwist, value); inst.handForwardDuration = Scale(_vanillaForward, value); if (AlsoSpeedUpRecovery.Value) { inst.handHoldDuration = Scale(_vanillaHold, value); inst.handReturnDuration = Scale(_vanillaReturn, value); } LogOnce("windup", "[windup] pre-impact " + VanillaWindupTotal().ToString("0.###") + "s -> " + (Scale(_vanillaWindup, value) + Scale(_vanillaTwist, value) + Scale(_vanillaForward, value)).ToString("0.###") + "s (x" + value.ToString("0.##") + ")"); } } internal static float VanillaWindupTotal() { return _vanillaWindup + _vanillaTwist + _vanillaForward; } private static void LogVanillaOnce(PlayerSlapInteraction inst) { if (!_loggedOriginal) { _loggedOriginal = true; _vanillaWindup = inst.handWindupDuration; _vanillaTwist = inst.handTwistDuration; _vanillaForward = inst.handForwardDuration; _vanillaHold = inst.handHoldDuration; _vanillaReturn = inst.handReturnDuration; Logger.LogInfo((object)("Vanilla slapCooldown=" + inst.slapCooldown.ToString("0.###") + "s windup=" + _vanillaWindup.ToString("0.###") + " twist=" + _vanillaTwist.ToString("0.###") + " forward=" + _vanillaForward.ToString("0.###") + " (pre-impact total " + VanillaWindupTotal().ToString("0.###") + "s) hold=" + _vanillaHold.ToString("0.###") + " return=" + _vanillaReturn.ToString("0.###"))); } } } [HarmonyPatch(typeof(PlayerSlapInteraction), "LateUpdate")] internal static class Patch_SlapInteraction_LateUpdate { private static void Postfix(PlayerSlapInteraction __instance) { if (Plugin.Enabled.Value) { Plugin.ApplyTuning(__instance); } } } [HarmonyPatch(typeof(PlayerSlapInteraction), "Awake")] internal static class Patch_SlapInteraction_Awake { private static void Postfix(PlayerSlapInteraction __instance) { if (Plugin.Enabled.Value) { Plugin.ApplyTuning(__instance); __instance.lastLocalSlapTime = -9999f; } } } [HarmonyPatch(typeof(PlayerBase), "RequestSlap")] internal static class Patch_PlayerBase_RequestSlap { private static bool Prefix(PlayerBase __instance) { if (!Plugin.Enabled.Value) { return true; } float value = Plugin.CooldownSeconds.Value; if (value > 0f) { int instanceID = ((Object)__instance).GetInstanceID(); if (Plugin.LastAllowedSlap.TryGetValue(instanceID, out var value2) && Time.time - value2 < value) { return false; } Plugin.LastAllowedSlap[instanceID] = Time.time; } Plugin.LogOnce("gate2", "[gate 2/4] client: RequestSlap intercepted, lastClientSlapTime rewound"); __instance.lastClientSlapTime = -9999f; __instance.lastServerSlapTime = -9999f; return true; } } [HarmonyPatch(typeof(PlayerThrowableImpactEffects), "HandleSlapImpact")] internal static class Patch_ImpactEffects_HandleSlapImpact { private static void Prefix(PlayerThrowableImpactEffects __instance) { if (Plugin.Enabled.Value && Plugin.RemoveImpactCooldown.Value) { Plugin.LogOnce("gate4", "[gate 4/4] impact: HandleSlapImpact reached us, lastPlayerImpactTime rewound"); __instance.lastPlayerImpactTime = -9999f; } } } [HarmonyPatch(typeof(PlayerBase), "RequestSlapServerRpc")] internal static class Patch_PlayerBase_RequestSlapServerRpc { private static void Prefix(PlayerBase __instance) { if (Plugin.Enabled.Value) { Plugin.LogOnce("gate3", "[gate 3/4] server: RequestSlapServerRpc reached us -- we are host for this slap, lastServerSlapTime rewound"); __instance.lastServerSlapTime = -9999f; } } } }