FSDS.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace FSDS;

[BepInProcess("valheim.exe")]
[BepInPlugin("Heimlife.FSDS", "FSDS", "0.3.6")]
public sealed class Plugin : BaseUnityPlugin
{
	private enum RecoveryPhase
	{
		None,
		Stop,
		Reverse,
		Turn,
		Replan
	}

	internal static Plugin I;

	internal static bool Active;

	internal static Ship Helm;

	internal static Vector3 Destination;

	internal static string DestinationName = "";

	internal static bool HasDestination;

	internal static readonly List<Vector3> Route = new List<Vector3>();

	internal static int RouteIndex;

	internal static Vector3 RouteEndpoint;

	internal static Vector3 SteeringTarget;

	internal static bool AvoidingObstacle;

	internal static string NavState = "STANDBY";

	internal static ConfigEntry<bool> Enabled;

	internal static ConfigEntry<KeyboardShortcut> ToggleKey;

	internal static ConfigEntry<string> PinName;

	internal static ConfigEntry<float> ArrivalRadius;

	internal static ConfigEntry<bool> ManualCancel;

	internal static ConfigEntry<bool> ManualThrottleCancel;

	internal static ConfigEntry<bool> Hud;

	internal static ConfigEntry<float> HudScale;

	internal static ConfigEntry<float> Kp;

	internal static ConfigEntry<float> Ki;

	internal static ConfigEntry<float> Kd;

	internal static ConfigEntry<bool> RefreshPin;

	internal static ConfigEntry<float> RefreshSeconds;

	internal static ConfigEntry<bool> DeletePinOnArrival;

	internal static ConfigEntry<bool> AutoThrottle;

	internal static ConfigEntry<bool> WindAwareThrottle;

	internal static ConfigEntry<float> ThrottleStepSeconds;

	internal static ConfigEntry<float> SlowdownDistance;

	internal static ConfigEntry<float> SharpTurnDegrees;

	internal static ConfigEntry<float> MediumTurnDegrees;

	internal static ConfigEntry<bool> RoutePlanning;

	internal static ConfigEntry<float> RouteGridSize;

	internal static ConfigEntry<float> MinWaterDepth;

	internal static ConfigEntry<float> SafeShoreDistance;

	internal static ConfigEntry<float> RouteMargin;

	internal static ConfigEntry<int> MaxRouteNodes;

	internal static ConfigEntry<float> WaypointRadius;

	internal static ConfigEntry<bool> SmoothRoute;

	internal static ConfigEntry<bool> FallbackDirect;

	internal static ConfigEntry<bool> ObstacleAvoidance;

	internal static ConfigEntry<float> ObstacleLookahead;

	internal static ConfigEntry<float> ObstacleRadius;

	internal static ConfigEntry<float> AvoidanceTurnDegrees;

	internal static ConfigEntry<bool> LeviathanAvoidance;

	internal static ConfigEntry<float> LeviathanLookahead;

	internal static ConfigEntry<float> LeviathanScanRadius;

	internal static ConfigEntry<float> LeviathanTurnDegrees;

	internal static ConfigEntry<bool> ScanAllSolidLayers;

	internal static ConfigEntry<float> LargeObstacleLookahead;

	internal static ConfigEntry<float> LargeObstacleScanRadius;

	internal static ConfigEntry<float> LargeObstacleTurnDegrees;

	internal static ConfigEntry<float> IgnoreTinyColliderSize;

	internal static ConfigEntry<bool> LiveShoreAvoidance;

	internal static ConfigEntry<float> ShoreLookahead;

	internal static ConfigEntry<float> ShoreAvoidanceTurnDegrees;

	internal static ConfigEntry<float> SensorScanSeconds;

	internal static ConfigEntry<bool> StuckDetection;

	internal static ConfigEntry<float> StuckCheckSeconds;

	internal static ConfigEntry<float> StuckMinProgress;

	internal static ConfigEntry<bool> ReplanWhenStuck;

	internal static ConfigEntry<bool> DebugLogging;

	internal static ConfigEntry<bool> ShipAwareClearance;

	internal static ConfigEntry<float> SmallShipExtraClearance;

	internal static ConfigEntry<float> LongshipExtraClearance;

	internal static ConfigEntry<bool> TurnAnticipation;

	internal static ConfigEntry<float> TurnLookaheadBlend;

	internal static ConfigEntry<bool> AdvancedStuckRecovery;

	internal static ConfigEntry<float> RecoveryReverseSeconds;

	internal static ConfigEntry<float> RecoveryTurnSeconds;

	internal static ConfigEntry<bool> RouteVisualization;

	internal static ConfigEntry<float> RouteMarkerSpacing;

	private Harmony _harmony;

	private float _nextDestinationRefresh;

	private float _nextThrottleStep;

	private float _nextObstacleScan;

	private float _nextStuckCheck;

	private Vector3 _lastStuckPosition;

	private int _solidMask;

	private readonly RaycastHit[] _sensorHits = (RaycastHit[])(object)new RaycastHit[256];

	private static readonly float[] BroadScanHeights = new float[3] { 0.7f, 2f, 4.5f };

	private RecoveryPhase _recoveryPhase;

	private float _recoveryUntil;

	private float _recoveryTurnSign = 1f;

	private readonly List<object> _routePins = new List<object>();

	private GUIStyle _title;

	private GUIStyle _text;

	internal static readonly Pid Rudder = new Pid();

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

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

	private static readonly FieldInfo WaterLevelField = AccessTools.Field(typeof(ZoneSystem), "m_waterLevel");

