Decompiled source of Hafvisir v1.0.0

Hafvisir.dll

Decompiled a day ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Hafvisir.Assets;
using Hafvisir.Nav;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("assembly_valheim")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyCompany("Hafvisir")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Hafvisir")]
[assembly: AssemblyTitle("Hafvisir")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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 Hafvisir
{
	internal static class Recolor
	{
		private static readonly Dictionary<Texture, Texture2D> Done = new Dictionary<Texture, Texture2D>();

		public static bool Possible => (int)SystemInfo.graphicsDeviceType != 4;

		public static Sprite Icon(Sprite source, Color tint)
		{
			//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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)source == (Object)null || !Possible)
			{
				return source;
			}
			Rect textureRect = source.textureRect;
			Texture2D val = Read((Texture)(object)source.texture, textureRect, (int)((Rect)(ref textureRect)).width, (int)((Rect)(ref textureRect)).height, mips: false);
			if ((Object)(object)val == (Object)null)
			{
				return source;
			}
			Shift(val, tint);
			return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), source.pixelsPerUnit);
		}

		public static void Model(GameObject root, Color tint)
		{
			//IL_0008: 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_0146: 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_0063: Expected O, but got Unknown
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_017c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_018c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0191: 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_00bc: 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)
			//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			if (!Possible)
			{
				return;
			}
			float hue = default(float);
			float saturation = default(float);
			float num = default(float);
			Color.RGBToHSV(tint, ref hue, ref saturation, ref num);
			Renderer[] componentsInChildren = root.GetComponentsInChildren<Renderer>(true);
			foreach (Renderer val in componentsInChildren)
			{
				if (val is ParticleSystemRenderer)
				{
					continue;
				}
				Material[] sharedMaterials = val.sharedMaterials;
				for (int j = 0; j < sharedMaterials.Length; j++)
				{
					if (!((Object)(object)sharedMaterials[j] == (Object)null))
					{
						Material val2 = new Material(sharedMaterials[j]);
						Texture val3 = (val2.HasProperty("_MainTex") ? val2.GetTexture("_MainTex") : null);
						if ((Object)(object)val3 != (Object)null)
						{
							val2.SetTexture("_MainTex", (Texture)(object)Whole(val3, tint));
						}
						if (val2.HasProperty("_Color"))
						{
							val2.SetColor("_Color", Rehue(val2.GetColor("_Color"), hue, saturation));
						}
						if (val2.HasProperty("_EmissionColor"))
						{
							val2.SetColor("_EmissionColor", Rehue(val2.GetColor("_EmissionColor"), hue, saturation));
						}
						sharedMaterials[j] = val2;
					}
				}
				val.sharedMaterials = sharedMaterials;
			}
			Light[] componentsInChildren2 = root.GetComponentsInChildren<Light>(true);
			foreach (Light obj in componentsInChildren2)
			{
				obj.color = Rehue(obj.color, hue, saturation);
			}
			ParticleSystem[] componentsInChildren3 = root.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				MainModule main = componentsInChildren3[i].main;
				MinMaxGradient startColor = ((MainModule)(ref main)).startColor;
				((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Rehue(((MinMaxGradient)(ref startColor)).color, hue, saturation));
			}
		}

		private static Texture2D Whole(Texture source, Color tint)
		{
			//IL_0055: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if (Done.TryGetValue(source, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			int width = Mathf.Min(source.width, 512);
			int height = Mathf.Min(source.height, 512);
			Texture2D val = Read(source, new Rect(0f, 0f, (float)source.width, (float)source.height), width, height, mips: true);
			if ((Object)(object)val == (Object)null)
			{
				return (Texture2D)(object)((source is Texture2D) ? source : null);
			}
			Shift(val, tint);
			((Texture)val).wrapMode = source.wrapMode;
			Done[source] = val;
			return val;
		}

		private static Texture2D Read(Texture source, Rect part, int width, int height, bool mips)
		{
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: 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_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Expected O, but got Unknown
			RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2);
			RenderTexture active = RenderTexture.active;
			try
			{
				Vector2 val = default(Vector2);
				((Vector2)(ref val))..ctor(((Rect)(ref part)).width / (float)source.width, ((Rect)(ref part)).height / (float)source.height);
				Vector2 val2 = default(Vector2);
				((Vector2)(ref val2))..ctor(((Rect)(ref part)).x / (float)source.width, ((Rect)(ref part)).y / (float)source.height);
				Graphics.Blit(source, temporary, val, val2);
				RenderTexture.active = temporary;
				Texture2D val3 = new Texture2D(width, height, (TextureFormat)4, mips);
				val3.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
				val3.Apply(mips);
				return val3;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Could not recolour " + ((Object)source).name + ": " + ex.Message));
				return null;
			}
			finally
			{
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
			}
		}

		private static void Shift(Texture2D texture, Color tint)
		{
			//IL_0000: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			float hue = default(float);
			float saturation = default(float);
			float num = default(float);
			Color.RGBToHSV(tint, ref hue, ref saturation, ref num);
			Color32[] pixels = texture.GetPixels32();
			for (int i = 0; i < pixels.Length; i++)
			{
				if (pixels[i].a != 0)
				{
					Color val = Rehue(Color32.op_Implicit(pixels[i]), hue, saturation);
					val.a = (float)(int)pixels[i].a / 255f;
					pixels[i] = Color32.op_Implicit(val);
				}
			}
			texture.SetPixels32(pixels);
			texture.Apply(((Texture)texture).mipmapCount > 1);
		}

		private static Color Rehue(Color colour, float hue, float saturation)
		{
			//IL_0000: 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_0028: 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_0036: Unknown result type (might be due to invalid IL or missing references)
			float num = default(float);
			float num2 = default(float);
			float num3 = default(float);
			Color.RGBToHSV(colour, ref num, ref num2, ref num3);
			Color result = Color.HSVToRGB(hue, Mathf.Clamp01(saturation * (0.55f + 0.45f * num2)), num3, true);
			result.a = colour.a;
			return result;
		}
	}
	internal enum PilotState
	{
		Idle,
		Plotted,
		Sailing,
		Paused
	}
	internal static class Autopilot
	{
		public static readonly int StateKey = StringExtensionMethods.GetStableHashCode("hafvisir_state");

		public static readonly int RemainingKey = StringExtensionMethods.GetStableHashCode("hafvisir_remaining");

		private const float ScanInterval = 0.25f;

		private const int ScanBudget = 320;

		private const float MastHeight = 12f;

		private const float StuckSeconds = 8f;

		private const float StuckGrace = 12f;

		private const float BackMinSeconds = 3f;

		private const float BackMaxSeconds = 16f;

		private static Ship _ship;

		private static float _burnLeft;

		private static float _extraThrust;

		private static float _scanTimer;

		private static float _claimTimer;

		private static float _stuckTimer;

		private static bool _backing;

		private static float _backTimer;

		private static float _backStill;

		private static float _backCooldown;

		private static float _replanAt;

		private static bool _replanQueued;

		private static float _zdoTimer;

		private static int _solidMask;

		private static byte[] _scanned;

		private static float _slowScanTimer;

		private static float _loadedAhead = 240f;

		private static float _noProgress;

		private static float _markError;

		private static Vector3 _markPos;

		private static bool _marked;

		private static bool _assist;

		private static int _assistCount;

		private static Vector3 _assistPos;

		private static float _assistTime;

		private const float AssistAfter = 8f;

		private const float AssistMax = 30f;

		private const float GiveUpSeconds = 50f;

		private const float RoomToAvoid = 24f;

		private static readonly RaycastHit[] Hits = (RaycastHit[])(object)new RaycastHit[12];

		private static float _trawled;

		private static float _baitNotice;

		private static readonly Random NetChance = new Random();

		private static Ship _settleShip;

		private static float _settleUntil;

		private const float SmallObstacle = 5f;

		private static readonly List<Collider> Ghosted = new List<Collider>();

		private static Collider[] _hullColliders;

		private static Ship _hullOwner;

		private static float _hullTimer;

		private static int _smallMask;

		public static PilotState State { get; private set; }

		public static Route Route { get; private set; }

		public static Vector3 Destination { get; private set; }

		public static string DestinationName { get; private set; }

		public static bool Planning { get; private set; }

		public static float Progress { get; private set; }

		public static string Problem { get; private set; }

		public static string Warning { get; private set; }

		public static Fuel Burning { get; private set; }

		public static bool Backing => _backing;

		public static float Remaining
		{
			get
			{
				if (Route == null)
				{
					return 0f;
				}
				return Mathf.Max(0f, Route.Length - Progress);
			}
		}

		public static void Reset()
		{
			State = PilotState.Idle;
			Route = null;
			Planning = false;
			Problem = null;
			Burning = null;
			Warning = null;
			_ship = null;
			_scanned = null;
			_burnLeft = 0f;
		}

		public static void SetDestination(Vector3 point, string name)
		{
			//IL_004f: 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_0054: 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)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !WorldNav.Ready)
			{
				return;
			}
			Ship ship = CurrentShip(localPlayer);
			Vector3 val = (((Object)(object)ship != (Object)null) ? ((Component)ship).transform.position : ((Component)localPlayer).transform.position);
			Destination = point;
			DestinationName = name;
			Planning = true;
			Problem = null;
			bool aboard = (Object)(object)ship != (Object)null;
			WorldNav.RequestRoute(val, point, HullClearance(ship), !aboard, delegate(Route route, RouteFailure failure)
			{
				Planning = false;
				Route = route;
				Progress = 0f;
				Warning = Tightness(route, ship);
				if (route == null)
				{
					Publish(PilotState.Idle);
					State = PilotState.Idle;
					Problem = Explain(failure, aboard);
					Notify(Problem);
				}
				else if (State == PilotState.Idle)
				{
					State = PilotState.Plotted;
				}
			});
		}

		private static string Explain(RouteFailure failure, bool aboard)
		{
			switch (failure)
			{
			case RouteFailure.NoWaterNearStart:
				return "No sailable water near you";
			case RouteFailure.NoWaterNearGoal:
				return "No sailable water near that spot";
			case RouteFailure.Blocked:
				return "No clear route: obstacles are in the way. Steer to open water and try again";
			case RouteFailure.NotConnected:
				if (!aboard)
				{
					return "No sea passage reaches that spot from here";
				}
				return "This water is landlocked: no passage from here to there";
			default:
				return "No sea route there";
			}
		}

		public static void ClearCourse()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			RestoreHull();
			if (State == PilotState.Sailing && (Object)(object)_ship != (Object)null && _ship.IsOwner())
			{
				_ship.m_speed = (Speed)0;
				SettleDown(_ship);
			}
			Publish(PilotState.Idle);
			State = PilotState.Idle;
			Route = null;
			Planning = false;
			Problem = null;
			Warning = null;
		}

		private static string Tightness(Route route, Ship ship)
		{
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			if (route == null || (Object)(object)ship == (Object)null || (Object)(object)ship.m_floatCollider == (Object)null || WorldNav.Grid == null)
			{
				return null;
			}
			float num = ship.m_floatCollider.size.x * 0.5f + 4f;
			float num2 = 0f;
			for (float num3 = 0f; num3 < route.Length; num3 += 8f)
			{
				route.PointAt(num3, out var x, out var z);
				if (WorldNav.Grid.ClearAt(x, z) <= num)
				{
					num2 += 8f;
				}
			}
			if (!(num2 >= 16f))
			{
				return null;
			}
			return "Tight passage: " + UIKit.Distance(num2) + " of this route leaves little room for this ship";
		}

		public static void Toggle()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer.GetControlledShip() == (Object)null)
			{
				if (State != PilotState.Idle && (Object)(object)CurrentShip(localPlayer) != (Object)null)
				{
					Notify("Hold the rudder to engage or pause Hafvisir");
				}
			}
			else if (State == PilotState.Sailing)
			{
				Pause("Hafvisir paused");
			}
			else
			{
				Engage();
			}
		}

		public static void Engage()
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			if (Route == null)
			{
				Notify(Planning ? "The route is still being calculated" : "No route set. Open the chart and click a destination.");
				return;
			}
			Ship controlledShip = localPlayer.GetControlledShip();
			if ((Object)(object)controlledShip == (Object)null)
			{
				Notify("Hold the rudder to engage Hafvisir");
				return;
			}
			if (Fuels.Next(Hold(controlledShip), out var _) == null && _burnLeft <= 0f)
			{
				Notify("No fuel in the ship's storage");
				return;
			}
			if ((Object)(object)controlledShip != (Object)(object)_ship)
			{
				Burning = null;
				_burnLeft = 0f;
			}
			_ship = controlledShip;
			_stuckTimer = -12f;
			_noProgress = 0f;
			_marked = false;
			_assist = false;
			_assistCount = 0;
			Bridges.Reset();
			_backing = false;
			_backCooldown = 0f;
			_scanTimer = 0f;
			_extraThrust = 0f;
			State = PilotState.Sailing;
			_settleShip = null;
			WorldNav.ForgetGuesses();
			controlledShip.m_nview.ClaimOwnership();
			Replan(0f);
			Notify((Warning != null) ? "Hafvisir engaged. Tight passage ahead: it will go slowly" : "Hafvisir engaged");
		}

		public static void Pause(string message)
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			if (State == PilotState.Sailing)
			{
				State = PilotState.Paused;
				_backing = false;
				RestoreHull();
				if ((Object)(object)_ship != (Object)null && _ship.IsOwner())
				{
					_ship.m_speed = (Speed)0;
					SettleDown(_ship);
				}
				Publish(PilotState.Paused);
				if (message != null)
				{
					Notify(message);
				}
			}
		}

		public static void ReleaseToPlayer()
		{
			_settleShip = null;
			WorldNav.ForgetGuesses();
		}

		public static void Validate()
		{
			if (State == PilotState.Sailing && (Object)(object)_ship == (Object)null)
			{
				State = PilotState.Paused;
			}
		}

		public static Ship CurrentShip(Player player)
		{
			Ship val = player.GetControlledShip();
			if ((Object)(object)val == (Object)null)
			{
				val = ((Character)player).GetStandingOnShip();
			}
			if ((Object)(object)val == (Object)null)
			{
				val = Ship.GetLocalShip();
			}
			Fuels.SetShip(val);
			return val;
		}

		public static Inventory Hold(Ship ship)
		{
			if ((Object)(object)ship == (Object)null)
			{
				return null;
			}
			Container componentInChildren = ((Component)ship).GetComponentInChildren<Container>();
			if (!((Object)(object)componentInChildren != (Object)null))
			{
				return null;
			}
			return componentInChildren.GetInventory();
		}

		public static Fuel PlanningFuel(Ship ship)
		{
			if (State == PilotState.Sailing && Burning != null && _burnLeft > 0f)
			{
				return Burning;
			}
			ItemData stack;
			return Fuels.Next(Hold(ship), out stack) ?? Fuels.All[0];
		}

		public static bool EngineActive(Ship ship)
		{
			if (State == PilotState.Sailing && (Object)(object)ship == (Object)(object)_ship && Burning != null && _burnLeft > 0f)
			{
				return !_backing;
			}
			return false;
		}

		public static bool Controls(Ship ship)
		{
			if (State == PilotState.Sailing)
			{
				return (Object)(object)ship == (Object)(object)_ship;
			}
			return false;
		}

		private static float HullClearance(Ship ship)
		{
			return Fleet.HullClearance(ship);
		}

		public static void Drive(Ship ship, float dt)
		{
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0203: Unknown result type (might be due to invalid IL or missing references)
			//IL_0211: Unknown result type (might be due to invalid IL or missing references)
			//IL_021d: Unknown result type (might be due to invalid IL or missing references)
			//IL_021e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0220: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_024c: Unknown result type (might be due to invalid IL or missing references)
			//IL_024d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0257: Unknown result type (might be due to invalid IL or missing references)
			//IL_0294: Unknown result type (might be due to invalid IL or missing references)
			//IL_0295: Unknown result type (might be due to invalid IL or missing references)
			//IL_0305: Unknown result type (might be due to invalid IL or missing references)
			//IL_0306: Unknown result type (might be due to invalid IL or missing references)
			//IL_031f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0325: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e7: Unknown result type (might be due to invalid IL or missing references)
			//IL_044e: Unknown result type (might be due to invalid IL or missing references)
			//IL_044f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0460: Unknown result type (might be due to invalid IL or missing references)
			//IL_0461: Unknown result type (might be due to invalid IL or missing references)
			//IL_0462: Unknown result type (might be due to invalid IL or missing references)
			//IL_0361: Unknown result type (might be due to invalid IL or missing references)
			//IL_0362: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_036c: 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_038e: Unknown result type (might be due to invalid IL or missing references)
			//IL_038f: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_051d: Unknown result type (might be due to invalid IL or missing references)
			//IL_051e: Unknown result type (might be due to invalid IL or missing references)
			//IL_053e: Unknown result type (might be due to invalid IL or missing references)
			//IL_053f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0540: Unknown result type (might be due to invalid IL or missing references)
			//IL_0896: Unknown result type (might be due to invalid IL or missing references)
			//IL_0899: Unknown result type (might be due to invalid IL or missing references)
			//IL_08c7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0652: Unknown result type (might be due to invalid IL or missing references)
			//IL_0653: Unknown result type (might be due to invalid IL or missing references)
			//IL_0656: Unknown result type (might be due to invalid IL or missing references)
			//IL_065b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0909: Unknown result type (might be due to invalid IL or missing references)
			//IL_090b: Unknown result type (might be due to invalid IL or missing references)
			//IL_06cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_06e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ed: Unknown result type (might be due to invalid IL or missing references)
			//IL_06fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0712: Unknown result type (might be due to invalid IL or missing references)
			//IL_0969: Unknown result type (might be due to invalid IL or missing references)
			//IL_096b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0947: Unknown result type (might be due to invalid IL or missing references)
			//IL_0949: Unknown result type (might be due to invalid IL or missing references)
			//IL_0990: Unknown result type (might be due to invalid IL or missing references)
			//IL_0992: Unknown result type (might be due to invalid IL or missing references)
			//IL_09b9: Unknown result type (might be due to invalid IL or missing references)
			//IL_09bc: Invalid comparison between Unknown and I4
			//IL_098d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0981: Unknown result type (might be due to invalid IL or missing references)
			//IL_0935: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a3d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a15: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a16: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a31: Unknown result type (might be due to invalid IL or missing references)
			//IL_0752: Unknown result type (might be due to invalid IL or missing references)
			//IL_076c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a61: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a64: Invalid comparison between Unknown and I4
			//IL_0a66: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a69: Invalid comparison between Unknown and I4
			//IL_0b05: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae0: Unknown result type (might be due to invalid IL or missing references)
			//IL_0af9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b9b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b9c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b9f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ba9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0baf: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bb6: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bbb: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null || !ship.IsPlayerInBoat(localPlayer))
			{
				Pause("Hafvisir paused: no one aboard");
			}
			else
			{
				if (!WorldNav.Ready || Route == null)
				{
					return;
				}
				if (!ship.IsOwner())
				{
					_claimTimer -= dt;
					if (_claimTimer <= 0f)
					{
						_claimTimer = 1f;
						ship.m_nview.ClaimOwnership();
					}
					return;
				}
				Vector3 position = ((Component)ship).transform.position;
				Vector3 forward = ((Component)ship).transform.forward;
				forward.y = 0f;
				((Vector3)(ref forward)).Normalize();
				float num = Vector3.Dot(ship.m_body.linearVelocity, forward);
				if (!BurnFuel(ship, dt))
				{
					return;
				}
				Progress = Route.Project(position.x, position.z, Progress, 120f + Mathf.Abs(num) * 4f, out var offCourse);
				float num2 = Route.Length - Progress;
				if (num2 <= Plugin.ArrivalRadius.Value)
				{
					Arrive(ship);
					return;
				}
				NavGrid grid = WorldNav.Grid;
				float num3 = HullClearance(ship);
				_scanTimer -= dt;
				if (_scanTimer <= 0f)
				{
					_scanTimer = 0.25f;
					Scan(ship, position, forward, Mathf.Clamp(Mathf.Abs(num) * 7f, 80f, 200f));
					_loadedAhead = LoadedAhead(240f);
					if (offCourse > 60f)
					{
						_replanQueued = true;
					}
				}
				if (_replanQueued && Time.time >= _replanAt)
				{
					Replan(1.5f);
				}
				float num4 = grid.ClearAt(position.x, position.z);
				float num5 = Mathf.Clamp(Mathf.Min(Mathf.Abs(num) * 3.5f, Mathf.Max(num4 * 0.7f, Mathf.Abs(num) * 2f)), 14f, 70f);
				Route.PointAt(Progress + num5, out var x, out var z);
				Vector3 val = default(Vector3);
				((Vector3)(ref val))..ctor(x - position.x, 0f, z - position.z);
				float num6 = Vector3.SignedAngle(forward, val, Vector3.up);
				float num7 = ship.m_body.angularVelocity.y * 57.29578f;
				bool flag = ship.HaveControllingPlayer();
				Vector3 val2 = position - _markPos;
				val2.y = 0f;
				if (!_marked || ((Vector3)(ref val2)).sqrMagnitude > 144f || Mathf.Abs(num6) < _markError - 20f)
				{
					_marked = true;
					_markPos = position;
					_markError = Mathf.Abs(num6);
					_noProgress = 0f;
				}
				else
				{
					_noProgress += dt;
				}
				if (Bridges.Ahead < 80f)
				{
					_noProgress = 0f;
					_stuckTimer = Mathf.Min(_stuckTimer, 0f);
				}
				bool flag2 = Mathf.Abs(num6) > 60f && Mathf.Abs(num) < 3f && Room(grid, position, forward, num3, 70f) < num3 + 28f && grid.ClearAt(position.x, position.z) < 45f;
				if (!_assist && !Planning && (_noProgress > 8f || flag2))
				{
					Vector3 val3 = position - _assistPos;
					val3.y = 0f;
					if (((Vector3)(ref val3)).sqrMagnitude > 225f)
					{
						_assistCount = 0;
						_assistPos = position;
					}
					if (++_assistCount > 3)
					{
						_assistCount = 0;
						Problem = "No room to manoeuvre here";
						Pause("Hafvisir paused: no room to manoeuvre here. Steer to wider water and engage again");
						return;
					}
					_assist = true;
					_assistTime = 0f;
					_backing = false;
					Notify("Hafvisir: working clear");
				}
				if (_assist)
				{
					if (CastOff(ship, position, offCourse, dt))
					{
						PublishTick(dt, num2);
						return;
					}
					_assist = false;
					_noProgress = 0f;
					_marked = false;
					_stuckTimer = -6f;
				}
				if (_noProgress > 50f)
				{
					_noProgress = 0f;
					Problem = "No room to manoeuvre here";
					Pause("Hafvisir paused: no room to manoeuvre here. Steer to wider water and engage again");
					_assist = false;
					return;
				}
				float num8 = Room(grid, position, forward, num3, 70f);
				float num9 = Room(grid, position, -forward, num3, 50f);
				float halfBeam = (((Object)(object)ship.m_floatCollider != (Object)null) ? (ship.m_floatCollider.size.x * 0.5f) : 2.5f);
				float num10 = (((Object)(object)ship.m_floatCollider != (Object)null) ? (ship.m_floatCollider.size.z * 0.5f) : (num3 - 3f));
				Bridges.Tick(ship, Route, Progress, halfBeam, num10, dt);
				if (Bridges.Barred)
				{
					Problem = "A closed drawbridge is in the way";
					Pause("Hafvisir paused: a closed drawbridge is in the way and cannot be raised from here");
					return;
				}
				bool flag3 = num10 > 10f;
				if (flag3 && num8 < 16f)
				{
					num8 = Mathf.Max(num8, Probe(position, forward, num10, halfBeam));
				}
				if (flag3 && num9 < 16f)
				{
					num9 = Mathf.Max(num9, Probe(position, -forward, num10, halfBeam));
				}
				_backCooldown -= dt;
				if (!_backing && flag && _backCooldown <= 0f && Mathf.Abs(num) < 3f && Mathf.Abs(num6) > 75f && num8 < num3 + 28f && num9 > (flag3 ? 10f : (num3 + 8f)))
				{
					StartBacking();
				}
				if (_backing)
				{
					_backTimer += dt;
					_backStill = ((Mathf.Abs(num) < 0.3f) ? (_backStill + dt) : 0f);
					bool flag4 = Mathf.Abs(num6) < 35f && _backTimer > 3f;
					bool flag5 = num9 < (flag3 ? 5f : (num3 + 2f)) && _backTimer > 3f;
					if (_backStill > 5f)
					{
						for (float num11 = num3 - 2f; num11 <= num3 + 8f; num11 += 5f)
						{
							WorldNav.MarkBlocked(position - forward * num11, persist: false);
						}
					}
					if (!(flag4 || flag5) && flag && !(_backTimer > 16f) && !(_backStill > 5f))
					{
						ship.m_speed = (Speed)1;
						float num12 = (flag3 ? 0.65f : 1f);
						SetRudder(ship, (num6 > 0f) ? (0f - num12) : num12, dt);
						if (flag3 && num < -1f)
						{
							ship.m_body.AddForce(forward * (Mathf.Min(-1f - num, 2f) * 2f * dt), (ForceMode)2);
						}
						PublishTick(dt, num2);
						return;
					}
					_backing = false;
					_backCooldown = 5f;
					_stuckTimer = -6f;
					if (flag3 && num < 0f)
					{
						Vector3 linearVelocity = ship.m_body.linearVelocity;
						ship.m_body.linearVelocity = new Vector3(linearVelocity.x * 0.3f, linearVelocity.y, linearVelocity.z * 0.3f);
					}
					Replan(0f);
				}
				float num13 = num4;
				float num14 = Mathf.Max(64f, Mathf.Abs(num) * 9f);
				for (float num15 = 16f; num15 <= num14; num15 += 16f)
				{
					Route.PointAt(Progress + num15, out var x2, out var z2);
					num13 = Mathf.Min(num13, grid.ClearAt(x2, z2));
				}
				float num16 = 6f + num13 * 0.22f;
				num16 = Mathf.Min(num16, Mathf.Max(1.5f, num2 * 0.11f));
				num16 = Mathf.Min(num16, Mathf.Max(5f, num8 * 0.3f));
				num16 = Mathf.Min(num16, 8f + _loadedAhead * 0.26f);
				if (Bridges.Ahead < float.MaxValue)
				{
					num16 = Mathf.Min(num16, Mathf.Max(0f, (Bridges.Ahead - num10 - 14f) * 0.3f));
				}
				if (Mathf.Abs(num6) > 25f)
				{
					num16 = Mathf.Min(num16, 9f);
				}
				Speed val4 = (Speed)(flag ? 2 : 3);
				Speed val5 = (Speed)4;
				if (Mathf.Abs(num6) > 30f || num13 < 36f || num2 < 90f || num > num16 * 1.15f)
				{
					val5 = (Speed)3;
				}
				bool flag6 = num4 >= 45f && num8 >= 55f;
				if ((Mathf.Abs(num6) > 70f && !flag6) || num2 < 40f || num > num16 * 1.6f)
				{
					val5 = val4;
				}
				if (num13 < num3 + 4f)
				{
					if (flag3 && Mathf.Abs(num6) < 25f && num8 >= 16f)
					{
						val5 = (Speed)3;
						num16 = Mathf.Min(num16, 3.5f);
					}
					else
					{
						val5 = val4;
					}
				}
				if (num8 < Mathf.Max(14f, num * 3f) - num3 * 0.5f)
				{
					val5 = val4;
				}
				if (num > num16 * 1.5f && num > 12f)
				{
					val5 = (Speed)0;
				}
				if (num16 < 0.8f)
				{
					val5 = (Speed)0;
				}
				ship.m_speed = val5;
				float num17 = Mathf.Clamp(num6 / 35f - num7 / 60f, -1f, 1f);
				if ((int)val5 == 2 && flag3)
				{
					float num18 = ((num8 < 8f) ? 1f : ((_noProgress > 10f) ? 0.4f : 0.75f));
					num17 = Mathf.Clamp(num17, 0f - num18, num18);
				}
				SetRudder(ship, num17, dt);
				if (num > num16 + 0.6f)
				{
					ship.m_body.AddForce(-forward * (Mathf.Min(num - num16, 4f) * 0.9f * dt), (ForceMode)2);
				}
				SoftHull(ship, position, num, num3, dt);
				float num19 = ((Burning != null) ? Burning.Power : 0f);
				float num20 = (((int)val5 == 4) ? 1f : (((int)val5 == 3) ? 0.5f : 0f));
				float num21 = ((num < num16) ? (Mathf.Max(0f, num19 - 1f) * num20) : 0f);
				_extraThrust = Mathf.MoveTowards(_extraThrust, num21, dt * 1.5f);
				if (_extraThrust > 0.001f && position.y < WorldNav.WaterLevel + 2f)
				{
					ship.m_body.AddForce(forward * (_extraThrust * ship.m_sailForceFactor * ship.m_body.mass), (ForceMode)1);
				}
				Trawl(ship, position, num, dt);
				if (Burning != null && num > 2f)
				{
					Fuels.Learn(Burning, num, dt * 0.01f);
				}
				if (Mathf.Abs(num) < 0.5f && Mathf.Abs(num7) < 2f)
				{
					_stuckTimer += dt;
				}
				else if (_stuckTimer > 0f)
				{
					_stuckTimer = 0f;
				}
				if (_stuckTimer > 8f)
				{
					_stuckTimer = 0f;
					for (float num22 = num3 - 2f; num22 <= num3 + 14f; num22 += 6f)
					{
						for (float num23 = -6f; num23 <= 6f; num23 += 6f)
						{
							WorldNav.MarkBlocked(position + forward * num22 + Vector3.Cross(Vector3.up, forward) * num23, persist: false);
						}
					}
					if (flag)
					{
						StartBacking();
						Notify("Hafvisir: reversing clear of an obstacle");
					}
					else
					{
						Replan(0f);
					}
				}
				PublishTick(dt, num2);
			}
		}

		private static float LoadedAhead(float max)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			float num2 = default(float);
			for (float num = 24f; num <= max && !(Progress + num > Route.Length); num += 24f)
			{
				Route.PointAt(Progress + num, out var x, out var z);
				if (!Heightmap.GetHeight(new Vector3(x, 0f, z), ref num2))
				{
					return num - 24f;
				}
			}
			return max;
		}

		private static void StartBacking()
		{
			_backing = true;
			_backTimer = 0f;
			_backStill = 0f;
			_extraThrust = 0f;
		}

		private static float Room(NavGrid grid, Vector3 pos, Vector3 dir, float hull, float max)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			float num = hull - 3f;
			for (float num2 = num; num2 <= num + max; num2 += 4f)
			{
				if (grid.ClearAt(pos.x + dir.x * num2, pos.z + dir.z * num2) == 0f)
				{
					return num2 - num;
				}
			}
			return max;
		}

		private static bool CastOff(Ship ship, Vector3 pos, float off, float dt)
		{
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_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)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: 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_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: 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_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bf: 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)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cb: Unknown result type (might be due to invalid IL or missing references)
			_assistTime += dt;
			Route.PointAt(Progress + 4f, out var x, out var z);
			Route.PointAt(Mathf.Min(Route.Length, Progress + 22f), out var x2, out var z2);
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor(x2 - x, 0f, z2 - z);
			if (((Vector3)(ref val)).sqrMagnitude < 0.01f)
			{
				return false;
			}
			((Vector3)(ref val)).Normalize();
			GhostHull.Hold(ship, 1.5f);
			Rigidbody body = ship.m_body;
			Vector3 val2 = default(Vector3);
			((Vector3)(ref val2))..ctor(x - pos.x, 0f, z - pos.z);
			float magnitude = ((Vector3)(ref val2)).magnitude;
			if (magnitude > 0.05f)
			{
				body.position += val2 / magnitude * Mathf.Min(magnitude, 2.5f * dt);
			}
			Quaternion val3 = body.rotation;
			Vector3 eulerAngles = ((Quaternion)(ref val3)).eulerAngles;
			val3 = Quaternion.LookRotation(val, Vector3.up);
			float y = ((Quaternion)(ref val3)).eulerAngles.y;
			float num = Mathf.MoveTowardsAngle(eulerAngles.y, y, 28f * dt);
			body.rotation = Quaternion.Euler(eulerAngles.x, num, eulerAngles.z);
			body.linearVelocity = new Vector3(0f, body.linearVelocity.y, 0f);
			Vector3 angularVelocity = body.angularVelocity;
			angularVelocity.y = 0f;
			body.angularVelocity = angularVelocity;
			ship.m_speed = (Speed)0;
			ship.m_rudderValue = 0f;
			ship.m_rudder = 0f;
			if (!(off < 3f) || !(Mathf.Abs(Mathf.DeltaAngle(num, y)) < 10f) || !(WorldNav.Grid.ClearAt(pos.x, pos.z) > 0f))
			{
				return _assistTime < 30f;
			}
			return false;
		}

		private static float Probe(Vector3 pos, Vector3 dir, float halfLength, float halfBeam)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: 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_006c: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: Unknown result type (might be due to invalid IL or missing references)
			if (_solidMask == 0)
			{
				_solidMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
			}
			float waterLevel = WorldNav.WaterLevel;
			Vector3 val = Vector3.Cross(Vector3.up, dir);
			for (float num = 2f; num <= 16f; num += 3.5f)
			{
				for (int i = -1; i <= 1; i++)
				{
					Vector3 origin = pos + dir * (halfLength + num) + val * ((float)i * halfBeam * 0.8f);
					origin.y = waterLevel + 12f;
					if (Obstructed(origin, waterLevel - 1.6f, tight: true))
					{
						return num - 2f;
					}
				}
			}
			return 16f;
		}

		private static void SetRudder(Ship ship, float target, float dt)
		{
			float num = Mathf.Max(0.5f, ship.m_rudderSpeed) * 1.5f * dt;
			ship.m_rudderValue = Mathf.MoveTowards(ship.m_rudderValue, target, num);
			ship.m_rudder = Mathf.Clamp(target - ship.m_rudderValue, -1f, 1f);
		}

		private static void Trawl(Ship ship, Vector3 pos, float speed, float dt)
		{
			//IL_007e: 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)
			if (speed <= 0f)
			{
				return;
			}
			_trawled += speed * dt;
			float num = Mathf.Max(50f, Plugin.MetresPerFish.Value);
			if (_trawled < num)
			{
				return;
			}
			_trawled -= num;
			Container componentInChildren = ((Component)ship).GetComponentInChildren<Container>();
			Inventory hold = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.GetInventory() : null);
			if (!Modules.Has(hold, "Fishing Nets") || componentInChildren.IsInUse() || WorldGenerator.instance == null)
			{
				return;
			}
			bool lacking;
			GameObject val = Modules.Catch(hold, WorldGenerator.instance.GetBiome(pos), NetChance, out lacking);
			if ((Object)(object)val == (Object)null)
			{
				if (lacking && Time.time > _baitNotice && (Object)(object)Player.m_localPlayer != (Object)null)
				{
					_baitNotice = Time.time + 180f;
					((Character)Player.m_localPlayer).Message((MessageType)1, "Nets: no bait aboard for these waters", 0, (Sprite)null, false);
				}
				return;
			}
			Player localPlayer = Player.m_localPlayer;
			ItemDrop component = val.GetComponent<ItemDrop>();
			if ((Object)(object)localPlayer != (Object)null && (Object)(object)component != (Object)null)
			{
				((Character)localPlayer).Message((MessageType)1, "Nets: " + Localization.instance.Localize(component.m_itemData.m_shared.m_name), 1, component.m_itemData.GetIcon(), false);
			}
		}

		private static bool BurnFuel(Ship ship, float dt)
		{
			//IL_0007: 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_000e: 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_0027: Expected I4, but got Unknown
			float num = 0f;
			Speed speed = ship.m_speed;
			switch (speed - 1)
			{
			case 3:
				num = 1f;
				break;
			case 2:
				num = 0.6f;
				break;
			case 1:
				num = 0.3f;
				break;
			case 0:
				num = 0.3f;
				break;
			}
			if (Burning != null)
			{
				_burnLeft -= dt * num / (Burning.Seconds * Modules.Stretch(Modules.Has(Hold(ship), "Fuel Regulator")));
			}
			if (_burnLeft > 0f)
			{
				return true;
			}
			Container componentInChildren = ((Component)ship).GetComponentInChildren<Container>();
			Inventory val = (((Object)(object)componentInChildren != (Object)null) ? componentInChildren.GetInventory() : null);
			ItemData stack;
			Fuel fuel = Fuels.Next(val, out stack);
			if (fuel == null)
			{
				_burnLeft = 0f;
				Burning = null;
				Pause("Hafvisir paused: out of fuel");
				return false;
			}
			if (componentInChildren.IsInUse())
			{
				return true;
			}
			Burning = fuel;
			_burnLeft = 1f;
			val.RemoveItem(stack, 1);
			return true;
		}

		private static void Arrive(Ship ship)
		{
			//IL_0006: 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)
			Bridges.Lower(((Component)ship).transform.position, 12f, all: true);
			ship.m_speed = (Speed)0;
			ship.m_rudderValue = 0f;
			RestoreHull();
			SettleDown(ship);
			string destinationName = DestinationName;
			Publish(PilotState.Idle);
			State = PilotState.Idle;
			Route = null;
			Notify(string.IsNullOrEmpty(destinationName) ? "Arrived at destination" : ("Arrived at " + destinationName));
		}

		private static void SettleDown(Ship ship)
		{
			_settleShip = ship;
			_settleUntil = Time.time + 8f;
		}

		public static void Settle(Ship ship, float dt)
		{
			//IL_002b: 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)
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: 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)
			if (!((Object)(object)ship != (Object)(object)_settleShip))
			{
				if (Time.time > _settleUntil || State == PilotState.Sailing || !ship.IsOwner() || (int)ship.m_speed != 0)
				{
					_settleShip = null;
					return;
				}
				Vector3 linearVelocity = ship.m_body.linearVelocity;
				float num = Mathf.Clamp01(1f - 1.2f * dt);
				ship.m_body.linearVelocity = new Vector3(linearVelocity.x * num, linearVelocity.y, linearVelocity.z * num);
			}
		}

		private static void SoftHull(Ship ship, Vector3 pos, float speed, float hull, float dt)
		{
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: 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)
			//IL_0172: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_017b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			_hullTimer -= dt;
			if (_hullTimer > 0f)
			{
				return;
			}
			_hullTimer = 0.3f;
			Collider[] componentsInChildren;
			if ((Object)(object)_hullOwner != (Object)(object)ship)
			{
				RestoreHull();
				_hullOwner = ship;
				List<Collider> list = new List<Collider>();
				componentsInChildren = ((Component)ship).GetComponentsInChildren<Collider>();
				foreach (Collider val in componentsInChildren)
				{
					if (!val.isTrigger)
					{
						list.Add(val);
					}
				}
				_hullColliders = list.ToArray();
			}
			if (_smallMask == 0)
			{
				_smallMask = LayerMask.GetMask(new string[3] { "static_solid", "Default", "Default_small" });
			}
			Bounds bounds;
			for (int num = Ghosted.Count - 1; num >= 0; num--)
			{
				Collider val2 = Ghosted[num];
				if ((Object)(object)val2 != (Object)null)
				{
					bounds = val2.bounds;
					Vector3 val3 = ((Bounds)(ref bounds)).center - pos;
					if (((Vector3)(ref val3)).sqrMagnitude < (hull + 18f) * (hull + 18f))
					{
						continue;
					}
				}
				Ignore(val2, ignore: false);
				Ghosted.RemoveAt(num);
			}
			bool flag = Mathf.Abs(speed) <= 5f;
			NavGrid grid = WorldNav.Grid;
			componentsInChildren = Physics.OverlapSphere(pos, hull + 8f, _smallMask, (QueryTriggerInteraction)1);
			foreach (Collider val4 in componentsInChildren)
			{
				if (!Ghosted.Contains(val4) && Small(val4))
				{
					bounds = val4.bounds;
					Vector3 center = ((Bounds)(ref bounds)).center;
					if (flag || !(grid.ClearAt(center.x, center.z) >= 24f))
					{
						Ignore(val4, ignore: true);
						Ghosted.Add(val4);
					}
				}
			}
		}

		private static bool Small(Collider c)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//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_0027: 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_0033: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)c.attachedRigidbody != (Object)null || c is TerrainCollider)
			{
				return false;
			}
			Bounds bounds = c.bounds;
			Vector3 size = ((Bounds)(ref bounds)).size;
			if (Mathf.Max(size.x, Mathf.Max(size.y, size.z)) > 5f)
			{
				return false;
			}
			if ((Object)(object)((Component)c).GetComponentInParent<Piece>() == (Object)null)
			{
				return (Object)(object)((Component)c).GetComponentInParent<Heightmap>() == (Object)null;
			}
			return false;
		}

		private static void Ignore(Collider obstacle, bool ignore)
		{
			if ((Object)(object)obstacle == (Object)null || _hullColliders == null)
			{
				return;
			}
			Collider[] hullColliders = _hullColliders;
			foreach (Collider val in hullColliders)
			{
				if ((Object)(object)val != (Object)null)
				{
					Physics.IgnoreCollision(val, obstacle, ignore);
				}
			}
		}

		private static void RestoreHull()
		{
			foreach (Collider item in Ghosted)
			{
				Ignore(item, ignore: false);
			}
			Ghosted.Clear();
		}

		private static void Scan(Ship ship, Vector3 pos, Vector3 forward, float range)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0324: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Expected O, but got Unknown
			//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_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: 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_0122: 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_012c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_034b: 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_034f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0350: Unknown result type (might be due to invalid IL or missing references)
			//IL_0355: Unknown result type (might be due to invalid IL or missing references)
			//IL_0367: Unknown result type (might be due to invalid IL or missing references)
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Unknown result type (might be due to invalid IL or missing references)
			NavGrid grid = WorldNav.Grid;
			if (_scanned == null || _scanned.Length != grid.Clear.Length)
			{
				_scanned = new byte[grid.Clear.Length];
			}
			if (_solidMask == 0)
			{
				_solidMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });
			}
			float waterLevel = WorldNav.WaterLevel;
			float limit = waterLevel - Plugin.MinDepth.Value;
			float num = HullClearance(ship);
			Vector3 val = Vector3.Cross(Vector3.up, forward);
			float cell = grid.Cell;
			int num2 = 320;
			bool flag = false;
			float num9 = default(float);
			for (float num3 = 0f - (num + 34f); num3 <= range; num3 += cell * 0.75f)
			{
				if (num2 <= 0)
				{
					break;
				}
				float num4 = ((num3 < num + 34f) ? (num + 34f) : (14f + num3 * 0.4f));
				for (float num5 = 0f - num4; num5 <= num4; num5 += cell * 0.75f)
				{
					if (num2 <= 0)
					{
						break;
					}
					if (Mathf.Abs(num3) < num - 2f && Mathf.Abs(num5) < 5f)
					{
						continue;
					}
					Vector3 val2 = pos + forward * num3 + val * num5;
					int num6 = grid.Index(val2.x, val2.z);
					byte b = (byte)((!(num3 <= 40f)) ? 1u : 2u);
					if (_scanned[num6] >= b || grid.Clear[num6] == 0)
					{
						continue;
					}
					float num7 = grid.CellX(num6 % grid.Size);
					float num8 = grid.CellZ(num6 / grid.Size);
					if (!Heightmap.GetHeight(new Vector3(num7, 0f, num8), ref num9))
					{
						continue;
					}
					_scanned[num6] = b;
					for (int i = 0; i < 5; i++)
					{
						float num10;
						switch (i)
						{
						default:
							num10 = 2.5f;
							break;
						case 1:
						case 2:
							num10 = -2.5f;
							break;
						case 0:
							num10 = 0f;
							break;
						}
						float num11 = num10;
						float num12;
						switch (i)
						{
						default:
							num12 = 2.5f;
							break;
						case 1:
						case 3:
							num12 = -2.5f;
							break;
						case 0:
							num12 = 0f;
							break;
						}
						float num13 = num12;
						num2--;
						if (Obstructed(new Vector3(num7 + num11, waterLevel + 12f, num8 + num13), limit, (float)(int)grid.Clear[num6] < 24f))
						{
							flag |= WorldNav.MarkBlocked(new Vector3(num7, 0f, num8));
							break;
						}
					}
				}
			}
			_slowScanTimer -= 0.25f;
			if (_slowScanTimer <= 0f)
			{
				_slowScanTimer = 2f;
				Leviathan[] array = Object.FindObjectsByType<Leviathan>((FindObjectsSortMode)0);
				Vector3 val3;
				for (int j = 0; j < array.Length; j++)
				{
					Vector3 position = ((Component)array[j]).transform.position;
					val3 = position - pos;
					if (!(((Vector3)(ref val3)).sqrMagnitude > 62500f))
					{
						flag |= MarkDisc(position, 32f, cell, persist: true);
					}
				}
				foreach (Ship instance in Ship.Instances)
				{
					Ship val4 = instance;
					if (!((Object)(object)val4 == (Object)null) && !((Object)(object)val4 == (Object)(object)ship))
					{
						Vector3 position2 = ((Component)val4).transform.position;
						val3 = position2 - pos;
						if (!(((Vector3)(ref val3)).sqrMagnitude > 40000f))
						{
							flag |= MarkDisc(position2, HullClearance(val4), cell, persist: false);
						}
					}
				}
			}
			if (flag && CourseObstructed(grid, num))
			{
				_replanQueued = true;
			}
		}

		private static bool MarkDisc(Vector3 centre, float radius, float cell, bool persist)
		{
			//IL_0019: 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_002e: Unknown result type (might be due to invalid IL or missing references)
			bool flag = false;
			for (float num = 0f - radius; num <= radius; num += cell)
			{
				for (float num2 = 0f - radius; num2 <= radius; num2 += cell)
				{
					if (num * num + num2 * num2 <= radius * radius)
					{
						flag |= WorldNav.MarkBlocked(new Vector3(centre.x + num, 0f, centre.z + num2), persist);
					}
				}
			}
			return flag;
		}

		private static bool Obstructed(Vector3 origin, float limit, bool tight)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			int num = Physics.RaycastNonAlloc(origin, Vector3.down, Hits, origin.y - limit, _solidMask, (QueryTriggerInteraction)1);
			for (int i = 0; i < num; i++)
			{
				Collider collider = ((RaycastHit)(ref Hits[i])).collider;
				Rigidbody attachedRigidbody = collider.attachedRigidbody;
				if ((Object)(object)attachedRigidbody != (Object)null)
				{
					if ((Object)(object)((Component)attachedRigidbody).GetComponent<Leviathan>() != (Object)null)
					{
						return true;
					}
				}
				else if ((!tight || !Small(collider)) && !BridgePass.Covers(collider))
				{
					return true;
				}
			}
			return false;
		}

		private static bool CourseObstructed(NavGrid grid, float hull)
		{
			for (float num = 0f; num <= 300f && !(Progress + num > Route.Length); num += grid.Cell)
			{
				Route.PointAt(Progress + num, out var x, out var z);
				if (grid.ClearAt(x, z) < hull)
				{
					return true;
				}
			}
			return false;
		}

		private static void Replan(float cooldown)
		{
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_ship == (Object)null)
			{
				return;
			}
			_replanQueued = false;
			_replanAt = Time.time + cooldown;
			Ship ship = _ship;
			Planning = true;
			WorldNav.RequestRoute(((Component)ship).transform.position, Destination, HullClearance(ship), fromShore: false, delegate(Route route, RouteFailure failure)
			{
				Planning = false;
				if (route == null)
				{
					Problem = Explain(failure, aboard: true);
					if (State == PilotState.Sailing)
					{
						Pause(Problem);
					}
				}
				else
				{
					Problem = null;
					Route = route;
					Progress = 0f;
					_markError = 180f;
					Warning = Tightness(route, ship);
				}
			});
		}

		private static void PublishTick(float dt, float remaining)
		{
			_zdoTimer -= dt;
			if (!(_zdoTimer > 0f))
			{
				_zdoTimer = 1f;
				ZDO zDO = _ship.m_nview.GetZDO();
				if (zDO != null)
				{
					zDO.Set(StateKey, 2, false);
					zDO.Set(RemainingKey, remaining);
				}
			}
		}

		private static void Publish(PilotState state)
		{
			if (!((Object)(object)_ship == (Object)null) && !((Object)(object)_ship.m_nview == (Object)null) && _ship.m_nview.IsValid() && _ship.m_nview.IsOwner())
			{
				_ship.m_nview.GetZDO().Set(StateKey, (int)state, false);
			}
		}

		private static void Notify(string text)
		{
			if ((Object)(object)Player.m_localPlayer != (Object)null)
			{
				((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false);
			}
		}
	}
	internal static class Bridges
	{
		private const float Reach = 160f;

		private const float OpenWithin = 130f;

		private static readonly Dictionary<Door, float> Raised = new Dictionary<Door, float>();

		private static readonly Dictionary<Door, float> Used = new Dictionary<Door, float>();

		private static readonly List<Door> Scratch = new List<Door>();

		private static readonly Dictionary<Door, float> Heights = new Dictionary<Door, float>();

		private static float _timer;

		private static readonly Dictionary<Door, float> Nearest = new Dictionary<Door, float>();

		public static float Ahead { get; private set; } = float.MaxValue;

		public static bool Barred { get; private set; }

		public static void Reset()
		{
			Heights.Clear();
			Raised.Clear();
			Used.Clear();
			Ahead = float.MaxValue;
			Barred = false;
			_timer = 0f;
		}

		public static void Tick(Ship ship, Route route, float progress, float halfBeam, float halfLength, float dt)
		{
			//IL_003a: 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)
			//IL_0069: 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_006f: 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_021a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: 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_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0111: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			_timer -= dt;
			if (_timer > 0f)
			{
				return;
			}
			_timer = 0.5f;
			Ahead = float.MaxValue;
			Barred = false;
			Vector3 position = ((Component)ship).transform.position;
			foreach (Door drawbridge in BridgePass.Drawbridges)
			{
				if (!IsDrawbridge(drawbridge))
				{
					continue;
				}
				Vector3 val = ((Component)drawbridge).transform.position - position;
				if (((Vector3)(ref val)).sqrMagnitude > 25600f || !Deck(drawbridge, out var deck))
				{
					continue;
				}
				float value;
				bool flag = Heights.TryGetValue(drawbridge, out value) && Mathf.Abs(((Bounds)(ref deck)).size.y - value) > 0.04f;
				Heights[drawbridge] = ((Bounds)(ref deck)).size.y;
				Vector3 val2 = ((Component)drawbridge).transform.position - position;
				val2.y = 0f;
				if (Raised.ContainsKey(drawbridge) && flag && Vector3.Dot(val2, ((Component)ship).transform.forward) > 0f)
				{
					Ahead = Mathf.Min(Ahead, Mathf.Max(0f, ((Vector3)(ref val2)).magnitude - 4f));
				}
				if (!Lowered(deck))
				{
					continue;
				}
				float num = OnCourse(route, progress, deck, halfBeam + 3f);
				if (num < 0f)
				{
					continue;
				}
				Ahead = Mathf.Min(Ahead, num);
				if (!MayUse(drawbridge))
				{
					if (num < 70f)
					{
						Barred = true;
					}
				}
				else
				{
					if (num > 130f || !Rested(drawbridge))
					{
						continue;
					}
					if (!Raised.ContainsKey(drawbridge))
					{
						Player localPlayer = Player.m_localPlayer;
						if ((Object)(object)localPlayer != (Object)null)
						{
							((Character)localPlayer).Message((MessageType)2, "Hafvisir: raising the drawbridge", 0, (Sprite)null, false);
						}
					}
					if (!Raised.ContainsKey(drawbridge))
					{
						Raised[drawbridge] = ((Vector3)(ref val2)).magnitude;
					}
					Use(drawbridge);
				}
			}
			Lower(position, halfLength, all: false);
		}

		public static void Lower(Vector3 pos, float halfLength, bool all)
		{
			//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_004f: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
			Scratch.Clear();
			foreach (KeyValuePair<Door, float> item in Raised)
			{
				Door key = item.Key;
				if ((Object)(object)key == (Object)null)
				{
					Scratch.Add(key);
					continue;
				}
				Vector3 val = ((Component)key).transform.position - pos;
				val.y = 0f;
				float magnitude = ((Vector3)(ref val)).magnitude;
				if (magnitude < item.Value)
				{
					Nearest[key] = magnitude;
				}
				else if (((magnitude > item.Value + 12f && magnitude > halfLength + 16f) || (all && magnitude > item.Value + 4f)) && (Rested(key) || all))
				{
					if (Deck(key, out var deck) && !Lowered(deck))
					{
						Use(key);
					}
					Scratch.Add(key);
				}
			}
			foreach (KeyValuePair<Door, float> item2 in Nearest)
			{
				Raised[item2.Key] = item2.Value;
			}
			Nearest.Clear();
			foreach (Door item3 in Scratch)
			{
				Raised.Remove(item3);
			}
		}

		internal static bool IsDrawbridge(Door door)
		{
			if ((Object)(object)door != (Object)null && (Object)(object)door.m_nview != (Object)null && door.m_nview.IsValid())
			{
				return Utils.GetPrefabName(((Component)door).gameObject).ToLowerInvariant().Contains("drawbridge");
			}
			return false;
		}

		internal static bool Deck(Door door, out Bounds deck)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			deck = default(Bounds);
			Rigidbody componentInChildren = ((Component)door).GetComponentInChildren<Rigidbody>();
			if ((Object)(object)componentInChildren == (Object)null)
			{
				return false;
			}
			bool flag = false;
			Collider[] componentsInChildren = ((Component)componentInChildren).GetComponentsInChildren<Collider>();
			foreach (Collider val in componentsInChildren)
			{
				if (!val.isTrigger && val.enabled)
				{
					if (flag)
					{
						((Bounds)(ref deck)).Encapsulate(val.bounds);
					}
					else
					{
						deck = val.bounds;
					}
					flag = true;
				}
			}
			return flag;
		}

		private static bool Lowered(Bounds deck)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			return ((Bounds)(ref deck)).size.y < Mathf.Max(((Bounds)(ref deck)).size.x, ((Bounds)(ref deck)).size.z) * 0.75f;
		}

		private static float OnCourse(Route route, float progress, Bounds deck, float margin)
		{
			//IL_0025: 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)
			for (float num = 0f; num <= 160f && !(progress + num > route.Length); num += 3f)
			{
				route.PointAt(progress + num, out var x, out var z);
				if (((Bounds)(ref deck)).SqrDistance(new Vector3(x, ((Bounds)(ref deck)).center.y, z)) < margin * margin)
				{
					return num;
				}
			}
			return -1f;
		}

		private static bool MayUse(Door door)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)door.m_keyItem != (Object)null)
			{
				return false;
			}
			if (door.m_checkGuardStone)
			{
				return PrivateArea.CheckAccess(((Component)door).transform.position, 0f, false, false);
			}
			return true;
		}

		private static bool Rested(Door door)
		{
			if (Used.TryGetValue(door, out var value))
			{
				return Time.time > value + 8f;
			}
			return true;
		}

		private static void Use(Door door)
		{
			//IL_0020: 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)
			Used[door] = Time.time;
			Plugin.Log.LogInfo((object)$"Drawbridge at {((Component)door).transform.position.x:0},{((Component)door).transform.position.z:0} worked by the helm (was state {door.m_nview.GetZDO().GetInt(ZDOVars.s_state, 0)})");
			door.m_nview.InvokeRPC("UseDoor", new object[1] { true });
		}
	}
	internal static class BridgePass
	{
		private struct Gate
		{
			public Vector3 Centre;

			public float Radius;
		}

		private const float Frame = 4f;

		private static readonly List<Gate> Gates = new List<Gate>();

		public static readonly List<Door> Drawbridges = new List<Door>();

		private static float _timer;

		private static int _refresh;

		public static bool InGate(Vector3 point, float margin = 0f)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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)
			foreach (Gate gate in Gates)
			{
				float num = point.x - gate.Centre.x;
				float num2 = point.z - gate.Centre.z;
				float num3 = gate.Radius + margin;
				if (num * num + num2 * num2 < num3 * num3)
				{
					return true;
				}
			}
			return false;
		}

		public static bool Covers(Collider collider)
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)collider == (Object)null) && Gates.Count != 0)
			{
				Bounds bounds = collider.bounds;
				if (InGate(((Bounds)(ref bounds)).center))
				{
					return (Object)(object)((Component)collider).GetComponentInParent<Piece>() != (Object)null;
				}
			}
			return false;
		}

		public static void Tick()
		{
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Expected O, but got Unknown
			//IL_0107: Unknown result type (might be due to invalid IL or missing references)
			//IL_010c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			_timer -= Time.deltaTime;
			if (_timer > 0f)
			{
				return;
			}
			_timer = 0.5f;
			if (!Plugin.BridgesPassable.Value || (Object)(object)ZNetScene.instance == (Object)null || Ship.Instances.Count == 0)
			{
				Gates.Clear();
				Drawbridges.Clear();
				return;
			}
			if (_refresh-- <= 0)
			{
				_refresh = 5;
				Gates.Clear();
				Drawbridges.Clear();
				Door[] array = Object.FindObjectsByType<Door>((FindObjectsSortMode)0);
				foreach (Door val in array)
				{
					if (Bridges.IsDrawbridge(val))
					{
						Drawbridges.Add(val);
						float num = 8f;
						if (Bridges.Deck(val, out var deck))
						{
							num = Mathf.Max(((Bounds)(ref deck)).size.x, Mathf.Max(((Bounds)(ref deck)).size.y, ((Bounds)(ref deck)).size.z));
						}
						Gates.Add(new Gate
						{
							Centre = ((Component)val).transform.position,
							Radius = num + 4f
						});
					}
				}
			}
			if (Gates.Count == 0)
			{
				return;
			}
			foreach (Ship instance in Ship.Instances)
			{
				Ship val2 = instance;
				if ((Object)(object)val2 != (Object)null && InGate(((Component)val2).transform.position, Fleet.HullClearance(val2)))
				{
					GhostHull.Hold(val2, 1.2f);
				}
			}
		}
	}
	internal sealed class Module
	{
		public string Prefab;

		public string Name;

		public string Description;

		public string[] Templates;

		public Func<int> Price;

		public GameObject Object;

		public Color Tint;

		public string IconAsset;

		public string MeshAsset;
	}
	internal static class Modules
	{
		[HarmonyPatch(typeof(ObjectDB), "Awake")]
		private static class ObjectDbAwake
		{
			private static void Postfix(ObjectDB __instance)
			{
				AddTo(__instance);
			}
		}

		[HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")]
		private static class ObjectDbCopy
		{
			private static void Postfix(ObjectDB __instance)
			{
				AddTo(__instance);
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class SceneAwake
		{
			private static void Postfix(ZNetScene __instance)
			{
				if ((Object)(object)ObjectDB.instance != (Object)null)
				{
					AddTo(ObjectDB.instance);
				}
				foreach (Module item in All)
				{
					if (!((Object)(object)item.Object == (Object)null))
					{
						int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)item.Object).name);
						if (!__instance.m_namedPrefabs.ContainsKey(stableHashCode))
						{
							__instance.m_prefabs.Add(item.Object);
							__instance.m_namedPrefabs.Add(stableHashCode, item.Object);
						}
					}
				}
			}
		}

		public const string AntennaPrefab = "HafvisirAntenna";

		public const string AntennaName = "Sonar Antenna";

		public const string RegulatorPrefab = "HafvisirRegulator";

		public const string RegulatorName = "Fuel Regulator";

		public const string NetsPrefab = "HafvisirNets";

		public const string NetsName = "Fishing Nets";

		public static readonly List<Module> All = new List<Module>
		{
			new Module
			{
				Prefab = "HafvisirBeacon",
				Name = "Hafvisir Beacon",
				Templates = new string[2] { "Thunderstone", "SurtlingCore" },
				Tint = new Color(0.25f, 1f, 0.8f),
				IconAsset = "icon_beacon",
				MeshAsset = "beacon",
				Price = () => Plugin.BeaconPrice.Value,
				Description = "Mossbeard's own make. Stow it in a ship's storage and that ship can be sent to sea with no one aboard from a Captain's Table. A ship with no crew is an insult to Aegir, the old sea jotunn. Now and then he stops one dead and keeps its fuel."
			},
			new Module
			{
				Prefab = "HafvisirAntenna",
				Name = "Sonar Antenna",
				Templates = new string[3] { "MechanicalSpring", "DvergrNeedle", "Thunderstone" },
				Tint = new Color(1f, 0.72f, 0.15f),
				IconAsset = "icon_antenna",
				MeshAsset = "antenna",
				Price = () => Plugin.AntennaPrice.Value,
				Description = "A brass aerial that sounds out the coast. While it sits in a ship's storage, everyone aboard uncovers the map much farther around the ship."
			},
			new Module
			{
				Prefab = "HafvisirRegulator",
				Name = "Fuel Regulator",
				Templates = new string[3] { "BlackCore", "SurtlingCore", "Thunderstone" },
				Tint = new Color(1f, 0.3f, 0.2f),
				IconAsset = "icon_regulator",
				MeshAsset = "regulator",
				Price = () => Plugin.RegulatorPrice.Value,
				Description = "A valve that feeds the firebox evenly. While it sits in a ship's storage, Hafvisir burns a quarter less fuel on every trip, with a crew or without."
			},
			new Module
			{
				Prefab = "HafvisirNets",
				Name = "Fishing Nets",
				Templates = new string[3] { "LinenThread", "FishingRod", "Chain" },
				Tint = new Color(0.85f, 0.6f, 0.3f),
				IconAsset = "icon_nets",
				MeshAsset = "nets",
				Price = () => Plugin.NetsPrice.Value,
				Description = "Nets trailed behind a ship. While they sit in its storage, a ship sailing under Hafvisir lands a fish every so often. The catch depends on the waters it crosses, and each fish uses up the bait it takes on a rod, which must be in the storage too."
			}
		};

		private static GameObject _holder;

		private static readonly Dictionary<Color, Texture2D> Paints = new Dictionary<Color, Texture2D>();

		private static readonly float[] Shades = new float[7] { 0.55f, 0.68f, 0.78f, 0.86f, 0.86f, 0.93f, 1f };

		public static float Stretch(bool regulated)
		{
			if (!regulated)
			{
				return 1f;
			}
			return 1f / (1f - Mathf.Clamp(Plugin.RegulatorSaving.Value, 0f, 0.9f));
		}

		public static bool Has(Inventory hold, string module)
		{
			if (hold != null)
			{
				return hold.CountItems(module, -1, true) > 0;
			}
			return false;
		}

		private static string[] Waters(Biome biome)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Invalid comparison between Unknown and I4
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Invalid comparison between Unknown and I4
			//IL_0005: 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_001d: Expected I4, but got Unknown
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: 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
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Invalid comparison between Unknown and I4
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Invalid comparison between Unknown and I4
			if ((int)biome <= 16)
			{
				switch (biome - 1)
				{
				default:
					if ((int)biome != 8)
					{
						if ((int)biome != 16)
						{
							break;
						}
						return new string[1] { "Fish7" };
					}
					return new string[2] { "Fish5", "Fish2" };
				case 0:
					return new string[2] { "Fish1", "Fish2" };
				case 1:
					return new string[1] { "Fish6" };
				case 3:
					return new string[1] { "Fish2" };
				case 2:
					break;
				}
			}
			else
			{
				if ((int)biome == 32)
				{
					return new string[1] { "Fish11" };
				}
				if ((int)biome == 64)
				{
					return new string[1] { "Fish10" };
				}
				if ((int)biome == 512)
				{
					return new string[2] { "Fish9", "Fish12" };
				}
			}
			return new string[2] { "Fish3", "Fish8" };
		}

		public static GameObject Catch(Inventory hold, Biome biome, Random chance, out bool lacking)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			lacking = false;
			if (hold == null || (Object)(object)ObjectDB.instance == (Object)null)
			{
				return null;
			}
			string[] array = Waters(biome);
			int num = ((array.Length > 1 && chance.Next(3) == 0) ? 1 : 0);
			int num2 = Mathf.Max(1, Plugin.BaitPerFish.Value);
			for (int i = 0; i < array.Length; i++)
			{
				GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(array[(num + i) % array.Length]);
				if ((Object)(object)itemPrefab == (Object)null)
				{
					continue;
				}
				string text = null;
				if (Plugin.NetsNeedBait.Value)
				{
					Fish component = itemPrefab.GetComponent<Fish>();
					if ((Object)(object)component != (Object)null && component.m_baits != null && component.m_baits.Count > 0)
					{
						foreach (BaitSetting bait in component.m_baits)
						{
							string text2 = (((Object)(object)bait.m_bait != (Object)null) ? bait.m_bait.m_itemData.m_shared.m_name : null);
							if (text2 != null && hold.CountItems(text2, -1, true) >= num2)
							{
								text = text2;
								break;
							}
						}
						if (text == null)
						{
							lacking = true;
							continue;
						}
					}
				}
				if (!hold.AddItem(itemPrefab, 1))
				{
					lacking = false;
					return null;
				}
				if (text != null)
				{
					hold.RemoveItem(text, num2, -1, true);
				}
				lacking = false;
				return itemPrefab;
			}
			return null;
		}

		private static GameObject Build(ObjectDB db, Module module)
		{
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Expected O, but got Unknown
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Expected O, but got Unknown
			//IL_01be: Unknown result type (might be due to invalid IL or missing references)
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0207: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)module.Object != (Object)null)
			{
				return module.Object;
			}
			GameObject val = null;
			string[] templates = module.Templates;
			foreach (string name in templates)
			{
				val = db.m_items.Find((GameObject item) => (Object)(object)item != (Object)null && ((Object)item).name == name);
				if ((Object)(object)val != (Object)null)
				{
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return null;
			}
			if ((Object)(object)_holder == (Object)null)
			{
				_holder = new GameObject("HafvisirPrefabs");
				_holder.SetActive(false);
				Object.DontDestroyOnLoad((Object)(object)_holder);
			}
			GameObject val2 = Object.Instantiate<GameObject>(val, _holder.transform);
			((Object)val2).name = module.Prefab;
			ItemDrop component = val2.GetComponent<ItemDrop>();
			component.m_itemData = component.m_itemData.Clone();
			component.m_itemData.m_shared = (SharedData)AccessTools.Method(typeof(object), "MemberwiseClone", (Type[])null, (Type[])null).Invoke(component.m_itemData.m_shared, null);
			SharedData shared = component.m_itemData.m_shared;
			shared.m_name = module.Name;
			shared.m_description = module.Description;
			shared.m_maxStackSize = 1;
			shared.m_weight = 4f;
			shared.m_value = 0;
			shared.m_teleportable = true;
			shared.m_itemType = (ItemType)1;
			shared.m_maxQuality = 1;
			shared.m_useDurability = false;
			Texture2D val3 = ((module.IconAsset != null && Recolor.Possible) ? UIKit.Embedded(module.IconAsset) : null);
			if ((Object)(object)val3 != (Object)null)
			{
				((Texture)val3).filterMode = (FilterMode)1;
				shared.m_icons = (Sprite[])(object)new Sprite[1] { Sprite.Create(val3, new Rect(0f, 0f, (float)((Texture)val3).width, (float)((Texture)val3).height), new Vector2(0.5f, 0.5f), 100f) };
			}
			else if (shared.m_icons != null && shared.m_icons.Length != 0)
			{
				shared.m_icons = (Sprite[])(object)new Sprite[1] { Recolor.Icon(shared.m_icons[0], module.Tint) };
			}
			if (module.MeshAsset == null || !Remodel(val2, module.MeshAsset))
			{
				Recolor.Model(val2, module.Tint);
			}
			component.m_itemData.m_dropPrefab = val2;
			module.Object = val2;
			return val2;
		}

		public static GameObject Model(string asset, Material like, int layer, float glow = 1f)
		{
			//IL_00c1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0212: Unknown result type (might be due to invalid IL or missing references)
			//IL_0217: Unknown result type (might be due to invalid IL or missing references)
			//IL_022a: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b6: Expected O, but got Unknown
			//IL_0404: 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_0410: 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_042b: Expected O, but got Unknown
			//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_035d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0352: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ca: Unknown result type (might be due to invalid IL or missing references)
			//IL_03e4: Unknown result type (might be due to invalid IL or missing references)
			if (!Recolor.Possible || (Object)(object)like == (Object)null)
			{
				return null;
			}
			Stream manifestResourceStream = typeof(Modules).Assembly.GetManifestResourceStream("Hafvisir.assets." + asset + ".mesh");
			if (manifestResourceStream == null)
			{
				return null;
			}
			List<Vector3> list = new List<Vector3>();
			List<Vector3> list2 = new List<Vector3>();
			List<Vector2> list3 = new List<Vector2>();
			List<Color> list4 = new List<Color>();
			List<float> list5 = new List<float>();
			List<List<int>> list6 = new List<List<int>>();
			int num = 0;
			using (StreamReader streamReader = new StreamReader(manifestResourceStream))
			{
				CultureInfo invariantCulture = CultureInfo.InvariantCulture;
				string text;
				while ((text = streamReader.ReadLine()) != null)
				{
					string[] array = text.Split(new char[1] { ' ' });
					if (array[0] == "c")
					{
						list4.Add(new Color(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture), float.Parse(array[3], invariantCulture)));
						list5.Add((array.Length > 4) ? float.Parse(array[4], invariantCulture) : 0f);
						list6.Add(new List<int>());
						num = list.Count;
					}
					else if (array[0] == "v")
					{
						list.Add(new Vector3(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture), float.Parse(array[3], invariantCulture)));
						list2.Add(new Vector3(float.Parse(array[4], invariantCulture), float.Parse(array[5], invariantCulture), float.Parse(array[6], invariantCulture)));
						list3.Add((Vector2)((array.Length > 8) ? new Vector2(float.Parse(array[7], invariantCulture), float.Parse(array[8], invariantCulture)) : Vector2.zero));
					}
					else if (array[0] == "t")
					{
						List<int> list7 = list6[list6.Count - 1];
						list7.Add(num + int.Parse(array[1]));
						list7.Add(num + int.Parse(array[2]));
						list7.Add(num + int.Parse(array[3]));
					}
				}
			}
			Mesh val = new Mesh
			{
				name = "Hafvisir_" + asset
			};
			if (list.Count > 65000)
			{
				val.indexFormat = (IndexFormat)1;
			}
			val.SetVertices(list);
			val.SetNormals(list2);
			val.SetUVs(0, list3);
			val.subMeshCount = list6.Count;
			for (int i = 0; i < list6.Count; i++)
			{
				val.SetTriangles(list6[i], i);
			}
			val.RecalculateBounds();
			Material[] array2 = (Material[])(object)new Material[list4.Count];
			for (int j = 0; j < array2.Length; j++)
			{
				array2[j] = new Material(like);
				array2[j].mainTexture = (Texture)(object)((list5[j] > 0f) ? Texture2D.whiteTexture : Paint(list4[j]));
				if (array2[j].HasProperty("_BumpMap"))
				{
					array2[j].SetTexture("_BumpMap", (Texture)null);
				}
				if (array2[j].HasProperty("_MetallicGlossMap"))
				{
					array2[j].SetTexture("_MetallicGlossMap", (Texture)null);
				}
				if (array2[j].HasProperty("_Color"))
				{
					array2[j].SetColor("_Color", (list5[j] > 0f) ? list4[j] : Color.white);
				}
				if (array2[j].HasProperty("_Cull"))
				{
					array2[j].SetFloat("_Cull", 0f);
				}
				if (list5[j] > 0f && array2[j].HasProperty("_EmissionColor"))
				{
					array2[j].EnableKeyword("_EMISSION");
					array2[j].SetColor("_EmissionColor", list4[j] * (Mathf.Min(list5[j], 3f) * glow));
				}
			}
			GameObject val2 = new GameObject("HafvisirModel")
			{
				layer = layer
			};
			val2.AddComponent<MeshFilter>().sharedMesh = val;
			((Renderer)val2.AddComponent<MeshRenderer>()).sharedMaterials = array2;
			return val2;
		}

		private unsafe static Texture2D Paint(Color colour)
		{
			//IL_0005: 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_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected O, but got Unknown
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			if (Paints.TryGetValue(colour, out var value) && (Object)(object)value != (Object)null)
			{
				return value;
			}
			Random random = new Random(((object)(*(Color*)(&colour))/*cast due to .constrained prefix*/).GetHashCode());
			Color32[] array = (Color32[])(object)new Color32[256];
			for (int i = 0; i < array.Length; i++)
			{
				float num = Shades[random.Next(Shades.Length)];
				float num2 = (float)(random.NextDouble() - 0.5) * 0.08f;
				array[i] = Color32.op_Implicit(new Color(Mathf.Clamp01(colour.r * num + num2), Mathf.Clamp01(colour.g * num), Mathf.Clamp01(colour.b * num - num2), 1f));
			}
			Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false)
			{
				filterMode = (FilterMode)0,
				wrapMode = (TextureWrapMode)0
			};
			val.SetPixels32(array);
			val.Apply(false);
			Paints[colour] = val;
			return val;
		}

		private static bool Remodel(GameObject prefab, string asset)
		{
			//IL_00bc: 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_010c: Unknown result type (might be due to invalid IL or missing references)
			MeshRenderer componentInChildren = prefab.GetComponentInChildren<MeshRenderer>(true);
			GameObject val = Model(asset, ((Object)(object)componentInChildren != (Object)null) ? ((Renderer)componentInChildren).sharedMaterial : null, ((Object)(object)componentInChildren != (Object)null) ? ((Component)componentInChildren).gameObject.layer : 0);
			if ((Object)(object)val == (Object)null)
			{
				return false;
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].enabled = false;
			}
			LODGroup[] componentsInChildren2 = prefab.GetComponentsInChildren<LODGroup>(true);
			for (int i = 0; i < componentsInChildren2.Length; i++)
			{
				componentsInChildren2[i].enabled = false;
			}
			Light[] componentsInChildren3 = prefab.GetComponentsInChildren<Light>(true);
			for (int i = 0; i < componentsInChildren3.Length; i++)
			{
				((Behaviour)componentsInChildren3[i]).enabled = false;
			}
			ParticleSystem[] componentsInChildren4 = prefab.GetComponentsInChildren<ParticleSystem>(true);
			for (int i = 0; i < componentsInChildren4.Length; i++)
			{
				EmissionModule emission = componentsInChildren4[i].emission;
				((EmissionModule)(ref emission)).enabled = false;
			}
			if (!prefab.activeSelf)
			{
				prefab.SetActive(true);
			}
			val.transform.SetParent(prefab.transform, false);
			val.transform.localPosition = new Vector3(0f, 0.05f, 0f);
			return true;
		}

		private static void AddTo(ObjectDB db)
		{
			if ((Object)(object)db == (Object)null || db.m_items == null || db.m_items.Count == 0)
			{
				return;
			}
			bool flag = false;
			foreach (Module item in All)
			{
				GameObject val = Build(db, item);
				if (!((Object)(object)val == (Object)null) && !db.m_items.Contains(val))
				{
					db.m_items.Add(val);
					flag = true;
				}
			}
			if (flag)
			{
				db.UpdateRegisters();
			}
		}
	}
	[HarmonyPatch(typeof(Minimap), "UpdateExplore")]
	internal static class Antenna
	{
		private static float _vanilla = -1f;

		private static float _nextCheck;

		private static bool _active;

		public static bool Active => _active;

		private static void Prefix(Minimap __instance, Player player)
		{
			if (_vanilla < 0f)
			{
				_vanilla = __instance.m_exploreRadius;
			}
			if (Time.time >= _nextCheck)
			{
				_nextCheck = Time.time + 1f;
				Inventory val = Autopilot.Hold(((Object)(object)player != (Object)null) ? (player.GetControlledShip() ?? ((Character)player).GetStandingOnShip()) : null);
				_active = val != null && val.CountItems("Sonar Antenna", -1, true) > 0;
			}
			__instance.m_exploreRadius = (_active ? Mathf.Max(_vanilla, Plugin.AntennaRadius.Value) : _vanilla);
		}
	}
	[HarmonyPatch(typeof(Trader), "OnBought")]
	internal static class KeeperSold
	{
		private static bool Prefix(Trader __instance)
		{
			Keeper component = ((Component)__instance).GetComponent<Keeper>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			component.Bought();
			return false;
		}
	}
	[HarmonyPatch(typeof(Trader), "OnSold")]
	internal static class KeeperBought
	{
		private static bool Prefix(Trader __instance)
		{
			return (Object)(object)((Component)__instance).GetComponent<Keeper>() == (Object)null;
		}
	}
	internal enum VoyageState
	{
		None,
		Underway,
		Anchored,
		Adrift,
		Cursed,
		Towed
	}
	internal static class Fleet
	{
		public const string BeaconPrefab = "HafvisirBeacon";

		public const string BeaconName = "Hafvisir Beacon";

		public static readonly int StateKey = StringExtensionMethods.GetStableHashCode("hafvisir_voyage");

		public static readonly int NameKey = StringExtensionMethods.GetStableHashCode("hafvisir_name");

		public static readonly int RouteKey = StringExtensionMethods.GetStableHashCode("hafvisir_route");

		public static readonly int DepartKey = StringExtensionMethods.GetStableHashCode("hafvisir_depart");

		public static readonly int SpeedKey = StringExtensionMethods.GetStableHashCode("hafvisir_speed");

		public static readonly int StopAtKey = StringExtensionMethods.GetStableHashCode("hafvisir_stopat");

		public static readonly int EndKey = StringExtensionMethods.GetStableHashCode("hafvisir_end");

		public static readonly int RoundKey = StringExtensionMethods.GetStableHashCode("hafvisir_round");

		public static readonly int DestNameKey = StringExtensionMethods.GetStableHashCode("hafvisir_dest");

		public static readonly int ChargeKey = StringExtensionMethods.GetStableHashCode("hafvisir_charge");

		public static bool DevNoDrive;

		private static readonly Dictionary<ZDOID, KeyValuePair<long, Route>> RouteCache = new Dictionary<ZDOID, KeyValuePair<long, Route>>();

		public static double Now => ZNet.instance.GetTimeSeconds();

		public static float TowSpeed(string shipPrefab)
		{
			return UnmannedSpeed(Fuels.All[0], shipPrefab) * Mathf.Clamp(Plugin.TowSpeed.Value, 0.1f, 2f);
		}

		public static VoyageState State(ZDO zdo)
		{
			return (VoyageState)zdo.GetInt(StateKey, 0);
		}

		public static bool Moving(VoyageState state)
		{
			if (state != VoyageState.Underway)
			{
				return state == VoyageState.Towed;
			}
			return true;
		}

		public static bool Moving(Ship ship)
		{
			ZDO val = (((Object)(object)ship != (Object)null && (Object)(object)ship.m_nview != (Object)null && ship.m_nview.IsValid()) ? ship.m_nview.GetZDO() : null);
			if (val != null)
			{
				return Moving(State(val));
			}
			return false;
		}

		public static bool Stranded(Ship ship)
		{
			ZDO val = (((Object)(object)ship != (Object)null && (Object)(object)ship.m_nview != (Object)null && ship.m_nview.IsValid()) ? ship.m_nview.GetZDO() : null);
			if (val == null)
			{
				return false;
			}
			VoyageState voyageState = State(val);
			if (voyageState != VoyageState.Adrift)
			{
				return voyageState == VoyageState.Cursed;
			}
			return true;
		}

		public static void Write(ZDO zdo, Action<ZDO> change)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			bool num = !zdo.IsOwner();
			if (num)
			{
				zdo.SetOwner(ZDOMan.GetSessionID());
			}
			change(zdo);
			if (num)
			{
				zdo.DataRevision += 20000;
				if (!ZNet.instance.IsServer())
				{
					ZDOMan.instance.ClientChanged(zdo.m_uid);
				}
			}
		}

		public static Inventory Hold(ZDO zdo, out Action save)
		{
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Expected O, but got Unknown
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0117: Expected O, but got Unknown
			save = null;
			ZNetView val = ZNetScene.instance.FindInstance(zdo);
			if ((Object)(object)val != (Object)null)
			{
				C