Decompiled source of NoUnarmedCombat v1.0.2

NoUnarmedCombat.dll

Decompiled 6 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("NoUnarmedCombat")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Riintouge")]
[assembly: AssemblyProduct("No Unarmed Combat")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6245a6e2-549d-4d09-b596-43a8169cad43")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.2.0")]
namespace NoUnarmedCombat;

[BepInPlugin("com.riintouge.nounarmedcombat", "No Unarmed Combat", "1.0.2")]
[BepInProcess("valheim.exe")]
public class NoUnarmedCombat : BaseUnityPlugin
{
	[HarmonyPatch(typeof(Humanoid))]
	private class HumanoidPatch
	{
		private static bool InStartAttack;

		private static bool PerformingSecondaryAttack;

		private static bool SheathedBecauseSwimming;

		private static bool SkipNextEquipAttempt;

		private static ItemData[] GetToolbarWeaponsAndShield(Humanoid humanoid)
		{
			List<ItemData> list = new List<ItemData>();
			humanoid.GetInventory().GetBoundItems(list);
			List<ItemData> source = (from x in list
				orderby x.m_gridPos.x
				where x.GetDurabilityPercentage() > 0f
				select x).ToList();
			return (ItemData[])(object)new ItemData[3]
			{
				((IEnumerable<ItemData>)source).FirstOrDefault((Func<ItemData, bool>)((ItemData itemData) => itemData.IsWeapon() && itemData.IsTwoHanded())),
				((IEnumerable<ItemData>)source).FirstOrDefault((Func<ItemData, bool>)((ItemData itemData) => itemData.IsWeapon() && !itemData.IsTwoHanded())),
				((IEnumerable<ItemData>)source).FirstOrDefault((Func<ItemData, bool>)((ItemData itemData) => ItemIsShield(itemData)))
			};
		}

		private static bool HumanoidIsLocalPlayer(Humanoid humanoid)
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			if (((Character)humanoid).IsPlayer())
			{
				ZDOID zDOID = ((Character)humanoid).GetZDOID();
				return ((ZDOID)(ref zDOID)).UserID == ZDOMan.GetSessionID();
			}
			return false;
		}