	private void Awake()
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: Expected O, but got Unknown
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Expected O, but got Unknown
		I = this;
		BindConfig();
		_solidMask = LayerMask.GetMask(new string[10] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "vehicle", "character", "character_noenv", "character_net" });
		if (_solidMask == 0)
		{
			_solidMask = -1;
		}
		_harmony = new Harmony("Heimlife.FSDS");
		MethodInfo methodInfo = AccessTools.Method(typeof(Ship), "ApplyControlls", new Type[1] { typeof(Vector3) }, (Type[])null) ?? AccessTools.Method(typeof(Ship), "ApplyControls", new Type[1] { typeof(Vector3) }, (Type[])null);
		if (methodInfo == null)
		{
			((BaseUnityPlugin)this).Logger.LogError((object)"FSDS could not find Ship.ApplyControlls/ApplyControls(Vector3).");
			return;
		}
		_harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(ShipPatch), "Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		((BaseUnityPlugin)this).Logger.LogInfo((object)("FSDS v0.3.6 loaded. Destination pin: " + PinName.Value));
		((BaseUnityPlugin)this).Logger.LogInfo((object)"FSDS 0.3.6 low-lag pass: non-alloc physics sensors, reduced terrain sampling, and 0.30s sensor cadence.");
	}

	private void BindConfig()
	{
		//IL_0038: 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_00e9: Expected O, but got Unknown
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0147: Expected O, but got Unknown
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a5: Expected O, but got Unknown
		//IL_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e3: Expected O, but got Unknown
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Expected O, but got Unknown
		//IL_0295: Unknown result type (might be due to invalid IL or missing references)
		//IL_029f: Expected O, but got Unknown
		//IL_02d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02dd: Expected O, but got Unknown
		//IL_0311: Unknown result type (might be due to invalid IL or missing references)
		//IL_031b: Expected O, but got Unknown
		//IL_034f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0359: Expected O, but got Unknown
		//IL_03ad: Unknown result type (might be due to invalid IL or missing references)
		//IL_03b7: Expected O, but got Unknown
		//IL_03eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f5: Expected O, but got Unknown
		//IL_0429: Unknown result type (might be due to invalid IL or missing references)
		//IL_0433: Expected O, but got Unknown
		//IL_0467: Unknown result type (might be due to invalid IL or missing references)
		//IL_0471: Expected O, but got Unknown
		//IL_04a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_04af: Expected O, but got Unknown
		//IL_04e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_04ed: Expected O, but got Unknown
		//IL_0581: Unknown result type (might be due to invalid IL or missing references)
		//IL_058b: Expected O, but got Unknown
		//IL_05bf: Unknown result type (might be due to invalid IL or missing references)
		//IL_05c9: Expected O, but got Unknown
		//IL_05fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0607: Expected O, but got Unknown
		//IL_065b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0665: Expected O, but got Unknown
		//IL_0699: Unknown result type (might be due to invalid IL or missing references)
		//IL_06a3: Expected O, but got Unknown
		//IL_06d7: Unknown result type (might be due to invalid IL or missing references)
		//IL_06e1: Expected O, but got Unknown
		//IL_0735: Unknown result type (might be due to invalid IL or missing references)
		//IL_073f: Expected O, but got Unknown
		//IL_0773: Unknown result type (might be due to invalid IL or missing references)
		//IL_077d: Expected O, but got Unknown
		//IL_07b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_07bb: Expected O, but got Unknown
		//IL_07ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_07f9: Expected O, but got Unknown
		//IL_084d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0857: Expected O, but got Unknown
		//IL_088b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0895: Expected O, but got Unknown
		//IL_08c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_08d3: Expected O, but got Unknown
		//IL_0927: Unknown result type (might be due to invalid IL or missing references)
		//IL_0931: Expected O, but got Unknown
		//IL_0965: Unknown result type (might be due to invalid IL or missing references)
		//IL_096f: Expected O, but got Unknown
		//IL_09e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_09ed: Expected O, but got Unknown
		//IL_0a41: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a4b: Expected O, but got Unknown
		//IL_0a7f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0a89: Expected O, but got Unknown
		//IL_0add: Unknown result type (might be due to invalid IL or missing references)
		//IL_0ae7: Expected O, but got Unknown
		//IL_0b3b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b45: Expected O, but got Unknown
		//IL_0b79: Unknown result type (might be due to invalid IL or missing references)
		//IL_0b83: Expected O, but got Unknown
		//IL_0bd7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0be1: Expected O, but got Unknown
		Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("1 - General", "Enabled", true, "Master switch.");
		ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("2 - Controls", "Autopilot Toggle Key", new KeyboardShortcut((KeyCode)112, (KeyCode[])(object)new KeyCode[0]), "Engage/disengage FSDS while at the helm.");
		ManualCancel = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Controls", "Manual Steering Cancels Autopilot", true, "A/D or Left/Right immediately cancels FSDS.");
		ManualThrottleCancel = ((BaseUnityPlugin)this).Config.Bind<bool>("2 - Controls", "Manual Throttle Cancels Autopilot", true, "W/S or Up/Down immediately cancels FSDS while automatic throttle is enabled.");
		PinName = ((BaseUnityPlugin)this).Config.Bind<string>("3 - Destination", "Destination Pin Name", "GO", "Exact map-pin name used as the destination.");
		ArrivalRadius = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Destination", "Arrival Radius", 15f, new ConfigDescription("Distance from the final navigable water point where FSDS stops.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 100f), new object[0]));
		RefreshPin = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Destination", "Refresh Destination While Active", true, "Re-read the destination pin while sailing.");
		RefreshSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("3 - Destination", "Destination Refresh Seconds", 1f, new ConfigDescription("Pin refresh interval.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 10f), new object[0]));
		DeletePinOnArrival = ((BaseUnityPlugin)this).Config.Bind<bool>("3 - Destination", "Delete Destination Pin On Arrival", true, "When enabled, FSDS deletes the matching destination pin after arriving.");
		Kp = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Steering", "Steering Proportional", 3f, new ConfigDescription("Primary steering response.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 10f), new object[0]));
		Ki = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Steering", "Steering Integral", 0.003f, new ConfigDescription("Long-term steering correction.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), new object[0]));
		Kd = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Steering", "Steering Damping", 6f, new ConfigDescription("Reduces steering oscillation.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), new object[0]));
		AutoThrottle = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Throttle", "Automatic Throttle", true, "FSDS automatically changes paddle/half/full sail and stops on arrival.");
		WindAwareThrottle = ((BaseUnityPlugin)this).Config.Bind<bool>("5 - Throttle", "Wind Aware Throttle", true, "When the wind is poor, FSDS can fall back to paddle speed. With permanent Moder this normally stays at sail.");
		ThrottleStepSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Throttle", "Throttle Step Seconds", 0.35f, new ConfigDescription("Minimum time between automatic speed-setting changes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 2f), new object[0]));
		SlowdownDistance = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Throttle", "Arrival Slowdown Distance", 70f, new ConfigDescription("Begin slowing as the final route endpoint approaches.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 250f), new object[0]));
		SharpTurnDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Throttle", "Sharp Turn Angle", 65f, new ConfigDescription("Turns sharper than this use paddle speed.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 120f), new object[0]));
		MediumTurnDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("5 - Throttle", "Medium Turn Angle", 30f, new ConfigDescription("Turns sharper than this use half sail.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 80f), new object[0]));
		RoutePlanning = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Routing", "Water Route Planning", true, "Calculate a water-only route instead of sailing straight through land.");
		RouteGridSize = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Route Grid Size", 45f, new ConfigDescription("Navigation grid spacing in meters. Smaller is more precise but costs more CPU.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 120f), new object[0]));
		MinWaterDepth = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Minimum Water Depth", 2f, new ConfigDescription("Minimum generated-water depth required for a route cell.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), new object[0]));
		SafeShoreDistance = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Safe Shore Distance", 12f, new ConfigDescription("Extra radius sampled around route cells to keep boats away from shore.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 40f), new object[0]));
		RouteMargin = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Route Search Margin", 450f, new ConfigDescription("Extra search area around the start/destination bounding box.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(100f, 1500f), new object[0]));
		MaxRouteNodes = ((BaseUnityPlugin)this).Config.Bind<int>("6 - Routing", "Maximum Route Nodes", 9000, new ConfigDescription("Maximum A* navigation-grid cells. FSDS automatically coarsens the grid if needed.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(2000, 60000), new object[0]));
		WaypointRadius = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Waypoint Radius", 25f, new ConfigDescription("Distance used to advance to the next route waypoint.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 80f), new object[0]));
		SmoothRoute = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Routing", "Smooth Route", true, "Remove unnecessary A* corners when a direct water segment is safe.");
		FallbackDirect = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Routing", "Fallback To Direct Steering", false, "If no safe water route can be found, steer directly to the destination instead of refusing to engage.");
		ObstacleAvoidance = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Obstacle Avoidance", "Obstacle Avoidance", true, "Locally steer around rocks, structures, ships and other solid obstacles.");
		ObstacleLookahead = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Obstacle Lookahead", 45f, new ConfigDescription("Forward obstacle scan distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 100f), new object[0]));
		ObstacleRadius = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Obstacle Scan Radius", 1.8f, new ConfigDescription("Sphere-cast radius used for obstacle sensing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 5f), new object[0]));
		AvoidanceTurnDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Avoidance Turn Degrees", 38f, new ConfigDescription("Temporary steering offset while avoiding a local obstacle.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 70f), new object[0]));
		LeviathanAvoidance = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Obstacle Avoidance", "Leviathan Avoidance", true, "Explicitly detect Leviathans on any collision layer and steer around them.");
		LeviathanLookahead = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Leviathan Lookahead", 95f, new ConfigDescription("How far ahead FSDS scans specifically for Leviathans.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(35f, 180f), new object[0]));
		LeviathanScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Leviathan Scan Radius", 4f, new ConfigDescription("Width of the Leviathan-specific forward sensor.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 10f), new object[0]));
		LeviathanTurnDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Leviathan Avoidance Turn", 58f, new ConfigDescription("Steering offset used to route around a detected Leviathan.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(25f, 80f), new object[0]));
		ScanAllSolidLayers = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Obstacle Avoidance", "Scan All Solid Layers", true, "Use an all-layer physical scan for spawned ocean/world obstacles such as Ashlands rock spires, wrecks, structures and unusual prefab colliders.");
		LargeObstacleLookahead = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Large Obstacle Lookahead", 85f, new ConfigDescription("Forward distance for the broad spawned-object safety scan.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 180f), new object[0]));
		LargeObstacleScanRadius = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Large Obstacle Scan Radius", 3.5f, new ConfigDescription("Width of the broad obstacle sensor. Larger values give longships more room around Ashlands spires and rocks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1.5f, 8f), new object[0]));
		LargeObstacleTurnDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Large Obstacle Avoidance Turn", 52f, new ConfigDescription("Temporary course offset when a large spawned obstacle is detected.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(25f, 80f), new object[0]));
		IgnoreTinyColliderSize = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Ignore Tiny Collider Size", 0.8f, new ConfigDescription("Colliders smaller than this approximate size are ignored by the broad scan so dropped items and tiny clutter do not cause needless turns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), new object[0]));
		LiveShoreAvoidance = ((BaseUnityPlugin)this).Config.Bind<bool>("7 - Obstacle Avoidance", "Live Shore Avoidance", true, "Continuously enforce Safe Shore Distance while the ship is actually sailing.");
		ShoreLookahead = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Shore Lookahead", 70f, new ConfigDescription("How far ahead FSDS checks the generated shoreline while sailing.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(25f, 140f), new object[0]));
		ShoreAvoidanceTurnDegrees = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Shore Avoidance Turn", 50f, new ConfigDescription("Temporary steering angle used to move the boat away from shore.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 80f), new object[0]));
		SensorScanSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("7 - Obstacle Avoidance", "Sensor Scan Seconds", 0.3f, new ConfigDescription("Interval between live shore/obstacle sensor passes. Higher values reduce CPU use; 0.30 is the recommended low-lag default.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.15f, 1f), new object[0]));
		StuckDetection = ((BaseUnityPlugin)this).Config.Bind<bool>("8 - Recovery", "Stuck Detection", true, "Detect when the boat is making almost no progress.");
		StuckCheckSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Recovery", "Stuck Check Seconds", 7f, new ConfigDescription("Time between progress checks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(3f, 20f), new object[0]));
		StuckMinProgress = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Recovery", "Minimum Progress", 2.5f, new ConfigDescription("Minimum movement in meters during a stuck-check interval.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), new object[0]));
		ReplanWhenStuck = ((BaseUnityPlugin)this).Config.Bind<bool>("8 - Recovery", "Replan When Stuck", true, "Recalculate the water route when stuck.");
		Hud = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - HUD", "HUD Enabled", true, "Show FSDS navigation status while at the helm.");
		HudScale = ((BaseUnityPlugin)this).Config.Bind<float>("9 - HUD", "HUD Scale", 1f, new ConfigDescription("FSDS HUD scale.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.6f, 1.6f), new object[0]));
		ShipAwareClearance = ((BaseUnityPlugin)this).Config.Bind<bool>("6 - Routing", "Ship Aware Clearance", true, "Automatically increases shoreline/route clearance for larger ships.");
		SmallShipExtraClearance = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Small Ship Extra Clearance", 2f, new ConfigDescription("Extra meters added for raft/karve-sized vessels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 15f), new object[0]));
		LongshipExtraClearance = ((BaseUnityPlugin)this).Config.Bind<float>("6 - Routing", "Longship Extra Clearance", 7f, new ConfigDescription("Extra meters added for longship-sized vessels.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 25f), new object[0]));
		TurnAnticipation = ((BaseUnityPlugin)this).Config.Bind<bool>("4 - Steering", "Turn Anticipation", true, "Blend toward the following waypoint before reaching the current one for smoother turns.");
		TurnLookaheadBlend = ((BaseUnityPlugin)this).Config.Bind<float>("4 - Steering", "Turn Lookahead Blend", 0.45f, new ConfigDescription("How strongly FSDS blends toward the next waypoint near a turn.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.9f), new object[0]));
		AdvancedStuckRecovery = ((BaseUnityPlugin)this).Config.Bind<bool>("8 - Recovery", "Advanced Stuck Recovery", true, "When stuck: stop, reverse briefly, steer away, then recalculate the route.");
		RecoveryReverseSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Recovery", "Recovery Reverse Seconds", 2f, new ConfigDescription("How long FSDS reverses when recovering from being stuck.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), new object[0]));
		RecoveryTurnSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("8 - Recovery", "Recovery Turn Seconds", 2.5f, new ConfigDescription("How long FSDS holds an escape turn before replanning.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 8f), new object[0]));
		RouteVisualization = ((BaseUnityPlugin)this).Config.Bind<bool>("9 - HUD", "Show Route On Map", true, "Show temporary FSDS route markers on the map while autopilot is active.");
		RouteMarkerSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("9 - HUD", "Route Marker Spacing", 1f, new ConfigDescription("Place every Nth route waypoint as a temporary map marker.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 8f), new object[0]));
		DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("10 - Debug", "Debug Logging", false, "Write detailed route/autopilot information to the BepInEx log.");
		MigrateOldDefaults();
	}

	private void MigrateOldDefaults()
	{
		try
		{
			string a = (PinName.Value ?? "").Trim();
			if (string.Equals(a, "★ FSDS", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "* FSDS", StringComparison.OrdinalIgnoreCase))
			{
				PinName.Value = "GO";
				((BaseUnityPlugin)this).Config.Save();
				((BaseUnityPlugin)this).Logger.LogInfo((object)"Migrated old FSDS destination pin name to GO.");
			}
			if (Mathf.Abs(ObstacleLookahead.Value - 45f) < 0.01f)
			{
				ObstacleLookahead.Value = 65f;
			}
			if (Mathf.Abs(ObstacleRadius.Value - 1.8f) < 0.01f)
			{
				ObstacleRadius.Value = 2.6f;
			}
			if (Mathf.Abs(AvoidanceTurnDegrees.Value - 38f) < 0.01f)
			{
				AvoidanceTurnDegrees.Value = 46f;
			}
			if (MaxRouteNodes.Value == 16000)
			{
				MaxRouteNodes.Value = 9000;
			}
			((BaseUnityPlugin)this).Config.Save();
		}
		catch (Exception ex)
		{
			((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not migrate old FSDS config defaults: " + ex.Message));
		}
	}

	private void Update()
	{
		//IL_0086: Unknown result type (might be due to invalid IL or missing references)
		//IL_008b: 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_0184: Unknown result type (might be due to invalid IL or missing references)
		if (!Enabled.Value)
		{
			if (Active)
			{
				Stop("disabled", stopThrottle: true);
			}
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		Ship val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
		if ((Object)(object)val != (Object)(object)Helm)
		{
			Helm = val;
			Rudder.Reset();
			if (Active && (Object)(object)val == (Object)null)
			{
				Stop("helm released", stopThrottle: false);
			}
		}
		if ((Object)(object)val == (Object)null || Typing())
		{
			return;
		}
		KeyboardShortcut value = ToggleKey.Value;
		if (((KeyboardShortcut)(ref value)).IsDown())
		{
			if (Active)
			{
				Stop("manual", stopThrottle: true);
			}
			else
			{
				StartAutopilot(val);
			}
		}
		else
		{
			if (!Active)
			{
				return;
			}
			if (ManualCancel.Value && (Input.GetKeyDown((KeyCode)97) || Input.GetKeyDown((KeyCode)100) || Input.GetKeyDown((KeyCode)276) || Input.GetKeyDown((KeyCode)275)))
			{
				Stop("manual steering", stopThrottle: false);
				return;
			}
			if (AutoThrottle.Value && ManualThrottleCancel.Value && (Input.GetKeyDown((KeyCode)119) || Input.GetKeyDown((KeyCode)115) || Input.GetKeyDown((KeyCode)273) || Input.GetKeyDown((KeyCode)274)))
			{
				Stop("manual throttle", stopThrottle: false);
				return;
			}
			if (_recoveryPhase != RecoveryPhase.None)
			{
				UpdateRecovery(val);
				return;
			}
			RefreshDestination(val);
			AdvanceRoute(val);
			if (!HasDestination)
			{
				Stop("destination lost", stopThrottle: true);
				return;
			}
			float num = DistanceXZ(((Component)val).transform.position, RouteEndpoint);
			if (num <= ArrivalRadius.Value)
			{
				SetThrottleImmediate(val, 0);
				if (DeletePinOnArrival.Value)
				{
					DeleteDestinationPin();
				}
				Stop("arrived", stopThrottle: false);
			}
			else
			{
				UpdateObstacleAvoidance(val);
				UpdateThrottle(val);
				UpdateStuckDetection(val);
			}
		}
	}

	private void StartAutopilot(Ship ship)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0038: 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_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_0108: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		if (!FindPin(((Component)ship).transform.position, out var pos, out var label))
		{
			Notify("FSDS: no map pin named \"" + PinName.Value + "\"");
			return;
		}
		Destination = pos;
		DestinationName = label;
		HasDestination = true;
		Helm = ship;
		ClearRoutePins();
		if (!BuildRoute(((Component)ship).transform.position, Destination))
		{
			if (!FallbackDirect.Value)
			{
				Notify("FSDS: no safe water route found");
				HasDestination = false;
				return;
			}
			Route.Clear();
			Route.Add(Destination);
			RouteIndex = 0;
			RouteEndpoint = Destination;
			RefreshRoutePins();
		}
		Active = true;
		NavState = "SAILING";
		_nextDestinationRefresh = 0f;
		_nextThrottleStep = 0f;
		_nextObstacleScan = 0f;
		_nextStuckCheck = Time.unscaledTime + StuckCheckSeconds.Value;
		_lastStuckPosition = ((Component)ship).transform.position;
		Rudder.Reset();
		UpdateSteeringTarget(ship);
		Notify("FSDS AUTOPILOT ENGAGED");
		DebugLog("Route waypoints: " + Route.Count);
	}

	private void RefreshDestination(Ship ship)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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_0055: 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)
		if (!RefreshPin.Value || Time.unscaledTime < _nextDestinationRefresh)
		{
			return;
		}
		_nextDestinationRefresh = Time.unscaledTime + RefreshSeconds.Value;
		if (FindPin(((Component)ship).transform.position, out var pos, out var label))
		{
			float num = DistanceXZ(Destination, pos);
			Destination = pos;
			DestinationName = label;
			if (num > Mathf.Max(10f, RouteGridSize.Value * 0.5f))
			{
				DebugLog("Destination moved; recalculating route.");
				BuildRoute(((Component)ship).transform.position, Destination);
			}
		}
	}

	private void AdvanceRoute(Ship ship)
	{
		//IL_000c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//IL_001b: 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_005f: Unknown result type (might be due to invalid IL or missing references)
		if (Route.Count == 0)
		{
			SteeringTarget = Destination;
			RouteEndpoint = Destination;
			return;
		}
		while (RouteIndex < Route.Count - 1 && DistanceXZ(((Component)ship).transform.position, Route[RouteIndex]) <= WaypointRadius.Value)
		{
			RouteIndex++;
			Rudder.Reset();
		}
		UpdateSteeringTarget(ship);
	}

	private void UpdateSteeringTarget(Ship ship)
	{
		//IL_0030: Unknown result type (might be due to invalid IL or missing references)
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: 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_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_0084: Unknown result type (might be due to invalid IL or missing references)
		//IL_0089: Unknown result type (might be due to invalid IL or missing references)
		//IL_0090: 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_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
		Vector3 steeringTarget = ((Route.Count > 0) ? Route[Mathf.Clamp(RouteIndex, 0, Route.Count - 1)] : Destination);
		if (TurnAnticipation.Value && Route.Count > 1 && RouteIndex < Route.Count - 1)
		{
			Vector3 val = Route[RouteIndex];
			Vector3 val2 = Route[RouteIndex + 1];
			float num = DistanceXZ(((Component)ship).transform.position, val);
			float num2 = Mathf.Max(WaypointRadius.Value * 2.5f, 40f);
			if (num < num2)
			{
				float num3 = 1f - Mathf.Clamp01(num / num2);
				steeringTarget = Vector3.Lerp(val, val2, num3 * TurnLookaheadBlend.Value);
			}
		}
		SteeringTarget = steeringTarget;
		if (!AvoidingObstacle)
		{
			NavState = (RoutePlanning.Value ? "SAILING" : "DIRECT");
		}
	}

	private void UpdateObstacleAvoidance(Ship ship)
	{
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0055: Unknown result type (might be due to invalid IL or missing references)
		//IL_007d: 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_0356: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: 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_0386: Unknown result type (might be due to invalid IL or missing references)
		//IL_0387: Unknown result type (might be due to invalid IL or missing references)
		//IL_01eb: Unknown result type (might be due to invalid IL or missing references)
		//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_0139: Unknown result type (might be due to invalid IL or missing references)
		//IL_013e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_014d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0152: 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)
		//IL_015a: Unknown result type (might be due to invalid IL or missing references)
		//IL_015f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02d2: 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_021f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0224: Unknown result type (might be due to invalid IL or missing references)
		//IL_0226: Unknown result type (might be due to invalid IL or missing references)
		//IL_022b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0233: Unknown result type (might be due to invalid IL or missing references)
		//IL_0238: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0241: Unknown result type (might be due to invalid IL or missing references)
		//IL_0246: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fc: Unknown result type (might be due to invalid IL or missing references)
		//IL_03fe: Unknown result type (might be due to invalid IL or missing references)
		//IL_0403: Unknown result type (might be due to invalid IL or missing references)
		//IL_040b: 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_0413: Unknown result type (might be due to invalid IL or missing references)
		//IL_0418: 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_0306: Unknown result type (might be due to invalid IL or missing references)
		//IL_030b: Unknown result type (might be due to invalid IL or missing references)
		//IL_030d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0312: Unknown result type (might be due to invalid IL or missing references)
		//IL_031a: Unknown result type (might be due to invalid IL or missing references)
		//IL_031f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0323: Unknown result type (might be due to invalid IL or missing references)
		//IL_0328: Unknown result type (might be due to invalid IL or missing references)
		//IL_032d: Unknown result type (might be due to invalid IL or missing references)
		if (!ObstacleAvoidance.Value)
		{
			AvoidingObstacle = false;
			UpdateSteeringTarget(ship);
		}
		else
		{
			if (Time.unscaledTime < _nextObstacleScan)
			{
				return;
			}
			_nextObstacleScan = Time.unscaledTime + Mathf.Max(0.15f, SensorScanSeconds.Value);
			Vector3 steeringTarget = ((Route.Count > 0) ? Route[Mathf.Clamp(RouteIndex, 0, Route.Count - 1)] : Destination);
			float value = ObstacleLookahead.Value;
			if (LiveShoreAvoidance.Value)
			{
				float clearance = SafeShoreDistance.Value + GetShipExtraClearance(ship);
				float value2 = ShoreLookahead.Value;
				if (!IsHeadingShoreSafe(ship, 0f, value2, clearance))
				{
					float value3 = ShoreAvoidanceTurnDegrees.Value;
					float num = ShoreHeadingScore(ship, 0f - value3, value2, clearance);
					float num2 = ShoreHeadingScore(ship, value3, value2, clearance);
					float num3 = ((num >= num2) ? (0f - value3) : value3);
					Vector3 forward = ((Component)ship).transform.forward;
					forward.y = 0f;
					if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f)
					{
						((Vector3)(ref forward)).Normalize();
						Vector3 val = Quaternion.Euler(0f, num3, 0f) * forward;
						SteeringTarget = ((Component)ship).transform.position + val * value2;
						AvoidingObstacle = true;
						NavState = "AVOIDING SHORE";
						return;
					}
				}
			}
			if (ScanAllSolidLayers.Value)
			{
				float value4 = LargeObstacleLookahead.Value;
				float num4 = BroadObstacleClearDistance(ship, 0f, value4);
				if (num4 < value4 * 0.92f)
				{
					float value5 = LargeObstacleTurnDegrees.Value;
					float num5 = BroadObstacleClearDistance(ship, 0f - value5, value4);
					float num6 = BroadObstacleClearDistance(ship, value5, value4);
					float num7 = ((num5 >= num6) ? (0f - value5) : value5);
					Vector3 forward2 = ((Component)ship).transform.forward;
					forward2.y = 0f;
					if (((Vector3)(ref forward2)).sqrMagnitude > 0.0001f)
					{
						((Vector3)(ref forward2)).Normalize();
						Vector3 val2 = Quaternion.Euler(0f, num7, 0f) * forward2;
						SteeringTarget = ((Component)ship).transform.position + val2 * value4;
						AvoidingObstacle = true;
						NavState = "AVOIDING OBSTACLE";
						return;
					}
				}
			}
			if (LeviathanAvoidance.Value)
			{
				float value6 = LeviathanLookahead.Value;
				float num8 = LeviathanClearDistance(ship, 0f, value6);
				if (num8 < value6 * 0.92f)
				{
					float value7 = LeviathanTurnDegrees.Value;
					float num9 = LeviathanClearDistance(ship, 0f - value7, value6);
					float num10 = LeviathanClearDistance(ship, value7, value6);
					float num11 = ((num9 >= num10) ? (0f - value7) : value7);
					Vector3 forward3 = ((Component)ship).transform.forward;
					forward3.y = 0f;
					if (((Vector3)(ref forward3)).sqrMagnitude > 0.0001f)
					{
						((Vector3)(ref forward3)).Normalize();
						Vector3 val3 = Quaternion.Euler(0f, num11, 0f) * forward3;
						SteeringTarget = ((Component)ship).transform.position + val3 * value6;
						AvoidingObstacle = true;
						NavState = "AVOIDING LEVIATHAN";
						return;
					}
				}
			}
			if (ScanAllSolidLayers.Value)
			{
				AvoidingObstacle = false;
				SteeringTarget = steeringTarget;
				NavState = "SAILING";
				return;
			}
			float num12 = ClearDistance(ship, 0f, value);
			if (num12 > value * 0.78f)
			{
				AvoidingObstacle = false;
				SteeringTarget = steeringTarget;
				NavState = "SAILING";
				return;
			}
			float value8 = AvoidanceTurnDegrees.Value;
			float num13 = ClearDistance(ship, 0f - value8, value);
			float num14 = ClearDistance(ship, value8, value);
			float num15 = ((num13 >= num14) ? (0f - value8) : value8);
			Vector3 forward4 = ((Component)ship).transform.forward;
			forward4.y = 0f;
			((Vector3)(ref forward4)).Normalize();
			Vector3 val4 = Quaternion.Euler(0f, num15, 0f) * forward4;
			SteeringTarget = ((Component)ship).transform.position + val4 * value;
			AvoidingObstacle = true;
			NavState = "AVOIDING";
		}
	}

	private bool IsHeadingShoreSafe(Ship ship, float yawOffset, float lookahead, float clearance)
	{
		return ShoreHeadingScore(ship, yawOffset, lookahead, clearance) >= 0.999f;
	}

	private float ShoreHeadingScore(Ship ship, float yawOffset, float lookahead, float clearance)
	{
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_0059: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ship == (Object)null || WorldGenerator.instance == null)
		{
			return 1f;
		}
		Vector3 forward = ((Component)ship).transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			return 1f;
		}
		((Vector3)(ref forward)).Normalize();
		Vector3 val = Quaternion.Euler(0f, yawOffset, 0f) * forward;
		float waterLevel = GetWaterLevel();
		float value = MinWaterDepth.Value;
		int num = 0;
		int num2 = 0;
		float num3 = Mathf.Clamp(RouteGridSize.Value * 0.35f, 12f, 20f);
		for (float num4 = 12f; num4 <= lookahead; num4 += num3)
		{
			Vector3 val2 = ((Component)ship).transform.position + val * num4;
			if (IsWorldPointClearOfShore(val2.x, val2.z, clearance, waterLevel, value))
			{
				num++;
			}
			num2++;
		}
		if (num2 <= 0)
		{
			return 1f;
		}
		return (float)num / (float)num2;
	}

	private bool IsWorldPointClearOfShore(float x, float z, float clearance, float water, float minimumDepth)
	{
		WorldGenerator instance = WorldGenerator.instance;
		if (instance == null)
		{
			return true;
		}
		float num = water - minimumDepth;
		if (instance.GetHeight(x, z) > num)
		{
			return false;
		}
		if (clearance <= 0.01f)
		{
			return true;
		}
		for (int i = 1; i <= 2; i++)
		{
			float num2 = clearance * ((float)i * 0.5f);
			for (int j = 0; j < 8; j++)
			{
				float num3 = (float)Math.PI * 2f * (float)j / 8f;
				float num4 = x + Mathf.Cos(num3) * num2;
				float num5 = z + Mathf.Sin(num3) * num2;
				if (instance.GetHeight(num4, num5) > num)
				{
					return false;
				}
			}
		}
		return true;
	}

	private float BroadObstacleClearDistance(Ship ship, float yawOffset, float maxDistance)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//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_00de: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: 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_00f0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fd: Unknown result type (might be due to invalid IL or missing references)
		//IL_0102: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_0109: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0130: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ship == (Object)null)
		{
			return maxDistance;
		}
		Vector3 forward = ((Component)ship).transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			return maxDistance;
		}
		((Vector3)(ref forward)).Normalize();
		Vector3 val = Quaternion.Euler(0f, yawOffset, 0f) * forward;
		string text = (((Object)(object)((Component)ship).gameObject != (Object)null) ? ((Object)((Component)ship).gameObject).name.ToLowerInvariant() : "");
		bool flag = text.Contains("longship") || text.Contains("vikingship") || text.Contains("drakkar");
		float num = (flag ? 10f : 5.5f);
		float num2 = LargeObstacleScanRadius.Value + (flag ? 0.75f : 0f);
		float num3 = maxDistance;
		for (int i = 0; i < BroadScanHeights.Length; i++)
		{
			Vector3 val2 = ((Component)ship).transform.position + forward * num + Vector3.up * BroadScanHeights[i];
			int num4 = Physics.SphereCastNonAlloc(val2, num2, val, _sensorHits, maxDistance, -1, (QueryTriggerInteraction)1);
			for (int j = 0; j < num4; j++)
			{
				RaycastHit val3 = _sensorHits[j];
				Collider collider = ((RaycastHit)(ref val3)).collider;
				if (IsRelevantBroadObstacle(ship, collider) && ((RaycastHit)(ref val3)).distance < num3)
				{
					num3 = ((RaycastHit)(ref val3)).distance;
				}
			}
		}
		return num3;
	}

	private bool IsRelevantBroadObstacle(Ship ship, Collider collider)
	{
		//IL_0071: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0085: 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 ((Object)(object)collider == (Object)null || collider.isTrigger)
		{
			return false;
		}
		Transform transform = ((Component)collider).transform;
		if ((Object)(object)transform == (Object)null)
		{
			return false;
		}
		if ((Object)(object)transform == (Object)(object)((Component)ship).transform || transform.IsChildOf(((Component)ship).transform))
		{
			return false;
		}
		Player localPlayer = Player.m_localPlayer;
		if ((Object)(object)localPlayer != (Object)null && ((Object)(object)transform == (Object)(object)((Component)localPlayer).transform || transform.IsChildOf(((Component)localPlayer).transform)))
		{
			return false;
		}
		try
		{
			Bounds bounds = collider.bounds;
			float num = Mathf.Max(((Bounds)(ref bounds)).size.x, Mathf.Max(((Bounds)(ref bounds)).size.y, ((Bounds)(ref bounds)).size.z));
			if (num < IgnoreTinyColliderSize.Value)
			{
				return false;
			}
		}
		catch
		{
		}
		return true;
	}

	private float LeviathanClearDistance(Ship ship, float yawOffset, float maxDistance)
	{
		//IL_0011: Unknown result type (might be due to invalid IL or missing references)
		//IL_0016: Unknown result type (might be due to invalid IL or missing references)
		//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_00b1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cc: 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_00d6: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ship == (Object)null)
		{
			return maxDistance;
		}
		Vector3 forward = ((Component)ship).transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			return maxDistance;
		}
		((Vector3)(ref forward)).Normalize();
		Vector3 val = Quaternion.Euler(0f, yawOffset, 0f) * forward;
		string text = (((Object)(object)((Component)ship).gameObject != (Object)null) ? ((Object)((Component)ship).gameObject).name.ToLowerInvariant() : "");
		float num = ((text.Contains("longship") || text.Contains("vikingship") || text.Contains("drakkar")) ? 9f : 5f);
		Vector3 val2 = ((Component)ship).transform.position + forward * num + Vector3.up * 1.8f;
		int num2 = Physics.SphereCastNonAlloc(val2, LeviathanScanRadius.Value, val, _sensorHits, maxDistance, -1, (QueryTriggerInteraction)2);
		float num3 = maxDistance;
		for (int i = 0; i < num2; i++)
		{
			RaycastHit val3 = _sensorHits[i];
			Collider collider = ((RaycastHit)(ref val3)).collider;
			if ((Object)(object)collider == (Object)null)
			{
				continue;
			}
			Transform transform = ((Component)collider).transform;
			if (!((Object)(object)transform == (Object)null) && !((Object)(object)transform == (Object)(object)((Component)ship).transform) && !transform.IsChildOf(((Component)ship).transform))
			{
				Player localPlayer = Player.m_localPlayer;
				if ((!((Object)(object)localPlayer != (Object)null) || (!((Object)(object)transform == (Object)(object)((Component)localPlayer).transform) && !transform.IsChildOf(((Component)localPlayer).transform))) && IsLeviathanCollider(collider) && ((RaycastHit)(ref val3)).distance < num3)
				{
					num3 = ((RaycastHit)(ref val3)).distance;
				}
			}
		}
		return num3;
	}

	private bool IsLeviathanCollider(Collider collider)
	{
		if ((Object)(object)collider == (Object)null)
		{
			return false;
		}
		try
		{
			Transform val = ((Component)collider).transform;
			int num = 0;
			while ((Object)(object)val != (Object)null && num < 12)
			{
				string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : ((Object)val).name);
				if (!string.IsNullOrEmpty(text) && (text.IndexOf("leviathan", StringComparison.OrdinalIgnoreCase) >= 0 || text.IndexOf("kraken", StringComparison.OrdinalIgnoreCase) >= 0))
				{
					return true;
				}
				if ((Object)(object)((Component)val).gameObject != (Object)null && (Object)(object)((Component)val).gameObject.GetComponent("Leviathan") != (Object)null)
				{
					return true;
				}
				val = val.parent;
				num++;
			}
		}
		catch
		{
		}
		return false;
	}

	private float ClearDistance(Ship ship, float yawOffset, float maxDistance)
	{
		//IL_0006: 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)
		//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_0040: Unknown result type (might be due to invalid IL or missing references)
		//IL_0045: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0051: Unknown result type (might be due to invalid IL or missing references)
		//IL_0057: 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_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_0075: Unknown result type (might be due to invalid IL or missing references)
		//IL_0076: 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_00ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		Vector3 forward = ((Component)ship).transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			return maxDistance;
		}
		((Vector3)(ref forward)).Normalize();
		Vector3 val = Quaternion.Euler(0f, yawOffset, 0f) * forward;
		Vector3 val2 = ((Component)ship).transform.position + forward * 4f + Vector3.up * 1.4f;
		int num = Physics.SphereCastNonAlloc(val2, ObstacleRadius.Value, val, _sensorHits, maxDistance, _solidMask, (QueryTriggerInteraction)1);
		float num2 = maxDistance;
		for (int i = 0; i < num; i++)
		{
			RaycastHit val3 = _sensorHits[i];
			Collider collider = ((RaycastHit)(ref val3)).collider;
			if ((Object)(object)collider == (Object)null)
			{
				continue;
			}
			Transform transform = ((Component)collider).transform;
			if (!((Object)(object)transform == (Object)null) && !((Object)(object)transform == (Object)(object)((Component)ship).transform) && !transform.IsChildOf(((Component)ship).transform))
			{
				Player localPlayer = Player.m_localPlayer;
				if ((!((Object)(object)localPlayer != (Object)null) || (!((Object)(object)transform == (Object)(object)((Component)localPlayer).transform) && !transform.IsChildOf(((Component)localPlayer).transform))) && ((RaycastHit)(ref val3)).distance < num2)
				{
					num2 = ((RaycastHit)(ref val3)).distance;
				}
			}
		}
		return num2;
	}

	private void UpdateThrottle(Ship ship)
	{
		if (AutoThrottle.Value && !(Time.unscaledTime < _nextThrottleStep))
		{
			_nextThrottleStep = Time.unscaledTime + ThrottleStepSeconds.Value;
			int desired = DesiredSpeedSetting(ship);
			StepThrottle(ship, desired);
		}
	}

	private int DesiredSpeedSetting(Ship ship)
	{
		//IL_0006: 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)
		//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)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: 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_0083: Unknown result type (might be due to invalid IL or missing references)
		//IL_008a: Unknown result type (might be due to invalid IL or missing references)
		//IL_008f: Unknown result type (might be due to invalid IL or missing references)
		float num = DistanceXZ(((Component)ship).transform.position, RouteEndpoint);
		if (num <= ArrivalRadius.Value)
		{
			return 0;
		}
		Vector3 val = SteeringTarget - ((Component)ship).transform.position;
		val.y = 0f;
		Vector3 forward = ((Component)ship).transform.forward;
		forward.y = 0f;
		float num2 = 0f;
		if (((Vector3)(ref val)).sqrMagnitude > 0.0001f && ((Vector3)(ref forward)).sqrMagnitude > 0.0001f)
		{
			num2 = Mathf.Abs(Vector3.SignedAngle(((Vector3)(ref forward)).normalized, ((Vector3)(ref val)).normalized, Vector3.up));
		}
		if (AvoidingObstacle || num2 >= SharpTurnDegrees.Value)
		{
			return 2;
		}
		if (num <= SlowdownDistance.Value)
		{
			return 2;
		}
		if (num2 >= MediumTurnDegrees.Value)
		{
			return 3;
		}
		if (WindAwareThrottle.Value)
		{
			try
			{
				if (ship.GetWindAngleFactor() < 0.15f)
				{
					return 2;
				}
			}
			catch
			{
			}
		}
		return 4;
	}

	private static void StepThrottle(Ship ship, int desired)
	{
		int speedSetting = GetSpeedSetting(ship);
		if (speedSetting == desired)
		{
			return;
		}
		switch (desired)
		{
		case 0:
			if (speedSetting == 1)
			{
				InvokeShipMethod(ShipForward, ship);
			}
			else
			{
				InvokeShipMethod(ShipBackward, ship);
			}
			return;
		case 1:
			InvokeShipMethod(ShipBackward, ship);
			return;
		}
		if (speedSetting == 1)
		{
			InvokeShipMethod(ShipForward, ship);
		}
		else if (speedSetting < desired)
		{
			InvokeShipMethod(ShipForward, ship);
		}
		else
		{
			InvokeShipMethod(ShipBackward, ship);
		}
	}

	private static void SetThrottleImmediate(Ship ship, int desired)
	{
		for (int i = 0; i < 6; i++)
		{
			int speedSetting = GetSpeedSetting(ship);
			if (speedSetting == desired)
			{
				break;
			}
			StepThrottle(ship, desired);
		}
	}

	private static int GetSpeedSetting(Ship ship)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			return Convert.ToInt32(ship.GetSpeedSetting());
		}
		catch
		{
			return 0;
		}
	}

	private static void InvokeShipMethod(MethodInfo method, Ship ship)
	{
		try
		{
			if (method != null && (Object)(object)ship != (Object)null)
			{
				method.Invoke(ship, null);
			}
		}
		catch
		{
		}
	}

	private void UpdateStuckDetection(Ship ship)
	{
		//IL_001b: 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_0038: 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_00c1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
		if (!StuckDetection.Value || Time.unscaledTime < _nextStuckCheck)
		{
			return;
		}
		float num = DistanceXZ(_lastStuckPosition, ((Component)ship).transform.position);
		_lastStuckPosition = ((Component)ship).transform.position;
		_nextStuckCheck = Time.unscaledTime + StuckCheckSeconds.Value;
		if (num >= StuckMinProgress.Value || GetSpeedSetting(ship) == 0)
		{
			return;
		}
		DebugLog("Stuck detected. Progress=" + num.ToString("0.0") + "m");
		if (AdvancedStuckRecovery.Value)
		{
			BeginRecovery(ship);
			return;
		}
		NavState = "REPLANNING";
		if (ReplanWhenStuck.Value)
		{
			BuildRoute(((Component)ship).transform.position, Destination);
			Rudder.Reset();
		}
	}

	private void BeginRecovery(Ship ship)
	{
		NavState = "RECOVERY";
		_recoveryPhase = RecoveryPhase.Stop;
		_recoveryUntil = Time.unscaledTime + 0.5f;
		float num = ClearDistance(ship, -45f, 30f);
		float num2 = ClearDistance(ship, 45f, 30f);
		_recoveryTurnSign = ((num >= num2) ? (-1f) : 1f);
		SetThrottleImmediate(ship, 0);
		Rudder.Reset();
		DebugLog("Advanced recovery started. Escape turn=" + ((_recoveryTurnSign < 0f) ? "left" : "right"));
	}

	private void UpdateRecovery(Ship ship)
	{
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_0077: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_00af: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b5: 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_00c6: 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_00d1: 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_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0170: Unknown result type (might be due to invalid IL or missing references)
		//IL_0171: Unknown result type (might be due to invalid IL or missing references)
		//IL_0176: Unknown result type (might be due to invalid IL or missing references)
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0188: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Unknown result type (might be due to invalid IL or missing references)
		//IL_020d: 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_01d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01de: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)ship == (Object)null)
		{
			_recoveryPhase = RecoveryPhase.None;
		}
		else if (_recoveryPhase == RecoveryPhase.Stop)
		{
			NavState = "RECOVERY STOP";
			if (Time.unscaledTime >= _recoveryUntil)
			{
				_recoveryPhase = RecoveryPhase.Reverse;
				_recoveryUntil = Time.unscaledTime + RecoveryReverseSeconds.Value;
				SetThrottleImmediate(ship, 1);
			}
		}
		else if (_recoveryPhase == RecoveryPhase.Reverse)
		{
			NavState = "RECOVERY REVERSE";
			Vector3 forward = ((Component)ship).transform.forward;
			forward.y = 0f;
			if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f)
			{
				((Vector3)(ref forward)).Normalize();
				Vector3 val = Quaternion.Euler(0f, _recoveryTurnSign * 35f, 0f) * -forward;
				SteeringTarget = ((Component)ship).transform.position + val * 30f;
			}
			if (Time.unscaledTime >= _recoveryUntil)
			{
				_recoveryPhase = RecoveryPhase.Turn;
				_recoveryUntil = Time.unscaledTime + RecoveryTurnSeconds.Value;
				SetThrottleImmediate(ship, 2);
			}
		}
		else if (_recoveryPhase == RecoveryPhase.Turn)
		{
			NavState = "RECOVERY TURN";
			Vector3 forward2 = ((Component)ship).transform.forward;
			forward2.y = 0f;
			if (((Vector3)(ref forward2)).sqrMagnitude > 0.0001f)
			{
				((Vector3)(ref forward2)).Normalize();
				Vector3 val2 = Quaternion.Euler(0f, _recoveryTurnSign * 65f, 0f) * forward2;
				SteeringTarget = ((Component)ship).transform.position + val2 * 45f;
			}
			if (Time.unscaledTime >= _recoveryUntil)
			{
				_recoveryPhase = RecoveryPhase.Replan;
			}
		}
		else if (_recoveryPhase == RecoveryPhase.Replan)
		{
			NavState = "REPLANNING";
			SetThrottleImmediate(ship, 0);
			if (ReplanWhenStuck.Value)
			{
				BuildRoute(((Component)ship).transform.position, Destination);
			}
			_recoveryPhase = RecoveryPhase.None;
			_nextStuckCheck = Time.unscaledTime + StuckCheckSeconds.Value;
			_lastStuckPosition = ((Component)ship).transform.position;
			Rudder.Reset();
		}
	}

	private bool BuildRoute(Vector3 start, Vector3 destination)
	{
		//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_002e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0033: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_010d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0126: Unknown result type (might be due to invalid IL or missing references)
		Route.Clear();
		RouteIndex = 0;
		AvoidingObstacle = false;
		if (!RoutePlanning.Value)
		{
			Route.Add(destination);
			RouteEndpoint = destination;
			SteeringTarget = destination;
			return true;
		}
		if (WorldGenerator.instance == null || (Object)(object)ZoneSystem.instance == (Object)null)
		{
			DebugLog("WorldGenerator/ZoneSystem unavailable.");
			return false;
		}
		NavState = "ROUTING";
		float shore = SafeShoreDistance.Value + GetShipExtraClearance(Helm);
		WaterPlanner waterPlanner = new WaterPlanner(RouteGridSize.Value, MinWaterDepth.Value, shore, RouteMargin.Value, MaxRouteNodes.Value, GetWaterLevel());
		List<Vector3> list = waterPlanner.Plan(start, destination, SmoothRoute.Value);
		if (list == null || list.Count == 0)
		{
			NavState = "NO ROUTE";
			return false;
		}
		Route.AddRange(list);
		RouteIndex = ((Route.Count > 1) ? 1 : 0);
		RouteEndpoint = Route[Route.Count - 1];
		SteeringTarget = Route[RouteIndex];
		NavState = "SAILING";
		DebugLog("Water route built with " + Route.Count + " waypoint(s). Grid=" + waterPlanner.CellSize.ToString("0") + "m.");
		RefreshRoutePins();
		return true;
	}

	private float GetShipExtraClearance(Ship ship)
	{
		if (!ShipAwareClearance.Value || (Object)(object)ship == (Object)null)
		{
			return 0f;
		}
		string text = (((Object)(object)((Component)ship).gameObject != (Object)null) ? ((Object)((Component)ship).gameObject).name.ToLowerInvariant() : "");
		if (text.Contains("longship") || text.Contains("vikingship") || text.Contains("drakkar"))
		{
			return LongshipExtraClearance.Value;
		}
		return SmallShipExtraClearance.Value;
	}

	private void RefreshRoutePins()
	{
		//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
		ClearRoutePins();
		if (!RouteVisualization.Value || (Object)(object)Minimap.instance == (Object)null || Route.Count == 0)
		{
			return;
		}
		try
		{
			MethodInfo methodInfo = null;
			MethodInfo[] methods = typeof(Minimap).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (!(methodInfo2.Name != "AddPin"))
				{
					ParameterInfo[] parameters = methodInfo2.GetParameters();
					if (parameters.Length >= 4 && parameters[0].ParameterType == typeof(Vector3) && parameters[2].ParameterType == typeof(string))
					{
						methodInfo = methodInfo2;
						break;
					}
				}
			}
			if (methodInfo == null)
			{
				DebugLog("Minimap.AddPin was not found for route visualization.");
				return;
			}
			int num = Mathf.Max(1, Mathf.RoundToInt(RouteMarkerSpacing.Value));
			for (int j = 0; j < Route.Count; j += num)
			{
				object[] parameters2 = BuildAddPinArguments(methodInfo, Route[j], "FSDS");
				object obj = methodInfo.Invoke(Minimap.instance, parameters2);
				if (obj != null)
				{
					_routePins.Add(obj);
				}
			}
		}
		catch (Exception ex)
		{
			DebugLog("Could not visualize route: " + ex.Message);
		}
	}

	private object[] BuildAddPinArguments(MethodInfo method, Vector3 pos, string name)
	{
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		ParameterInfo[] parameters = method.GetParameters();
		object[] array = new object[parameters.Length];
		for (int i = 0; i < parameters.Length; i++)
		{
			Type parameterType = parameters[i].ParameterType;
			if (i == 0 && parameterType == typeof(Vector3))
			{
				array[i] = pos;
			}
			else if (parameterType.IsEnum)
			{
				array[i] = Enum.ToObject(parameterType, 0);
			}
			else if (parameterType == typeof(string))
			{
				array[i] = name;
			}
			else if (parameterType == typeof(bool))
			{
				array[i] = false;
			}
			else if (parameterType == typeof(long))
			{
				array[i] = 0L;
			}
			else if (parameterType == typeof(int))
			{
				array[i] = 0;
			}
			else if (parameterType == typeof(float))
			{
				array[i] = 0f;
			}
			else
			{
				array[i] = null;
			}
		}
		return array;
	}

	private void ClearRoutePins()
	{
		if (_routePins.Count == 0 || (Object)(object)Minimap.instance == (Object)null)
		{
			_routePins.Clear();
			return;
		}
		try
		{
			MethodInfo methodInfo = null;
			MethodInfo[] methods = typeof(Minimap).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo2 in methods)
			{
				if (methodInfo2.Name == "RemovePin" && methodInfo2.GetParameters().Length == 1)
				{
					methodInfo = methodInfo2;
					break;
				}
			}
			if (methodInfo != null)
			{
				for (int j = 0; j < _routePins.Count; j++)
				{
					object obj = _routePins[j];
					if (obj != null)
					{
						try
						{
							methodInfo.Invoke(Minimap.instance, new object[1] { obj });
						}
						catch
						{
						}
					}
				}
			}
		}
		catch
		{
		}
		_routePins.Clear();
	}

	private static float GetWaterLevel()
	{
		try
		{
			if ((Object)(object)ZoneSystem.instance != (Object)null && WaterLevelField != null)
			{
				return Convert.ToSingle(WaterLevelField.GetValue(ZoneSystem.instance));
			}
		}
		catch
		{
		}
		return 30f;
	}

	private void DeleteDestinationPin()
	{
		//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_0105: 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)
		try
		{
			Minimap instance = Minimap.instance;
			if ((Object)(object)instance == (Object)null)
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(Minimap), "m_pins");
			IList list = ((fieldInfo != null) ? (fieldInfo.GetValue(instance) as IList) : null);
			if (list == null)
			{
				return;
			}
			string b = (PinName.Value ?? "").Trim();
			int num = -1;
			float num2 = float.MaxValue;
			for (int i = 0; i < list.Count; i++)
			{
				object obj = list[i];
				if (obj == null)
				{
					continue;
				}
				Type type = obj.GetType();
				FieldInfo fieldInfo2 = AccessTools.Field(type, "m_name");
				FieldInfo fieldInfo3 = AccessTools.Field(type, "m_pos");
				if (fieldInfo2 == null || fieldInfo3 == null)
				{
					continue;
				}
				string text = fieldInfo2.GetValue(obj) as string;
				if (string.Equals((text ?? "").Trim(), b, StringComparison.OrdinalIgnoreCase) && fieldInfo3.GetValue(obj) is Vector3 b2)
				{
					float num3 = DistanceXZ(Destination, b2);
					if (num3 < num2)
					{
						num2 = num3;
						num = i;
					}
				}
			}
			if (num < 0)
			{
				return;
			}
			object obj2 = list[num];
			MethodInfo methodInfo = AccessTools.Method(typeof(Minimap), "RemovePin", new Type[1] { obj2.GetType() }, (Type[])null);
			if (methodInfo == null)
			{
				methodInfo = AccessTools.Method(typeof(Minimap), "RemovePin", (Type[])null, (Type[])null);
			}
			if (methodInfo != null)
			{
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length == 1)
				{
					methodInfo.Invoke(instance, new object[1] { obj2 });
					DebugLog("Destination pin deleted on arrival.");
					return;
				}
			}
			list.RemoveAt(num);
			DebugLog("Destination pin removed from map list on arrival.");
		}
		catch (Exception ex)
		{
			DebugLog("Could not delete destination pin: " + ex.Message);
		}
	}

	private bool FindPin(Vector3 from, out Vector3 pos, out string label)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0112: Unknown result type (might be due to invalid IL or missing references)
		//IL_012d: Unknown result type (might be due to invalid IL or missing references)
		//IL_012f: Unknown result type (might be due to invalid IL or missing references)
		pos = Vector3.zero;
		label = null;
		Minimap instance = Minimap.instance;
		if ((Object)(object)instance == (Object)null)
		{
			return false;
		}
		FieldInfo fieldInfo = AccessTools.Field(typeof(Minimap), "m_pins");
		IEnumerable enumerable = ((fieldInfo != null) ? (fieldInfo.GetValue(instance) as IEnumerable) : null);
		if (enumerable == null)
		{
			return false;
		}
		string b = (PinName.Value ?? "").Trim();
		bool flag = false;
		float num = float.MaxValue;
		foreach (object item in enumerable)
		{
			if (item == null)
			{
				continue;
			}
			Type type = item.GetType();
			FieldInfo fieldInfo2 = AccessTools.Field(type, "m_name");
			FieldInfo fieldInfo3 = AccessTools.Field(type, "m_pos");
			if (fieldInfo2 == null || fieldInfo3 == null)
			{
				continue;
			}
			string text = fieldInfo2.GetValue(item) as string;
			if (string.Equals((text ?? "").Trim(), b, StringComparison.OrdinalIgnoreCase) && fieldInfo3.GetValue(item) is Vector3 val)
			{
				float num2 = DistanceXZ(from, val);
				if (!flag || num2 < num)
				{
					flag = true;
					num = num2;
					pos = val;
					label = text;
				}
			}
		}
		return flag;
	}

	internal static float Steering(Ship ship, Rigidbody body)
	{
		//IL_002a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_003a: Unknown result type (might be due to invalid IL or missing references)
		//IL_003f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0072: Unknown result type (might be due to invalid IL or missing references)
		//IL_009a: Unknown result type (might be due to invalid IL or missing references)
		//IL_009b: Unknown result type (might be due to invalid IL or missing references)
		//IL_009c: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: 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_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		if (!Active || (Object)(object)ship == (Object)null || (Object)(object)ship != (Object)(object)Helm || !HasDestination)
		{
			return 0f;
		}
		Vector3 val = SteeringTarget - ((Component)ship).transform.position;
		val.y = 0f;
		if (((Vector3)(ref val)).sqrMagnitude < 0.0001f)
		{
			return 0f;
		}
		((Vector3)(ref val)).Normalize();
		Vector3 forward = ((Component)ship).transform.forward;
		forward.y = 0f;
		if (((Vector3)(ref forward)).sqrMagnitude < 0.0001f)
		{
			return 0f;
		}
		((Vector3)(ref forward)).Normalize();
		float num = Vector3.SignedAngle(forward, val, Vector3.up);
		float num2 = (((Object)(object)body != (Object)null) ? body.angularVelocity.y : 0f);
		int speedSetting = GetSpeedSetting(ship);
		if (speedSetting == 1)
		{
			num2 = 0f - num2;
			num = 0f - Vector3.SignedAngle(-forward, val, Vector3.up);
			if (Mathf.Abs(num) > 90f)
			{
				num += ((num < 0f) ? 180f : (-180f));
			}
		}
		Rudder.Configure(Kp.Value, Ki.Value, Kd.Value);
		return Rudder.Update(num2 - num / 40f, Time.fixedDeltaTime);
	}

	internal static float Neutral(Ship ship)
	{
		try
		{
			return 0f - Mathf.Clamp(ship.GetRudderValue(), -1f, 1f);
		}
		catch
		{
			return 0f;
		}
	}

	internal static void Stop(string why, bool stopThrottle)
	{
		if (Active)
		{
			if (stopThrottle && (Object)(object)Helm != (Object)null && AutoThrottle != null && AutoThrottle.Value)
			{
				SetThrottleImmediate(Helm, 0);
			}
			Active = false;
			AvoidingObstacle = false;
			NavState = "STANDBY";
			Rudder.Reset();
			if ((Object)(object)I != (Object)null)
			{
				I.ClearRoutePins();
				I.Notify("FSDS OFF - " + why);
			}
		}
	}

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

	private static bool Typing()
	{
		try
		{
			if (Console.IsVisible())
			{
				return true;
			}
		}
		catch
		{
		}
		try
		{
			if (TextInput.IsVisible())
			{
				return true;
			}
		}
		catch
		{
		}
		try
		{
			if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus())
			{
				return true;
			}
		}
		catch
		{
		}
		return false;
	}

	private void Notify(string text)
	{
		((BaseUnityPlugin)this).Logger.LogInfo((object)text);
		try
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer == (Object)null)
			{
				return;
			}
			MethodInfo[] methods = typeof(Character).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			foreach (MethodInfo methodInfo in methods)
			{
				if (methodInfo.Name != "Message")
				{
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length < 2 || parameters[1].ParameterType != typeof(string))
				{
					continue;
				}
				object[] array = new object[parameters.Length];
				for (int j = 0; j < parameters.Length; j++)
				{
					Type parameterType = parameters[j].ParameterType;
					if (j == 0 && parameterType.IsEnum)
					{
						array[j] = Enum.ToObject(parameterType, 2);
					}
					else if (j == 1)
					{
						array[j] = text;
					}
					else if (parameterType == typeof(int))
					{
						array[j] = 0;
					}
					else if (parameterType == typeof(bool))
					{
						array[j] = false;
					}
					else
					{
						array[j] = null;
					}
				}
				methodInfo.Invoke(localPlayer, array);
				break;
			}
		}
		catch
		{
		}
	}

	private void DebugLog(string text)
	{
		if (DebugLogging.Value)
		{
			((BaseUnityPlugin)this).Logger.LogInfo((object)("[DEBUG] " + text));
		}
	}

	private void OnGUI()
	{
		//IL_0049: Unknown result type (might be due to invalid IL or missing references)
		//IL_004e: Unknown result type (might be due to invalid IL or missing references)
		//IL_005a: Unknown result type (might be due to invalid IL or missing references)
		//IL_005f: Unknown result type (might be due to invalid IL or missing references)
		//IL_006b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0070: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_0245: Unknown result type (might be due to invalid IL or missing references)
		//IL_024f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0254: Unknown result type (might be due to invalid IL or missing references)
		//IL_0282: Unknown result type (might be due to invalid IL or missing references)
		//IL_010e: 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_0133: Unknown result type (might be due to invalid IL or missing references)
		//IL_0166: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_020a: Unknown result type (might be due to invalid IL or missing references)
		if (Hud == null || !Hud.Value || !Enabled.Value)
		{
			return;
		}
		Player localPlayer = Player.m_localPlayer;
		Ship val = (((Object)(object)localPlayer != (Object)null) ? localPlayer.GetControlledShip() : null);
		if (!((Object)(object)val == (Object)null))
		{
			EnsureStyles();
			Matrix4x4 matrix = GUI.matrix;
			float value = HudScale.Value;
			GUI.matrix = Matrix4x4.TRS(Vector3.zero, Quaternion.identity, new Vector3(value, value, 1f));
			float num = (Active ? 118f : 56f);
			Rect val2 = default(Rect);
			((Rect)(ref val2))..ctor(20f, 150f, 330f, num);
			GUI.Box(val2, GUIContent.none);
			GUI.Label(new Rect(32f, 158f, 300f, 24f), Active ? ("FSDS  •  " + NavState) : "FSDS  •  STANDBY", _title);
			if (Active && HasDestination)
			{
				float meters = DistanceXZ(((Component)val).transform.position, RouteEndpoint);
				GUI.Label(new Rect(32f, 184f, 300f, 20f), "Destination: " + DestinationName, _text);
				GUI.Label(new Rect(32f, 205f, 300f, 20f), "Distance: " + FormatDistance(meters), _text);
				GUI.Label(new Rect(32f, 226f, 300f, 20f), "Waypoint: " + ((Route.Count > 0) ? (RouteIndex + 1 + "/" + Route.Count) : "direct"), _text);
				GUI.Label(new Rect(32f, 247f, 300f, 20f), "Throttle: " + SpeedName(GetSpeedSetting(val)), _text);
			}
			else
			{
				GUI.Label(new Rect(32f, 184f, 300f, 20f), ((object)ToggleKey.Value/*cast due to .constrained prefix*/).ToString() + ": engage  •  Pin: " + PinName.Value, _text);
			}
			GUI.matrix = matrix;
		}
	}

	private void EnsureStyles()
	{
		//IL_0014: Unknown result type (might be due to invalid IL or missing references)
		//IL_001e: Expected O, but got Unknown
		//IL_0042: 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_0061: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		if (_title == null)
		{
			_title = new GUIStyle(GUI.skin.label);
			_title.fontSize = 16;
			_title.fontStyle = (FontStyle)1;
			_title.normal.textColor = Color.white;
			_text = new GUIStyle(GUI.skin.label);
			_text.fontSize = 13;
			_text.normal.textColor = Color.white;
		}
	}

	private static string FormatDistance(float meters)
	{
		if (!(meters >= 1000f))
		{
			return meters.ToString("0") + " m";
		}
		return (meters / 1000f).ToString("0.00") + " km";
	}

	private static string SpeedName(int speed)
	{
		return speed switch
		{
			1 => "Reverse", 
			2 => "Paddle", 
			3 => "Half Sail", 
			4 => "Full Sail", 
			_ => "Stop", 
		};
	}

	private void OnDestroy()
	{
		try
		{
			if (_harmony != null)
			{
				_harmony.UnpatchSelf();
			}
		}
		catch
		{
		}
		ClearRoutePins();
		Active = false;
		Helm = null;
		HasDestination = false;
		Route.Clear();
	}
}
internal static class ShipPatch
{
	private static void Prefix(Ship __instance, ref Vector3 dir, Rigidbody ___m_body)
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		if (Plugin.Active && !((Object)(object)__instance == (Object)null) && !((Object)(object)__instance != (Object)(object)Plugin.Helm))
		{
			bool flag = false;
			try
			{
				int num = Convert.ToInt32(__instance.GetSpeedSetting());
				float speed = __instance.GetSpeed();
				flag = (num == 1 && speed > 0f) || (num != 1 && speed < 0f);
			}
			catch
			{
			}
			dir.x = (flag ? Plugin.Neutral(__instance) : Plugin.Steering(__instance, ___m_body));
		}
	}
}
internal sealed class Pid
{
	private double kp = 3.0;

