Decompiled source of RustyHeathensWarShips v0.1.3

plugins/RustyHeathensWarShips/RustyHeathensWarShips.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Rusty Heathens War Ships")]
[assembly: AssemblyFileVersion("0.1.3.0")]
[assembly: AssemblyVersion("0.1.3.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 RustyHeathens.ShipBallista
{
	public sealed class MountedBallista : MonoBehaviour, IPlaced, IDoodadController
	{
		internal static readonly List<MountedBallista> All = new List<MountedBallista>();

		private const string ParentKey = "RHSB.Ship.v1";

		private const string PositionKey = "RHSB.Position.v1";

		private const string RotationKey = "RHSB.Rotation.v1";

		private const string ShipGuidKey = "RHSB.ParentGuid.v1";

		private const string GunnerKey = "RHSB.Gunner.v1";

		private const string YawKey = "RHSB.Yaw.v1";

		private const string PitchKey = "RHSB.Pitch.v1";

		private const string RequestRpc = "RHSB.Request.v1";

		private const string ReplyRpc = "RHSB.Reply.v1";

		private const string InputRpc = "RHSB.Input.v1";

		private const string ReleaseRpc = "RHSB.Release.v1";

		private const string DestroyRpc = "RHSB.ShipGone.v1";

		internal ZNetView View;

		internal Ship Ship;

		internal GameObject LastInheritedProjectile;

		private Turret turret;

		private WearNTear wear;

		private Rigidbody body;

		private Transform seat;

		private Collider[] colliders;

		private Renderer[] renderers;

		private bool[] colliderEnabled;

		private bool[] rendererEnabled;

		private bool visible = true;

		private bool wasOwner;

		private long parentPeer;

		private float nextPosition;

		private float nextInput;

		private float pendingUntil;

		private float lastPacketTime;

		private float localSince;

		private float weaponInputAt;

		private float yaw;

		private float pitch;

		private float inputYaw;

		private float inputPitch;

		private bool fire;

		private bool aimOutside;

		private bool capturedFire;

		private bool linkLogged;

		private bool legacyWarning;

		private Player local;

		private int localToken;

		private readonly ExitKeyLatch exitKey = new ExitKeyLatch();

		private readonly ControlLease lease = new ControlLease(Guid.NewGuid().GetHashCode());

		private static readonly MethodInfo DestroyPiece = AccessTools.Method(typeof(WearNTear), "Destroy", new Type[2]
		{
			typeof(HitData),
			typeof(bool)
		}, (Type[])null);

		internal ZDOID ParentId
		{
			get
			{
				//IL_001a: 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_005f: Unknown result type (might be due to invalid IL or missing references)
				if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
				{
					return ZDOID.None;
				}
				ZDO zDO = View.GetZDO();
				string text = zDO.GetString("RHSB.ParentGuid.v1", "");
				if (!string.IsNullOrEmpty(text))
				{
					Ship val = ShipIdentity.Find(text);
					if (Object.op_Implicit((Object)(object)val))
					{
						return ((Component)val).GetComponent<ZNetView>().GetZDO().m_uid;
					}
				}
				return zDO.GetZDOID("RHSB.Ship.v1");
			}
		}

		private bool PersistentParent
		{
			get
			{
				if (Object.op_Implicit((Object)(object)View) && View.IsValid())
				{
					return !string.IsNullOrEmpty(View.GetZDO().GetString("RHSB.ParentGuid.v1", ""));
				}
				return false;
			}
		}

		internal bool Mounted
		{
			get
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000e: Unknown result type (might be due to invalid IL or missing references)
				if (!PersistentParent)
				{
					return ParentId != ZDOID.None;
				}
				return true;
			}
		}

		internal bool Ready
		{
			get
			{
				if (Mounted && Object.op_Implicit((Object)(object)Ship))
				{
					return ((Component)Ship).GetComponent<ZNetView>().IsValid();
				}
				return false;
			}
		}

		internal bool Manual
		{
			get
			{
				if (Mounted)
				{
					return View.GetZDO().GetLong("RHSB.Gunner.v1", 0L) != 0;
				}
				return false;
			}
		}

		private double Now
		{
			get
			{
				if (!Object.op_Implicit((Object)(object)ZNet.instance))
				{
					return Time.realtimeSinceStartup;
				}
				return ZNet.instance.GetTimeSeconds();
			}
		}

		private float YawLimit
		{
			get
			{
				if (!Manual)
				{
					if (!(turret.m_horizontalAngle < 0f))
					{
						return Mathf.Min(180f, turret.m_horizontalAngle);
					}
					return 180f;
				}
				return 180f;
			}
		}

		private void Awake()
		{
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			turret = ((Component)this).GetComponent<Turret>();
			wear = ((Component)this).GetComponent<WearNTear>();
			View = ((Component)this).GetComponent<ZNetView>();
			if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
			{
				((Behaviour)this).enabled = false;
				return;
			}
			wasOwner = false;
			if (Mounted && Object.op_Implicit((Object)(object)wear))
			{
				wear.m_noSupportWear = false;
				wear.m_staticPosition = false;
			}
			View.Register<long>("RHSB.Request.v1", (Action<long, long>)ReceiveRequest);
			View.Register<long, bool, int>("RHSB.Reply.v1", (Action<long, long, bool, int>)ReceiveReply);
			View.Register<ZPackage>("RHSB.Input.v1", (Action<long, ZPackage>)ReceiveInput);
			View.Register<long, int>("RHSB.Release.v1", (Action<long, long, int>)ReceiveRelease);
			View.Register<ZDOID>("RHSB.ShipGone.v1", (Action<long, ZDOID>)ReceiveParentDestroyed);
			GameObject val = new GameObject("RHSB_Gunner");
			val.transform.SetParent(((Component)this).transform, false);
			seat = val.transform;
			seat.localPosition = new Vector3(0f, 0.05f, -1.35f);
			colliders = ((Component)this).GetComponentsInChildren<Collider>(true);
			renderers = ((Component)this).GetComponentsInChildren<Renderer>(true);
			colliderEnabled = new bool[colliders.Length];
			for (int i = 0; i < colliders.Length; i++)
			{
				colliderEnabled[i] = colliders[i].enabled;
			}
			rendererEnabled = new bool[renderers.Length];
			for (int j = 0; j < renderers.Length; j++)
			{
				rendererEnabled[j] = renderers[j].enabled;
			}
			All.Add(this);
		}

		public void OnPlaced()
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			if (Mounted)
			{
				return;
			}
			Ship placingOn = Plugin.PlacingOn;
			if (!Object.op_Implicit((Object)(object)placingOn) || !Object.op_Implicit((Object)(object)View) || !View.IsValid() || !View.IsOwner())
			{
				return;
			}
			ZNetView component = ((Component)placingOn).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid())
			{
				ZDO zDO = View.GetZDO();
				string text = ShipIdentity.Ensure(placingOn);
				if (string.IsNullOrEmpty(text))
				{
					Plugin.LogMount("Ship identity not ready; mount binding deferred.");
					return;
				}
				zDO.Set("RHSB.ParentGuid.v1", text);
				zDO.Set("RHSB.Ship.v1", component.GetZDO().m_uid);
				zDO.Set("RHSB.Position.v1", ((Component)placingOn).transform.InverseTransformPoint(((Component)this).transform.position));
				Vector3 val = Vector3.ProjectOnPlane(((Component)this).transform.forward, ((Component)placingOn).transform.up);
				Quaternion val2 = Quaternion.LookRotation(((Vector3)(ref val)).normalized, ((Component)placingOn).transform.up);
				zDO.Set("RHSB.Rotation.v1", Quaternion.Inverse(((Component)placingOn).transform.rotation) * val2);
				zDO.Set("RHSB.Gunner.v1", 0L);
				Ship = placingOn;
				SetupMovingBody();
				Follow();
				Plugin.LogMount("Mounted ballista on " + ((Object)((Component)placingOn).gameObject).name + " at local " + ((object)zDO.GetVec3("RHSB.Position.v1", Vector3.zero)/*cast due to .constrained prefix*/).ToString());
			}
		}

		private void SetupMovingBody()
		{
			if (!Object.op_Implicit((Object)(object)body))
			{
				body = ((Component)this).GetComponent<Rigidbody>();
				if (!Object.op_Implicit((Object)(object)body))
				{
					body = ((Component)this).gameObject.AddComponent<Rigidbody>();
				}
			}
			body.isKinematic = true;
			body.useGravity = false;
			if (Object.op_Implicit((Object)(object)wear))
			{
				wear.m_noSupportWear = false;
				wear.m_staticPosition = false;
				Plugin.ProvideShipSupport(wear, this);
			}
			ZSyncTransform component = ((Component)this).GetComponent<ZSyncTransform>();
			if (Object.op_Implicit((Object)(object)component))
			{
				((Behaviour)component).enabled = false;
			}
			Collider[] componentsInChildren = ((Component)Ship).GetComponentsInChildren<Collider>(true);
			Collider[] array = colliders;
			foreach (Collider val in array)
			{
				if (!Object.op_Implicit((Object)(object)val))
				{
					continue;
				}
				Collider[] array2 = componentsInChildren;
				foreach (Collider val2 in array2)
				{
					if (Object.op_Implicit((Object)(object)val2) && (Object)(object)val != (Object)(object)val2)
					{
						Physics.IgnoreCollision(val, val2, true);
					}
				}
			}
		}

		private void Follow()
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0204: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_020e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0213: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_022c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0231: Unknown result type (might be due to invalid IL or missing references)
			//IL_0236: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0245: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0280: Unknown result type (might be due to invalid IL or missing references)
			//IL_0289: Unknown result type (might be due to invalid IL or missing references)
			if (!Mounted || !Object.op_Implicit((Object)(object)ZNetScene.instance))
			{
				return;
			}
			GameObject val = ZNetScene.instance.FindInstance(ParentId);
			Ship val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Ship>() : null);
			string text = View.GetZDO().GetString("RHSB.ParentGuid.v1", "");
			if (!string.IsNullOrEmpty(text))
			{
				val2 = ShipIdentity.Find(text);
			}
			if (Object.op_Implicit((Object)(object)val2) && Rules.SupportedShip(((Object)((Component)val2).gameObject).name))
			{
				if (!PersistentParent)
				{
					if (Vector3.Distance(((Component)val2).transform.TransformPoint(View.GetZDO().GetVec3("RHSB.Position.v1", Vector3.zero)), ((Component)this).transform.position) > 2f)
					{
						MissingParent();
						return;
					}
					string text2 = ShipIdentity.Ensure(val2);
					if (string.IsNullOrEmpty(text2))
					{
						MissingParent();
						return;
					}
					if (View.IsOwner())
					{
						View.GetZDO().Set("RHSB.ParentGuid.v1", text2);
					}
				}
				if ((Object)(object)Ship != (Object)(object)val2 || !Object.op_Implicit((Object)(object)body))
				{
					Ship = val2;
					SetupMovingBody();
				}
				if (!linkLogged)
				{
					linkLogged = true;
					Plugin.LogMount("Restored ship attachment on " + ((Object)((Component)val2).gameObject).name + "; persistent=" + PersistentParent);
				}
				ZNetView component = ((Component)Ship).GetComponent<ZNetView>();
				if (!Object.op_Implicit((Object)(object)component) || !component.IsValid())
				{
					SetVisible(show: false);
					return;
				}
				parentPeer = component.GetZDO().GetOwner();
				ZDO zDO = View.GetZDO();
				if (View.IsOwner() && zDO.GetZDOID("RHSB.Ship.v1") != component.GetZDO().m_uid)
				{
					zDO.Set("RHSB.Ship.v1", component.GetZDO().m_uid);
				}
				Vector3 val3 = ((Component)Ship).transform.TransformPoint(zDO.GetVec3("RHSB.Position.v1", Vector3.zero));
				Quaternion val4 = ((Component)Ship).transform.rotation * zDO.GetQuaternion("RHSB.Rotation.v1", Quaternion.identity);
				((Component)this).transform.SetPositionAndRotation(val3, val4);
				SetVisible(show: true);
				if (View.IsOwner() && Time.unscaledTime >= nextPosition)
				{
					nextPosition = Time.unscaledTime + 0.2f;
					zDO.SetPosition(val3);
					zDO.SetRotation(val4);
				}
			}
			else
			{
				MissingParent();
			}
		}

		private void MissingParent()
		{
			Ship = null;
			StopLocal();
			bool flag = !PersistentParent;
			SetVisible(flag);
			if (flag && !legacyWarning)
			{
				legacyWarning = true;
				Plugin.LogMount("Legacy ship link is unavailable. Remove/rebuild this ballista once to establish a persistent connection.");
			}
		}

		private void SetVisible(bool show)
		{
			if (visible == show)
			{
				return;
			}
			visible = show;
			for (int i = 0; i < colliders.Length; i++)
			{
				if (Object.op_Implicit((Object)(object)colliders[i]))
				{
					colliders[i].enabled = show && colliderEnabled[i];
				}
			}
			for (int j = 0; j < renderers.Length; j++)
			{
				if (Object.op_Implicit((Object)(object)renderers[j]))
				{
					renderers[j].enabled = show && rendererEnabled[j];
				}
			}
		}

		private void FixedUpdate()
		{
			if (Mounted)
			{
				Follow();
			}
		}

		private void LateUpdate()
		{
			if (Mounted)
			{
				Follow();
			}
		}

		private bool OwnerReady()
		{
			if (!Object.op_Implicit((Object)(object)View) || !View.IsValid())
			{
				return false;
			}
			bool flag = View.IsOwner();
			if (flag != wasOwner)
			{
				wasOwner = flag;
				lease.Clear();
				fire = false;
				if (flag)
				{
					View.GetZDO().Set("RHSB.Gunner.v1", 0L);
				}
			}
			if (flag)
			{
				return Ready;
			}
			return false;
		}

		internal void TickOwner()
		{
			if (!Mounted)
			{
				return;
			}
			Follow();
			if (OwnerReady())
			{
				turret.m_targetPlayers = false;
				turret.m_targetTamed = false;
				turret.m_targetTamedConfig = false;
				turret.m_targetEnemies = true;
				if (lease.Player != 0L && (!lease.Active(Now) || !ValidPawn(lease.Player, lease.Peer)))
				{
					ClearLease();
				}
				if (lease.Active(Now))
				{
					Plugin.ClearTarget(turret);
				}
			}
		}

		private bool ValidPawn(long playerId, long peer)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			Player player = Player.GetPlayer(playerId);
			if (!Object.op_Implicit((Object)(object)player) || ((Character)player).IsDead() || !Ready)
			{
				return false;
			}
			ZNetView component = ((Component)player).GetComponent<ZNetView>();
			if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.GetZDO().GetOwner() == peer && Vector3.Distance(((Component)player).transform.position, seat.position) <= 4f)
			{
				return Ship.IsPlayerInBoat(player);
			}
			return false;
		}

		internal void Request(Player player)
		{
			if (!((Object)(object)player != (Object)(object)Player.m_localPlayer))
			{
				if (!Ready)
				{
					Plugin.Tell("Ship link unavailable. Rebuild this older ballista once.");
					return;
				}
				if (player.GetDoodadController() != null || ((Character)player).IsAttached())
				{
					Plugin.Tell("Leave the helm or seat before operating the ballista.");
					return;
				}
				if ((Object)(object)((Character)player).GetStandingOnShip() != (Object)(object)Ship)
				{
					Plugin.Tell("Stand on the ship near the ballista.");
					return;
				}
				pendingUntil = Time.unscaledTime + 3f;
				Plugin.LogMount("Manual control requested by " + player.GetPlayerName());
				View.InvokeRPC("RHSB.Request.v1", new object[1] { player.GetPlayerID() });
			}
		}

		private void ReceiveRequest(long sender, long playerId)
		{
			if (OwnerReady())
			{
				bool flag = lease.Acquire(playerId, sender, Now, ValidPawn(playerId, sender));
				if (flag)
				{
					View.GetZDO().Set("RHSB.Gunner.v1", playerId);
					fire = false;
					Plugin.ClearTarget(turret);
				}
				Plugin.LogMount("Manual control " + (flag ? "granted" : "denied") + " for player " + playerId);
				View.InvokeRPC(sender, "RHSB.Reply.v1", new object[3] { playerId, flag, lease.Token });
			}
		}

		private void ReceiveReply(long sender, long playerId, bool approved, int token)
		{
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (Object.op_Implicit((Object)(object)View) && View.IsValid() && View.GetZDO().GetOwner() == sender && Object.op_Implicit((Object)(object)localPlayer) && localPlayer.GetPlayerID() == playerId && !(Time.unscaledTime > pendingUntil))
			{
				pendingUntil = 0f;
				if (!approved)
				{
					Plugin.Tell("Ballista is occupied, or you are too far away.");
					return;
				}
				if (!Ready || ((Character)localPlayer).IsDead() || localPlayer.GetDoodadController() != null || ((Character)localPlayer).IsAttached())
				{
					View.InvokeRPC("RHSB.Release.v1", new object[2] { playerId, token });
					return;
				}
				local = localPlayer;
				localToken = token;
				localSince = Time.unscaledTime;
				nextInput = 0f;
				exitKey.Reset();
				Plugin.LogMount("Manual control started for " + localPlayer.GetPlayerName());
				localPlayer.StartDoodadControl((IDoodadController)(object)this);
				((Character)localPlayer).AttachStart(seat, (GameObject)null, false, false, true, "standing", new Vector3(0f, 0f, -0.5f), (Transform)null);
				Plugin.Tell("Manual ballista: mouse to aim, left mouse to fire, E to leave.");
			}
		}

		private void ReceiveInput(long sender, ZPackage pkg)
		{
			if (!OwnerReady() || pkg == null || pkg.GetArray().Length > 64)
			{
				return;
			}
			try
			{
				long num = pkg.ReadLong();
				int token = pkg.ReadInt();
				float n = pkg.ReadSingle();
				float n2 = pkg.ReadSingle();
				bool flag = pkg.ReadBool();
				if (lease.Input(num, sender, token, Now, ValidPawn(num, sender), n, n2))
				{
					inputYaw = Rules.Clamp(n, -180f, 180f);
					inputPitch = Rules.Clamp(n2, -75f, 60f);
					View.GetZDO().Set("RHSB.Yaw.v1", inputYaw);
					View.GetZDO().Set("RHSB.Pitch.v1", inputPitch);
					lastPacketTime = Time.unscaledTime;
					fire = flag && Rules.InArc(n, n2, 180f, -75f, 60f);
				}
			}
			catch (Exception)
			{
			}
		}

		private void ReceiveRelease(long sender, long playerId, int token)
		{
			if (OwnerReady() && lease.Matches(playerId, sender, token, Now))
			{
				ClearLease();
			}
		}

		private void ClearLease()
		{
			lease.Clear();
			fire = false;
			View.GetZDO().Set("RHSB.Gunner.v1", 0L);
			Plugin.ClearTarget(turret);
		}

		internal void RotateGun()
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0209: Unknown result type (might be due to invalid IL or missing references)
			//IL_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_021f: Unknown result type (might be due to invalid IL or missing references)
			//IL_023f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0254: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0273: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: 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_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0132: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0140: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02e9: Unknown result type (might be due to invalid IL or missing references)
			if (Ready && Object.op_Implicit((Object)(object)turret.m_turretBody) && Object.op_Implicit((Object)(object)turret.m_turretNeck) && Object.op_Implicit((Object)(object)turret.m_eye))
			{
				Vector3 val = ((Component)this).transform.forward;
				object? value = Plugin.Target.GetValue(turret);
				Character val2 = (Character)((value is Character) ? value : null);
				if (Manual)
				{
					inputYaw = View.GetZDO().GetFloat("RHSB.Yaw.v1", 0f);
					inputPitch = View.GetZDO().GetFloat("RHSB.Pitch.v1", 0f);
				}
				else if (Object.op_Implicit((Object)(object)val2) && !val2.IsDead())
				{
					val = val2.GetCenterPoint() - turret.m_eye.transform.position;
					Vector3 val3 = ((Component)this).transform.InverseTransformDirection(((Vector3)(ref val)).normalized);
					inputYaw = Rules.Clamp(Mathf.Atan2(val3.x, val3.z) * 57.29578f, 0f - YawLimit, YawLimit);
					float y = val3.y;
					Vector2 val4 = new Vector2(val3.x, val3.z);
					inputPitch = Rules.Clamp((0f - Mathf.Atan2(y, ((Vector2)(ref val4)).magnitude)) * 57.29578f, -30f, 45f);
				}
				else
				{
					inputYaw = 0f;
					inputPitch = 0f;
				}
				float num = Mathf.Max(0.1f, turret.m_turnRate) * Time.fixedDeltaTime;
				yaw = Mathf.MoveTowardsAngle(yaw, inputYaw, num);
				pitch = Mathf.MoveTowards(pitch, inputPitch, num);
				Quaternion val5 = ((Component)this).transform.rotation * Quaternion.Euler(pitch, yaw, 0f);
				turret.m_turretBody.transform.rotation = val5 * (Quaternion)Plugin.BaseBody.GetValue(turret);
				turret.m_turretNeck.transform.rotation = ((Component)this).transform.rotation * Quaternion.Euler(0f, yaw, 0f) * (Quaternion)Plugin.BaseNeck.GetValue(turret);
				Quaternion val6 = ((Object.op_Implicit((Object)(object)val2) && !Manual) ? Quaternion.LookRotation(((Vector3)(ref val)).normalized, ((Component)this).transform.up) : (((Component)this).transform.rotation * Quaternion.Euler(inputPitch, inputYaw, 0f)));
				Plugin.AimDiff.SetValue(turret, Object.op_Implicit((Object)(object)val2) ? Mathf.Abs(Quaternion.Dot(val5, val6)) : (-1f));
				if (View.IsOwner() && lease.Active(Now) && fire && Time.unscaledTime - lastPacketTime < 0.4f && Mathf.Abs(Mathf.DeltaAngle(yaw, inputYaw)) < 1f && Mathf.Abs(pitch - inputPitch) < 1f && Plugin.HasAmmo(turret) && !Plugin.IsCooling(turret) && LineSafe())
				{
					Plugin.Shoot.Invoke(turret, null);
				}
			}
		}

		internal bool LineSafe()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: 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_0098: Unknown result type (might be due to invalid IL or missing references)
			if (!Ready || !Object.op_Implicit((Object)(object)turret.m_eye))
			{
				return false;
			}
			RaycastHit[] array = Physics.RaycastAll(new Ray(turret.m_eye.transform.position, turret.m_eye.transform.forward), Mathf.Max(5f, turret.m_viewDistance), -1, (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				RaycastHit val = array2[num];
				if (!((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(((Component)this).transform))
				{
					if ((Object)(object)((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Ship>() == (Object)(object)Ship)
					{
						return false;
					}
					Character componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Character>();
					if (Object.op_Implicit((Object)(object)componentInParent) && (componentInParent.IsPlayer() || componentInParent.IsTamed()))
					{
						return false;
					}
					return true;
				}
			}
			return true;
		}

		private void Update()
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0123: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0142: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Expected O, but got Unknown
			if (!Object.op_Implicit((Object)(object)local))
			{
				return;
			}
			bool flag = Menu.IsVisible() || InventoryGui.IsVisible() || Console.IsVisible() || TextInput.IsVisible() || (Object.op_Implicit((Object)(object)Chat.instance) && Chat.instance.HasFocus());
			bool flag2 = exitKey.Poll(Input.GetKey((KeyCode)101), Input.GetKeyDown((KeyCode)101));
			if (!Ready || ((Character)local).IsDead() || (object)local.GetDoodadController() != this || flag || flag2 || Input.GetKeyDown((KeyCode)27))
			{
				StopLocal();
			}
			else if (View.GetZDO().GetLong("RHSB.Gunner.v1", 0L) != local.GetPlayerID() && Time.unscaledTime > localSince + 2.5f)
			{
				StopLocal();
			}
			else if (!(Time.unscaledTime < nextInput))
			{
				nextInput = Time.unscaledTime + 0.1f;
				GameCamera instance = GameCamera.instance;
				if (Object.op_Implicit((Object)(object)instance))
				{
					Vector3 val = ((Component)this).transform.InverseTransformDirection(((Component)instance).transform.forward);
					float num = Mathf.Atan2(val.x, val.z) * 57.29578f;
					float y = val.y;
					Vector2 val2 = new Vector2(val.x, val.z);
					float num2 = (0f - Mathf.Atan2(y, ((Vector2)(ref val2)).magnitude)) * 57.29578f;
					aimOutside = !Rules.InArc(num, num2, 180f, -75f, 60f);
					ZPackage val3 = new ZPackage();
					val3.Write(local.GetPlayerID());
					val3.Write(localToken);
					val3.Write(num);
					val3.Write(num2);
					val3.Write(capturedFire && Time.unscaledTime - weaponInputAt < 0.3f);
					View.InvokeRPC("RHSB.Input.v1", new object[1] { val3 });
				}
			}
		}

		internal void CaptureWeaponInput(ref bool attack, ref bool attackHold, ref bool secondary, ref bool secondaryHold)
		{
			capturedFire = GunnerInput.Consume(ref attack, ref attackHold, ref secondary, ref secondaryHold);
			weaponInputAt = Time.unscaledTime;
		}

		internal void StopLocal()
		{
			Player val = local;
			if (Object.op_Implicit((Object)(object)val))
			{
				((Character)val).AttachStop();
				if ((object)val.GetDoodadController() == this)
				{
					val.StopDoodadControl();
				}
				else
				{
					OnUseStop(val);
				}
				local = null;
			}
		}

		public void OnUseStop(Player player)
		{
			Plugin.LogMount("Manual control released by " + player.GetPlayerName());
			if (Object.op_Implicit((Object)(object)View) && View.IsValid())
			{
				View.InvokeRPC("RHSB.Release.v1", new object[2]
				{
					player.GetPlayerID(),
					localToken
				});
			}
			((Character)player).AttachStop();
			local = null;
		}

		public void ApplyControlls(Vector3 move, Vector3 look, bool run, bool autoRun, bool block)
		{
		}

		public Component GetControlledComponent()
		{
			return (Component)(object)this;
		}

		public Vector3 GetPosition()
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)seat))
			{
				return ((Component)this).transform.position;
			}
			return seat.position;
		}

		public bool IsValid()
		{
			if (Object.op_Implicit((Object)(object)this))
			{
				return Ready;
			}
			return false;
		}

		private void OnGUI()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Expected O, but got Unknown
			//IL_004e: 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)
			if (Object.op_Implicit((Object)(object)local))
			{
				GUIStyle val = new GUIStyle(GUI.skin.label)
				{
					fontSize = 18,
					alignment = (TextAnchor)4
				};
				GUI.Label(new Rect((float)(Screen.width / 2 - 300), (float)(Screen.height - 100), 600f, 70f), "WAR SHIPS — MANUAL\nMouse: aim  |  LMB: fire  |  E: automatic\nAmmo: " + turret.GetAmmo() + (aimOutside ? "  |  Aim outside firing arc" : ""), val);
				GUI.Label(new Rect((float)(Screen.width / 2 - 12), (float)(Screen.height / 2 - 16), 24f, 32f), "+", val);
			}
		}

		internal void ParentDestroyed()
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			if (Mounted && Object.op_Implicit((Object)(object)View) && View.IsValid())
			{
				if (View.IsOwner())
				{
					DestroyMount();
					return;
				}
				View.InvokeRPC("RHSB.ShipGone.v1", new object[1] { ParentId });
			}
		}

		private void ReceiveParentDestroyed(long sender, ZDOID parent)
		{
			//IL_0030: 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)
			if (Object.op_Implicit((Object)(object)View) && View.IsValid() && View.IsOwner() && sender == parentPeer && parent == ParentId)
			{
				DestroyMount();
			}
		}

		private void DestroyMount()
		{
			StopLocal();
			if (Object.op_Implicit((Object)(object)wear) && View.IsOwner())
			{
				DestroyPiece.Invoke(wear, new object[2] { null, false });
			}
		}

		private void OnDestroy()
		{
			StopLocal();
			All.Remove(this);
		}
	}
	[BepInPlugin("com.rustyheathens.warships", "Rusty Heathens War Ships", "0.1.3")]
	public sealed class Plugin : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Turret), "Awake")]
		private static class TurretSpawn
		{
			private static void Postfix(Turret __instance)
			{
				EnsureMount(__instance);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "CreateObject")]
		private static class RestoredObject
		{
			private static void Postfix(GameObject __result)
			{
				if (Object.op_Implicit((Object)(object)__result))
				{
					ShipIdentity.Ensure(__result.GetComponent<Ship>());
					EnsureMount(__result.GetComponent<Turret>());
				}
			}
		}

		[HarmonyPatch(typeof(Ship), "Awake")]
		private static class ShipSpawn
		{
			private static void Postfix(Ship __instance)
			{
				ShipIdentity.Ensure(__instance);
			}
		}

		[HarmonyPatch(typeof(Player), "PieceRayTest")]
		private static class DeckPlacementRay
		{
			private static bool Prefix(Player __instance, ref Vector3 __0, ref Vector3 __1, ref Piece __2, ref Heightmap __3, ref Collider __4, ref bool __result)
			{
				//IL_008b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00e0: 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)
				//IL_0142: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Unknown result type (might be due to invalid IL or missing references)
				//IL_0108: Unknown result type (might be due to invalid IL or missing references)
				//IL_0109: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0110: Unknown result type (might be due to invalid IL or missing references)
				//IL_0112: Unknown result type (might be due to invalid IL or missing references)
				//IL_0155: Unknown result type (might be due to invalid IL or missing references)
				//IL_015a: Unknown result type (might be due to invalid IL or missing references)
				//IL_0162: Unknown result type (might be due to invalid IL or missing references)
				//IL_0167: Unknown result type (might be due to invalid IL or missing references)
				object? value = Ghost.GetValue(__instance);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val.GetComponent<Turret>()))
				{
					Piece selectedPiece = __instance.GetSelectedPiece();
					if (Rules.Ballista((selectedPiece != null) ? ((Object)((Component)selectedPiece).gameObject).name : null) && Object.op_Implicit((Object)(object)GameCamera.instance))
					{
						int num = (int)RayMask.GetValue(__instance) | LayerMask.GetMask(new string[2] { "vehicle", "piece" });
						Transform transform = ((Component)GameCamera.instance).transform;
						RaycastHit val2 = default(RaycastHit);
						if (!Physics.Raycast(transform.position, transform.forward, ref val2, 50f, num, (QueryTriggerInteraction)1))
						{
							return true;
						}
						Ship componentInParent = ((Component)((RaycastHit)(ref val2)).collider).GetComponentInParent<Ship>();
						if (!Object.op_Implicit((Object)(object)componentInParent) || !Rules.SupportedShip(((Object)((Component)componentInParent).gameObject).name) || Vector3.Dot(((RaycastHit)(ref val2)).normal, ((Component)componentInParent).transform.up) < 0.5f)
						{
							return true;
						}
						if (string.IsNullOrEmpty(ShipIdentity.Ensure(componentInParent)))
						{
							__0 = (__1 = Vector3.zero);
							__2 = null;
							__3 = null;
							__4 = null;
							__result = false;
							return false;
						}
						float num2 = (float)PlaceDistance.GetValue(__instance);
						if (Vector3.Distance(((Character)__instance).GetEyePoint(), ((RaycastHit)(ref val2)).point) >= num2)
						{
							return true;
						}
						__0 = ((RaycastHit)(ref val2)).point;
						__1 = ((RaycastHit)(ref val2)).normal;
						__2 = null;
						__3 = null;
						__4 = null;
						__result = true;
						return false;
					}
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Player), "PlacePiece")]
		private static class PlacementContext
		{
			private static void Prefix(Piece piece, Vector3 pos)
			{
				//IL_002a: Unknown result type (might be due to invalid IL or missing references)
				PlacingOn = ((Object.op_Implicit((Object)(object)piece) && Object.op_Implicit((Object)(object)((Component)piece).GetComponent<Turret>()) && Rules.Ballista(((Object)((Component)piece).gameObject).name)) ? ResolveShip(pos) : null);
			}

			private static Exception Finalizer(Exception __exception)
			{
				PlacingOn = null;
				return __exception;
			}
		}

		[HarmonyPatch(typeof(WearNTear), "OnPlaced")]
		private static class EarlyMountBinding
		{
			private static void Prefix(WearNTear __instance)
			{
				if (Object.op_Implicit((Object)(object)PlacingOn))
				{
					MountedBallista component = ((Component)__instance).GetComponent<MountedBallista>();
					if (Object.op_Implicit((Object)(object)component))
					{
						component.OnPlaced();
					}
				}
			}
		}

		[HarmonyPatch(typeof(WearNTear), "UpdateSupport")]
		private static class ShipSupport
		{
			private static bool Prefix(WearNTear __instance)
			{
				MountedBallista component = ((Component)__instance).GetComponent<MountedBallista>();
				if (!Object.op_Implicit((Object)(object)component) || !component.Mounted)
				{
					return true;
				}
				ProvideShipSupport(__instance, component);
				return false;
			}
		}

		[HarmonyPatch(typeof(Turret), "UpdateTurretRotation")]
		private static class MountedRotation
		{
			private static bool Prefix(Turret __instance)
			{
				MountedBallista mountedBallista = Mount(__instance);
				if (!Object.op_Implicit((Object)(object)mountedBallista) || !mountedBallista.Mounted)
				{
					return true;
				}
				if (mountedBallista.Ready)
				{
					mountedBallista.RotateGun();
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Turret), "FixedUpdate")]
		private static class MountedTick
		{
			private static bool Prefix(Turret __instance)
			{
				MountedBallista mountedBallista = Mount(__instance);
				if (!Object.op_Implicit((Object)(object)mountedBallista) || !mountedBallista.Mounted)
				{
					return true;
				}
				mountedBallista.TickOwner();
				return mountedBallista.Ready;
			}
		}

		[HarmonyPatch(typeof(Turret), "UpdateTarget")]
		private static class ManualTarget
		{
			private static bool Prefix(Turret __instance)
			{
				MountedBallista mountedBallista = Mount(__instance);
				if (Object.op_Implicit((Object)(object)mountedBallista) && mountedBallista.Mounted)
				{
					return !mountedBallista.Manual;
				}
				return true;
			}
		}

		[HarmonyPatch(typeof(Turret), "UpdateAttack")]
		private static class AttackGuard
		{
			private static bool Prefix(Turret __instance)
			{
				MountedBallista mountedBallista = Mount(__instance);
				if (!Object.op_Implicit((Object)(object)mountedBallista) || !mountedBallista.Mounted)
				{
					return true;
				}
				object? value = Target.GetValue(__instance);
				Character val = (Character)((value is Character) ? value : null);
				if (mountedBallista.Ready && !mountedBallista.Manual && Object.op_Implicit((Object)(object)val) && !val.IsPlayer())
				{
					return !val.IsTamed();
				}
				return false;
			}
		}

		[HarmonyPatch(typeof(Turret), "ShootProjectile")]
		private static class ShootGuard
		{
			private static bool Prefix(Turret __instance)
			{
				MountedBallista mountedBallista = Mount(__instance);
				if (Object.op_Implicit((Object)(object)mountedBallista) && mountedBallista.Mounted)
				{
					if (mountedBallista.Ready && mountedBallista.View.IsOwner())
					{
						return mountedBallista.LineSafe();
					}
					return false;
				}
				return true;
			}

			private static void Postfix(Turret __instance)
			{
				//IL_0080: Unknown result type (might be due to invalid IL or missing references)
				//IL_008c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0091: Unknown result type (might be due to invalid IL or missing references)
				//IL_0096: Unknown result type (might be due to invalid IL or missing references)
				MountedBallista mountedBallista = Mount(__instance);
				if (!Object.op_Implicit((Object)(object)mountedBallista) || !mountedBallista.Ready || !mountedBallista.View.IsOwner())
				{
					return;
				}
				object? value = Projectile.GetValue(__instance);
				GameObject val = (GameObject)((value is GameObject) ? value : null);
				if (Object.op_Implicit((Object)(object)val) && (Object)(object)val != (Object)(object)mountedBallista.LastInheritedProjectile)
				{
					Projectile component = val.GetComponent<Projectile>();
					Rigidbody component2 = ((Component)mountedBallista.Ship).GetComponent<Rigidbody>();
					if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component2))
					{
						ProjectileVelocity.SetValue(component, (Vector3)ProjectileVelocity.GetValue(component) + component2.GetPointVelocity(val.transform.position));
					}
					mountedBallista.LastInheritedProjectile = val;
				}
			}
		}

		[HarmonyPatch(typeof(Turret), "Interact")]
		private static class ManualInteract
		{
			private static bool Prefix(Turret __instance, Humanoid __0, bool __1, bool __2, ref bool __result)
			{
				//IL_002e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0038: Expected O, but got Unknown
				MountedBallista mountedBallista = Mount(__instance);
				if (!Object.op_Implicit((Object)(object)mountedBallista) || !mountedBallista.Mounted || !__2 || __1 || !(__0 is Player))
				{
					return true;
				}
				mountedBallista.Request((Player)__0);
				__result = true;
				return false;
			}
		}

		[HarmonyPatch(typeof(Turret), "GetHoverText")]
		private static class HoverText
		{
			private static void Postfix(Turret __instance, ref string __result)
			{
				MountedBallista mountedBallista = Mount(__instance);
				if (Object.op_Implicit((Object)(object)mountedBallista) && mountedBallista.Mounted)
				{
					__result = __result + "\n[Shift+E] Manual control\n" + (mountedBallista.Manual ? "Gunner operating" : "Automatic: enemies only");
				}
			}
		}

		[HarmonyPatch(typeof(Player), "SetControls")]
		private static class GunnerControlInput
		{
			private static void Prefix(Player __instance, ref bool attack, ref bool attackHold, ref bool secondaryAttack, ref bool secondaryAttackHold)
			{
				MountedBallista mountedBallista = __instance.GetDoodadController() as MountedBallista;
				if (Object.op_Implicit((Object)(object)mountedBallista))
				{
					mountedBallista.CaptureWeaponInput(ref attack, ref attackHold, ref secondaryAttack, ref secondaryAttackHold);
				}
			}
		}

		[HarmonyPatch(typeof(Player), "PlayerAttackInput")]
		private static class GunnerAttackInput
		{
			private static bool Prefix(Player __instance)
			{
				return !(__instance.GetDoodadController() is MountedBallista);
			}
		}

		[HarmonyPatch(typeof(Ship), "CanBeRemoved")]
		private static class ShipDismantle
		{
			private static void Postfix(Ship __instance, ref bool __result)
			{
				if (!__result)
				{
					return;
				}
				foreach (MountedBallista item in MountedBallista.All)
				{
					if (Object.op_Implicit((Object)(object)item) && (Object)(object)item.Ship == (Object)(object)__instance && item.Mounted)
					{
						__result = false;
						break;
					}
				}
			}
		}

		[HarmonyPatch(typeof(Ship), "OnDestroyed")]
		private static class ShipDestroyed
		{
			private static void Prefix(Ship __instance)
			{
				foreach (MountedBallista item in new List<MountedBallista>(MountedBallista.All))
				{
					if (Object.op_Implicit((Object)(object)item) && (Object)(object)item.Ship == (Object)(object)__instance)
					{
						item.ParentDestroyed();
					}
				}
			}
		}

		public const string Id = "com.rustyheathens.warships";

		internal static Plugin Instance;

		private Harmony harmony;

		[ThreadStatic]
		internal static Ship PlacingOn;

		internal static readonly FieldInfo Ghost = AccessTools.Field(typeof(Player), "m_placementGhost");

		internal static readonly FieldInfo RayMask = AccessTools.Field(typeof(Player), "m_placeRayMask");

		internal static readonly FieldInfo PlaceDistance = AccessTools.Field(typeof(Player), "m_maxPlaceDistance");

		internal static readonly FieldInfo Target = AccessTools.Field(typeof(Turret), "m_target");

		internal static readonly FieldInfo HaveTarget = AccessTools.Field(typeof(Turret), "m_haveTarget");

		internal static readonly FieldInfo AimDiff = AccessTools.Field(typeof(Turret), "m_aimDiffToTarget");

		internal static readonly FieldInfo TargetTimer = AccessTools.Field(typeof(Turret), "m_updateTargetTimer");

		internal static readonly FieldInfo BaseBody = AccessTools.Field(typeof(Turret), "m_baseBodyRotation");

		internal static readonly FieldInfo BaseNeck = AccessTools.Field(typeof(Turret), "m_baseNeckRotation");

		internal static readonly MethodInfo Shoot = AccessTools.Method(typeof(Turret), "ShootProjectile", (Type[])null, (Type[])null);

		internal static readonly MethodInfo Ammo = AccessTools.Method(typeof(Turret), "HasAmmo", (Type[])null, (Type[])null);

		internal static readonly MethodInfo Cooling = AccessTools.Method(typeof(Turret), "IsCoolingDown", (Type[])null, (Type[])null);

		internal static readonly MethodInfo Reload = AccessTools.Method(typeof(Turret), "UpdateReloadState", (Type[])null, (Type[])null);

		internal static readonly MethodInfo Bolt = AccessTools.Method(typeof(Turret), "UpdateVisualBolt", (Type[])null, (Type[])null);

		internal static readonly FieldInfo Projectile = AccessTools.Field(typeof(Turret), "m_lastProjectile");

		internal static readonly FieldInfo Support = AccessTools.Field(typeof(WearNTear), "m_support");

		internal static readonly MethodInfo MaxSupport = AccessTools.Method(typeof(WearNTear), "GetMaxSupport", (Type[])null, (Type[])null);

		internal static readonly FieldInfo ProjectileVelocity = AccessTools.Field(typeof(Projectile), "m_vel");

		private void Awake()
		{
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			Instance = this;
			if (Target == null || Shoot == null || Ammo == null || Cooling == null || Ghost == null || PlaceDistance == null)
			{
				throw new InvalidOperationException("Unsupported Valheim ballista/placement API.");
			}
			harmony = new Harmony("com.rustyheathens.warships");
			harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"War Ships 0.1.3 test build loaded. Longship/Drakkar: place a ballista with the hammer; Shift+E to aim manually.");
		}

		private void OnDestroy()
		{
			foreach (MountedBallista item in new List<MountedBallista>(MountedBallista.All))
			{
				if (Object.op_Implicit((Object)(object)item))
				{
					item.StopLocal();
				}
			}
			Harmony obj = harmony;
			if (obj != null)
			{
				obj.UnpatchSelf();
			}
			Instance = null;
		}

		internal static void LogMount(string message)
		{
			if (Object.op_Implicit((Object)(object)Instance))
			{
				((BaseUnityPlugin)Instance).Logger.LogInfo((object)("[War Ships] " + message));
			}
		}

		internal static void Tell(string message)
		{
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, message, 0, (Sprite)null, false);
			}
		}

		internal static bool HasAmmo(Turret t)
		{
			return (bool)Ammo.Invoke(t, null);
		}

		internal static bool IsCooling(Turret t)
		{
			return (bool)Cooling.Invoke(t, null);
		}

		internal static void ClearTarget(Turret t)
		{
			Target.SetValue(t, null);
			HaveTarget.SetValue(t, false);
			TargetTimer.SetValue(t, 0f);
		}

		internal static MountedBallista Mount(Turret t)
		{
			if (!Object.op_Implicit((Object)(object)t))
			{
				return null;
			}
			return ((Component)t).GetComponent<MountedBallista>();
		}

		internal static Ship ResolveShip(Vector3 pos)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			RaycastHit[] array = Physics.RaycastAll(pos + Vector3.up * 0.4f, Vector3.down, 1.8f, -1, (QueryTriggerInteraction)1);
			Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
			RaycastHit[] array2 = array;
			for (int num = 0; num < array2.Length; num++)
			{
				RaycastHit val = array2[num];
				Ship componentInParent = ((Component)((RaycastHit)(ref val)).collider).GetComponentInParent<Ship>();
				if (Object.op_Implicit((Object)(object)componentInParent) && Rules.SupportedShip(((Object)((Component)componentInParent).gameObject).name) && Vector3.Dot(((RaycastHit)(ref val)).normal, ((Component)componentInParent).transform.up) > 0.5f)
				{
					return componentInParent;
				}
			}
			return null;
		}

		internal static void ProvideShipSupport(WearNTear wear, MountedBallista mount)
		{
			if (!Object.op_Implicit((Object)(object)wear) || !Object.op_Implicit((Object)(object)mount) || !mount.Mounted)
			{
				return;
			}
			wear.m_noSupportWear = false;
			if (mount.Ready)
			{
				float num = (float)MaxSupport.Invoke(wear, null);
				Support.SetValue(wear, num);
				if (mount.View.IsOwner())
				{
					mount.View.GetZDO().Set(ZDOVars.s_support, num);
				}
			}
		}

		internal static void EnsureMount(Turret turret)
		{
			if (Object.op_Implicit((Object)(object)turret) && Rules.Ballista(((Object)((Component)turret).gameObject).name))
			{
				ZNetView component = ((Component)turret).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid() && !Object.op_Implicit((Object)(object)Mount(turret)))
				{
					((Component)turret).gameObject.AddComponent<MountedBallista>();
				}
			}
		}
	}
	internal static class Rules
	{
		internal const float ManualYawLimit = 180f;

		internal const float ManualPitchMin = -75f;

		internal const float ManualPitchMax = 60f;

		internal static bool SupportedShip(string name)
		{
			if (name == null)
			{
				return false;
			}
			if (name.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				name = name.Substring(0, name.Length - 7);
			}
			if (!(name == "VikingShip"))
			{
				return name == "VikingShip_Ashlands";
			}
			return true;
		}

		internal static bool Ballista(string name)
		{
			if (name == null)
			{
				return false;
			}
			if (name.EndsWith("(Clone)", StringComparison.Ordinal))
			{
				name = name.Substring(0, name.Length - 7);
			}
			return name == "piece_turret";
		}

		internal static bool Finite(float n)
		{
			if (!float.IsNaN(n))
			{
				return !float.IsInfinity(n);
			}
			return false;
		}

		internal static bool InArc(float yaw, float pitch, float limit, float minPitch = -30f, float maxPitch = 45f)
		{
			if (Finite(yaw) && Finite(pitch) && Math.Abs(yaw) <= limit && pitch >= minPitch)
			{
				return pitch <= maxPitch;
			}
			return false;
		}

		internal static float Clamp(float n, float lo, float hi)
		{
			return Math.Max(lo, Math.Min(hi, n));
		}
	}
	internal sealed class StableShipIndex<T> where T : class
	{
		private readonly Dictionary<string, HashSet<T>> entries = new Dictionary<string, HashSet<T>>(StringComparer.Ordinal);

		internal void Add(string id, T item)
		{
			if (!string.IsNullOrEmpty(id) && item != null)
			{
				if (!entries.TryGetValue(id, out var value))
				{
					value = new HashSet<T>();
					entries.Add(id, value);
				}
				value.Add(item);
			}
		}

		internal void Remove(string id, T item)
		{
			if (!string.IsNullOrEmpty(id) && entries.TryGetValue(id, out var value))
			{
				value.Remove(item);
				if (value.Count == 0)
				{
					entries.Remove(id);
				}
			}
		}

		internal bool TryUnique(string id, Predicate<T> valid, out T result)
		{
			result = null;
			if (string.IsNullOrEmpty(id) || !entries.TryGetValue(id, out var value))
			{
				return false;
			}
			foreach (T item in value)
			{
				if (valid(item))
				{
					if (result != null)
					{
						result = null;
						return false;
					}
					result = item;
				}
			}
			return result != null;
		}
	}
	internal static class GunnerInput
	{
		internal static bool Consume(ref bool attack, ref bool attackHold, ref bool secondary, ref bool secondaryHold)
		{
			bool result = attack | attackHold;
			attack = (attackHold = (secondary = (secondaryHold = false)));
			return result;
		}
	}
	internal sealed class ExitKeyLatch
	{
		private bool released;

		internal void Reset()
		{
			released = false;
		}

		internal bool Poll(bool held, bool down)
		{
			if (!released)
			{
				if (!held)
				{
					released = true;
				}
				return false;
			}
			return down;
		}
	}
	internal sealed class ControlLease
	{
		internal long Player;

		internal long Peer;

		internal int Token;

		internal double Expires;

		private int sequence;

		internal ControlLease(int seed)
		{
			sequence = seed;
		}

		internal bool Active(double now)
		{
			if (Player != 0L)
			{
				return now < Expires;
			}
			return false;
		}

		internal bool Acquire(long player, long peer, double now, bool allowed)
		{
			if (!allowed || player == 0L || peer == 0L || Active(now))
			{
				return false;
			}
			Player = player;
			Peer = peer;
			Token = ++sequence;
			if (Token == 0)
			{
				Token = ++sequence;
			}
			Expires = now + 2.5;
			return true;
		}

		internal bool Matches(long player, long peer, int token, double now)
		{
			if (Active(now) && Player == player && Peer == peer)
			{
				return Token == token;
			}
			return false;
		}

		internal bool Input(long player, long peer, int token, double now, bool allowed, float yaw, float pitch)
		{
			if (!allowed || !Matches(player, peer, token, now) || !Rules.Finite(yaw) || !Rules.Finite(pitch))
			{
				return false;
			}
			Expires = now + 2.5;
			return true;
		}

		internal void Clear()
		{
			Player = (Peer = 0L);
			Expires = 0.0;
			Token = 0;
		}
	}
	public sealed class ShipIdentity : MonoBehaviour
	{
		internal const string Key = "RHSB.ShipGuid.v1";

		private static readonly StableShipIndex<ShipIdentity> Index = new StableShipIndex<ShipIdentity>();

		private Ship ship;

		private ZNetView view;

		private string registered = "";

		private float next;

		internal static string Ensure(Ship ship)
		{
			if (!Object.op_Implicit((Object)(object)ship) || !Rules.SupportedShip(((Object)((Component)ship).gameObject).name))
			{
				return "";
			}
			ShipIdentity shipIdentity = ((Component)ship).GetComponent<ShipIdentity>();
			if (!Object.op_Implicit((Object)(object)shipIdentity))
			{
				shipIdentity = ((Component)ship).gameObject.AddComponent<ShipIdentity>();
			}
			return shipIdentity.Refresh();
		}

		internal static Ship Find(string guid)
		{
			if (!Index.TryUnique(guid, (ShipIdentity x) => Object.op_Implicit((Object)(object)x) && Object.op_Implicit((Object)(object)x.view) && x.view.IsValid() && x.view.GetZDO().GetString("RHSB.ShipGuid.v1", "") == guid, out var result))
			{
				return null;
			}
			return result.ship;
		}

		private void Awake()
		{
			ship = ((Component)this).GetComponent<Ship>();
			view = ((Component)this).GetComponent<ZNetView>();
			Refresh();
		}

		private string Refresh()
		{
			if (!Object.op_Implicit((Object)(object)view) || !view.IsValid())
			{
				return "";
			}
			ZDO zDO = view.GetZDO();
			string text = zDO.GetString("RHSB.ShipGuid.v1", "");
			if (string.IsNullOrEmpty(text) && view.IsOwner())
			{
				text = Guid.NewGuid().ToString("N");
				zDO.Set("RHSB.ShipGuid.v1", text);
				Plugin.LogMount("Saved ship identity initialized for " + ((Object)((Component)this).gameObject).name);
			}
			if (text != registered)
			{
				Index.Remove(registered, this);
				registered = text;
				Index.Add(registered, this);
			}
			return text;
		}

		private void Update()
		{
			if (Time.unscaledTime >= next)
			{
				next = Time.unscaledTime + 0.5f;
				Refresh();
			}
		}

		private void OnDestroy()
		{
			Index.Remove(registered, this);
		}
	}
}