Decompiled source of Autosail v0.2.0

Autosail.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;

[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace NewtAutosail;

[BepInPlugin("tonto.autosail", "Autosail", "0.2.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	public const string Guid = "tonto.autosail";

	internal static ConfigEntry<KeyboardShortcut> ToggleKey;

	internal static ConfigEntry<bool> RequireFavor;

	internal static ConfigEntry<bool> InvertRudder;

	internal static ConfigEntry<bool> DebugLog;

	internal static ConfigEntry<bool> CloseMap;

	internal static ConfigEntry<bool> ShowStatus;

	internal static ConfigEntry<float> CellSize;

	internal static ConfigEntry<float> MinDepth;

	internal static ConfigEntry<float> ShoreMargin;

	internal static ConfigEntry<float> ArrivalRadius;

	internal static ConfigEntry<float> PinSnapRadius;

	internal static ConfigEntry<float> SteerRange;

	internal static ConfigEntry<float> Damping;

	internal static ConfigEntry<float> AvoidDistance;

	internal static ConfigEntry<float> ShoreCost;

	internal static Plugin Instance;

	internal static ManualLogSource Log;

	private GUIStyle statusStyle;

	private void Awake()
	{
		//IL_0028: 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_00b4: Expected O, but got Unknown
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Expected O, but got Unknown
		//IL_0144: Unknown result type (might be due to invalid IL or missing references)
		//IL_014e: Expected O, but got Unknown
		//IL_0181: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Expected O, but got Unknown
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c8: Expected O, but got Unknown
		//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
		//IL_0205: Expected O, but got Unknown
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_0242: Expected O, but got Unknown
		//IL_0275: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Expected O, but got Unknown
		//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02bc: Expected O, but got Unknown
		//IL_0306: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Log = ((BaseUnityPlugin)this).Logger;
		ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "AutopilotKey", new KeyboardShortcut((KeyCode)104, Array.Empty<KeyCode>()), "Map open: hover a pin or any spot and press to sail there (press again with the map open to change destination). Map closed: press to switch autopilot off. You must be at the helm.");
		CloseMap = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "CloseMapAfterStart", true, "Close the map after choosing a destination so you can watch the ship.");
		ShowStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "ShowStatus", true, "Show distance to go and estimated arrival time on screen while the autopilot is on.");
		ShoreCost = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "ShoreCost", 2.5f, new ConfigDescription("How strongly routes avoid coastlines. 0 hugs the shore, higher keeps to open water. Raise it for jagged coasts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>()));
		RequireFavor = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "RequireNjordsFavor", true, "Only start while wearing Njord's Belt or Charm (steady tailwind in the direction the ship faces). Without it the wind decides the speed and the autopilot cannot tack.");
		CellSize = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "CellSize", 64f, new ConfigDescription("Route grid cell size in metres. Smaller finds narrower channels but plans slower.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(32f, 192f), Array.Empty<object>()));
		MinDepth = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "MinDepth", 3f, new ConfigDescription("Metres of water required under the route.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 12f), Array.Empty<object>()));
		ShoreMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "ShoreMargin", 25f, new ConfigDescription("Sideways clearance (m) kept when shortening the route.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>()));
		ArrivalRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "ArrivalRadius", 45f, new ConfigDescription("Stop when this close (m) to the end of the route.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 200f), Array.Empty<object>()));
		PinSnapRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "PinSnapRadius", 300f, new ConfigDescription("A pin this close (m) to the map cursor is used instead of the cursor spot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1500f), Array.Empty<object>()));
		SteerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Steering", "SteerRange", 35f, new ConfigDescription("Heading error (degrees) that asks for full rudder.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 90f), Array.Empty<object>()));
		Damping = ((BaseUnityPlugin)this).Config.Bind<float>("Steering", "Damping", 0.02f, new ConfigDescription("Counter-steer per degree/second of turn rate. Raise it if the ship swings past its heading.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.1f), Array.Empty<object>()));
		AvoidDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Steering", "AvoidDistance", 80f, new ConfigDescription("How far ahead (m) it looks for rocks, ships and shores.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 200f), Array.Empty<object>()));
		InvertRudder = ((BaseUnityPlugin)this).Config.Bind<bool>("Steering", "InvertRudder", false, "Test option: flip the rudder direction if the ship turns away from its target.");
		DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Log", false, "Log route and steering details to LogOutput.log.");
		try
		{
			new Harmony("tonto.autosail").PatchAll(typeof(ShipPatch));
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded. Steering hook installed. Autopilot key: " + ToggleKey.Value));
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)("Steering hook failed, autopilot cannot steer: " + ex.Message));
		}
	}

	private void OnGUI()
	{
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Expected O, but got Unknown
		//IL_0056: Unknown result type (might be due to invalid IL or missing references)
		//IL_005b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: 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_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: 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_0124: 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_003d: Expected O, but got Unknown
		if (!ShowStatus.Value)
		{
			return;
		}
		string text = Pilot.StatusText();
		if (text != null)
		{
			if (statusStyle == null)
			{
				statusStyle = new GUIStyle(GUI.skin.label);
				statusStyle.fontSize = 18;
			}
			Vector2 val = statusStyle.CalcSize(new GUIContent(text));
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor((float)Screen.width / 2f - val.x / 2f, 118f, val.x + 8f, val.y + 4f);
			Color color = GUI.color;
			GUI.color = new Color(0f, 0f, 0f, 0.9f);
			GUI.Label(new Rect(((Rect)(ref val2)).x + 1.5f, ((Rect)(ref val2)).y + 1.5f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), text, statusStyle);
			GUI.color = new Color(1f, 0.93f, 0.65f, 1f);
			GUI.Label(val2, text, statusStyle);
			GUI.color = color;
		}
	}

	private void Update()
	{
		try
		{
			Pilot.Tick();
		}
		catch (Exception ex)
		{
			Log.LogError((object)("Autosail error: " + ex));
			Pilot.Stop("Autosail error, see log");
		}
	}
}
[HarmonyPatch(typeof(Ship), "ApplyControlls")]
internal static class ShipPatch
{
	private static void Prefix(Ship __instance, ref Vector3 __0)
	{
		if (!Pilot.Active || (Object)(object)__instance != (Object)(object)Pilot.CurrentShip)
		{
			return;
		}
		try
		{
			Pilot.Steer(__instance, ref __0);
		}
		catch (Exception ex)
		{
			Plugin.Log.LogError((object)("Autosail steer error: " + ex));
			Pilot.Stop("Autosail error, see log");
		}
	}
}
internal static class Pilot
{
	private class PlanResult
	{
		public List<Vector3> Path;