	private double ki = 0.003;

	private double kd = 6.0;

	private double integral;

	private double last;

	private bool primed;

	internal void Configure(double p, double i, double d)
	{
		kp = p;
		ki = i;
		kd = d;
	}

	internal void Reset()
	{
		integral = 0.0;
		last = 0.0;
		primed = false;
	}

	internal float Update(double error, double dt)
	{
		if (dt <= 0.0)
		{
			return 0f;
		}
		integral = Clamp(integral + error * dt, -1.0, 1.0);
		double num = (primed ? ((error - last) / dt) : 0.0);
		last = error;
		primed = true;
		return (float)Clamp(0.0 - (kp * error + ki * integral + kd * num), -1.0, 1.0);
	}

	private static double Clamp(double value, double min, double max)
	{
		if (value < min)
		{
			return min;
		}
		if (value > max)
		{
			return max;
		}
		return value;
	}
}
internal sealed class WaterPlanner
{
	private float _cell;

	private readonly float _minDepth;

	private readonly float _shore;

	private readonly float _margin;

	private readonly int _maxNodes;

	private readonly float _water;

	private float _originX;

	private float _originZ;

	private int _width;

	private int _height;

	private sbyte[] _passability;

	internal float CellSize => _cell;

	internal WaterPlanner(float cell, float minDepth, float shore, float margin, int maxNodes, float water)
	{
		_cell = Mathf.Max(10f, cell);
		_minDepth = Mathf.Max(0.1f, minDepth);
		_shore = Mathf.Max(0f, shore);
		_margin = Mathf.Max(50f, margin);
		_maxNodes = Mathf.Max(1000, maxNodes);
		_water = water;
	}

