Decompiled source of Smooth Sailing v0.3.4

plugins/SmoothSailing.dll

Decompiled a week ago
using System;
using System.Collections;
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 Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using MagicaCloth2;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("SmoothSailing")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+8ca184414935f658778b42b69a4425ec3c11c79d")]
[assembly: AssemblyProduct("SmoothSailing")]
[assembly: AssemblyTitle("SmoothSailing")]
[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 SmoothSailing
{
	[BepInPlugin("p377y.valheim.smoothsailing", "Smooth Sailing", "0.3.4")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public sealed class Plugin : BaseUnityPlugin
	{
		internal enum TailwindMode
		{
			Off,
			DeadAstern,
			PositiveOffset,
			NegativeOffset
		}

		internal enum WindIntensityMode
		{
			Vanilla,
			Minimum,
			Maximum
		}

		[CompilerGenerated]
		private static class <>O
		{
			public static CoroutineHandler <0>__OnTailwindModeServerReceive;

			public static CoroutineHandler <1>__OnTailwindModeClientReceive;
		}

		public const string ModGuid = "p377y.valheim.smoothsailing";

		public const string ModName = "Smooth Sailing";

		public const string ModVersion = "0.3.4";

		internal static Plugin Instance;

		internal static ManualLogSource ModLog;

		internal static ConfigEntry<bool> Enabled;

		internal static ConfigEntry<TailwindMode> TailwindModeSetting;

		internal static ConfigEntry<float> OffsetAngle;

		internal static ConfigEntry<WindIntensityMode> WindIntensityModeSetting;

		internal static ConfigEntry<float> MinimumWindIntensity;

		internal static ConfigEntry<KeyboardShortcut> AdminToggleKey;

		internal static ConfigEntry<float> ShipExploreRadiusMultiplier;

		internal static ConfigEntry<float> ForwardRowMultiplier;

		internal static ConfigEntry<float> ReverseRowMultiplier;

		private static readonly Dictionary<Ship, MagicaWindZone> ShipWindZones = new Dictionary<Ship, MagicaWindZone>();

		private Harmony _harmony;

		internal static CustomRPC TailwindModeRPC;

		private static readonly FieldInfo SailForceFactorField = AccessTools.Field(typeof(Ship), "m_sailForceFactor");

		private static readonly FieldInfo SailForceField = AccessTools.Field(typeof(Ship), "m_sailForce");

		private static readonly FieldInfo WindChangeVelocityField = AccessTools.Field(typeof(Ship), "m_windChangeVelocity");

		private void Awake()
		{
			//IL_0031: 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: Expected O, but got Unknown
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Expected O, but got Unknown
			//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_0057: Expected O, but got Unknown
			Instance = this;
			ModLog = ((BaseUnityPlugin)this).Logger;
			BindConfig();
			NetworkManager instance = NetworkManager.Instance;
			object obj = <>O.<0>__OnTailwindModeServerReceive;
			if (obj == null)
			{
				CoroutineHandler val = OnTailwindModeServerReceive;
				<>O.<0>__OnTailwindModeServerReceive = val;
				obj = (object)val;
			}
			object obj2 = <>O.<1>__OnTailwindModeClientReceive;
			if (obj2 == null)
			{
				CoroutineHandler val2 = OnTailwindModeClientReceive;
				<>O.<1>__OnTailwindModeClientReceive = val2;
				obj2 = (object)val2;
			}
			TailwindModeRPC = instance.AddRPC("SmoothSailing_TailwindMode", (CoroutineHandler)obj, (CoroutineHandler)obj2);
			_harmony = new Harmony("p377y.valheim.smoothsailing");
			_harmony.PatchAll();
			((BaseUnityPlugin)this).Logger.LogInfo((object)"Smooth Sailing 0.3.4 loaded.");
		}

		private static IEnumerator OnTailwindModeServerReceive(long sender, ZPackage package)
		{
			if (package == null || (Object)(object)ZNet.instance == (Object)null)
			{
				yield break;
			}
			int num = package.ReadInt();
			if (!Enum.IsDefined(typeof(TailwindMode), num))
			{
				ManualLogSource modLog = ModLog;
				if (modLog != null)
				{
					modLog.LogWarning((object)$"Rejected invalid Smooth Sailing tailwind mode {num} from peer {sender}.");
				}
				yield break;
			}
			ZNetPeer peer = ZNet.instance.GetPeer(sender);
			if (peer == null || peer.m_socket == null || !ZNet.instance.IsAdmin(peer.m_socket.GetHostName()))
			{
				ManualLogSource modLog2 = ModLog;
				if (modLog2 != null)
				{
					modLog2.LogWarning((object)$"Rejected Smooth Sailing tailwind mode change from non-admin peer {sender}.");
				}
				yield break;
			}
			TailwindMode tailwindMode = (TailwindMode)num;
			TailwindModeSetting.Value = tailwindMode;
			ZPackage val = new ZPackage();
			val.Write((int)tailwindMode);
			TailwindModeRPC.SendPackage(ZNet.instance.GetPeers(), val);
			ManualLogSource modLog3 = ModLog;
			if (modLog3 != null)
			{
				modLog3.LogInfo((object)$"Tailwind mode changed to {tailwindMode} by admin peer {sender}.");
			}
		}

		private static IEnumerator OnTailwindModeClientReceive(long sender, ZPackage package)
		{
			if (package == null)
			{
				yield break;
			}
			int num = package.ReadInt();
			if (!Enum.IsDefined(typeof(TailwindMode), num))
			{
				ManualLogSource modLog = ModLog;
				if (modLog != null)
				{
					modLog.LogWarning((object)$"Received invalid Smooth Sailing tailwind mode {num} from server.");
				}
				yield break;
			}
			TailwindMode tailwindMode = (TailwindMode)num;
			TailwindModeSetting.Value = tailwindMode;
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)1, GetTailwindModeDisplay(tailwindMode), 0, (Sprite)null, false);
			}
			ManualLogSource modLog2 = ModLog;
			if (modLog2 != null)
			{
				modLog2.LogInfo((object)$"Tailwind mode synchronized to {tailwindMode}.");
			}
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
			foreach (KeyValuePair<Ship, MagicaWindZone> shipWindZone in ShipWindZones)
			{
				if ((Object)(object)shipWindZone.Value != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)shipWindZone.Value).gameObject);
				}
			}
			ShipWindZones.Clear();
		}

		private void BindConfig()
		{
			//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_000d: Expected O, but got Unknown
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Expected O, but got Unknown
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Expected O, but got Unknown
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Expected O, but got Unknown
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Expected O, but got Unknown
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011c: Expected O, but got Unknown
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Expected O, but got Unknown
			//IL_01c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Expected O, but got Unknown
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_020d: Expected O, but got Unknown
			ConfigurationManagerAttributes val = new ConfigurationManagerAttributes
			{
				IsAdminOnly = true
			};
			Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, new ConfigDescription("Master switch for Smooth Sailing.", (AcceptableValueBase)null, new object[1] { val }));
			TailwindModeSetting = ((BaseUnityPlugin)this).Config.Bind<TailwindMode>("Tailwind", "Tailwind Mode", TailwindMode.DeadAstern, new ConfigDescription("Favorable-wind mode: Off, DeadAstern, PositiveOffset, or NegativeOffset.", (AcceptableValueBase)null, new object[1] { val }));
			OffsetAngle = ((BaseUnityPlugin)this).Config.Bind<float>("Tailwind", "Offset Angle", 60f, new ConfigDescription("Wind angle used by PositiveOffset and NegativeOffset. 0 = dead astern; 60 is near peak vanilla sail efficiency.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 90f), new object[1] { val }));
			WindIntensityModeSetting = ((BaseUnityPlugin)this).Config.Bind<WindIntensityMode>("Tailwind", "Wind Intensity Mode", WindIntensityMode.Vanilla, new ConfigDescription("Sailing wind intensity while a favorable-wind mode is active: Vanilla uses world intensity, Minimum enforces the configured minimum, Maximum always uses full intensity.", (AcceptableValueBase)null, new object[1] { val }));
			MinimumWindIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("Tailwind", "Minimum Wind Intensity", 0.5f, new ConfigDescription("Minimum sailing wind intensity used when Wind Intensity Mode is Minimum. Natural wind stronger than this value is preserved.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[1] { val }));
			AdminToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Tailwind", "Admin Toggle Key", new KeyboardShortcut((KeyCode)107, Array.Empty<KeyCode>()), "Local hotkey used by a server administrator to cycle Off -> DeadAstern -> PositiveOffset -> NegativeOffset.");
			ShipExploreRadiusMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Exploration", "Ship Exploration Radius Multiplier", 2f, new ConfigDescription("Multiplier applied to map exploration radius while aboard a ship. 1 = vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 20f), new object[1] { val }));
			ForwardRowMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "Forward Row Speed Multiplier", 1.5f, new ConfigDescription("Multiplier for forward rowing force (Slow speed). 1 = vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), new object[1] { val }));
			ReverseRowMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Rowing", "Backward Row Speed Multiplier", 2f, new ConfigDescription("Multiplier for reverse rowing force (Back speed). 1 = vanilla.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), new object[1] { val }));
		}

		internal static string GetTailwindModeDisplay(TailwindMode mode)
		{
			return mode switch
			{
				TailwindMode.DeadAstern => "Smooth Sailing: DEAD ASTERN", 
				TailwindMode.PositiveOffset => $"Smooth Sailing: OFFSET +{OffsetAngle.Value:0.#}°", 
				TailwindMode.NegativeOffset => $"Smooth Sailing: OFFSET -{OffsetAngle.Value:0.#}°", 
				_ => "Smooth Sailing: OFF", 
			};
		}

		internal static bool IsTailwindEnabled()
		{
			if (Enabled.Value)
			{
				return TailwindModeSetting.Value != TailwindMode.Off;
			}
			return false;
		}

		internal static float GetTailwindAngle()
		{
			return TailwindModeSetting.Value switch
			{
				TailwindMode.PositiveOffset => OffsetAngle.Value, 
				TailwindMode.NegativeOffset => 0f - OffsetAngle.Value, 
				_ => 0f, 
			};
		}

		internal static Vector3 GetDesiredWindDirection(Ship ship)
		{
			//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_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ship == (Object)null)
			{
				return Vector3.zero;
			}
			return Quaternion.AngleAxis(GetTailwindAngle(), ((Component)ship).transform.up) * ((Component)ship).transform.forward;
		}

		internal static float GetEffectiveWindIntensity(float worldIntensity)
		{
			if (!IsTailwindEnabled())
			{
				return worldIntensity;
			}
			return WindIntensityModeSetting.Value switch
			{
				WindIntensityMode.Minimum => Mathf.Max(worldIntensity, MinimumWindIntensity.Value), 
				WindIntensityMode.Maximum => 1f, 
				_ => worldIntensity, 
			};
		}

		internal static MagicaWindZone GetOrCreateShipWindZone(Ship ship)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ship == (Object)null)
			{
				return null;
			}
			if (ShipWindZones.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			MagicaCloth componentInChildren = ((Component)ship).GetComponentInChildren<MagicaCloth>(true);
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return null;
			}
			GameObject val = new GameObject("SmoothSailing_SailWindZone");
			val.transform.SetParent(((Component)componentInChildren).transform, false);
			val.transform.localPosition = Vector3.zero;
			val.transform.localRotation = Quaternion.identity;
			val.transform.localScale = Vector3.one;
			MagicaWindZone val2 = val.AddComponent<MagicaWindZone>();
			val2.mode = (Mode)2;
			val2.size = new Vector3(12f, 12f, 4f);
			val2.main = 0f;
			val2.turbulence = 1f;
			val2.isAddition = false;
			ShipWindZones[ship] = val2;
			return val2;
		}

		internal static void UpdateShipWindZone(Ship ship)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)ship == (Object)null)
			{
				return;
			}
			ShipWindZones.TryGetValue(ship, out var value);
			if (!IsSailingShip(ship))
			{
				if ((Object)(object)value != (Object)null)
				{
					((Behaviour)value).enabled = false;
				}
				return;
			}
			value = GetOrCreateShipWindZone(ship);
			if (!((Object)(object)value == (Object)null))
			{
				if (!((Behaviour)value).enabled)
				{
					((Behaviour)value).enabled = true;
				}
				value.SetWindDirection(GetDesiredWindDirection(ship), false);
				float effectiveWindIntensity = GetEffectiveWindIntensity(((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetWindIntensity() : 0f);
				value.main = Mathf.Pow(effectiveWindIntensity, 2f) * 100f;
			}
		}

		internal static void RemoveShipWindZone(Ship ship)
		{
			if (!((Object)(object)ship == (Object)null) && ShipWindZones.TryGetValue(ship, out var value))
			{
				ShipWindZones.Remove(ship);
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)((Component)value).gameObject);
				}
			}
		}

		internal static bool TryCalculateSmoothSailForce(Ship ship, float sailSize, float dt, out Vector3 result)
		{
			//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_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012a: Unknown result type (might be due to invalid IL or missing references)
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_0154: Unknown result type (might be due to invalid IL or missing references)
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_015b: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			result = Vector3.zero;
			if (!IsTailwindEnabled() || (Object)(object)ship == (Object)null || SailForceFactorField == null || SailForceField == null || WindChangeVelocityField == null)
			{
				return false;
			}
			if (!IsLocallyControlledSailingShip(ship) && !IsLocallyOwnedSailingShip(ship))
			{
				return false;
			}
			Vector3 desiredWindDirection = GetDesiredWindDirection(ship);
			Vector3 normalized = ((Vector3)(ref desiredWindDirection)).normalized;
			float effectiveWindIntensity = GetEffectiveWindIntensity(((Object)(object)EnvMan.instance != (Object)null) ? EnvMan.instance.GetWindIntensity() : 0f);
			float num = Mathf.Lerp(0.25f, 1f, effectiveWindIntensity);
			float num2 = Vector3.Dot(normalized, -((Component)ship).transform.forward);
			float num3 = Mathf.Lerp(0.7f, 1f, 1f - Utils.Abs(num2));
			float num4 = 1f - Utils.LerpStep(0.75f, 0.8f, num2);
			float num5 = num3 * num4 * num;
			float num6 = (float)SailForceFactorField.GetValue(ship);
			Vector3 val = (Vector3)SailForceField.GetValue(ship);
			Vector3 val2 = (Vector3)WindChangeVelocityField.GetValue(ship);
			Vector3 val3 = normalized + ((Component)ship).transform.forward;
			Vector3 val4 = ((((Vector3)(ref val3)).sqrMagnitude > 1E-06f) ? (((Vector3)(ref val3)).normalized * (num5 * num6 * sailSize)) : Vector3.zero);
			val = Vector3.SmoothDamp(val, val4, ref val2, 1f, 99f, dt);
			SailForceField.SetValue(ship, val);
			WindChangeVelocityField.SetValue(ship, val2);
			result = val;
			return true;
		}

		internal static bool IsLocallyControlledSailingShip(Ship ship)
		{
			//IL_0034: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			if (!IsTailwindEnabled() || (Object)(object)ship == (Object)null || (Object)(object)Player.m_localPlayer == (Object)null)
			{
				return false;
			}
			if ((Object)(object)Player.m_localPlayer.GetControlledShip() != (Object)(object)ship)
			{
				return false;
			}
			Speed speedSetting = ship.GetSpeedSetting();
			if ((int)speedSetting != 3)
			{
				return (int)speedSetting == 4;
			}
			return true;
		}

		internal static bool IsSailingShip(Ship ship)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			if (!IsTailwindEnabled() || (Object)(object)ship == (Object)null)
			{
				return false;
			}
			Speed speedSetting = ship.GetSpeedSetting();
			if ((int)speedSetting != 3)
			{
				return (int)speedSetting == 4;
			}
			return true;
		}

		internal static bool IsLocallyOwnedSailingShip(Ship ship)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Invalid comparison between Unknown and I4
			if (!IsTailwindEnabled() || (Object)(object)ship == (Object)null)
			{
				return false;
			}
			ZNetView component = ((Component)ship).GetComponent<ZNetView>();
			if ((Object)(object)component == (Object)null || !component.IsOwner())
			{
				return false;
			}
			Speed speedSetting = ship.GetSpeedSetting();
			if ((int)speedSetting != 3)
			{
				return (int)speedSetting == 4;
			}
			return true;
		}

		internal static bool IsLocalPlayerAboardAnyShip()
		{
			if (Enabled.Value && (Object)(object)Player.m_localPlayer != (Object)null)
			{
				return ((Character)Player.m_localPlayer).IsAttachedToShip();
			}
			return false;
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	internal static class PlayerUpdateHotkeyPatch
	{
		private static bool _toggleWasDown;

		private static void Postfix(Player __instance)
		{
			//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)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Expected O, but got Unknown
			if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer)
			{
				return;
			}
			KeyboardShortcut value = Plugin.AdminToggleKey.Value;
			if (!Input.GetKey(((KeyboardShortcut)(ref value)).MainKey))
			{
				_toggleWasDown = false;
			}
			else
			{
				if (_toggleWasDown)
				{
					return;
				}
				_toggleWasDown = true;
				if ((Object)(object)ZNet.instance == (Object)null || !SynchronizationManager.Instance.PlayerIsAdmin)
				{
					((Character)__instance).Message((MessageType)1, "Smooth Sailing: Admin only", 0, (Sprite)null, false);
					return;
				}
				Plugin.TailwindMode tailwindMode = Plugin.TailwindModeSetting.Value switch
				{
					Plugin.TailwindMode.Off => Plugin.TailwindMode.DeadAstern, 
					Plugin.TailwindMode.DeadAstern => Plugin.TailwindMode.PositiveOffset, 
					Plugin.TailwindMode.PositiveOffset => Plugin.TailwindMode.NegativeOffset, 
					_ => Plugin.TailwindMode.Off, 
				};
				if (ZNet.instance.IsServer())
				{
					Plugin.TailwindModeSetting.Value = tailwindMode;
					((Character)__instance).Message((MessageType)1, Plugin.GetTailwindModeDisplay(tailwindMode), 0, (Sprite)null, false);
					ManualLogSource modLog = Plugin.ModLog;
					if (modLog != null)
					{
						modLog.LogInfo((object)$"Tailwind mode changed locally to {tailwindMode}.");
					}
					return;
				}
				ZNetPeer serverPeer = ZNet.instance.GetServerPeer();
				if (serverPeer == null)
				{
					ManualLogSource modLog2 = Plugin.ModLog;
					if (modLog2 != null)
					{
						modLog2.LogWarning((object)"Could not send tailwind mode change: server peer not found.");
					}
				}
				else
				{
					ZPackage val = new ZPackage();
					val.Write((int)tailwindMode);
					Plugin.TailwindModeRPC.SendPackage(serverPeer.m_uid, val);
				}
			}
		}
	}
	internal static class MinimapRealWindScope
	{
		internal static bool UpdatingWindMarker;
	}
	[HarmonyPatch(typeof(Minimap), "UpdateWindMarker")]
	internal static class MinimapUpdateWindMarkerScopePatch
	{
		private static void Prefix()
		{
			MinimapRealWindScope.UpdatingWindMarker = true;
		}

		private static void Postfix()
		{
			MinimapRealWindScope.UpdatingWindMarker = false;
		}

		private static Exception Finalizer(Exception __exception)
		{
			MinimapRealWindScope.UpdatingWindMarker = false;
			return __exception;
		}
	}
	internal static class ShipHudWindScope
	{
		internal static bool UpdatingShipHud;
	}
	[HarmonyPatch(typeof(Hud), "UpdateShipHud")]
	internal static class HudUpdateShipHudPatch
	{
		private static void Prefix()
		{
			ShipHudWindScope.UpdatingShipHud = true;
		}

		private static void Postfix()
		{
			ShipHudWindScope.UpdatingShipHud = false;
		}

		private static Exception Finalizer(Exception __exception)
		{
			ShipHudWindScope.UpdatingShipHud = false;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Ship), "GetWindAngleFactor")]
	internal static class ShipGetWindAngleFactorPatch
	{
		private static void Postfix(Ship __instance, ref float __result)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			if (Plugin.IsTailwindEnabled() && !((Object)(object)__instance == (Object)null) && (Plugin.IsLocallyControlledSailingShip(__instance) || Plugin.IsLocallyOwnedSailingShip(__instance)))
			{
				float num = Vector3.Dot(Plugin.GetDesiredWindDirection(__instance), -((Component)__instance).transform.forward);
				float num2 = Mathf.Lerp(0.7f, 1f, 1f - Utils.Abs(num));
				float num3 = 1f - Utils.LerpStep(0.75f, 0.8f, num);
				__result = num2 * num3;
			}
		}
	}
	[HarmonyPatch(typeof(Ship), "GetWindAngle")]
	internal static class ShipGetWindAnglePatch
	{
		private static void Postfix(Ship __instance, ref float __result)
		{
			if (ShipHudWindScope.UpdatingShipHud && Plugin.IsTailwindEnabled() && (Plugin.IsLocallyControlledSailingShip(__instance) || Plugin.IsLocallyOwnedSailingShip(__instance)))
			{
				float tailwindAngle = Plugin.GetTailwindAngle();
				__result = Mathf.Repeat(360f - tailwindAngle, 360f);
			}
		}
	}
	internal static class ShipSailForceScope
	{
		internal static bool CalculatingSailForce;

		internal static Ship CurrentShip;
	}
	[HarmonyPatch(typeof(Ship), "GetSailForce")]
	internal static class ShipGetSailForceScopePatch
	{
		private static bool Prefix(Ship __instance, float sailSize, float dt, ref Vector3 __result)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			ShipSailForceScope.CalculatingSailForce = true;
			ShipSailForceScope.CurrentShip = __instance;
			if (Plugin.TryCalculateSmoothSailForce(__instance, sailSize, dt, out var result))
			{
				__result = result;
				ShipSailForceScope.CalculatingSailForce = false;
				ShipSailForceScope.CurrentShip = null;
				return false;
			}
			return true;
		}

		private static void Postfix()
		{
			ShipSailForceScope.CalculatingSailForce = false;
			ShipSailForceScope.CurrentShip = null;
		}

		private static Exception Finalizer(Exception __exception)
		{
			ShipSailForceScope.CalculatingSailForce = false;
			ShipSailForceScope.CurrentShip = null;
			return __exception;
		}
	}
	[HarmonyPatch(typeof(Ship), "CustomFixedUpdate", new Type[] { typeof(float) })]
	internal static class ShipCustomFixedUpdatePatch
	{
		internal sealed class State
		{
			public float BackwardForce;

			public bool Modified;
		}

		private static readonly FieldInfo BackwardForceField = AccessTools.Field(typeof(Ship), "m_backwardForce");

		private static void Prefix(Ship __instance, out State __state)
		{
			//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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Invalid comparison between Unknown and I4
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Invalid comparison between Unknown and I4
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Invalid comparison between Unknown and I4
			__state = new State();
			if (!Plugin.Enabled.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			ZNetView component = ((Component)__instance).GetComponent<ZNetView>();
			if (!((Object)(object)component == (Object)null) && component.IsOwner())
			{
				Speed speedSetting = __instance.GetSpeedSetting();
				if (((int)speedSetting == 2 || (int)speedSetting == 1) && !(BackwardForceField == null))
				{
					__state.BackwardForce = (float)BackwardForceField.GetValue(__instance);
					__state.Modified = true;
					float num = (((int)speedSetting == 2) ? Plugin.ForwardRowMultiplier.Value : Plugin.ReverseRowMultiplier.Value);
					BackwardForceField.SetValue(__instance, __state.BackwardForce * num);
				}
			}
		}

		private static void Postfix(Ship __instance, State __state)
		{
			if (__state != null && __state.Modified && !((Object)(object)__instance == (Object)null))
			{
				BackwardForceField?.SetValue(__instance, __state.BackwardForce);
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "Explore", new Type[]
	{
		typeof(Vector3),
		typeof(float)
	})]
	internal static class MinimapExplorePatch
	{
		private static void Prefix(ref float radius)
		{
			if (Plugin.Enabled.Value && Plugin.IsLocalPlayerAboardAnyShip())
			{
				radius *= Plugin.ShipExploreRadiusMultiplier.Value;
			}
		}
	}
	[HarmonyPatch(typeof(Ship), "UpdateSail")]
	internal static class ShipUpdateSailPatch
	{
		private static void Postfix(Ship __instance, float dt)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: 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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
			Plugin.UpdateShipWindZone(__instance);
			if (Plugin.IsTailwindEnabled() && Plugin.IsSailingShip(__instance) && !((Object)(object)__instance.m_mastObject == (Object)null))
			{
				Vector3 desiredWindDirection = Plugin.GetDesiredWindDirection(__instance);
				desiredWindDirection = Vector3.Cross(Vector3.Cross(desiredWindDirection, ((Component)__instance).transform.up), ((Component)__instance).transform.up);
				float num = 0.5f + Vector3.Dot(((Component)__instance).transform.forward, desiredWindDirection) * 0.5f;
				Quaternion val = Quaternion.LookRotation(-Vector3.Lerp(desiredWindDirection, Vector3.Normalize(desiredWindDirection - ((Component)__instance).transform.forward), num), ((Component)__instance).transform.up);
				__instance.m_mastObject.transform.rotation = Quaternion.RotateTowards(__instance.m_mastObject.transform.rotation, val, 30f * dt);
			}
		}
	}
	[HarmonyPatch(typeof(Ship), "OnDisable")]
	internal static class ShipOnDisablePatch
	{
		private static void Prefix(Ship __instance)
		{
			Plugin.RemoveShipWindZone(__instance);
		}
	}
	[HarmonyPatch(typeof(EnvMan), "GetWindDir")]
	internal static class EnvManGetWindDirPatch
	{
		private static void Postfix(ref Vector3 __result)
		{
			//IL_0021: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			if (ShipSailForceScope.CalculatingSailForce && Plugin.IsTailwindEnabled() && (Object)(object)ShipSailForceScope.CurrentShip != (Object)null)
			{
				__result = Plugin.GetDesiredWindDirection(ShipSailForceScope.CurrentShip);
			}
			else if (!MinimapRealWindScope.UpdatingWindMarker && Plugin.IsTailwindEnabled())
			{
				Player localPlayer = Player.m_localPlayer;
				Ship ship = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
				if (Plugin.IsLocallyControlledSailingShip(ship))
				{
					__result = Plugin.GetDesiredWindDirection(ship);
				}
			}
		}
	}
}