Decompiled source of AutoEquipShield v1.0.4

BepInEx/plugins/RambosAutoEquipShield.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("RambosAutoEquipShield")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("RambosAutoEquipShield")]
[assembly: AssemblyTitle("RambosAutoEquipShield")]
[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;
		}
	}
}
[BepInPlugin("rambos.valheim.autoequipshield", "Rambo's Auto Equip Shield", "1.0.4")]
public class AutoEquipShield : BaseUnityPlugin
{
	public const string PluginGuid = "rambos.valheim.autoequipshield";

	public const string PluginName = "Rambo's Auto Equip Shield";

	public const string PluginVersion = "1.0.4";

	private static AutoEquipShield _instance;

	private static Harmony _harmony;

	private ConfigEntry<bool> _enabled;

	private ConfigEntry<KeyboardShortcut> _toggleKey;

	private ConfigEntry<bool> _debug;

	private static bool _equippingShield;

	private static Type _humanoidType;

	private static Type _itemDataType;

	private static MethodInfo _equipItemMethod;

	private static FieldInfo _localPlayerField;

	private static FieldInfo _leftItemField;

	private static FieldInfo _rightItemField;

	private static FieldInfo _inventoryField;

	private static MethodInfo _getInventoryMethod;

	private static MethodInfo _getAllItemsMethod;

	private static MethodInfo _getBlockPowerMethod;

	private static FieldInfo _sharedField;

	private static FieldInfo _itemTypeField;

	private static FieldInfo _blockPowerField;

	private static FieldInfo _blockPowerPerLevelField;

	private static FieldInfo _qualityField;

	private static FieldInfo _equippedField;

	private static Type _messageHudType;

	private static MethodInfo _showMessageMethod;

	private static Type _messageTypeEnum;

	private static string _popupText;

	private static float _popupUntil;

	private GUIStyle _popupStyle;