		private static bool ItemIsShield(ItemData itemData)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			if (itemData == null)
			{
				return false;
			}
			return (int)itemData.m_shared.m_itemType == 5;
		}

		private static void ShowHandItems(ref Humanoid __instance)
		{
			Traverse.Create((object)__instance).Method("ShowHandItems", Array.Empty<object>()).GetValue();
		}

		[HarmonyPatch("GetCurrentWeapon")]
		[HarmonyPostfix]
		private static ItemData GetCurrentWeaponPostfix(ItemData result, ref Humanoid __instance, ref ItemData ___m_hiddenLeftItem, ref ItemData ___m_hiddenRightItem)
		{
			if (InStartAttack && IsEnabled.Value && result == __instance.m_unarmedWeapon?.m_itemData && HumanoidIsLocalPlayer(__instance) && (!PerformingSecondaryAttack || !AllowKick.Value))
			{
				if (UnsheatheOnPunch.Value && (___m_hiddenLeftItem != null || ___m_hiddenRightItem != null))
				{
					return null;
				}
				if (ToolbarEquipOnPunch.Value)
				{
					ItemData[] toolbarWeaponsAndShield = GetToolbarWeaponsAndShield(__instance);
					if (toolbarWeaponsAndShield[0] != null || toolbarWeaponsAndShield[1] != null)
					{
						return null;
					}
				}
				if (!FallbackFisticuffs.Value)
				{
					SkipNextEquipAttempt = true;
					return null;
				}
			}
			return result;
		}

		[HarmonyPatch("StartAttack")]
		[HarmonyPrefix]
		private static bool StartAttackPrefix(ref Humanoid __instance, ref bool secondaryAttack)
		{
			if (!IsEnabled.Value)
			{
				return true;
			}
			if (HumanoidIsLocalPlayer(__instance) && Minimap.IsOpen())
			{
				return false;
			}
			InStartAttack = true;
			PerformingSecondaryAttack = secondaryAttack;
			return true;
		}

		[HarmonyPatch("StartAttack")]
		[HarmonyPostfix]
		private static void StartAttackPostfix(ref Humanoid __instance, ref ItemData ___m_hiddenLeftItem, ref ItemData ___m_hiddenRightItem, ref ZSyncAnimation ___m_zanim)
		{
			bool num = !IsEnabled.Value || !HumanoidIsLocalPlayer(__instance) || __instance.GetCurrentWeapon() != null || !InStartAttack || SkipNextEquipAttempt;
			InStartAttack = false;
			PerformingSecondaryAttack = false;
			SkipNextEquipAttempt = false;
			if (num)
			{
				return;
			}
			ItemData val = __instance.RightItem;
			ItemData val2 = __instance.LeftItem;
			if (val != null || val2 != null)
			{
				return;
			}
			ItemData val3 = null;
			ItemData val4 = null;
			if (UnsheatheOnPunch.Value && (___m_hiddenRightItem != null || ___m_hiddenLeftItem != null))
			{
				if (!ToolbarEquipOnPunch.Value || (___m_hiddenLeftItem != null && ___m_hiddenRightItem != null))
				{
					ShowHandItems(ref __instance);
					return;
				}
				val = ___m_hiddenRightItem;
				val2 = ___m_hiddenLeftItem;
				val3 = ___m_hiddenRightItem;
				val4 = ___m_hiddenLeftItem;
			}
			if (!ToolbarEquipOnPunch.Value || (val3 != null && val4 != null))
			{
				return;
			}
			ItemData[] toolbarWeaponsAndShield = GetToolbarWeaponsAndShield(__instance);
			ItemData val5 = toolbarWeaponsAndShield[0];
			ItemData val6 = toolbarWeaponsAndShield[1];
			ItemData val7 = toolbarWeaponsAndShield[2];
			if (val3 == null && val4 == null)
			{
				if (val6 != null && val5 != null)
				{
					if (val6.m_gridPos.x < val5.m_gridPos.x)
					{
						val3 = val6;
						val4 = val7;
					}
					else
					{
						val3 = val5;
					}
				}
				else if (val5 != null)
				{
					val3 = val5;
				}
				else
				{
					val3 = val6;
					val4 = val7;
				}
			}
			else if (val3 != null && val4 == null)
			{
				if (!val3.IsTwoHanded())
				{
					val4 = val7;
				}
			}
			else if (val3 == null && val4 != null && !val4.IsTwoHanded() && !val4.IsWeapon() && ItemIsShield(val4) && val6 != null)
			{
				val3 = val6;
			}
			if (val != null)
			{
				__instance.EquipItem(val, true);
			}
			else if (val3 != null && !__instance.IsItemEquiped(val3))
			{
				__instance.EquipItem(val3, true);
				val = val3;
			}
			if (val2 != null)
			{
				__instance.EquipItem(val2, true);
			}
			else if (val4 != null && !__instance.IsItemEquiped(val4))
			{
				__instance.EquipItem(val4, true);
				if (val != null && !__instance.IsItemEquiped(val))
				{
					__instance.EquipItem(val, true);
				}
				else
				{
					val2 = val4;
				}
			}
			if (val != null || val2 != null)
			{
				___m_zanim.SetTrigger("equip_hip");
			}
			PlayerPatch.RestoreQueuedAttackTimers = true;
		}

		[HarmonyPatch("UpdateEquipment")]
		[HarmonyPrefix]
		private static void UpdateEquipmentPrefix(ref Humanoid __instance, ref ItemData ___m_leftItem, ref ItemData ___m_rightItem)
		{
			if (!HumanoidIsLocalPlayer(__instance))
			{
				return;
			}
			if (((Character)__instance).IsSwimming() && !((Character)__instance).IsOnGround())
			{
				SheathedBecauseSwimming |= ___m_leftItem != null || ___m_rightItem != null;
			}
			else if (SheathedBecauseSwimming)
			{
				if (IsEnabled.Value && UnsheatheAfterSwimming.Value)
				{
					ShowHandItems(ref __instance);
				}
				SheathedBecauseSwimming = false;
			}
		}
	}

	[HarmonyPatch(typeof(Player))]
	private class PlayerPatch
	{
		internal static bool RestoreQueuedAttackTimers;

		private static float LastAttackTimer;

		private static float LastSecondaryAttackTimer;

		[HarmonyPatch("PlayerAttackInput")]
		[HarmonyPrefix]
		private static void PlayerAttackInputPrefix(ref float ___m_queuedAttackTimer, ref float ___m_queuedSecondAttackTimer)
		{
			LastAttackTimer = ___m_queuedAttackTimer;
			LastSecondaryAttackTimer = ___m_queuedSecondAttackTimer;
		}

		[HarmonyPatch("PlayerAttackInput")]
		[HarmonyPostfix]
		private static void PlayerAttackInputPostfix(ref float ___m_queuedAttackTimer, ref float ___m_queuedSecondAttackTimer)
		{
			if (RestoreQueuedAttackTimers)
			{
				___m_queuedAttackTimer = LastAttackTimer;
				___m_queuedSecondAttackTimer = LastSecondaryAttackTimer;
			}
		}
	}

	public static ConfigEntry<bool> IsEnabled;

	public static ConfigEntry<bool> LoadOnStart;

	public static ConfigEntry<bool> AllowKick;

	public static ConfigEntry<bool> FallbackFisticuffs;

	public static ConfigEntry<bool> ToolbarEquipOnPunch;

	public static ConfigEntry<bool> UnsheatheAfterSwimming;

	public static ConfigEntry<bool> UnsheatheOnPunch;

	private readonly Harmony Harmony = new Harmony("com.riintouge.nounarmedcombat");

	private void Awake()
	{
		IsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "Enable", true, "Whether this plugin has any effect when loaded.");
		LoadOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Core", "LoadOnStart", true, "Whether this plugin loads on game start.");
		AllowKick = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "AllowKick", false, "Allow the player to kick.");
		FallbackFisticuffs = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "FallbackFisticuffs", true, "Allow the player to punch and kick when they have no weapon to equip.");
		ToolbarEquipOnPunch = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "ToolbarEquipOnPunch", true, "Instead of punching and if nothing is sheathed, equip gear from the toolbar, left to right.");
		UnsheatheAfterSwimming = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "UnsheatheAfterSwimming", false, "Unsheathe equipment when exiting water that was put away upon swimming.");
		UnsheatheOnPunch = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "UnsheatheOnPunch", true, "Instead of punching, equip sheathed equipment. Takes precedence over equipment on the toolbar.");
		if (LoadOnStart.Value)
		{
			Harmony.PatchAll();
		}
	}
}