Decompiled source of BatteringRamFix v1.0.1

BatteringRamFix.dll

Decompiled a day ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
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("BatteringRamFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyInformationalVersion("1.0.1")]
[assembly: AssemblyProduct("BatteringRamFix")]
[assembly: AssemblyTitle("BatteringRamFix")]
[assembly: AssemblyVersion("1.0.1.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;
		}
	}
}
namespace BatteringRamFixMod
{
	[BepInPlugin("valheim.batteringramfix", "BatteringRamFix", "1.0.1")]
	public sealed class BatteringRamFix : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Piece), "Awake")]
		private static class PieceAwakePatch
		{
			[HarmonyPostfix]
			private static void Postfix(Piece __instance)
			{
				ConfigureRam(__instance);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetSceneAwakePatch
		{
			[HarmonyPostfix]
			private static void Postfix(ZNetScene __instance)
			{
				GameObject prefab = __instance.GetPrefab("BatteringRam");
				if ((Object)(object)prefab != (Object)null)
				{
					ConfigureRam(prefab.GetComponent<Piece>());
				}
			}
		}

		[HarmonyPatch(typeof(Player), "RemovePiece")]
		private static class PlayerRemovePiecePatch
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					ConfigureRam(__instance.GetHoveringPiece());
				}
			}
		}

		[HarmonyPatch(typeof(Player), "Repair", new Type[]
		{
			typeof(ItemData),
			typeof(Piece)
		})]
		private static class PlayerRepairPatch
		{
			[HarmonyPrefix]
			private static bool Prefix(Player __instance, ItemData toolItem, Piece repairPiece)
			{
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !((Character)__instance).InPlaceMode())
				{
					return true;
				}
				if ((Object)(object)repairPiece != (Object)null && repairPiece.m_repairPiece && TryRepairRam(__instance, toolItem, "Player.Repair"))
				{
					return false;
				}
				_insideVanillaPlayerRepair = true;
				return true;
			}

			[HarmonyPostfix]
			private static void Postfix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					_insideVanillaPlayerRepair = false;
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "Repair", new Type[] { })]
		private static class WearNTearRepairPatch
		{
			[HarmonyPostfix]
			private static void Postfix(bool __result)
			{
				if (_insideVanillaPlayerRepair && __result)
				{
					_repairSucceeded = true;
				}
			}
		}

		[HarmonyPatch(typeof(Player), "UpdatePlacement")]
		private static class PlayerUpdatePlacementPatch
		{
			[HarmonyPrefix]
			private static void Prefix(Player __instance)
			{
				if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
				{
					_repairSucceeded = false;
					_insideVanillaPlayerRepair = false;
				}
			}

			[HarmonyPostfix]
			private static void Postfix(Player __instance, bool takeInput)
			{
				if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !takeInput || _repairSucceeded || !((Character)__instance).InPlaceMode() || Hud.IsPieceSelectionVisible() || (!ZInput.GetButtonDown("Attack") && !ZInput.GetButtonDown("JoyPlace")))
				{
					return;
				}
				Piece selectedPiece = __instance.GetSelectedPiece();
				if ((Object)(object)selectedPiece == (Object)null || !selectedPiece.m_repairPiece)
				{
					if ((Object)(object)FindTargetRam(__instance) != (Object)null)
					{
						Trace("UpdatePlacement: aimed at ram but Hammer repair mode is not selected");
					}
					return;
				}
				if (GetRightItemMethod == null)
				{
					Trace("UpdatePlacement: Humanoid.GetRightItem not found");
					return;
				}
				ItemData tool;
				try
				{
					object? obj = GetRightItemMethod.Invoke(__instance, null);
					tool = (ItemData)((obj is ItemData) ? obj : null);
				}
				catch (Exception ex)
				{
					Trace("UpdatePlacement: could not read equipped Hammer: " + ex.Message);
					return;
				}
				TryRepairRam(__instance, tool, "UpdatePlacement");
			}
		}

		public const string ModGuid = "valheim.batteringramfix";

		public const string ModName = "BatteringRamFix";

		public const string ModVersion = "1.0.1";

		private static BatteringRamFix Instance;

		private Harmony _harmony;

		[ThreadStatic]
		private static bool _repairSucceeded;

		[ThreadStatic]
		private static bool _insideVanillaPlayerRepair;

		private static readonly MethodInfo CheckCanRemovePiece = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", new Type[1] { typeof(Piece) }, (Type[])null);

		private static readonly MethodInfo GetBuildStamina = AccessTools.Method(typeof(Player), "GetBuildStamina", Type.EmptyTypes, (Type[])null);

		private static readonly MethodInfo GetRightItemMethod = AccessTools.Method(typeof(Humanoid), "GetRightItem", Type.EmptyTypes, (Type[])null);

		private static int? _ramRaycastMask;

		private static int RamRaycastMask
		{
			get
			{
				if (!_ramRaycastMask.HasValue)
				{
					_ramRaycastMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "vehicle" });
				}
				return _ramRaycastMask.Value;
			}
		}

		private void Awake()
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Expected O, but got Unknown
			Instance = this;
			try
			{
				_harmony = new Harmony("valheim.batteringramfix");
				_harmony.PatchAll(typeof(BatteringRamFix).Assembly);
				((BaseUnityPlugin)this).Logger.LogInfo((object)"BatteringRamFix 1.0.1 loaded (all features enabled; no configuration).");
				if (CheckCanRemovePiece == null)
				{
					((BaseUnityPlugin)this).Logger.LogWarning((object)"CheckCanRemovePiece not found; custom repair will fail closed.");
				}
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Could not install BatteringRamFix patches: " + ex));
			}
		}

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

		private static void Trace(string message)
		{
			if ((Object)(object)Instance != (Object)null)
			{
				((BaseUnityPlugin)Instance).Logger.LogDebug((object)("[Ram repair] " + message));
			}
		}

		private static bool IsRam(Piece piece)
		{
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			string name = ((Object)((Component)piece).gameObject).name;
			if (!string.Equals(name, "BatteringRam", StringComparison.Ordinal))
			{
				return string.Equals(name, "BatteringRam(Clone)", StringComparison.Ordinal);
			}
			return true;
		}

		private static void ConfigureRam(Piece piece)
		{
			if ((Object)(object)piece != (Object)null && IsRam(piece))
			{
				piece.m_canBeRemoved = true;
			}
		}

		private static Piece FindTargetRam(Player player)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			Piece hoveringPiece = player.GetHoveringPiece();
			if (IsRam(hoveringPiece))
			{
				return hoveringPiece;
			}
			if ((Object)(object)GameCamera.instance == (Object)null)
			{
				return null;
			}
			Transform transform = ((Component)GameCamera.instance).transform;
			RaycastHit val = default(RaycastHit);
			if (!Physics.Raycast(transform.position, transform.forward, ref val, 50f, RamRaycastMask))
			{
				return null;
			}
			if (Vector3.Distance(((Character)player).GetEyePoint(), ((RaycastHit)(ref val)).point) > player.m_maxPlaceDistance)
			{
				return null;
			}
			Piece val2 = (((Object)(object)((RaycastHit)(ref val)).collider != (Object)null) ? ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Piece>() : null);
			if (!IsRam(val2))
			{
				return null;
			}
			return val2;
		}

		private static void PlayRamRepairEffect(Player player, Piece target)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_013b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)target == (Object)null || (Object)(object)ZNetScene.instance == (Object)null)
			{
				return;
			}
			Vector3 val = ((Component)target).transform.position + Vector3.up * 1.4f;
			if ((Object)(object)GameCamera.instance != (Object)null)
			{
				Transform transform = ((Component)GameCamera.instance).transform;
				RaycastHit val2 = default(RaycastHit);
				if (Physics.Raycast(transform.position, transform.forward, ref val2, 50f, RamRaycastMask) && (Object)(object)((RaycastHit)(ref val2)).collider != (Object)null && (Object)(object)((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Piece>() == (Object)(object)target && Vector3.Distance(((Character)player).GetEyePoint(), ((RaycastHit)(ref val2)).point) <= player.m_maxPlaceDistance)
				{
					val = ((RaycastHit)(ref val2)).point + ((RaycastHit)(ref val2)).normal * 0.12f;
				}
			}
			GameObject prefab = ZNetScene.instance.GetPrefab("woodwall");
			Piece val3 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
			if ((Object)(object)val3 != (Object)null && val3.m_placeEffect != null && val3.m_placeEffect.m_effectPrefabs != null && val3.m_placeEffect.m_effectPrefabs.Length != 0)
			{
				val3.m_placeEffect.Create(val, Quaternion.identity, (Transform)null, 1f, -1, ((Character)player).GetZDOID());
				Trace("Wood wall repair puff played at ram surface");
				return;
			}
			GameObject prefab2 = ZNetScene.instance.GetPrefab("vfx_Place_wood");
			if ((Object)(object)prefab2 != (Object)null)
			{
				Object.Instantiate<GameObject>(prefab2, val, Quaternion.identity);
				Trace("Wood repair puff played via vfx_Place_wood fallback");
			}
			else
			{
				Trace("Repair succeeded, but woodwall and vfx_Place_wood effects were unavailable");
			}
		}

		private static bool TryRepairRam(Player player, ItemData tool, string source)
		{
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer || !((Character)player).InPlaceMode() || tool == null || tool.m_shared == null || tool.m_shared.m_attack == null)
			{
				return false;
			}
			Piece val = FindTargetRam(player);
			if (!IsRam(val))
			{
				return false;
			}
			bool result = false;
			try
			{
				ConfigureRam(val);
				WearNTear component = ((Component)val).GetComponent<WearNTear>();
				if ((Object)(object)component == (Object)null)
				{
					Trace(source + ": no WearNTear component on ram");
					return false;
				}
				float healthPercentage = component.GetHealthPercentage();
				if (healthPercentage >= 0.99999f)
				{
					Trace(source + ": ram already at full WearNTear health");
					return false;
				}
				if (CheckCanRemovePiece == null)
				{
					Trace(source + ": game access-check method missing");
					return false;
				}
				if (!(bool)CheckCanRemovePiece.Invoke(player, new object[1] { val }))
				{
					Trace(source + ": missing station or other vanilla building restriction");
					return false;
				}
				if (!PrivateArea.CheckAccess(((Component)val).transform.position, 0f, true, false))
				{
					Trace(source + ": blocked by a ward/private area");
					return false;
				}
				float num = tool.m_shared.m_attack.m_attackStamina;
				if (GetBuildStamina != null)
				{
					num = (float)GetBuildStamina.Invoke(player, null);
				}
				if (!((Character)player).HaveStamina(num))
				{
					Trace(source + ": not enough stamina");
					return false;
				}
				if (tool.m_shared.m_useDurability && tool.m_durability <= 0f)
				{
					Trace(source + ": Hammer has no durability");
					return false;
				}
				if (!component.Repair())
				{
					Trace(source + ": WearNTear.Repair() returned false (health=" + healthPercentage.ToString("0.000") + ")");
					return false;
				}
				result = true;
				_repairSucceeded = true;
				((Character)player).UseStamina(num);
				if (tool.m_shared.m_useDurability)
				{
					tool.m_durability -= tool.m_shared.m_useDurabilityDrain;
				}
				try
				{
					PlayRamRepairEffect(player, val);
					((Character)player).Message((MessageType)1, "Battering Ram repaired", 0, (Sprite)null, false);
				}
				catch (Exception ex)
				{
					Trace(source + ": repair succeeded, visual/message failed: " + ex.Message);
				}
				Trace(source + ": repair accepted by WearNTear");
				return true;
			}
			catch (Exception ex2)
			{
				if ((Object)(object)Instance != (Object)null)
				{
					((BaseUnityPlugin)Instance).Logger.LogWarning((object)("[Ram repair] " + source + ": " + ex2));
				}
				return result;
			}
		}
	}
}