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 LethalParryingRebind v1.0.34
Redcom1988.LethalParryingRebind.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using LethalParrying.Patches; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Redcom1988")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Lethal Company Parrying")] [assembly: AssemblyFileVersion("1.0.2.0")] [assembly: AssemblyInformationalVersion("1.0.2")] [assembly: AssemblyProduct("LethalParryingRebind")] [assembly: AssemblyTitle("Redcom1988.LethalParryingRebind")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.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 LethalParrying { public class ParryNetworkHandler : NetworkBehaviour { } [BepInPlugin("Redcom1988.LethalParryingRebind", "LethalParryingRebind", "1.0.2")] [BepInProcess("Lethal Company.exe")] public class LethalParryBase : BaseUnityPlugin { public static LethalParryBase instance; public static ManualLogSource logger; public static bool serverModCheck = true; public static bool stun = false; internal static ConfigEntry<int> DropProbability; internal static ConfigEntry<bool> Notify; internal static ConfigEntry<bool> DisplayCooldown; internal static ConfigEntry<float> ParryWindow; internal static ConfigEntry<float> ParryCooldown; internal static ConfigEntry<string> Keybind; private readonly Harmony harmony = new Harmony("Redcom1988.LethalParryingRebind"); private void NetCodeWeaver() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { methodInfo.Invoke(null, null); } } } } private void Awake() { DropProbability = ((BaseUnityPlugin)this).Config.Bind<int>("General", "Drop chance", 15, "Probability for how often you might drop your weapon when failing to parry or holding R."); ParryWindow = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Parry Window", 0.25f, "Time for parry window."); ParryCooldown = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Parry Cooldown", 2f, "Time for parry cooldown."); Keybind = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Parry Keybind", "f", "Keybind to trigger parry."); Notify = ((BaseUnityPlugin)this).Config.Bind<bool>("Screen Information", "Display Parry Notifications", false, "Enables/Disables screen notifications for parry information. (Will be removed when sounds and effects are added)"); DisplayCooldown = ((BaseUnityPlugin)this).Config.Bind<bool>("Screen Information", "Display Parry Cooldown (Notification)", true, "Will show you a notification if your parry is on cooldown. (Display Parry Notifications does not affect this.)"); if (DropProbability.Value < (int)((ConfigEntryBase)DropProbability).DefaultValue) { DropProbability.Value = (int)((ConfigEntryBase)DropProbability).DefaultValue; } NetCodeWeaver(); if ((Object)(object)instance == (Object)null) { instance = this; logger = ((BaseUnityPlugin)this).Logger; } logger.LogInfo((object)"---[Only skill issue can kill you now..]---"); logger.LogInfo((object)"---[Plugin Redcom1988.LethalParryingRebind is loaded!]---"); logger.LogInfo((object)"---[Only skill issue can kill you now..]---"); harmony.PatchAll(typeof(LethalParryBase)); harmony.PatchAll(typeof(PlayerControllerBPatch)); harmony.PatchAll(typeof(ShovelPatch)); } } public static class PluginInfo { public const string PLUGIN_GUID = "Redcom1988.LethalParryingRebind"; public const string PLUGIN_NAME = "LethalParryingRebind"; public const string PLUGIN_VERSION = "1.0.2"; } } namespace LethalParrying.Patches { [HarmonyPatch(typeof(PlayerControllerB))] internal class PlayerControllerBPatch { internal static bool isPerfectParryFrame = false; internal static bool isSlow = false; internal static float perfectParryWindow = LethalParryBase.ParryWindow.Value; internal static float lastParryTime; internal static float perfectParryCooldown = LethalParryBase.ParryCooldown.Value; internal static Key convertedKey = GetKeyFromString(LethalParryBase.Keybind.Value); internal static GrabbableObject currentItem; internal static Shovel shovel = null; internal static bool ParriedDeath = false; internal static Coroutine currentCoroutine; [HarmonyPatch("KillPlayer")] [HarmonyPrefix] private static bool KillPlayerPatch(PlayerControllerB __instance, CauseOfDeath causeOfDeath) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Invalid comparison between Unknown and I4 //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Invalid comparison between Unknown and I4 //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Invalid comparison between Unknown and I4 //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Invalid comparison between Unknown and I4 if (!LethalParryBase.serverModCheck) { return true; } if (!((NetworkBehaviour)__instance).IsOwner) { return false; } if (__instance.isPlayerDead) { return false; } if (!__instance.AllowPlayerDeath()) { return false; } if (ParriedDeath) { LethalParryBase.logger.LogWarning((object)"Server called KillPlayer method again. Might have to patch this method properly."); ParriedDeath = false; return false; } if ((int)causeOfDeath == 0 || (int)causeOfDeath == 2 || (int)causeOfDeath == 10 || (int)causeOfDeath == 5 || (int)causeOfDeath == 9 || (Object)(object)shovel == (Object)null) { return true; } if (isPerfectParryFrame) { if (LethalParryBase.Notify.Value) { HUDManager.Instance.DisplayTip("Parried Death..", "Nothing can stop you.", true, false, "LC_Tip1"); } HUDManager.Instance.ShakeCamera((ScreenShakeType)3); __instance.DropAllHeldItems(true, false); lastParryTime = 0f; ParriedDeath = true; return false; } return true; } [HarmonyPatch("DamagePlayer")] [HarmonyPrefix] private static bool DamagePlayerPatch(PlayerControllerB __instance, ref int damageNumber, CauseOfDeath causeOfDeath) { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Invalid comparison between Unknown and I4 //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Invalid comparison between Unknown and I4 //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Invalid comparison between Unknown and I4 //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) if (!LethalParryBase.serverModCheck) { return true; } if (!((NetworkBehaviour)__instance).IsOwner) { return false; } if (__instance.isPlayerDead) { return false; } if (!__instance.AllowPlayerDeath()) { return false; } if ((int)causeOfDeath == 10 || (int)causeOfDeath == 5 || (int)causeOfDeath == 9 || (Object)(object)shovel == (Object)null) { return true; } if (isPerfectParryFrame) { isSlow = false; if (currentCoroutine == null) { currentCoroutine = ((MonoBehaviour)__instance).StartCoroutine(DoHit(__instance, shovel)); } MakeCriticallyInjured(__instance, enable: false); HUDManager.Instance.ShakeCamera((ScreenShakeType)1); if (LethalParryBase.Notify.Value) { HUDManager.Instance.DisplayTip("Parried!", "Nice job!", false, false, "LC_Tip1"); } __instance.ResetFallGravity(); lastParryTime = 0f; } else if ((int)convertedKey != 0 && ((ButtonControl)Keyboard.current[convertedKey]).isPressed) { int num = Random.Range(0, damageNumber - Random.Range(0, damageNumber)); damageNumber -= num; if (LethalParryBase.Notify.Value) { HUDManager.Instance.DisplayTip("Blocked Damage", $"Damage negated: {num}", false, false, "LC_Tip1"); } HUDManager.Instance.ShakeCamera((ScreenShakeType)1); int num2 = Random.Range(1, 100); if (num2 <= LethalParryBase.DropProbability.Value && (Object)(object)currentItem != (Object)null) { __instance.DiscardHeldObject(false, (NetworkObject)null, default(Vector3), true); } } return !isPerfectParryFrame; } [HarmonyPatch("Update")] [HarmonyPostfix] private static void UpdatePatch(PlayerControllerB __instance) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) if (!LethalParryBase.serverModCheck || ((!((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerControlled || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer)) { return; } currentItem = __instance.ItemSlots[__instance.currentItemSlot]; if ((int)convertedKey == 0 || !((ButtonControl)Keyboard.current[convertedKey]).isPressed || (Object)(object)currentItem == (Object)null || (Object)(object)shovel == (Object)null) { if (__instance.bleedingHeavily) { isSlow = false; return; } if (isSlow && __instance.criticallyInjured) { isSlow = false; MakeCriticallyInjured(__instance, enable: false); } } if ((Object)(object)currentItem == (Object)null) { return; } shovel = (Shovel)((currentItem is Shovel) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)shovel == (Object)null || (int)convertedKey == 0 || !((ButtonControl)Keyboard.current[convertedKey]).isPressed) { return; } if (shovel.reelingUp || __instance.bleedingHeavily) { if (LethalParryBase.Notify.Value) { HUDManager.Instance.DisplayTip("Can't parry.", "You are attacking or injured.", false, false, "LC_Tip1"); } } else if (!IsParryOnCooldown()) { ((MonoBehaviour)__instance).StartCoroutine(PerfectParryWindow(__instance, shovel)); MakeCriticallyInjured(__instance, enable: true); LethalParryBase.stun = true; isSlow = true; } else if (!isPerfectParryFrame && LethalParryBase.DisplayCooldown.Value) { HUDManager.Instance.DisplayTip("Can't parry. On cooldown", $"Can parry again after {Math.Round(perfectParryCooldown - Time.time + lastParryTime, 1)} seconds.", false, false, "LC_Tip1"); } } private static Key GetKeyFromString(string keyString) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) foreach (Key value in Enum.GetValues(typeof(Key))) { Key result = value; if (((object)(Key)(ref result)).ToString().ToLower() == keyString.ToLower()) { return result; } } return (Key)0; } private static IEnumerator DoHit(PlayerControllerB player, Shovel shovel) { AccessTools.Field(typeof(Shovel), "previousPlayerHeldBy").SetValue(shovel, player); shovel.reelingUp = true; if (currentCoroutine == null) { player.activatingItem = true; player.twoHanded = true; player.playerBodyAnimator.ResetTrigger("shovelHit"); player.playerBodyAnimator.SetBool("reelingUp", true); shovel.shovelAudio.PlayOneShot(shovel.reelUp); yield return (object)new WaitForSeconds(0.1f); if (shovel != null) { shovel.SwingShovel(!((GrabbableObject)shovel).isHeld); } yield return (object)new WaitForSeconds(0.15f); if (shovel != null) { shovel.HitShovel(!((GrabbableObject)shovel).isHeld); } shovel.reelingUp = false; AccessTools.Field(typeof(Shovel), "reelingUpCoroutine").SetValue(shovel, null); currentCoroutine = null; } } private static IEnumerator PerfectParryWindow(PlayerControllerB player, Shovel shovel) { if (!isPerfectParryFrame) { isPerfectParryFrame = true; lastParryTime = Time.fixedTime; shovel.shovelAudio.PlayOneShot(shovel.reelUp); shovel.ReelUpSFXServerRpc(); yield return (object)new WaitForSeconds(perfectParryWindow); isPerfectParryFrame = false; } } private static void MakeCriticallyInjured(PlayerControllerB player, bool enable) { player.criticallyInjured = enable; player.playerBodyAnimator.SetBool("Limp", enable); } private static bool IsParryOnCooldown() { return Time.fixedTime - lastParryTime < perfectParryCooldown; } } [HarmonyPatch(typeof(Shovel))] internal class ShovelPatch { [HarmonyPatch("HitShovel")] [HarmonyPostfix] public static void HitShovelPostfix(ref Shovel __instance, ref List<RaycastHit> ___objectsHitByShovelList, ref PlayerControllerB ___previousPlayerHeldBy) { //IL_0048: 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 (___objectsHitByShovelList == null && (___objectsHitByShovelList.Count == 0 || !LethalParryBase.stun || !LethalParryBase.serverModCheck)) { return; } LethalParryBase.logger.LogInfo((object)"Got hit list"); EnemyAI val = default(EnemyAI); foreach (RaycastHit ___objectsHitByShovel in ___objectsHitByShovelList) { RaycastHit current = ___objectsHitByShovel; if (((Component)((RaycastHit)(ref current)).transform.parent).TryGetComponent<EnemyAI>(ref val) && (Object)(object)((RaycastHit)(ref current)).transform != (Object)(object)___previousPlayerHeldBy && (Object)(object)val != (Object)null) { try { LethalParryBase.logger.LogInfo((object)$"Stunned enemy {val.enemyType}!"); val.SetEnemyStunned(true, 1f, ___previousPlayerHeldBy); } catch (Exception arg) { Debug.Log((object)$"Exception caught when hitting object with shovel from player #{___previousPlayerHeldBy.playerClientId}: {arg}"); } } } LethalParryBase.stun = false; } } } namespace LethalParrying.Netcode { [HarmonyPatch] public class ServerModCheck { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnRequest; public static HandleNamedMessageDelegate <1>__OnReceive; } public static PlayerControllerB localPlayer; public static bool hasMod; public static bool synced; [HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")] [HarmonyPostfix] public static void InitLocalPlayer(PlayerControllerB __instance) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_003b: 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_0046: Expected O, but got Unknown localPlayer = __instance; if (NetworkManager.Singleton.IsServer) { hasMod = true; CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; object obj = <>O.<0>__OnRequest; if (obj == null) { HandleNamedMessageDelegate val = OnRequest; <>O.<0>__OnRequest = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("LethalParryingOnRequestModCheck", (HandleNamedMessageDelegate)obj); LethalParryBase.logger.LogInfo((object)"Setting up Server CustomMessagingManager"); SyncOnLocalClient(); } else { CustomMessagingManager customMessagingManager2 = NetworkManager.Singleton.CustomMessagingManager; object obj2 = <>O.<1>__OnReceive; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnReceive; <>O.<1>__OnReceive = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("LethalParryingOnReceiveModCheck", (HandleNamedMessageDelegate)obj2); LethalParryBase.logger.LogInfo((object)"Setting up Client CustomMessagingManager"); SendRequestToServer(); } } [HarmonyPatch(typeof(GameNetworkManager), "Disconnect")] [HarmonyPrefix] public static bool OnDestroy() { if ((Object)(object)NetworkManager.Singleton != (Object)null) { if (NetworkManager.Singleton.IsServer) { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LethalParryingOnRequestModCheck"); LethalParryBase.logger.LogInfo((object)"Destroying Server CustomMessagingManager"); } else { NetworkManager.Singleton.CustomMessagingManager.UnregisterNamedMessageHandler("LethalParryingOnReceiveModCheck"); LethalParryBase.logger.LogInfo((object)"Destroying Client CustomMessagingManager"); } } hasMod = false; LethalParryBase.serverModCheck = false; LethalParryBase.logger.LogInfo((object)"Setting mod check to false"); return true; } public static void SendRequestToServer() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsClient) { LethalParryBase.logger.LogInfo((object)"Sending request to server."); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LethalParryingOnRequestModCheck", 0uL, val, (NetworkDelivery)3); } else { LethalParryBase.logger.LogError((object)"Faile to send request if server has mod."); } } public static void OnRequest(ulong clientId, FastBufferReader reader) { //IL_0033: 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_004c: 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_006a: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsServer) { LethalParryBase.logger.LogInfo((object)$"Player_ID: {clientId} Requested for Mod Check."); bool flag = true; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(FastBufferWriter.GetWriteSize<bool>(ref flag, default(ForStructs)), (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref flag, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("LethalParryingOnReceiveModCheck", clientId, val, (NetworkDelivery)3); } } public static void OnReceive(ulong clientId, FastBufferReader reader) { //IL_0007: 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) bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); hasMod = flag; LethalParryBase.logger.LogInfo((object)$"Received mod check: {hasMod} from server!"); SyncOnLocalClient(); } public static void SyncOnLocalClient() { LethalParryBase.serverModCheck = hasMod; } } }