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;
}
}