Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Autosail v0.2.0
Autosail.dll
Decompiled 11 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace NewtAutosail; [BepInPlugin("tonto.autosail", "Autosail", "0.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "tonto.autosail"; internal static ConfigEntry<KeyboardShortcut> ToggleKey; internal static ConfigEntry<bool> RequireFavor; internal static ConfigEntry<bool> InvertRudder; internal static ConfigEntry<bool> DebugLog; internal static ConfigEntry<bool> CloseMap; internal static ConfigEntry<bool> ShowStatus; internal static ConfigEntry<float> CellSize; internal static ConfigEntry<float> MinDepth; internal static ConfigEntry<float> ShoreMargin; internal static ConfigEntry<float> ArrivalRadius; internal static ConfigEntry<float> PinSnapRadius; internal static ConfigEntry<float> SteerRange; internal static ConfigEntry<float> Damping; internal static ConfigEntry<float> AvoidDistance; internal static ConfigEntry<float> ShoreCost; internal static Plugin Instance; internal static ManualLogSource Log; private GUIStyle statusStyle; private void Awake() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Expected O, but got Unknown //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Expected O, but got Unknown //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Expected O, but got Unknown //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Expected O, but got Unknown //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Expected O, but got Unknown //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Controls", "AutopilotKey", new KeyboardShortcut((KeyCode)104, Array.Empty<KeyCode>()), "Map open: hover a pin or any spot and press to sail there (press again with the map open to change destination). Map closed: press to switch autopilot off. You must be at the helm."); CloseMap = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "CloseMapAfterStart", true, "Close the map after choosing a destination so you can watch the ship."); ShowStatus = ((BaseUnityPlugin)this).Config.Bind<bool>("Controls", "ShowStatus", true, "Show distance to go and estimated arrival time on screen while the autopilot is on."); ShoreCost = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "ShoreCost", 2.5f, new ConfigDescription("How strongly routes avoid coastlines. 0 hugs the shore, higher keeps to open water. Raise it for jagged coasts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); RequireFavor = ((BaseUnityPlugin)this).Config.Bind<bool>("Safety", "RequireNjordsFavor", true, "Only start while wearing Njord's Belt or Charm (steady tailwind in the direction the ship faces). Without it the wind decides the speed and the autopilot cannot tack."); CellSize = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "CellSize", 64f, new ConfigDescription("Route grid cell size in metres. Smaller finds narrower channels but plans slower.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(32f, 192f), Array.Empty<object>())); MinDepth = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "MinDepth", 3f, new ConfigDescription("Metres of water required under the route.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 12f), Array.Empty<object>())); ShoreMargin = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "ShoreMargin", 25f, new ConfigDescription("Sideways clearance (m) kept when shortening the route.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 120f), Array.Empty<object>())); ArrivalRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "ArrivalRadius", 45f, new ConfigDescription("Stop when this close (m) to the end of the route.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(15f, 200f), Array.Empty<object>())); PinSnapRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Route", "PinSnapRadius", 300f, new ConfigDescription("A pin this close (m) to the map cursor is used instead of the cursor spot.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1500f), Array.Empty<object>())); SteerRange = ((BaseUnityPlugin)this).Config.Bind<float>("Steering", "SteerRange", 35f, new ConfigDescription("Heading error (degrees) that asks for full rudder.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(10f, 90f), Array.Empty<object>())); Damping = ((BaseUnityPlugin)this).Config.Bind<float>("Steering", "Damping", 0.02f, new ConfigDescription("Counter-steer per degree/second of turn rate. Raise it if the ship swings past its heading.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.1f), Array.Empty<object>())); AvoidDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Steering", "AvoidDistance", 80f, new ConfigDescription("How far ahead (m) it looks for rocks, ships and shores.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(30f, 200f), Array.Empty<object>())); InvertRudder = ((BaseUnityPlugin)this).Config.Bind<bool>("Steering", "InvertRudder", false, "Test option: flip the rudder direction if the ship turns away from its target."); DebugLog = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "Log", false, "Log route and steering details to LogOutput.log."); try { new Harmony("tonto.autosail").PatchAll(typeof(ShipPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Loaded. Steering hook installed. Autopilot key: " + ToggleKey.Value)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Steering hook failed, autopilot cannot steer: " + ex.Message)); } } private void OnGUI() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown if (!ShowStatus.Value) { return; } string text = Pilot.StatusText(); if (text != null) { if (statusStyle == null) { statusStyle = new GUIStyle(GUI.skin.label); statusStyle.fontSize = 18; } Vector2 val = statusStyle.CalcSize(new GUIContent(text)); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor((float)Screen.width / 2f - val.x / 2f, 118f, val.x + 8f, val.y + 4f); Color color = GUI.color; GUI.color = new Color(0f, 0f, 0f, 0.9f); GUI.Label(new Rect(((Rect)(ref val2)).x + 1.5f, ((Rect)(ref val2)).y + 1.5f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height), text, statusStyle); GUI.color = new Color(1f, 0.93f, 0.65f, 1f); GUI.Label(val2, text, statusStyle); GUI.color = color; } } private void Update() { try { Pilot.Tick(); } catch (Exception ex) { Log.LogError((object)("Autosail error: " + ex)); Pilot.Stop("Autosail error, see log"); } } } [HarmonyPatch(typeof(Ship), "ApplyControlls")] internal static class ShipPatch { private static void Prefix(Ship __instance, ref Vector3 __0) { if (!Pilot.Active || (Object)(object)__instance != (Object)(object)Pilot.CurrentShip) { return; } try { Pilot.Steer(__instance, ref __0); } catch (Exception ex) { Plugin.Log.LogError((object)("Autosail steer error: " + ex)); Pilot.Stop("Autosail error, see log"); } } } internal static class Pilot { private class PlanResult { public List<Vector3> Path; public string Error; public Vector3 End; } public class PlanConfig { public Func<float, float, float> Height; public float Water; public float MinDepth; public float Cell; public float Margin; public float ShoreCost; public Vector3 Start; public Vector3 Dest; } private static class Planner { private class Ctx { public PlanConfig C; public Dictionary<long, bool> Nav = new Dictionary<long, bool>(); public Dictionary<long, float> Pen = new Dictionary<long, float>(); } private class Heap { private readonly List<long> keys = new List<long>(); private readonly List<float> pri = new List<float>(); public int Count => keys.Count; public void Push(long k, float p) { keys.Add(k); pri.Add(p); int num = keys.Count - 1; while (num > 0) { int num2 = (num - 1) / 2; if (pri[num2] <= pri[num]) { break; } Swap(num, num2); num = num2; } } public long Pop() { long result = keys[0]; int index = keys.Count - 1; keys[0] = keys[index]; pri[0] = pri[index]; keys.RemoveAt(index); pri.RemoveAt(index); int num = 0; while (true) { int num2 = 2 * num + 1; int num3 = num2 + 1; int num4 = num; if (num2 < keys.Count && pri[num2] < pri[num4]) { num4 = num2; } if (num3 < keys.Count && pri[num3] < pri[num4]) { num4 = num3; } if (num4 == num) { break; } Swap(num, num4); num = num4; } return result; } private void Swap(int a, int b) { long value = keys[a]; keys[a] = keys[b]; keys[b] = value; float value2 = pri[a]; pri[a] = pri[b]; pri[b] = value2; } } private const float WorldLimit = 10400f; private const int MaxExpansions = 500000; private static long Key(int ix, int iz) { return ((long)(ix + 32768) << 16) | (iz + 32768); } private static int KX(long k) { return (int)(k >> 16) - 32768; } private static int KZ(long k) { return (int)(k & 0xFFFF) - 32768; } private static Vector3 Center(Ctx x, int ix, int iz) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) return new Vector3(((float)ix + 0.5f) * x.C.Cell, 0f, ((float)iz + 0.5f) * x.C.Cell); } private static int Idx(Ctx x, float v) { return (int)Mathf.Floor(v / x.C.Cell); } private static bool Deep(Ctx x, float wx, float wz) { if (wx * wx + wz * wz > 108160000f) { return false; } return x.C.Height(wx, wz) < x.C.Water - x.C.MinDepth; } private static bool Nav(Ctx x, int ix, int iz) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) long key = Key(ix, iz); if (x.Nav.TryGetValue(key, out var value)) { return value; } Vector3 val = Center(x, ix, iz); value = Deep(x, val.x, val.z); if (value) { float num = Mathf.Max(20f, x.C.Cell * 0.4f); value = Deep(x, val.x + num, val.z) && Deep(x, val.x - num, val.z) && Deep(x, val.x, val.z + num) && Deep(x, val.x, val.z - num); } x.Nav[key] = value; return value; } private static float Penalty(Ctx x, int ix, int iz) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (x.C.ShoreCost <= 0f) { return 0f; } long key = Key(ix, iz); if (x.Pen.TryGetValue(key, out var value)) { return value; } Vector3 val = Center(x, ix, iz); float num = Mathf.Max(x.C.Cell * 1.5f, 100f); float num2 = num * 0.7071f; int num3 = 0; if (!Deep(x, val.x + num, val.z)) { num3++; } if (!Deep(x, val.x - num, val.z)) { num3++; } if (!Deep(x, val.x, val.z + num)) { num3++; } if (!Deep(x, val.x, val.z - num)) { num3++; } if (!Deep(x, val.x + num2, val.z + num2)) { num3++; } if (!Deep(x, val.x - num2, val.z + num2)) { num3++; } if (!Deep(x, val.x + num2, val.z - num2)) { num3++; } if (!Deep(x, val.x - num2, val.z - num2)) { num3++; } value = x.C.ShoreCost * (float)num3 / 8f; x.Pen[key] = value; return value; } private static bool LineClear(Ctx x, Vector3 a, Vector3 b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) Vector3 val = b - a; val.y = 0f; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 1f) { return true; } Vector3 val2 = val / magnitude; Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(val2.z, 0f, 0f - val2.x); float num = Mathf.Max(24f, x.C.Cell * 0.5f); for (float num2 = 0f; num2 <= magnitude; num2 += num) { Vector3 val4 = a + val2 * num2; if (!Deep(x, val4.x, val4.z)) { return false; } if (x.C.Margin > 1f) { if (!Deep(x, val4.x + val3.x * x.C.Margin, val4.z + val3.z * x.C.Margin)) { return false; } if (!Deep(x, val4.x - val3.x * x.C.Margin, val4.z - val3.z * x.C.Margin)) { return false; } } } return Deep(x, b.x, b.z); } private static bool Nearest(Ctx x, Vector3 p, int maxRings, out int bx, out int bz) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) int num = Idx(x, p.x); int num2 = Idx(x, p.z); bx = num; bz = num2; float num3 = float.MaxValue; bool flag = false; for (int i = 0; i <= maxRings && (!flag || !((float)(i - 1) * x.C.Cell > num3)); i++) { for (int j = -i; j <= i; j++) { for (int k = -i; k <= i; k++) { if (Math.Max(Math.Abs(j), Math.Abs(k)) == i && Nav(x, num + j, num2 + k)) { Vector3 val = Center(x, num + j, num2 + k); float num4 = (val.x - p.x) * (val.x - p.x) + (val.z - p.z) * (val.z - p.z); num4 = Mathf.Sqrt(num4); if (num4 < num3) { num3 = num4; bx = num + j; bz = num2 + k; flag = true; } } } } } return flag; } public static PlanResult Plan(PlanConfig cfg) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_038e: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_0409: Unknown result type (might be due to invalid IL or missing references) //IL_04bc: Unknown result type (might be due to invalid IL or missing references) //IL_04c1: Unknown result type (might be due to invalid IL or missing references) //IL_04d5: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04a7: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_0452: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Unknown result type (might be due to invalid IL or missing references) Ctx ctx = new Ctx(); ctx.C = cfg; Ctx x = ctx; PlanResult planResult; if (!Nearest(x, cfg.Start, 10, out var bx, out var bz)) { planResult = new PlanResult(); planResult.Error = "No deep water near the ship."; return planResult; } if (!Nearest(x, cfg.Dest, 70, out var bx2, out var bz2)) { bx2 = Idx(x, cfg.Dest.x); bz2 = Idx(x, cfg.Dest.z); } long num = Key(bx, bz); long num2 = Key(bx2, bz2); Dictionary<long, float> dictionary = new Dictionary<long, float>(); Dictionary<long, long> dictionary2 = new Dictionary<long, long>(); HashSet<long> hashSet = new HashSet<long>(); Heap heap = new Heap(); dictionary[num] = 0f; heap.Push(num, Heur(bx, bz, bx2, bz2, cfg.Cell)); long num3 = num; float num4 = float.MaxValue; bool flag = false; int num5 = 0; float x2 = cfg.Dest.x; float z = cfg.Dest.z; while (heap.Count > 0 && num5 < 500000) { long num6 = heap.Pop(); if (!hashSet.Add(num6)) { continue; } num5++; int num7 = KX(num6); int num8 = KZ(num6); Vector3 val = Center(x, num7, num8); float num9 = (val.x - x2) * (val.x - x2) + (val.z - z) * (val.z - z); if (num9 < num4) { num4 = num9; num3 = num6; } if (num6 == num2) { flag = true; num3 = num6; break; } for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) { continue; } int num10 = num7 + i; int num11 = num8 + j; if (!Nav(x, num10, num11) || (i != 0 && j != 0 && (!Nav(x, num7 + i, num8) || !Nav(x, num7, num8 + j)))) { continue; } long num12 = Key(num10, num11); if (!hashSet.Contains(num12)) { float num13 = dictionary[num6] + ((i == 0 || j == 0) ? 1f : 1.4142f) * (1f + Penalty(x, num10, num11)); if (!dictionary.TryGetValue(num12, out var value) || !(value <= num13)) { dictionary[num12] = num13; dictionary2[num12] = num6; heap.Push(num12, num13 + Heur(num10, num11, bx2, bz2, 1f)); } } } } } List<Vector3> list = new List<Vector3>(); long value2 = num3; do { list.Add(Center(x, KX(value2), KZ(value2))); } while (value2 != num && dictionary2.TryGetValue(value2, out value2)); list.Reverse(); if (list.Count == 0) { planResult = new PlanResult(); planResult.Error = "No water route found."; return planResult; } List<Vector3> list2 = new List<Vector3>(); list2.Add(new Vector3(cfg.Start.x, 0f, cfg.Start.z)); for (int k = 1; k < list.Count; k++) { list2.Add(list[k]); } if (flag && Deep(x, cfg.Dest.x, cfg.Dest.z)) { list2.Add(new Vector3(cfg.Dest.x, 0f, cfg.Dest.z)); } List<Vector3> list3 = new List<Vector3>(); int num14 = 0; while (num14 < list2.Count - 1) { int num15 = Math.Min(list2.Count - 1, num14 + 24); while (num15 > num14 + 1 && !LineClear(x, list2[num14], list2[num15])) { num15--; } list3.Add(list2[num15]); num14 = num15; } if (list3.Count == 0) { list3.Add(list2[list2.Count - 1]); } Vector3 end = list3[list3.Count - 1]; planResult = new PlanResult(); planResult.Path = list3; planResult.End = end; return planResult; } private static float Heur(int ax, int az, int bx, int bz, float scale) { float val = Math.Abs(ax - bx); float val2 = Math.Abs(az - bz); return (Math.Max(val, val2) + 0.4142f * Math.Min(val, val2)) * scale / ((scale != 1f) ? 1f : 1f); } } public static bool Active; public static Ship CurrentShip; private static List<Vector3> path; private static int index; private static Vector3 destination; private static Vector3 endPoint; private static Vector3? lastDestination; private static volatile PlanResult planResult; private static bool planning; private static float startedAt; private static float lastSpeedStep; private static float lastAvoidProbe; private static float stuckCheckAt; private static float badHeadingSince = -1f; private static Vector3 stuckPos; private static float avoidAngle; private static bool pulse; private static bool planIsReplan; private static bool recovering; private static float recoverUntil; private static float recoverSide = 1f; private static float lastReplan; private static float shipSpeed; private static float remaining; private static float freeLeft; private static float freeRight; private static float chosenFree = 999f; private static int retries; private static Vector3 routeStart; private static Vector3 recoverPos; private static readonly string[] FavorPrefabs = new string[2] { "TailwindBelt", "TailwindCharm" }; private static int ObstacleMask = -1; public static void Tick() { //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { if (Active) { Stop(null); } return; } if (Active) { if ((Object)(object)localPlayer.GetControlledShip() != (Object)(object)CurrentShip) { Stop("Autopilot off: you left the helm."); return; } if (Plugin.RequireFavor.Value && !FavorActive(localPlayer)) { Stop("Autopilot off: Njord's Favor is gone."); return; } PlanResult planResult = Pilot.planResult; if (planning && planResult != null) { planning = false; Pilot.planResult = null; if (planResult.Error != null) { Stop(planResult.Error); return; } path = planResult.Path; index = 0; endPoint = planResult.End; startedAt = Time.time; routeStart = ((Component)CurrentShip).transform.position; stuckPos = routeStart; stuckCheckAt = Time.time + 8f; float num = Vector2.Distance(new Vector2(endPoint.x, endPoint.z), new Vector2(destination.x, destination.z)); if (!planIsReplan) { Say((!(num > Plugin.ArrivalRadius.Value + 30f)) ? "Route set." : ("Route set: nearest water is " + Mathf.RoundToInt(num) + " m from the spot.")); } if (Plugin.DebugLog.Value) { Plugin.Log.LogInfo((object)("Route with " + path.Count + " waypoints.")); } } } KeyboardShortcut value = Plugin.ToggleKey.Value; if (!((KeyboardShortcut)(ref value)).IsDown()) { return; } bool flag = Minimap.IsOpen(); Ship controlledShip = localPlayer.GetControlledShip(); string text = BlockedReason(); Plugin.Log.LogInfo((object)("Autosail key pressed: map open=" + flag + ", at helm=" + ((Object)(object)controlledShip != (Object)null) + ", favor=" + FavorActive(localPlayer) + ", blocked=" + (text ?? "no") + ", active=" + Active)); if (text != null) { if (text == "pin name box") { Say(string.Concat("Finish or cancel the pin name box first, then press ", Plugin.ToggleKey.Value, " again.")); } return; } if (Active && !flag) { Stop("Autopilot off."); return; } if ((Object)(object)controlledShip == (Object)null) { Say("Take the helm first."); return; } if (Plugin.RequireFavor.Value && !FavorActive(localPlayer)) { Say("Put on Njord's Belt or Charm first."); return; } Vector3 dest; if (flag) { dest = MapTarget(); } else { if (!lastDestination.HasValue) { Say(string.Concat("Open the map, hover where you want to go and press ", Plugin.ToggleKey.Value, ".")); return; } dest = lastDestination.Value; } if (flag && Plugin.CloseMap.Value) { Minimap.instance.SetMapMode((MapMode)1); } Begin(controlledShip, dest, replan: false); } private static string BlockedReason() { if ((Object)(object)Chat.instance != (Object)null && Chat.instance.HasFocus()) { return "chat"; } if (Console.IsVisible()) { return "console"; } if (TextInput.IsVisible()) { return "text input"; } if (Menu.IsVisible()) { return "menu"; } if (Minimap.InTextInput()) { return "pin name box"; } return null; } private static bool FavorActive(Player p) { foreach (ItemData allItem in ((Humanoid)p).GetInventory().GetAllItems()) { if (!allItem.m_equipped || (Object)(object)allItem.m_dropPrefab == (Object)null) { continue; } string name = ((Object)allItem.m_dropPrefab).name; for (int i = 0; i < FavorPrefabs.Length; i++) { if (name == FavorPrefabs[i]) { return true; } } } return false; } private static Vector3 MapTarget() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; MethodInfo methodInfo = AccessTools.Method(typeof(Minimap), "ScreenToWorldPoint", (Type[])null, (Type[])null); Vector3 val = (Vector3)methodInfo.Invoke(instance, new object[1] { Input.mousePosition }); Vector3 val2 = val; float num = Plugin.PinSnapRadius.Value; if (AccessTools.Field(typeof(Minimap), "m_pins").GetValue(instance) is IEnumerable enumerable) { foreach (object item in enumerable) { PinData val3 = (PinData)((item is PinData) ? item : null); if (val3 != null) { float num2 = Vector2.Distance(new Vector2(val3.m_pos.x, val3.m_pos.z), new Vector2(val.x, val.z)); if (num2 < num) { num = num2; val2 = val3.m_pos; } } } } return new Vector3(val2.x, 0f, val2.z); } private static void Begin(Ship ship, Vector3 dest, bool replan) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) CurrentShip = ship; destination = dest; lastDestination = dest; Active = true; planning = true; planResult = null; path = null; index = 0; startedAt = Time.time; lastSpeedStep = 0f; lastAvoidProbe = 0f; badHeadingSince = -1f; planIsReplan = replan; recovering = false; if (!replan) { retries = 0; avoidAngle = 0f; lastReplan = Time.time; } WorldGenerator wg = WorldGenerator.instance; ZoneSystem instance = ZoneSystem.instance; if (wg == null || (Object)(object)instance == (Object)null) { Stop("World is not ready."); return; } PlanConfig cfg = new PlanConfig { Height = (float x, float z) => wg.GetHeight(x, z), Water = instance.m_waterLevel, MinDepth = Plugin.MinDepth.Value, Cell = Plugin.CellSize.Value, Margin = Plugin.ShoreMargin.Value, ShoreCost = Plugin.ShoreCost.Value, Start = ((Component)ship).transform.position, Dest = dest }; Say((!replan) ? "Planning route..." : "Replanning route..."); ThreadPool.QueueUserWorkItem(delegate { PlanResult planResult; try { planResult = Planner.Plan(cfg); } catch (Exception ex) { planResult = new PlanResult { Error = "Route planning failed: " + ex.Message }; } Pilot.planResult = planResult; }); } public static void Stop(string message) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) bool active = Active; Ship currentShip = CurrentShip; Active = false; planning = false; planResult = null; path = null; CurrentShip = null; if ((Object)(object)currentShip != (Object)null && (int)currentShip.GetSpeedSetting() != 0) { try { currentShip.Stop(); } catch { } } if (active && message != null) { Say(message); } } private static void Say(string text) { Player localPlayer = Player.m_localPlayer; Plugin.Log.LogInfo((object)("Autosail: " + text)); if ((Object)(object)localPlayer != (Object)null) { ((Character)localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); ((Character)localPlayer).Message((MessageType)1, text, 0, (Sprite)null, false); } } public static void Steer(Ship ship, ref Vector3 moveDir) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_0375: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0398: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Unknown result type (might be due to invalid IL or missing references) //IL_0463: Unknown result type (might be due to invalid IL or missing references) //IL_0474: Unknown result type (might be due to invalid IL or missing references) //IL_0477: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0498: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_050e: Unknown result type (might be due to invalid IL or missing references) //IL_059e: Unknown result type (might be due to invalid IL or missing references) //IL_059f: Unknown result type (might be due to invalid IL or missing references) //IL_0523: Unknown result type (might be due to invalid IL or missing references) //IL_0682: Unknown result type (might be due to invalid IL or missing references) if (Time.time - startedAt > 1f && (Mathf.Abs(moveDir.x) > 0.5f || moveDir.z < -0.5f)) { Stop("Autopilot off: manual steering."); return; } moveDir = Vector3.zero; if (path == null) { return; } Vector3 position = ((Component)ship).transform.position; Vector3 val = Flat(((Component)ship).transform.forward); Rigidbody component = ((Component)ship).GetComponent<Rigidbody>(); float num = shipSpeed; float num2; if ((Object)(object)component != (Object)null) { Vector3 velocity = component.velocity; num2 = ((Vector3)(ref velocity)).magnitude; } else { num2 = 0f; } shipSpeed = Mathf.Lerp(num, num2, 0.05f); if (recovering) { if (Time.time < recoverUntil) { AdjustSpeed(ship, (Speed)1, ref moveDir); moveDir.x = Mathf.Clamp((recoverSide - ship.GetRudderValue()) * 4f, -1f, 1f); } else { recovering = false; recoverPos = position; Begin(ship, destination, replan: true); } return; } if (Dist2D(position, recoverPos) > 250f) { retries = 0; } while (index < path.Count - 1 && Dist2D(position, path[index]) < 45f) { index++; } Vector3 val2 = path[index]; bool flag = index == path.Count - 1; float num3 = Dist2D(position, path[path.Count - 1]); if (num3 < Plugin.ArrivalRadius.Value) { float num4 = Dist2D(endPoint, destination); Stop((!(num4 > Plugin.ArrivalRadius.Value + 30f)) ? "Arrived." : ("Arrived: " + Mathf.RoundToInt(num4) + " m short of the spot (land).")); return; } remaining = Dist2D(position, path[index]); for (int i = index; i < path.Count - 1; i++) { remaining += Dist2D(path[i], path[i + 1]); } Vector3 a = ((index <= 0) ? routeStart : path[index - 1]); if (DistToSegment(position, a, path[index]) > 250f && Time.time - lastReplan > 30f) { lastReplan = Time.time; Begin(ship, destination, replan: true); return; } Vector3 val3 = Flat(val2 - position); if (((Vector3)(ref val3)).sqrMagnitude < 0.0001f) { return; } ((Vector3)(ref val3)).Normalize(); if (Time.time - lastAvoidProbe > 0.25f) { lastAvoidProbe = Time.time; avoidAngle = Mathf.Lerp(avoidAngle, PickAvoidAngle(ship, position, val3), 0.6f); } Vector3 val4 = Quaternion.AngleAxis(avoidAngle, Vector3.up) * val3; float num5 = Vector3.SignedAngle(val, val4, Vector3.up); float num6 = ((!((Object)(object)component != (Object)null)) ? 0f : (component.angularVelocity.y * 57.29578f)); float num7 = Mathf.Clamp(num5 / Plugin.SteerRange.Value - Plugin.Damping.Value * num6, -1f, 1f); if (Plugin.InvertRudder.Value) { num7 = 0f - num7; } moveDir.x = Mathf.Clamp((num7 - ship.GetRudderValue()) * 4f, -1f, 1f); Speed val5 = (Speed)4; if (Mathf.Abs(num5) > 60f || Mathf.Abs(avoidAngle) > 30f) { val5 = (Speed)3; } if (num3 < 350f) { val5 = (Speed)3; } if (num3 < 150f) { val5 = (Speed)2; } if (chosenFree < 70f) { val5 = Slower(val5, (Speed)3); } if (chosenFree < 35f) { val5 = Slower(val5, (Speed)2); } AdjustSpeed(ship, val5, ref moveDir); if (Mathf.Abs(num5) > 120f) { if (badHeadingSince < 0f) { badHeadingSince = Time.time; } else if (Time.time - badHeadingSince > 25f) { Stop("Autopilot off: cannot turn toward the route. Try the InvertRudder setting."); return; } } else { badHeadingSince = -1f; } if (Time.time > stuckCheckAt) { if (Dist2D(position, stuckPos) < 6f && Rank(ship.GetSpeedSetting()) >= Rank((Speed)2)) { retries++; if (retries > 3) { Stop("Autopilot off: the ship cannot get free."); return; } recovering = true; recoverUntil = Time.time + 4.5f; recoverSide = ((!(freeLeft > freeRight)) ? 1f : (-1f)); Say("Stuck, backing off..."); return; } stuckPos = position; stuckCheckAt = Time.time + 7f; } if (Plugin.DebugLog.Value && Time.frameCount % 120 == 0) { Plugin.Log.LogInfo((object)("wp " + index + "/" + path.Count + " toEnd " + Mathf.RoundToInt(num3) + " err " + Mathf.RoundToInt(num5) + " avoid " + Mathf.RoundToInt(avoidAngle) + " rudder " + ship.GetRudderValue().ToString("0.00") + " speed " + ship.GetSpeedSetting())); } } private static int Rank(Speed v) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected I4, but got Unknown return (int)v switch { 1 => 0, 0 => 1, 2 => 2, 3 => 3, _ => 4, }; } private static Speed Slower(Speed a, Speed b) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) return (Rank(a) > Rank(b)) ? b : a; } private static void AdjustSpeed(Ship ship, Speed wanted, ref Vector3 moveDir) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) Speed speedSetting = ship.GetSpeedSetting(); if (speedSetting != wanted && !(Time.time - lastSpeedStep < 0.5f)) { pulse = !pulse; float z = ((Rank(speedSetting) >= Rank(wanted)) ? (-1f) : 1f); if (pulse) { moveDir.z = z; return; } moveDir.z = 0f; lastSpeedStep = Time.time; } } private static float DistToSegment(Vector3 p, Vector3 a, Vector3 b) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(p.x - a.x, p.z - a.z); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(b.x - a.x, b.z - a.z); float sqrMagnitude = ((Vector2)(ref val2)).sqrMagnitude; float num = ((!(sqrMagnitude < 1f)) ? Mathf.Clamp01(Vector2.Dot(val, val2) / sqrMagnitude) : 0f); Vector2 val3 = val - val2 * num; return ((Vector2)(ref val3)).magnitude; } public static string StatusText() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (!Active || (Object)(object)CurrentShip == (Object)null) { return null; } if (planning) { return (!planIsReplan) ? "Autosail: planning route..." : "Autosail: replanning route..."; } if (recovering) { return "Autosail: backing off..."; } if (path == null) { return null; } string text = ((!(shipSpeed > 0.8f)) ? "--" : FormatTime(remaining / shipSpeed)); return string.Concat("Autosail ", FormatDist(remaining), " to go ETA ", text, " (", Plugin.ToggleKey.Value, " to stop)"); } private static string FormatDist(float m) { return (!(m >= 1000f)) ? (Mathf.RoundToInt(m) + " m") : ((m / 1000f).ToString("0.0") + " km"); } private static string FormatTime(float sec) { int num = Mathf.Clamp(Mathf.RoundToInt(sec), 0, 359999); return (num < 3600) ? (num / 60 + ":" + (num % 60).ToString("00")) : (num / 3600 + ":" + (num / 60 % 60).ToString("00") + ":" + (num % 60).ToString("00")); } private static float PickAvoidAngle(Ship ship, Vector3 pos, Vector3 want) { //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if (ObstacleMask == -1) { ObstacleMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "terrain", "vehicle" }); } float num = Mathf.Clamp(Mathf.Max(Plugin.AvoidDistance.Value, shipSpeed * 8f), 30f, 240f); float[] array = new float[11] { 0f, 12f, -12f, 24f, -24f, 40f, -40f, 60f, -60f, 85f, -85f }; float result = 0f; float num2 = -1f; freeLeft = 0f; freeRight = 0f; chosenFree = num; bool flag = false; float result2 = 0f; for (int i = 0; i < array.Length; i++) { Vector3 dir = Quaternion.AngleAxis(array[i], Vector3.up) * want; float num3 = FreeDistance(ship, pos + Vector3.up * 1.5f, dir, num); if (array[i] > 0f) { freeRight = Mathf.Max(freeRight, num3); } else if (array[i] < 0f) { freeLeft = Mathf.Max(freeLeft, num3); } if (!flag && num3 >= num) { flag = true; result2 = array[i]; chosenFree = num3; } if (num3 > num2) { num2 = num3; result = array[i]; } } if (flag) { return result2; } chosenFree = num2; return result; } private static float FreeDistance(Ship ship, Vector3 origin, Vector3 dir, float range) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) RaycastHit[] array = Physics.SphereCastAll(origin, 3.5f, dir, range, ObstacleMask, (QueryTriggerInteraction)1); float num = range; for (int i = 0; i < array.Length; i++) { Collider collider = ((RaycastHit)(ref array[i])).collider; if (!((Object)(object)collider == (Object)null) && !((Object)(object)((Component)collider).GetComponentInParent<Ship>() == (Object)(object)ship) && ((RaycastHit)(ref array[i])).distance < num) { num = ((RaycastHit)(ref array[i])).distance; } } return num; } private static Vector3 Flat(Vector3 v) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) v.y = 0f; return v; } private static float Dist2D(Vector3 a, Vector3 b) { float num = a.x - b.x; float num2 = a.z - b.z; return Mathf.Sqrt(num * num + num2 * num2); } }