Decompiled source of SailingTogether v1.0.0

plugins/SailingTogether.dll

Decompiled 3 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("SailingTogether")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+d730bfbdd3d8d6ff7ae17d22fa53f3e7a46c6d19")]
[assembly: AssemblyProduct("SailingTogether")]
[assembly: AssemblyTitle("SailingTogether")]
[assembly: AssemblyVersion("1.0.0.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 SailingTogether
{
	internal class DebugPanel : MonoBehaviour
	{
		internal class SimSeat
		{
			public string Name;

			public float LocalX;

			public float LocalZ;

			public float Row;
		}

		private static readonly List<SimSeat> s_seats = new List<SimSeat>();

		private static readonly SimSeat[] s_none = new SimSeat[0];

		private static Ship s_ship;

		private static bool s_simActive = true;

		private Rect _window = new Rect(40f, 120f, 380f, 10f);

		internal static bool IsOpen { get; private set; }

		internal static IEnumerable<SimSeat> GetSimulatedSeats(Ship ship)
		{
			if (!s_simActive || !SailingTogetherPlugin.DebugTool.Value || (Object)(object)ship != (Object)(object)s_ship || !Object.op_Implicit((Object)(object)s_ship))
			{
				return s_none;
			}
			return s_seats;
		}

		private void Update()
		{
			//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)
			if (!SailingTogetherPlugin.DebugTool.Value)
			{
				IsOpen = false;
				return;
			}
			KeyboardShortcut value = SailingTogetherPlugin.DebugHotkey.Value;
			if (((KeyboardShortcut)(ref value)).IsDown() && Object.op_Implicit((Object)(object)Player.m_localPlayer) && !Console.IsVisible() && (!Object.op_Implicit((Object)(object)Chat.instance) || !Chat.instance.HasFocus()))
			{
				IsOpen = !IsOpen;
			}
			Ship val = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? Ship.GetLocalShip() : null);
			if ((Object)(object)val != (Object)(object)s_ship)
			{
				RebuildSeats(val);
			}
		}

		private static void RebuildSeats(Ship ship)
		{
			s_ship = ship;
			s_seats.Clear();
			if (!Object.op_Implicit((Object)(object)ship))
			{
				return;
			}
			foreach (ShipLayout.Seat seat in ShipLayout.Get(ship).Seats)
			{
				s_seats.Add(new SimSeat
				{
					LocalX = seat.Local.x,
					LocalZ = seat.Local.z
				});
			}
			if (s_seats.Count == 0)
			{
				s_seats.Add(new SimSeat
				{
					LocalX = -1f,
					LocalZ = 0f
				});
				s_seats.Add(new SimSeat
				{
					LocalX = 1f,
					LocalZ = 0f
				});
			}
			for (int i = 0; i < s_seats.Count; i++)
			{
				s_seats[i].Name = $"#{i + 1} {SideName(s_seats[i].LocalX)}";
			}
		}

		private static string SideName(float localX)
		{
			float num = ShipAccess.SideOf(localX);
			if (num != 0f)
			{
				if (!(num < 0f))
				{
					return "Right";
				}
				return "Left";
			}
			return "Center";
		}

		private static void SetAll(float row, float side = 0f)
		{
			foreach (SimSeat s_seat in s_seats)
			{
				float num = ShipAccess.SideOf(s_seat.LocalX);
				if (side == 0f || num == side)
				{
					s_seat.Row = row;
				}
				else if (side != 0f)
				{
					s_seat.Row = 0f;
				}
			}
		}

		private void OnGUI()
		{
			//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_0052: 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_0072: Expected O, but got Unknown
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ca: 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 (SailingTogetherPlugin.DebugTool.Value && Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				float num = Mathf.Max(1f, (float)Screen.height / 1080f);
				GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f));
				if (IsOpen)
				{
					_window = GUILayout.Window(23063, _window, new WindowFunction(DrawWindow), "SailingTogether — rower simulator", Array.Empty<GUILayoutOption>());
				}
				else if (s_simActive && Object.op_Implicit((Object)(object)s_ship) && s_seats.Any((SimSeat s) => s.Row != 0f))
				{
					GUI.Label(new Rect(10f, 10f, 600f, 22f), $"SailingTogether sim: {StatusLine()}   [{SailingTogetherPlugin.DebugHotkey.Value}] panel");
				}
			}
		}

		private void DrawWindow(int id)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Unknown result type (might be due to invalid IL or missing references)
			if (!Object.op_Implicit((Object)(object)s_ship))
			{
				GUILayout.Label("Board a ship to simulate its benches.", Array.Empty<GUILayoutOption>());
				if (GUILayout.Button("Close", Array.Empty<GUILayoutOption>()))
				{
					IsOpen = false;
				}
				GUI.DragWindow();
				return;
			}
			s_simActive = GUILayout.Toggle(s_simActive, " Simulation active", Array.Empty<GUILayoutOption>());
			GUILayout.Label($"Ship: {Utils.GetPrefabName(((Component)s_ship).gameObject)}   Speed: {s_ship.GetSpeedSetting()}", Array.Empty<GUILayoutOption>());
			GUILayout.Label(StatusLine(), Array.Empty<GUILayoutOption>());
			RowingStats rowingStats = RowingStats.Get(s_ship);
			if (rowingStats != null && !rowingStats.IsOwner)
			{
				GUILayout.Label("<color=orange>You are not the ship owner: physics runs on another client.</color>", Array.Empty<GUILayoutOption>());
			}
			else if (rowingStats != null && !rowingStats.Allowed)
			{
				GUILayout.Label("<color=orange>Rowing inactive at this speed (set speed 1 at the helm).</color>", Array.Empty<GUILayoutOption>());
			}
			GUILayout.Space(6f);
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("All W", Array.Empty<GUILayoutOption>()))
			{
				SetAll(1f);
			}
			if (GUILayout.Button("All S", Array.Empty<GUILayoutOption>()))
			{
				SetAll(-1f);
			}
			if (GUILayout.Button("Reset", Array.Empty<GUILayoutOption>()))
			{
				SetAll(0f);
			}
			GUILayout.EndHorizontal();
			GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
			if (GUILayout.Button("Left W", Array.Empty<GUILayoutOption>()))
			{
				SetAll(1f, -1f);
			}
			if (GUILayout.Button("Right W", Array.Empty<GUILayoutOption>()))
			{
				SetAll(1f, 1f);
			}
			if (GUILayout.Button("Spin →", Array.Empty<GUILayoutOption>()))
			{
				MergeSpin(1f);
			}
			if (GUILayout.Button("← Spin", Array.Empty<GUILayoutOption>()))
			{
				MergeSpin(-1f);
			}
			GUILayout.EndHorizontal();
			GUILayout.Space(6f);
			foreach (SimSeat s_seat in s_seats)
			{
				GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
				GUILayout.Label(s_seat.Name, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(110f) });
				GUILayout.Label("S", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(12f) });
				float num = GUILayout.HorizontalSlider(s_seat.Row, -1f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) });
				s_seat.Row = Mathf.Round(num);
				GUILayout.Label("W", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(16f) });
				GUILayout.Label((s_seat.Row > 0f) ? "+1" : ((s_seat.Row < 0f) ? "-1" : " 0"), (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(24f) });
				GUILayout.EndHorizontal();
			}
			GUILayout.Space(6f);
			GUILayout.Label($"[{SailingTogetherPlugin.DebugHotkey.Value}] closes the panel (values keep applying).", Array.Empty<GUILayoutOption>());
			GUI.DragWindow();
		}

		private static void MergeSpin(float dir)
		{
			foreach (SimSeat s_seat in s_seats)
			{
				float num = ShipAccess.SideOf(s_seat.LocalX);
				s_seat.Row = ((num == 0f) ? 0f : ((0f - num) * dir));
			}
		}

		private static string StatusLine()
		{
			RowingStats rowingStats = RowingStats.Get(s_ship);
			if (rowingStats == null)
			{
				return "no data";
			}
			return $"rowers {rowingStats.Rowers}  thrust {rowingStats.Thrust:+0.0;-0.0;0}  turn {rowingStats.Turn:+0.0;-0.0;0}  " + string.Format("speed {0:0.0} m/s  yaw {1:+0;-0;0}°/s  {2}", s_ship.GetSpeed(), rowingStats.YawRate, rowingStats.Applied ? "APPLYING" : "idle");
		}
	}
	[HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")]
	internal static class GameCamera_UpdateMouseCapture_Patch
	{
		private static void Postfix()
		{
			if (DebugPanel.IsOpen)
			{
				ZCursor.LockState = (CursorLockMode)0;
				ZCursor.Show();
			}
		}
	}
	[HarmonyPatch(typeof(PlayerController), "TakeInput")]
	internal static class PlayerController_TakeInput_Patch
	{
		private static void Postfix(ref bool __result)
		{
			if (DebugPanel.IsOpen)
			{
				__result = false;
			}
		}
	}
	[HarmonyPatch(typeof(Player), "TakeInput")]
	internal static class Player_TakeInput_Patch
	{
		private static void Postfix(ref bool __result)
		{
			if (DebugPanel.IsOpen)
			{
				__result = false;
			}
		}
	}
	internal static class GameSprites
	{
		private static readonly Color DefaultShipColor = new Color(1f, 0.62f, 0.15f, 1f);

		private static bool s_loaded;

		internal static Sprite Ship;

		internal static Color ShipColor = DefaultShipColor;

		internal static Rect ShipVisible = new Rect(0f, 0f, 1f, 1f);

		internal static Sprite Arrow;

		internal static Sprite Oar;

		internal static void Reset()
		{
			s_loaded = false;
		}

		internal static void TryLoad()
		{
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0045: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			if (!s_loaded && Object.op_Implicit((Object)(object)Hud.instance))
			{
				s_loaded = true;
				Ship = Find(SailingTogetherPlugin.HudShipSprite.Value, out var hudImage);
				ShipColor = (Object.op_Implicit((Object)(object)hudImage) ? ((Graphic)hudImage).color : DefaultShipColor);
				ShipVisible = ((Object.op_Implicit((Object)(object)Ship) && ((Object)Ship).name == "ship_top") ? new Rect(61f / 171f, 0.11328125f, 49f / 171f, 0.67578125f) : new Rect(0f, 0f, 1f, 1f));
				Arrow = Find(SailingTogetherPlugin.HudArrowSprite.Value, out var hudImage2);
				Oar = Find(SailingTogetherPlugin.HudOarSprite.Value, out hudImage2);
				SailingTogetherPlugin.Log.LogInfo((object)("HUD: ship = '" + (Object.op_Implicit((Object)(object)Ship) ? ((Object)Ship).name : "built-in") + "', arrow = '" + (Object.op_Implicit((Object)(object)Arrow) ? ((Object)Arrow).name : "built-in") + "', oar = '" + (Object.op_Implicit((Object)(object)Oar) ? ((Object)Oar).name : "none") + "'"));
			}
		}

		private static Sprite Find(string spriteName, out Image hudImage)
		{
			hudImage = null;
			if (string.IsNullOrWhiteSpace(spriteName))
			{
				return null;
			}
			spriteName = spriteName.Trim();
			Hud instance = Hud.instance;
			if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)instance.m_shipHudRoot))
			{
				Image[] componentsInChildren = instance.m_shipHudRoot.GetComponentsInChildren<Image>(true);
				foreach (Image val in componentsInChildren)
				{
					if (Object.op_Implicit((Object)(object)val.sprite) && ((Object)val.sprite).name == spriteName)
					{
						hudImage = val;
						return val.sprite;
					}
				}
			}
			Sprite[] array = Resources.FindObjectsOfTypeAll<Sprite>();
			foreach (Sprite val2 in array)
			{
				if (Object.op_Implicit((Object)(object)val2) && ((Object)val2).name == spriteName)
				{
					return val2;
				}
			}
			SailingTogetherPlugin.Log.LogWarning((object)("HUD: sprite '" + spriteName + "' not found."));
			return null;
		}

		internal static void Draw(Rect rect, Sprite sprite, float angle, Color color, float guiScale)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			Draw(rect, sprite, angle, ((Rect)(ref rect)).center, color, guiScale);
		}

		internal static void Draw(Rect rect, Sprite sprite, float angle, Vector2 pivotPoint, Color color, float guiScale)
		{
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_00c4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: 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_009e: 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_00af: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: 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)
			Texture texture = (Texture)(object)sprite.texture;
			Rect textureRect = sprite.textureRect;
			Rect val = default(Rect);
			((Rect)(ref val))..ctor(((Rect)(ref textureRect)).x / (float)texture.width, ((Rect)(ref textureRect)).y / (float)texture.height, ((Rect)(ref textureRect)).width / (float)texture.width, ((Rect)(ref textureRect)).height / (float)texture.height);
			Matrix4x4 matrix = GUI.matrix;
			Color color2 = GUI.color;
			if (angle != 0f)
			{
				Vector3 val2 = default(Vector3);
				((Vector3)(ref val2))..ctor(pivotPoint.x * guiScale, pivotPoint.y * guiScale, 0f);
				GUI.matrix = Matrix4x4.TRS(val2, Quaternion.Euler(0f, 0f, angle), Vector3.one) * Matrix4x4.TRS(-val2, Quaternion.identity, Vector3.one) * matrix;
			}
			GUI.color = color;
			GUI.DrawTextureWithTexCoords(rect, texture, val, true);
			GUI.color = color2;
			GUI.matrix = matrix;
		}
	}
	internal static class RowerInput
	{
		internal static readonly int RowHash = StringExtensionMethods.GetStableHashCode("SailingTogether_Row");

		internal static readonly int SeatedHash = StringExtensionMethods.GetStableHashCode("SailingTogether_Seated");

		private static float s_lastSent;

		private static bool s_lastSeated;

		private static Ship s_seatedShip;

		internal static Ship GetSeatedShip(Player player)
		{
			if (!((Character)player).IsAttachedToShip() || player.GetDoodadController() != null)
			{
				return null;
			}
			Transform attachPoint = player.GetAttachPoint();
			if (!Object.op_Implicit((Object)(object)attachPoint))
			{
				return null;
			}
			return ((Component)attachPoint).GetComponentInParent<Ship>();
		}

		internal static void Send(Player player, float row, bool seated)
		{
			row = Mathf.Round(Mathf.Clamp(row, -1f, 1f) * 20f) / 20f;
			if (!Mathf.Approximately(row, s_lastSent) || seated != s_lastSeated)
			{
				ZNetView component = ((Component)player).GetComponent<ZNetView>();
				if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner())
				{
					component.GetZDO().Set(RowHash, row);
					component.GetZDO().Set(SeatedHash, seated ? 1 : 0, false);
					s_lastSent = row;
					s_lastSeated = seated;
				}
			}
		}

		internal static bool TryGetRower(Player player, out float row)
		{
			row = 0f;
			ZNetView val = (Object.op_Implicit((Object)(object)player) ? ((Component)player).GetComponent<ZNetView>() : null);
			ZDO val2 = (Object.op_Implicit((Object)(object)val) ? val.GetZDO() : null);
			if (val2 == null || val2.GetInt(SeatedHash, 0) == 0)
			{
				return false;
			}
			row = Mathf.Clamp(val2.GetFloat(RowHash, 0f), -1f, 1f);
			return true;
		}

		internal static void OnSeatChanged(Player player, Ship ship)
		{
			if (!((Object)(object)ship == (Object)(object)s_seatedShip))
			{
				s_seatedShip = ship;
				if (Object.op_Implicit((Object)(object)ship) && SailingTogetherPlugin.ShowHint.Value)
				{
					((Character)player).Message((MessageType)1, "Rowing: [W] forward  [S] backward  —  [Jump] stand up", 0, (Sprite)null, false);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Player), "SetControls")]
	internal static class Player_SetControls_Patch
	{
		private static void Prefix(Player __instance, ref Vector3 movedir)
		{
			//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)
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				Ship val = (SailingTogetherPlugin.Enabled.Value ? RowerInput.GetSeatedShip(__instance) : null);
				RowerInput.OnSeatChanged(__instance, val);
				float row = 0f;
				if (Object.op_Implicit((Object)(object)val))
				{
					row = movedir.z;
					movedir = Vector3.zero;
				}
				RowerInput.Send(__instance, row, Object.op_Implicit((Object)(object)val));
			}
		}
	}
	internal class RowingHud : MonoBehaviour
	{
		private enum SeatState
		{
			Free,
			Player,
			Simulated,
			Local
		}

		private struct SeatView
		{
			public SeatState State;

			public float Row;
		}

		private static readonly Color HullFill = new Color(0.42f, 0.28f, 0.15f, 0.85f);

		private static readonly Color HullEdge = new Color(0.16f, 0.09f, 0.04f, 1f);

		private static readonly Color FreeColor = new Color(0.85f, 0.85f, 0.85f, 0.55f);

		private static readonly Color PlayerColor = new Color(0.35f, 0.7f, 1f, 1f);

		private static readonly Color SimColor = new Color(0.75f, 0.5f, 1f, 1f);

		private static readonly Color LocalColor = new Color(1f, 0.82f, 0.3f, 1f);

		private static readonly Color HelmColor = new Color(1f, 0.95f, 0.6f, 1f);

		private static readonly Color ForwardColor = new Color(0.45f, 1f, 0.45f, 1f);

		private static readonly Color BackColor = new Color(1f, 0.45f, 0.35f, 1f);

		private static readonly Color InactiveColor = new Color(0.6f, 0.6f, 0.6f, 0.6f);

		private const float MaxHullHeight = 140f;

		private const float MaxHullWidth = 52f;

		private const float SeatSize = 9f;

		private const float ArrowSize = 17f;

		private const float ArrowGap = 4f;

		private const float OarHeight = 20f;

		private readonly Dictionary<ShipLayout, Texture2D> _hullTextures = new Dictionary<ShipLayout, Texture2D>();

		private readonly List<SeatView> _views = new List<SeatView>();

		private Texture2D _circle;

		private Texture2D _ring;

		private Texture2D _arrowUp;

		private Texture2D _arrowDown;

		private void OnGUI()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Invalid comparison between Unknown and I4
			//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)
			if ((int)Event.current.type != 7 || !SailingTogetherPlugin.Enabled.Value || !SailingTogetherPlugin.ShowHud.Value)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if (!Object.op_Implicit((Object)(object)localPlayer) || !Object.op_Implicit((Object)(object)Hud.instance) || Hud.IsUserHidden() || Menu.IsVisible() || InventoryGui.IsVisible() || Minimap.IsOpen())
			{
				return;
			}
			bool flag = false;
			Ship val = null;
			IDoodadController doodadController = localPlayer.GetDoodadController();
			ShipControlls val2 = (ShipControlls)(object)((doodadController is ShipControlls) ? doodadController : null);
			if (val2 != null && Object.op_Implicit((Object)(object)val2.m_ship))
			{
				val = val2.m_ship;
				flag = true;
			}
			else
			{
				val = RowerInput.GetSeatedShip(localPlayer);
			}
			if (Object.op_Implicit((Object)(object)val))
			{
				ShipLayout shipLayout = ShipLayout.Get(val);
				if (!flag || shipLayout.Seats.Count != 0)
				{
					EnsureResources();
					GameSprites.TryLoad();
					float num = Mathf.Max(1f, (float)Screen.height / 1080f) * SailingTogetherPlugin.HudScale.Value;
					GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f));
					BuildViews(val, shipLayout, localPlayer, flag);
					Draw(val, shipLayout, flag, num);
				}
			}
		}

		private void BuildViews(Ship ship, ShipLayout layout, Player local, bool pilot)
		{
			//IL_0197: 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)
			_views.Clear();
			for (int i = 0; i < layout.Seats.Count; i++)
			{
				_views.Add(new SeatView
				{
					State = SeatState.Free
				});
			}
			Transform transform = ((Component)ship).transform;
			long num = (Object.op_Implicit((Object)(object)ship.m_shipControlls) ? ship.m_shipControlls.GetUser() : 0);
			List<Player> list = ShipAccess.Players.Invoke(ship);
			if (list != null)
			{
				foreach (Player item in list)
				{
					if (!Object.op_Implicit((Object)(object)item) || item.GetPlayerID() == num)
					{
						continue;
					}
					bool flag = (Object)(object)item == (Object)(object)local;
					if ((pilot || flag) && RowerInput.TryGetRower(item, out var row))
					{
						int num2 = layout.NearestSeat(transform.InverseTransformPoint(((Component)item).transform.position), 1f);
						if (num2 >= 0)
						{
							_views[num2] = new SeatView
							{
								State = ((!flag) ? SeatState.Player : SeatState.Local),
								Row = row
							};
						}
					}
				}
			}
			if (!pilot)
			{
				return;
			}
			foreach (DebugPanel.SimSeat simulatedSeat in DebugPanel.GetSimulatedSeats(ship))
			{
				if (simulatedSeat.Row != 0f)
				{
					int num3 = layout.NearestSeat(new Vector3(simulatedSeat.LocalX, (layout.Seats.Count > 0) ? layout.Seats[0].Local.y : 0f, simulatedSeat.LocalZ), 1f);
					if (num3 >= 0 && _views[num3].State == SeatState.Free)
					{
						_views[num3] = new SeatView
						{
							State = SeatState.Simulated,
							Row = simulatedSeat.Row
						};
					}
				}
			}
		}

		private void Draw(Ship ship, ShipLayout layout, bool pilot, float scale)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//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_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: 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_01bc: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0200: Unknown result type (might be due to invalid IL or missing references)
			//IL_0227: Unknown result type (might be due to invalid IL or missing references)
			//IL_0281: Unknown result type (might be due to invalid IL or missing references)
			//IL_0288: Unknown result type (might be due to invalid IL or missing references)
			//IL_028d: Unknown result type (might be due to invalid IL or missing references)
			//IL_028f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0296: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02bf: 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_02d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_02de: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0310: Unknown result type (might be due to invalid IL or missing references)
			//IL_031a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0322: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0344: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_039d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_042d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0421: Unknown result type (might be due to invalid IL or missing references)
			//IL_041a: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_0483: Unknown result type (might be due to invalid IL or missing references)
			//IL_04da: Unknown result type (might be due to invalid IL or missing references)
			//IL_04a7: Unknown result type (might be due to invalid IL or missing references)
			float num = 140f;
			float num2;
			if (Object.op_Implicit((Object)(object)GameSprites.Ship))
			{
				Rect shipVisible = GameSprites.ShipVisible;
				Rect rect = GameSprites.Ship.rect;
				num2 = num * (((Rect)(ref shipVisible)).width * ((Rect)(ref rect)).width) / (((Rect)(ref shipVisible)).height * ((Rect)(ref rect)).height);
			}
			else
			{
				num2 = Mathf.Min(num * layout.Width / layout.Length, 52f);
			}
			float ppmX = num2 / layout.Width;
			float ppmZ = num / layout.Length;
			float num3 = 17f;
			if (Object.op_Implicit((Object)(object)GameSprites.Arrow))
			{
				Rect rect2 = GameSprites.Arrow.rect;
				float num4 = 17f * ((Rect)(ref rect2)).width;
				rect2 = GameSprites.Arrow.rect;
				num3 = num4 / Mathf.Max(1f, ((Rect)(ref rect2)).height);
			}
			float num5 = num2 + (num3 + 4f) * 2f;
			float num6 = (float)Screen.width / scale;
			float num7 = (float)Screen.height / scale;
			Rect hull = new Rect(num6 - SailingTogetherPlugin.HudOffsetX.Value - (num5 + num2) * 0.5f, num7 - SailingTogetherPlugin.HudOffsetY.Value - num, num2, num);
			if (Object.op_Implicit((Object)(object)GameSprites.Ship))
			{
				Rect shipVisible2 = GameSprites.ShipVisible;
				float num8 = num2 / ((Rect)(ref shipVisible2)).width;
				float num9 = num / ((Rect)(ref shipVisible2)).height;
				GameSprites.Draw(new Rect(((Rect)(ref hull)).x - ((Rect)(ref shipVisible2)).x * num8, ((Rect)(ref hull)).y - ((Rect)(ref shipVisible2)).y * num9, num8, num9), GameSprites.Ship, 0f, GameSprites.ShipColor, scale);
			}
			else
			{
				DrawTinted(hull, GetHullTexture(layout, num2, num), Color.white);
			}
			bool flag = ShipAccess.RowingAllowed(ship.GetSpeedSetting());
			if (layout.HasHelm)
			{
				Vector2 c = ToGui(layout.HelmLocal);
				DrawTinted(texture: (Object.op_Implicit((Object)(object)ship.m_shipControlls) && ship.m_shipControlls.HaveValidUser()) ? _circle : _ring, rect: Centered(c, 9f), color: HelmColor);
			}
			for (int i = 0; i < layout.Seats.Count; i++)
			{
				SeatView seatView = _views[i];
				if (!pilot && seatView.State != SeatState.Local)
				{
					continue;
				}
				Vector2 val = ToGui(layout.Seats[i].Local);
				Rect rect3 = Centered(val, 9f);
				switch (seatView.State)
				{
				case SeatState.Free:
					DrawTinted(rect3, _ring, FreeColor);
					continue;
				case SeatState.Player:
					DrawTinted(rect3, _circle, PlayerColor);
					break;
				case SeatState.Simulated:
					DrawTinted(rect3, _circle, SimColor);
					break;
				case SeatState.Local:
					DrawTinted(Centered(val, 13f), _ring, Color.white);
					DrawTinted(rect3, _circle, LocalColor);
					break;
				}
				bool flag2 = Mathf.Abs(seatView.Row) >= 0.05f;
				DrawOar(val, flag2 ? seatView.Row : 0f, flag, scale);
				if (flag2)
				{
					float num10 = ShipAccess.SideOf(layout.Seats[i].Local.x);
					Vector2 val2 = ((num10 > 0f) ? new Vector2(((Rect)(ref hull)).xMax + 4f + num3 * 0.5f, val.y) : ((num10 < 0f) ? new Vector2(((Rect)(ref hull)).x - 4f - num3 * 0.5f, val.y) : new Vector2(val.x, val.y - 18.5f)));
					Color color = ((!flag) ? InactiveColor : ((seatView.Row > 0f) ? ForwardColor : BackColor));
					color.a *= Mathf.Lerp(0.5f, 1f, Mathf.Abs(seatView.Row));
					if (Object.op_Implicit((Object)(object)GameSprites.Arrow))
					{
						GameSprites.Draw(new Rect(val2.x - num3 * 0.5f, val2.y - 8.5f, num3, 17f), GameSprites.Arrow, (seatView.Row > 0f) ? 0f : 180f, color, scale);
					}
					else
					{
						DrawTinted(Centered(val2, 17f), (seatView.Row > 0f) ? _arrowUp : _arrowDown, color);
					}
				}
			}
			Vector2 ToGui(Vector3 local)
			{
				//IL_000b: Unknown result type (might be due to invalid IL or missing references)
				//IL_003b: 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)
				return new Vector2(((Rect)(ref hull)).x + (local.x - layout.MinX) * ppmX, ((Rect)(ref hull)).y + (layout.MaxZ - local.z) * ppmZ);
			}
		}

		private static void DrawOar(Vector2 seat, float row, bool allowed, float scale)
		{
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: 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_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			Sprite oar = GameSprites.Oar;
			if (Object.op_Implicit((Object)(object)oar))
			{
				float angle = 0f;
				if (row != 0f && allowed)
				{
					angle = ((row > 0f) ? (Mathf.Sin(Time.time * 6f) * 20f) : (Mathf.Sin(Time.time * -3f) * 40f));
				}
				Rect rect = oar.rect;
				float num = 20f * ((Rect)(ref rect)).width;
				rect = oar.rect;
				float num2 = num / ((Rect)(ref rect)).height;
				GameSprites.Draw(new Rect(seat.x - num2 * 0.5f, seat.y - 10f, num2, 20f), oar, angle, allowed ? Color.white : InactiveColor, scale);
			}
		}

		private static Rect Centered(Vector2 c, float size)
		{
			//IL_0000: 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)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			return new Rect(c.x - size * 0.5f, c.y - size * 0.5f, size, size);
		}

		private static void DrawTinted(Rect rect, Texture2D texture, Color color)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: 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)
			Color color2 = GUI.color;
			GUI.color = color;
			GUI.DrawTexture(rect, (Texture)(object)texture, (ScaleMode)0, true);
			GUI.color = color2;
		}

		private void EnsureResources()
		{
			if (!Object.op_Implicit((Object)(object)_circle))
			{
				_circle = Procedural(32, (float u, float v) => Coverage(0.46f - Mathf.Sqrt(u * u + v * v), 32));
				_ring = Procedural(32, delegate(float u, float v)
				{
					float num = Mathf.Sqrt(u * u + v * v);
					return Mathf.Min(Coverage(0.46f - num, 32), Coverage(num - 0.32f, 32));
				});
				_arrowUp = Procedural(32, (float u, float v) => Coverage(Mathf.Min(v + 0.4f, (0.4f - v) * 0.5f - Mathf.Abs(u) * 1f), 32));
				_arrowDown = Procedural(32, (float u, float v) => Coverage(Mathf.Min(0f - v + 0.4f, (0.4f + v) * 0.5f - Mathf.Abs(u) * 1f), 32));
			}
		}

		private Texture2D GetHullTexture(ShipLayout layout, float width, float height)
		{
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: 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_01cd: 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_01d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			if (_hullTextures.TryGetValue(layout, out var value) && Object.op_Implicit((Object)(object)value))
			{
				return value;
			}
			int num = Mathf.Clamp(Mathf.RoundToInt(width * 2f), 32, 256);
			int num2 = Mathf.Clamp(Mathf.RoundToInt(height * 2f), 64, 512);
			value = NewTexture(num, num2);
			Color32[] array = (Color32[])(object)new Color32[num * num2];
			Color val = default(Color);
			for (int i = 0; i < num2; i++)
			{
				float num3 = ((float)i + 0.5f) / (float)num2 * 2f - 1f;
				float num4 = ((num3 >= 0f) ? Mathf.Pow(Mathf.Max(0f, 1f - num3 * num3), 0.6f) : Mathf.Pow(Mathf.Max(0f, 1f - Mathf.Pow(0f - num3, 2.5f)), 0.55f));
				for (int j = 0; j < num; j++)
				{
					float num5 = Mathf.Abs(((float)j + 0.5f) / (float)num * 2f - 1f);
					float num6 = (num4 - num5) * (float)num * 0.5f;
					if (num6 <= -1f)
					{
						val = Color.clear;
					}
					else if (num6 < 3f)
					{
						((Color)(ref val))..ctor(HullEdge.r, HullEdge.g, HullEdge.b, HullEdge.a * Mathf.Clamp01(num6 + 1f));
					}
					else
					{
						val = HullFill;
						if (Mathf.Repeat((float)i, 10f) < 1f)
						{
							val *= 0.85f;
						}
						if (num5 * (float)num * 0.5f < 1f)
						{
							val = Color.Lerp(val, HullEdge, 0.5f);
						}
						val.a = HullFill.a;
					}
					array[i * num + j] = Color32.op_Implicit(val);
				}
			}
			value.SetPixels32(array);
			value.Apply();
			_hullTextures[layout] = value;
			return value;
		}

		private static float Coverage(float signedDistance, int size)
		{
			return Mathf.Clamp01(signedDistance * (float)size + 0.5f);
		}

		private static Texture2D Procedural(int size, Func<float, float, float> alpha)
		{
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			Texture2D val = NewTexture(size, size);
			Color32[] array = (Color32[])(object)new Color32[size * size];
			for (int i = 0; i < size; i++)
			{
				for (int j = 0; j < size; j++)
				{
					float arg = ((float)j + 0.5f) / (float)size - 0.5f;
					float arg2 = ((float)i + 0.5f) / (float)size - 0.5f;
					array[i * size + j] = Color32.op_Implicit(new Color(1f, 1f, 1f, alpha(arg, arg2)));
				}
			}
			val.SetPixels32(array);
			val.Apply();
			return val;
		}

		private static Texture2D NewTexture(int w, int h)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: 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_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Expected O, but got Unknown
			return new Texture2D(w, h, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)1,
				wrapMode = (TextureWrapMode)1,
				hideFlags = (HideFlags)61
			};
		}
	}
	[BepInPlugin("farias.SailingTogether", "SailingTogether", "1.0.0")]
	public class SailingTogetherPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "farias.SailingTogether";

		public const string ModName = "SailingTogether";

		public const string ModVersion = "1.0.0";

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<float> PowerPerRower;

		internal static ConfigEntry<float> TurnAccelPerRower;

		internal static ConfigEntry<float> MaxTurnRate;

		internal static ConfigEntry<float> CenterDeadZone;

		internal static ConfigEntry<bool> RowInStop;

		internal static ConfigEntry<bool> RowInBack;

		internal static ConfigEntry<bool> ShowHint;

		internal static ConfigEntry<bool> ShowHud;

		internal static ConfigEntry<float> HudScale;

		internal static ConfigEntry<float> HudOffsetX;

		internal static ConfigEntry<float> HudOffsetY;

		internal static ConfigEntry<string> HudShipSprite;

		internal static ConfigEntry<string> HudArrowSprite;

		internal static ConfigEntry<string> HudOarSprite;

		internal static ConfigEntry<bool> DebugTool;

		internal static ConfigEntry<KeyboardShortcut> DebugHotkey;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0304: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enables/disables cooperative rowing.");
			PowerPerRower = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "PowerPerRower", 0.35f, "Force of each rower, as a fraction of the ship's own helm-oar force (speed 1).");
			TurnAccelPerRower = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "TurnAccelPerRower", 10f, "Turn acceleration (degrees/s²) produced by each unbalanced rower (e.g. one side rowing and the other not).");
			MaxTurnRate = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "MaxTurnRate", 25f, "Maximum turn rate (degrees/s) the rowers can apply to the ship.");
			CenterDeadZone = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "CenterDeadZone", 0.4f, "Lateral distance (meters) from the ship's centerline within which a bench counts as 'center' (pushes only, does not turn).");
			RowInStop = ((BaseUnityPlugin)this).Config.Bind<bool>("Rowing", "RowInStop", false, "Allows rowing while the ship is stopped (speed 0), even with nobody at the helm.");
			RowInBack = ((BaseUnityPlugin)this).Config.Bind<bool>("Rowing", "RowInBack", true, "Allows rowing while the ship is in reverse.");
			ShowHint = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowHint", true, "Shows the controls hint when sitting on a ship bench.");
			ShowHud = ((BaseUnityPlugin)this).Config.Bind<bool>("Hud", "ShowShipHud", true, "Shows the top-down ship HUD with the benches (helmsman: all benches, rower: only their own).");
			HudScale = ((BaseUnityPlugin)this).Config.Bind<float>("Hud", "Scale", 1f, "Scale of the ship HUD.");
			HudOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("Hud", "OffsetX", 30f, "Distance (px at 1080p) from the right edge of the screen.");
			HudOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("Hud", "OffsetY", 230f, "Distance (px at 1080p) from the bottom edge of the screen.");
			HudShipSprite = ((BaseUnityPlugin)this).Config.Bind<string>("Hud", "ShipSprite", "ship_top", "Name of the game sprite used for the ship (bow up). Empty = built-in drawing.");
			HudArrowSprite = ((BaseUnityPlugin)this).Config.Bind<string>("Hud", "ArrowSprite", "winddirection", "Name of the game sprite used for the arrows (tip up). Empty = built-in drawing.");
			HudOarSprite = ((BaseUnityPlugin)this).Config.Bind<string>("Hud", "OarSprite", "ship_rudder_icon", "Name of the game sprite used for the animated oar on each occupied bench. Empty = no oar.");
			HudOarSprite.SettingChanged += delegate
			{
				GameSprites.Reset();
			};
			HudShipSprite.SettingChanged += delegate
			{
				GameSprites.Reset();
			};
			HudArrowSprite.SettingChanged += delegate
			{
				GameSprites.Reset();
			};
			DebugTool = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "SimulatorPanel", false, "Enables the simulated rowers panel (F8), for testing alone. Default: disabled.");
			DebugHotkey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Debug", "SimulatorHotkey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Key that opens/closes the simulated rowers panel.");
			((Component)this).gameObject.AddComponent<DebugPanel>();
			((Component)this).gameObject.AddComponent<RowingHud>();
			_harmony = new Harmony("farias.SailingTogether");
			_harmony.PatchAll(typeof(SailingTogetherPlugin).Assembly);
			((BaseUnityPlugin)this).Logger.LogInfo((object)"SailingTogether 1.0.0 loaded.");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
	internal static class ShipAccess
	{
		internal static readonly FieldRef<Ship, List<Player>> Players = AccessTools.FieldRefAccess<Ship, List<Player>>("m_players");

		internal static float SideOf(float localX)
		{
			if (!(Mathf.Abs(localX) < SailingTogetherPlugin.CenterDeadZone.Value))
			{
				return Mathf.Sign(localX);
			}
			return 0f;
		}

		internal static bool RowingAllowed(Speed speed)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Expected I4, but got Unknown
			return (int)speed switch
			{
				2 => true, 
				1 => SailingTogetherPlugin.RowInBack.Value, 
				0 => SailingTogetherPlugin.RowInStop.Value, 
				_ => false, 
			};
		}
	}
	internal class ShipLayout
	{
		internal class Seat
		{
			public Vector3 Local;
		}

		private static readonly Dictionary<string, ShipLayout> s_cache = new Dictionary<string, ShipLayout>();

		public readonly List<Seat> Seats = new List<Seat>();

		public bool HasHelm;

		public Vector3 HelmLocal;

		public float MinX;

		public float MaxX;

		public float MinZ;

		public float MaxZ;

		public float Length => MaxZ - MinZ;

		public float Width => MaxX - MinX;

		internal static ShipLayout Get(Ship ship)
		{
			string prefabName = Utils.GetPrefabName(((Component)ship).gameObject);
			if (!s_cache.TryGetValue(prefabName, out var value))
			{
				value = Build(ship);
				s_cache[prefabName] = value;
			}
			return value;
		}

		private static ShipLayout Build(Ship ship)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: 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_0137: 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_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c2: 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_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0182: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)ship).transform;
			ShipLayout shipLayout = new ShipLayout();
			Chair[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Chair>();
			foreach (Chair val in componentsInChildren)
			{
				Transform val2 = (Object.op_Implicit((Object)(object)val.m_attachPoint) ? val.m_attachPoint : ((Component)val).transform);
				shipLayout.Seats.Add(new Seat
				{
					Local = transform.InverseTransformPoint(val2.position)
				});
			}
			shipLayout.Seats.Sort((Seat a, Seat b) => (!(Mathf.Abs(a.Local.z - b.Local.z) > 0.05f)) ? a.Local.x.CompareTo(b.Local.x) : b.Local.z.CompareTo(a.Local.z));
			if (Object.op_Implicit((Object)(object)ship.m_shipControlls))
			{
				Transform val3 = (Object.op_Implicit((Object)(object)ship.m_shipControlls.m_attachPoint) ? ship.m_shipControlls.m_attachPoint : ((Component)ship.m_shipControlls).transform);
				shipLayout.HasHelm = true;
				shipLayout.HelmLocal = transform.InverseTransformPoint(val3.position);
			}
			shipLayout.MinX = (shipLayout.MinZ = float.MaxValue);
			shipLayout.MaxX = (shipLayout.MaxZ = float.MinValue);
			if (Object.op_Implicit((Object)(object)ship.m_floatCollider))
			{
				BoxCollider floatCollider = ship.m_floatCollider;
				Vector3 val4 = floatCollider.size * 0.5f;
				for (int num = -1; num <= 1; num += 2)
				{
					for (int num2 = -1; num2 <= 1; num2 += 2)
					{
						shipLayout.Encapsulate(transform.InverseTransformPoint(((Component)floatCollider).transform.TransformPoint(floatCollider.center + new Vector3(val4.x * (float)num, 0f, val4.z * (float)num2))), 0f);
					}
				}
			}
			foreach (Seat seat in shipLayout.Seats)
			{
				shipLayout.Encapsulate(seat.Local, 0.6f);
			}
			if (shipLayout.HasHelm)
			{
				shipLayout.Encapsulate(shipLayout.HelmLocal, 0.6f);
			}
			if (shipLayout.MinX > shipLayout.MaxX)
			{
				shipLayout.MinX = -1.5f;
				shipLayout.MaxX = 1.5f;
				shipLayout.MinZ = -4f;
				shipLayout.MaxZ = 4f;
			}
			return shipLayout;
		}

		private void Encapsulate(Vector3 p, float margin)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: 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)
			MinX = Mathf.Min(MinX, p.x - margin);
			MaxX = Mathf.Max(MaxX, p.x + margin);
			MinZ = Mathf.Min(MinZ, p.z - margin);
			MaxZ = Mathf.Max(MaxZ, p.z + margin);
		}

		internal int NearestSeat(Vector3 local, float maxDistance)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			int result = -1;
			float num = maxDistance * maxDistance;
			for (int i = 0; i < Seats.Count; i++)
			{
				Vector3 val = Seats[i].Local - local;
				val.y *= 0.5f;
				float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
				if (sqrMagnitude < num)
				{
					num = sqrMagnitude;
					result = i;
				}
			}
			return result;
		}
	}
	[HarmonyPatch(typeof(Ship), "CustomFixedUpdate")]
	internal static class Ship_CustomFixedUpdate_Patch
	{
		private static readonly FieldRef<Ship, ZNetView> s_nview = AccessTools.FieldRefAccess<Ship, ZNetView>("m_nview");

		private static readonly FieldRef<Ship, Rigidbody> s_body = AccessTools.FieldRefAccess<Ship, Rigidbody>("m_body");

		private static readonly FieldRef<Ship, WaterVolume> s_previousCenter = AccessTools.FieldRefAccess<Ship, WaterVolume>("m_previousCenter");

		private static void Postfix(Ship __instance, float fixedDeltaTime)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_01bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_023e: Unknown result type (might be due to invalid IL or missing references)
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			//IL_025f: 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_02e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ea: Unknown result type (might be due to invalid IL or missing references)
			if (!SailingTogetherPlugin.Enabled.Value)
			{
				return;
			}
			ZNetView val = s_nview.Invoke(__instance);
			if (!Object.op_Implicit((Object)(object)val) || !val.IsValid())
			{
				return;
			}
			RowingStats stats = RowingStats.For(__instance);
			stats.Reset();
			stats.IsOwner = val.IsOwner();
			if (!stats.IsOwner)
			{
				return;
			}
			stats.Allowed = ShipAccess.RowingAllowed(__instance.GetSpeedSetting());
			Transform transform = ((Component)__instance).transform;
			float thrust = 0f;
			float turn = 0f;
			List<Player> list = ShipAccess.Players.Invoke(__instance);
			if (list != null)
			{
				long num = (Object.op_Implicit((Object)(object)__instance.m_shipControlls) ? __instance.m_shipControlls.GetUser() : 0);
				foreach (Player item in list)
				{
					if (Object.op_Implicit((Object)(object)item) && item.GetPlayerID() != num && RowerInput.TryGetRower(item, out var row))
					{
						AddRower(transform.InverseTransformPoint(((Component)item).transform.position).x, row);
					}
				}
			}
			foreach (DebugPanel.SimSeat simulatedSeat in DebugPanel.GetSimulatedSeats(__instance))
			{
				AddRower(simulatedSeat.LocalX, simulatedSeat.Row);
			}
			stats.Thrust = thrust;
			stats.Turn = turn;
			Rigidbody val2 = s_body.Invoke(__instance);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				return;
			}
			stats.YawRate = Vector3.Dot(val2.angularVelocity, transform.up) * 57.29578f;
			stats.Floating = IsFloating(__instance, val2);
			if (stats.Allowed && stats.Floating && (thrust != 0f || turn != 0f))
			{
				stats.Applied = true;
				float num2 = __instance.m_backwardForce * SailingTogetherPlugin.PowerPerRower.Value;
				val2.AddForce(transform.forward * (thrust * num2 * fixedDeltaTime), (ForceMode)2);
				Vector3 up = transform.up;
				float yawRate = stats.YawRate;
				float num3 = (0f - turn) * SailingTogetherPlugin.TurnAccelPerRower.Value * fixedDeltaTime;
				float value = SailingTogetherPlugin.MaxTurnRate.Value;
				if (num3 > 0f)
				{
					num3 = Mathf.Min(num3, Mathf.Max(0f, value - yawRate));
				}
				else if (num3 < 0f)
				{
					num3 = Mathf.Max(num3, Mathf.Min(0f, 0f - value - yawRate));
				}
				if (num3 != 0f)
				{
					val2.AddTorque(up * (num3 * ((float)Math.PI / 180f)), (ForceMode)2);
				}
			}
			void AddRower(float localX, float num4)
			{
				num4 = Mathf.Clamp(num4, -1f, 1f);
				if (!(Mathf.Abs(num4) < 0.05f))
				{
					float num5 = ShipAccess.SideOf(localX);
					thrust += num4;
					turn += num4 * num5;
					stats.Rowers++;
				}
			}
		}

		private static bool IsFloating(Ship ship, Rigidbody body)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			Vector3 worldCenterOfMass = body.worldCenterOfMass;
			float waterLevel = Floating.GetWaterLevel(worldCenterOfMass, ref s_previousCenter.Invoke(ship));
			return worldCenterOfMass.y - waterLevel - ship.m_waterLevelOffset <= ship.m_disableLevel;
		}
	}
	internal class RowingStats
	{
		private static readonly RowingStats s_empty = new RowingStats();

		private static Ship s_ship;

		private static readonly RowingStats s_current = new RowingStats();

		public bool IsOwner;

		public bool Allowed;

		public bool Floating;

		public bool Applied;

		public int Rowers;

		public float Thrust;

		public float Turn;

		public float YawRate;

		internal static RowingStats For(Ship ship)
		{
			if ((Object)(object)ship != (Object)(object)Ship.GetLocalShip())
			{
				return s_empty;
			}
			s_ship = ship;
			return s_current;
		}

		internal static RowingStats Get(Ship ship)
		{
			if (!Object.op_Implicit((Object)(object)ship) || !((Object)(object)ship == (Object)(object)s_ship))
			{
				return null;
			}
			return s_current;
		}

		internal void Reset()
		{
			IsOwner = (Allowed = (Floating = (Applied = false)));
			Rowers = 0;
			Thrust = (Turn = (YawRate = 0f));
		}
	}
}