	internal List<Vector3> Plan(Vector3 start, Vector3 destination, bool smooth)
	{
		//IL_000a: 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)
		//IL_0078: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Unknown result type (might be due to invalid IL or missing references)
		//IL_0034: Unknown result type (might be due to invalid IL or missing references)
		//IL_0035: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_00b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b1: 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_00cb: 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_010e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0160: Unknown result type (might be due to invalid IL or missing references)
		//IL_014b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0150: Unknown result type (might be due to invalid IL or missing references)
		if (WorldGenerator.instance == null)
		{
			return null;
		}
		BuildBounds(start, destination);
		int num = _width * _height;
		while (num > _maxNodes && _cell < 250f)
		{
			_cell *= 1.2f;
			BuildBounds(start, destination);
			num = _width * _height;
		}
		if (num > _maxNodes)
		{
			return null;
		}
		_passability = new sbyte[num];
		int num2 = FindNearestPassable(WorldToIndex(start), 5);
		int num3 = FindNearestPassable(WorldToIndex(destination), 8);
		if (num2 < 0 || num3 < 0)
		{
			return null;
		}
		Vector3 a = IndexToWorld(num2);
		Vector3 val = IndexToWorld(num3);
		if (LineSafe(a, val))
		{
			List<Vector3> list = new List<Vector3>();
			list.Add(start);
			list.Add(val);
			return list;
		}
		List<int> list2 = AStar(num2, num3);
		if (list2 == null || list2.Count == 0)
		{
			return null;
		}
		List<Vector3> list3 = new List<Vector3>();
		list3.Add(start);
		for (int i = 1; i < list2.Count; i++)
		{
			list3.Add(IndexToWorld(list2[i]));
		}
		if (smooth)
		{
			list3 = Smooth(list3);
		}
		if (list3.Count == 1 || DistanceXZ(list3[list3.Count - 1], val) > 1f)
		{
			list3.Add(val);
		}
		return list3;
	}

