Decompiled source of BoatAnchor v1.3.3

BoatAnchor.dll

Decompiled 3 days ago
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("BoatAnchor")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Boat Anchor mod for Valheim")]
[assembly: AssemblyFileVersion("1.3.3.0")]
[assembly: AssemblyInformationalVersion("1.3.3")]
[assembly: AssemblyProduct("BoatAnchor")]
[assembly: AssemblyTitle("BoatAnchor")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.3.3.0")]
[module: UnverifiableCode]
[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 BoatAnchor
{
	[BepInPlugin("com.kalellmodding.BoatAnchor", "Boat Anchor", "1.3.3")]
	public class BoatAnchorPlugin : BaseUnityPlugin
	{
		internal static ManualLogSource Log;

		internal static ConfigEntry<bool> EnableBoatDismantling;

		private Harmony harmony;

		private void Awake()
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			EnableBoatDismantling = ((BaseUnityPlugin)this).Config.Bind<bool>("Boat Dismantling", "Enable", true, "Allow boats to be dismantled with Hammer -> Remove. Removal is blocked while a player is on the boat or its storage contains items. When disabled, Boat Anchor does not touch boat removal at all, so vanilla behavior or other mods (e.g. boat/cart dismantling mods) are free to handle it instead.");
			EnableBoatDismantling.SettingChanged += OnBoatDismantlingSettingChanged;
			harmony = new Harmony("com.kalellmodding.BoatAnchor");
			harmony.PatchAll();
			ApplyBoatDismantlingSetting();
			Log.LogInfo((object)"Boat Anchor 1.3.3 loaded – Hold Shift + E to toggle anchor.");
		}

		private void OnBoatDismantlingSettingChanged(object sender, EventArgs e)
		{
			ApplyBoatDismantlingSetting();
		}

		internal static void ApplyBoatDismantlingSetting()
		{
			if (EnableBoatDismantling == null || !EnableBoatDismantling.Value)
			{
				return;
			}
			Ship[] array = Resources.FindObjectsOfTypeAll<Ship>();
			Ship[] array2 = array;
			foreach (Ship val in array2)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Transform root = ((Component)val).transform.root;
				if ((Object)(object)root == (Object)null)
				{
					continue;
				}
				Piece[] componentsInChildren = ((Component)root).GetComponentsInChildren<Piece>(true);
				Piece[] array3 = componentsInChildren;
				foreach (Piece val2 in array3)
				{
					if ((Object)(object)val2 != (Object)null)
					{
						val2.m_canBeRemoved = true;
					}
				}
			}
		}

		private void OnDestroy()
		{
			if (EnableBoatDismantling != null)
			{
				EnableBoatDismantling.SettingChanged -= OnBoatDismantlingSettingChanged;
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
		}
	}
	public class BoatAnchorBehaviour : MonoBehaviour
	{
		private Ship ship;

		private Rigidbody rb;

		private ZNetView nview;

		private Vector3 anchorWorldPos;

		public bool IsAnchored { get; private set; }

		private void Awake()
		{
			ship = ((Component)this).GetComponent<Ship>();
			rb = ((Component)this).GetComponent<Rigidbody>();
			nview = ((Component)this).GetComponent<ZNetView>();
		}

		public void ToggleAnchor()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nview == (Object)null || !nview.IsValid() || (!nview.IsOwner() && !ZNet.instance.IsServer()))
			{
				return;
			}
			IsAnchored = !IsAnchored;
			if (IsAnchored)
			{
				anchorWorldPos = ((Component)this).transform.position;
				if ((Object)(object)rb != (Object)null)
				{
					rb.linearVelocity = new Vector3(0f, rb.linearVelocity.y, 0f);
					rb.angularVelocity = Vector3.zero;
				}
			}
			nview.GetZDO().Set("BoatAnchored", IsAnchored);
			string text = (IsAnchored ? "Boat anchored" : "Boat unanchored");
			Player localPlayer = Player.m_localPlayer;
			if (localPlayer != null)
			{
				((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}

		private void FixedUpdate()
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: 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_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			if (IsAnchored && !((Object)(object)rb == (Object)null))
			{
				Vector3 position = ((Component)this).transform.position;
				Vector3 linearVelocity = rb.linearVelocity;
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(anchorWorldPos.x - position.x, 0f, anchorWorldPos.z - position.z);
				Vector3 val2 = Vector3.ClampMagnitude(val * 4f, 3f);
				rb.linearVelocity = new Vector3(val2.x, linearVelocity.y, val2.z);
				Vector3 angularVelocity = rb.angularVelocity;
				rb.angularVelocity = new Vector3(angularVelocity.x * 0.92f, angularVelocity.y * 0.1f, angularVelocity.z * 0.92f);
			}
		}

		public void SetAnchoredFromZDO(bool value)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (IsAnchored != value)
			{
				IsAnchored = value;
				if (IsAnchored)
				{
					anchorWorldPos = ((Component)this).transform.position;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Ship), "Awake")]
	public static class Ship_Awake_Patch
	{
		private static void Postfix(Ship __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<BoatAnchorBehaviour>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<BoatAnchorBehaviour>();
			}
		}
	}
	[HarmonyPatch(typeof(ZNetView), "Awake")]
	public static class ZNetView_Awake_Patch
	{
		private static void Postfix(ZNetView __instance)
		{
			if (!((Object)(object)((Component)__instance).GetComponent<Ship>() == (Object)null))
			{
				BoatAnchorBehaviour component = ((Component)__instance).GetComponent<BoatAnchorBehaviour>();
				if (!((Object)(object)component == (Object)null))
				{
					bool anchoredFromZDO = __instance.GetZDO().GetBool("BoatAnchored", false);
					component.SetAnchoredFromZDO(anchoredFromZDO);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	public static class Player_Update_Patch
	{
		private static void Prefix(Player __instance)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)(object)__instance || (!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303)) || !ZInput.GetButtonDown("Use"))
			{
				return;
			}
			GameObject hoverObject = ((Humanoid)__instance).GetHoverObject();
			if (!((Object)(object)hoverObject != (Object)null))
			{
				return;
			}
			ShipControlls component = hoverObject.GetComponent<ShipControlls>();
			if ((Object)(object)component != (Object)null && (Object)(object)component.m_ship != (Object)null)
			{
				BoatAnchorBehaviour component2 = ((Component)component.m_ship).GetComponent<BoatAnchorBehaviour>();
				if ((Object)(object)component2 != (Object)null)
				{
					component2.ToggleAnchor();
				}
			}
		}
	}
	[HarmonyPatch(typeof(Hud), "UpdateCrosshair")]
	public static class Hud_UpdateCrosshair_Patch
	{
		private static void Postfix(Hud __instance, Player player)
		{
			if ((Object)(object)__instance == (Object)null)
			{
				return;
			}
			TMP_Text hoverName = (TMP_Text)(object)__instance.m_hoverName;
			if ((Object)(object)hoverName == (Object)null || (Object)(object)player == (Object)null || (Object)(object)player != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			GameObject hoverObject = ((Humanoid)player).GetHoverObject();
			if ((Object)(object)hoverObject == (Object)null)
			{
				return;
			}
			ShipControlls component = hoverObject.GetComponent<ShipControlls>();
			if ((Object)(object)component == (Object)null || (Object)(object)component.m_ship == (Object)null)
			{
				return;
			}
			BoatAnchorBehaviour component2 = ((Component)component.m_ship).GetComponent<BoatAnchorBehaviour>();
			if (!((Object)(object)component2 == (Object)null))
			{
				string text = (component2.IsAnchored ? "Raise Anchor" : "Anchor Boat");
				string text2 = "[<color=yellow><b>Shift + E</b></color>] " + text;
				string text3 = hoverName.text;
				if (string.IsNullOrEmpty(text3))
				{
					hoverName.text = text2;
				}
				else if (!text3.Contains(text))
				{
					hoverName.text = text3 + "\n" + text2;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Interact")]
	public static class Player_Interact_Patch
	{
		private static bool Prefix(Player __instance, GameObject go, bool hold, bool alt)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (!Input.GetKey((KeyCode)304) && !Input.GetKey((KeyCode)303))
			{
				return true;
			}
			if ((Object)(object)go != (Object)null)
			{
				ShipControlls component = go.GetComponent<ShipControlls>();
				if ((Object)(object)component != (Object)null)
				{
					return false;
				}
			}
			return true;
		}
	}
	[HarmonyPatch(typeof(Piece), "Awake")]
	public static class Piece_Awake_ShipRemovableByHammer_Patch
	{
		private static void Postfix(Piece __instance)
		{
			if (!((Object)(object)__instance == (Object)null) && BoatAnchorPlugin.EnableBoatDismantling != null && BoatAnchorPlugin.EnableBoatDismantling.Value)
			{
				Ship val = BoatDismantlingSafety.FindShipForTransform(((Component)__instance).transform);
				if (!((Object)(object)val == (Object)null))
				{
					__instance.m_canBeRemoved = true;
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "RemovePiece")]
	public static class Player_RemovePiece_BoatSafety_Patch
	{
		private static bool Prefix(Player __instance, ref bool __result)
		{
			if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return true;
			}
			if (BoatAnchorPlugin.EnableBoatDismantling == null || !BoatAnchorPlugin.EnableBoatDismantling.Value)
			{
				return true;
			}
			if (!BoatDismantlingSafety.TryGetHammerTargetBoat(__instance, out var _, out var ship))
			{
				return true;
			}
			if (!BoatDismantlingSafety.CanDismantle(ship, out var warning))
			{
				((Character)__instance).Message((MessageType)2, warning, 0, (Sprite)null, false);
				if (BoatAnchorPlugin.Log != null)
				{
					BoatAnchorPlugin.Log.LogInfo((object)("Blocked boat dismantle: " + warning));
				}
				__result = false;
				return false;
			}
			return true;
		}
	}
	internal static class BoatDismantlingSafety
	{
		internal static bool TryGetHammerTargetBoat(Player player, out Piece piece, out Ship ship)
		{
			piece = null;
			ship = null;
			if ((Object)(object)player == (Object)null)
			{
				return false;
			}
			piece = player.GetHoveringPiece();
			if ((Object)(object)piece == (Object)null)
			{
				return false;
			}
			ship = FindShipForTransform(((Component)piece).transform);
			return (Object)(object)ship != (Object)null;
		}

		internal static Ship FindShipForTransform(Transform source)
		{
			if ((Object)(object)source == (Object)null)
			{
				return null;
			}
			Ship component = ((Component)source).GetComponent<Ship>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			component = ((Component)source).GetComponentInParent<Ship>();
			if ((Object)(object)component != (Object)null)
			{
				return component;
			}
			Transform root = source.root;
			if ((Object)(object)root != (Object)null)
			{
				component = ((Component)root).GetComponentInChildren<Ship>(true);
				if ((Object)(object)component != (Object)null)
				{
					return component;
				}
			}
			return null;
		}

		internal static bool CanDismantle(Ship ship, out string warning)
		{
			warning = null;
			bool flag = IsPlayerOnBoat(ship);
			bool flag2 = HasItemsInBoatStorage(ship);
			if (BoatAnchorPlugin.Log != null)
			{
				BoatAnchorPlugin.Log.LogInfo((object)("Boat dismantle safety check: playerOnBoat=" + flag + ", storageNotEmpty=" + flag2));
			}
			if (flag && flag2)
			{
				warning = "Cannot dismantle boat: a player is on the boat and storage is not empty.";
				return false;
			}
			if (flag)
			{
				warning = "Cannot dismantle boat: a player is on the boat.";
				return false;
			}
			if (flag2)
			{
				warning = "Cannot dismantle boat: boat storage is not empty.";
				return false;
			}
			return true;
		}

		private static bool HasItemsInBoatStorage(Ship ship)
		{
			if ((Object)(object)ship == (Object)null)
			{
				return false;
			}
			Transform root = ((Component)ship).transform.root;
			if ((Object)(object)root == (Object)null)
			{
				return false;
			}
			Container[] componentsInChildren = ((Component)root).GetComponentsInChildren<Container>(true);
			Container[] array = componentsInChildren;
			foreach (Container val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				Inventory inventory = val.GetInventory();
				if (inventory != null)
				{
					int num = inventory.NrOfItems();
					if (BoatAnchorPlugin.Log != null)
					{
						BoatAnchorPlugin.Log.LogInfo((object)("Boat storage check: " + ((Object)((Component)val).gameObject).name + " contains " + num + " item(s)."));
					}
					if (num > 0)
					{
						return true;
					}
				}
			}
			return false;
		}

		private static bool IsPlayerOnBoat(Ship ship)
		{
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: 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_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ship == (Object)null)
			{
				return false;
			}
			if (ship.HasPlayerOnboard())
			{
				return true;
			}
			foreach (Player allPlayer in Player.GetAllPlayers())
			{
				if ((Object)(object)allPlayer == (Object)null || ((Character)allPlayer).IsDead())
				{
					continue;
				}
				Character val = (Character)(object)allPlayer;
				if ((Object)(object)val != (Object)null)
				{
					Ship standingOnShip = val.GetStandingOnShip();
					if ((Object)(object)standingOnShip == (Object)(object)ship)
					{
						return true;
					}
				}
				Ship controlledShip = allPlayer.GetControlledShip();
				if ((Object)(object)controlledShip == (Object)(object)ship)
				{
					return true;
				}
				Vector3 val2 = ((Component)allPlayer).transform.position + Vector3.up * 1f;
				RaycastHit[] array = Physics.RaycastAll(val2, Vector3.down, 4f, -1, (QueryTriggerInteraction)2);
				RaycastHit[] array2 = array;
				for (int i = 0; i < array2.Length; i++)
				{
					RaycastHit val3 = array2[i];
					if (!((Object)(object)((RaycastHit)(ref val3)).collider == (Object)null))
					{
						Ship val4 = FindShipForTransform(((Component)((RaycastHit)(ref val3)).collider).transform);
						if ((Object)(object)val4 == (Object)(object)ship)
						{
							return true;
						}
					}
				}
			}
			return false;
		}
	}
}