Decompiled source of LethalParryingRebind v1.0.34

Redcom1988.LethalParryingRebind.dll

Decompiled 10 months ago
using 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;
		}
	}
}