		public string Error;

		public Vector3 End;
	}

	public class PlanConfig
	{
		public Func<float, float, float> Height;

		public float Water;

		public float MinDepth;

		public float Cell;

		public float Margin;

		public float ShoreCost;

		public Vector3 Start;

		public Vector3 Dest;
	}

	private static class Planner
	{
		private class Ctx
		{
			public PlanConfig C;

			public Dictionary<long, bool> Nav = new Dictionary<long, bool>();

			public Dictionary<long, float> Pen = new Dictionary<long, float>();
		}

		private class Heap
		{
			private readonly List<long> keys = new List<long>();

			private readonly List<float> pri = new List<float>();

			public int Count => keys.Count;

			public void Push(long k, float p)
			{
				keys.Add(k);
				pri.Add(p);
				int num = keys.Count - 1;
				while (num > 0)
				{
					int num2 = (num - 1) / 2;
					if (pri[num2] <= pri[num])
					{
						break;
					}
					Swap(num, num2);
					num = num2;
				}
			}

			public long Pop()
			{
				long result = keys[0];
				int index = keys.Count - 1;
				keys[0] = keys[index];
				pri[0] = pri[index];
				keys.RemoveAt(index);
				pri.RemoveAt(index);
				int num = 0;
				while (true)
				{
					int num2 = 2 * num + 1;
					int num3 = num2 + 1;
					int num4 = num;
					if (num2 < keys.Count && pri[num2] < pri[num4])
					{
						num4 = num2;
					}
					if (num3 < keys.Count && pri[num3] < pri[num4])
					{
						num4 = num3;
					}
					if (num4 == num)
					{
						break;
					}
					Swap(num, num4);
					num = num4;
				}
				return result;
			}

			private void Swap(int a, int b)
			{
				long value = keys[a];
				keys[a] = keys[b];
				keys[b] = value;
				float value2 = pri[a];
				pri[a] = pri[b];
				pri[b] = value2;
			}
		}

		private const float WorldLimit = 10400f;

		private const int MaxExpansions = 500000;

		private static long Key(int ix, int iz)
		{
			return ((long)(ix + 32768) << 16) | (iz + 32768);
		}

		private static int KX(long k)
		{
			return (int)(k >> 16) - 32768;
		}

		private static int KZ(long k)
		{
			return (int)(k & 0xFFFF) - 32768;
		}

		private static Vector3 Center(Ctx x, int ix, int iz)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			return new Vector3(((float)ix + 0.5f) * x.C.Cell, 0f, ((float)iz + 0.5f) * x.C.Cell);
		}

		private static int Idx(Ctx x, float v)
		{
			return (int)Mathf.Floor(v / x.C.Cell);
		}

		private static bool Deep(Ctx x, float wx, float wz)
		{
			if (wx * wx + wz * wz > 108160000f)
			{
				return false;
			}
			return x.C.Height(wx, wz) < x.C.Water - x.C.MinDepth;
		}

		private static bool Nav(Ctx x, int ix, int iz)
		{
			//IL_0020: 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)
			long key = Key(ix, iz);
			if (x.Nav.TryGetValue(key, out var value))
			{
				return value;
			}
			Vector3 val = Center(x, ix, iz);
			value = Deep(x, val.x, val.z);
			if (value)
			{
				float num = Mathf.Max(20f, x.C.Cell * 0.4f);
				value = Deep(x, val.x + num, val.z) && Deep(x, val.x - num, val.z) && Deep(x, val.x, val.z + num) && Deep(x, val.x, val.z - num);
			}
			x.Nav[key] = value;
			return value;
		}

