Decompiled source of MastercraftHammer v1.0.1

MastercraftHammer.dll

Decompiled 5 months ago
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("MastercraftHammer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Riintouge")]
[assembly: AssemblyProduct("MastercraftHammer")]
[assembly: AssemblyCopyright("Copyright © 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("32bb953c-6574-411a-b1e4-d82bec00fcd0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.1.0")]
namespace MastercraftHammer;

[BepInPlugin("com.riintouge.mastercrafthammer", "Mastercraft Hammer", "1.0.1")]
[BepInProcess("valheim.exe")]
public class MastercraftHammer : BaseUnityPlugin
{
	[HarmonyPatch(typeof(WearNTear))]
	private class WearNTearPatch
	{
		internal static List<uint> WornNTorn = new List<uint>();

		private static readonly float[] DamageStateMultipliers = new float[4] { 0f, 0.25f, 0.75f, 1f };

		private static bool DoesMaterialPassFilter(MaterialType materialType)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Invalid comparison between Unknown and I4
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Invalid comparison between Unknown and I4
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Invalid comparison between Unknown and I4
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (((int)materialType != 3 || !IncludeHardWood.Value) && ((int)materialType != 2 || !IncludeIron.Value) && ((int)materialType != 4 || !IncludeMarble.Value) && ((int)materialType != 1 || !IncludeStone.Value))
			{
				if ((int)materialType == 0)
				{
					return IncludeWood.Value;
				}
				return false;
			}
			return true;
		}

		private static float? GetRandomHealth(WearNTear instance, bool forPlacement)
		{
			int[] array = new int[4]
			{
				(!forPlacement && AllowDestruction.Value) ? DestructionRatio.Value : 0,
				AllowBroken.Value ? BrokenRatio.Value : 0,
				AllowWorn.Value ? WornRatio.Value : 0,
				AllowNew.Value ? NewRatio.Value : 0
			};
			int num = 0;
			int[] array2 = array;
			foreach (int num2 in array2)
			{
				num += num2;
			}
			if (num == 0)
			{
				return null;
			}
			int num3 = Random.Range(0, num);
			int num4 = 0;
			for (int j = 0; j < array.Length; j++)
			{
				num4 += array[j];
				if (num3 < num4)
				{
					return Mathf.Floor(instance.m_health * DamageStateMultipliers[j]);
				}
			}
			return null;
		}

		private static void RandomizeHealth(WearNTear instance, ZNetView netView, bool forPlacement)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			ZDO zDO = netView.GetZDO();
			if (!DoesMaterialPassFilter(instance.m_materialType) || (EnableSingleTouch.Value && WornNTorn.Contains(((ZDOID)(ref zDO.m_uid)).ID)))
			{
				return;
			}
			float num = GetRandomHealth(instance, forPlacement) ?? instance.m_health;
			if (num == 0f)
			{
				instance.Remove();
				return;
			}
			if (EnableSingleTouch.Value)
			{
				WornNTorn.Add(((ZDOID)(ref zDO.m_uid)).ID);
			}
			if (num != zDO.GetFloat("health", instance.m_health))
			{
				zDO.Set("health", num);
				netView.InvokeRPC(ZNetView.Everybody, "WNTHealthChanged", new object[1] { num });
			}
		}

		[HarmonyPatch("OnPlaced")]
		[HarmonyPostfix]
		private static void OnPlacedPostfix(ref WearNTear __instance, ref ZNetView ___m_nview)
		{
			if (IsEnabled.Value && RandomizeStateOnPlacement.Value)
			{
				RandomizeHealth(__instance, ___m_nview, forPlacement: true);
			}
		}

		[HarmonyPatch("Remove")]
		[HarmonyPrefix]
		private static void RemovePrefix(ref WearNTear __instance, ref ZNetView ___m_nview, out uint __state)
		{
			__state = ((ZDOID)(ref ___m_nview.GetZDO().m_uid)).ID;
		}

		[HarmonyPatch("Remove")]
		[HarmonyPostfix]
		private static void RemovePostfix(ref WearNTear __instance, ref ZNetView ___m_nview, ref uint __state)
		{
			WornNTorn.Remove(__state);
		}

		[HarmonyPatch("Repair")]
		[HarmonyTranspiler]
		private static IEnumerable<CodeInstruction> RepairPatch(IEnumerable<CodeInstruction> instructionsIn)
		{
			List<CodeInstruction> list = new List<CodeInstruction>(instructionsIn);
			int num = -1;
			for (int i = 0; i + 3 < list.Count; i++)
			{
				if (num != -1 && list[i].opcode == OpCodes.Ldfld && list[i + 1].opcode == OpCodes.Blt_Un && list[i + 2].opcode == OpCodes.Ldc_I4_0 && list[i + 3].opcode == OpCodes.Ret)
				{
					if (((FieldInfo)list[i].operand).Name == "m_health")
					{
						for (int j = num + 1; j <= i + 3; j++)
						{
							list[j].opcode = OpCodes.Nop;
						}
					}
				}
				else if (list[i].opcode == OpCodes.Ret)
				{
					num = i;
				}
			}
			return list;
		}

		[HarmonyPatch("Repair")]
		[HarmonyPrefix]
		private static bool RepairPrefix(ref WearNTear __instance, ref ZNetView ___m_nview, ref bool __result)
		{
			if (!IsEnabled.Value && ___m_nview.IsValid() && ___m_nview.GetZDO().GetFloat("health", __instance.m_health) >= __instance.m_health)
			{
				__result = false;
				return false;
			}
			return true;
		}

		[HarmonyPatch("RPC_Repair")]
		[HarmonyPrefix]
		private static bool RPC_RepairPrefix(ref WearNTear __instance, ref ZNetView ___m_nview, ref long sender)
		{
			if (IsEnabled.Value && RandomizeStateOnRepair.Value && sender == ZDOMan.GetSessionID() && ___m_nview.IsValid() && ___m_nview.IsOwner() && Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer() && ZNet.instance.GetPeerConnections() == 0 && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				RandomizeHealth(__instance, ___m_nview, forPlacement: false);
				return false;
			}
			return true;
		}
	}

	public static ConfigEntry<bool> IsEnabled;

	public static ConfigEntry<bool> LoadOnStart;

	public static ConfigEntry<bool> RandomizeStateOnPlacement;

	public static ConfigEntry<bool> RandomizeStateOnRepair;

	public static ConfigEntry<bool> IncludeHardWood;

	public static ConfigEntry<bool> IncludeIron;

	public static ConfigEntry<bool> IncludeMarble;

	public static ConfigEntry<bool> IncludeStone;

	public static ConfigEntry<bool> IncludeWood;

	public static ConfigEntry<bool> EnableSingleTouch;

	public static ConfigEntry<bool> ResetSingleTouch;

	public static ConfigEntry<bool> AllowNew;

	public static ConfigEntry<int> NewRatio;

	public static ConfigEntry<bool> AllowWorn;

	public static ConfigEntry<int> WornRatio;

	public static ConfigEntry<bool> AllowBroken;

	public static ConfigEntry<int> BrokenRatio;

	public static ConfigEntry<bool> AllowDestruction;

	public static ConfigEntry<int> DestructionRatio;

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

	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.");
		RandomizeStateOnPlacement = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "RandomizeOnPlacement", false, "Affect objects newly placed into the world.");
		RandomizeStateOnRepair = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "RandomizeOnRepair", false, "Affect objects undergoing repairs. Only works in singleplayer!");
		IncludeHardWood = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Filter", "IncludeHardWood", true, "Affect hardwood objects.");
		IncludeIron = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Filter", "IncludeIron", true, "Affect iron objects.");
		IncludeMarble = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Filter", "IncludeMarble", true, "Affect marble objects.");
		IncludeStone = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Filter", "IncludeStone", true, "Affect stone objects.");
		IncludeWood = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Filter", "IncludeWood", true, "Affect wooden objects.");
		EnableSingleTouch = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Single Touch", "EnableSingleTouch", false, "Prevent objects from being affected more than once during a single session. Does not persist.");
		ResetSingleTouch = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Single Touch", "ResetSingleTouch", false, "Toggle to true to reset the list of single-touched objects.");
		AllowNew = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - New", "AllowNew", true, "Whether objects may be fully restored.");
		NewRatio = ((BaseUnityPlugin)this).Config.Bind<int>("4 - New", "NewRatio", 1, "The Value:X chance, where X is the sum of allowed ratios, the object will be fully restored.");
		AllowWorn = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Worn", "AllowWorn", true, "Whether objects may be made to appear worn.");
		WornRatio = ((BaseUnityPlugin)this).Config.Bind<int>("5 - Worn", "WornRatio", 1, "The Value:X chance, where X is the sum of allowed ratios, the object will be made to appear worn.");
		AllowBroken = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Broken", "AllowBroken", true, "Whether objects may be made to appear broken.");
		BrokenRatio = ((BaseUnityPlugin)this).Config.Bind<int>("6 - Broken", "BrokenRatio", 1, "The Value:X chance, where X is the sum of allowed ratios, the object will be made to appear broken.");
		AllowDestruction = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Destruction", "AllowDestruction", false, "Whether objects may be destroyed completely. Use with caution! There is no undo.");
		DestructionRatio = ((BaseUnityPlugin)this).Config.Bind<int>("7 - Destruction", "DestructionRatio", 0, "The Value:X chance, where X is the sum of allowed ratios, the object will be destroyed.");
		if (LoadOnStart.Value)
		{
			Harmony.PatchAll();
			AllowDestruction.Value = false;
			DestructionRatio.Value = 0;
			ResetSingleTouch.Value = false;
			((BaseUnityPlugin)this).Config.SettingChanged += Config_SettingChanged;
		}
	}

	private void Config_SettingChanged(object sender, SettingChangedEventArgs e)
	{
		if (e.ChangedSetting == ResetSingleTouch && ResetSingleTouch.Value)
		{
			WearNTearPatch.WornNTorn.Clear();
			((MonoBehaviour)this).StartCoroutine("DelayResetResetSingleTouch");
		}
	}

	private IEnumerator DelayResetResetSingleTouch()
	{
		yield return (object)new WaitForSecondsRealtime(0.1f);
		ResetSingleTouch.Value = false;
	}
}