	private void BuildBounds(Vector3 start, Vector3 destination)
	{
		float num = Mathf.Min(start.x, destination.x) - _margin;
		float num2 = Mathf.Max(start.x, destination.x) + _margin;
		float num3 = Mathf.Min(start.z, destination.z) - _margin;
		float num4 = Mathf.Max(start.z, destination.z) + _margin;
		_originX = Mathf.Floor(num / _cell) * _cell;
		_originZ = Mathf.Floor(num3 / _cell) * _cell;
		_width = Mathf.CeilToInt((num2 - _originX) / _cell) + 1;
		_height = Mathf.CeilToInt((num4 - _originZ) / _cell) + 1;
	}

	private int WorldToIndex(Vector3 world)
	{
		int num = Mathf.Clamp(Mathf.RoundToInt((world.x - _originX) / _cell), 0, _width - 1);
		int num2 = Mathf.Clamp(Mathf.RoundToInt((world.z - _originZ) / _cell), 0, _height - 1);
		return num2 * _width + num;
	}

	private Vector3 IndexToWorld(int index)
	{
		//IL_0038: Unknown result type (might be due to invalid IL or missing references)
		int num = index % _width;
		int num2 = index / _width;
		return new Vector3(_originX + (float)num * _cell, _water, _originZ + (float)num2 * _cell);
	}

