Decompiled source of CrewManualSailControl v0.9.5

ManualSail.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
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.Rendering;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("ManualSail")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyInformationalVersion("0.1.0")]
[assembly: AssemblyProduct("ManualSail")]
[assembly: AssemblyTitle("ManualSail")]
[assembly: AssemblyVersion("0.1.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 ManualSail
{
	[BepInPlugin("com.bouns.manualsail", "Manual Sail", "0.9.5")]
	public class Plugin : BaseUnityPlugin
	{
		internal sealed class OarCfg
		{
			public ConfigEntry<int> count;

			public ConfigEntry<float> side;

			public ConfigEntry<float> spacing;

			public ConfigEntry<float> height;

			public ConfigEntry<float> stand;

			public ConfigEntry<float> length;

			public ConfigEntry<float> width;
		}

		internal sealed class RowerState
		{
			public readonly Dictionary<long, float> beats = new Dictionary<long, float>();
		}

		public const string GUID = "com.bouns.manualsail";

		public const string NAME = "Manual Sail";

		public const string VERSION = "0.9.5";

		internal static ManualLogSource Log;

		internal const string ZKEY = "bouns_sailyaw";

		internal const string RPC = "bouns_setsail";

		internal const string RPC_ROW = "bouns_row";

		internal const string ZKEY_ROWERS = "bouns_rowers";

		internal const float ROW_ACCEL = 9.8f;

		private static readonly FieldInfo F_nview = AccessTools.Field(typeof(Ship), "m_nview");

		private static readonly MethodInfo M_isSailUp = AccessTools.Method(typeof(Ship), "IsSailUp", (Type[])null, (Type[])null);

		private static readonly FieldInfo F_shipControlls = AccessTools.Field(typeof(Ship), "m_shipControlls");

		private static readonly FieldInfo F_scAnim = AccessTools.Field(typeof(ShipControlls), "m_attachAnimation");

		private static readonly FieldInfo F_scDetach = AccessTools.Field(typeof(ShipControlls), "m_detachOffset");

		private static readonly FieldInfo F_scAttachPoint = AccessTools.Field(typeof(ShipControlls), "m_attachPoint");

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<KeyCode> KeyLeft;

		internal static ConfigEntry<KeyCode> KeyRight;

		internal static ConfigEntry<float> RotateSpeed;

		internal static ConfigEntry<float> MaxAngle;

		internal static ConfigEntry<float> MinEfficiency;

		internal static ConfigEntry<bool> Debug;

		internal static ConfigEntry<bool> OarsEnabled;

		internal static ConfigEntry<float> BonusUp;

		internal static ConfigEntry<float> BonusDown;

		private static readonly Dictionary<string, OarCfg> _oarCfg = new Dictionary<string, OarCfg>();

		private Ship _editShip;

		private float _editYaw;

		private float _lastRpcYaw;

		private float _lastRpcTime;

		private bool _wasRowing;

		private Ship _rowShip;

		private float _lastRowBeat;

		internal static bool StationRowing;

		internal static Ship StationShip;

		internal static OarStation CurrentStation;

		private static readonly ConditionalWeakTable<Ship, RowerState> _rowers = new ConditionalWeakTable<Ship, RowerState>();

		private static readonly List<long> _staleBuf = new List<long>();

		private static Font _font;

		private static bool _fontTried;

		private const string Deg = "°";

		private void Awake()
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: Expected O, but got Unknown
			//IL_011b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Expected O, but got Unknown
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01df: Expected O, but got Unknown
			//IL_02a5: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch for the whole mod (manual sail + oars). false = vanilla.");
			KeyLeft = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "RotateSailLeft", (KeyCode)276, "Hold to swing the sail to port (left).");
			KeyRight = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "RotateSailRight", (KeyCode)275, "Hold to swing the sail to starboard (right).");
			RotateSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "RotateSpeedDegPerSec", 60f, new ConfigDescription("How fast the sail swings while a key is held.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(5f, 360f), Array.Empty<object>()));
			MaxAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Controls", "MaxAngleDeg", 90f, new ConfigDescription("Maximum swing to each side.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 90f), Array.Empty<object>()));
			MinEfficiency = ((BaseUnityPlugin)this).Config.Bind<float>("Sailing", "MinEfficiency", 0.25f, new ConfigDescription("Lowest wind efficiency, even with the sail badly trimmed or into the wind. 0 = you can be brought to a full stop. 0.25 = you always keep some way on.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
			Debug = ((BaseUnityPlugin)this).Config.Bind<bool>("HUD", "Debug", false, "true = show a small sail angle and wind efficiency overlay while aboard a ship.");
			OarsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Oars", "Enabled", true, "Crew oars: players aboard can man an oar to add speed.");
			BonusUp = ((BaseUnityPlugin)this).Config.Bind<float>("Oars", "SpeedBonusPerRowerSailUp", 6f, new ConfigDescription("Speed bonus per active rower when the sail is up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			BonusDown = ((BaseUnityPlugin)this).Config.Bind<float>("Oars", "SpeedBonusPerRowerSailDown", 4f, new ConfigDescription("Speed bonus per active rower when the sail is down.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>()));
			Bind("Raft", "Oars 1 Raft", 2, 1.2f, 1.2f, 0.8f, 0f, 1f, 1f);
			Bind("Karve", "Oars 2 Karve", 2, 0.8f, 3.5f, 0.3f, 0f, 1f, 1f);
			Bind("Longship", "Oars 3 Longship", 4, 2f, 4f, 1.2f, 0f, 1f, 1f);
			Bind("Drakkar", "Oars 4 Drakkar", 4, 3f, 9f, 2.4f, -2f, 1.6f, 1.6f);
			try
			{
				new Harmony("com.bouns.manualsail").PatchAll();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Manual Sail v0.9.5 loaded.");
			}
			catch (Exception ex)
			{
				((BaseUnityPlugin)this).Logger.LogError((object)("Manual Sail v0.9.5 FAILED to patch (Valheim version mismatch?): " + ex));
			}
			void Bind(string key, string section, int cnt, float side, float sp, float h, float stand, float len, float wid)
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected O, but got Unknown
				//IL_005c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0066: Expected O, but got Unknown
				//IL_0093: Unknown result type (might be due to invalid IL or missing references)
				//IL_009d: Expected O, but got Unknown
				//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
				//IL_00d4: Expected O, but got Unknown
				//IL_0101: Unknown result type (might be due to invalid IL or missing references)
				//IL_010b: Expected O, but got Unknown
				//IL_0138: Unknown result type (might be due to invalid IL or missing references)
				//IL_0142: Expected O, but got Unknown
				//IL_016f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0179: Expected O, but got Unknown
				OarCfg value = new OarCfg
				{
					count = ((BaseUnityPlugin)this).Config.Bind<int>(section, "OarCount", cnt, new ConfigDescription("Number of oars (0 disables).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>())),
					side = ((BaseUnityPlugin)this).Config.Bind<float>(section, "SideOffset", side, new ConfigDescription("Distance from center to each side. Live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 8f), Array.Empty<object>())),
					spacing = ((BaseUnityPlugin)this).Config.Bind<float>(section, "Spacing", sp, new ConfigDescription("Spacing along the hull between oars on the same side. Live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 10f), Array.Empty<object>())),
					height = ((BaseUnityPlugin)this).Config.Bind<float>(section, "Height", h, new ConfigDescription("Oar visual height above the boat origin. Live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-2f, 6f), Array.Empty<object>())),
					stand = ((BaseUnityPlugin)this).Config.Bind<float>(section, "StandOffset", stand, new ConfigDescription("Vertical offset for where the rower stands. Lower it if they float above the deck. Live.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(-3f, 3f), Array.Empty<object>())),
					length = ((BaseUnityPlugin)this).Config.Bind<float>(section, "OarLength", len, new ConfigDescription("Oar length multiplier (extends the blade end). Applied when the boat loads.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 4f), Array.Empty<object>())),
					width = ((BaseUnityPlugin)this).Config.Bind<float>(section, "OarWidth", wid, new ConfigDescription("Oar thickness multiplier. Applied when the boat loads.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.3f, 4f), Array.Empty<object>()))
				};
				_oarCfg[key] = value;
			}
		}

		internal static float GetYaw(Ship s)
		{
			if ((Object)(object)s == (Object)null)
			{
				return 0f;
			}
			object? value = F_nview.GetValue(s);
			ZNetView val = (ZNetView)((value is ZNetView) ? value : null);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return 0f;
			}
			return val.GetZDO().GetFloat("bouns_sailyaw", 0f);
		}

		internal static ZNetView NView(Ship s)
		{
			if (!((Object)(object)s == (Object)null))
			{
				object? value = F_nview.GetValue(s);
				return (ZNetView)((value is ZNetView) ? value : null);
			}
			return null;
		}

		internal static bool SailUp(Ship s)
		{
			try
			{
				return M_isSailUp != null && (bool)M_isSailUp.Invoke(s, null);
			}
			catch
			{
				return true;
			}
		}

		internal static Vector3 SailNormal(Ship s, float yaw)
		{
			//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)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			return Quaternion.AngleAxis(yaw, Vector3.up) * ((Component)s).transform.forward;
		}

		internal static float Efficiency(Ship s, float yaw)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: 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_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			float num = ((MinEfficiency != null) ? MinEfficiency.Value : 0f);
			EnvMan instance = EnvMan.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return num;
			}
			Vector3 windDir = instance.GetWindDir();
			Vector3 val = SailNormal(s, yaw);
			float num2 = Mathf.Max(0f, Vector3.Dot(windDir, val));
			return Mathf.Clamp01(Mathf.Max(num, num2));
		}

		private static Ship FindMyShip(Player local)
		{
			List<IMonoUpdater> instances = Ship.Instances;
			if (instances == null)
			{
				return null;
			}
			for (int i = 0; i < instances.Count; i++)
			{
				IMonoUpdater obj = instances[i];
				Ship val = (Ship)(object)((obj is Ship) ? obj : null);
				if ((Object)(object)val != (Object)null && val.IsPlayerInBoat(local))
				{
					return val;
				}
			}
			return null;
		}

		internal static string BoatKey(Ship s)
		{
			string text = (((Object)(object)s != (Object)null && ((Object)s).name != null) ? ((Object)s).name.ToLowerInvariant() : "");
			if (text.Contains("raft"))
			{
				return "Raft";
			}
			if (text.Contains("karve"))
			{
				return "Karve";
			}
			if (text.Contains("cargo"))
			{
				return null;
			}
			if (text.Contains("ashlands"))
			{
				return "Drakkar";
			}
			if (!text.Contains("vikingship"))
			{
				text.Contains("longship");
			}
			return "Longship";
		}

		internal static OarCfg CfgFor(Ship s)
		{
			string text = BoatKey(s);
			if (text == null || !_oarCfg.TryGetValue(text, out var value))
			{
				return null;
			}
			return value;
		}

		internal static int OarCount(Ship s)
		{
			return CfgFor(s)?.count.Value ?? 0;
		}

		internal static RowerState Rowers(Ship s)
		{
			return _rowers.GetOrCreateValue(s);
		}

		internal static int CountAndPurgeRowers(Ship s)
		{
			if (!_rowers.TryGetValue(s, out var value) || value.beats.Count == 0)
			{
				return 0;
			}
			float time = Time.time;
			_staleBuf.Clear();
			foreach (KeyValuePair<long, float> beat in value.beats)
			{
				if (time - beat.Value > 1.5f)
				{
					_staleBuf.Add(beat.Key);
				}
			}
			for (int i = 0; i < _staleBuf.Count; i++)
			{
				value.beats.Remove(_staleBuf[i]);
			}
			int num = OarCount(s);
			int count = value.beats.Count;
			if (count >= num)
			{
				return num;
			}
			return count;
		}

		internal static int RowerCount(Ship s)
		{
			ZNetView val = NView(s);
			if ((Object)(object)val == (Object)null || !val.IsValid())
			{
				return 0;
			}
			return Mathf.RoundToInt(val.GetZDO().GetFloat("bouns_rowers", 0f));
		}

		internal static string SteerAnim(Ship s)
		{
			try
			{
				object value = F_shipControlls.GetValue(s);
				string text = ((value != null) ? (F_scAnim.GetValue(value) as string) : null);
				return string.IsNullOrEmpty(text) ? "attach_chair" : text;
			}
			catch
			{
				return "attach_chair";
			}
		}

		internal static Vector3 SteerDetach(Ship s)
		{
			//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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				object value = F_shipControlls.GetValue(s);
				if (value != null)
				{
					return (Vector3)F_scDetach.GetValue(value);
				}
			}
			catch
			{
			}
			return new Vector3(0f, 0.5f, 0f);
		}

		internal static float DeckY(Ship s)
		{
			//IL_0033: 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)
			try
			{
				object value = F_shipControlls.GetValue(s);
				Transform val = (Transform)((value != null) ? /*isinst with value type is only supported in some contexts*/: null);
				if ((Object)(object)val != (Object)null)
				{
					return ((Component)s).transform.InverseTransformPoint(val.position).y;
				}
			}
			catch
			{
			}
			return 0.5f;
		}

		internal static void ClearStationFlags()
		{
			StationRowing = false;
			StationShip = null;
			CurrentStation = null;
		}

		internal static void LeaveStation()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null && localPlayer.GetDoodadController() != null)
			{
				localPlayer.StopDoodadControl();
				return;
			}
			if ((Object)(object)localPlayer != (Object)null && ((Character)localPlayer).IsAttached())
			{
				((Character)localPlayer).AttachStop();
			}
			ClearStationFlags();
		}

		private void ApplyYaw(Ship ship, float yaw)
		{
			ZNetView val = NView(ship);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				if (val.IsOwner())
				{
					val.GetZDO().Set("bouns_sailyaw", yaw);
				}
				else if (Mathf.Abs(yaw - _lastRpcYaw) > 0.01f && Time.time - _lastRpcTime > 0.1f)
				{
					val.InvokeRPC("bouns_setsail", new object[1] { yaw });
					_lastRpcYaw = yaw;
					_lastRpcTime = Time.time;
				}
			}
		}

		private void SendRow(Ship ship, bool on)
		{
			ZNetView val = NView(ship);
			if (!((Object)(object)val == (Object)null) && val.IsValid())
			{
				val.InvokeRPC("bouns_row", new object[1] { on ? 1 : 0 });
			}
		}

		private void StopRowing()
		{
			if (_wasRowing && (Object)(object)_rowShip != (Object)null)
			{
				SendRow(_rowShip, on: false);
			}
			if (StationRowing)
			{
				LeaveStation();
			}
			_wasRowing = false;
			_rowShip = null;
		}

		private void Update()
		{
			if (!Enabled.Value)
			{
				_editShip = null;
				StopRowing();
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				_editShip = null;
				StopRowing();
				return;
			}
			Ship val = FindMyShip(localPlayer);
			if ((Object)(object)val == (Object)null)
			{
				_editShip = null;
				StopRowing();
			}
			else
			{
				HandleSail(val);
				HandleRowing(localPlayer);
			}
		}

		private void HandleSail(Ship ship)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			float num = 0f;
			if (Input.GetKey(KeyLeft.Value))
			{
				num -= 1f;
			}
			if (Input.GetKey(KeyRight.Value))
			{
				num += 1f;
			}
			if (num == 0f)
			{
				_editShip = null;
				return;
			}
			if ((Object)(object)_editShip != (Object)(object)ship)
			{
				_editShip = ship;
				_editYaw = GetYaw(ship);
			}
			_editYaw = Mathf.Clamp(_editYaw + num * RotateSpeed.Value * Time.deltaTime, 0f - MaxAngle.Value, MaxAngle.Value);
			ApplyYaw(ship, _editYaw);
		}

		private void HandleRowing(Player local)
		{
			if (!OarsEnabled.Value)
			{
				if (_wasRowing && (Object)(object)_rowShip != (Object)null)
				{
					SendRow(_rowShip, on: false);
				}
				if (StationRowing)
				{
					LeaveStation();
				}
				_wasRowing = false;
				return;
			}
			if (StationRowing && ((Object)(object)local == (Object)null || !((Character)local).IsAttached()))
			{
				ClearStationFlags();
			}
			bool stationRowing = StationRowing;
			Ship stationShip = StationShip;
			if (stationRowing && (Object)(object)stationShip != (Object)null)
			{
				_rowShip = stationShip;
				if (Time.time - _lastRowBeat > 0.5f)
				{
					SendRow(stationShip, on: true);
					_lastRowBeat = Time.time;
				}
			}
			else if (_wasRowing && (Object)(object)_rowShip != (Object)null)
			{
				SendRow(_rowShip, on: false);
			}
			_wasRowing = stationRowing;
		}

		private void OnGUI()
		{
			if (!Enabled.Value)
			{
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			Ship val = FindMyShip(localPlayer);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			if (OarsEnabled.Value)
			{
				int num = RowerCount(val);
				bool stationRowing = StationRowing;
				if (num > 0 || stationRowing)
				{
					DrawLabel("Oars " + num + "/" + OarCount(val) + (stationRowing ? "  (rowing)" : ""), 0.31f);
				}
			}
			if (Debug.Value)
			{
				float num2 = (((Object)(object)_editShip == (Object)(object)val) ? _editYaw : GetYaw(val));
				int num3 = Mathf.RoundToInt(Efficiency(val, num2) * 100f);
				DrawLabel("Sail " + Mathf.RoundToInt(num2) + "°    Wind " + num3 + "%", 0.275f);
			}
		}

		private static void DrawLabel(string txt, float yFrac)
		{
			//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_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: 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_0023: Expected O, but got Unknown
			//IL_0078: 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_00bc: 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)
			GUIStyle val = new GUIStyle
			{
				alignment = (TextAnchor)5,
				fontSize = 18,
				fontStyle = (FontStyle)1,
				richText = false
			};
			Font val2 = GameFont();
			if ((Object)(object)val2 != (Object)null)
			{
				val.font = val2;
			}
			Rect val3 = default(Rect);
			((Rect)(ref val3))..ctor(0f, (float)Screen.height * yFrac, (float)Screen.width - 30f, 26f);
			val.normal.textColor = new Color(0f, 0f, 0f, 0.8f);
			GUI.Label(new Rect(((Rect)(ref val3)).x + 2f, ((Rect)(ref val3)).y + 2f, ((Rect)(ref val3)).width, ((Rect)(ref val3)).height), txt, val);
			val.normal.textColor = Color.white;
			GUI.Label(val3, txt, val);
		}

		private static Font GameFont()
		{
			if (_fontTried)
			{
				return _font;
			}
			_fontTried = true;
			try
			{
				Font val = null;
				Font val2 = null;
				Font[] array = Resources.FindObjectsOfTypeAll<Font>();
				foreach (Font val3 in array)
				{
					if (!((Object)(object)val3 == (Object)null))
					{
						string text = ((Object)val3).name ?? "";
						if ((Object)(object)val == (Object)null && text.IndexOf("Norse", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							val = val3;
						}
						else if ((Object)(object)val2 == (Object)null && text.IndexOf("Averia", StringComparison.OrdinalIgnoreCase) >= 0)
						{
							val2 = val3;
						}
					}
				}
				_font = (((Object)(object)val != (Object)null) ? val : val2);
			}
			catch
			{
				_font = null;
			}
			return _font;
		}
	}
	internal sealed class OarStation : MonoBehaviour, Interactable, Hoverable, IDoodadController
	{
		internal Ship ship;

		internal Plugin.OarCfg cfg;

		internal Transform stand;

		internal Transform oarPivot;

		internal float sideSign;

		internal int slot;

		internal int perSide;

		private float _lastSide = float.NaN;

		private float _lastHeight;

		private float _lastSpacing;

		private float _lastStand;

		private float _deckY;

		private bool _deckYCached;

		private bool _wasActive;

		private void Update()
		{
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0163: 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)
			if (cfg == null)
			{
				return;
			}
			float value = cfg.side.Value;
			float value2 = cfg.height.Value;
			float value3 = cfg.spacing.Value;
			float value4 = cfg.stand.Value;
			if (value != _lastSide || value2 != _lastHeight || value3 != _lastSpacing || value4 != _lastStand)
			{
				_lastSide = value;
				_lastHeight = value2;
				_lastSpacing = value3;
				_lastStand = value4;
				float num = value * sideSign;
				float num2 = ((float)slot - (float)(perSide - 1) * 0.5f) * value3;
				((Component)this).transform.localPosition = new Vector3(num, value2, num2);
				if ((Object)(object)stand != (Object)null)
				{
					if (!_deckYCached)
					{
						_deckY = Plugin.DeckY(ship);
						_deckYCached = true;
					}
					stand.localPosition = new Vector3(num, _deckY + value4, num2);
				}
			}
			if ((Object)(object)oarPivot != (Object)null)
			{
				bool flag = Plugin.StationRowing && (Object)(object)Plugin.CurrentStation == (Object)(object)this;
				if (flag)
				{
					oarPivot.localRotation = Quaternion.Euler(0f, Mathf.Sin(Time.time * 3f) * 22f, 0f);
				}
				else if (_wasActive)
				{
					oarPivot.localRotation = Quaternion.identity;
				}
				_wasActive = flag;
			}
		}

		public bool Interact(Humanoid user, bool hold, bool alt)
		{
			if (hold)
			{
				return false;
			}
			Player val = (Player)(object)((user is Player) ? user : null);
			if ((Object)(object)val == (Object)null || (Object)(object)val != (Object)(object)Player.m_localPlayer)
			{
				return false;
			}
			if (Plugin.StationRowing)
			{
				Plugin.LeaveStation();
			}
			else
			{
				Man(val);
			}
			return true;
		}

		public bool UseItem(Humanoid user, ItemData item)
		{
			return false;
		}

		public string GetHoverText()
		{
			string text = (Plugin.StationRowing ? "[<color=yellow><b>$KEY_Use</b></color>] Leave oar" : "[<color=yellow><b>$KEY_Use</b></color>] Man oar");
			try
			{
				return Localization.instance.Localize(text);
			}
			catch
			{
				return text;
			}
		}

		public string GetHoverName()
		{
			return "Oar";
		}

		public float GetHoverOffset()
		{
			return 0f;
		}

		private void Man(Player p)
		{
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)ship == (Object)null))
			{
				p.StartDoodadControl((IDoodadController)(object)this);
				Transform val = (((Object)(object)stand != (Object)null) ? stand : ((Component)this).transform);
				((Character)p).AttachStart(val, (GameObject)null, false, false, true, Plugin.SteerAnim(ship), Plugin.SteerDetach(ship), (Transform)null);
				Plugin.StationRowing = true;
				Plugin.StationShip = ship;
				Plugin.CurrentStation = this;
			}
		}

		public void ApplyControlls(Vector3 moveDir, Vector3 lookDir, bool run, bool autoRun, bool block)
		{
		}

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

		public Vector3 GetPosition()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return ((Component)this).transform.position;
		}

		public bool IsValid()
		{
			return (Object)(object)ship != (Object)null;
		}

		public void OnUseStop(Player player)
		{
			if ((Object)(object)player != (Object)null && ((Character)player).IsAttached())
			{
				((Character)player).AttachStop();
			}
			Plugin.ClearStationFlags();
		}
	}
	[HarmonyPatch(typeof(Ship), "GetWindAngleFactor")]
	internal static class Patch_GetWindAngleFactor
	{
		private static bool Prefix(Ship __instance, ref float __result)
		{
			if (!Plugin.Enabled.Value)
			{
				return true;
			}
			__result = Plugin.Efficiency(__instance, Plugin.GetYaw(__instance));
			return false;
		}
	}
	[HarmonyPatch(typeof(Ship), "UpdateSail")]
	internal static class Patch_UpdateSail
	{
		private static readonly FieldInfo F_mast = AccessTools.Field(typeof(Ship), "m_mastObject");

		private static void Postfix(Ship __instance)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_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)
			if (!Plugin.Enabled.Value || !Plugin.SailUp(__instance))
			{
				return;
			}
			object? value = F_mast.GetValue(__instance);
			GameObject val = (GameObject)((value is GameObject) ? value : null);
			if (!((Object)(object)val == (Object)null))
			{
				Vector3 val2 = Plugin.SailNormal(__instance, Plugin.GetYaw(__instance));
				if (((Vector3)(ref val2)).sqrMagnitude > 0.0001f)
				{
					val.transform.rotation = Quaternion.LookRotation(val2, Vector3.up);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Ship), "CustomFixedUpdate")]
	internal static class Patch_Ship_Rowing
	{
		private static readonly FieldInfo F_body = AccessTools.Field(typeof(Ship), "m_body");

		private static readonly MethodInfo M_haveCtrl = AccessTools.Method(typeof(Ship), "HaveControllingPlayer", (Type[])null, (Type[])null);

		private static bool HasPilot(Ship s)
		{
			try
			{
				return M_haveCtrl != null && (bool)M_haveCtrl.Invoke(s, null);
			}
			catch
			{
				return true;
			}
		}

		private static void Postfix(Ship __instance)
		{
			//IL_007d: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Invalid comparison between Unknown and I4
			//IL_00d3: 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)
			if (!Plugin.Enabled.Value || !Plugin.OarsEnabled.Value)
			{
				return;
			}
			ZNetView val = Plugin.NView(__instance);
			if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
			{
				return;
			}
			int num = Plugin.CountAndPurgeRowers(__instance);
			val.GetZDO().Set("bouns_rowers", (float)num);
			if (num <= 0 || !HasPilot(__instance))
			{
				return;
			}
			object? value = F_body.GetValue(__instance);
			Rigidbody val2 = (Rigidbody)((value is Rigidbody) ? value : null);
			if (!((Object)(object)val2 == (Object)null))
			{
				Speed speedSetting = __instance.GetSpeedSetting();
				if ((int)speedSetting != 0)
				{
					float num2 = (((int)speedSetting == 1) ? (-1f) : 1f);
					float num3 = (Plugin.SailUp(__instance) ? Plugin.BonusUp.Value : Plugin.BonusDown.Value);
					float num4 = (float)num * (num3 / 100f) * 9.8f;
					val2.AddForce(((Component)__instance).transform.forward * (num2 * num4 * val2.mass), (ForceMode)0);
				}
			}
		}
	}
	[HarmonyPatch(typeof(Ship), "Awake")]
	internal static class Patch_Ship_Awake_Setup
	{
		private static readonly FieldInfo F_nview = AccessTools.Field(typeof(Ship), "m_nview");

		private static Mesh _cubeMesh;

		private static void Postfix(Ship __instance)
		{
			ZNetView nv = default(ZNetView);
			ref ZNetView reference = ref nv;
			object? value = F_nview.GetValue(__instance);
			reference = (ZNetView)((value is ZNetView) ? value : null);
			if ((Object)(object)nv != (Object)null)
			{
				nv.Register<float>("bouns_setsail", (Action<long, float>)delegate(long sender, float yaw)
				{
					if (nv.IsValid() && nv.IsOwner())
					{
						nv.GetZDO().Set("bouns_sailyaw", yaw);
					}
				});
				nv.Register<int>("bouns_row", (Action<long, int>)delegate(long sender, int on)
				{
					if (nv.IsValid() && nv.IsOwner())
					{
						Plugin.RowerState rowerState = Plugin.Rowers(__instance);
						if (on != 0)
						{
							rowerState.beats[sender] = Time.time;
						}
						else
						{
							rowerState.beats.Remove(sender);
						}
					}
				});
			}
			SpawnOarStations(__instance);
		}

		private static void SpawnOarStations(Ship ship)
		{
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Expected O, but got Unknown
			//IL_00a9: 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)
			if (!Plugin.OarsEnabled.Value)
			{
				return;
			}
			Plugin.OarCfg oarCfg = Plugin.CfgFor(ship);
			if (oarCfg == null)
			{
				return;
			}
			int value = oarCfg.count.Value;
			if (value <= 0)
			{
				return;
			}
			int num = LayerMask.NameToLayer("piece");
			Material val = PickHullMaterial(ship);
			int num2 = (value + 1) / 2;
			int num3 = 0;
			for (int i = 0; i < 2; i++)
			{
				if (num3 >= value)
				{
					break;
				}
				float num4 = ((i == 0) ? (-1f) : 1f);
				for (int j = 0; j < num2; j++)
				{
					if (num3 >= value)
					{
						break;
					}
					GameObject val2 = new GameObject("bouns_oar");
					val2.transform.SetParent(((Component)ship).transform, false);
					if (num >= 0)
					{
						val2.layer = num;
					}
					BoxCollider obj = val2.AddComponent<BoxCollider>();
					obj.size = new Vector3(0.8f, 1.2f, 0.8f);
					((Collider)obj).isTrigger = true;
					Transform transform = new GameObject("bouns_oar_stand").transform;
					transform.SetParent(((Component)ship).transform, false);
					OarStation oarStation = val2.AddComponent<OarStation>();
					oarStation.ship = ship;
					oarStation.cfg = oarCfg;
					oarStation.stand = transform;
					oarStation.sideSign = num4;
					oarStation.slot = j;
					oarStation.perSide = num2;
					oarStation.oarPivot = BuildOar(val2.transform, num4, val, oarCfg.length.Value, oarCfg.width.Value);
					num3++;
				}
			}
			ManualLogSource log = Plugin.Log;
			if (log != null)
			{
				log.LogInfo((object)string.Format("[Oars] {0}: placed {1} oar stations (layer 'piece'={2}, mat={3}).", ((Object)ship).name, num3, num, ((Object)(object)val != (Object)null) ? ((Object)val).name : "none"));
			}
		}

		private static Material PickHullMaterial(Ship ship)
		{
			Material val = null;
			MeshRenderer[] componentsInChildren = ((Component)ship).GetComponentsInChildren<MeshRenderer>();
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				Material sharedMaterial = ((Renderer)componentsInChildren[i]).sharedMaterial;
				if (!((Object)(object)sharedMaterial == (Object)null))
				{
					if ((Object)(object)val == (Object)null)
					{
						val = sharedMaterial;
					}
					string text = ((Object)sharedMaterial).name.ToLowerInvariant();
					if (!text.Contains("water") && !text.Contains("mask") && !text.Contains("sail") && !text.Contains("cloth") && !text.Contains("flag") && !text.Contains("rope") && !text.Contains("smoke") && !text.Contains("fx") && !text.Contains("particle") && !text.Contains("foam") && !text.Contains("cloud"))
					{
						return sharedMaterial;
					}
				}
			}
			return val;
		}

		private static Transform BuildOar(Transform parent, float sign, Material mat, float lm, float wm)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: 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)
			//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_007a: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = new GameObject("bouns_oar_pivot").transform;
			transform.SetParent(parent, false);
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(sign * 0.77f, -0.64f, 0f);
			Quaternion rot = Quaternion.FromToRotation(Vector3.right, val);
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(sign * 0.15f, 0.2f, 0f);
			float num = 1.9f * lm;
			float num2 = 0.06f * wm;
			OarPart(transform, mat, val2 + val * (num * 0.5f), rot, new Vector3(num, num2, num2));
			float num3 = 0.55f * wm;
			OarPart(transform, mat, val2 + val * (num + num3 * 0.4f), rot, new Vector3(num3, 0.05f * wm, 0.26f * wm));
			return transform;
		}

		private static Mesh CubeMesh()
		{
			if ((Object)(object)_cubeMesh == (Object)null)
			{
				GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3);
				_cubeMesh = obj.GetComponent<MeshFilter>().sharedMesh;
				Object.Destroy((Object)(object)obj);
			}
			return _cubeMesh;
		}

		private static void OarPart(Transform parent, Material mat, Vector3 pos, Quaternion rot, Vector3 scale)
		{
			//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)
			//IL_0017: 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_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("bouns_oar_part");
			val.transform.SetParent(parent, false);
			val.transform.localPosition = pos;
			val.transform.localRotation = rot;
			val.transform.localScale = scale;
			val.AddComponent<MeshFilter>().sharedMesh = CubeMesh();
			MeshRenderer val2 = val.AddComponent<MeshRenderer>();
			if ((Object)(object)mat != (Object)null)
			{
				((Renderer)val2).sharedMaterial = mat;
			}
			((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0;
		}
	}
}