	private void Awake()
	{
		//IL_0042: Unknown result type (might be due to invalid IL or missing references)
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: Expected O, but got Unknown
		//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d0: Expected O, but got Unknown
		_instance = this;
		_enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Automatically equip the strongest shield when you equip a one-handed weapon.");
		_toggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("General", "ToggleKeyF7", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Press F7 to enable/disable automatic shield equipping.");
		_debug = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DebugLogging", false, "Write diagnostic information to the BepInEx log.");
		ResolveValheimTypes();
		_harmony = new Harmony("rambos.valheim.autoequipshield");
		try
		{
			MethodInfo methodInfo = FindEquipItemMethod();
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)"Could not find Humanoid.EquipItem(ItemData, bool). Auto Equip Shield is disabled.");
			}
			else
			{
				_harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(AutoEquipShield), "EquipItemPostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched Humanoid.EquipItem successfully. Auto Equip Shield is ready.");
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Failed to patch Humanoid.EquipItem: " + ex));
		}
		((BaseUnityPlugin)this).Logger.LogInfo((object)"Rambo's Auto Equip Shield 1.0.4 loaded. Press F7 to enable/disable.");
		((MonoBehaviour)this).StartCoroutine(ShowStartupPopup());
	}

	private IEnumerator ShowStartupPopup()
	{
		yield return null;
		yield return (object)new WaitForSeconds(1f);
		ShowPopup("Auto Equip Shield: " + (_enabled.Value ? "ENABLED" : "DISABLED") + " | F7 to toggle");
	}

	private void Update()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000b: Unknown result type (might be due to invalid IL or missing references)
		KeyboardShortcut value = _toggleKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			_enabled.Value = !_enabled.Value;
			string text = (_enabled.Value ? "ENABLED" : "DISABLED");
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Auto Equip Shield " + text));
			ShowPopup("Auto Equip Shield: " + text);
		}
	}

	private static void ResolveValheimTypes()
	{
		_humanoidType = FindType("Humanoid");
		_itemDataType = FindType("ItemDrop+ItemData");
		if (_humanoidType == null || _itemDataType == null)
		{
			((BaseUnityPlugin)_instance).Logger.LogError((object)"Could not resolve Valheim Humanoid or ItemDrop.ItemData types.");
			return;
		}
		_localPlayerField = FindField(FindType("Player"), "m_localPlayer");
		_leftItemField = FindField(_humanoidType, "m_leftItem");
		_rightItemField = FindField(_humanoidType, "m_rightItem");
		_inventoryField = FindField(_humanoidType, "m_inventory");
		_getInventoryMethod = FindMethod(_humanoidType, "GetInventory", 0);
		_sharedField = FindField(_itemDataType, "m_shared");
		_qualityField = FindField(_itemDataType, "m_quality");
		_equippedField = FindField(_itemDataType, "m_equipped") ?? FindField(_itemDataType, "m_equiped");
		_messageHudType = FindType("MessageHud");
		if (_messageHudType != null)
		{
			_messageTypeEnum = FindNestedType(_messageHudType, "MessageType");
			_showMessageMethod = _messageHudType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "ShowMessage" && m.GetParameters().Length == 2);
		}
		Type type = _sharedField?.FieldType;
		_itemTypeField = FindField(type, "m_itemType");
		_blockPowerField = FindField(type, "m_blockPower");
		_blockPowerPerLevelField = FindField(type, "m_blockPowerPerLevel");
		_getAllItemsMethod = FindMethodByNameContains(_inventoryField?.FieldType, "GetAllItems", 0);
		_getBlockPowerMethod = FindMethodByNameContains(_itemDataType, "GetBlockPower", 1) ?? FindMethodByNameContains(_itemDataType, "GetBaseBlockPower", 1);
	}

	private static MethodInfo FindEquipItemMethod()
	{
		if (_humanoidType == null || _itemDataType == null)
		{
			return null;
		}
		List<MethodInfo> source = (from m in _humanoidType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
			where m.Name == "EquipItem"
			select m).ToList();
		MethodInfo methodInfo = source.FirstOrDefault(delegate(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			return parameters.Length == 2 && parameters[0].ParameterType == _itemDataType && parameters[1].ParameterType == typeof(bool) && m.ReturnType == typeof(bool);
		});
		if (methodInfo != null)
		{
			return _equipItemMethod = methodInfo;
		}
		return _equipItemMethod = source.FirstOrDefault(delegate(MethodInfo m)
		{
			ParameterInfo[] parameters = m.GetParameters();
			return parameters.Length >= 1 && parameters[0].ParameterType == _itemDataType;
		});
	}

	private static void EquipItemPostfix(object __instance, object item, bool __result)
	{
		if ((Object)(object)_instance == (Object)null || _equippingShield || !_instance._enabled.Value || !__result || __instance == null || item == null)
		{
			return;
		}
		try
		{
			object obj = _localPlayerField?.GetValue(null);
			if (obj == null || obj != __instance || !IsItemType(item, "OneHandedWeapon"))
			{
				return;
			}
			object obj2 = _leftItemField?.GetValue(__instance);
			if (obj2 != null && IsItemType(obj2, "Shield"))
			{
				if (_instance._debug.Value)
				{
					((BaseUnityPlugin)_instance).Logger.LogInfo((object)"One-handed weapon equipped; shield already equipped, leaving it alone.");
				}
			}
			else
			{
				TryEquipBestShield(__instance);
			}
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)_instance).Logger.LogError((object)("Auto shield error: " + ex));
		}
	}

	private static void TryEquipBestShield(object player)
	{
		object obj = _inventoryField?.GetValue(player) ?? _getInventoryMethod?.Invoke(player, null);
		if (obj == null || !(_getAllItemsMethod?.Invoke(obj, null) is IEnumerable enumerable))
		{
			return;
		}
		object obj2 = null;
		float num = float.MinValue;
		foreach (object item in enumerable)
		{
			if (item != null && IsItemType(item, "Shield") && !IsEquipped(item))
			{
				float blockPower = GetBlockPower(item);
				if (obj2 == null || blockPower > num)
				{
					obj2 = item;
					num = blockPower;
				}
			}
		}
		if (obj2 == null)
		{
			return;
		}
		MethodInfo equipItemMethod = _equipItemMethod;
		if (equipItemMethod == null)
		{
			return;
		}
		ParameterInfo[] parameters = equipItemMethod.GetParameters();
		_equippingShield = true;
		try
		{
			if (parameters.Length == 2 && parameters[1].ParameterType == typeof(bool))
			{
				equipItemMethod.Invoke(player, new object[2] { obj2, false });
			}
			else
			{
				equipItemMethod.Invoke(player, new object[1] { obj2 });
			}
			string itemName = GetItemName(obj2);
			((BaseUnityPlugin)_instance).Logger.LogInfo((object)("Auto-equipped shield: " + itemName + " (block " + num.ToString("0.0") + ")."));
			ShowPopup("Auto Shield: " + itemName);
		}
		finally
		{
			_equippingShield = false;
		}
	}

	private static string GetItemName(object item)
	{
		try
		{
			object obj = _sharedField?.GetValue(item);
			string text = FindField(obj?.GetType(), "m_name")?.GetValue(obj)?.ToString();
			if (!string.IsNullOrEmpty(text))
			{
				return text;
			}
		}
		catch
		{
		}
		return "shield";
	}

	private static void ShowPopup(string text)
	{
		_popupText = text;
		_popupUntil = Time.unscaledTime + 3f;
		try
		{
			if ((Object)(object)_instance != (Object)null)
			{
				((BaseUnityPlugin)_instance).Logger.LogInfo((object)("POPUP: " + text));
			}
		}
		catch
		{
		}
	}

	private void OnGUI()
	{
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0036: Expected O, but got Unknown
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_007c: Expected O, but got Unknown
		if (!string.IsNullOrEmpty(_popupText) && !(Time.unscaledTime >= _popupUntil))
		{
			if (_popupStyle == null)
			{
				_popupStyle = new GUIStyle(GUI.skin.box);
				_popupStyle.fontSize = 24;
				_popupStyle.alignment = (TextAnchor)4;
				_popupStyle.normal.textColor = Color.white;
				_popupStyle.padding = new RectOffset(24, 24, 14, 14);
			}
			GUI.Box(new Rect(((float)Screen.width - 560f) * 0.5f, (float)Screen.height * 0.16f, 560f, 72f), _popupText, _popupStyle);
		}
	}

	private static bool IsItemType(object item, string wanted)
	{
		object obj = _sharedField?.GetValue(item);
		object obj2 = _itemTypeField?.GetValue(obj);
		if (obj2 != null)
		{
			return string.Equals(obj2.ToString(), wanted, StringComparison.OrdinalIgnoreCase);
		}
		return false;
	}

	private static bool IsEquipped(object item)
	{
		if (_equippedField == null)
		{
			return false;
		}
		try
		{
			return Convert.ToBoolean(_equippedField.GetValue(item));
		}
		catch
		{
			return false;
		}
	}

	private static float GetBlockPower(object item)
	{
		try
		{
			if (_getBlockPowerMethod != null)
			{
				ParameterInfo[] parameters = _getBlockPowerMethod.GetParameters();
				int num = ((_qualityField == null) ? 1 : Convert.ToInt32(_qualityField.GetValue(item)));
				if (parameters.Length == 1)
				{
					return Convert.ToSingle(_getBlockPowerMethod.Invoke(item, new object[1] { num }));
				}
			}
			object obj = _sharedField?.GetValue(item);
			float num2 = ((_blockPowerField == null) ? 0f : Convert.ToSingle(_blockPowerField.GetValue(obj)));
			float num3 = ((_blockPowerPerLevelField == null) ? 0f : Convert.ToSingle(_blockPowerPerLevelField.GetValue(obj)));
			int num4 = ((_qualityField == null) ? 1 : Convert.ToInt32(_qualityField.GetValue(item)));
			return num2 + (float)Math.Max(0, num4 - 1) * num3;
		}
		catch
		{
			return 0f;
		}
	}

	private static Type FindNestedType(Type parent, string name)
	{
		if (parent == null)
		{
			return null;
		}
		return parent.GetNestedType(name, BindingFlags.Public | BindingFlags.NonPublic);
	}

	private static Type FindType(string fullName)
	{
		Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly assembly in assemblies)
		{
			try
			{
				Type type = assembly.GetType(fullName, throwOnError: false);
				if (type != null)
				{
					return type;
				}
			}
			catch
			{
			}
		}
		return null;
	}

	private static FieldInfo FindField(Type type, string name)
	{
		if (type == null)
		{
			return null;
		}
		Type type2 = type;
		while (type2 != null)
		{
			FieldInfo field = type2.GetField(name, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
			if (field != null)
			{
				return field;
			}
			type2 = type2.BaseType;
		}
		return null;
	}

	private static MethodInfo FindMethod(Type type, string name, int parameterCount)
	{
		if (type == null)
		{
			return null;
		}
		return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == name && m.GetParameters().Length == parameterCount);
	}

	private static MethodInfo FindMethodByNameContains(Type type, string name, int parameterCount)
	{
		if (type == null)
		{
			return null;
		}
		return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name.IndexOf(name, StringComparison.OrdinalIgnoreCase) >= 0 && m.GetParameters().Length == parameterCount);
	}
}