	private int FindNearestPassable(int center, int maxRadius)
	{
		if (center < 0)
		{
			return -1;
		}
		int num = center % _width;
		int num2 = center / _width;
		for (int i = 0; i <= maxRadius; i++)
		{
			for (int j = num2 - i; j <= num2 + i; j++)
			{
				for (int k = num - i; k <= num + i; k++)
				{
					if (k >= 0 && k < _width && j >= 0 && j < _height && (i <= 0 || k == num - i || k == num + i || j == num2 - i || j == num2 + i))
					{
						int num3 = j * _width + k;
						if (IsPassable(num3))
						{
							return num3;
						}
					}
				}
			}
		}
		return -1;
	}

	private bool IsPassable(int index)
	{
		//IL_0024: Unknown result type (might be due to invalid IL or missing references)
		//IL_0029: Unknown result type (might be due to invalid IL or missing references)
		if (index < 0 || index >= _passability.Length)
		{
			return false;
		}
		sbyte b = _passability[index];
		if (b != 0)
		{
			return b > 0;
		}
		Vector3 val = IndexToWorld(index);
		bool flag = IsWaterPoint(val.x, val.z);
		_passability[index] = (sbyte)(flag ? 1 : (-1));
		return flag;
	}

	private bool IsWaterPoint(float x, float z)
	{
		WorldGenerator instance = WorldGenerator.instance;
		if (instance == null)
		{
			return false;
		}
		if (instance.GetHeight(x, z) > _water - _minDepth)
		{
			return false;
		}
		if (_shore <= 0.01f)
		{
			return true;
		}
		float num = _water - _minDepth;
		for (int i = 1; i <= 2; i++)
		{
			float num2 = _shore * ((float)i * 0.5f);
			for (int j = 0; j < 8; j++)
			{
				float num3 = (float)Math.PI * 2f * (float)j / 8f;
				float num4 = x + Mathf.Cos(num3) * num2;
				float num5 = z + Mathf.Sin(num3) * num2;
				if (instance.GetHeight(num4, num5) > num)
				{
					return false;
				}
			}
		}
		return true;
	}

