Decompiled source of DurabilityBegone v1.0.1

BepInEx/plugins/DurabilityBegone/DurabilityBegone.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace DurabilityBegone;

[BepInPlugin("DurabilityBegone.Valheim", "DurabilityBegone", "1.0.0")]
public sealed class DurabilityBegonePlugin : BaseUnityPlugin
{
	public const string PluginGuid = "DurabilityBegone.Valheim";

	public const string PluginName = "DurabilityBegone";

	public const string PluginVersion = "1.0.0";

	internal static ConfigEntry<bool> EnabledConfig;

	internal static ConfigEntry<bool> AreaRepairEnabledConfig;

	internal static ConfigEntry<float> AreaRepairRadiusConfig;

	private static MethodInfo _wearNTearRepairMethod;

	private static MethodInfo _wearNTearHealthPercentMethod;

	private static MethodInfo _playerRepairMethod;

	private static FieldInfo _hoveringPieceField;

	private static bool _areaRepairRunning = false;

	private static int _areaRepairCount = 0;

	private Harmony _harmony;

	private void Awake()
	{
		//IL_001d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected O, but got Unknown
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Expected O, but got Unknown
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Expected O, but got Unknown
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a6: Expected O, but got Unknown
		EnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Enable or disable DurabilityBegone. When enabled, durability-using items do not lose durability and are kept at maximum durability.", (AcceptableValueBase)null, new object[0]));
		AreaRepairEnabledConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("Area Repair", "Enabled", false, new ConfigDescription("When enabled, using the hammer's normal Repair action also repairs damaged build pieces around the piece you repaired.", (AcceptableValueBase)null, new object[0]));
		AreaRepairRadiusConfig = ((BaseUnityPlugin)this).Config.Bind<float>("Area Repair", "Repair Radius (m)", 10f, new ConfigDescription("Radius in meters for hammer area repair.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 30f), new object[0]));
		_harmony = new Harmony("DurabilityBegone.Valheim");
		PatchDurabilityLoss();
		PatchHammerRepair();
		((BaseUnityPlugin)this).Logger.LogInfo((object)"DurabilityBegone 1.0.0 loaded.");
	}

	private void PatchDurabilityLoss()
	{
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Expected O, but got Unknown
		MethodInfo methodInfo = AccessTools.Method(typeof(ItemData), "SetDurability", new Type[1] { typeof(float) }, (Type[])null);
		if (methodInfo != null)
		{
			MethodInfo methodInfo2 = AccessTools.Method(typeof(DurabilityBegonePlugin), "SetDurabilityPrefix", (Type[])null, (Type[])null);
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Patched ItemData.SetDurability(float).");
		}
		else
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)"ItemData.SetDurability(float) was not found. The safety repair pass will still run.");
		}
		PatchSkipMethod(typeof(Player), "DrainEquipedItemDurability");
		PatchSkipMethod(typeof(Player), "DamageArmorDurability");
	}

	private void PatchHammerRepair()
	{
		//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ff: Expected O, but got Unknown
		//IL_016d: Unknown result type (might be due to invalid IL or missing references)
		//IL_017a: Expected O, but got Unknown
		try
		{
			_playerRepairMethod = AccessTools.Method(typeof(Player), "Repair", new Type[2]
			{
				typeof(ItemData),
				typeof(Piece)
			}, (Type[])null);
			_hoveringPieceField = AccessTools.Field(typeof(Player), "m_hoveringPiece");
			_wearNTearRepairMethod = AccessTools.Method(typeof(WearNTear), "Repair", Type.EmptyTypes, (Type[])null);
			_wearNTearHealthPercentMethod = AccessTools.Method(typeof(WearNTear), "GetHealthPercentage", Type.EmptyTypes, (Type[])null);
			MethodInfo methodInfo = AccessTools.Method(typeof(DurabilityBegonePlugin), "PlayerRepairPostfix", (Type[])null, (Type[])null);
			MethodInfo[] methods = typeof(Player).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			int num = 0;
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2 == null) && !(methodInfo2.Name != "Repair"))
				{
					try
					{
						_harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
						num++;
					}
					catch (Exception ex)
					{
						((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch Player.Repair overload: " + ex.Message));
					}
				}
			}
			MethodInfo methodInfo3 = AccessTools.Method(typeof(DurabilityBegonePlugin), "WearNTearRepairPostfix", (Type[])null, (Type[])null);
			if (_wearNTearRepairMethod != null && methodInfo3 != null)
			{
				_harmony.Patch((MethodBase)_wearNTearRepairMethod, (HarmonyMethod)null, new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (num > 0)
			{
				((BaseUnityPlugin)this).Logger.LogInfo((object)("Area Repair hooked to " + num + " Player.Repair method(s)."));
			}
			else
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"No Player.Repair method was found.");
			}
			if (_playerRepairMethod == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Player.Repair(ItemData, Piece) was not found.");
			}
			if (_hoveringPieceField == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)"Player.m_hoveringPiece was not found.");
			}
		}
		catch (Exception ex2)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not initialize Area Repair: " + ex2.Message));
		}
	}

	private void PatchSkipMethod(Type type, string methodName)
	{
		//IL_004d: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Expected O, but got Unknown
		try
		{
			MethodInfo methodInfo = AccessTools.Method(type, methodName, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				((BaseUnityPlugin)this).Logger.LogWarning((object)(methodName + " was not found."));
				return;
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(DurabilityBegonePlugin), "SkipDurabilityMethodPrefix", (Type[])null, (Type[])null);
			_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Patched " + type.Name + "." + methodName + "."));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch " + methodName + ": " + ex.Message));
		}
	}

	private void OnDestroy()
	{
		try
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
	}

	private static void SetDurabilityPrefix(ItemData __instance, ref float __0)
	{
		if (EnabledConfig != null && EnabledConfig.Value && __instance != null)
		{
			float maxDurability = __instance.GetMaxDurability();
			if (maxDurability > 0f && __0 < maxDurability)
			{
				__0 = maxDurability;
			}
		}
	}

	private static bool SkipDurabilityMethodPrefix()
	{
		if (EnabledConfig != null)
		{
			return !EnabledConfig.Value;
		}
		return true;
	}

	private static void PlayerRepairPostfix(Player __instance, object[] __args)
	{
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		if (_areaRepairRunning || EnabledConfig == null || !EnabledConfig.Value || AreaRepairEnabledConfig == null || !AreaRepairEnabledConfig.Value || AreaRepairRadiusConfig == null || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || _playerRepairMethod == null || _hoveringPieceField == null)
		{
			return;
		}
		try
		{
			ItemData val = null;
			Piece val2 = null;
			if (__args != null)
			{
				for (int i = 0; i < __args.Length; i++)
				{
					if (val == null)
					{
						object obj = __args[i];
						val = (ItemData)((obj is ItemData) ? obj : null);
					}
					if ((Object)(object)val2 == (Object)null)
					{
						object obj2 = __args[i];
						val2 = (Piece)((obj2 is Piece) ? obj2 : null);
					}
				}
			}
			if (val == null)
			{
				return;
			}
			Piece val3 = null;
			try
			{
				val3 = __instance.GetHoveringPiece();
			}
			catch
			{
			}
			if ((Object)(object)val3 == (Object)null)
			{
				val3 = val2;
			}
			Vector3 val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).transform.position : ((Component)__instance).transform.position);
			float num = Mathf.Clamp(AreaRepairRadiusConfig.Value, 5f, 30f);
			List<Piece> list = new List<Piece>();
			Piece.GetAllPiecesInRadius(val4, num, list);
			if (list.Count == 0)
			{
				ShowAreaRepairCount(__instance, 0);
				return;
			}
			object? value = _hoveringPieceField.GetValue(__instance);
			Piece value2 = (Piece)((value is Piece) ? value : null);
			_areaRepairRunning = true;
			_areaRepairCount = 0;
			try
			{
				for (int j = 0; j < list.Count; j++)
				{
					Piece val5 = list[j];
					if ((Object)(object)val5 == (Object)null || ((Object)(object)val3 != (Object)null && (Object)(object)val5 == (Object)(object)val3))
					{
						continue;
					}
					try
					{
						float attackStamina = val.m_shared.m_attack.m_attackStamina;
						if (!((Character)__instance).HaveStamina(attackStamina) || (val.m_shared.m_useDurability && val.m_durability <= 0f))
						{
							break;
						}
						goto IL_01ae;
					}
					catch
					{
						goto IL_01ae;
					}
					IL_01ae:
					_hoveringPieceField.SetValue(__instance, val5);
					try
					{
						_playerRepairMethod.Invoke(__instance, new object[2] { val, val2 });
					}
					catch
					{
					}
				}
			}
			finally
			{
				_hoveringPieceField.SetValue(__instance, value2);
				_areaRepairRunning = false;
			}
			ShowAreaRepairCount(__instance, _areaRepairCount);
		}
		catch (Exception ex)
		{
			_areaRepairRunning = false;
			Logger.CreateLogSource("DurabilityBegone.AreaRepair").LogWarning((object)("Area Repair failed: " + ex));
		}
	}

	private static void WearNTearRepairPostfix(bool __result)
	{
		if (_areaRepairRunning && __result)
		{
			_areaRepairCount++;
		}
	}

	private static void ShowAreaRepairCount(Player player, int count)
	{
		if (!((Object)(object)player == (Object)null))
		{
			((Character)player).Message((MessageType)2, "Area Repair: " + count + ((count == 1) ? " piece repaired" : " pieces repaired"), 0, (Sprite)null, false);
		}
	}

	private static bool IsDamaged(WearNTear wear)
	{
		if ((Object)(object)wear == (Object)null)
		{
			return false;
		}
		if (_wearNTearHealthPercentMethod == null)
		{
			return true;
		}
		try
		{
			object obj = _wearNTearHealthPercentMethod.Invoke(wear, null);
			if (obj is float)
			{
				return (float)obj < 0.9999f;
			}
		}
		catch
		{
		}
		return true;
	}

	private void LateUpdate()
	{
		if (EnabledConfig == null || !EnabledConfig.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			return;
		}
		Inventory inventory = ((Humanoid)localPlayer).GetInventory();
		if (inventory == null)
		{
			return;
		}
		List<ItemData> allItems = inventory.GetAllItems();
		if (allItems == null)
		{
			return;
		}
		for (int i = 0; i < allItems.Count; i++)
		{
			ItemData val = allItems[i];
			if (val != null && val.m_shared != null && val.m_shared.m_useDurability)
			{
				float maxDurability = val.GetMaxDurability();
				if (maxDurability > 0f && val.m_durability != maxDurability)
				{
					val.m_durability = maxDurability;
				}
			}
		}
	}
}