		private static float Penalty(Ctx x, int ix, int iz)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			if (x.C.ShoreCost <= 0f)
			{
				return 0f;
			}
			long key = Key(ix, iz);
			if (x.Pen.TryGetValue(key, out var value))
			{
				return value;
			}
			Vector3 val = Center(x, ix, iz);
			float num = Mathf.Max(x.C.Cell * 1.5f, 100f);
			float num2 = num * 0.7071f;
			int num3 = 0;
			if (!Deep(x, val.x + num, val.z))
			{
				num3++;
			}
			if (!Deep(x, val.x - num, val.z))
			{
				num3++;
			}
			if (!Deep(x, val.x, val.z + num))
			{
				num3++;
			}
			if (!Deep(x, val.x, val.z - num))
			{
				num3++;
			}
			if (!Deep(x, val.x + num2, val.z + num2))
			{
				num3++;
			}
			if (!Deep(x, val.x - num2, val.z + num2))
			{
				num3++;
			}
			if (!Deep(x, val.x + num2, val.z - num2))
			{
				num3++;
			}
			if (!Deep(x, val.x - num2, val.z - num2))
			{
				num3++;
			}
			value = x.C.ShoreCost * (float)num3 / 8f;
			x.Pen[key] = value;
			return value;
		}

		private static bool LineClear(Ctx x, Vector3 a, Vector3 b)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: 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_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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: 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)
			Vector3 val = b - a;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude < 1f)
			{
				return true;
			}
			Vector3 val2 = val / magnitude;
			Vector3 val3 = default(Vector3);
			((Vector3)(ref val3))..ctor(val2.z, 0f, 0f - val2.x);
			float num = Mathf.Max(24f, x.C.Cell * 0.5f);
			for (float num2 = 0f; num2 <= magnitude; num2 += num)
			{
				Vector3 val4 = a + val2 * num2;
				if (!Deep(x, val4.x, val4.z))
				{
					return false;
				}
				if (x.C.Margin > 1f)
				{
					if (!Deep(x, val4.x + val3.x * x.C.Margin, val4.z + val3.z * x.C.Margin))
					{
						return false;
					}
					if (!Deep(x, val4.x - val3.x * x.C.Margin, val4.z - val3.z * x.C.Margin))
					{
						return false;
					}
				}
			}
			return Deep(x, b.x, b.z);
		}

		private static bool Nearest(Ctx x, Vector3 p, int maxRings, out int bx, out int bz)
		{
			//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			int num = Idx(x, p.x);
			int num2 = Idx(x, p.z);
			bx = num;
			bz = num2;
			float num3 = float.MaxValue;
			bool flag = false;
			for (int i = 0; i <= maxRings && (!flag || !((float)(i - 1) * x.C.Cell > num3)); i++)
			{
				for (int j = -i; j <= i; j++)
				{
					for (int k = -i; k <= i; k++)
					{
						if (Math.Max(Math.Abs(j), Math.Abs(k)) == i && Nav(x, num + j, num2 + k))
						{
							Vector3 val = Center(x, num + j, num2 + k);
							float num4 = (val.x - p.x) * (val.x - p.x) + (val.z - p.z) * (val.z - p.z);
							num4 = Mathf.Sqrt(num4);
							if (num4 < num3)
							{
								num3 = num4;
								bx = num + j;
								bz = num2 + k;
								flag = true;
							}
						}
					}
				}
			}
			return flag;
		}

		public static PlanResult Plan(PlanConfig cfg)
		{
			//IL_0011: 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_030f: 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_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0409: Unknown result type (might be due to invalid IL or missing references)
			//IL_04bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_04d7: 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)
			//IL_0470: Unknown result type (might be due to invalid IL or missing references)
			//IL_0452: Unknown result type (might be due to invalid IL or missing references)
			//IL_045b: Unknown result type (might be due to invalid IL or missing references)
			Ctx ctx = new Ctx();
			ctx.C = cfg;
			Ctx x = ctx;
			PlanResult planResult;
			if (!Nearest(x, cfg.Start, 10, out var bx, out var bz))
			{
				planResult = new PlanResult();
				planResult.Error = "No deep water near the ship.";
				return planResult;
			}
			if (!Nearest(x, cfg.Dest, 70, out var bx2, out var bz2))
			{
				bx2 = Idx(x, cfg.Dest.x);
				bz2 = Idx(x, cfg.Dest.z);
			}
			long num = Key(bx, bz);
			long num2 = Key(bx2, bz2);
			Dictionary<long, float> dictionary = new Dictionary<long, float>();
			Dictionary<long, long> dictionary2 = new Dictionary<long, long>();
			HashSet<long> hashSet = new HashSet<long>();
			Heap heap = new Heap();
			dictionary[num] = 0f;
			heap.Push(num, Heur(bx, bz, bx2, bz2, cfg.Cell));
			long num3 = num;
			float num4 = float.MaxValue;
			bool flag = false;
			int num5 = 0;
			float x2 = cfg.Dest.x;
			float z = cfg.Dest.z;
			while (heap.Count > 0 && num5 < 500000)
			{
				long num6 = heap.Pop();
				if (!hashSet.Add(num6))
				{
					continue;
				}
				num5++;
				int num7 = KX(num6);
				int num8 = KZ(num6);
				Vector3 val = Center(x, num7, num8);
				float num9 = (val.x - x2) * (val.x - x2) + (val.z - z) * (val.z - z);
				if (num9 < num4)
				{
					num4 = num9;
					num3 = num6;
				}
				if (num6 == num2)
				{
					flag = true;
					num3 = num6;
					break;
				}
				for (int i = -1; i <= 1; i++)
				{
					for (int j = -1; j <= 1; j++)
					{
						if (i == 0 && j == 0)
						{
							continue;
						}
						int num10 = num7 + i;
						int num11 = num8 + j;
						if (!Nav(x, num10, num11) || (i != 0 && j != 0 && (!Nav(x, num7 + i, num8) || !Nav(x, num7, num8 + j))))
						{
							continue;
						}
						long num12 = Key(num10, num11);
						if (!hashSet.Contains(num12))
						{
							float num13 = dictionary[num6] + ((i == 0 || j == 0) ? 1f : 1.4142f) * (1f + Penalty(x, num10, num11));
							if (!dictionary.TryGetValue(num12, out var value) || !(value <= num13))
							{
								dictionary[num12] = num13;
								dictionary2[num12] = num6;
								heap.Push(num12, num13 + Heur(num10, num11, bx2, bz2, 1f));
							}
						}
					}
				}
			}
			List<Vector3> list = new List<Vector3>();
			long value2 = num3;
			do
			{
				list.Add(Center(x, KX(value2), KZ(value2)));
			}
			while (value2 != num && dictionary2.TryGetValue(value2, out value2));
			list.Reverse();
			if (list.Count == 0)
			{
				planResult = new PlanResult();
				planResult.Error = "No water route found.";
				return planResult;
			}
			List<Vector3> list2 = new List<Vector3>();
			list2.Add(new Vector3(cfg.Start.x, 0f, cfg.Start.z));
			for (int k = 1; k < list.Count; k++)
			{
				list2.Add(list[k]);
			}
			if (flag && Deep(x, cfg.Dest.x, cfg.Dest.z))
			{
				list2.Add(new Vector3(cfg.Dest.x, 0f, cfg.Dest.z));
			}
			List<Vector3> list3 = new List<Vector3>();
			int num14 = 0;
			while (num14 < list2.Count - 1)
			{
				int num15 = Math.Min(list2.Count - 1, num14 + 24);
				while (num15 > num14 + 1 && !LineClear(x, list2[num14], list2[num15]))
				{
					num15--;
				}
				list3.Add(list2[num15]);
				num14 = num15;
			}
			if (list3.Count == 0)
			{
				list3.Add(list2[list2.Count - 1]);
			}
			Vector3 end = list3[list3.Count - 1];
			planResult = new PlanResult();
			planResult.Path = list3;
			planResult.End = end;
			return planResult;
		}

		private static float Heur(int ax, int az, int bx, int bz, float scale)
		{
			float val = Math.Abs(ax - bx);
			float val2 = Math.Abs(az - bz);
			return (Math.Max(val, val2) + 0.4142f * Math.Min(val, val2)) * scale / ((scale != 1f) ? 1f : 1f);
		}
	}

	public static bool Active;

	public static Ship CurrentShip;

	private static List<Vector3> path;

	private static int index;

	private static Vector3 destination;

	private static Vector3 endPoint;

	private static Vector3? lastDestination;

	private static volatile PlanResult planResult;

	private static bool planning;

	private static float startedAt;

	private static float lastSpeedStep;

	private static float lastAvoidProbe;

	private static float stuckCheckAt;

	private static float badHeadingSince = -1f;

	private static Vector3 stuckPos;

	private static float avoidAngle;

	private static bool pulse;

	private static bool planIsReplan;

	private static bool recovering;

	private static float recoverUntil;

	private static float recoverSide = 1f;

	private static float lastReplan;

	private static float shipSpeed;

	private static float remaining;

	private static float freeLeft;

	private static float freeRight;

	private static float chosenFree = 999f;

	private static int retries;

	private static Vector3 routeStart;

	private static Vector3 recoverPos;

	private static readonly string[] FavorPrefabs = new string[2] { "TailwindBelt", "TailwindCharm" };

	private static int ObstacleMask = -1;

	public static void Tick()
	{
		//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
		//IL_0290: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00df: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ee: 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_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_030a: Unknown result type (might be due to invalid IL or missing references)
		//IL_030f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0340: Unknown result type (might be due to invalid IL or missing references)
		//IL_032a: Unknown result type (might be due to invalid IL or missing references)
		//IL_032f: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer == (Object)null)
		{
			if (Active)
			{
				Stop(null);
			}
			return;
		}
		if (Active)
		{
			if ((Object)(object)localPlayer.GetControlledShip() != (Object)(object)CurrentShip)
			{
				Stop("Autopilot off: you left the helm.");
				return;
			}
			if (Plugin.RequireFavor.Value && !FavorActive(localPlayer))
			{
				Stop("Autopilot off: Njord's Favor is gone.");
				return;
			}
			PlanResult planResult = Pilot.planResult;
			if (planning && planResult != null)
			{
				planning = false;
				Pilot.planResult = null;
				if (planResult.Error != null)
				{
					Stop(planResult.Error);
					return;
				}
				path = planResult.Path;
				index = 0;
				endPoint = planResult.End;
				startedAt = Time.time;
				routeStart = ((Component)CurrentShip).transform.position;
				stuckPos = routeStart;
				stuckCheckAt = Time.time + 8f;
				float num = Vector2.Distance(new Vector2(endPoint.x, endPoint.z), new Vector2(destination.x, destination.z));
				if (!planIsReplan)
				{
					Say((!(num > Plugin.ArrivalRadius.Value + 30f)) ? "Route set." : ("Route set: nearest water is " + Mathf.RoundToInt(num) + " m from the spot."));
				}
				if (Plugin.DebugLog.Value)
				{
					Plugin.Log.LogInfo((object)("Route with " + path.Count + " waypoints."));
				}
			}
		}
		KeyboardShortcut value = Plugin.ToggleKey.Value;
		if (!((KeyboardShortcut)(ref value)).IsDown())
		{
			return;
		}
		bool flag = Minimap.IsOpen();
		Ship controlledShip = localPlayer.GetControlledShip();
		string text = BlockedReason();
		Plugin.Log.LogInfo((object)("Autosail key pressed: map open=" + flag + ", at helm=" + ((Object)(object)controlledShip != (Object)null) + ", favor=" + FavorActive(localPlayer) + ", blocked=" + (text ?? "no") + ", active=" + Active));
		if (text != null)
		{
			if (text == "pin name box")
			{
				Say(string.Concat("Finish or cancel the pin name box first, then press ", Plugin.ToggleKey.Value, " again."));
			}
			return;
		}
		if (Active && !flag)
		{
			Stop("Autopilot off.");
			return;
		}
		if ((Object)(object)controlledShip == (Object)null)
		{
			Say("Take the helm first.");
			return;
		}
		if (Plugin.RequireFavor.Value && !FavorActive(localPlayer))
		{
			Say("Put on Njord's Belt or Charm first.");
			return;
		}
		Vector3 dest;
		if (flag)
		{
			dest = MapTarget();
		}
		else
		{
			if (!lastDestination.HasValue)
			{
				Say(string.Concat("Open the map, hover where you want to go and press ", Plugin.ToggleKey.Value, "."));
				return;
			}
			dest = lastDestination.Value;
		}
		if (flag && Plugin.CloseMap.Value)
		{
			Minimap.instance.SetMapMode((MapMode)1);
		}
		Begin(controlledShip, dest, replan: false);
	}

	private static string BlockedReason()
	{
		if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
		{
			return "chat";
		}
		if (Console.IsVisible())
		{
			return "console";
		}
		if (TextInput.IsVisible())
		{
			return "text input";
		}
		if (Menu.IsVisible())
		{
			return "menu";
		}
		if (Minimap.InTextInput())
		{
			return "pin name box";
		}
		return null;
	}

	private static bool FavorActive(Player p)
	{
		foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems())
		{
			if (!allItem.m_equipped || (Object)(object)allItem.m_dropPrefab == (Object)null)
			{
				continue;
			}
			string name = ((Object)allItem.m_dropPrefab).name;
			for (int i = 0; i < FavorPrefabs.Length; i++)
			{
				if (name == FavorPrefabs[i])
				{
					return true;
				}
			}
		}
		return false;
	}

	private static Vector3 MapTarget()
	{
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//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_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ca: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
		Minimap instance = Minimap.instance;
		MethodInfo methodInfo = AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", (Type[])null, (Type[])null);
		Vector3 val = (Vector3)methodInfo.Invoke(instance, new object[1] { Input.mousePosition });
		Vector3 val2 = val;
		float num = Plugin.PinSnapRadius.Value;
		if (AccessTools.Field(typeof(Minimap), "m_pins").GetValue(instance) is IEnumerable enumerable)
		{
			foreach (object item in enumerable)
			{
				PinData val3 = (PinData)((item is PinData) ? item : null);
				if (val3 != null)
				{
					float num2 = Vector2.Distance(new Vector2(val3.m_pos.x, val3.m_pos.z), new Vector2(val.x, val.z));
					if (num2 < num)
					{
						num = num2;
						val2 = val3.m_pos;
					}
				}
			}
		}
		return new Vector3(val2.x, 0f, val2.z);
	}

	private static void Begin(Ship ship, Vector3 dest, bool replan)
	{
		//IL_000c: 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_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_013b: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		CurrentShip = ship;
		destination = dest;
		lastDestination = dest;
		Active = true;
		planning = true;
		planResult = null;
		path = null;
		index = 0;
		startedAt = Time.time;
		lastSpeedStep = 0f;
		lastAvoidProbe = 0f;
		badHeadingSince = -1f;
		planIsReplan = replan;
		recovering = false;
		if (!replan)
		{
			retries = 0;
			avoidAngle = 0f;
			lastReplan = Time.time;
		}
		WorldGenerator wg = WorldGenerator.instance;
		ZoneSystem instance = ZoneSystem.instance;
		if (wg == null || (Object)(object)instance == (Object)null)
		{
			Stop("World is not ready.");
			return;
		}
		PlanConfig cfg = new PlanConfig
		{
			Height = (float x, float z) => wg.GetHeight(x, z),
			Water = instance.m_waterLevel,
			MinDepth = Plugin.MinDepth.Value,
			Cell = Plugin.CellSize.Value,
			Margin = Plugin.ShoreMargin.Value,
			ShoreCost = Plugin.ShoreCost.Value,
			Start = ((Component)ship).transform.position,
			Dest = dest
		};
		Say((!replan) ? "Planning route..." : "Replanning route...");
		ThreadPool.QueueUserWorkItem(delegate
		{
			PlanResult planResult;
			try
			{
				planResult = Planner.Plan(cfg);
			}
			catch (Exception ex)
			{
				planResult = new PlanResult
				{
					Error = "Route planning failed: " + ex.Message
				};
			}
			Pilot.planResult = planResult;
		});
	}

	public static void Stop(string message)
	{
		//IL_0039: Unknown result type (might be due to invalid IL or missing references)
		bool active = Active;
		Ship currentShip = CurrentShip;
		Active = false;
		planning = false;
		planResult = null;
		path = null;
		CurrentShip = null;
		if ((Object)(object)currentShip != (Object)null && (int)currentShip.GetSpeedSetting() != 0)
		{
			try
			{
				currentShip.Stop();
			}
			catch
			{
			}
		}
		if (active && message != null)
		{
			Say(message);
		}
	}

	private static void Say(string text)
	{
		Player localPlayer = Player.m_localPlayer;
		Plugin.Log.LogInfo((object)("Autosail: " + text));
		if ((Object)(object)localPlayer != (Object)null)
		{
			((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false);
		}
	}

	public static void Steer(Ship ship, ref Vector3 moveDir)
	{
		//IL_0046: Unknown result type (might be due to invalid IL or missing references)
		//IL_004b: Unknown result type (might be due to invalid IL or missing references)
		//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_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_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0091: Unknown result type (might be due to invalid IL or missing references)
		//IL_0096: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_011a: 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_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0184: Unknown result type (might be due to invalid IL or missing references)
		//IL_0189: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a0: 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)
		//IL_015b: 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_0222: Unknown result type (might be due to invalid IL or missing references)
		//IL_022d: 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_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0262: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02c0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0300: Unknown result type (might be due to invalid IL or missing references)
		//IL_0302: Unknown result type (might be due to invalid IL or missing references)
		//IL_0303: Unknown result type (might be due to invalid IL or missing references)
		//IL_0308: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02f4: Unknown result type (might be due to invalid IL or missing references)
		//IL_0369: Unknown result type (might be due to invalid IL or missing references)
		//IL_036e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0373: Unknown result type (might be due to invalid IL or missing references)
		//IL_0375: Unknown result type (might be due to invalid IL or missing references)
		//IL_037a: Unknown result type (might be due to invalid IL or missing references)
		//IL_037c: Unknown result type (might be due to invalid IL or missing references)
		//IL_037d: Unknown result type (might be due to invalid IL or missing references)
		//IL_037f: Unknown result type (might be due to invalid IL or missing references)
		//IL_034d: Unknown result type (might be due to invalid IL or missing references)
		//IL_034e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0398: 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_041d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0445: Unknown result type (might be due to invalid IL or missing references)
		//IL_0454: Unknown result type (might be due to invalid IL or missing references)
		//IL_0463: Unknown result type (might be due to invalid IL or missing references)
		//IL_0474: Unknown result type (might be due to invalid IL or missing references)
		//IL_0477: Unknown result type (might be due to invalid IL or missing references)
		//IL_047c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0498: Unknown result type (might be due to invalid IL or missing references)
		//IL_048d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0490: Unknown result type (might be due to invalid IL or missing references)
		//IL_0495: Unknown result type (might be due to invalid IL or missing references)
		//IL_050d: Unknown result type (might be due to invalid IL or missing references)
		//IL_050e: Unknown result type (might be due to invalid IL or missing references)
		//IL_059e: Unknown result type (might be due to invalid IL or missing references)
		//IL_059f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0523: Unknown result type (might be due to invalid IL or missing references)
		//IL_0682: Unknown result type (might be due to invalid IL or missing references)
		if (Time.time - startedAt > 1f && (Mathf.Abs(moveDir.x) > 0.5f || moveDir.z < -0.5f))
		{
			Stop("Autopilot off: manual steering.");
			return;
		}
		moveDir = Vector3.zero;
		if (path == null)
		{
			return;
		}
		Vector3 position = ((Component)ship).transform.position;
		Vector3 val = Flat(((Component)ship).transform.forward);
		Rigidbody component = ((Component)ship).GetComponent<Rigidbody>();
		float num = shipSpeed;
		float num2;
		if ((Object)(object)component != (Object)null)
		{
			Vector3 velocity = component.velocity;
			num2 = ((Vector3)(ref velocity)).magnitude;
		}
		else
		{
			num2 = 0f;
		}
		shipSpeed = Mathf.Lerp(num, num2, 0.05f);
		if (recovering)
		{
			if (Time.time < recoverUntil)
			{
				AdjustSpeed(ship, (Speed)1, ref moveDir);
				moveDir.x = Mathf.Clamp((recoverSide - ship.GetRudderValue()) * 4f, -1f, 1f);
			}
			else
			{
				recovering = false;
				recoverPos = position;
				Begin(ship, destination, replan: true);
			}
			return;
		}
		if (Dist2D(position, recoverPos) > 250f)
		{
			retries = 0;
		}
		while (index < path.Count - 1 && Dist2D(position, path[index]) < 45f)
		{
			index++;
		}
		Vector3 val2 = path[index];
		bool flag = index == path.Count - 1;
		float num3 = Dist2D(position, path[path.Count - 1]);
		if (num3 < Plugin.ArrivalRadius.Value)
		{
			float num4 = Dist2D(endPoint, destination);
			Stop((!(num4 > Plugin.ArrivalRadius.Value + 30f)) ? "Arrived." : ("Arrived: " + Mathf.RoundToInt(num4) + " m short of the spot (land)."));
			return;
		}
		remaining = Dist2D(position, path[index]);
		for (int i = index; i < path.Count - 1; i++)
		{
			remaining += Dist2D(path[i], path[i + 1]);
		}
		Vector3 a = ((index <= 0) ? routeStart : path[index - 1]);
		if (DistToSegment(position, a, path[index]) > 250f && Time.time - lastReplan > 30f)
		{
			lastReplan = Time.time;
			Begin(ship, destination, replan: true);
			return;
		}
		Vector3 val3 = Flat(val2 - position);
		if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f)
		{
			return;
		}
		((Vector3)(ref val3)).Normalize();
		if (Time.time - lastAvoidProbe > 0.25f)
		{
			lastAvoidProbe = Time.time;
			avoidAngle = Mathf.Lerp(avoidAngle, PickAvoidAngle(ship, position, val3), 0.6f);
		}
		Vector3 val4 = Quaternion.AngleAxis(avoidAngle, Vector3.up) * val3;
		float num5 = Vector3.SignedAngle(val, val4, Vector3.up);
		float num6 = ((!((Object)(object)component != (Object)null)) ? 0f : (component.angularVelocity.y * 57.29578f));
		float num7 = Mathf.Clamp(num5 / Plugin.SteerRange.Value - Plugin.Damping.Value * num6, -1f, 1f);
		if (Plugin.InvertRudder.Value)
		{
			num7 = 0f - num7;
		}
		moveDir.x = Mathf.Clamp((num7 - ship.GetRudderValue()) * 4f, -1f, 1f);
		Speed val5 = (Speed)4;
		if (Mathf.Abs(num5) > 60f || Mathf.Abs(avoidAngle) > 30f)
		{
			val5 = (Speed)3;
		}
		if (num3 < 350f)
		{
			val5 = (Speed)3;
		}
		if (num3 < 150f)
		{
			val5 = (Speed)2;
		}
		if (chosenFree < 70f)
		{
			val5 = Slower(val5, (Speed)3);
		}
		if (chosenFree < 35f)
		{
			val5 = Slower(val5, (Speed)2);
		}
		AdjustSpeed(ship, val5, ref moveDir);
		if (Mathf.Abs(num5) > 120f)
		{
			if (badHeadingSince < 0f)
			{
				badHeadingSince = Time.time;
			}
			else if (Time.time - badHeadingSince > 25f)
			{
				Stop("Autopilot off: cannot turn toward the route. Try the InvertRudder setting.");
				return;
			}
		}
		else
		{
			badHeadingSince = -1f;
		}
		if (Time.time > stuckCheckAt)
		{
			if (Dist2D(position, stuckPos) < 6f && Rank(ship.GetSpeedSetting()) >= Rank((Speed)2))
			{
				retries++;
				if (retries > 3)
				{
					Stop("Autopilot off: the ship cannot get free.");
					return;
				}
				recovering = true;
				recoverUntil = Time.time + 4.5f;
				recoverSide = ((!(freeLeft > freeRight)) ? 1f : (-1f));
				Say("Stuck, backing off...");
				return;
			}
			stuckPos = position;
			stuckCheckAt = Time.time + 7f;
		}
		if (Plugin.DebugLog.Value && Time.frameCount % 120 == 0)
		{
			Plugin.Log.LogInfo((object)("wp " + index + "/" + path.Count + " toEnd " + Mathf.RoundToInt(num3) + " err " + Mathf.RoundToInt(num5) + " avoid " + Mathf.RoundToInt(avoidAngle) + " rudder " + ship.GetRudderValue().ToString("0.00") + " speed " + ship.GetSpeedSetting()));
		}
	}

	private static int Rank(Speed v)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Expected I4, but got Unknown
		return (int)v switch
		{
			1 => 0, 
			0 => 1, 
			2 => 2, 
			3 => 3, 
			_ => 4, 
		};
	}

	private static Speed Slower(Speed a, Speed b)
	{
		//IL_0000: 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_0017: 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)
		return (Rank(a) > Rank(b)) ? b : a;
	}

	private static void AdjustSpeed(Ship ship, Speed wanted, ref Vector3 moveDir)
	{
		//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_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: 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_0038: Unknown result type (might be due to invalid IL or missing references)
		Speed speedSetting = ship.GetSpeedSetting();
		if (speedSetting != wanted && !(Time.time - lastSpeedStep < 0.5f))
		{
			pulse = !pulse;
			float z = ((Rank(speedSetting) >= Rank(wanted)) ? (-1f) : 1f);
			if (pulse)
			{
				moveDir.z = z;
				return;
			}
			moveDir.z = 0f;
			lastSpeedStep = Time.time;
		}
	}

	private static float DistToSegment(Vector3 p, Vector3 a, Vector3 b)
	{
		//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_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_007e: 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)
		Vector2 val = default(Vector2);
		((Vector2)(ref val))..ctor(p.x - a.x, p.z - a.z);
		Vector2 val2 = default(Vector2);
		((Vector2)(ref val2))..ctor(b.x - a.x, b.z - a.z);
		float sqrMagnitude = ((Vector2)(ref val2)).sqrMagnitude;
		float num = ((!(sqrMagnitude < 1f)) ? Mathf.Clamp01(Vector2.Dot(val, val2) / sqrMagnitude) : 0f);
		Vector2 val3 = val - val2 * num;
		return ((Vector2)(ref val3)).magnitude;
	}

	public static string StatusText()
	{
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		if (!Active || (Object)(object)CurrentShip == (Object)null)
		{
			return null;
		}
		if (planning)
		{
			return (!planIsReplan) ? "Autosail: planning route..." : "Autosail: replanning route...";
		}
		if (recovering)
		{
			return "Autosail: backing off...";
		}
		if (path == null)
		{
			return null;
		}
		string text = ((!(shipSpeed > 0.8f)) ? "--" : FormatTime(remaining / shipSpeed));
		return string.Concat("Autosail  ", FormatDist(remaining), " to go  ETA ", text, "  (", Plugin.ToggleKey.Value, " to stop)");
	}

	private static string FormatDist(float m)
	{
		return (!(m >= 1000f)) ? (Mathf.RoundToInt(m) + " m") : ((m / 1000f).ToString("0.0") + " km");
	}

	private static string FormatTime(float sec)
	{
		int num = Mathf.Clamp(Mathf.RoundToInt(sec), 0, 359999);
		return (num < 3600) ? (num / 60 + ":" + (num % 60).ToString("00")) : (num / 3600 + ":" + (num / 60 % 60).ToString("00") + ":" + (num % 60).ToString("00"));
	}

	private static float PickAvoidAngle(Ship ship, Vector3 pos, Vector3 want)
	{
		//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d7: 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_00e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		if (ObstacleMask == -1)
		{
			ObstacleMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" });
		}
		float num = Mathf.Clamp(Mathf.Max(Plugin.AvoidDistance.Value, shipSpeed * 8f), 30f, 240f);
		float[] array = new float[11]
		{
			0f, 12f, -12f, 24f, -24f, 40f, -40f, 60f, -60f, 85f,
			-85f
		};
		float result = 0f;
		float num2 = -1f;
		freeLeft = 0f;
		freeRight = 0f;
		chosenFree = num;
		bool flag = false;
		float result2 = 0f;
		for (int i = 0; i < array.Length; i++)
		{
			Vector3 dir = Quaternion.AngleAxis(array[i], Vector3.up) * want;
			float num3 = FreeDistance(ship, pos + Vector3.up * 1.5f, dir, num);
			if (array[i] > 0f)
			{
				freeRight = Mathf.Max(freeRight, num3);
			}
			else if (array[i] < 0f)
			{
				freeLeft = Mathf.Max(freeLeft, num3);
			}
			if (!flag && num3 >= num)
			{
				flag = true;
				result2 = array[i];
				chosenFree = num3;
			}
			if (num3 > num2)
			{
				num2 = num3;
				result = array[i];
			}
		}
		if (flag)
		{
			return result2;
		}
		chosenFree = num2;
		return result;
	}

	private static float FreeDistance(Ship ship, Vector3 origin, Vector3 dir, float range)
	{
		//IL_0000: 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)
		RaycastHit[] array = Physics.SphereCastAll(origin, 3.5f, dir, range, ObstacleMask, (QueryTriggerInteraction)1);
		float num = range;
		for (int i = 0; i < array.Length; i++)
		{
			Collider collider = ((RaycastHit)(ref array[i])).collider;
			if (!((Object)(object)collider == (Object)null) && !((Object)(object)((Component)collider).GetComponentInParent<Ship>() == (Object)(object)ship) && ((RaycastHit)(ref array[i])).distance < num)
			{
				num = ((RaycastHit)(ref array[i])).distance;
			}
		}
		return num;
	}

	private static Vector3 Flat(Vector3 v)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		v.y = 0f;
		return v;
	}

	private static float Dist2D(Vector3 a, Vector3 b)
	{
		float num = a.x - b.x;
		float num2 = a.z - b.z;
		return Mathf.Sqrt(num * num + num2 * num2);
	}
}