	private List<int> AStar(int start, int goal)
	{
		int num = _width * _height;
		float[] array = new float[num];
		int[] array2 = new int[num];
		bool[] array3 = new bool[num];
		for (int i = 0; i < num; i++)
		{
			array[i] = float.PositiveInfinity;
			array2[i] = -1;
		}
		MinHeap minHeap = new MinHeap();
		array[start] = 0f;
		minHeap.Push(start, Heuristic(start, goal));
		int[] array4 = new int[8] { -1, 0, 1, -1, 1, -1, 0, 1 };
		int[] array5 = new int[8] { -1, -1, -1, 0, 0, 1, 1, 1 };
		int num2 = 0;
		while (minHeap.Count > 0)
		{
			int node = minHeap.Pop().Node;
			if (array3[node])
			{
				continue;
			}
			if (node == goal)
			{
				return Reconstruct(array2, start, goal);
			}
			array3[node] = true;
			num2++;
			if (num2 > _maxNodes)
			{
				break;
			}
			int num3 = node % _width;
			int num4 = node / _width;
			for (int j = 0; j < 8; j++)
			{
				int num5 = num3 + array4[j];
				int num6 = num4 + array5[j];
				if (num5 < 0 || num5 >= _width || num6 < 0 || num6 >= _height)
				{
					continue;
				}
				int num7 = num6 * _width + num5;
				if (array3[num7] || !IsPassable(num7))
				{
					continue;
				}
				bool flag = array4[j] != 0 && array5[j] != 0;
				if (flag)
				{
					int index = num4 * _width + num5;
					int index2 = num6 * _width + num3;
					if (!IsPassable(index) || !IsPassable(index2))
					{
						continue;
					}
				}
				float num8 = (flag ? (_cell * 1.4142135f) : _cell);
				float num9 = array[node] + num8;
				if (!(num9 >= array[num7]))
				{
					array2[num7] = node;
					array[num7] = num9;
					minHeap.Push(num7, num9 + Heuristic(num7, goal));
				}
			}
		}
		return null;
	}

