Decompiled source of LethalParrying v1.0.31

Ryokune.LethalParrying.dll

Decompiled a year 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 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 = "")]
[assembly: AssemblyCompany("Ryokune")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Lethal Company Parrying")]
[assembly: AssemblyFileVersion("1.0.31.0")]
[assembly: AssemblyInformationalVersion("1.0.31")]
[assembly: AssemblyProduct("LethalParrying")]
[assembly: AssemblyTitle("Ryokune.LethalParrying")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.31.0")]
[module: UnverifiableCode]
namespace LethalParrying
{
	public class ParryNetworkHandler : NetworkBehaviour
	{
	}
	[BepInPlugin("Ryokune.LethalParrying", "LethalParrying", "1.0.31")]
	[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;

		private readonly Harmony harmony = new Harmony("Ryokune.LethalParrying");

		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 F.");
			Notify = ((BaseUnityPlugin)this).Config.Bind<bool>("Screen Information", "Display Parry Notifications", true, "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 Ryokune.LethalParrying 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 = "Ryokune.LethalParrying";

		public const string PLUGIN_NAME = "LethalParrying";

		public const string PLUGIN_VERSION = "1.0.31";
	}
}
namespace LethalParrying.Patches
{
	[HarmonyPatch(typeof(PlayerControllerB))]
	internal class PlayerControllerBPatch
	{
		internal static bool isPerfectParryFrame = false;

		internal static bool isSlow = false;

		internal static float perfectParryWindow = 0.25f;

		internal static float lastParryTime;

		internal static float perfectParryCooldown = 2f;

		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_01c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c9: 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 (((ButtonControl)Keyboard.current.fKey).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)
		{
			if (!LethalParryBase.serverModCheck || ((!((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerControlled || (((NetworkBehaviour)__instance).IsServer && !__instance.isHostPlayerObject)) && !__instance.isTestingPlayer))
			{
				return;
			}
			currentItem = __instance.ItemSlots[__instance.currentItemSlot];
			if (!((ButtonControl)Keyboard.current.fKey).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 || !((ButtonControl)Keyboard.current.fKey).wasPressedThisFrame)
			{
				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 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
	{
		public static PlayerControllerB localPlayer;

		public static bool hasMod;

		public static bool synced;

		[HarmonyPatch(typeof(PlayerControllerB), "ConnectClientToPlayerObject")]
		[HarmonyPostfix]
		public static void InitLocalPlayer(PlayerControllerB __instance)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			localPlayer = __instance;
			if (NetworkManager.Singleton.IsServer)
			{
				hasMod = true;
				NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LethalParryingOnRequestModCheck", new HandleNamedMessageDelegate(OnRequest));
				LethalParryBase.logger.LogInfo((object)"Setting up Server CustomMessagingManager");
				SyncOnLocalClient();
			}
			else
			{
				NetworkManager.Singleton.CustomMessagingManager.RegisterNamedMessageHandler("LethalParryingOnReceiveModCheck", new HandleNamedMessageDelegate(OnReceive));
				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;
		}
	}
}