	private float Heuristic(int a, int b)
	{
		int num = a % _width;
		int num2 = a / _width;
		int num3 = b % _width;
		int num4 = b / _width;
		float num5 = num - num3;
		float num6 = num2 - num4;
		return Mathf.Sqrt(num5 * num5 + num6 * num6) * _cell;
	}

	private static List<int> Reconstruct(int[] parent, int start, int goal)
	{
		List<int> list = new List<int>();
		int num = goal;
		list.Add(num);
		int num2 = 0;
		while (num != start && num2 < parent.Length)
		{
			num = parent[num];
			if (num < 0)
			{
				return null;
			}
			list.Add(num);
			num2++;
		}
		list.Reverse();
		return list;
	}

	private List<Vector3> Smooth(List<Vector3> input)
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003e: 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)
		if (input == null || input.Count <= 2)
		{
			return input;
		}
		List<Vector3> list = new List<Vector3>();
		int num = 0;
		list.Add(input[0]);
		while (num < input.Count - 1)
		{
			int num2 = num + 1;
			for (int num3 = input.Count - 1; num3 > num + 1; num3--)
			{
				if (LineSafe(input[num], input[num3]))
				{
					num2 = num3;
					break;
				}
			}
			list.Add(input[num2]);
			num = num2;
		}
		return list;
	}

	private bool LineSafe(Vector3 a, Vector3 b)
	{
		//IL_0000: Unknown result type (might be due to invalid IL or missing references)
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		float num = DistanceXZ(a, b);
		int num2 = Mathf.Max(1, Mathf.CeilToInt(num / Mathf.Clamp(_cell * 0.4f, 12f, 20f)));
		for (int i = 0; i <= num2; i++)
		{
			float num3 = (float)i / (float)num2;
			float x = Mathf.Lerp(a.x, b.x, num3);
			float z = Mathf.Lerp(a.z, b.z, num3);
			if (!IsWaterPoint(x, z))
			{
				return false;
			}
		}
		return true;
	}

	private static float DistanceXZ(Vector3 a, Vector3 b)
	{
		float num = a.x - b.x;
		float num2 = a.z - b.z;
		return Mathf.Sqrt(num * num + num2 * num2);
	}
}
internal struct HeapItem
{
	internal int Node;

	internal float Priority;

	internal HeapItem(int node, float priority)
	{
		Node = node;
		Priority = priority;
	}
}
internal sealed class MinHeap
{
	private readonly List<HeapItem> _items = new List<HeapItem>();

	internal int Count => _items.Count;

	internal void Push(int node, float priority)
	{
		HeapItem item = new HeapItem(node, priority);
		_items.Add(item);
		int num = _items.Count - 1;
		while (num > 0)
		{
			int num2 = (num - 1) / 2;
			if (_items[num2].Priority <= _items[num].Priority)
			{
				break;
			}
			HeapItem value = _items[num2];
			_items[num2] = _items[num];
			_items[num] = value;
			num = num2;
		}
	}

	internal HeapItem Pop()
	{
		HeapItem result = _items[0];
		int index = _items.Count - 1;
		_items[0] = _items[index];
		_items.RemoveAt(index);
		int num = 0;
		while (true)
		{
			int num2 = num * 2 + 1;
			int num3 = num2 + 1;
			if (num2 >= _items.Count)
			{
				break;
			}
			int num4 = num2;
			if (num3 < _items.Count && _items[num3].Priority < _items[num2].Priority)
			{
				num4 = num3;
			}
			if (_items[num].Priority <= _items[num4].Priority)
			{
				break;
			}
			HeapItem value = _items[num];
			_items[num] = _items[num4];
			_items[num4] = value;
			num = num4;
		}
		return result;
	}
}